hookehuyr

feat(verificationResult): 重构核销结果页面并优化核销流程

重构核销结果页面UI,增加状态显示和更好的用户反馈
优化核销流程,移除直接扫码功能改为点击核销按钮触发
添加核销状态管理,包括核销中、成功和失败状态
1 export default { 1 export default {
2 - navigationBarTitleText: '核销结果' 2 + navigationBarTitleText: '核销'
3 } 3 }
......
1 <!-- 1 <!--
2 * @Date: 2026-01-08 13:01:20 2 * @Date: 2026-01-08 13:01:20
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-08 13:08:22 4 + * @LastEditTime: 2026-01-14 10:07:56
5 * @FilePath: /xyxBooking-weapp/src/pages/verificationResult/index.vue 5 * @FilePath: /xyxBooking-weapp/src/pages/verificationResult/index.vue
6 * @Description: 核销结果页面 6 * @Description: 核销结果页面
7 --> 7 -->
8 <template> 8 <template>
9 - <view class="result-page"> 9 + <view class="min-h-screen bg-gray-100 p-4 verify-page">
10 - <view class="result-content"> 10 + <view class="rounded-2xl bg-white p-4 shadow-sm">
11 - <icon type="success" size="64" color="#A67939"/> 11 + <view class="flex items-center">
12 - <view class="msg">{{ msg }}</view> 12 + <view class="flex h-11 w-11 items-center justify-center rounded-full bg-amber-50">
13 - <view class="info" v-if="resultContent">预约码: {{ resultContent }}</view> 13 + <icon :type="status_icon_type" size="24" :color="status_icon_color" />
14 - <nut-button color="#A67939" class="back-btn" @tap="continueScan">继续核销</nut-button> 14 + </view>
15 - <!-- <nut-button type="default" class="home-btn" @tap="goHome">返回首页</nut-button> --> 15 + <view class="ml-4 flex-1">
16 + <view class="text-sm font-semibold text-gray-900">{{ status_title }}</view>
17 + <view class="mt-1 text-xs text-gray-500">{{ msg }}</view>
18 + </view>
19 + </view>
20 + </view>
21 +
22 + <view v-if="result_content" class="mt-4 rounded-2xl bg-white p-5 shadow-sm">
23 + <view class="text-xs text-gray-500">核销结果</view>
24 + <view class="mt-2 break-all text-sm font-medium text-gray-900">{{ result_content }}</view>
25 + </view>
26 + <view v-else class="mt-4 rounded-2xl bg-white p-5 shadow-sm">
27 + <view class="text-xs text-gray-500">核销结果</view>
28 + <view class="mt-2 text-sm text-gray-400">暂无核销结果,点击下方核销按钮开始扫码</view>
29 + </view>
30 +
31 + <view class="verify-footer">
32 + <nut-button
33 + block
34 + color="#A67939"
35 + :loading="verify_status === 'verifying'"
36 + :disabled="verify_status === 'verifying'"
37 + class="verify-btn"
38 + @tap="start_scan_and_verify"
39 + >
40 + 核销
41 + </nut-button>
42 + <view class="mt-4 text-center text-xs text-gray-400">扫描预约码二维码进行核销</view>
16 </view> 43 </view>
17 </view> 44 </view>
18 </template> 45 </template>
19 46
20 <script setup> 47 <script setup>
21 -import { ref } from 'vue' 48 +import { ref, computed } from 'vue'
22 import { useRouter } from '@tarojs/taro' 49 import { useRouter } from '@tarojs/taro'
23 -// import { useGo } from '@/hooks/useGo'
24 import { verifyTicketAPI } from '@/api/index' 50 import { verifyTicketAPI } from '@/api/index'
25 import Taro, { useDidShow } from '@tarojs/taro' 51 import Taro, { useDidShow } from '@tarojs/taro'
26 52
27 const router = useRouter() 53 const router = useRouter()
28 -// const go = useGo() 54 +const result_content = ref('')
29 -const resultContent = ref('') 55 +const verify_status = ref('idle')
30 -const msg = ref('核销成功') 56 +const msg = ref('请点击下方按钮进行核销')
57 +
58 +// TODO: 还没有真实字段信息, 如果有需要修改, 这个页面涉及verify_status的功能都要注意
59 +const status_title = computed(() => {
60 + if (verify_status.value === 'verifying') return '核销中'
61 + if (verify_status.value === 'success') return '核销成功'
62 + if (verify_status.value === 'fail') return '核销失败'
63 + return '核销'
64 +})
65 +
66 +const status_icon_type = computed(() => {
67 + if (verify_status.value === 'verifying') return 'waiting'
68 + if (verify_status.value === 'success') return 'success'
69 + if (verify_status.value === 'fail') return 'cancel'
70 + return 'info'
71 +})
72 +
73 +const status_icon_color = computed(() => {
74 + if (verify_status.value === 'fail') return '#E24A4A'
75 + return '#A67939'
76 +})
77 +/******************* END **********************/
78 +
79 +const verify_ticket = async (code) => {
80 + if (!code) return
81 + if (verify_status.value === 'verifying') return
82 +
83 + result_content.value = code
84 + verify_status.value = 'verifying'
85 + msg.value = '核销中...'
31 86
32 -useDidShow(async () => {
33 - resultContent.value = router.params.result || ''
34 - if (resultContent.value) {
35 Taro.showLoading({ title: '核销中...' }) 87 Taro.showLoading({ title: '核销中...' })
36 - const res = await verifyTicketAPI({ code: resultContent.value }) 88 + try {
37 - Taro.hideLoading() 89 + const res = await verifyTicketAPI({ code })
38 - if (res.code === 1) { 90 + if (res?.code) {
39 - msg.value = res.msg || '核销成功' 91 + verify_status.value = 'success'
40 - } else { 92 + msg.value = res?.msg || '核销成功'
41 - msg.value = res.msg || '核销失败' 93 + return
94 + }
95 + verify_status.value = 'fail'
96 + msg.value = res?.msg || '核销失败'
42 Taro.showToast({ title: msg.value, icon: 'none' }) 97 Taro.showToast({ title: msg.value, icon: 'none' })
98 + } catch (e) {
99 + verify_status.value = 'fail'
100 + msg.value = '核销失败'
101 + Taro.showToast({ title: msg.value, icon: 'none' })
102 + } finally {
103 + Taro.hideLoading()
43 } 104 }
105 +}
106 +
107 +useDidShow(async () => {
108 + /**
109 + * 现在主要用于:外部渠道如果手动带参进入则自动核销;正常业务流程(从义工登录进入)是不会带参的,会走缺省态 + 点击“核销”扫码。
110 + */
111 + const code = router?.params?.result || ''
112 + if (!code) {
113 + result_content.value = ''
114 + verify_status.value = 'idle'
115 + msg.value = '请点击下方按钮进行核销'
116 + return
44 } 117 }
118 + await verify_ticket(code)
45 }) 119 })
46 120
47 -const continueScan = () => { 121 +const start_scan_and_verify = () => {
48 Taro.scanCode({ 122 Taro.scanCode({
49 success: (res) => { 123 success: (res) => {
50 - // Reload current page with new result 124 + verify_ticket(res?.result || '')
51 - // Taro doesn't support easy reload with params change in same page easily without redirect
52 - // So we redirect to self
53 - Taro.redirectTo({
54 - url: `/pages/verificationResult/index?result=${res.result}`
55 - })
56 }, 125 },
57 fail: () => { 126 fail: () => {
58 - // Cancelled
59 } 127 }
60 }) 128 })
61 } 129 }
62 -
63 -// const goHome = () => {
64 -// Taro.reLaunch({ url: '/pages/index/index' })
65 -// }
66 </script> 130 </script>
67 131
68 <style lang="less"> 132 <style lang="less">
69 -.result-page { 133 +.verify-page {
70 - padding: 64rpx 32rpx; 134 + padding-bottom: 220rpx;
71 - text-align: center; 135 +}
72 - min-height: 100vh;
73 - background-color: #fff;
74 136
75 - .result-content { 137 +.verify-footer {
76 - display: flex; 138 + position: fixed;
77 - flex-direction: column; 139 + left: 0;
78 - align-items: center; 140 + right: 0;
79 - } 141 + bottom: 0;
142 + width: 750rpx;
143 + padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom));
144 + background-color: #FFFFFF;
145 + box-sizing: border-box;
146 + box-shadow: 0 -10rpx 8rpx 0 rgba(0,0,0,0.08);
147 +}
80 148
81 - .msg { 149 +.verify-btn {
82 - font-size: 40rpx; 150 + font-size: 36rpx;
83 - margin-top: 32rpx; 151 + height: 104rpx;
84 - font-weight: bold; 152 + line-height: 104rpx;
85 - color: #333; 153 + border-radius: 16rpx;
86 - } 154 + font-weight: 600;
87 - .info {
88 - margin-top: 20rpx;
89 - color: #999;
90 - font-size: 28rpx;
91 - word-break: break-all;
92 - padding: 0 32rpx;
93 - }
94 - .back-btn {
95 - margin-top: 80rpx;
96 - background-color: #A67939;
97 - color: #fff;
98 - width: 80%;
99 - border-radius: 44rpx;
100 - }
101 - .home-btn {
102 - margin-top: 32rpx;
103 - background-color: #fff;
104 - color: #666;
105 - width: 80%;
106 - border-radius: 44rpx;
107 - border: 1rpx solid #b0b0b0;
108 - }
109 } 155 }
110 </style> 156 </style>
......
1 <!-- 1 <!--
2 * @Date: 2026-01-08 13:01:56 2 * @Date: 2026-01-08 13:01:56
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-13 22:11:30 4 + * @LastEditTime: 2026-01-14 09:59:46
5 * @FilePath: /xyxBooking-weapp/src/pages/volunteerLogin/index.vue 5 * @FilePath: /xyxBooking-weapp/src/pages/volunteerLogin/index.vue
6 * @Description: 义工登录页面 6 * @Description: 义工登录页面
7 --> 7 -->
...@@ -43,17 +43,37 @@ ...@@ -43,17 +43,37 @@
43 43
44 <script setup> 44 <script setup>
45 import { ref } from 'vue' 45 import { ref } from 'vue'
46 -import Taro from '@tarojs/taro' 46 +import Taro, { useDidShow } from '@tarojs/taro'
47 import { mainStore } from '@/stores/main' 47 import { mainStore } from '@/stores/main'
48 import { volunteerLoginAPI, getUserInfoAPI } from '@/api/index' 48 import { volunteerLoginAPI, getUserInfoAPI } from '@/api/index'
49 -import { useGo } from '@/hooks/useGo' 49 +import { useReplace } from '@/hooks/useGo'
50 import logo from '@/assets/images/logo.png' 50 import logo from '@/assets/images/logo.png'
51 51
52 const store = mainStore() 52 const store = mainStore()
53 -const go = useGo() 53 +const replace = useReplace()
54 const username = ref('') 54 const username = ref('')
55 const password = ref('') 55 const password = ref('')
56 56
57 +/**
58 + * @description: 检查用户权限并根据角色重定向
59 + */
60 +
61 +const check_permission_and_redirect = async () => {
62 + try {
63 + const user_res = await getUserInfoAPI()
64 + if (user_res?.code === 1 && user_res?.data) {
65 + store.changeUserInfo(user_res.data)
66 + if (store.isVolunteer) {
67 + replace('verificationResult')
68 + }
69 + }
70 + } catch (e) {}
71 +}
72 +
73 +useDidShow(() => {
74 + check_permission_and_redirect()
75 +})
76 +
57 const handleLogin = async () => { 77 const handleLogin = async () => {
58 if (!username.value || !password.value) { 78 if (!username.value || !password.value) {
59 Taro.showToast({ title: '请输入账号密码', icon: 'none' }) 79 Taro.showToast({ title: '请输入账号密码', icon: 'none' })
...@@ -77,7 +97,7 @@ const handleLogin = async () => { ...@@ -77,7 +97,7 @@ const handleLogin = async () => {
77 if (store.isVolunteer) { 97 if (store.isVolunteer) {
78 Taro.showToast({ title: '登录成功', icon: 'success' }) 98 Taro.showToast({ title: '登录成功', icon: 'success' })
79 setTimeout(() => { 99 setTimeout(() => {
80 - triggerScan() 100 + replace('verificationResult')
81 }, 1500) 101 }, 1500)
82 } else { 102 } else {
83 Taro.showToast({ title: '非义工账号', icon: 'none' }) 103 Taro.showToast({ title: '非义工账号', icon: 'none' })
...@@ -90,17 +110,6 @@ const handleLogin = async () => { ...@@ -90,17 +110,6 @@ const handleLogin = async () => {
90 Taro.showToast({ title: loginRes.msg || '登录失败', icon: 'none' }) 110 Taro.showToast({ title: loginRes.msg || '登录失败', icon: 'none' })
91 } 111 }
92 } 112 }
93 -
94 -const triggerScan = () => {
95 - Taro.scanCode({
96 - success: (res) => {
97 - go(`/pages/verificationResult/index?result=${res.result}`)
98 - },
99 - fail: (err) => {
100 - console.log('Scan failed', err)
101 - }
102 - })
103 -}
104 </script> 113 </script>
105 114
106 <style lang="less"> 115 <style lang="less">
......