peixue-dev/peidu/uniapp/teacher-package/pages/teacher/verify.vue

466 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="verify-page">
<!-- 扫码区域 -->
<view class="scan-section">
<view class="scan-icon" @click="scanCode">
<text class="icon">📷</text>
<text class="text">点击扫码核销</text>
</view>
<text class="scan-tip">扫描订单二维码或核销码进行核销</text>
</view>
<!-- 手动输入核销码 -->
<view class="input-section">
<view class="section-title">或手动输入核销码</view>
<view class="input-row">
<input
class="verify-input"
v-model="verifyCode"
placeholder="请输入12位核销码"
maxlength="12"
type="number"
/>
<button class="verify-btn" @click="manualVerify" :disabled="!verifyCode">
核销
</button>
</view>
</view>
<!-- 今日核销记录 -->
<view class="records-section">
<view class="section-title">今日核销记录</view>
<view class="record-list">
<view
v-for="(record, index) in records"
:key="index"
class="record-item"
@click="viewOrderDetail(record)"
>
<view class="record-header">
<text class="order-no">订单号: {{ record.orderNo }}</text>
<text class="verify-time">{{ formatTime(record.verifyTime) }}</text>
</view>
<view class="record-content">
<text class="user-name">用户: {{ record.userName || '未知' }}</text>
<text class="service-name">服务: {{ record.serviceName || '未知' }}</text>
</view>
<view class="record-footer">
<text class="status success">✓ 已核销</text>
<text class="amount">¥{{ record.totalAmount }}</text>
</view>
</view>
<view v-if="records.length === 0" class="empty-tip">
<text class="empty-icon">📋</text>
<text class="empty-text">今日暂无核销记录</text>
</view>
</view>
</view>
</view>
</template>
<script>
import request from '@/utils/request'
export default {
data() {
return {
verifyCode: '',
records: []
}
},
onLoad() {
this.loadTodayRecords()
},
onShow() {
// 每次显示页面时刷新记录
this.loadTodayRecords()
},
methods: {
// 扫码核销
scanCode() {
uni.scanCode({
success: (res) => {
console.log('扫码结果:', res)
const code = res.result
// 判断扫描结果类型
if (code.includes('orderId=')) {
// 订单ID格式orderId=123
const orderId = code.split('orderId=')[1]
this.scanVerifyByOrderId(orderId)
} else if (code.length === 12 && /^\d+$/.test(code)) {
// 12位数字核销码
this.verifyByCode(code)
} else {
// 尝试作为核销码处理
this.verifyByCode(code)
}
},
fail: (err) => {
console.error('扫码失败:', err)
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
})
},
// 手动输入核销码核销
manualVerify() {
if (!this.verifyCode) {
uni.showToast({
title: '请输入核销码',
icon: 'none'
})
return
}
if (this.verifyCode.length !== 12) {
uni.showToast({
title: '核销码应为12位数字',
icon: 'none'
})
return
}
this.verifyByCode(this.verifyCode)
},
// 通过核销码核销
async verifyByCode(code) {
try {
uni.showLoading({ title: '核销中...' })
const res = await request.post('/api/order/verify', null, {
verifyCode: code
})
console.log('核销响应:', res)
uni.hideLoading()
uni.showModal({
title: '核销成功',
content: '订单已核销,服务已开始',
showCancel: false,
success: () => {
this.verifyCode = ''
this.loadTodayRecords()
}
})
} catch (e) {
console.error('核销失败:', e)
uni.hideLoading()
uni.showModal({
title: '核销失败',
content: e.message || e.msg || '核销码无效或订单状态不允许核销',
showCancel: false
})
}
},
// 通过订单ID核销
async scanVerifyByOrderId(orderId) {
try {
uni.showLoading({ title: '核销中...' })
const res = await request.post(`/api/order/scan-verify/${orderId}`)
console.log('核销响应:', res)
uni.hideLoading()
uni.showModal({
title: '核销成功',
content: '订单已核销,服务已开始',
showCancel: false,
success: () => {
this.loadTodayRecords()
}
})
} catch (e) {
console.error('核销失败:', e)
uni.hideLoading()
uni.showModal({
title: '核销失败',
content: e.message || e.msg || '订单不存在或状态不允许核销',
showCancel: false
})
}
},
// 加载今日核销记录
async loadTodayRecords() {
try {
const today = this.getToday()
console.log('=== 加载核销记录 ===')
console.log('今天日期:', today)
// 获取当前登录的教师ID
const teacherId = uni.getStorageSync('userId')
console.log('教师ID:', teacherId)
const res = await request.get('/api/order/list', {
teacherId: teacherId,
status: 2, // 2=服务中(已核销)
page: 1,
size: 50
})
console.log('核销记录返回:', res)
// 处理返回的数据格式
const data = res.data || res
if (data && data.records) {
console.log('所有订单记录:', data.records)
console.log('订单记录数量:', data.records.length)
// 筛选今天核销的订单
this.records = data.records.filter(order => {
console.log('检查订单:', order.id, 'verifyTime:', order.verifyTime)
if (!order.verifyTime) {
console.log('订单没有核销时间,跳过')
return false
}
// 处理不同的日期格式
let verifyDate = ''
if (typeof order.verifyTime === 'string') {
verifyDate = order.verifyTime.split(' ')[0]
} else {
console.log('verifyTime不是字符串:', typeof order.verifyTime)
return false
}
console.log('订单核销日期:', verifyDate, '今天:', today, '匹配:', verifyDate === today)
return verifyDate === today
})
console.log('今日核销记录数量:', this.records.length)
// 如果没有今日记录,显示提示
if (this.records.length === 0 && data.records.length > 0) {
console.log('⚠️ 有核销记录但不是今天的')
console.log('最近的核销时间:', data.records[0]?.verifyTime)
}
} else {
console.log('没有返回records数据')
this.records = []
}
} catch (e) {
console.error('加载核销记录失败:', e)
this.records = []
}
},
// 查看订单详情
viewOrderDetail(record) {
uni.navigateTo({
url: `/pages/order/detail?id=${record.id}`
})
},
// 获取今天日期
getToday() {
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
// 格式化时间
formatTime(datetime) {
if (!datetime) return ''
const d = new Date(datetime)
const hours = String(d.getHours()).padStart(2, '0')
const minutes = String(d.getMinutes()).padStart(2, '0')
return `${hours}:${minutes}`
}
}
}
</script>
<style lang="scss" scoped>
.verify-page {
min-height: 100vh;
background: #f5f5f5;
padding: 30rpx;
}
.scan-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 80rpx 40rpx;
border-radius: 20rpx;
text-align: center;
margin-bottom: 30rpx;
.scan-icon {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
.icon {
font-size: 120rpx;
margin-bottom: 30rpx;
}
.text {
font-size: 36rpx;
color: #fff;
font-weight: bold;
}
}
.scan-tip {
display: block;
margin-top: 30rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.9);
}
}
.input-section {
background: #fff;
padding: 30rpx;
border-radius: 20rpx;
margin-bottom: 30rpx;
.section-title {
font-size: 28rpx;
color: #666;
margin-bottom: 20rpx;
}
.input-row {
display: flex;
align-items: center;
gap: 20rpx;
.verify-input {
flex: 1;
height: 80rpx;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 10rpx;
font-size: 32rpx;
}
.verify-btn {
width: 160rpx;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
border-radius: 10rpx;
font-size: 32rpx;
border: none;
padding: 0;
&[disabled] {
opacity: 0.5;
}
}
}
}
.records-section {
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.record-list {
.record-item {
background: #fff;
padding: 30rpx;
border-radius: 16rpx;
margin-bottom: 20rpx;
.record-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.order-no {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.verify-time {
font-size: 24rpx;
color: #999;
}
}
.record-content {
display: flex;
flex-direction: column;
gap: 10rpx;
margin-bottom: 20rpx;
.user-name,
.service-name {
font-size: 26rpx;
color: #666;
}
}
.record-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 20rpx;
border-top: 1rpx solid #f0f0f0;
.status {
font-size: 26rpx;
&.success {
color: #52c41a;
}
}
.amount {
font-size: 32rpx;
color: #ff6b00;
font-weight: bold;
}
}
}
.empty-tip {
display: flex;
flex-direction: column;
align-items: center;
padding: 100rpx 0;
.empty-icon {
font-size: 100rpx;
margin-bottom: 20rpx;
opacity: 0.3;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
}
}
}
</style>