feat(核销): 重构义工核销流程,使用新接口和权限检查
- 替换模拟接口为真实核销接口 - 修改义工权限判断逻辑,使用 can_redeem 字段 - 优化登录流程,增加权限检查 - 更新核销结果页面显示逻辑
Showing
4 changed files
with
77 additions
and
105 deletions
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-08-24 09:42:27 | 2 | * @Date: 2023-08-24 09:42:27 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-13 23:13:04 | 4 | + * @LastEditTime: 2026-01-14 20:43:23 |
| 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js | 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -28,32 +28,25 @@ const Api = { | ... | @@ -28,32 +28,25 @@ const Api = { |
| 28 | QUERY_QR_CODE: '/srv/?a=api&t=id_number_query_qr_code', | 28 | QUERY_QR_CODE: '/srv/?a=api&t=id_number_query_qr_code', |
| 29 | ICBC_ORDER_QRY: '/srv/?a=icbc_orderqry', | 29 | ICBC_ORDER_QRY: '/srv/?a=icbc_orderqry', |
| 30 | WX_PAY: '/srv/?a=icbc_pay_wxamp', | 30 | WX_PAY: '/srv/?a=icbc_pay_wxamp', |
| 31 | - // TODO: 3个关于核销的接口都是假的, 等待真实接口 | 31 | + REDEEM_LOGIN: '/srv/?a=redeem&t=login', |
| 32 | - VOLUNTEER_LOGIN: '/srv/?a=api&t=volunteer_login', | 32 | + REDEEM_CHECK_AUTH: '/srv/?a=redeem&t=check_auth', |
| 33 | - VERIFY_TICKET: '/srv/?a=api&t=verify_ticket', | 33 | + REDEEM_REDEEM: '/srv/?a=redeem&t=redeem', |
| 34 | - GET_USER_INFO: '/srv/?a=api&t=get_user_info', | ||
| 35 | }; | 34 | }; |
| 36 | 35 | ||
| 37 | /** | 36 | /** |
| 38 | - * @description: 获取用户信息 (Mock) | 37 | + * @description: 义工登录 |
| 39 | */ | 38 | */ |
| 40 | -export const getUserInfoAPI = () => { | 39 | +export const volunteerLoginAPI = (params) => fn(fetch.post(Api.REDEEM_LOGIN, params)); |
| 41 | - return fn(fetch.get(Api.GET_USER_INFO)); | ||
| 42 | -}; | ||
| 43 | 40 | ||
| 44 | /** | 41 | /** |
| 45 | - * @description: 义工登录 (Mock) | 42 | + * @description: 检查核销权限 |
| 46 | */ | 43 | */ |
| 47 | -export const volunteerLoginAPI = (params) => { | 44 | +export const checkRedeemPermissionAPI = (params) => fn(fetch.get(Api.REDEEM_CHECK_AUTH, params)); |
| 48 | - return fn(fetch.post(Api.VOLUNTEER_LOGIN, params)); | ||
| 49 | -}; | ||
| 50 | 45 | ||
| 51 | /** | 46 | /** |
| 52 | - * @description: 核销门票 (Mock) | 47 | + * @description: 核销 |
| 53 | */ | 48 | */ |
| 54 | -export const verifyTicketAPI = (params) => { | 49 | +export const verifyTicketAPI = (params) => fn(fetch.post(Api.REDEEM_REDEEM, params)); |
| 55 | - return fn(fetch.post(Api.VERIFY_TICKET, params)); | ||
| 56 | -}; | ||
| 57 | 50 | ||
| 58 | /** | 51 | /** |
| 59 | * @description: 可预约日期列表 | 52 | * @description: 可预约日期列表 | ... | ... |
| ... | @@ -19,23 +19,16 @@ | ... | @@ -19,23 +19,16 @@ |
| 19 | </view> | 19 | </view> |
| 20 | </view> | 20 | </view> |
| 21 | 21 | ||
| 22 | - <view v-if="verify_result_text" class="mt-4 rounded-2xl bg-white p-5 shadow-sm"> | 22 | + <view class="mt-4 rounded-2xl bg-white p-5 shadow-sm"> |
| 23 | - <view class="text-xs text-gray-500">核销结果</view> | 23 | + <view class="text-xs text-gray-500">核销权限</view> |
| 24 | - <view class="mt-2 break-all whitespace-pre-wrap text-sm font-medium text-gray-900">{{ verify_result_text }}</view> | 24 | + <view class="mt-2 text-sm font-medium text-gray-900">{{ can_redeem_text }}</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> | 25 | </view> |
| 30 | 26 | ||
| 31 | - <!-- <view v-if="verify_code" class="mt-4 rounded-2xl bg-white p-5 shadow-sm"> | 27 | + <view class="mt-4 rounded-2xl bg-white p-5 shadow-sm"> |
| 32 | - <view class="text-xs text-gray-500">预约码</view> | 28 | + <view class="text-xs text-gray-500">最近一次扫码内容</view> |
| 33 | - <view class="mt-2 break-all text-sm font-medium text-gray-900">{{ verify_code }}</view> | 29 | + <view v-if="verify_code" class="mt-2 break-all whitespace-pre-wrap text-sm font-medium text-gray-900">{{ verify_code }}</view> |
| 30 | + <view v-else class="mt-2 text-sm text-gray-400">暂无扫码内容</view> | ||
| 34 | </view> | 31 | </view> |
| 35 | - <view v-else class="mt-4 rounded-2xl bg-white p-5 shadow-sm"> | ||
| 36 | - <view class="text-xs text-gray-500">预约码</view> | ||
| 37 | - <view class="mt-2 text-sm text-gray-400">暂无预约码</view> | ||
| 38 | - </view> --> | ||
| 39 | 32 | ||
| 40 | <view class="verify-footer"> | 33 | <view class="verify-footer"> |
| 41 | <nut-button | 34 | <nut-button |
| ... | @@ -56,14 +49,17 @@ | ... | @@ -56,14 +49,17 @@ |
| 56 | <script setup> | 49 | <script setup> |
| 57 | import { ref, computed } from 'vue' | 50 | import { ref, computed } from 'vue' |
| 58 | import { useRouter } from '@tarojs/taro' | 51 | import { useRouter } from '@tarojs/taro' |
| 59 | -import { verifyTicketAPI } from '@/api/index' | 52 | +import { verifyTicketAPI, checkRedeemPermissionAPI } from '@/api/index' |
| 60 | import Taro, { useDidShow } from '@tarojs/taro' | 53 | import Taro, { useDidShow } from '@tarojs/taro' |
| 54 | +import { mainStore } from '@/stores/main' | ||
| 55 | +import { useReplace } from '@/hooks/useGo' | ||
| 61 | 56 | ||
| 62 | const router = useRouter() | 57 | const router = useRouter() |
| 63 | const verify_code = ref('') | 58 | const verify_code = ref('') |
| 64 | -const verify_result = ref(null) | ||
| 65 | const verify_status = ref('idle') | 59 | const verify_status = ref('idle') |
| 66 | const msg = ref('请点击下方按钮进行核销') | 60 | const msg = ref('请点击下方按钮进行核销') |
| 61 | +const store = mainStore() | ||
| 62 | +const replace = useReplace() | ||
| 67 | 63 | ||
| 68 | // TODO: 还没有真实字段信息, 如果有需要修改, 这个页面涉及verify_status的功能都要注意 | 64 | // TODO: 还没有真实字段信息, 如果有需要修改, 这个页面涉及verify_status的功能都要注意 |
| 69 | const status_title = computed(() => { | 65 | const status_title = computed(() => { |
| ... | @@ -85,16 +81,9 @@ const status_icon_color = computed(() => { | ... | @@ -85,16 +81,9 @@ const status_icon_color = computed(() => { |
| 85 | return '#A67939' | 81 | return '#A67939' |
| 86 | }) | 82 | }) |
| 87 | 83 | ||
| 88 | -const verify_result_text = computed(() => { | 84 | +const can_redeem_text = computed(() => { |
| 89 | - const data = verify_result.value | 85 | + if (store?.appUserInfo?.can_redeem === true) return '已授权' |
| 90 | - if (data === null || data === undefined) return '' | 86 | + return '未授权' |
| 91 | - if (typeof data === 'string') return data | ||
| 92 | - if (typeof data === 'number' || typeof data === 'boolean') return String(data) | ||
| 93 | - try { | ||
| 94 | - return JSON.stringify(data, null, 2) | ||
| 95 | - } catch (e) { | ||
| 96 | - return '' | ||
| 97 | - } | ||
| 98 | }) | 87 | }) |
| 99 | 88 | ||
| 100 | const verify_ticket = async (code) => { | 89 | const verify_ticket = async (code) => { |
| ... | @@ -102,26 +91,19 @@ const verify_ticket = async (code) => { | ... | @@ -102,26 +91,19 @@ const verify_ticket = async (code) => { |
| 102 | if (verify_status.value === 'verifying') return | 91 | if (verify_status.value === 'verifying') return |
| 103 | 92 | ||
| 104 | verify_code.value = code | 93 | verify_code.value = code |
| 105 | - verify_result.value = null | ||
| 106 | verify_status.value = 'verifying' | 94 | verify_status.value = 'verifying' |
| 107 | msg.value = '核销中...' | 95 | msg.value = '核销中...' |
| 108 | 96 | ||
| 109 | Taro.showLoading({ title: '核销中...' }) | 97 | Taro.showLoading({ title: '核销中...' }) |
| 110 | try { | 98 | try { |
| 111 | - const res = await verifyTicketAPI({ code }) | 99 | + const res = await verifyTicketAPI({ qr_code: code }) |
| 112 | if (res?.code === 1) { | 100 | if (res?.code === 1) { |
| 113 | verify_status.value = 'success' | 101 | verify_status.value = 'success' |
| 114 | msg.value = res?.msg || '核销成功' | 102 | msg.value = res?.msg || '核销成功' |
| 115 | - if (res?.data !== undefined && res?.data !== null && res?.data !== '') { | ||
| 116 | - verify_result.value = res.data | ||
| 117 | - } | ||
| 118 | return | 103 | return |
| 119 | } | 104 | } |
| 120 | verify_status.value = 'fail' | 105 | verify_status.value = 'fail' |
| 121 | msg.value = res?.msg || '核销失败' | 106 | msg.value = res?.msg || '核销失败' |
| 122 | - if (res?.data !== undefined && res?.data !== null && res?.data !== '') { | ||
| 123 | - verify_result.value = res.data | ||
| 124 | - } | ||
| 125 | Taro.showToast({ title: msg.value, icon: 'none' }) | 107 | Taro.showToast({ title: msg.value, icon: 'none' }) |
| 126 | } catch (e) { | 108 | } catch (e) { |
| 127 | verify_status.value = 'fail' | 109 | verify_status.value = 'fail' |
| ... | @@ -133,10 +115,21 @@ const verify_ticket = async (code) => { | ... | @@ -133,10 +115,21 @@ const verify_ticket = async (code) => { |
| 133 | } | 115 | } |
| 134 | 116 | ||
| 135 | useDidShow(async () => { | 117 | useDidShow(async () => { |
| 118 | + const permission_res = await checkRedeemPermissionAPI() | ||
| 119 | + if (permission_res?.code !== 1) { | ||
| 120 | + replace('volunteerLogin') | ||
| 121 | + return | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + if (permission_res?.data) store.changeUserInfo(permission_res.data) | ||
| 125 | + if (permission_res?.data?.can_redeem !== true) { | ||
| 126 | + replace('volunteerLogin') | ||
| 127 | + return | ||
| 128 | + } | ||
| 129 | + | ||
| 136 | const code = router?.params?.result || '' | 130 | const code = router?.params?.result || '' |
| 137 | if (!code) { | 131 | if (!code) { |
| 138 | verify_code.value = '' | 132 | verify_code.value = '' |
| 139 | - verify_result.value = null | ||
| 140 | verify_status.value = 'idle' | 133 | verify_status.value = 'idle' |
| 141 | msg.value = '请点击下方按钮进行核销' | 134 | msg.value = '请点击下方按钮进行核销' |
| 142 | return | 135 | return | ... | ... |
| 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-14 10:18:59 | 4 | + * @LastEditTime: 2026-01-14 20:49:12 |
| 5 | * @FilePath: /xyxBooking-weapp/src/pages/volunteerLogin/index.vue | 5 | * @FilePath: /xyxBooking-weapp/src/pages/volunteerLogin/index.vue |
| 6 | * @Description: 义工登录页面 | 6 | * @Description: 义工登录页面 |
| 7 | --> | 7 | --> |
| ... | @@ -17,23 +17,13 @@ | ... | @@ -17,23 +17,13 @@ |
| 17 | 17 | ||
| 18 | <view class="input-group"> | 18 | <view class="input-group"> |
| 19 | <text class="label">账号</text> | 19 | <text class="label">账号</text> |
| 20 | - <input | 20 | + <input v-model="username" placeholder="请输入账号" placeholder-class="input-placeholder" cursorSpacing="40rpx" /> |
| 21 | - v-model="username" | ||
| 22 | - placeholder="请输入账号" | ||
| 23 | - placeholder-class="input-placeholder" | ||
| 24 | - cursorSpacing="40rpx" | ||
| 25 | - /> | ||
| 26 | </view> | 21 | </view> |
| 27 | 22 | ||
| 28 | <view class="input-group"> | 23 | <view class="input-group"> |
| 29 | <text class="label">密码</text> | 24 | <text class="label">密码</text> |
| 30 | - <input | 25 | + <input v-model="password" password placeholder="请输入密码" placeholder-class="input-placeholder" |
| 31 | - v-model="password" | 26 | + cursorSpacing="40rpx" /> |
| 32 | - password | ||
| 33 | - placeholder="请输入密码" | ||
| 34 | - placeholder-class="input-placeholder" | ||
| 35 | - cursorSpacing="40rpx" | ||
| 36 | - /> | ||
| 37 | </view> | 27 | </view> |
| 38 | 28 | ||
| 39 | <button class="login-btn" @tap="handleLogin">立即登录</button> | 29 | <button class="login-btn" @tap="handleLogin">立即登录</button> |
| ... | @@ -45,7 +35,7 @@ | ... | @@ -45,7 +35,7 @@ |
| 45 | import { ref } from 'vue' | 35 | import { ref } from 'vue' |
| 46 | import Taro, { useDidShow } from '@tarojs/taro' | 36 | import Taro, { useDidShow } from '@tarojs/taro' |
| 47 | import { mainStore } from '@/stores/main' | 37 | import { mainStore } from '@/stores/main' |
| 48 | -import { volunteerLoginAPI, getUserInfoAPI } from '@/api/index' | 38 | +import { volunteerLoginAPI, checkRedeemPermissionAPI } from '@/api/index' |
| 49 | import { useReplace } from '@/hooks/useGo' | 39 | import { useReplace } from '@/hooks/useGo' |
| 50 | import logo from '@/assets/images/logo.png' | 40 | import logo from '@/assets/images/logo.png' |
| 51 | 41 | ||
| ... | @@ -55,26 +45,22 @@ const username = ref('') | ... | @@ -55,26 +45,22 @@ const username = ref('') |
| 55 | const password = ref('') | 45 | const password = ref('') |
| 56 | 46 | ||
| 57 | /** | 47 | /** |
| 58 | - * @description: 检查用户权限并根据角色重定向 | 48 | + * @description: 检查核销权限并重定向 |
| 59 | */ | 49 | */ |
| 60 | 50 | ||
| 61 | const check_permission_and_redirect = async () => { | 51 | const check_permission_and_redirect = async () => { |
| 62 | try { | 52 | try { |
| 63 | - const user_res = await getUserInfoAPI() | 53 | + const permission_res = await checkRedeemPermissionAPI() |
| 64 | - if (user_res?.code === 1 && user_res?.data) { | 54 | + if (permission_res?.code !== 1) return |
| 65 | - store.changeUserInfo(user_res.data) | 55 | + if (permission_res?.data) store.changeUserInfo(permission_res.data) |
| 66 | - if (store.isVolunteer) { | 56 | + if (permission_res?.data?.can_redeem === true) replace('verificationResult') |
| 67 | - replace('verificationResult') | 57 | + } catch (e) { } |
| 68 | - } | ||
| 69 | - } | ||
| 70 | - } catch (e) {} | ||
| 71 | } | 58 | } |
| 72 | 59 | ||
| 73 | useDidShow(() => { | 60 | useDidShow(() => { |
| 74 | check_permission_and_redirect() | 61 | check_permission_and_redirect() |
| 75 | }) | 62 | }) |
| 76 | 63 | ||
| 77 | -// TODO: 功能需要联调, 登录功能都是模拟, 实际登录需要后端接口支持 | ||
| 78 | const handleLogin = async () => { | 64 | const handleLogin = async () => { |
| 79 | if (!username.value || !password.value) { | 65 | if (!username.value || !password.value) { |
| 80 | Taro.showToast({ title: '请输入账号密码', icon: 'none' }) | 66 | Taro.showToast({ title: '请输入账号密码', icon: 'none' }) |
| ... | @@ -82,34 +68,32 @@ const handleLogin = async () => { | ... | @@ -82,34 +68,32 @@ const handleLogin = async () => { |
| 82 | } | 68 | } |
| 83 | 69 | ||
| 84 | Taro.showLoading({ title: '登录中...' }) | 70 | Taro.showLoading({ title: '登录中...' }) |
| 85 | - // 1. 执行登录 | 71 | + const login_res = await volunteerLoginAPI({ username: username.value, password: password.value }) |
| 86 | - const loginRes = await volunteerLoginAPI({ username: username.value, password: password.value }) | ||
| 87 | - | ||
| 88 | - if (loginRes.code === 1) { | ||
| 89 | - // 2. 登录成功后,获取用户信息来验证和更新状态 | ||
| 90 | - const userRes = await getUserInfoAPI() | ||
| 91 | Taro.hideLoading() | 72 | Taro.hideLoading() |
| 92 | 73 | ||
| 93 | - if (userRes.code === 1 && userRes.data) { | 74 | + if (login_res?.code !== 1) { |
| 94 | - // 更新 store 中的用户信息 (isVolunteer 会自动通过 getter 更新) | 75 | + Taro.showToast({ title: login_res?.msg || '登录失败', icon: 'none' }) |
| 95 | - store.changeUserInfo(userRes.data) | 76 | + return |
| 96 | - | ||
| 97 | - // TODO: 这是模拟功能, 检查是否为义工账号 | ||
| 98 | - if (store.isVolunteer) { | ||
| 99 | - Taro.showToast({ title: '登录成功', icon: 'success' }) | ||
| 100 | - setTimeout(() => { | ||
| 101 | - replace('verificationResult') | ||
| 102 | - }, 1500) | ||
| 103 | - } else { | ||
| 104 | - Taro.showToast({ title: '非义工账号', icon: 'none' }) | ||
| 105 | - } | ||
| 106 | - } else { | ||
| 107 | - Taro.showToast({ title: '获取用户信息失败', icon: 'none' }) | ||
| 108 | } | 77 | } |
| 109 | - } else { | 78 | + |
| 79 | + Taro.showLoading({ title: '校验权限中...' }) | ||
| 80 | + const permission_res = await checkRedeemPermissionAPI() | ||
| 110 | Taro.hideLoading() | 81 | Taro.hideLoading() |
| 111 | - Taro.showToast({ title: loginRes.msg || '登录失败', icon: 'none' }) | 82 | + |
| 83 | + if (permission_res?.code !== 1) { | ||
| 84 | + Taro.showToast({ title: permission_res?.msg || '权限校验失败', icon: 'none' }) | ||
| 85 | + return | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + if (permission_res?.data) store.changeUserInfo(permission_res.data) | ||
| 89 | + | ||
| 90 | + if (permission_res?.data?.can_redeem === true) { | ||
| 91 | + Taro.showToast({ title: permission_res?.msg || login_res?.msg || '登录成功', icon: 'success' }) | ||
| 92 | + setTimeout(() => replace('verificationResult'), 1200) | ||
| 93 | + return | ||
| 112 | } | 94 | } |
| 95 | + | ||
| 96 | + Taro.showToast({ title: permission_res?.msg || '暂无核销权限', icon: 'none' }) | ||
| 113 | } | 97 | } |
| 114 | </script> | 98 | </script> |
| 115 | 99 | ||
| ... | @@ -127,14 +111,16 @@ const handleLogin = async () => { | ... | @@ -127,14 +111,16 @@ const handleLogin = async () => { |
| 127 | flex-direction: column; | 111 | flex-direction: column; |
| 128 | align-items: center; | 112 | align-items: center; |
| 129 | margin-bottom: 60rpx; | 113 | margin-bottom: 60rpx; |
| 114 | + | ||
| 130 | image { | 115 | image { |
| 131 | width: 120rpx; | 116 | width: 120rpx; |
| 132 | height: 120rpx; | 117 | height: 120rpx; |
| 133 | border-radius: 50%; | 118 | border-radius: 50%; |
| 134 | margin-bottom: 24rpx; | 119 | margin-bottom: 24rpx; |
| 135 | - box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.1); | 120 | + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1); |
| 136 | background-color: #fff; | 121 | background-color: #fff; |
| 137 | } | 122 | } |
| 123 | + | ||
| 138 | .app-name { | 124 | .app-name { |
| 139 | font-size: 36rpx; | 125 | font-size: 36rpx; |
| 140 | font-weight: 600; | 126 | font-weight: 600; |
| ... | @@ -148,7 +134,7 @@ const handleLogin = async () => { | ... | @@ -148,7 +134,7 @@ const handleLogin = async () => { |
| 148 | background: #fff; | 134 | background: #fff; |
| 149 | border-radius: 24rpx; | 135 | border-radius: 24rpx; |
| 150 | padding: 60rpx 40rpx; | 136 | padding: 60rpx 40rpx; |
| 151 | - box-shadow: 0 12rpx 40rpx rgba(0,0,0,0.04); | 137 | + box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.04); |
| 152 | box-sizing: border-box; | 138 | box-sizing: border-box; |
| 153 | 139 | ||
| 154 | .title { | 140 | .title { | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2022-04-18 15:59:42 | 2 | * @Date: 2022-04-18 15:59:42 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2024-01-30 15:26:30 | 4 | + * @LastEditTime: 2026-01-14 20:43:54 |
| 5 | * @FilePath: /xyxBooking-weapp/src/stores/main.js | 5 | * @FilePath: /xyxBooking-weapp/src/stores/main.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -18,9 +18,9 @@ export const mainStore = defineStore('main', { | ... | @@ -18,9 +18,9 @@ export const mainStore = defineStore('main', { |
| 18 | }; | 18 | }; |
| 19 | }, | 19 | }, |
| 20 | getters: { | 20 | getters: { |
| 21 | - // 判断是否为义工 (基于 appUserInfo 中的 role 字段) | 21 | + // 判断是否为义工 |
| 22 | isVolunteer: (state) => { | 22 | isVolunteer: (state) => { |
| 23 | - return state.appUserInfo && state.appUserInfo.role === 'volunteer'; | 23 | + return !!(state.appUserInfo && (state.appUserInfo.can_redeem === true)); |
| 24 | }, | 24 | }, |
| 25 | }, | 25 | }, |
| 26 | actions: { | 26 | actions: { | ... | ... |
-
Please register or login to post a comment