first commit
This commit is contained in:
@@ -0,0 +1,678 @@
|
||||
<!--#
|
||||
layout("/mobile/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.page-container {
|
||||
background: #f7f8fa;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.van-dropdown-menu {
|
||||
position: fixed;
|
||||
top: 46px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 101;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.van-dropdown-menu__item {
|
||||
flex: 1;
|
||||
flex-shrink: unset;
|
||||
}
|
||||
|
||||
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 90px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
background: #f7f8fa; /* 与页面背景色保持一致 */
|
||||
}
|
||||
|
||||
.fixed-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 10px;
|
||||
background: linear-gradient(to bottom, rgba(247, 248, 250, 1), rgba(247, 248, 250, 0));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
background: #fff;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.staff-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.staff-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #323233;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.card-content .info-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
color: #646566;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
width: 70px;
|
||||
color: #969799;
|
||||
}
|
||||
|
||||
.card-container .receive-time {
|
||||
font-size: 14px;
|
||||
color: #07c160;
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px dashed #ebedf0;
|
||||
}
|
||||
|
||||
.stats-panel {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.stats-content {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.stats-item {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stats-item:not(:last-child):after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
height: 60%;
|
||||
width: 1px;
|
||||
background: #ebedf0;
|
||||
}
|
||||
|
||||
.stats-number {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #323233;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
}
|
||||
|
||||
.total-number {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.received-number {
|
||||
color: #07c160;
|
||||
}
|
||||
|
||||
.pending-number {
|
||||
color: #ff976a;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
margin-top: 210px;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
padding: 10px 16px;
|
||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.scan-button {
|
||||
border-radius: 24px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
font-size: 16px;
|
||||
box-shadow: 0 2px 8px rgba(25, 137, 250, 0.2);
|
||||
}
|
||||
|
||||
.scan-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: #000;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* 导航栏样式覆盖 */
|
||||
.scan-wrapper .van-nav-bar {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.scan-wrapper .van-nav-bar__title {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.scan-wrapper .van-nav-bar__text {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#reader {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 确保扫描区域在中间 */
|
||||
#reader video {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.confirm-dialog {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
color: #323233;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.confirm-dialog .info-item {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.confirm-dialog .info-item .label {
|
||||
width: 80px;
|
||||
color: #969799;
|
||||
}
|
||||
|
||||
.confirm-dialog .info-item .value {
|
||||
flex: 1;
|
||||
color: #323233;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dialog-footer .van-button {
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.confirm-dialog .receive-time {
|
||||
color: #969799;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.confirm-dialog .van-tag {
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.confirm-dialog .van-button--disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div v-if="!scanStatus">
|
||||
<van-nav-bar title="发放奖品" left-arrow placeholder fixed @click-left="history.go(-1)"></van-nav-bar>
|
||||
|
||||
<!-- 问卷下拉框 -->
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item v-model="pageForm.questionId" :options="questionOptions"
|
||||
@change="onSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<div class="fixed-header">
|
||||
<div class="search-bar">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入姓名或工号"
|
||||
@search="onSearch"
|
||||
shape="round"
|
||||
></van-search>
|
||||
</div>
|
||||
<!-- 统计面板 -->
|
||||
<div class="stats-panel">
|
||||
<div class="stats-content">
|
||||
<div class="stats-grid">
|
||||
<div class="stats-item">
|
||||
<div class="stats-number total-number">{{totalCount}}</div>
|
||||
<div class="stats-label">总人数</div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-number received-number">{{receivedCount}}</div>
|
||||
<div class="stats-label">已领取</div>
|
||||
</div>
|
||||
<div class="stats-item">
|
||||
<div class="stats-number pending-number">{{pendingCount}}</div>
|
||||
<div class="stats-label">未领取</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 人员 -->
|
||||
<div class="card-container">
|
||||
<van-list
|
||||
v-model="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多了"
|
||||
@load="onLoad"
|
||||
>
|
||||
<div
|
||||
v-for="item in staffList"
|
||||
:key="item.id"
|
||||
class="staff-card"
|
||||
>
|
||||
<div class="card-header">
|
||||
<span class="staff-name">{{item.userName}}</span>
|
||||
<van-tag
|
||||
:type="item.isReceive ? 'success' : 'warning'"
|
||||
round
|
||||
size="large"
|
||||
>
|
||||
{{item.isReceive ? '已领取' : '未领取'}}
|
||||
</van-tag>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="info-item">
|
||||
<span class="info-label">工号:</span>
|
||||
<span>{{item.loginName}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">部门:</span>
|
||||
<span>{{item.unitName}}</span>
|
||||
</div>
|
||||
<div class="receive-time" v-if="item.isReceive">
|
||||
领取时间:{{item.receiveTime}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</div>
|
||||
|
||||
<!-- 底部扫描按钮 -->
|
||||
<div class="bottom-bar">
|
||||
<van-button
|
||||
type="primary"
|
||||
block
|
||||
class="scan-button"
|
||||
@click="startScan"
|
||||
icon="scan"
|
||||
color="#1867b0"
|
||||
>
|
||||
扫描二维码发放奖品
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 确认发放弹窗 -->
|
||||
<van-popup
|
||||
v-model="showConfirmDialog"
|
||||
round
|
||||
position="center"
|
||||
:style="{ width: '80%' }"
|
||||
>
|
||||
<div class="confirm-dialog">
|
||||
<!-- 标题 -->
|
||||
<div class="dialog-title">
|
||||
确认发放奖品
|
||||
</div>
|
||||
|
||||
<!-- 内容区 -->
|
||||
<div class="dialog-content" v-if="currentStaff">
|
||||
<div class="info-item">
|
||||
<span class="label">姓名:</span>
|
||||
<span class="value">{{currentStaff.userName}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">工号:</span>
|
||||
<span class="value">{{currentStaff.loginName}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">单位:</span>
|
||||
<span class="value">{{currentStaff.unitName}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">工会:</span>
|
||||
<span class="value">{{currentStaff.unionName}}</span>
|
||||
</div>
|
||||
<!-- 添加领取状态 -->
|
||||
<div class="info-item">
|
||||
<span class="label">状态:</span>
|
||||
<span class="value">
|
||||
<van-tag :type="currentStaff.isReceive ? 'success' : 'warning'" round>
|
||||
{{currentStaff.isReceive ? '已领取' : '未领取'}}
|
||||
</van-tag>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 如果已领取则显示领取时间 -->
|
||||
<div class="info-item" v-if="currentStaff.isReceive">
|
||||
<span class="label">领取时间:</span>
|
||||
<span class="value">{{currentStaff.receiveTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按钮区 -->
|
||||
<div class="dialog-footer">
|
||||
<van-button
|
||||
plain
|
||||
round
|
||||
block
|
||||
@click="showConfirmDialog = false"
|
||||
>
|
||||
取消
|
||||
</van-button>
|
||||
<van-button
|
||||
type="primary"
|
||||
round
|
||||
block
|
||||
@click="confirmReceive"
|
||||
:loading="confirmLoading"
|
||||
:disabled="currentStaff.isReceive"
|
||||
>
|
||||
确认发放
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<!-- 扫描界面 -->
|
||||
<div v-if="scanStatus" class="scan-wrapper">
|
||||
<div class="scan-header">
|
||||
<van-nav-bar
|
||||
title="扫描二维码"
|
||||
left-text="返回"
|
||||
left-arrow
|
||||
@click-left="exitScan"
|
||||
:border="false"
|
||||
fixed
|
||||
>
|
||||
<template #left>
|
||||
<van-icon name="arrow-left" size="20" color="#fff"></van-icon>
|
||||
</template>
|
||||
</van-nav-bar>
|
||||
</div>
|
||||
<div id="reader"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let html5QrCode = null
|
||||
const vue = new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
questionOptions: [],
|
||||
pageForm: {
|
||||
questionId: null,
|
||||
searchKeyword: null,
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0
|
||||
},
|
||||
loading: false,
|
||||
finished: false,
|
||||
staffList: [],
|
||||
|
||||
showConfirmDialog: false,
|
||||
currentStaff: {},
|
||||
|
||||
totalCount: 0,
|
||||
receivedCount: 0,
|
||||
pendingCount: 0,
|
||||
cameraId: null,
|
||||
devices: null,
|
||||
|
||||
scanStatus: false,
|
||||
|
||||
confirmLoading: false
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSearch() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.staffList = []
|
||||
this.finished = false;
|
||||
this.onLoad()
|
||||
},
|
||||
|
||||
async onLoad() {
|
||||
if (!this.pageForm.questionId) {
|
||||
this.loading = false;
|
||||
this.finished = true;
|
||||
return;
|
||||
}
|
||||
this.finished = false
|
||||
|
||||
try {
|
||||
const {code, data} = await $.post('/mobile/question/h5/winnerList', this.pageForm)
|
||||
this.staffList = [...this.staffList, ...data.list];
|
||||
if (data.list.length < this.pageForm.pageSize) {
|
||||
this.finished = true;
|
||||
}
|
||||
this.pageForm.pageNumber++;
|
||||
this.loading = false;
|
||||
} catch (err) {
|
||||
this.loading = false;
|
||||
this.finished = true;
|
||||
}
|
||||
},
|
||||
|
||||
// 更新统计数据
|
||||
updateStats() {
|
||||
$.get('/mobile/question/h5/winnerCount', {questionId: this.pageForm.questionId}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.totalCount = res.data.totalCount;
|
||||
this.receivedCount = res.data.receivedCount;
|
||||
this.pendingCount = res.data.pendingCount;
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 开始扫描
|
||||
startScan() {
|
||||
Html5Qrcode.getCameras().then((devices) => {
|
||||
if (devices && devices.length) {
|
||||
// 如果有2个摄像头,1为前置的
|
||||
if (devices.length > 1) {
|
||||
this.cameraId = devices[1].id;
|
||||
} else {
|
||||
this.cameraId = devices[0].id;
|
||||
}
|
||||
let isHuawei = navigator.userAgent.toLowerCase().match(/huawei/i) === 'huawei';
|
||||
if (isHuawei) {
|
||||
const backCamera = devices.filter(o => o.label.includes('back'))
|
||||
this.cameraId = backCamera[0].id;
|
||||
}
|
||||
this.devices = devices;
|
||||
this.scanStatus = true
|
||||
|
||||
this.$nextTick(() => {
|
||||
html5QrCode = new Html5Qrcode("reader");
|
||||
html5QrCode.start(
|
||||
this.cameraId,
|
||||
{
|
||||
fps: 20,
|
||||
qrbox: {width: 250, height: 250},
|
||||
aspectRatio: 1.7777777777777777,
|
||||
},
|
||||
(decodedText, decodedResult) => {
|
||||
this.handleScanResult(decodedText)
|
||||
},
|
||||
(errorMessage) => {
|
||||
console.log(errorMessage);
|
||||
}
|
||||
).catch(err => {
|
||||
alert(err)
|
||||
});
|
||||
})
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
alert(err)
|
||||
})
|
||||
},
|
||||
|
||||
// 停止扫描
|
||||
exitScan() {
|
||||
this.scanStatus = false;
|
||||
if (html5QrCode) {
|
||||
html5QrCode.stop().then(() => {
|
||||
console.log('扫描已停止');
|
||||
}).catch((err) => {
|
||||
console.log('停止扫描出错:', err);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//校验扫描结果
|
||||
handleScanResult(result) {
|
||||
this.exitScan()
|
||||
if (!result) {
|
||||
this.$toast.fail('请扫描正确的二维码')
|
||||
return
|
||||
}
|
||||
$.post('/mobile/question/h5/checkScanResult', {
|
||||
questionId: this.pageForm.questionId,
|
||||
id: result
|
||||
}).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.currentStaff = res.data;
|
||||
this.showConfirmDialog = true;
|
||||
} else {
|
||||
this.$toast.fail(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 确认领取奖品
|
||||
async confirmReceive() {
|
||||
if (!this.currentStaff) return;
|
||||
this.confirmLoading = true;
|
||||
try {
|
||||
const res = await $.post('/mobile/question/h5/confirmReceive', {
|
||||
questionId: this.pageForm.questionId,
|
||||
id: this.currentStaff.id
|
||||
});
|
||||
|
||||
if (res.code === 0) {
|
||||
// 重新搜索
|
||||
this.onSearch()
|
||||
// 更新统计数据
|
||||
this.updateStats();
|
||||
// 提示成功
|
||||
this.$toast.success('发放成功');
|
||||
// 关闭弹窗
|
||||
this.showConfirmDialog = false;
|
||||
// 重置当前
|
||||
// this.currentStaff = null;
|
||||
} else {
|
||||
this.$toast.fail(res.msg || '发放失败');
|
||||
}
|
||||
} catch (err) {
|
||||
this.$toast.fail('网络错误,请重试');
|
||||
} finally {
|
||||
this.confirmLoading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
$.get('/mobile/question/h5/listQuestion').then(res => {
|
||||
if (res.code === 0) {
|
||||
this.questionOptions = res.data.map(v => {
|
||||
return {
|
||||
text: v.qtitle,
|
||||
value: v.qid
|
||||
}
|
||||
})
|
||||
if (this.questionOptions.length > 0) {
|
||||
this.pageForm.questionId = this.questionOptions[0].value
|
||||
// 设置完questionId后主动加载数据
|
||||
this.onLoad();
|
||||
// 同时更新统计数据
|
||||
this.updateStats();
|
||||
|
||||
//this.handleScanResult('999')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Reference in New Issue
Block a user