679 lines
19 KiB
HTML
679 lines
19 KiB
HTML
<!--#
|
|
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>
|
|
|
|
|
|
<!--#
|
|
}
|
|
#-->
|