feat: 新增西园寺预约小程序功能
新增预约码、参观者管理、预约记录等功能模块 添加预约流程页面及状态管理 集成微信支付和身份证验证 优化UI设计及用户体验 更新依赖包和工具函数
Showing
74 changed files
with
2979 additions
and
465 deletions
| ... | @@ -9,9 +9,19 @@ declare module 'vue' { | ... | @@ -9,9 +9,19 @@ declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] | 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] |
| 11 | NutButton: typeof import('@nutui/nutui-taro')['Button'] | 11 | NutButton: typeof import('@nutui/nutui-taro')['Button'] |
| 12 | - NutToast: typeof import('@nutui/nutui-taro')['Toast'] | 12 | + NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox'] |
| 13 | + NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup'] | ||
| 14 | + NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] | ||
| 15 | + NutForm: typeof import('@nutui/nutui-taro')['Form'] | ||
| 16 | + NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] | ||
| 17 | + NutIcon: typeof import('@nutui/nutui-taro')['Icon'] | ||
| 18 | + NutInput: typeof import('@nutui/nutui-taro')['Input'] | ||
| 19 | + NutPopup: typeof import('@nutui/nutui-taro')['Popup'] | ||
| 13 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 20 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 14 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 21 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 22 | + QrCode: typeof import('./src/components/qrCode.vue')['default'] | ||
| 23 | + QrCodeSearch: typeof import('./src/components/qrCodeSearch.vue')['default'] | ||
| 24 | + ReserveCard: typeof import('./src/components/reserveCard.vue')['default'] | ||
| 15 | RouterLink: typeof import('vue-router')['RouterLink'] | 25 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 16 | RouterView: typeof import('vue-router')['RouterView'] | 26 | RouterView: typeof import('vue-router')['RouterView'] |
| 17 | } | 27 | } | ... | ... |
| ... | @@ -54,9 +54,12 @@ | ... | @@ -54,9 +54,12 @@ |
| 54 | "@tarojs/shared": "4.1.9", | 54 | "@tarojs/shared": "4.1.9", |
| 55 | "@tarojs/taro": "4.1.9", | 55 | "@tarojs/taro": "4.1.9", |
| 56 | "axios-miniprogram": "^2.7.2", | 56 | "axios-miniprogram": "^2.7.2", |
| 57 | + "dayjs": "^1.11.19", | ||
| 57 | "pinia": "^3.0.3", | 58 | "pinia": "^3.0.3", |
| 59 | + "qs": "^6.14.1", | ||
| 58 | "taro-plugin-pinia": "^1.0.0", | 60 | "taro-plugin-pinia": "^1.0.0", |
| 59 | - "vue": "^3.3.0" | 61 | + "vue": "^3.3.0", |
| 62 | + "xst-solar2lunar": "^2.1.0" | ||
| 60 | }, | 63 | }, |
| 61 | "devDependencies": { | 64 | "devDependencies": { |
| 62 | "@babel/core": "^7.26.0", | 65 | "@babel/core": "^7.26.0", | ... | ... |
| ... | @@ -62,15 +62,24 @@ importers: | ... | @@ -62,15 +62,24 @@ importers: |
| 62 | axios-miniprogram: | 62 | axios-miniprogram: |
| 63 | specifier: ^2.7.2 | 63 | specifier: ^2.7.2 |
| 64 | version: 2.7.2 | 64 | version: 2.7.2 |
| 65 | + dayjs: | ||
| 66 | + specifier: ^1.11.19 | ||
| 67 | + version: 1.11.19 | ||
| 65 | pinia: | 68 | pinia: |
| 66 | specifier: ^3.0.3 | 69 | specifier: ^3.0.3 |
| 67 | version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) | 70 | version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) |
| 71 | + qs: | ||
| 72 | + specifier: ^6.14.1 | ||
| 73 | + version: 6.14.1 | ||
| 68 | taro-plugin-pinia: | 74 | taro-plugin-pinia: |
| 69 | specifier: ^1.0.0 | 75 | specifier: ^1.0.0 |
| 70 | version: 1.0.0 | 76 | version: 1.0.0 |
| 71 | vue: | 77 | vue: |
| 72 | specifier: ^3.3.0 | 78 | specifier: ^3.3.0 |
| 73 | version: 3.5.26(typescript@5.9.3) | 79 | version: 3.5.26(typescript@5.9.3) |
| 80 | + xst-solar2lunar: | ||
| 81 | + specifier: ^2.1.0 | ||
| 82 | + version: 2.1.0 | ||
| 74 | devDependencies: | 83 | devDependencies: |
| 75 | '@babel/core': | 84 | '@babel/core': |
| 76 | specifier: ^7.26.0 | 85 | specifier: ^7.26.0 |
| ... | @@ -3039,6 +3048,9 @@ packages: | ... | @@ -3039,6 +3048,9 @@ packages: |
| 3039 | resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} | 3048 | resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} |
| 3040 | engines: {node: '>= 0.4'} | 3049 | engines: {node: '>= 0.4'} |
| 3041 | 3050 | ||
| 3051 | + dayjs@1.11.19: | ||
| 3052 | + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} | ||
| 3053 | + | ||
| 3042 | debug@2.6.9: | 3054 | debug@2.6.9: |
| 3043 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} | 3055 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} |
| 3044 | peerDependencies: | 3056 | peerDependencies: |
| ... | @@ -6693,6 +6705,9 @@ packages: | ... | @@ -6693,6 +6705,9 @@ packages: |
| 6693 | xmlchars@2.2.0: | 6705 | xmlchars@2.2.0: |
| 6694 | resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} | 6706 | resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} |
| 6695 | 6707 | ||
| 6708 | + xst-solar2lunar@2.1.0: | ||
| 6709 | + resolution: {integrity: sha512-1X2Enk2LK1l6ZQWjSFQsLspmm6h32p8a+UGYi+HkJLEQmKiy5KSlTs2xEiyyAAG+7jTo6EOxPWS2lk3yLk/ivg==} | ||
| 6710 | + | ||
| 6696 | xtend@4.0.2: | 6711 | xtend@4.0.2: |
| 6697 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} | 6712 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} |
| 6698 | engines: {node: '>=0.4'} | 6713 | engines: {node: '>=0.4'} |
| ... | @@ -10036,6 +10051,8 @@ snapshots: | ... | @@ -10036,6 +10051,8 @@ snapshots: |
| 10036 | es-errors: 1.3.0 | 10051 | es-errors: 1.3.0 |
| 10037 | is-data-view: 1.0.2 | 10052 | is-data-view: 1.0.2 |
| 10038 | 10053 | ||
| 10054 | + dayjs@1.11.19: {} | ||
| 10055 | + | ||
| 10039 | debug@2.6.9: | 10056 | debug@2.6.9: |
| 10040 | dependencies: | 10057 | dependencies: |
| 10041 | ms: 2.0.0 | 10058 | ms: 2.0.0 |
| ... | @@ -14129,6 +14146,10 @@ snapshots: | ... | @@ -14129,6 +14146,10 @@ snapshots: |
| 14129 | 14146 | ||
| 14130 | xmlchars@2.2.0: {} | 14147 | xmlchars@2.2.0: {} |
| 14131 | 14148 | ||
| 14149 | + xst-solar2lunar@2.1.0: | ||
| 14150 | + dependencies: | ||
| 14151 | + dayjs: 1.11.19 | ||
| 14152 | + | ||
| 14132 | xtend@4.0.2: {} | 14153 | xtend@4.0.2: {} |
| 14133 | 14154 | ||
| 14134 | xxhashjs@0.2.2: | 14155 | xxhashjs@0.2.2: | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2022-05-18 22:56:08 | 2 | * @Date: 2022-05-18 22:56:08 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2024-05-25 22:35:00 | 4 | + * @LastEditTime: 2026-01-06 20:56:55 |
| 5 | - * @FilePath: /meihuaApp/src/api/fn.js | 5 | + * @FilePath: /git/xyxBooking-weapp/src/api/fn.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | import axios from '@/utils/request'; | 8 | import axios from '@/utils/request'; |
| ... | @@ -17,13 +17,15 @@ import Taro from '@tarojs/taro' | ... | @@ -17,13 +17,15 @@ import Taro from '@tarojs/taro' |
| 17 | export const fn = (api) => { | 17 | export const fn = (api) => { |
| 18 | return api | 18 | return api |
| 19 | .then(res => { | 19 | .then(res => { |
| 20 | - if (res.data.code) { | 20 | + // 适配 H5 逻辑,code === 1 为成功 |
| 21 | + if (res.data.code === 1) { | ||
| 21 | return res.data || true; | 22 | return res.data || true; |
| 22 | } else { | 23 | } else { |
| 23 | // tslint:disable-next-line: no-console | 24 | // tslint:disable-next-line: no-console |
| 24 | console.warn(res); | 25 | console.warn(res); |
| 26 | + if (res.data.show === false) return false; | ||
| 25 | Taro.showToast({ | 27 | Taro.showToast({ |
| 26 | - title: res.data.msg, | 28 | + title: res.data.msg || '请求失败', |
| 27 | icon: 'none', | 29 | icon: 'none', |
| 28 | duration: 2000 | 30 | duration: 2000 |
| 29 | }); | 31 | }); |
| ... | @@ -52,6 +54,7 @@ export const uploadFn = (api) => { | ... | @@ -52,6 +54,7 @@ export const uploadFn = (api) => { |
| 52 | } else { | 54 | } else { |
| 53 | // tslint:disable-next-line: no-console | 55 | // tslint:disable-next-line: no-console |
| 54 | console.warn(res); | 56 | console.warn(res); |
| 57 | + if (!res.data.show) return false; | ||
| 55 | Taro.showToast({ | 58 | Taro.showToast({ |
| 56 | title: res.data.msg, | 59 | title: res.data.msg, |
| 57 | icon: 'none', | 60 | icon: 'none', |
| ... | @@ -72,7 +75,7 @@ export const uploadFn = (api) => { | ... | @@ -72,7 +75,7 @@ export const uploadFn = (api) => { |
| 72 | */ | 75 | */ |
| 73 | export const fetch = { | 76 | export const fetch = { |
| 74 | get: function (api, params) { | 77 | get: function (api, params) { |
| 75 | - return axios.get(api, params) | 78 | + return axios.get(api, { params }) // 注意 axios-miniprogram 的 get 参数通常也是放在 config 对象中, key 为 params |
| 76 | }, | 79 | }, |
| 77 | post: function (api, params) { | 80 | post: function (api, params) { |
| 78 | return axios.post(api, params) | 81 | return axios.post(api, params) | ... | ... |
| 1 | /* | 1 | /* |
| 2 | - * @Date: 2023-12-22 10:29:37 | 2 | + * @Date: 2023-08-24 09:42:27 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2024-06-06 09:31:34 | 4 | + * @LastEditTime: 2024-01-29 17:26:42 |
| 5 | - * @FilePath: /meihuaApp/src/api/index.js | 5 | + * @FilePath: /xyxBooking-weapp/src/api/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | -import { fn, fetch } from './fn'; | 8 | +import { fn, fetch } from '@/api/fn'; |
| 9 | 9 | ||
| 10 | const Api = { | 10 | const Api = { |
| 11 | - BIND_PHONE: '/srv/?a=room_order&t=bind_phone', | 11 | + CAN_RESERVE_DATE_LIST: '/srv/?a=api&t=can_reserve_date_list', |
| 12 | - SEND_SMS_CODE: '/srv/?a=room_order&t=send_sms_code', | 12 | + CAN_RESERVE_TIME_LIST: '/srv/?a=api&t=can_reserve_time_list', |
| 13 | - SHOW_SESSION: '/srv/?a=room_order&t=show_session', | 13 | + PERSON_LIST: '/srv/?a=api&t=person_list', |
| 14 | - SAVE_CUSTOMER_INFO: '/srv/?a=room_order&t=save_customer_info', | 14 | + ADD_PERSON: '/srv/?a=api&t=add_person', |
| 15 | - SYS_PARAM: '/srv/?a=room_order&t=sys_param', | 15 | + DEL_PERSON: '/srv/?a=api&t=del_person', |
| 16 | - GET_LIST: '/srv/?a=room_data&t=get_list', | 16 | + ADD_RESERVE: '/srv/?a=api&t=add_reserve', |
| 17 | - GET_ROOM: '/srv/?a=room_data&t=get_room', | 17 | + PAY_PREPARE: '/srv/?a=api&t=pay_prepare', |
| 18 | - ADD_ORDER: '/srv/?a=room_data&t=add_order', | 18 | + PAY_CALLBACK: '/srv/?a=api&t=pay_callback', |
| 19 | - MY_ORDER: '/srv/?a=room_data&t=my_order', | 19 | + BILL_INFO: '/srv/?a=api&t=bill_info', |
| 20 | - ORDER_CANCEL: '/srv/?a=room_data&t=order_cancel', | 20 | + ON_AUTH_BILL_INFO: '/srv/?a=no_auth_api&t=bill_info', |
| 21 | - PAY: '/srv/?a=pay', | 21 | + QRCODE_LIST: '/srv/?a=api&t=qrcode_list', |
| 22 | - PAY_CHECK: '/srv/?a=pay_check', | 22 | + QRCODE_STATUS: '/srv/?a=api&t=qrcode_status', |
| 23 | - ORDER_SUCCESS: '/srv/?a=room_data&t=order_success', | 23 | + BILL_LIST: '/srv/?a=api&t=bill_list', |
| 24 | - TMP_SYS_PARAM: '/srv/?a=get_item', | 24 | + ICBC_REFUND: '/srv/?a=icbc_refund', |
| 25 | -} | 25 | + BILL_PREPARE: '/srv/?a=api&t=bill_person', |
| 26 | - | 26 | + BILL_PAY_STATUS: '/srv/?a=api&t=bill_pay_status', |
| 27 | -/** | 27 | + QUERY_QR_CODE: '/srv/?a=api&t=id_number_query_qr_code', |
| 28 | - * @description: 绑定手机号(手机号登录) | 28 | + ICBC_ORDER_QRY: '/srv/?a=icbc_orderqry', |
| 29 | - * @param phone 手机号 | 29 | +}; |
| 30 | - * @param sms_code 验证码 | 30 | + |
| 31 | +/** | ||
| 32 | + * @description: 可预约日期列表 | ||
| 33 | + * @param {Array} month 月份,格式yyyy-mm | ||
| 31 | * @returns | 34 | * @returns |
| 32 | */ | 35 | */ |
| 33 | -export const bindPhoneAPI = (params) => fn(fetch.post(Api.BIND_PHONE, params)); | 36 | +export const canReserveDateListAPI = (params) => fn(fetch.get(Api.CAN_RESERVE_DATE_LIST, params)); |
| 34 | 37 | ||
| 35 | /** | 38 | /** |
| 36 | - * @description: 发送验证码 | 39 | + * @description: 可预约时段列表 |
| 37 | - * @param phone 手机号 | 40 | + * @param {Array} month_date 日期,格式yyyy-mm-dd |
| 38 | * @returns | 41 | * @returns |
| 39 | */ | 42 | */ |
| 40 | -export const sendSmsCodeAPI = (params) => fn(fetch.post(Api.SEND_SMS_CODE, params)); | 43 | +export const canReserveTimeListAPI = (params) => fn(fetch.get(Api.CAN_RESERVE_TIME_LIST, params)); |
| 41 | 44 | ||
| 42 | /** | 45 | /** |
| 43 | - * @description: 获取我的信息 | 46 | + * @description: 参观者列表 |
| 47 | + * @param {String} reserve_date 预约日期,格式 yyyy-mm-dd,没有传入则不查询指定日期是否已预约 | ||
| 48 | + * @param {String} begin_time 时段开始时间,格式 hh:mm | ||
| 49 | + * @param {String} end_time 时段结束时间,格式 hh:mm | ||
| 44 | * @returns | 50 | * @returns |
| 45 | */ | 51 | */ |
| 46 | -export const showMyInfoAPI = (params) => fn(fetch.get(Api.SHOW_SESSION, params)); | 52 | +export const personListAPI = (params) => fn(fetch.get(Api.PERSON_LIST, params)); |
| 47 | 53 | ||
| 48 | /** | 54 | /** |
| 49 | - * @description: 保存我的信息 | 55 | + * @description: 添加参观者 |
| 50 | - * @param params | 56 | + * @param {String} name 参观者姓名 |
| 57 | + * @param {String} id_type 证件类型,1=身份证,3=其他 | ||
| 58 | + * @param {String} id_number 证件号 | ||
| 51 | * @returns | 59 | * @returns |
| 52 | */ | 60 | */ |
| 53 | -export const saveCustomerInfoAPI = (params) => fn(fetch.post(Api.SAVE_CUSTOMER_INFO, params)); | 61 | +export const addPersonAPI = (params) => fn(fetch.post(Api.ADD_PERSON, params)); |
| 54 | 62 | ||
| 55 | /** | 63 | /** |
| 56 | - * @description: 获取系统参数 | 64 | + * @description: 删除参观者 |
| 65 | + * @param {String} person_id 参观者id | ||
| 57 | * @returns | 66 | * @returns |
| 58 | */ | 67 | */ |
| 59 | -export const sysParamAPI = (params) => fn(fetch.get(Api.SYS_PARAM, params)); | 68 | +export const delPersonAPI = (params) => fn(fetch.post(Api.DEL_PERSON, params)); |
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * @description: 提交预约 | ||
| 72 | + * @param {String} reserve_date | ||
| 73 | + * @param {String} begin_time | ||
| 74 | + * @param {String} end_time | ||
| 75 | + * @param {String} person_id_list | ||
| 76 | + * @returns {String} bill_id 预约单id | ||
| 77 | + */ | ||
| 78 | +export const addReserveAPI = (params) => fn(fetch.post(Api.ADD_RESERVE, params)); | ||
| 79 | + | ||
| 80 | +/** | ||
| 81 | + * @description: 支付准备(模拟) | ||
| 82 | + * @param {String} bill_id | ||
| 83 | + * @returns {String} bill_id 预约单id | ||
| 84 | + */ | ||
| 85 | +export const payPrepareAPI = (params) => fn(fetch.post(Api.PAY_PREPARE, params)); | ||
| 86 | + | ||
| 87 | +/** | ||
| 88 | + * @description: 支付回调(模拟) | ||
| 89 | + * @param {String} pay_id 预约单支付凭证 | ||
| 90 | + * @param {String} pay_status 支付状态,1为成功,0为失败(缺省) | ||
| 91 | + * @returns {String} bill_id 预约单id | ||
| 92 | + */ | ||
| 93 | +export const payCallbackAPI = (params) => fn(fetch.post(Api.PAY_CALLBACK, params)); | ||
| 94 | + | ||
| 95 | +/** | ||
| 96 | + * @description: 预约单详情,参观者列表 | ||
| 97 | + * @param {String} bill_id 预约单id | ||
| 98 | + * @returns {String} | ||
| 99 | + */ | ||
| 100 | +export const billInfoAPI = (params) => fn(fetch.get(Api.BILL_INFO, params)); | ||
| 60 | 101 | ||
| 61 | /** | 102 | /** |
| 62 | - * @description: 获取房间列表 | 103 | + * @description: 扫码核销二维码列表 |
| 63 | - * @param start_date 入住时间 | ||
| 64 | - * @param end_date 离店时间 | ||
| 65 | - * @param offset 偏移量 | ||
| 66 | - * @param limit 条数 | ||
| 67 | * @returns | 104 | * @returns |
| 68 | */ | 105 | */ |
| 69 | -export const getListAPI = (params) => fn(fetch.get(Api.GET_LIST, params)); | 106 | +export const qrcodeListAPI = (params) => fn(fetch.get(Api.QRCODE_LIST, params)); |
| 70 | 107 | ||
| 71 | /** | 108 | /** |
| 72 | - * @description: 获取房间详情 | 109 | + * @description: 扫码核销二维码状态 |
| 73 | - * @param start_date 入住时间 | ||
| 74 | - * @param end_date 离店时间 | ||
| 75 | - * @param room_type floor/room | ||
| 76 | * @returns | 110 | * @returns |
| 77 | */ | 111 | */ |
| 78 | -export const getRoomAPI = (params) => fn(fetch.get(Api.GET_ROOM, params)); | 112 | +export const qrcodeStatusAPI = (params) => fn(fetch.get(Api.QRCODE_STATUS, params)); |
| 79 | 113 | ||
| 80 | /** | 114 | /** |
| 81 | - * @description: 预定房间 | 115 | + * @description: 预约单列表 |
| 82 | - * @param id ID | ||
| 83 | - * @param num 预定房间数量 | ||
| 84 | - * @param plan_in 入住时间 | ||
| 85 | - * @param plan_out 离店时间 | ||
| 86 | - * @param contact_name 联系人 | ||
| 87 | - * @param contact_phone 联系电话 | ||
| 88 | - * @param order_remark 备注 | ||
| 89 | - * @param room_type floor/room | ||
| 90 | * @returns | 116 | * @returns |
| 91 | */ | 117 | */ |
| 92 | -export const addOrderAPI = (params) => fn(fetch.post(Api.ADD_ORDER, params)); | 118 | +export const billListAPI = (params) => fn(fetch.get(Api.BILL_LIST, params)); |
| 93 | 119 | ||
| 94 | /** | 120 | /** |
| 95 | - * @description: 支付 | 121 | + * @description: 退款 |
| 96 | - * @param order_id 订单ID | ||
| 97 | * @returns | 122 | * @returns |
| 98 | */ | 123 | */ |
| 99 | -export const payAPI = (params) => fn(fetch.post(Api.PAY, params)); | 124 | +export const icbcRefundAPI = (params) => fn(fetch.post(Api.ICBC_REFUND, params)); |
| 100 | 125 | ||
| 101 | /** | 126 | /** |
| 102 | - * @description: 检查是否支付成功 | 127 | + * @description: 支付前准备(获取支付参数等) |
| 103 | - * @param order_id 订单ID | ||
| 104 | * @returns | 128 | * @returns |
| 105 | */ | 129 | */ |
| 106 | -export const payCheckAPI = (params) => fn(fetch.post(Api.PAY_CHECK, params)); | 130 | +export const billPrepareAPI = (params) => fn(fetch.post(Api.BILL_PREPARE, params)); |
| 107 | 131 | ||
| 108 | /** | 132 | /** |
| 109 | - * @description: 获取我的订单列表 | 133 | + * @description: 支付状态查询 |
| 110 | - * @param pay_type | ||
| 111 | - * @param page | ||
| 112 | - * @param limit | ||
| 113 | * @returns | 134 | * @returns |
| 114 | */ | 135 | */ |
| 115 | -export const myOrderAPI = (params) => fn(fetch.get(Api.MY_ORDER, params)); | 136 | +export const billPayStatusAPI = (params) => fn(fetch.get(Api.BILL_PAY_STATUS, params)); |
| 116 | 137 | ||
| 117 | /** | 138 | /** |
| 118 | - * @description: 取消订单 | 139 | + * @description: 证件号查询二维码 |
| 119 | - * @param id | ||
| 120 | * @returns | 140 | * @returns |
| 121 | */ | 141 | */ |
| 122 | -export const orderCancelAPI = (params) => fn(fetch.post(Api.ORDER_CANCEL, params)); | 142 | +export const queryQrCodeAPI = (params) => fn(fetch.get(Api.QUERY_QR_CODE, params)); |
| 123 | 143 | ||
| 124 | /** | 144 | /** |
| 125 | - * @description: 订单成功 | 145 | + * @description: 订单查询 |
| 126 | - * @param id | ||
| 127 | * @returns | 146 | * @returns |
| 128 | */ | 147 | */ |
| 129 | -export const orderSuccessAPI = (params) => fn(fetch.post(Api.ORDER_SUCCESS, params)); | 148 | +export const icbcOrderQryAPI = (params) => fn(fetch.get(Api.ICBC_ORDER_QRY, params)); |
| 130 | 149 | ||
| 131 | /** | 150 | /** |
| 132 | - * @description: | 151 | + * @description: 授权前订单详情查询 |
| 133 | - * @param id | ||
| 134 | * @returns | 152 | * @returns |
| 135 | */ | 153 | */ |
| 136 | -export const tmpSysParamAPI = (params) => fn(fetch.get(Api.TMP_SYS_PARAM, params)); | 154 | +export const onAuthBillInfoAPI = (params) => fn(fetch.get(Api.ON_AUTH_BILL_INFO, params)); | ... | ... |
| ... | @@ -9,6 +9,19 @@ export default { | ... | @@ -9,6 +9,19 @@ export default { |
| 9 | pages: [ | 9 | pages: [ |
| 10 | 'pages/index/index', | 10 | 'pages/index/index', |
| 11 | 'pages/auth/index', | 11 | 'pages/auth/index', |
| 12 | + 'pages/notice/index', | ||
| 13 | + 'pages/booking/index', | ||
| 14 | + 'pages/submit/index', | ||
| 15 | + 'pages/addVisitor/index', | ||
| 16 | + 'pages/success/index', | ||
| 17 | + 'pages/bookingCode/index', | ||
| 18 | + 'pages/bookingList/index', | ||
| 19 | + 'pages/bookingDetail/index', | ||
| 20 | + 'pages/me/index', | ||
| 21 | + 'pages/waiting/index', | ||
| 22 | + 'pages/callback/index', | ||
| 23 | + 'pages/search/index', | ||
| 24 | + 'pages/visitorList/index', | ||
| 12 | ], | 25 | ], |
| 13 | subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 | 26 | subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 |
| 14 | { | 27 | { |
| ... | @@ -19,7 +32,7 @@ export default { | ... | @@ -19,7 +32,7 @@ export default { |
| 19 | window: { | 32 | window: { |
| 20 | backgroundTextStyle: 'light', | 33 | backgroundTextStyle: 'light', |
| 21 | navigationBarBackgroundColor: '#fff', | 34 | navigationBarBackgroundColor: '#fff', |
| 22 | - navigationBarTitleText: 'WeChat', | 35 | + navigationBarTitleText: '西园寺预约', |
| 23 | navigationBarTextStyle: 'black' | 36 | navigationBarTextStyle: 'black' |
| 24 | } | 37 | } |
| 25 | } | 38 | } | ... | ... |
src/assets/css/content-bg.less
0 → 100644
| 1 | + | ||
| 2 | +.modify-top { | ||
| 3 | + z-index: 36; | ||
| 4 | + position: absolute; | ||
| 5 | + left: 0; | ||
| 6 | + top: 0; | ||
| 7 | + width: 100%; | ||
| 8 | + height: 10px; | ||
| 9 | + background-image: url('http://gyzs.onwall.cn/top-xian%402x.png'); | ||
| 10 | + background-size: contain; | ||
| 11 | +} | ||
| 12 | +.content-bg { | ||
| 13 | + /** | ||
| 14 | + * background-color and background-image 共存,不能使用渐变色 | ||
| 15 | + * 图片铺平当时精度提高看看效果 | ||
| 16 | + * 直接用渐变色 | ||
| 17 | + * 不使用渐变色背景 | ||
| 18 | + */ | ||
| 19 | + height: 100%; | ||
| 20 | + min-height: 100vh; | ||
| 21 | + // background-image: url('@images/bg-yellow-duan@2x.png'); | ||
| 22 | + background-image: url('http://gyzs.onwall.cn/bg-yellow-duan%402x.png'); | ||
| 23 | + // background-size: cover; | ||
| 24 | + // background: linear-gradient(360deg, #FDD347 0%, #FFED6D 100%) ; | ||
| 25 | +} |
src/assets/images/+@2x.png
0 → 100644
247 Bytes
src/assets/images/-@2x.png
0 → 100644
129 Bytes
src/assets/images/banner.jpg
0 → 100644
272 KB
src/assets/images/bg.jpg
0 → 100644
149 KB
src/assets/images/bg@2x~1.png
0 → 100644
580 KB
src/assets/images/dui@2x.png
0 → 100644
1.31 KB
src/assets/images/error.png
0 → 100644
4.42 KB
src/assets/images/hua01@2x.png
0 → 100644
3.57 KB
src/assets/images/hua02@2x.png
0 → 100644
2.82 KB
src/assets/images/hua03@2x.png
0 → 100644
2.02 KB
src/assets/images/hua04@2x.png
0 → 100644
1.38 KB
src/assets/images/huizhu.png
0 → 100644
5.41 KB
src/assets/images/left001@2x.png
0 → 100644
4.6 KB
src/assets/images/left002@2x.png
0 → 100644
4.4 KB
src/assets/images/logo.png
0 → 100644
161 KB
src/assets/images/luru@2x.png
0 → 100644
1.93 KB
src/assets/images/right001@2x.png
0 → 100644
4.79 KB
src/assets/images/right002@2x.png
0 → 100644
4.65 KB
src/assets/images/rili@2x.png
0 → 100644
1.15 KB
src/assets/images/success.png
0 → 100644
4.71 KB
src/assets/images/top@2x~1.png
0 → 100644
25.7 KB
src/assets/images/二维码@2x.png
0 → 100644
186 KB
src/assets/images/二维码@2x2.png
0 → 100644
628 Bytes
src/assets/images/二维码icon.png
0 → 100644
10.1 KB
src/assets/images/删除@2x.png
0 → 100644
1 KB
src/assets/images/刷新@2x.png
0 → 100644
7.61 KB
src/assets/images/单选01@2x.png
0 → 100644
1.66 KB
src/assets/images/单选02@2x.png
0 → 100644
1.86 KB
src/assets/images/右@2x.png
0 → 100644
1.32 KB
src/assets/images/多选01@2x.png
0 → 100644
626 Bytes
src/assets/images/多选02@2x.png
0 → 100644
1.22 KB
src/assets/images/左@2x.png
0 → 100644
1.34 KB
src/assets/images/成功@2x.png
0 → 100644
20.7 KB
src/assets/images/我的01@2x.png
0 → 100644
1.8 KB
src/assets/images/我的02@2x.png
0 → 100644
1.44 KB
src/assets/images/暂无@2x.png
0 → 100644
16.6 KB
src/assets/images/立即预约@2x.png
0 → 100644
1.23 KB
src/assets/images/预约记录@2x.png
0 → 100644
2.19 KB
src/assets/images/首页01@2x.png
0 → 100644
1.38 KB
src/assets/images/首页02@2x.png
0 → 100644
1.03 KB
| 1 | -@namespace: 'meihua'; | 1 | +@namespace: 'tswj'; |
| 2 | 2 | ||
| 3 | /* ============ 颜色 ============ */ | 3 | /* ============ 颜色 ============ */ |
| 4 | 4 | ||
| 5 | // 主色调 | 5 | // 主色调 |
| 6 | -@base-color: #199A74; | 6 | +@base-color: #11D2B1; |
| 7 | - | ||
| 8 | // 文字颜色 | 7 | // 文字颜色 |
| 9 | -@base-font-color: #333333; | 8 | +@base-font-color: #FFFFFF; |
| 10 | -@sub-font-color: #999999; | ||
| 11 | 9 | ||
| 12 | // 定义一个映射 | 10 | // 定义一个映射 |
| 13 | #colors() { | 11 | #colors() { | ... | ... |
src/components/qrCode.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-16 10:06:47 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-12-26 11:15:45 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/components/qrCode.vue | ||
| 6 | + * @Description: 预约码卡组件 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="qr-code-page"> | ||
| 10 | + <view v-if="userList.length" class="show-qrcode"> | ||
| 11 | + <view class="qrcode-content"> | ||
| 12 | + <view class="user-info">{{ userinfo.name }} {{ userinfo.id }}</view> | ||
| 13 | + <view class="user-qrcode"> | ||
| 14 | + <view class="left" @tap="prevCode"> | ||
| 15 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E5%B7%A6@2x.png" /> | ||
| 16 | + </view> | ||
| 17 | + <view class="center"> | ||
| 18 | + <image :src="currentQrCodeUrl" mode="aspectFit" /> | ||
| 19 | + <view v-if="useStatus === STATUS_CODE.CANCELED || useStatus === STATUS_CODE.USED" class="qrcode-used"> | ||
| 20 | + <view class="overlay"></view> | ||
| 21 | + <text class="status-text">二维码{{ qr_code_status[useStatus] }}</text> | ||
| 22 | + </view> | ||
| 23 | + </view> | ||
| 24 | + <view class="right" @tap="nextCode"> | ||
| 25 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E5%8F%B3@2x.png" /> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | + <view style="color: red; margin-top: 1rem;">{{ userinfo.datetime }}</view> | ||
| 29 | + </view> | ||
| 30 | + <view class="user-list"> | ||
| 31 | + <view | ||
| 32 | + @tap="selectUser(index)" | ||
| 33 | + v-for="(item, index) in userList" | ||
| 34 | + :key="index" | ||
| 35 | + :class="[ | ||
| 36 | + 'user-item', | ||
| 37 | + select_index === index ? 'checked' : '', | ||
| 38 | + userList.length > 1 && item.sort ? 'border' : '', | ||
| 39 | + ]"> | ||
| 40 | + {{ item.name }} | ||
| 41 | + </view> | ||
| 42 | + </view> | ||
| 43 | + </view> | ||
| 44 | + <view v-else class="no-qrcode"> | ||
| 45 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem; height: 10rem;" /> | ||
| 46 | + <view class="no-qrcode-title">今天没有预约记录</view> | ||
| 47 | + <view style="text-align: center; color: #A67939; margin-top: 0.5rem;">查看我的“<text @tap="toRecord" style="text-decoration: underline; color: #ED9820;">预约记录</text>”</view> | ||
| 48 | + </view> | ||
| 49 | + </view> | ||
| 50 | +</template> | ||
| 51 | + | ||
| 52 | +<script setup> | ||
| 53 | +import { ref, computed, watch, onMounted, onUnmounted } from 'vue' | ||
| 54 | +import Taro, { useDidShow } from '@tarojs/taro' | ||
| 55 | +import { formatDatetime } from '@/utils/tools'; | ||
| 56 | +import { qrcodeListAPI, qrcodeStatusAPI, billPersonAPI } from '@/api/index' | ||
| 57 | +import { useGo } from '@/hooks/useGo' | ||
| 58 | +import BASE_URL from '@/utils/config'; | ||
| 59 | + | ||
| 60 | +const go = useGo(); | ||
| 61 | + | ||
| 62 | +const props = defineProps({ | ||
| 63 | + status: { | ||
| 64 | + type: String, | ||
| 65 | + default: '' | ||
| 66 | + }, | ||
| 67 | + type: { | ||
| 68 | + type: String, | ||
| 69 | + default: '' | ||
| 70 | + }, | ||
| 71 | + payId: { // 接收 payId | ||
| 72 | + type: String, | ||
| 73 | + default: '' | ||
| 74 | + } | ||
| 75 | +}); | ||
| 76 | + | ||
| 77 | +const select_index = ref(0); | ||
| 78 | +const userList = ref([]); | ||
| 79 | + | ||
| 80 | +const prevCode = () => { | ||
| 81 | + select_index.value = select_index.value - 1; | ||
| 82 | + if (select_index.value < 0) { | ||
| 83 | + select_index.value = userList.value.length - 1; | ||
| 84 | + } | ||
| 85 | +}; | ||
| 86 | +const nextCode = () => { | ||
| 87 | + select_index.value = select_index.value + 1; | ||
| 88 | + if (select_index.value > userList.value.length - 1) { | ||
| 89 | + select_index.value = 0; | ||
| 90 | + } | ||
| 91 | +}; | ||
| 92 | + | ||
| 93 | +watch( | ||
| 94 | + () => select_index.value, | ||
| 95 | + (index) => { | ||
| 96 | + refreshBtn(); | ||
| 97 | + } | ||
| 98 | +) | ||
| 99 | + | ||
| 100 | +function replaceMiddleCharacters(inputString) { | ||
| 101 | + if (!inputString || inputString.length < 15) { | ||
| 102 | + return inputString; | ||
| 103 | + } | ||
| 104 | + const start = Math.floor((inputString.length - 8) / 2); | ||
| 105 | + const end = start + 8; | ||
| 106 | + const replacement = '*'.repeat(8); | ||
| 107 | + return inputString.substring(0, start) + replacement + inputString.substring(end); | ||
| 108 | +} | ||
| 109 | + | ||
| 110 | +const formatId = (id) => replaceMiddleCharacters(id); | ||
| 111 | + | ||
| 112 | +const userinfo = computed(() => { | ||
| 113 | + return { | ||
| 114 | + name: userList.value[select_index.value]?.name, | ||
| 115 | + id: formatId(userList.value[select_index.value]?.id_number), | ||
| 116 | + datetime: userList.value[select_index.value]?.datetime, | ||
| 117 | + }; | ||
| 118 | +}); | ||
| 119 | + | ||
| 120 | +const currentQrCodeUrl = computed(() => { | ||
| 121 | + const url = userList.value[select_index.value]?.qr_code_url; | ||
| 122 | + if (url && url.startsWith('/')) { | ||
| 123 | + return BASE_URL + url; | ||
| 124 | + } | ||
| 125 | + return url; | ||
| 126 | +}) | ||
| 127 | + | ||
| 128 | +const useStatus = ref('0'); | ||
| 129 | + | ||
| 130 | +const qr_code_status = { | ||
| 131 | + '1': '未激活', | ||
| 132 | + '3': '待使用', | ||
| 133 | + '5': '被取消', | ||
| 134 | + '7': '已使用', | ||
| 135 | +}; | ||
| 136 | + | ||
| 137 | +const STATUS_CODE = { | ||
| 138 | + APPLY: '1', | ||
| 139 | + SUCCESS: '3', | ||
| 140 | + CANCELED: '5', | ||
| 141 | + USED: '7', | ||
| 142 | +}; | ||
| 143 | + | ||
| 144 | +const refreshBtn = async () => { | ||
| 145 | + if (!userList.value[select_index.value]) return; | ||
| 146 | + const { code, data } = await qrcodeStatusAPI({ qr_code: userList.value[select_index.value].qr_code }); | ||
| 147 | + if (code) { | ||
| 148 | + useStatus.value = data.status; | ||
| 149 | + } | ||
| 150 | +} | ||
| 151 | + | ||
| 152 | +const selectUser = (index) => { | ||
| 153 | + select_index.value = index; | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | +const formatGroup = (data) => { | ||
| 157 | + let lastPayId = null; | ||
| 158 | + for (let i = 0; i < data.length; i++) { | ||
| 159 | + if (data[i].pay_id !== lastPayId) { | ||
| 160 | + data[i].sort = 1; | ||
| 161 | + lastPayId = data[i].pay_id; | ||
| 162 | + } else { | ||
| 163 | + data[i].sort = 0; | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + return data; | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +const init = async () => { | ||
| 170 | + if (!props.type) { | ||
| 171 | + const { code, data } = await qrcodeListAPI(); | ||
| 172 | + if (code) { | ||
| 173 | + data.forEach(item => { | ||
| 174 | + item.qr_code_url = '/admin?m=srv&a=get_qrcode&key=' + item.qr_code; | ||
| 175 | + item.datetime = formatDatetime({ begin_time: item.begin_time, end_time: item.end_time }) | ||
| 176 | + item.sort = 0; | ||
| 177 | + }); | ||
| 178 | + // 剔除qr_code为空的二维码 | ||
| 179 | + const validData = data.filter(item => item.qr_code !== ''); | ||
| 180 | + | ||
| 181 | + if (validData.length > 0) { | ||
| 182 | + userList.value = formatGroup(validData); | ||
| 183 | + refreshBtn(); | ||
| 184 | + } else { | ||
| 185 | + userList.value = []; | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + } else { | ||
| 189 | + if (props.payId) { | ||
| 190 | + const { code, data } = await billPersonAPI({ pay_id: props.payId }); | ||
| 191 | + if (code) { | ||
| 192 | + data.forEach(item => { | ||
| 193 | + item.qr_code_url = '/admin?m=srv&a=get_qrcode&key=' + item.qr_code; | ||
| 194 | + item.sort = 0; | ||
| 195 | + // billPersonAPI 返回的数据可能没有 datetime 字段,需要检查 | ||
| 196 | + // 如果没有,可能需要从外部传入或者假设是当天的? | ||
| 197 | + // H5 代码没有处理 datetime,但在 template 里用了。 | ||
| 198 | + // 这里暂且不做处理,如果没有 datetime 就不显示 | ||
| 199 | + }); | ||
| 200 | + const validData = data.filter(item => item.qr_code !== ''); | ||
| 201 | + if (validData.length > 0) { | ||
| 202 | + userList.value = validData; | ||
| 203 | + refreshBtn(); | ||
| 204 | + } else { | ||
| 205 | + userList.value = []; | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | +}; | ||
| 211 | + | ||
| 212 | +onMounted(() => { | ||
| 213 | + init(); | ||
| 214 | +}); | ||
| 215 | + | ||
| 216 | +const poll = async () => { | ||
| 217 | + if (userList.value.length && useStatus.value === STATUS_CODE.SUCCESS) { | ||
| 218 | + if (userList.value[select_index.value]) { | ||
| 219 | + const { code, data } = await qrcodeStatusAPI({ qr_code: userList.value[select_index.value].qr_code }); | ||
| 220 | + if (code) { | ||
| 221 | + useStatus.value = data.status; | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | + } | ||
| 225 | +}; | ||
| 226 | + | ||
| 227 | +const intervalId = setInterval(poll, 3000); // 3秒轮询一次,避免过于频繁 | ||
| 228 | + | ||
| 229 | +onUnmounted(() => { | ||
| 230 | + clearInterval(intervalId); | ||
| 231 | +}); | ||
| 232 | + | ||
| 233 | +const toRecord = () => { | ||
| 234 | + go('/bookingList'); | ||
| 235 | +} | ||
| 236 | +</script> | ||
| 237 | + | ||
| 238 | +<style lang="less"> | ||
| 239 | +.qr-code-page { | ||
| 240 | + .qrcode-content { | ||
| 241 | + padding: 1rem 0; | ||
| 242 | + display: flex; | ||
| 243 | + flex-direction: column; | ||
| 244 | + justify-content: center; | ||
| 245 | + align-items: center; | ||
| 246 | + background-color: #FFF; | ||
| 247 | + border-radius: 8px; | ||
| 248 | + box-shadow: 0rem 0rem 0.92rem 0rem rgba(106,106,106,0.27); | ||
| 249 | + | ||
| 250 | + .user-info { | ||
| 251 | + color: #A6A6A6; | ||
| 252 | + font-size: 1.15rem; | ||
| 253 | + margin-top: 0.5rem; | ||
| 254 | + margin-bottom: 0.5rem; | ||
| 255 | + } | ||
| 256 | + .user-qrcode { | ||
| 257 | + display: flex; | ||
| 258 | + align-items: center; | ||
| 259 | + .left { | ||
| 260 | + image { | ||
| 261 | + width: 1.75rem; height: 1.75rem; margin-right: 0.5rem; | ||
| 262 | + } | ||
| 263 | + } | ||
| 264 | + .center { | ||
| 265 | + border: 1px solid #D1D1D1; | ||
| 266 | + border-radius: 20px; | ||
| 267 | + padding: 0.5rem; | ||
| 268 | + position: relative; | ||
| 269 | + image { | ||
| 270 | + width: 15rem; height: 15rem; | ||
| 271 | + } | ||
| 272 | + .qrcode-used { | ||
| 273 | + position: absolute; | ||
| 274 | + top: 0; | ||
| 275 | + left: 0; | ||
| 276 | + right: 0; | ||
| 277 | + bottom: 0; | ||
| 278 | + border-radius: 20px; | ||
| 279 | + overflow: hidden; | ||
| 280 | + | ||
| 281 | + .overlay { | ||
| 282 | + width: 100%; | ||
| 283 | + height: 100%; | ||
| 284 | + background-image: url('https://cdn.ipadbiz.cn/xys/booking/southeast.jpeg'); | ||
| 285 | + background-size: contain; | ||
| 286 | + opacity: 0.9; | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + .status-text { | ||
| 290 | + color: #A67939; | ||
| 291 | + position: absolute; | ||
| 292 | + top: 50%; | ||
| 293 | + left: 50%; | ||
| 294 | + transform: translate(-50%, -50%); | ||
| 295 | + font-size: 1.2rem; | ||
| 296 | + white-space: nowrap; | ||
| 297 | + font-weight: bold; | ||
| 298 | + z-index: 10; | ||
| 299 | + } | ||
| 300 | + } | ||
| 301 | + } | ||
| 302 | + .right { | ||
| 303 | + image { | ||
| 304 | + width: 1.75rem; height: 1.75rem; | ||
| 305 | + margin-left: 0.5rem; | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + } | ||
| 309 | + } | ||
| 310 | + .user-list { | ||
| 311 | + display: flex; | ||
| 312 | + padding: 1rem; | ||
| 313 | + align-items: center; | ||
| 314 | + flex-wrap: wrap; | ||
| 315 | + .user-item { | ||
| 316 | + position: relative; | ||
| 317 | + padding: 0.25rem 0.5rem; | ||
| 318 | + border: 1px solid #A67939; | ||
| 319 | + margin: 0.25rem; | ||
| 320 | + border-radius: 5px; | ||
| 321 | + color: #A67939; | ||
| 322 | + &.checked { | ||
| 323 | + color: #FFF; | ||
| 324 | + background-color: #A67939; | ||
| 325 | + } | ||
| 326 | + &.border { | ||
| 327 | + margin-right: 0.5rem; | ||
| 328 | + &::after { | ||
| 329 | + position: absolute; | ||
| 330 | + right: -0.5rem; | ||
| 331 | + top: calc(50% - 0.5rem); | ||
| 332 | + content: ''; | ||
| 333 | + height: 1rem; | ||
| 334 | + border-right: 1px solid #A67939; | ||
| 335 | + } | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + | ||
| 340 | + .no-qrcode { | ||
| 341 | + display: flex; | ||
| 342 | + justify-content: center; | ||
| 343 | + align-items: center; | ||
| 344 | + flex-direction: column; | ||
| 345 | + margin-bottom: 1rem; | ||
| 346 | + | ||
| 347 | + .no-qrcode-title { | ||
| 348 | + color: #A67939; | ||
| 349 | + font-size: 1.05rem; | ||
| 350 | + } | ||
| 351 | + } | ||
| 352 | +} | ||
| 353 | +</style> |
src/components/qrCodeSearch.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-16 10:06:47 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-12-26 12:35:01 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/components/qrCodeSearch.vue | ||
| 6 | + * @Description: 预约码卡组件 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="qr-code-page"> | ||
| 10 | + <view v-if="userinfo.qr_code" class="show-qrcode"> | ||
| 11 | + <view class="qrcode-content"> | ||
| 12 | + <view class="user-info">{{ userinfo.name }} {{ userinfo.id }}</view> | ||
| 13 | + <view class="user-qrcode"> | ||
| 14 | + <view class="left"> | ||
| 15 | + <!-- <image src="https://cdn.ipadbiz.cn/xys/booking/%E5%B7%A6@2x.png"> --> | ||
| 16 | + </view> | ||
| 17 | + <view class="center"> | ||
| 18 | + <image :src="userinfo.qr_code_url" mode="aspectFit" /> | ||
| 19 | + <view v-if="useStatus === STATUS_CODE.CANCELED || useStatus === STATUS_CODE.USED" class="qrcode-used"> | ||
| 20 | + <view class="overlay"></view> | ||
| 21 | + <text class="status-text">二维码{{ qr_code_status[useStatus] }}</text> | ||
| 22 | + </view> | ||
| 23 | + </view> | ||
| 24 | + <view class="right"> | ||
| 25 | + <!-- <image src="https://cdn.ipadbiz.cn/xys/booking/%E5%8F%B3@2x.png"> --> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | + <view style="color: red; margin-top: 1rem;">{{ userinfo.datetime }}</view> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + <view v-else class="no-qrcode"> | ||
| 32 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem; height: 10rem;" /> | ||
| 33 | + <view class="no-qrcode-title">您还没有预约过今天参观</view> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | +</template> | ||
| 37 | + | ||
| 38 | +<script setup> | ||
| 39 | +import { ref, onMounted } from 'vue' | ||
| 40 | +import { formatDatetime } from '@/utils/tools'; | ||
| 41 | +import { qrcodeStatusAPI, queryQrCodeAPI } from '@/api/index' | ||
| 42 | +import BASE_URL from '@/utils/config'; | ||
| 43 | + | ||
| 44 | +const props = defineProps({ | ||
| 45 | + id: { | ||
| 46 | + type: String, | ||
| 47 | + default: '' | ||
| 48 | + }, | ||
| 49 | +}); | ||
| 50 | + | ||
| 51 | +const userinfo = ref({}); | ||
| 52 | + | ||
| 53 | +function replaceMiddleCharacters(inputString) { | ||
| 54 | + if (!inputString || inputString.length < 15) { | ||
| 55 | + return inputString; | ||
| 56 | + } | ||
| 57 | + const start = Math.floor((inputString.length - 8) / 2); | ||
| 58 | + const end = start + 8; | ||
| 59 | + const replacement = '*'.repeat(8); | ||
| 60 | + return inputString.substring(0, start) + replacement + inputString.substring(end); | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +const formatId = (id) => replaceMiddleCharacters(id); | ||
| 64 | + | ||
| 65 | +const useStatus = ref('0'); | ||
| 66 | + | ||
| 67 | +const qr_code_status = { | ||
| 68 | + '1': '未激活', | ||
| 69 | + '3': '待使用', | ||
| 70 | + '5': '被取消', | ||
| 71 | + '7': '已使用', | ||
| 72 | +}; | ||
| 73 | + | ||
| 74 | +const STATUS_CODE = { | ||
| 75 | + APPLY: '1', | ||
| 76 | + SUCCESS: '3', | ||
| 77 | + CANCELED: '5', | ||
| 78 | + USED: '7', | ||
| 79 | +}; | ||
| 80 | + | ||
| 81 | +onMounted(async () => { | ||
| 82 | + if (props.id) { | ||
| 83 | + const { code, data } = await queryQrCodeAPI({ id_number: props.id }); | ||
| 84 | + if (code) { | ||
| 85 | + // data 可能是一个对象 | ||
| 86 | + const item = data; | ||
| 87 | + item.qr_code_url = BASE_URL + '/admin?m=srv&a=get_qrcode&key=' + item.qr_code; | ||
| 88 | + item.datetime = formatDatetime({ begin_time: item.begin_time, end_time: item.end_time }); | ||
| 89 | + item.id = formatId(item.id_number); | ||
| 90 | + userinfo.value = item; | ||
| 91 | + | ||
| 92 | + const { code: status_code, data: status_data } = await qrcodeStatusAPI({ qr_code: item.qr_code }); | ||
| 93 | + if (status_code) { | ||
| 94 | + useStatus.value = status_data.status; | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | +}) | ||
| 99 | +</script> | ||
| 100 | + | ||
| 101 | +<style lang="less"> | ||
| 102 | +.qr-code-page { | ||
| 103 | + .qrcode-content { | ||
| 104 | + padding: 1rem 0; | ||
| 105 | + display: flex; | ||
| 106 | + flex-direction: column; | ||
| 107 | + justify-content: center; | ||
| 108 | + align-items: center; | ||
| 109 | + background-color: #FFF; | ||
| 110 | + border-radius: 8px; | ||
| 111 | + box-shadow: 0rem 0rem 0.92rem 0rem rgba(106,106,106,0.27); | ||
| 112 | + | ||
| 113 | + .user-info { | ||
| 114 | + color: #A6A6A6; | ||
| 115 | + font-size: 1.15rem; | ||
| 116 | + margin-top: 0.5rem; | ||
| 117 | + margin-bottom: 0.5rem; | ||
| 118 | + } | ||
| 119 | + .user-qrcode { | ||
| 120 | + display: flex; | ||
| 121 | + align-items: center; | ||
| 122 | + .center { | ||
| 123 | + border: 1px solid #D1D1D1; | ||
| 124 | + border-radius: 20px; | ||
| 125 | + padding: 0.5rem; | ||
| 126 | + position: relative; | ||
| 127 | + image { | ||
| 128 | + width: 15rem; height: 15rem; | ||
| 129 | + } | ||
| 130 | + .qrcode-used { | ||
| 131 | + position: absolute; | ||
| 132 | + top: 0; | ||
| 133 | + left: 0; | ||
| 134 | + right: 0; | ||
| 135 | + bottom: 0; | ||
| 136 | + border-radius: 20px; | ||
| 137 | + overflow: hidden; | ||
| 138 | + | ||
| 139 | + .overlay { | ||
| 140 | + width: 100%; | ||
| 141 | + height: 100%; | ||
| 142 | + background-image: url('https://cdn.ipadbiz.cn/xys/booking/southeast.jpeg'); | ||
| 143 | + background-size: contain; | ||
| 144 | + opacity: 0.9; | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + .status-text { | ||
| 148 | + color: #A67939; | ||
| 149 | + position: absolute; | ||
| 150 | + top: 50%; | ||
| 151 | + left: 50%; | ||
| 152 | + transform: translate(-50%, -50%); | ||
| 153 | + font-size: 1.2rem; | ||
| 154 | + white-space: nowrap; | ||
| 155 | + font-weight: bold; | ||
| 156 | + z-index: 10; | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + .no-qrcode { | ||
| 164 | + display: flex; | ||
| 165 | + justify-content: center; | ||
| 166 | + align-items: center; | ||
| 167 | + flex-direction: column; | ||
| 168 | + margin-bottom: 1rem; | ||
| 169 | + | ||
| 170 | + .no-qrcode-title { | ||
| 171 | + color: #A67939; | ||
| 172 | + font-size: 1.05rem; | ||
| 173 | + } | ||
| 174 | + } | ||
| 175 | +} | ||
| 176 | +</style> |
src/components/reserveCard.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-24 16:38:13 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 15:19:44 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/components/reserveCard.vue | ||
| 6 | + * @Description: 预约记录卡组件 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="booking-list-item" @tap="goToDetail(reserve_info)"> | ||
| 10 | + <view class="booking-list-item-header"> | ||
| 11 | + <view>{{ reserve_info.booking_time }}</view> | ||
| 12 | + <view :class="[formatStatus(reserve_info.status)?.key, 'status']">{{ formatStatus(reserve_info.status)?.value }}</view> | ||
| 13 | + </view> | ||
| 14 | + <view class="booking-list-item-body"> | ||
| 15 | + <view class="booking-num"> | ||
| 16 | + <view class="num-body van-ellipsis">预约人数:<text>{{ reserve_info.total_qty }} 人</text> <text>({{ reserve_info.person_name }})</text></view> | ||
| 17 | + <view v-if="(reserve_info.status === CodeStatus.SUCCESS || reserve_info.status === CodeStatus.USED || reserve_info.status === CodeStatus.CANCEL)"> | ||
| 18 | + <nut-icon name="rect-right" /> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + <view class="booking-price">支付金额:<text>¥ {{ reserve_info.total_amt }}</text></view> | ||
| 22 | + <view class="booking-time">下单时间:<text>{{ reserve_info.order_time }}</text></view> | ||
| 23 | + </view> | ||
| 24 | + <view class="booking-list-item-footer"> | ||
| 25 | + <!-- 倒计时逻辑省略,如果需要可添加 --> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | +</template> | ||
| 29 | + | ||
| 30 | +<script setup> | ||
| 31 | +import { computed } from 'vue' | ||
| 32 | +import { useGo } from '@/hooks/useGo' | ||
| 33 | + | ||
| 34 | +const go = useGo(); | ||
| 35 | + | ||
| 36 | +const props = defineProps({ | ||
| 37 | + data: { | ||
| 38 | + type: Object, | ||
| 39 | + default: {}, | ||
| 40 | + }, | ||
| 41 | +}); | ||
| 42 | + | ||
| 43 | +const reserve_info = computed(() => props.data); | ||
| 44 | + | ||
| 45 | +const CodeStatus = { | ||
| 46 | + APPLY: '1', | ||
| 47 | + PAYING: '2', | ||
| 48 | + SUCCESS: '3', | ||
| 49 | + CANCEL: '5', | ||
| 50 | + CANCELED: '7', | ||
| 51 | + USED: '9', | ||
| 52 | + REFUNDING: '11' | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +const formatStatus = (status) => { | ||
| 56 | + switch (status) { | ||
| 57 | + case CodeStatus.APPLY: | ||
| 58 | + return { | ||
| 59 | + key: 'cancel', | ||
| 60 | + value: '待支付' | ||
| 61 | + } | ||
| 62 | + case CodeStatus.PAYING: | ||
| 63 | + return { | ||
| 64 | + key: 'success', | ||
| 65 | + value: '支付中' | ||
| 66 | + } | ||
| 67 | + case CodeStatus.SUCCESS: | ||
| 68 | + return { | ||
| 69 | + key: 'success', | ||
| 70 | + value: '预约成功' | ||
| 71 | + } | ||
| 72 | + case CodeStatus.CANCEL: | ||
| 73 | + return { | ||
| 74 | + key: 'cancel', | ||
| 75 | + value: '已取消' | ||
| 76 | + } | ||
| 77 | + case CodeStatus.CANCELED: | ||
| 78 | + return { | ||
| 79 | + key: 'cancel', | ||
| 80 | + value: '已取消' | ||
| 81 | + } | ||
| 82 | + case CodeStatus.USED: | ||
| 83 | + return { | ||
| 84 | + key: 'used', | ||
| 85 | + value: '已使用' | ||
| 86 | + } | ||
| 87 | + case CodeStatus.REFUNDING: | ||
| 88 | + return { | ||
| 89 | + key: 'cancel', | ||
| 90 | + value: '退款中' | ||
| 91 | + } | ||
| 92 | + default: | ||
| 93 | + return { key: '', value: '' } | ||
| 94 | + } | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +const goToDetail = (item) => { | ||
| 98 | + // 只有成功、已使用、已取消(退款成功)才跳转详情 | ||
| 99 | + if (item.status === CodeStatus.SUCCESS || item.status === CodeStatus.USED || item.status === CodeStatus.CANCEL) { | ||
| 100 | + go('/bookingDetail', { pay_id: item.pay_id }); | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | +</script> | ||
| 104 | + | ||
| 105 | +<style lang="less"> | ||
| 106 | +.booking-list-item { | ||
| 107 | + background-color: #FFF; | ||
| 108 | + border-radius: 8px; | ||
| 109 | + padding: 1rem; | ||
| 110 | + margin-bottom: 1rem; | ||
| 111 | + box-shadow: 0rem 0rem 0.92rem 0rem rgba(106,106,106,0.1); | ||
| 112 | + | ||
| 113 | + .booking-list-item-header { | ||
| 114 | + display: flex; | ||
| 115 | + justify-content: space-between; | ||
| 116 | + align-items: center; | ||
| 117 | + padding-bottom: 0.5rem; | ||
| 118 | + border-bottom: 1px dashed #E6E6E6; | ||
| 119 | + margin-bottom: 0.5rem; | ||
| 120 | + font-size: 1rem; | ||
| 121 | + font-weight: bold; | ||
| 122 | + color: #333; | ||
| 123 | + | ||
| 124 | + .status { | ||
| 125 | + font-size: 0.85rem; | ||
| 126 | + font-weight: normal; | ||
| 127 | + padding: 2px 6px; | ||
| 128 | + border-radius: 4px; | ||
| 129 | + | ||
| 130 | + &.success { | ||
| 131 | + color: #A67939; | ||
| 132 | + background-color: #FBEEDC; | ||
| 133 | + } | ||
| 134 | + &.cancel { | ||
| 135 | + color: #999; | ||
| 136 | + background-color: #EEE; | ||
| 137 | + } | ||
| 138 | + &.used { | ||
| 139 | + color: #477F3D; | ||
| 140 | + background-color: #E5EFE3; | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + .booking-list-item-body { | ||
| 146 | + .booking-num { | ||
| 147 | + display: flex; | ||
| 148 | + justify-content: space-between; | ||
| 149 | + align-items: center; | ||
| 150 | + margin-bottom: 0.5rem; | ||
| 151 | + color: #666; | ||
| 152 | + | ||
| 153 | + .num-body { | ||
| 154 | + span, text { | ||
| 155 | + color: #A67939; | ||
| 156 | + font-weight: bold; | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + .booking-price, .booking-time { | ||
| 161 | + color: #999; | ||
| 162 | + font-size: 0.9rem; | ||
| 163 | + margin-bottom: 0.3rem; | ||
| 164 | + text { | ||
| 165 | + color: #333; | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | +} | ||
| 170 | +</style> |
src/hooks/useGo.js
0 → 100644
| 1 | +import Taro from '@tarojs/taro'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 封装路由跳转方便行内调用 | ||
| 5 | + * @returns | ||
| 6 | + */ | ||
| 7 | +export function useGo () { | ||
| 8 | + function go (path, query = {}) { | ||
| 9 | + // 补全路径,如果是 / 开头,去掉 / | ||
| 10 | + let url = path.startsWith('/') ? path.substring(1) : path; | ||
| 11 | + // 检查是否是 tabbar 页面 (目前没有配置 tabbar,所以都是普通跳转) | ||
| 12 | + // 如果是页面,加上 pages/ 前缀 (假设都在 pages 下,且目录名和 path 一致) | ||
| 13 | + // H5 path 是 /notice,小程序是 pages/notice/index | ||
| 14 | + if (!url.startsWith('pages/')) { | ||
| 15 | + url = `pages/${url}/index`; // 适配 pages/notice/index 结构 | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + // 构建 query string | ||
| 19 | + let queryString = Object.keys(query).map(key => key + '=' + query[key]).join('&'); | ||
| 20 | + if (queryString) { | ||
| 21 | + url += '?' + queryString; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + Taro.navigateTo({ | ||
| 25 | + url: '/' + url, | ||
| 26 | + fail: (err) => { | ||
| 27 | + // 如果是 tabbar 页面,尝试 switchTab | ||
| 28 | + if (err.errMsg && err.errMsg.indexOf('tabbar') !== -1) { | ||
| 29 | + Taro.switchTab({ url: '/' + url }); | ||
| 30 | + } else { | ||
| 31 | + console.error('Navigation failed', err); | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + }) | ||
| 35 | + } | ||
| 36 | + return go | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +export function useReplace () { | ||
| 40 | + function replace (path, query = {}) { | ||
| 41 | + let url = path.startsWith('/') ? path.substring(1) : path; | ||
| 42 | + if (!url.startsWith('pages/')) { | ||
| 43 | + url = `pages/${url}/index`; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + let queryString = Object.keys(query).map(key => key + '=' + query[key]).join('&'); | ||
| 47 | + if (queryString) { | ||
| 48 | + url += '?' + queryString; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + Taro.redirectTo({ | ||
| 52 | + url: '/' + url | ||
| 53 | + }) | ||
| 54 | + } | ||
| 55 | + return replace | ||
| 56 | +} |
src/pages/addVisitor/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-15 16:35:10 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-29 17:35:19 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/addVisitor/index.vue | ||
| 6 | + * @Description: 添加参观者 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="add-visitor-page"> | ||
| 10 | + <nut-form> | ||
| 11 | + <nut-form-item label="姓名"> | ||
| 12 | + <nut-input v-model="name" placeholder="请输入参观者姓名" type="text" /> | ||
| 13 | + </nut-form-item> | ||
| 14 | + <nut-form-item label="证件类型"> | ||
| 15 | + <view style="padding: 10px 0;">身份证</view> | ||
| 16 | + </nut-form-item> | ||
| 17 | + <nut-form-item label="证件号"> | ||
| 18 | + <nut-input v-model="id_number" placeholder="请输入参观者证件号" type="idcard" /> | ||
| 19 | + </nut-form-item> | ||
| 20 | + </nut-form> | ||
| 21 | + | ||
| 22 | + <view style="padding: 1rem;"> | ||
| 23 | + <nut-button type="primary" block color="#A67939" @click="save">保存</nut-button> | ||
| 24 | + </view> | ||
| 25 | + | ||
| 26 | + <view v-if="visitorList.length" class="history-list"> | ||
| 27 | + <view class="title">历史参观者</view> | ||
| 28 | + <view v-for="(item, index) in visitorList" :key="index" class="item"> | ||
| 29 | + <view class="info"> | ||
| 30 | + <view class="name">{{ item.name }}</view> | ||
| 31 | + <view class="id">{{ formatId(item.id_number) }}</view> | ||
| 32 | + </view> | ||
| 33 | + <view class="action" @tap="delVisitor(item.id)">删除</view> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | + </view> | ||
| 37 | +</template> | ||
| 38 | + | ||
| 39 | +<script setup> | ||
| 40 | +import { ref } from 'vue' | ||
| 41 | +import Taro, { useDidShow } from '@tarojs/taro' | ||
| 42 | +import { personListAPI, addPersonAPI, delPersonAPI } from '@/api/index' | ||
| 43 | + | ||
| 44 | +const name = ref(''); | ||
| 45 | +const id_number = ref(''); | ||
| 46 | +const visitorList = ref([]); | ||
| 47 | + | ||
| 48 | +// 身份证校验 | ||
| 49 | +const checkIDCard = (idcode) => { | ||
| 50 | + // 简单校验 | ||
| 51 | + return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idcode); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +function replaceMiddleCharacters(inputString) { | ||
| 55 | + if (!inputString || inputString.length < 15) { | ||
| 56 | + return inputString; | ||
| 57 | + } | ||
| 58 | + const start = Math.floor((inputString.length - 8) / 2); | ||
| 59 | + const end = start + 8; | ||
| 60 | + const replacement = '*'.repeat(8); | ||
| 61 | + return inputString.substring(0, start) + replacement + inputString.substring(end); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +const formatId = (id) => replaceMiddleCharacters(id); | ||
| 65 | + | ||
| 66 | +const loadList = async () => { | ||
| 67 | + const { code, data } = await personListAPI({}); | ||
| 68 | + if (code) { | ||
| 69 | + visitorList.value = data; | ||
| 70 | + } | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +const save = async () => { | ||
| 74 | + if (!name.value) { | ||
| 75 | + Taro.showToast({ title: '请输入姓名', icon: 'none' }); | ||
| 76 | + return; | ||
| 77 | + } | ||
| 78 | + if (!checkIDCard(id_number.value)) { | ||
| 79 | + Taro.showToast({ title: '请输入正确的身份证号', icon: 'none' }); | ||
| 80 | + return; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + Taro.showLoading({ title: '保存中' }); | ||
| 84 | + const { code, msg } = await addPersonAPI({ | ||
| 85 | + name: name.value, | ||
| 86 | + id_type: 1, // 身份证 | ||
| 87 | + id_number: id_number.value | ||
| 88 | + }); | ||
| 89 | + Taro.hideLoading(); | ||
| 90 | + | ||
| 91 | + if (code) { | ||
| 92 | + Taro.showToast({ title: '添加成功' }); | ||
| 93 | + name.value = ''; | ||
| 94 | + id_number.value = ''; | ||
| 95 | + loadList(); | ||
| 96 | + // 自动返回上一页? H5 没有自动返回 | ||
| 97 | + Taro.navigateBack(); | ||
| 98 | + } else { | ||
| 99 | + Taro.showToast({ title: msg || '添加失败', icon: 'none' }); | ||
| 100 | + } | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +const delVisitor = async (id) => { | ||
| 104 | + const { confirm } = await Taro.showModal({ title: '提示', content: '确定删除该参观者吗?' }); | ||
| 105 | + if (confirm) { | ||
| 106 | + const { code, msg } = await delPersonAPI({ person_id: id }); | ||
| 107 | + if (code) { | ||
| 108 | + Taro.showToast({ title: '删除成功' }); | ||
| 109 | + loadList(); | ||
| 110 | + } else { | ||
| 111 | + Taro.showToast({ title: msg || '删除失败', icon: 'none' }); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | +} | ||
| 115 | + | ||
| 116 | +useDidShow(() => { | ||
| 117 | + loadList(); | ||
| 118 | +}) | ||
| 119 | +</script> | ||
| 120 | + | ||
| 121 | +<style lang="less"> | ||
| 122 | +.add-visitor-page { | ||
| 123 | + min-height: 100vh; | ||
| 124 | + background-color: #F6F6F6; | ||
| 125 | + padding-top: 1px; | ||
| 126 | + | ||
| 127 | + .history-list { | ||
| 128 | + margin-top: 1rem; | ||
| 129 | + background-color: #FFF; | ||
| 130 | + padding: 1rem; | ||
| 131 | + | ||
| 132 | + .title { | ||
| 133 | + font-size: 1rem; | ||
| 134 | + color: #333; | ||
| 135 | + margin-bottom: 1rem; | ||
| 136 | + border-left: 3px solid #A67939; | ||
| 137 | + padding-left: 0.5rem; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + .item { | ||
| 141 | + display: flex; | ||
| 142 | + justify-content: space-between; | ||
| 143 | + align-items: center; | ||
| 144 | + padding: 1rem 0; | ||
| 145 | + border-bottom: 1px solid #EEE; | ||
| 146 | + | ||
| 147 | + &:last-child { | ||
| 148 | + border-bottom: none; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + .info { | ||
| 152 | + .name { | ||
| 153 | + font-size: 1rem; | ||
| 154 | + color: #333; | ||
| 155 | + margin-bottom: 0.3rem; | ||
| 156 | + } | ||
| 157 | + .id { | ||
| 158 | + font-size: 0.9rem; | ||
| 159 | + color: #999; | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + .action { | ||
| 164 | + color: #FF0000; | ||
| 165 | + font-size: 0.9rem; | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | +} | ||
| 170 | +</style> |
| ... | @@ -2,30 +2,22 @@ | ... | @@ -2,30 +2,22 @@ |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | * @LastEditTime: 2024-05-26 10:17:04 | 4 | * @LastEditTime: 2024-05-26 10:17:04 |
| 5 | - * @FilePath: /meihuaApp/src/pages/auth/index.vue | 5 | + * @FilePath: /xyxBooking-weapp/src/pages/auth/index.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| 9 | - <div> | 9 | + <view class="auth-page"> |
| 10 | - <!-- <button wx:if="{{canIUse}}" open-type="getUserInfo" @getuserinfo="bindGetUserInfo">授权登录</button> | 10 | + <view class="loading"> |
| 11 | - <view @tap="auth">授权登陆</view> --> | 11 | + <view>正在授权登录...</view> |
| 12 | - </div> | 12 | + </view> |
| 13 | + </view> | ||
| 13 | </template> | 14 | </template> |
| 14 | 15 | ||
| 15 | <script setup> | 16 | <script setup> |
| 16 | -import Taro from '@tarojs/taro' | 17 | +import Taro, { useDidShow } from '@tarojs/taro' |
| 17 | -import { ref } from "vue"; | ||
| 18 | import request from '@/utils/request'; | 18 | import request from '@/utils/request'; |
| 19 | 19 | ||
| 20 | -</script> | 20 | +useDidShow(() => { |
| 21 | - | ||
| 22 | -<script> | ||
| 23 | -import "./index.less"; | ||
| 24 | -import { getCurrentPageParam } from "@/utils/weapp"; | ||
| 25 | - | ||
| 26 | -export default { | ||
| 27 | - name: "authPage", | ||
| 28 | - mounted () { | ||
| 29 | // 授权登陆 | 21 | // 授权登陆 |
| 30 | Taro.login({ | 22 | Taro.login({ |
| 31 | success: function (res) { | 23 | success: function (res) { |
| ... | @@ -36,134 +28,61 @@ export default { | ... | @@ -36,134 +28,61 @@ export default { |
| 36 | }) | 28 | }) |
| 37 | request.post('/srv/?a=openid', { | 29 | request.post('/srv/?a=openid', { |
| 38 | code: res.code | 30 | code: res.code |
| 39 | - // openid: '0002' | ||
| 40 | - // openid: 'o5NFZ5cFQtLRy3aVHaZMLkjHFusI' | ||
| 41 | - // openid: 'o5NFZ5TpgG4FwYursGCLjcUJH2ak' | ||
| 42 | - // openid: 'o5NFZ5cqroPYwawCp8FEOxewtgnw' | ||
| 43 | }) | 31 | }) |
| 44 | .then(res => { | 32 | .then(res => { |
| 45 | - if (res.data.code) { | 33 | + if (res.data.code === 1) { // 成功 |
| 46 | - var cookie = res.cookies[0]; | 34 | + var cookie = res.cookies ? res.cookies[0] : (res.header['Set-Cookie'] || res.header['set-cookie']); |
| 47 | - if (cookie != null) { | 35 | + // 有些时候 cookie 可能是一个数组,或者分号分隔的字符串 |
| 48 | - wx.setStorageSync("sessionid", res.cookies[0]);//服务器返回的 Set-Cookie,保存到本地 | 36 | + // axios-miniprogram 返回的 cookies 应该是一个数组 |
| 49 | - //TAG 小程序绑定cookie | 37 | + |
| 50 | - // 修改请求头 | 38 | + if (cookie) { |
| 51 | - request.defaults.headers.cookie = res.cookies[0]; | 39 | + // 处理 cookie 格式,如果包含分号,取第一个 |
| 52 | - // if (res.data.data.avatar) { | 40 | + if (Array.isArray(cookie)) cookie = cookie[0]; |
| 53 | - // Taro.reLaunch({ | 41 | + // 简单处理,通常服务器返回 PHPSESSID=xxx; path=/ |
| 54 | - // url: '../../' + getCurrentPageParam().url | 42 | + // 我们存入 storage |
| 55 | - // }) | 43 | + Taro.setStorageSync("sessionid", cookie); |
| 56 | - // } else { // 头像没有设置跳转完善信息页面 | 44 | + |
| 57 | - // Taro.redirectTo({ | 45 | + // 返回上一页 |
| 58 | - // url: '../apxUserInfo/index' | ||
| 59 | - // }) | ||
| 60 | - // } | ||
| 61 | - // TAG:处理分享跳转问题 | ||
| 62 | - const params = getCurrentPageParam(); | ||
| 63 | - if (getCurrentPageParam().url === 'pages/detail/index') { // 详情页的分享跳转处理 | ||
| 64 | - Taro.reLaunch({ | ||
| 65 | - url: `../../${params.url}?id=${params.id}&start_date=${params.start_date}&end_date=${params.end_date}` | ||
| 66 | - }) | ||
| 67 | - } else { // 其他页面分享跳首页 | ||
| 68 | - Taro.reLaunch({ | ||
| 69 | - url: `/pages/index/index?first_in=${wx.getStorageSync("first_in")}` | ||
| 70 | - }) | ||
| 71 | - } | ||
| 72 | Taro.hideLoading(); | 46 | Taro.hideLoading(); |
| 47 | + Taro.navigateBack({ | ||
| 48 | + fail: () => { | ||
| 49 | + Taro.reLaunch({ url: '/pages/index/index' }) | ||
| 50 | + } | ||
| 51 | + }); | ||
| 52 | + } else { | ||
| 53 | + console.warn('No cookie received'); | ||
| 54 | + Taro.hideLoading(); | ||
| 55 | + Taro.showToast({ title: '授权失败: 无Cookie', icon: 'none' }); | ||
| 73 | } | 56 | } |
| 74 | } else { | 57 | } else { |
| 75 | console.warn(res.data.msg); | 58 | console.warn(res.data.msg); |
| 76 | Taro.hideLoading(); | 59 | Taro.hideLoading(); |
| 60 | + Taro.showToast({ title: res.data.msg || '授权失败', icon: 'none' }); | ||
| 77 | } | 61 | } |
| 78 | }) | 62 | }) |
| 79 | .catch(err => { | 63 | .catch(err => { |
| 80 | console.error(err); | 64 | console.error(err); |
| 81 | Taro.hideLoading(); | 65 | Taro.hideLoading(); |
| 66 | + Taro.showToast({ title: '网络错误', icon: 'none' }); | ||
| 82 | }); | 67 | }); |
| 83 | } else { | 68 | } else { |
| 84 | console.log('登录失败!' + res.errMsg) | 69 | console.log('登录失败!' + res.errMsg) |
| 70 | + Taro.showToast({ title: '微信登录失败', icon: 'none' }); | ||
| 85 | } | 71 | } |
| 86 | } | 72 | } |
| 87 | }) | 73 | }) |
| 88 | - }, | 74 | +}) |
| 89 | - data () { | ||
| 90 | - return { | ||
| 91 | - canIUse: wx.canIUse('button.open-type.getUserInfo') | ||
| 92 | - } | ||
| 93 | - }, | ||
| 94 | - onLoad: function() { | ||
| 95 | - // 查看是否授权 | ||
| 96 | - // wx.getSetting({ | ||
| 97 | - // success (res){ | ||
| 98 | - // if (res.authSetting['scope.userInfo']) { | ||
| 99 | - // // 已经授权,可以直接调用 getUserInfo 获取头像昵称 | ||
| 100 | - // wx.getUserInfo({ | ||
| 101 | - // success: function(res) { | ||
| 102 | - // console.warn(res.userInfo) | ||
| 103 | - // } | ||
| 104 | - // }) | ||
| 105 | - // } | ||
| 106 | - // } | ||
| 107 | - // }) | ||
| 108 | - }, | ||
| 109 | - methods: { | ||
| 110 | - bindGetUserInfo (e) { | ||
| 111 | - console.warn(e.detail.userInfo) | ||
| 112 | - }, | ||
| 113 | - // auth () { | ||
| 114 | - // Taro.getSetting({ | ||
| 115 | - // success: function (res) { | ||
| 116 | - // if (!res.authSetting['scope.userInfo']) { | ||
| 117 | - // console.warn(0); | ||
| 118 | - // Taro.authorize({ | ||
| 119 | - // scope: 'scope.userInfo', | ||
| 120 | - // success: function () { | ||
| 121 | - // Taro.getUserInfo({ | ||
| 122 | - // success: function(res) { | ||
| 123 | - // var userInfo = res.userInfo | ||
| 124 | - // console.warn(userInfo); | ||
| 125 | - // } | ||
| 126 | - // }) | ||
| 127 | - // }, | ||
| 128 | - // fail: function (error) { | ||
| 129 | - // console.error(error) | ||
| 130 | - // } | ||
| 131 | - // }) | ||
| 132 | - // } | ||
| 133 | - // } | ||
| 134 | - // }) | ||
| 135 | - // } | ||
| 136 | - auth () { | ||
| 137 | - // wx.getSetting({ | ||
| 138 | - // success (res){ | ||
| 139 | - // if (res.authSetting['scope.userInfo']) { | ||
| 140 | - // // 已经授权,可以直接调用 getUserInfo 获取头像昵称 | ||
| 141 | - // wx.getUserInfo({ | ||
| 142 | - // success: function(res) { | ||
| 143 | - // console.warn(res.userInfo) | ||
| 144 | - // } | ||
| 145 | - // }) | ||
| 146 | - // } | ||
| 147 | - // } | ||
| 148 | - // }) | ||
| 149 | - wx.getSetting({ | ||
| 150 | - success(res) { | ||
| 151 | - if (!res.authSetting['scope.userInfo']) { | ||
| 152 | - wx.authorize({ | ||
| 153 | - scope: 'scope.userInfo', | ||
| 154 | - success () { | ||
| 155 | - // 已经授权,可以直接调用 getUserInfo 获取头像昵称 | ||
| 156 | - wx.getUserInfo({ | ||
| 157 | - success: function(res) { | ||
| 158 | - console.warn(res.userInfo) | ||
| 159 | - } | ||
| 160 | - }) | ||
| 161 | - } | ||
| 162 | - }) | ||
| 163 | - } | ||
| 164 | - } | ||
| 165 | - }) | ||
| 166 | - } | ||
| 167 | - } | ||
| 168 | -}; | ||
| 169 | </script> | 75 | </script> |
| 76 | + | ||
| 77 | +<style lang="less"> | ||
| 78 | +.auth-page { | ||
| 79 | + height: 100vh; | ||
| 80 | + display: flex; | ||
| 81 | + align-items: center; | ||
| 82 | + justify-content: center; | ||
| 83 | + .loading { | ||
| 84 | + text-align: center; | ||
| 85 | + color: #999; | ||
| 86 | + } | ||
| 87 | +} | ||
| 88 | +</style> | ... | ... |
src/pages/booking/index.vue
0 → 100644
This diff is collapsed. Click to expand it.
src/pages/bookingCode/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-16 10:06:47 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 17:48:42 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/bookingCode/index.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="booking-code-page"> | ||
| 10 | + <view style="padding: 1rem;"> | ||
| 11 | + <qrCode></qrCode> | ||
| 12 | + <view class="warning"> | ||
| 13 | + <view><nut-icon name="tips" /> 温馨提示</view> | ||
| 14 | + <view style="margin-top: 0.5rem;">一人一码,扫码或识别身份证成功后进入</view> | ||
| 15 | + <view style="height: 8rem;"></view> | ||
| 16 | + </view> | ||
| 17 | + </view> | ||
| 18 | + <view class="index-nav"> | ||
| 19 | + <view class="nav-logo" @tap="toHome"> | ||
| 20 | + <image :src="icon_3" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 21 | + 首页 | ||
| 22 | + </view> | ||
| 23 | + <view class="nav-logo"> | ||
| 24 | + <image :src="icon_4" style="width: 1.5rem; height: 1.5rem; margin-bottom: 0.1rem;" /> | ||
| 25 | + 预约码 | ||
| 26 | + </view> | ||
| 27 | + <view class="nav-logo" @tap="toMy"> | ||
| 28 | + <image :src="icon_5" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 29 | + 我的 | ||
| 30 | + </view> | ||
| 31 | + </view> | ||
| 32 | + </view> | ||
| 33 | +</template> | ||
| 34 | + | ||
| 35 | +<script setup> | ||
| 36 | +import { ref } from 'vue' | ||
| 37 | +import Taro from '@tarojs/taro' | ||
| 38 | +import qrCode from '@/components/qrCode'; | ||
| 39 | +import icon_3 from '@/assets/images/首页01@2x.png' | ||
| 40 | +import icon_4 from '@/assets/images/二维码icon.png' | ||
| 41 | +import icon_5 from '@/assets/images/我的01@2x.png' | ||
| 42 | +import { useGo } from '@/hooks/useGo' | ||
| 43 | + | ||
| 44 | +const go = useGo(); | ||
| 45 | + | ||
| 46 | +const toMy = () => { // 跳转到我的 | ||
| 47 | + go('/pages/me/index'); | ||
| 48 | +} | ||
| 49 | +const toHome = () => { // 跳转到首页 | ||
| 50 | + go('/pages/index/index'); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +</script> | ||
| 54 | + | ||
| 55 | +<style lang="less"> | ||
| 56 | +.booking-code-page { | ||
| 57 | + position: relative; | ||
| 58 | + min-height: 100vh; | ||
| 59 | + background-color: #F6F6F6; | ||
| 60 | + | ||
| 61 | + .warning { | ||
| 62 | + text-align: center; | ||
| 63 | + color: #A67939; | ||
| 64 | + margin-top: 1rem; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + .index-nav { | ||
| 68 | + position: fixed; | ||
| 69 | + bottom: 0; | ||
| 70 | + left: 0; | ||
| 71 | + width: 100vw; | ||
| 72 | + height: 10vh; | ||
| 73 | + background: #FFFFFF; | ||
| 74 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 75 | + display: flex; | ||
| 76 | + align-items: center; | ||
| 77 | + justify-content: space-around; | ||
| 78 | + color: #A67939; | ||
| 79 | + .nav-logo { | ||
| 80 | + position: relative; | ||
| 81 | + display: flex; | ||
| 82 | + flex-direction: column; | ||
| 83 | + align-items: center; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | +} | ||
| 87 | +</style> |
src/pages/bookingDetail/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-16 13:19:23 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 16:10:10 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/bookingDetail/index.vue | ||
| 6 | + * @Description: 预约记录详情 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="booking-detail-page"> | ||
| 10 | + <qrCode :status="qrCodeStatus" type="detail" :payId="pay_id"></qrCode> | ||
| 11 | + <view v-if="billInfo.pay_id" class="detail-wrapper"> | ||
| 12 | + <view class="detail-item"> | ||
| 13 | + <view>参访时间:</view> | ||
| 14 | + <view>{{ billInfo?.datetime }}</view> | ||
| 15 | + </view> | ||
| 16 | + <view class="detail-item"> | ||
| 17 | + <view>参访人数:</view> | ||
| 18 | + <view>{{ billInfo?.total_qty }} 人</view> | ||
| 19 | + </view> | ||
| 20 | + <view class="detail-item"> | ||
| 21 | + <view>支付金额:</view> | ||
| 22 | + <view>¥ {{ billInfo?.total_amt }}</view> | ||
| 23 | + </view> | ||
| 24 | + <view class="detail-item"> | ||
| 25 | + <view>下单时间:</view> | ||
| 26 | + <view>{{ billInfo?.order_time }}</view> | ||
| 27 | + </view> | ||
| 28 | + <view class="detail-item"> | ||
| 29 | + <view>订单编号:</view> | ||
| 30 | + <view>{{ billInfo?.pay_id }}</view> | ||
| 31 | + </view> | ||
| 32 | + <view class="detail-item"> | ||
| 33 | + <view>订单状态:</view> | ||
| 34 | + <view>{{ qrCodeStatusText }}</view> | ||
| 35 | + </view> | ||
| 36 | + </view> | ||
| 37 | + <view style="height: 5rem;"></view> | ||
| 38 | + <view v-if="billInfo.status === CodeStatus.SUCCESS && billInfo.show_cancel_reserve === 1" class="cancel-wrapper"> | ||
| 39 | + <view @tap="cancelBooking" class="cancel-btn ">取消预约</view> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | +</template> | ||
| 43 | + | ||
| 44 | +<script setup> | ||
| 45 | +import { ref, computed } from 'vue' | ||
| 46 | +import Taro, { useDidShow, useRouter as useTaroRouter } from '@tarojs/taro' | ||
| 47 | +import { useGo } from '@/hooks/useGo' | ||
| 48 | +import qrCode from '@/components/qrCode'; | ||
| 49 | +import { billInfoAPI, icbcRefundAPI } from '@/api/index' | ||
| 50 | +import { formatDatetime } from '@/utils/tools'; | ||
| 51 | + | ||
| 52 | +const router = useTaroRouter(); | ||
| 53 | +const go = useGo(); | ||
| 54 | + | ||
| 55 | +const pay_id = ref(''); | ||
| 56 | +const qrCodeStatus = ref(''); | ||
| 57 | +const billInfo = ref({}); | ||
| 58 | + | ||
| 59 | +const CodeStatus = { | ||
| 60 | + APPLY: '1', | ||
| 61 | + PAYING: '2', | ||
| 62 | + SUCCESS: '3', | ||
| 63 | + CANCEL: '5', | ||
| 64 | + CANCELED: '7', | ||
| 65 | + USED: '9', | ||
| 66 | + REFUNDING: '11' | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +const qrCodeStatusText = computed(() => { | ||
| 70 | + const status = billInfo.value?.status; | ||
| 71 | + switch (status) { | ||
| 72 | + case CodeStatus.SUCCESS: return '预约成功'; | ||
| 73 | + case CodeStatus.CANCEL: return '已取消'; | ||
| 74 | + case CodeStatus.USED: return '已使用'; | ||
| 75 | + case CodeStatus.REFUNDING: return '退款中'; | ||
| 76 | + default: return '未知状态'; | ||
| 77 | + } | ||
| 78 | +}) | ||
| 79 | + | ||
| 80 | +const cancelBooking = async () => { | ||
| 81 | + const { confirm } = await Taro.showModal({ | ||
| 82 | + title: '温馨提示', | ||
| 83 | + content: '是否取消预约?', | ||
| 84 | + confirmColor: '#A67939' | ||
| 85 | + }); | ||
| 86 | + | ||
| 87 | + if (confirm) { | ||
| 88 | + Taro.showLoading({ title: '取消中...' }); | ||
| 89 | + const { code, data } = await icbcRefundAPI({ pay_id: pay_id.value }); | ||
| 90 | + Taro.hideLoading(); | ||
| 91 | + if (code) { | ||
| 92 | + Taro.showToast({ title: '取消成功' }); | ||
| 93 | + Taro.navigateBack(); | ||
| 94 | + } else { | ||
| 95 | + Taro.showToast({ title: '取消失败', icon: 'none' }); | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +useDidShow(async () => { | ||
| 101 | + pay_id.value = router.params.pay_id; | ||
| 102 | + if (pay_id.value) { | ||
| 103 | + const { code, data } = await billInfoAPI({ pay_id: pay_id.value }); | ||
| 104 | + if (code) { | ||
| 105 | + data.datetime = data && formatDatetime(data); | ||
| 106 | + data.order_time = data.created_time ? data.created_time.slice(0, -3) : ''; | ||
| 107 | + billInfo.value = data; | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | +}) | ||
| 111 | +</script> | ||
| 112 | + | ||
| 113 | +<style lang="less"> | ||
| 114 | +.booking-detail-page { | ||
| 115 | + min-height: 100vh; | ||
| 116 | + background-color: #F6F6F6; | ||
| 117 | + padding: 1rem; | ||
| 118 | + | ||
| 119 | + .detail-wrapper { | ||
| 120 | + background-color: #FFF; | ||
| 121 | + border-radius: 8px; | ||
| 122 | + padding: 1rem; | ||
| 123 | + margin-top: 1rem; | ||
| 124 | + box-shadow: 0rem 0rem 0.92rem 0rem rgba(106,106,106,0.1); | ||
| 125 | + | ||
| 126 | + .detail-item { | ||
| 127 | + display: flex; | ||
| 128 | + justify-content: space-between; | ||
| 129 | + margin-bottom: 0.8rem; | ||
| 130 | + color: #333; | ||
| 131 | + font-size: 0.95rem; | ||
| 132 | + | ||
| 133 | + &:last-child { | ||
| 134 | + margin-bottom: 0; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + view:first-child { | ||
| 138 | + color: #999; | ||
| 139 | + width: 5rem; | ||
| 140 | + } | ||
| 141 | + view:last-child { | ||
| 142 | + flex: 1; | ||
| 143 | + text-align: right; | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + .cancel-wrapper { | ||
| 149 | + position: fixed; | ||
| 150 | + bottom: 0; | ||
| 151 | + left: 0; | ||
| 152 | + width: 100vw; | ||
| 153 | + background-color: #FFF; | ||
| 154 | + padding: 1rem; | ||
| 155 | + box-sizing: border-box; | ||
| 156 | + | ||
| 157 | + .cancel-btn { | ||
| 158 | + background-color: #FFF; | ||
| 159 | + color: #A67939; | ||
| 160 | + border: 1px solid #A67939; | ||
| 161 | + text-align: center; | ||
| 162 | + padding: 0.8rem 0; | ||
| 163 | + border-radius: 8px; | ||
| 164 | + font-size: 1.1rem; | ||
| 165 | + } | ||
| 166 | + } | ||
| 167 | +} | ||
| 168 | +</style> |
src/pages/bookingList/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-16 11:37:10 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 15:20:12 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/bookingList/index.vue | ||
| 6 | + * @Description: 预约记录列表页 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="booking-list-page"> | ||
| 10 | + <view v-for="(item, index) in bookingList" :key="index"> | ||
| 11 | + <reserveCard :data="item" /> | ||
| 12 | + </view> | ||
| 13 | + | ||
| 14 | + <view v-if="loading" style="text-align: center; color: #999; padding: 10px;">加载中...</view> | ||
| 15 | + <view v-if="finished && bookingList.length > 0" style="text-align: center; color: #999; padding: 10px;">没有更多了</view> | ||
| 16 | + | ||
| 17 | + <view v-if="!bookingList.length && finished" class="no-qrcode"> | ||
| 18 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem; height: 10rem;" /> | ||
| 19 | + <view class="no-qrcode-title">您还没有预约过参观</view> | ||
| 20 | + </view> | ||
| 21 | + </view> | ||
| 22 | +</template> | ||
| 23 | + | ||
| 24 | +<script setup> | ||
| 25 | +import { ref } from 'vue' | ||
| 26 | +import Taro, { useDidShow, useReachBottom } from '@tarojs/taro' | ||
| 27 | +import { billListAPI } from '@/api/index' | ||
| 28 | +import { formatDatetime } from '@/utils/tools'; | ||
| 29 | +import reserveCard from '@/components/reserveCard.vue' | ||
| 30 | + | ||
| 31 | +const page = ref(1); | ||
| 32 | +const limit = ref(5); | ||
| 33 | +const bookingList = ref([]); | ||
| 34 | +const loading = ref(false); | ||
| 35 | +const finished = ref(false); | ||
| 36 | + | ||
| 37 | +const loadData = async (isRefresh = false) => { | ||
| 38 | + if (loading.value || (finished.value && !isRefresh)) return; | ||
| 39 | + | ||
| 40 | + loading.value = true; | ||
| 41 | + if (isRefresh) { | ||
| 42 | + page.value = 1; | ||
| 43 | + finished.value = false; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + const { code, data } = await billListAPI({ page: page.value, row_num: limit.value }); | ||
| 47 | + loading.value = false; | ||
| 48 | + | ||
| 49 | + if (code) { | ||
| 50 | + data.forEach(item => { | ||
| 51 | + item.booking_time = item && formatDatetime(item); | ||
| 52 | + item.order_time = item.created_time ? item.created_time.slice(0, -3) : ''; | ||
| 53 | + }); | ||
| 54 | + | ||
| 55 | + if (isRefresh) { | ||
| 56 | + bookingList.value = data; | ||
| 57 | + } else { | ||
| 58 | + bookingList.value = bookingList.value.concat(data); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + if (data.length < limit.value) { | ||
| 62 | + finished.value = true; | ||
| 63 | + } else { | ||
| 64 | + page.value++; | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +useDidShow(() => { | ||
| 70 | + loadData(true); | ||
| 71 | +}); | ||
| 72 | + | ||
| 73 | +useReachBottom(() => { | ||
| 74 | + loadData(); | ||
| 75 | +}); | ||
| 76 | +</script> | ||
| 77 | + | ||
| 78 | +<style lang="less"> | ||
| 79 | +.booking-list-page { | ||
| 80 | + padding: 1rem; | ||
| 81 | + min-height: 100vh; | ||
| 82 | + background-color: #F6F6F6; | ||
| 83 | + | ||
| 84 | + .no-qrcode { | ||
| 85 | + display: flex; | ||
| 86 | + justify-content: center; | ||
| 87 | + align-items: center; | ||
| 88 | + flex-direction: column; | ||
| 89 | + padding-top: 5rem; | ||
| 90 | + | ||
| 91 | + .no-qrcode-title { | ||
| 92 | + color: #A67939; | ||
| 93 | + font-size: 1.05rem; | ||
| 94 | + margin-top: 1rem; | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | +</style> |
src/pages/callback/index.config.js
0 → 100644
src/pages/callback/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="callback-page"> | ||
| 3 | + <view> | ||
| 4 | + <view v-if="pay_status === PAY_STATUS.FAIL" class="text-prompts"> | ||
| 5 | + <image src="https://cdn.ipadbiz.cn/xys/booking/shibai.png" mode="widthFix" class="status-icon"/> | ||
| 6 | + <view class="text">支付失败</view> | ||
| 7 | + </view> | ||
| 8 | + <view v-else class="text-prompts"> | ||
| 9 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%88%90%E5%8A%9F@2x.png?imageMogr2/thumbnail/200x/strip/quality/70" mode="widthFix" class="status-icon"/> | ||
| 10 | + <!-- <view class="text">支付完成</view> --> | ||
| 11 | + </view> | ||
| 12 | + <view class="appointment-information"> | ||
| 13 | + <view class="info-item">参观人数:<text>{{ billInfo?.total_qty || 0 }} 人</text></view> | ||
| 14 | + <view class="info-item">参访时间:<text>{{ billInfo?.datetime || '--' }}</text></view> | ||
| 15 | + <view class="info-item">支付金额:<text>¥ {{ billInfo?.total_amt || 0 }}</text></view> | ||
| 16 | + </view> | ||
| 17 | + <view style="padding: 0.5rem; display: flex; justify-content: center; margin-top: 1rem;"> | ||
| 18 | + <nut-button color="#A67939" size="small" @click="returnMerchant">返回首页</nut-button> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + </view> | ||
| 22 | +</template> | ||
| 23 | + | ||
| 24 | +<script setup> | ||
| 25 | +import { ref, onMounted } from 'vue' | ||
| 26 | +import Taro, { useRouter } from '@tarojs/taro' | ||
| 27 | +import { onAuthBillInfoAPI } from '@/api/index' | ||
| 28 | +import { useGo } from '@/hooks/useGo' | ||
| 29 | +import { formatDatetime } from '@/utils/tools' | ||
| 30 | + | ||
| 31 | +const router = useRouter() | ||
| 32 | +const go = useGo() | ||
| 33 | + | ||
| 34 | +const billInfo = ref({}) | ||
| 35 | +const PAY_STATUS = { | ||
| 36 | + SUCCESS: '0', | ||
| 37 | + FAIL: '1', | ||
| 38 | + UNKNOWN: '2', | ||
| 39 | +} | ||
| 40 | +const pay_status = ref('0') // Default to success as per logic | ||
| 41 | + | ||
| 42 | +const out_trade_no = router.params.out_trade_no | ||
| 43 | + | ||
| 44 | +const getBillInfo = async () => { | ||
| 45 | + if (!out_trade_no) return | ||
| 46 | + | ||
| 47 | + try { | ||
| 48 | + // Get order details | ||
| 49 | + const { code, data } = await onAuthBillInfoAPI({ order_id: out_trade_no }) | ||
| 50 | + if (code && data) { | ||
| 51 | + data.datetime = data && formatDatetime(data) | ||
| 52 | + billInfo.value = data | ||
| 53 | + } else { | ||
| 54 | + // Handle error if needed | ||
| 55 | + } | ||
| 56 | + } catch (e) { | ||
| 57 | + console.error(e) | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +const returnMerchant = () => { | ||
| 62 | + go('/pages/index/index') | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +onMounted(() => { | ||
| 66 | + getBillInfo() | ||
| 67 | +}) | ||
| 68 | +</script> | ||
| 69 | + | ||
| 70 | +<style lang="less"> | ||
| 71 | +.callback-page { | ||
| 72 | + padding: 1rem; | ||
| 73 | + background: #fff; | ||
| 74 | + min-height: 100vh; | ||
| 75 | + | ||
| 76 | + .text-prompts { | ||
| 77 | + display: flex; | ||
| 78 | + flex-direction: column; | ||
| 79 | + align-items: center; | ||
| 80 | + margin-bottom: 2rem; | ||
| 81 | + padding-top: 2rem; | ||
| 82 | + | ||
| 83 | + .status-icon { | ||
| 84 | + width: 100px; | ||
| 85 | + height: 100px; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + .text { | ||
| 89 | + margin-top: 1rem; | ||
| 90 | + font-size: 1.2rem; | ||
| 91 | + color: #333; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + .appointment-information { | ||
| 96 | + background: #f8f8f8; | ||
| 97 | + padding: 1rem; | ||
| 98 | + border-radius: 8px; | ||
| 99 | + | ||
| 100 | + .info-item { | ||
| 101 | + margin-bottom: 0.5rem; | ||
| 102 | + font-size: 0.9rem; | ||
| 103 | + color: #666; | ||
| 104 | + | ||
| 105 | + text { | ||
| 106 | + color: #333; | ||
| 107 | + font-weight: 500; | ||
| 108 | + margin-left: 0.5rem; | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | +} | ||
| 113 | +</style> |
| 1 | <!-- | 1 | <!-- |
| 2 | - * @Date: 2025-06-28 10:33:00 | 2 | + * @Date: 2023-06-21 10:23:09 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-01 11:13:13 | 4 | + * @LastEditTime: 2024-02-05 18:36:21 |
| 5 | - * @FilePath: /myApp/src/pages/index/index.vue | 5 | + * @FilePath: /xysBooking/src/views/index.vue |
| 6 | - * @Description: 文件描述 | 6 | + * @Description: 预约页首页 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| 9 | - <view class="index"> | 9 | + <view class="index-page"> |
| 10 | - <nut-button type="primary" @click="onClick">按钮</nut-button> | 10 | + <view class="index-content"> |
| 11 | - <nut-toast v-model:visible="show" msg="你成功了" /> | 11 | + <view style="height: 30vh;"> |
| 12 | - <View className="text-[#acc855] text-[100px]">Hello world!</View> | 12 | + <swiper class="my-swipe" :autoplay="true" :interval="3000" indicator-dots indicator-color="white" :circular="true"> |
| 13 | + <swiper-item> | ||
| 14 | + <image style="height: 30vh; width: 100vw;" src="https://cdn.ipadbiz.cn/xys/booking/banner.jpg" mode="aspectFill" /> | ||
| 15 | + </swiper-item> | ||
| 16 | + </swiper> | ||
| 17 | + </view> | ||
| 18 | + | ||
| 19 | + <view ref="root" class="index-circular"> | ||
| 20 | + <view class="booking-wrapper"> | ||
| 21 | + <view class="booking" @tap="toBooking"> | ||
| 22 | + <view><image :src="icon_1" style="width: 3rem; height: 3rem;" /></view> | ||
| 23 | + <view style="color: #FFF;">开始预约</view> | ||
| 24 | + </view> | ||
| 25 | + </view> | ||
| 26 | + </view> | ||
| 27 | + <view class="logo"></view> | ||
| 28 | + </view> | ||
| 29 | + <view class="index-nav"> | ||
| 30 | + <view class="nav-logo"> | ||
| 31 | + <image :src="icon_3" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 32 | + 首页 | ||
| 33 | + </view> | ||
| 34 | + <view class="nav-logo" @tap="toCode"> | ||
| 35 | + <image :src="icon_4" style="width: 5rem; height: 5rem; position: absolute; top: -4rem;" /> | ||
| 36 | + <!-- <van-icon size="1.5rem" name="wap-home" color="#FFF" style="opacity: 0;" /> --> | ||
| 37 | + 预约码 | ||
| 38 | + </view> | ||
| 39 | + <view class="nav-logo" @tap="toMy"> | ||
| 40 | + <image :src="icon_5" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 41 | + 我的 | ||
| 42 | + </view> | ||
| 43 | + </view> | ||
| 13 | </view> | 44 | </view> |
| 14 | </template> | 45 | </template> |
| 15 | 46 | ||
| 16 | <script setup> | 47 | <script setup> |
| 17 | -import Taro from '@tarojs/taro' | 48 | +import { ref } from 'vue' |
| 18 | -import '@tarojs/taro/html.css' | 49 | +import Taro, { useDidShow, useShareAppMessage } from '@tarojs/taro' |
| 19 | -import { ref, onMounted } from 'vue' | 50 | +// import { showSuccessToast, showFailToast } from 'vant'; // NutUI 或 Taro API |
| 20 | -import { useDidShow, useReady } from '@tarojs/taro' | 51 | +import { billListAPI } from '@/api/index'; |
| 21 | -import "./index.less"; | 52 | +import { useGo } from '@/hooks/useGo' |
| 53 | +import icon_1 from '@/assets/images/立即预约@2x.png' | ||
| 54 | +import icon_2 from '@/assets/images/预约记录@2x.png' | ||
| 55 | +import icon_3 from '@/assets/images/首页02@2x.png' | ||
| 56 | +import icon_4 from '@/assets/images/二维码icon.png' | ||
| 57 | +import icon_5 from '@/assets/images/我的01@2x.png' | ||
| 58 | +import icon_6 from '@/assets/images/luru@2x.png' | ||
| 22 | 59 | ||
| 23 | -const show = ref(false) | 60 | +const go = useGo(); |
| 24 | -const onClick = () => { | 61 | + |
| 25 | - show.value = true | 62 | +const toBooking = () => { // 跳转到预约须知 |
| 63 | + go('/notice'); | ||
| 64 | +} | ||
| 65 | +const toRecord = () => { // 跳转到预约记录 | ||
| 66 | + go('/bookingList'); | ||
| 67 | +} | ||
| 68 | +const toSearch = () => { // 跳转到寺院录入 | ||
| 69 | + go('/search'); | ||
| 70 | +} | ||
| 71 | +const toCode = () => { // 跳转到预约码 | ||
| 72 | + go('/bookingCode'); | ||
| 73 | +} | ||
| 74 | +const toMy = () => { // 跳转到我的 | ||
| 75 | + go('/me'); | ||
| 26 | } | 76 | } |
| 27 | 77 | ||
| 28 | -// 生命周期钩子 | 78 | +useDidShow(async () => { |
| 29 | -useDidShow(() => { | 79 | + // TAG: 触发授权页面 (检查 session 或调用接口触发 401) |
| 30 | - console.warn('index onShow') | 80 | + // 小程序中,request.js 拦截器会处理 401 跳转 |
| 31 | -}) | 81 | + await billListAPI({ page: 1, row_num: 1 }); |
| 82 | +}); | ||
| 32 | 83 | ||
| 33 | -useReady(async () => { | 84 | +useShareAppMessage(() => { |
| 34 | - console.warn('index onReady') | 85 | + return { |
| 35 | - // 版本更新检查 | 86 | + title: '西园寺预约', |
| 36 | - if (!Taro.canIUse("getUpdateManager")) { | 87 | + path: '/pages/index/index' |
| 37 | - Taro.showModal({ | ||
| 38 | - title: "提示", | ||
| 39 | - content: "当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试", | ||
| 40 | - showCancel: false, | ||
| 41 | - }); | ||
| 42 | - return; | ||
| 43 | } | 88 | } |
| 44 | - | ||
| 45 | - // https://developers.weixin.qq.com/miniprogram/dev/api/base/update/UpdateManager.html | ||
| 46 | - const updateManager = Taro.getUpdateManager(); | ||
| 47 | - | ||
| 48 | - updateManager.onCheckForUpdate((res) => { | ||
| 49 | - // 请求完新版本信息的回调 | ||
| 50 | - if (res.hasUpdate) { | ||
| 51 | - updateManager.onUpdateReady(function () { | ||
| 52 | - Taro.showModal({ | ||
| 53 | - title: "更新提示", | ||
| 54 | - content: "新版本已经准备好,是否重启应用?", | ||
| 55 | - success: function (res) { | ||
| 56 | - if (res.confirm) { | ||
| 57 | - // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 | ||
| 58 | - updateManager.applyUpdate(); | ||
| 59 | - } | ||
| 60 | - }, | ||
| 61 | - }); | ||
| 62 | - }); | ||
| 63 | - | ||
| 64 | - updateManager.onUpdateFailed(function () { | ||
| 65 | - // 新版本下载失败 | ||
| 66 | - Taro.showModal({ | ||
| 67 | - title: "更新提示", | ||
| 68 | - content: "新版本已上线,请删除当前小程序,重新搜索打开", | ||
| 69 | - }); | ||
| 70 | - }); | ||
| 71 | - } | ||
| 72 | - }); | ||
| 73 | }) | 89 | }) |
| 74 | 90 | ||
| 75 | -onMounted(() => { | ||
| 76 | - console.warn('index mounted') | ||
| 77 | -}) | ||
| 78 | - | ||
| 79 | -// 分享功能 | ||
| 80 | -wx.showShareMenu({ | ||
| 81 | - withShareTicket: true, | ||
| 82 | - menus: ['shareAppMessage', 'shareTimeline'] | ||
| 83 | -}) | ||
| 84 | </script> | 91 | </script> |
| 85 | 92 | ||
| 86 | -<script> | 93 | +<style lang="less"> |
| 87 | -import { getCurrentPageParam } from "@/utils/weapp"; | 94 | +.index-page { |
| 95 | + position: relative; | ||
| 96 | + height: 100vh; | ||
| 97 | + background-image: url('https://cdn.ipadbiz.cn/xys/booking/bg.jpg'); | ||
| 98 | + background-repeat: no-repeat; | ||
| 99 | + background-position: center; | ||
| 100 | + background-size: cover; /* 确保背景覆盖 */ | ||
| 101 | + .index-content { | ||
| 102 | + height: 90vh; | ||
| 103 | + .index-control { | ||
| 104 | + position: relative; | ||
| 105 | + display: flex; | ||
| 106 | + flex-direction: column; | ||
| 107 | + align-items: center; | ||
| 108 | + justify-content: center; | ||
| 109 | + margin-top: 10vh; | ||
| 110 | + // font-weight: bold; | ||
| 111 | + font-size: 1.15rem; | ||
| 112 | + .booking { | ||
| 113 | + display: flex; | ||
| 114 | + justify-content: center; | ||
| 115 | + align-items: center; | ||
| 116 | + background-color: #A67939; | ||
| 117 | + border-radius: 7px; | ||
| 118 | + color: #FFFFFF; | ||
| 119 | + padding: 0.7rem 4rem; | ||
| 120 | + border: 1px solid #A67939; | ||
| 121 | + } | ||
| 122 | + .record { | ||
| 123 | + display: flex; | ||
| 124 | + justify-content: center; | ||
| 125 | + align-items: center; | ||
| 126 | + color: #A67939; | ||
| 127 | + border-radius: 7px; | ||
| 128 | + padding: 0.7rem 4rem; | ||
| 129 | + border: 1px solid #A67939; | ||
| 130 | + margin-top: 1.5rem; | ||
| 131 | + } | ||
| 132 | + .search { | ||
| 133 | + display: flex; | ||
| 134 | + justify-content: center; | ||
| 135 | + align-items: center; | ||
| 136 | + color: #A67939; | ||
| 137 | + border-radius: 7px; | ||
| 138 | + padding: 0.7rem 4rem; | ||
| 139 | + border: 1px solid #A67939; | ||
| 140 | + margin-top: 1.5rem; | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + .index-circular { | ||
| 144 | + position: relative; | ||
| 145 | + display: flex; | ||
| 146 | + align-items: center; | ||
| 147 | + justify-content: center; | ||
| 148 | + margin-top: 10vh; | ||
| 149 | + // font-weight: bold; | ||
| 150 | + font-size: 1.1rem; | ||
| 88 | 151 | ||
| 89 | -export default { | 152 | + .booking-wrapper { |
| 90 | - name: "indexPage", | 153 | + height: 19vh; |
| 91 | - onHide () { | 154 | + width: 19vh; |
| 92 | - console.warn('index onHide') | 155 | + border-radius: 50%; |
| 93 | - }, | 156 | + background-color: rgba(166, 121, 57, 0.26); |
| 94 | - onShareAppMessage() { | 157 | + display: flex; |
| 95 | - let params = getCurrentPageParam(); | 158 | + align-items: center; |
| 96 | - // 设置菜单中的转发按钮触发转发事件时的转发内容 | 159 | + justify-content: center; |
| 97 | - var shareObj = { | 160 | + .booking { |
| 98 | - title: "xxx", // 默认是小程序的名称(可以写slogan等) | 161 | + height: 17vh; |
| 99 | - path: `pages/detail/index?id=${params.id}&start_date=${params.start_date}&end_date=${params.end_date}&room_type=${params.room_type}`, // 默认是当前页面,必须是以'/'开头的完整路径 | 162 | + width: 17vh; |
| 100 | - imageUrl: '', //自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径,支持PNG及JPG,不传入 imageUrl 则使用默认截图。显示图片长宽比是 5:4 | 163 | + border-radius: 50%; |
| 101 | - success: function (res) { | 164 | + background-color: #A67939; |
| 102 | - // 转发成功之后的回调 | 165 | + display: flex; |
| 103 | - if (res.errMsg == 'shareAppMessage:ok') { | 166 | + align-items: center; |
| 104 | - // | 167 | + justify-content: center; |
| 105 | - } | 168 | + flex-direction: column; |
| 106 | - }, | ||
| 107 | - fail: function () { | ||
| 108 | - // 转发失败之后的回调 | ||
| 109 | - if (res.errMsg == 'shareAppMessage:fail cancel') { | ||
| 110 | - // 用户取消转发 | ||
| 111 | - } else if (res.errMsg == 'shareAppMessage:fail') { | ||
| 112 | - // 转发失败,其中 detail message 为详细失败信息 | ||
| 113 | } | 169 | } |
| 114 | - }, | ||
| 115 | - complete: function () { | ||
| 116 | - // 转发结束之后的回调(转发成不成功都会执行) | ||
| 117 | } | 170 | } |
| 118 | } | 171 | } |
| 119 | - // 来自页面内的按钮的转发 | 172 | + .logo { |
| 120 | - // if (options.from == 'button') { | 173 | + position: absolute; |
| 121 | - // var eData = options.target.dataset; | 174 | + right: 0; |
| 122 | - // // 此处可以修改 shareObj 中的内容 | 175 | + bottom: calc(15vh); |
| 123 | - // shareObj.path = '/pages/goods/goods?goodId=' + eData.id; | 176 | + height: 30vh; |
| 124 | - // } | 177 | + width: 20vw; |
| 125 | - // 返回shareObj | 178 | + background-image: url('https://cdn.ipadbiz.cn/xys/booking/logo.png'); |
| 126 | - return shareObj; | 179 | + background-repeat: no-repeat; |
| 180 | + background-size: contain; | ||
| 181 | + background-position: center; | ||
| 182 | + } | ||
| 127 | } | 183 | } |
| 128 | -}; | 184 | + .my-swipe { |
| 129 | -</script> | 185 | + height: 30vh; |
| 186 | + swiper-item { /* Taro swiper-item 编译后 */ | ||
| 187 | + height: 30vh; | ||
| 188 | + width: 100vw; | ||
| 189 | + background-size: cover; | ||
| 190 | + background-repeat: no-repeat; | ||
| 191 | + background-position: center; | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + .index-nav { | ||
| 195 | + position: absolute; | ||
| 196 | + bottom: 0; | ||
| 197 | + left: 0; | ||
| 198 | + width: 100vw; | ||
| 199 | + height: 10vh; | ||
| 200 | + background: #FFFFFF; | ||
| 201 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 202 | + display: flex; | ||
| 203 | + align-items: center; | ||
| 204 | + justify-content: space-around; | ||
| 205 | + color: #A67939; | ||
| 206 | + .nav-logo { | ||
| 207 | + position: relative; | ||
| 208 | + display: flex; | ||
| 209 | + flex-direction: column; | ||
| 210 | + align-items: center; | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | +} | ||
| 214 | +</style> | ... | ... |
src/pages/me/index.config.js
0 → 100644
src/pages/me/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="my-page"> | ||
| 3 | + <view v-for="(item, index) in menu_list" :key="index" class="my-item" @tap="go(item.to)"> | ||
| 4 | + <view class="left"> | ||
| 5 | + <image :src="item.icon" style="width: 1.2rem; height: 1.2rem; margin-right: 0.5rem;" /> | ||
| 6 | + {{ item.name }} | ||
| 7 | + </view> | ||
| 8 | + <view> | ||
| 9 | + <nut-icon name="rect-right" size="1.2rem" /> | ||
| 10 | + </view> | ||
| 11 | + </view> | ||
| 12 | + <view class="index-nav"> | ||
| 13 | + <view class="nav-logo" @tap="toHome"> | ||
| 14 | + <image :src="icon_3" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 15 | + 首页 | ||
| 16 | + </view> | ||
| 17 | + <view class="nav-logo" @tap="toCode"> | ||
| 18 | + <image :src="icon_4" style="width: 1.5rem; height: 1.5rem; margin-bottom: 0.1rem;" /> | ||
| 19 | + 预约码 | ||
| 20 | + </view> | ||
| 21 | + <view class="nav-logo"> | ||
| 22 | + <image :src="icon_5" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 23 | + 我的 | ||
| 24 | + </view> | ||
| 25 | + </view> | ||
| 26 | + </view> | ||
| 27 | +</template> | ||
| 28 | + | ||
| 29 | +<script setup> | ||
| 30 | +import { ref } from 'vue' | ||
| 31 | +import Taro from '@tarojs/taro' | ||
| 32 | +import { useGo } from '@/hooks/useGo' | ||
| 33 | +import icon_3 from '@/assets/images/首页01@2x.png' | ||
| 34 | +import icon_4 from '@/assets/images/二维码icon.png' | ||
| 35 | +import icon_5 from '@/assets/images/我的02@2x.png' | ||
| 36 | + | ||
| 37 | +import icon_booking from '@/assets/images/预约记录@2x.png' | ||
| 38 | +import icon_visitor from '@/assets/images/我的01@2x.png' | ||
| 39 | +import icon_invite from '@/assets/images/二维码@2x2.png' | ||
| 40 | + | ||
| 41 | +const go = useGo(); | ||
| 42 | + | ||
| 43 | +const toCode = () => { // 跳转到预约码 | ||
| 44 | + go('/pages/bookingCode/index'); | ||
| 45 | +} | ||
| 46 | +const toHome = () => { // 跳转到首页 | ||
| 47 | + go('/pages/index/index'); | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +const menu_list = [{ | ||
| 51 | + icon: icon_booking, | ||
| 52 | + name: '预约记录', | ||
| 53 | + to: '/pages/bookingList/index' | ||
| 54 | +}, { | ||
| 55 | + icon: icon_visitor, | ||
| 56 | + name: '参观者', | ||
| 57 | + to: '/pages/visitorList/index' | ||
| 58 | +}, { | ||
| 59 | + icon: icon_invite, | ||
| 60 | + name: '邀请码', | ||
| 61 | + to: '/pages/search/index' | ||
| 62 | +}] | ||
| 63 | +</script> | ||
| 64 | + | ||
| 65 | +<style lang="less"> | ||
| 66 | +.my-page { | ||
| 67 | + position: relative; | ||
| 68 | + min-height: 100vh; | ||
| 69 | + background-color: #F6F6F6; | ||
| 70 | + padding: 1rem; | ||
| 71 | + | ||
| 72 | + .my-item { | ||
| 73 | + padding: 1rem; | ||
| 74 | + display: flex; | ||
| 75 | + justify-content:space-between; | ||
| 76 | + align-items: center; | ||
| 77 | + margin-bottom: 1rem; | ||
| 78 | + background-color: #FFF; | ||
| 79 | + border-radius: 5px; | ||
| 80 | + .left { | ||
| 81 | + color: #A67939; | ||
| 82 | + display: flex; | ||
| 83 | + align-items: center; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + .index-nav { | ||
| 87 | + position: fixed; | ||
| 88 | + bottom: 0; | ||
| 89 | + left: 0; | ||
| 90 | + width: 100vw; | ||
| 91 | + height: 10vh; | ||
| 92 | + background: #FFFFFF; | ||
| 93 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 94 | + display: flex; | ||
| 95 | + align-items: center; | ||
| 96 | + justify-content: space-around; | ||
| 97 | + color: #A67939; | ||
| 98 | + .nav-logo { | ||
| 99 | + position: relative; | ||
| 100 | + display: flex; | ||
| 101 | + flex-direction: column; | ||
| 102 | + align-items: center; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | +</style> |
src/pages/notice/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-15 11:43:01 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-02-04 22:29:54 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/notice/index.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="notice-page"> | ||
| 10 | + <view class="content"> | ||
| 11 | + <view style="text-align: center; font-size: 1.1rem; margin-bottom: 0.5rem;">温馨提示</view> | ||
| 12 | + <view> | ||
| 13 | + 为了您和他人的健康与安全,维护清净庄严的寺院环境,营造一个喜悦而祥和的节日氛围,请您留意并遵守以下注意事项: | ||
| 14 | + </view> | ||
| 15 | + <view v-for="(item, index) in note_text" :key="index" style="margin-top: 0.5rem;">{{ item }}</view> | ||
| 16 | + <view style="margin-top: 0.5rem;">谢谢您的支持与配合。祝您新春吉祥、万事如意。</view> | ||
| 17 | + </view> | ||
| 18 | + <view style="height: 8rem"></view> | ||
| 19 | + <view class="footer"> | ||
| 20 | + <nut-checkbox-group v-model="checked"> | ||
| 21 | + <nut-checkbox label="1" icon-size="1rem"> | ||
| 22 | + <text style="color: #a67939; font-size: 1rem">我已阅读并同意以上内容</text> | ||
| 23 | + </nut-checkbox> | ||
| 24 | + </nut-checkbox-group> | ||
| 25 | + <view @tap="confirmBtn" class="confirm-btn">确认,下一步</view> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | +</template> | ||
| 29 | + | ||
| 30 | +<script setup> | ||
| 31 | +import { ref } from "vue"; | ||
| 32 | +import Taro, { useDidShow } from '@tarojs/taro' | ||
| 33 | +import { useGo } from "@/hooks/useGo"; | ||
| 34 | + | ||
| 35 | +const go = useGo(); | ||
| 36 | +const note_text = [ | ||
| 37 | + '1、敬香贵在心诚,不在数量多少。三支清香,可表心诚。请带着虔诚心、恭敬心和清净心敬香礼佛。', | ||
| 38 | + '2、请不要自带香烛进寺院。山门殿两侧设有赠香处,凭香花券可免费领取三支清香。', | ||
| 39 | + '3、点燃香烛时请多加小心,以免灼伤自己与他人。', | ||
| 40 | + '4、请在指定燃香处燃香,禁止将香烛带入殿堂。禁止燃放烟花爆竹。', | ||
| 41 | + '5、请爱护公共绿地,请不要踩踏及在草坪上点烛燃香。', | ||
| 42 | + '6、请照看好身边的家人,以免走散。', | ||
| 43 | + '7、请保管好自己随身携带的钱物,以免丢失给您带来麻烦。', | ||
| 44 | + '8、您若有任何问题和困难,请向身边的法师或义工咨询、求助,或直接与客堂联系。电话:0512-65349545。', | ||
| 45 | + '9、预约如需退款,请在初七之后,到客堂办理。' | ||
| 46 | +]; | ||
| 47 | +const checked = ref([]); | ||
| 48 | + | ||
| 49 | +const confirmBtn = () => { | ||
| 50 | + if (checked.value.includes("1")) { | ||
| 51 | + go("/booking"); | ||
| 52 | + } else { | ||
| 53 | + Taro.showToast({ title: "请勾选同意须知", icon: "none" }); | ||
| 54 | + } | ||
| 55 | +}; | ||
| 56 | +</script> | ||
| 57 | + | ||
| 58 | +<style lang="less"> | ||
| 59 | +.notice-page { | ||
| 60 | + position: relative; | ||
| 61 | + min-height: 100vh; | ||
| 62 | + background-color: #F6F6F6; | ||
| 63 | + padding-top: 1px; // 防止 margin collapse | ||
| 64 | + .content { | ||
| 65 | + margin: 1rem; | ||
| 66 | + background-color: #ffffff; | ||
| 67 | + border-radius: 8px; | ||
| 68 | + padding: 1rem; | ||
| 69 | + color: #333; | ||
| 70 | + font-size: 0.9rem; | ||
| 71 | + line-height: 1.5; | ||
| 72 | + } | ||
| 73 | + .footer { | ||
| 74 | + position: fixed; | ||
| 75 | + bottom: 0; | ||
| 76 | + width: 100vw; | ||
| 77 | + background-color: #FFF; | ||
| 78 | + display: flex; | ||
| 79 | + flex-direction: column; | ||
| 80 | + padding: 1rem; | ||
| 81 | + box-sizing: border-box; | ||
| 82 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 83 | + | ||
| 84 | + .confirm-btn { | ||
| 85 | + background-color: #A67939; | ||
| 86 | + color: #FFF; | ||
| 87 | + text-align: center; | ||
| 88 | + padding: 0.8rem 0; | ||
| 89 | + border-radius: 8px; | ||
| 90 | + margin-top: 1rem; | ||
| 91 | + font-size: 1.1rem; | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | +} | ||
| 95 | +</style> |
src/pages/search/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-26 13:08:09 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 17:51:11 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/search/index.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="search-page"> | ||
| 10 | + <view> | ||
| 11 | + <view v-if="!is_search"> | ||
| 12 | + <view class="input-item"> | ||
| 13 | + <view>证件号码</view> | ||
| 14 | + <view> | ||
| 15 | + <input type="text" v-model="idCode" placeholder="请输入证件号码" @blur="checkIdCode" maxlength="18" style="width: 100%;"> | ||
| 16 | + </view> | ||
| 17 | + </view> | ||
| 18 | + <view style="color:#A67939; font-size: 0.95rem; text-align: center;"> | ||
| 19 | + <view> | ||
| 20 | + <nut-icon name="tips" /> 温馨提示 | ||
| 21 | + </view> | ||
| 22 | + <view style="margin-top: 0.5rem;">获取参观码,扫码或识别身份证成功进闸机</view> | ||
| 23 | + </view> | ||
| 24 | + </view> | ||
| 25 | + <view v-else> | ||
| 26 | + <qrCodeSearch :id="id_number" /> | ||
| 27 | + </view> | ||
| 28 | + <view v-if="!is_search" class="save-wrapper"> | ||
| 29 | + <view class="save-btn" @tap="searchBtn">查询</view> | ||
| 30 | + </view> | ||
| 31 | + <view v-else class="success-btn"> | ||
| 32 | + <view @tap="goToHome" class="btn-item btn-left">首页</view> | ||
| 33 | + <view @tap="goBack" class="btn-item btn-right">返回查询</view> | ||
| 34 | + </view> | ||
| 35 | + </view> | ||
| 36 | + <view class="logo"></view> | ||
| 37 | + </view> | ||
| 38 | +</template> | ||
| 39 | + | ||
| 40 | +<script setup> | ||
| 41 | +import { ref } from 'vue' | ||
| 42 | +import Taro from '@tarojs/taro' | ||
| 43 | +import qrCodeSearch from '@/components/qrCodeSearch'; | ||
| 44 | +import { useGo } from '@/hooks/useGo' | ||
| 45 | + | ||
| 46 | +const go = useGo(); | ||
| 47 | +const is_search = ref(false); | ||
| 48 | +const idCode = ref(''); | ||
| 49 | +const id_number = ref(''); | ||
| 50 | + | ||
| 51 | +// 简单的身份证校验 | ||
| 52 | +const validateCIN = (id) => { | ||
| 53 | + return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(id); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +const checkIdCode = () => { // 检查身份证号是否为空 | ||
| 57 | + let flag = true; | ||
| 58 | + if (idCode.value.length === 15) { // 15位身份证号码不校验 | ||
| 59 | + flag = true; | ||
| 60 | + } else { | ||
| 61 | + if (!validateCIN(idCode.value)) { | ||
| 62 | + Taro.showToast({ title: '请检查身份证号码', icon: 'none' }); | ||
| 63 | + flag = false; | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + return flag; | ||
| 67 | +} | ||
| 68 | + | ||
| 69 | +const searchBtn = async () => { | ||
| 70 | + // 查询用户信息 | ||
| 71 | + if (checkIdCode() && idCode.value) { | ||
| 72 | + is_search.value = true; | ||
| 73 | + id_number.value = idCode.value; | ||
| 74 | + idCode.value = '' | ||
| 75 | + } | ||
| 76 | +} | ||
| 77 | +const goBack = () => { | ||
| 78 | + is_search.value = false; | ||
| 79 | +} | ||
| 80 | +const goToHome = () => { | ||
| 81 | + go('/index') | ||
| 82 | +} | ||
| 83 | +</script> | ||
| 84 | + | ||
| 85 | +<style lang="less"> | ||
| 86 | +.search-page { | ||
| 87 | + padding: 1rem; | ||
| 88 | + min-height: 100vh; | ||
| 89 | + background-color: #F6F6F6; | ||
| 90 | + | ||
| 91 | + .input-item { | ||
| 92 | + background-color: #FFF; | ||
| 93 | + padding: 1rem; | ||
| 94 | + border-radius: 8px; | ||
| 95 | + margin-bottom: 1rem; | ||
| 96 | + | ||
| 97 | + view:first-child { | ||
| 98 | + margin-bottom: 0.5rem; | ||
| 99 | + font-weight: bold; | ||
| 100 | + } | ||
| 101 | + input { | ||
| 102 | + border-bottom: 1px solid #EEE; | ||
| 103 | + padding: 0.5rem 0; | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + .save-wrapper { | ||
| 108 | + margin-top: 2rem; | ||
| 109 | + .save-btn { | ||
| 110 | + background-color: #A67939; | ||
| 111 | + color: #FFF; | ||
| 112 | + text-align: center; | ||
| 113 | + padding: 0.8rem 0; | ||
| 114 | + border-radius: 8px; | ||
| 115 | + font-size: 1.1rem; | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + .success-btn { | ||
| 120 | + position: fixed; | ||
| 121 | + bottom: 2rem; | ||
| 122 | + width: 100vw; | ||
| 123 | + left: 0; | ||
| 124 | + display: flex; | ||
| 125 | + justify-content: space-around; | ||
| 126 | + | ||
| 127 | + .btn-item { | ||
| 128 | + width: 40%; | ||
| 129 | + text-align: center; | ||
| 130 | + padding: 0.8rem 0; | ||
| 131 | + border-radius: 8px; | ||
| 132 | + font-size: 1.1rem; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + .btn-left { | ||
| 136 | + border: 1px solid #A67939; | ||
| 137 | + color: #A67939; | ||
| 138 | + background-color: #FFF; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + .btn-right { | ||
| 142 | + background-color: #A67939; | ||
| 143 | + color: #FFF; | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + .logo { | ||
| 148 | + position: absolute; | ||
| 149 | + right: 0; | ||
| 150 | + bottom: 15vh; | ||
| 151 | + height: 30vh; | ||
| 152 | + width: 20vw; | ||
| 153 | + background-image: url('https://cdn.ipadbiz.cn/xys/booking/logo.png'); | ||
| 154 | + background-repeat: no-repeat; | ||
| 155 | + background-size: contain; | ||
| 156 | + background-position: center; | ||
| 157 | + opacity: 0.5; | ||
| 158 | + pointer-events: none; | ||
| 159 | + } | ||
| 160 | +} | ||
| 161 | +</style> |
src/pages/submit/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-15 16:25:51 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 15:18:58 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/submit/index.vue | ||
| 6 | + * @Description: 预约人员信息 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="submit-page"> | ||
| 10 | + <view @tap="goToBooking" class="visit-time"> | ||
| 11 | + <view>参访时间</view> | ||
| 12 | + <view><text style="font-size: 0.95rem;">{{ date }} {{ time }}</text> <nut-icon name="rect-right" /></view> | ||
| 13 | + </view> | ||
| 14 | + <view @tap="goToVisitor" class="add-visitors"> | ||
| 15 | + <view><nut-icon name="plus" /> 添加参观者</view> | ||
| 16 | + </view> | ||
| 17 | + <view v-if="visitorList.length" class="visitors-list"> | ||
| 18 | + <view v-for="(item, index) in visitorList" :key="index" @tap="addVisitor(item)" class="visitor-item"> | ||
| 19 | + <view style="margin-right: 1rem;"> | ||
| 20 | + <image v-if="!checked_visitors.includes(item.id)" :src="icon_check1" style="width: 1.2rem; height: 1.2rem;" /> | ||
| 21 | + <image v-else :src="icon_check2" style="width: 1.2rem; height: 1.2rem;" /> | ||
| 22 | + </view> | ||
| 23 | + <view> | ||
| 24 | + <view style="color: #A67939;">{{ item.name }}</view> | ||
| 25 | + <view>证件号:{{ formatId(item.id_number) }}</view> | ||
| 26 | + <view v-if="item.is_reserve === RESERVE_STATUS.ENABLE" style="color: #9C9A9A; font-size: 0.8rem;">*已预约过{{ date }}参观,请不要重复预约</view> | ||
| 27 | + </view> | ||
| 28 | + </view> | ||
| 29 | + </view> | ||
| 30 | + <view v-else class="no-visitors-list"> | ||
| 31 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem; height: 10rem;" /> | ||
| 32 | + <view class="no-visitors-list-title">您还没有添加过参观者</view> | ||
| 33 | + </view> | ||
| 34 | + <view style="height: 5rem;"></view> | ||
| 35 | + <view class="submit-wrapper"> | ||
| 36 | + <view class="control-wrapper"> | ||
| 37 | + <view class="left"> | ||
| 38 | + <view style="margin-left: 1rem; display: flex;align-items: center;"> | ||
| 39 | + 订单金额 <view style="color: #FF1919;display: inline-block;">¥<view style="font-size: 1.5rem;display: inline-block;"> {{ total }}</view></view> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | + <view @tap="submitBtn" class="right">提交订单</view> | ||
| 43 | + </view> | ||
| 44 | + <view style="font-size: 0.85rem;margin-left: 1rem;color: #FF1919; margin-bottom: 1rem;">提交后请在10分钟内完成支付</view> | ||
| 45 | + </view> | ||
| 46 | + </view> | ||
| 47 | +</template> | ||
| 48 | + | ||
| 49 | +<script setup> | ||
| 50 | +import { ref, computed } from 'vue' | ||
| 51 | +import Taro, { useDidShow, useRouter as useTaroRouter } from '@tarojs/taro' | ||
| 52 | +import { useGo } from '@/hooks/useGo' | ||
| 53 | +import icon_check1 from '@/assets/images/多选01@2x.png' | ||
| 54 | +import icon_check2 from '@/assets/images/多选02@2x.png' | ||
| 55 | +import { personListAPI, addReserveAPI } from '@/api/index' | ||
| 56 | + | ||
| 57 | +const router = useTaroRouter(); | ||
| 58 | +const go = useGo(); | ||
| 59 | + | ||
| 60 | +const visitorList = ref([]); | ||
| 61 | +const date = ref(''); | ||
| 62 | +const time = ref(''); | ||
| 63 | +const price = ref(0); | ||
| 64 | + | ||
| 65 | +/** | ||
| 66 | + * 生成15位身份证号中间8位替换为*号 | ||
| 67 | + * @param {*} inputString | ||
| 68 | + */ | ||
| 69 | +function replaceMiddleCharacters(inputString) { | ||
| 70 | + if (!inputString || inputString.length < 15) { | ||
| 71 | + return inputString; // 字符串长度不足,不进行替换 | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + const start = Math.floor((inputString.length - 8) / 2); // 开始替换的索引位置 | ||
| 75 | + const end = start + 8; // 结束替换的索引位置 | ||
| 76 | + | ||
| 77 | + const replacement = '*'.repeat(8); // 生成包含8个*号的字符串 | ||
| 78 | + | ||
| 79 | + const replacedString = inputString.substring(0, start) + replacement + inputString.substring(end); | ||
| 80 | + return replacedString; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +const formatId = (id) => { | ||
| 84 | + return replaceMiddleCharacters(id); | ||
| 85 | +}; | ||
| 86 | + | ||
| 87 | +const RESERVE_STATUS = { | ||
| 88 | + ENABLE: '1' | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +const checked_visitors = ref([]); | ||
| 92 | +const addVisitor = (item) => { | ||
| 93 | + if (item.is_reserve === RESERVE_STATUS.ENABLE) { // 今天已经预约 | ||
| 94 | + Taro.showToast({ title: '已预约过参观,请不要重复预约', icon: 'none' }) | ||
| 95 | + return; | ||
| 96 | + } | ||
| 97 | + if (checked_visitors.value.includes(item.id)) { | ||
| 98 | + checked_visitors.value = checked_visitors.value.filter((v) => v !== item.id); | ||
| 99 | + } else { | ||
| 100 | + checked_visitors.value.push(item.id); | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +const total = computed(() => { | ||
| 105 | + return price.value * checked_visitors.value.length; | ||
| 106 | +}) | ||
| 107 | + | ||
| 108 | +const goToBooking = () => { | ||
| 109 | + go('/booking'); | ||
| 110 | +} | ||
| 111 | +const goToVisitor = () => { | ||
| 112 | + go('/addVisitor'); | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +const submitBtn = async () => { | ||
| 116 | + if (!checked_visitors.value.length) { | ||
| 117 | + Taro.showToast({ title: '请先添加参观者', icon: 'none' }) | ||
| 118 | + } else { | ||
| 119 | + // TAG: 提交订单跳转到支付页面 | ||
| 120 | + Taro.showLoading({ title: '提交中...' }); | ||
| 121 | + const { code, data } = await addReserveAPI({ | ||
| 122 | + reserve_date: date.value, | ||
| 123 | + begin_time: time.value.split('-')[0], | ||
| 124 | + end_time: time.value.split('-')[1], | ||
| 125 | + person_id_list: JSON.stringify(checked_visitors.value) | ||
| 126 | + }); | ||
| 127 | + | ||
| 128 | + Taro.hideLoading(); | ||
| 129 | + | ||
| 130 | + if (code) { | ||
| 131 | + // H5 逻辑: const pay_url = `/srv/?f=reserve&a=icbc_pay&pay_id=${data.pay_id}`; location.href = pay_url; | ||
| 132 | + // 小程序逻辑: | ||
| 133 | + // 1. 如果支持小程序支付,应该调用获取支付参数接口 | ||
| 134 | + // 2. 暂时提示不支持,或尝试模拟 | ||
| 135 | + | ||
| 136 | + // 假设 payPrepareAPI 可用 | ||
| 137 | + // const payParams = await payPrepareAPI({ bill_id: data.pay_id }); // 假设接口 | ||
| 138 | + | ||
| 139 | + Taro.showModal({ | ||
| 140 | + title: '提示', | ||
| 141 | + content: '订单提交成功。由于小程序支付暂未配置,请联系管理员或前往H5完成支付。', | ||
| 142 | + showCancel: false, | ||
| 143 | + success: () => { | ||
| 144 | + go('/bookingList'); | ||
| 145 | + } | ||
| 146 | + }); | ||
| 147 | + | ||
| 148 | + // 如果后端有返回支付参数,可以使用 requestPayment | ||
| 149 | + /* | ||
| 150 | + Taro.requestPayment({ | ||
| 151 | + timeStamp: '', | ||
| 152 | + nonceStr: '', | ||
| 153 | + package: '', | ||
| 154 | + signType: 'MD5', | ||
| 155 | + paySign: '', | ||
| 156 | + success (res) { | ||
| 157 | + go('/success'); | ||
| 158 | + }, | ||
| 159 | + fail (res) { } | ||
| 160 | + }) | ||
| 161 | + */ | ||
| 162 | + } | ||
| 163 | + } | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +useDidShow(async () => { | ||
| 167 | + const params = router.params; | ||
| 168 | + date.value = params.date || ''; | ||
| 169 | + time.value = params.time || ''; | ||
| 170 | + price.value = params.price || 0; | ||
| 171 | + | ||
| 172 | + if (date.value && time.value) { | ||
| 173 | + const { code, data } = await personListAPI({ reserve_date: date.value, begin_time: time.value.split('-')[0], end_time: time.value.split('-')[1] }); | ||
| 174 | + if (code) { | ||
| 175 | + visitorList.value = data; | ||
| 176 | + } | ||
| 177 | + } | ||
| 178 | +}); | ||
| 179 | +</script> | ||
| 180 | + | ||
| 181 | +<style lang="less"> | ||
| 182 | +.submit-page { | ||
| 183 | + margin: 1rem; | ||
| 184 | + position: relative; | ||
| 185 | + .visit-time { | ||
| 186 | + background-color: #FFF; | ||
| 187 | + display: flex; | ||
| 188 | + align-items: center; | ||
| 189 | + justify-content: space-between; | ||
| 190 | + padding: 0.75rem; | ||
| 191 | + border-radius: 8px; | ||
| 192 | + } | ||
| 193 | + .add-visitors { | ||
| 194 | + border: 1px dashed #A67939; | ||
| 195 | + color: #A67939; | ||
| 196 | + border-radius: 5px; | ||
| 197 | + text-align: center; | ||
| 198 | + padding: .65rem 0; | ||
| 199 | + margin: 1rem 0; | ||
| 200 | + font-size: 1.15rem; | ||
| 201 | + } | ||
| 202 | + .visitors-list { | ||
| 203 | + .visitor-item { | ||
| 204 | + background-color: #FFF; | ||
| 205 | + border-radius: 8px; | ||
| 206 | + padding: 1rem; | ||
| 207 | + margin-bottom: 1rem; | ||
| 208 | + display: flex; | ||
| 209 | + align-items: center; | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + .no-visitors-list { | ||
| 213 | + display: flex; | ||
| 214 | + justify-content: center; | ||
| 215 | + align-items: center; | ||
| 216 | + flex-direction: column; | ||
| 217 | + img { | ||
| 218 | + margin-top: 1rem; | ||
| 219 | + margin-bottom: 1rem; | ||
| 220 | + width: 10rem; | ||
| 221 | + } | ||
| 222 | + .no-visitors-list-title { | ||
| 223 | + color: #A67939; | ||
| 224 | + font-size: 1.05rem; | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + .submit-wrapper { | ||
| 228 | + position: fixed; | ||
| 229 | + bottom: 0; | ||
| 230 | + left: 0; | ||
| 231 | + width: 100vw; | ||
| 232 | + display: flex; | ||
| 233 | + background-color: #FFF; | ||
| 234 | + // padding: 1rem; | ||
| 235 | + justify-content: space-between; | ||
| 236 | + flex-direction: column; | ||
| 237 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 238 | + | ||
| 239 | + .control-wrapper { | ||
| 240 | + display: flex; | ||
| 241 | + justify-content: space-between; | ||
| 242 | + align-items: center; | ||
| 243 | + } | ||
| 244 | + .left { | ||
| 245 | + display: flex; | ||
| 246 | + justify-content: center; | ||
| 247 | + align-items: center; | ||
| 248 | + flex-wrap: nowrap; | ||
| 249 | + } | ||
| 250 | + .right { | ||
| 251 | + background-color: #A67939; | ||
| 252 | + color: #FFF; | ||
| 253 | + margin: 1rem; | ||
| 254 | + padding: 0.8rem 3rem; | ||
| 255 | + border-radius: 5px; | ||
| 256 | + font-size: 1.1rem; | ||
| 257 | + margin-bottom: 0; | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | +} | ||
| 261 | +</style> |
src/pages/success/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2024-01-15 18:28:25 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 15:18:54 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/success/index.vue | ||
| 6 | + * @Description: 预约成功提示页面 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="success-page"> | ||
| 10 | + <view style=""> | ||
| 11 | + <view class="text-prompts"> | ||
| 12 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%88%90%E5%8A%9F@2x.png" mode="widthFix" /> | ||
| 13 | + <view class="text">预约成功</view> | ||
| 14 | + </view> | ||
| 15 | + <view class="appointment-information"> | ||
| 16 | + <view class="number-of-visitors">参观人数:<text>{{ billInfo?.total_qty }} 人</text></view> | ||
| 17 | + <view class="visit-time">参访时间:<text>{{ billInfo?.datetime }}</text></view> | ||
| 18 | + <view class="payment-amount">支付金额:<text>¥ {{ billInfo?.total_amt }}</text></view> | ||
| 19 | + </view> | ||
| 20 | + <view class="appointment-notice"> | ||
| 21 | + <view style="margin-bottom: 0.25rem;"><nut-icon name="tips" /> 温馨提示</view> | ||
| 22 | + <view style="font-size: 0.85rem;">1. 一人一码,或拿身份证,扫码或识别身份证成功后进入</view> | ||
| 23 | + <view style="font-size: 0.85rem;">2. 若您无法按时参观,请提前在预约记录中取消您的预约</view> | ||
| 24 | + </view> | ||
| 25 | + </view> | ||
| 26 | + <view class="success-btn"> | ||
| 27 | + <view @tap="goToHome" class="btn-item btn-left">首页</view> | ||
| 28 | + <view @tap="goToDetail" class="btn-item btn-right">详情</view> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | +</template> | ||
| 32 | + | ||
| 33 | +<script setup> | ||
| 34 | +import { ref } from 'vue' | ||
| 35 | +import Taro, { useDidShow, useRouter as useTaroRouter } from '@tarojs/taro' | ||
| 36 | +import { useGo } from '@/hooks/useGo' | ||
| 37 | +import { billInfoAPI } from '@/api/index' | ||
| 38 | +import { formatDatetime } from '@/utils/tools'; | ||
| 39 | + | ||
| 40 | +const router = useTaroRouter(); | ||
| 41 | +const go = useGo(); | ||
| 42 | + | ||
| 43 | +const goToHome = () => { | ||
| 44 | + go('/index') | ||
| 45 | +} | ||
| 46 | +const goToDetail = () => { | ||
| 47 | + go('/bookingDetail', { pay_id: router.params.pay_id }); | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +const billInfo = ref({}); | ||
| 51 | + | ||
| 52 | +useDidShow(async () => { | ||
| 53 | + // 获取订单详情 | ||
| 54 | + const { code, data } = await billInfoAPI({ pay_id: router.params.pay_id }); | ||
| 55 | + if (code) { | ||
| 56 | + data.datetime = data && formatDatetime(data); | ||
| 57 | + billInfo.value = data; | ||
| 58 | + } | ||
| 59 | +}) | ||
| 60 | +</script> | ||
| 61 | + | ||
| 62 | +<style lang="less"> | ||
| 63 | +.success-page { | ||
| 64 | + position: relative; | ||
| 65 | + background-color: #FFF; | ||
| 66 | + min-height: 100vh; | ||
| 67 | + | ||
| 68 | + .text-prompts { | ||
| 69 | + display: flex; | ||
| 70 | + align-items: center; | ||
| 71 | + justify-content: center; | ||
| 72 | + height: 35vh; | ||
| 73 | + flex-direction: column; | ||
| 74 | + image { | ||
| 75 | + width: 60vw; | ||
| 76 | + } | ||
| 77 | + .text { | ||
| 78 | + color: #A67939; | ||
| 79 | + font-size: 1.25rem; | ||
| 80 | + margin-top: 1rem; | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + .appointment-information { | ||
| 84 | + padding: 2rem 1rem; | ||
| 85 | + border-bottom: 1px dashed #A67939; | ||
| 86 | + line-height: 2; | ||
| 87 | + .number-of-visitors { | ||
| 88 | + text { | ||
| 89 | + color: #A67939; | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + .visit-time { | ||
| 93 | + text { | ||
| 94 | + color: #A67939; | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + .payment-amount { | ||
| 98 | + text { | ||
| 99 | + color: #A67939; | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + .appointment-notice { | ||
| 105 | + padding: 1rem; | ||
| 106 | + color: #666; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + .success-btn { | ||
| 110 | + position: fixed; | ||
| 111 | + bottom: 2rem; | ||
| 112 | + width: 100vw; | ||
| 113 | + display: flex; | ||
| 114 | + justify-content: space-around; | ||
| 115 | + | ||
| 116 | + .btn-item { | ||
| 117 | + width: 40%; | ||
| 118 | + text-align: center; | ||
| 119 | + padding: 0.8rem 0; | ||
| 120 | + border-radius: 8px; | ||
| 121 | + font-size: 1.1rem; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + .btn-left { | ||
| 125 | + border: 1px solid #A67939; | ||
| 126 | + color: #A67939; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + .btn-right { | ||
| 130 | + background-color: #A67939; | ||
| 131 | + color: #FFF; | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | +} | ||
| 135 | +</style> |
src/pages/visitorList/index.config.js
0 → 100644
src/pages/visitorList/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="me-page"> | ||
| 3 | + <view class="me-content"> | ||
| 4 | + <view class="title"> | ||
| 5 | + <view class="text">参观者信息</view> | ||
| 6 | + </view> | ||
| 7 | + <view @tap="() => { go('/pages/addVisitor/index') }" class="add-visitors"> | ||
| 8 | + <view><nut-icon name="plus" /> 添加参观者</view> | ||
| 9 | + </view> | ||
| 10 | + <view v-if="visitorList.length" class="visitors-list"> | ||
| 11 | + <view v-for="(item, index) in visitorList" :key="index" class="visitor-item"> | ||
| 12 | + <view> | ||
| 13 | + <view style="color: #A67939;">{{ item.name }}</view> | ||
| 14 | + <view>证件号:{{ formatId(item.id_number) }}</view> | ||
| 15 | + </view> | ||
| 16 | + <view @tap="removeItem(item)" style="margin-left: 1rem;"> | ||
| 17 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E5%88%A0%E9%99%A4@2x.png" style="width: 1.2rem; height: 1.2rem;" /> | ||
| 18 | + </view> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + <view v-else class="no-visitors-list"> | ||
| 22 | + <image src="https://cdn.ipadbiz.cn/xys/booking/%E6%9A%82%E6%97%A0@2x.png" style="width: 10rem; height: 10rem;" /> | ||
| 23 | + <view class="no-visitors-list-title">您还没有添加过参观者</view> | ||
| 24 | + </view> | ||
| 25 | + </view> | ||
| 26 | + <view style="height: 8rem;"></view> | ||
| 27 | + <view class="index-nav"> | ||
| 28 | + <view class="nav-logo" @tap="toHome"> | ||
| 29 | + <image :src="icon_3" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 30 | + 首页 | ||
| 31 | + </view> | ||
| 32 | + <view class="nav-logo" @tap="toCode"> | ||
| 33 | + <image :src="icon_4" style="width: 1.5rem; height: 1.5rem; margin-bottom: 0.1rem;" /> | ||
| 34 | + 预约码 | ||
| 35 | + </view> | ||
| 36 | + <view class="nav-logo" @tap="toMy"> | ||
| 37 | + <image :src="icon_5" style="width: 1.5rem; height: 1.5rem;" /> | ||
| 38 | + 我的 | ||
| 39 | + </view> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | +</template> | ||
| 43 | + | ||
| 44 | +<script setup> | ||
| 45 | +import { ref } from 'vue' | ||
| 46 | +import Taro, { useDidShow } from '@tarojs/taro' | ||
| 47 | +import { useGo } from '@/hooks/useGo' | ||
| 48 | +import { personListAPI, delPersonAPI } from '@/api/index' | ||
| 49 | +import icon_3 from '@/assets/images/首页01@2x.png' | ||
| 50 | +import icon_4 from '@/assets/images/二维码icon.png' | ||
| 51 | +import icon_5 from '@/assets/images/我的02@2x.png' | ||
| 52 | + | ||
| 53 | +const go = useGo(); | ||
| 54 | + | ||
| 55 | +const toCode = () => { // 跳转到预约码 | ||
| 56 | + go('/pages/bookingCode/index'); | ||
| 57 | +} | ||
| 58 | +const toHome = () => { // 跳转到首页 | ||
| 59 | + go('/pages/index/index'); | ||
| 60 | +} | ||
| 61 | +const toMy = () => { // 跳转到我的 | ||
| 62 | + go('/pages/me/index'); | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +const visitorList = ref([]); | ||
| 66 | + | ||
| 67 | +function replaceMiddleCharacters(inputString) { | ||
| 68 | + if (!inputString || inputString.length < 15) { | ||
| 69 | + return inputString; | ||
| 70 | + } | ||
| 71 | + const start = Math.floor((inputString.length - 8) / 2); | ||
| 72 | + const end = start + 8; | ||
| 73 | + const replacement = '*'.repeat(8); | ||
| 74 | + return inputString.substring(0, start) + replacement + inputString.substring(end); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +const formatId = (id) => replaceMiddleCharacters(id); | ||
| 78 | + | ||
| 79 | +const loadList = async () => { | ||
| 80 | + const { code, data } = await personListAPI({}); | ||
| 81 | + if (code) { | ||
| 82 | + visitorList.value = data; | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +const removeItem = async (item) => { | ||
| 87 | + const { confirm } = await Taro.showModal({ title: '提示', content: '确定删除该参观者吗?' }); | ||
| 88 | + if (confirm) { | ||
| 89 | + const { code, msg } = await delPersonAPI({ person_id: item.id }); | ||
| 90 | + if (code) { | ||
| 91 | + Taro.showToast({ title: '删除成功' }); | ||
| 92 | + loadList(); | ||
| 93 | + } else { | ||
| 94 | + Taro.showToast({ title: msg || '删除失败', icon: 'none' }); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +useDidShow(() => { | ||
| 100 | + loadList(); | ||
| 101 | +}) | ||
| 102 | +</script> | ||
| 103 | + | ||
| 104 | +<style lang="less"> | ||
| 105 | +.me-page { | ||
| 106 | + min-height: 100vh; | ||
| 107 | + background-color: #F6F6F6; | ||
| 108 | + padding: 1rem; | ||
| 109 | + | ||
| 110 | + .me-content { | ||
| 111 | + .title { | ||
| 112 | + .text { | ||
| 113 | + font-size: 1.1rem; | ||
| 114 | + font-weight: bold; | ||
| 115 | + margin-bottom: 1rem; | ||
| 116 | + border-left: 3px solid #A67939; | ||
| 117 | + padding-left: 0.5rem; | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + .add-visitors { | ||
| 122 | + border: 1px dashed #A67939; | ||
| 123 | + color: #A67939; | ||
| 124 | + border-radius: 5px; | ||
| 125 | + text-align: center; | ||
| 126 | + padding: .65rem 0; | ||
| 127 | + margin: 1rem 0; | ||
| 128 | + font-size: 1.15rem; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + .visitors-list { | ||
| 132 | + .visitor-item { | ||
| 133 | + background-color: #FFF; | ||
| 134 | + border-radius: 8px; | ||
| 135 | + padding: 1rem; | ||
| 136 | + margin-bottom: 1rem; | ||
| 137 | + display: flex; | ||
| 138 | + align-items: center; | ||
| 139 | + justify-content: space-between; | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + .no-visitors-list { | ||
| 144 | + display: flex; | ||
| 145 | + justify-content: center; | ||
| 146 | + align-items: center; | ||
| 147 | + flex-direction: column; | ||
| 148 | + | ||
| 149 | + .no-visitors-list-title { | ||
| 150 | + color: #A67939; | ||
| 151 | + font-size: 1.05rem; | ||
| 152 | + margin-top: 1rem; | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + .index-nav { | ||
| 158 | + position: fixed; | ||
| 159 | + bottom: 0; | ||
| 160 | + left: 0; | ||
| 161 | + width: 100vw; | ||
| 162 | + height: 10vh; | ||
| 163 | + background: #FFFFFF; | ||
| 164 | + box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12); | ||
| 165 | + display: flex; | ||
| 166 | + align-items: center; | ||
| 167 | + justify-content: space-around; | ||
| 168 | + color: #A67939; | ||
| 169 | + .nav-logo { | ||
| 170 | + position: relative; | ||
| 171 | + display: flex; | ||
| 172 | + flex-direction: column; | ||
| 173 | + align-items: center; | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | +} | ||
| 177 | +</style> |
src/pages/waiting/index.config.js
0 → 100644
src/pages/waiting/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="waiting-page"> | ||
| 3 | + <view class="waiting-content"> | ||
| 4 | + <view> | ||
| 5 | + <nut-icon name="clock" size="40" color="#A67939" /> | ||
| 6 | + </view> | ||
| 7 | + <view style="margin: 1rem 0;">支付中</view> | ||
| 8 | + <view>{{ current.seconds }} s</view> | ||
| 9 | + <view style="margin: 1.5rem 0; font-size: 0.85rem; color: #A67939; text-align: center; line-height: 2;"> | ||
| 10 | + 温馨提示:{{ pay_msg }}<br /> | ||
| 11 | + </view> | ||
| 12 | + </view> | ||
| 13 | + <view class="go-back-wrapper"> | ||
| 14 | + <nut-button @click="goBackBtn" color="#A67939" block>返回首页</nut-button> | ||
| 15 | + </view> | ||
| 16 | + </view> | ||
| 17 | +</template> | ||
| 18 | + | ||
| 19 | +<script setup> | ||
| 20 | +import { ref, onMounted, onUnmounted } from 'vue' | ||
| 21 | +import Taro, { useRouter } from '@tarojs/taro' | ||
| 22 | +import { billPayStatusAPI } from '@/api/index' | ||
| 23 | +import { useGo } from '@/hooks/useGo' | ||
| 24 | + | ||
| 25 | +const router = useRouter() | ||
| 26 | +const go = useGo() | ||
| 27 | + | ||
| 28 | +const remaining = ref(10) | ||
| 29 | +const current = ref({ seconds: 10 }) | ||
| 30 | + | ||
| 31 | +// Ensure params are available. Taro.useRouter() might need time or be called in setup. | ||
| 32 | +// router.params is reactive in some Taro versions, or just an object. | ||
| 33 | +const pay_id = router.params.pay_id | ||
| 34 | +const pay_msg = ref('支付可能需要10s左右,请耐心等待') | ||
| 35 | + | ||
| 36 | +const PAY_STATUS = { | ||
| 37 | + PAY: '1', | ||
| 38 | + PAYING: '2', | ||
| 39 | + FAIL: '7', | ||
| 40 | + SUCCESS: '3' | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +let timer = null | ||
| 44 | +let countdownTimer = null | ||
| 45 | + | ||
| 46 | +const startCountdown = () => { | ||
| 47 | + countdownTimer = setInterval(() => { | ||
| 48 | + if (remaining.value > 0) { | ||
| 49 | + remaining.value-- | ||
| 50 | + current.value.seconds = remaining.value | ||
| 51 | + } else { | ||
| 52 | + clearInterval(countdownTimer) | ||
| 53 | + } | ||
| 54 | + }, 1000) | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +const checkStatus = async () => { | ||
| 58 | + if (!pay_id) return | ||
| 59 | + try { | ||
| 60 | + const { code, data } = await billPayStatusAPI({ pay_id }) | ||
| 61 | + // TAG:轮询支付回调 | ||
| 62 | + if (data) { | ||
| 63 | + switch (data.status) { | ||
| 64 | + case PAY_STATUS.PAY: | ||
| 65 | + pay_msg.value = '订单待支付' | ||
| 66 | + break | ||
| 67 | + case PAY_STATUS.PAYING: | ||
| 68 | + pay_msg.value = '订单支付中' | ||
| 69 | + break | ||
| 70 | + case PAY_STATUS.SUCCESS: | ||
| 71 | + // 预约成功页面 | ||
| 72 | + // Replace to avoid back button loop | ||
| 73 | + go(`/pages/success/index?pay_id=${pay_id}`, 'replace') | ||
| 74 | + break | ||
| 75 | + case PAY_STATUS.FAIL: | ||
| 76 | + pay_msg.value = '订单支付失败' | ||
| 77 | + break | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + } catch (error) { | ||
| 81 | + console.error('Check status error:', error) | ||
| 82 | + } | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +onMounted(() => { | ||
| 86 | + startCountdown() | ||
| 87 | + // Immediate check | ||
| 88 | + checkStatus() | ||
| 89 | + timer = setInterval(async () => { | ||
| 90 | + if (remaining.value <= 0) { | ||
| 91 | + clearInterval(timer) | ||
| 92 | + } | ||
| 93 | + await checkStatus() | ||
| 94 | + }, 1000) | ||
| 95 | +}) | ||
| 96 | + | ||
| 97 | +onUnmounted(() => { | ||
| 98 | + if(timer) clearInterval(timer) | ||
| 99 | + if(countdownTimer) clearInterval(countdownTimer) | ||
| 100 | +}) | ||
| 101 | + | ||
| 102 | +const goBackBtn = () => { | ||
| 103 | + go('/pages/index/index') | ||
| 104 | +} | ||
| 105 | +</script> | ||
| 106 | + | ||
| 107 | +<style lang="less"> | ||
| 108 | +.waiting-page { | ||
| 109 | + display: flex; | ||
| 110 | + flex-direction: column; | ||
| 111 | + height: 100vh; | ||
| 112 | + background-color: #fff; | ||
| 113 | + align-items: center; | ||
| 114 | + padding-top: 3rem; | ||
| 115 | + | ||
| 116 | + .waiting-content { | ||
| 117 | + display: flex; | ||
| 118 | + flex-direction: column; | ||
| 119 | + align-items: center; | ||
| 120 | + font-size: 1rem; | ||
| 121 | + color: #333; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + .go-back-wrapper { | ||
| 125 | + width: 80%; | ||
| 126 | + margin-top: 2rem; | ||
| 127 | + } | ||
| 128 | +} | ||
| 129 | +</style> |
src/stores/main.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2022-04-18 15:59:42 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2024-01-30 15:26:30 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/stores/main.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +import { defineStore } from 'pinia'; | ||
| 9 | + | ||
| 10 | +export const mainStore = defineStore('main', { | ||
| 11 | + state: () => { | ||
| 12 | + return { | ||
| 13 | + msg: 'Hello world', | ||
| 14 | + count: 0, | ||
| 15 | + auth: false, | ||
| 16 | + // keepPages: ['default'], // 小程序不支持这种 keep-alive 机制 | ||
| 17 | + appUserInfo: [], // 缓存预约人信息 | ||
| 18 | + }; | ||
| 19 | + }, | ||
| 20 | + getters: { | ||
| 21 | + // getKeepPages () { | ||
| 22 | + // return this.keepPages | ||
| 23 | + // }, | ||
| 24 | + }, | ||
| 25 | + actions: { | ||
| 26 | + changeState (state) { | ||
| 27 | + this.auth = state; | ||
| 28 | + }, | ||
| 29 | + // changeKeepPages () { | ||
| 30 | + // this.keepPages = ['default']; | ||
| 31 | + // }, | ||
| 32 | + // keepThisPage () { | ||
| 33 | + // // 小程序路由缓存由框架控制 | ||
| 34 | + // }, | ||
| 35 | + // removeThisPage () { | ||
| 36 | + // }, | ||
| 37 | + changeUserInfo (info) { | ||
| 38 | + this.appUserInfo = info; | ||
| 39 | + } | ||
| 40 | + }, | ||
| 41 | +}); |
| ... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | * @LastEditTime: 2025-07-01 11:17:49 | 4 | * @LastEditTime: 2025-07-01 11:17:49 |
| 5 | - * @FilePath: /myApp/src/utils/request.js | 5 | + * @FilePath: /xyxBooking-weapp/src/utils/request.js |
| 6 | * @Description: 简单axios封装,后续按实际处理 | 6 | * @Description: 简单axios封装,后续按实际处理 |
| 7 | */ | 7 | */ |
| 8 | // import axios from 'axios' | 8 | // import axios from 'axios' |
| ... | @@ -10,7 +10,7 @@ import axios from 'axios-miniprogram'; | ... | @@ -10,7 +10,7 @@ import axios from 'axios-miniprogram'; |
| 10 | import Taro from '@tarojs/taro' | 10 | import Taro from '@tarojs/taro' |
| 11 | // import { strExist } from './tools' | 11 | // import { strExist } from './tools' |
| 12 | // import qs from 'Qs' | 12 | // import qs from 'Qs' |
| 13 | -import { routerStore } from '@/stores/router' | 13 | +import { mainStore } from '@/stores/main' |
| 14 | 14 | ||
| 15 | // import { ProgressStart, ProgressEnd } from '@/components/axios-progress/progress'; | 15 | // import { ProgressStart, ProgressEnd } from '@/components/axios-progress/progress'; |
| 16 | // import store from '@/store' | 16 | // import store from '@/store' |
| ... | @@ -23,35 +23,13 @@ import BASE_URL from './config'; | ... | @@ -23,35 +23,13 @@ import BASE_URL from './config'; |
| 23 | */ | 23 | */ |
| 24 | const getSessionId = () => { | 24 | const getSessionId = () => { |
| 25 | try { | 25 | try { |
| 26 | - return wx.getStorageSync("sessionid") || null; | 26 | + return Taro.getStorageSync("sessionid") || null; |
| 27 | } catch (error) { | 27 | } catch (error) { |
| 28 | console.error('获取sessionid失败:', error); | 28 | console.error('获取sessionid失败:', error); |
| 29 | return null; | 29 | return null; |
| 30 | } | 30 | } |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | -/** | ||
| 34 | - * 设置sessionid的工具函数 | ||
| 35 | - * @param {string} sessionid - 要设置的sessionid | ||
| 36 | - */ | ||
| 37 | -const setSessionId = (sessionid) => { | ||
| 38 | - try { | ||
| 39 | - wx.setStorageSync("sessionid", sessionid); | ||
| 40 | - } catch (error) { | ||
| 41 | - console.error('设置sessionid失败:', error); | ||
| 42 | - } | ||
| 43 | -}; | ||
| 44 | - | ||
| 45 | -/** | ||
| 46 | - * 清除sessionid的工具函数 | ||
| 47 | - */ | ||
| 48 | -const clearSessionId = () => { | ||
| 49 | - try { | ||
| 50 | - wx.removeStorageSync("sessionid"); | ||
| 51 | - } catch (error) { | ||
| 52 | - console.error('清除sessionid失败:', error); | ||
| 53 | - } | ||
| 54 | -}; | ||
| 55 | // create an axios instance | 33 | // create an axios instance |
| 56 | const service = axios.create({ | 34 | const service = axios.create({ |
| 57 | baseURL: BASE_URL, // url = base url + request url | 35 | baseURL: BASE_URL, // url = base url + request url |
| ... | @@ -60,8 +38,8 @@ const service = axios.create({ | ... | @@ -60,8 +38,8 @@ const service = axios.create({ |
| 60 | }) | 38 | }) |
| 61 | 39 | ||
| 62 | service.defaults.params = { | 40 | service.defaults.params = { |
| 63 | - f: 'room', | 41 | + f: 'reserve', |
| 64 | - client_id: '772428', | 42 | + client_name: '智慧西园寺', |
| 65 | }; | 43 | }; |
| 66 | 44 | ||
| 67 | // request interceptor | 45 | // request interceptor |
| ... | @@ -78,6 +56,11 @@ service.interceptors.request.use( | ... | @@ -78,6 +56,11 @@ service.interceptors.request.use( |
| 78 | if (sessionid) { | 56 | if (sessionid) { |
| 79 | config.headers.cookie = sessionid; | 57 | config.headers.cookie = sessionid; |
| 80 | } | 58 | } |
| 59 | + | ||
| 60 | + // 增加时间戳 | ||
| 61 | + if (config.method === 'get') { | ||
| 62 | + config.params = { ...config.params, timestamp: (new Date()).valueOf() } | ||
| 63 | + } | ||
| 81 | 64 | ||
| 82 | /** | 65 | /** |
| 83 | * POST PHP需要修改数据格式 | 66 | * POST PHP需要修改数据格式 |
| ... | @@ -106,79 +89,37 @@ service.interceptors.response.use( | ... | @@ -106,79 +89,37 @@ service.interceptors.response.use( |
| 106 | * You can also judge the status by HTTP Status Code | 89 | * You can also judge the status by HTTP Status Code |
| 107 | */ | 90 | */ |
| 108 | response => { | 91 | response => { |
| 109 | - /** | 92 | + const res = response.data |
| 110 | - * 检查响应头中是否有新的sessionid | 93 | + |
| 111 | - * 如果有,则更新本地存储 | 94 | + // 401 未授权处理 |
| 112 | - */ | 95 | + if (res.code === 401) { |
| 113 | - const setCookieHeader = response.headers['set-cookie']; | 96 | + // 跳转到授权页 |
| 114 | - if (setCookieHeader) { | 97 | + // 避免死循环,如果已经在 auth 页则不跳 |
| 115 | - // 解析set-cookie头,提取sessionid | 98 | + const pages = Taro.getCurrentPages(); |
| 116 | - const sessionidMatch = setCookieHeader.match(/sessionid=([^;]+)/); | 99 | + const currentPage = pages[pages.length - 1]; |
| 117 | - if (sessionidMatch && sessionidMatch[1]) { | 100 | + if (currentPage && currentPage.route !== 'pages/auth/index') { |
| 118 | - setSessionId(sessionidMatch[1]); | 101 | + Taro.navigateTo({ |
| 119 | - } | 102 | + url: '/pages/auth/index' |
| 103 | + }); | ||
| 104 | + } | ||
| 105 | + return response; // 返回 response 以便业务代码处理(或者这里 reject) | ||
| 120 | } | 106 | } |
| 121 | 107 | ||
| 122 | - // wx.hideLoading(); | 108 | + if (['预约ID不存在'].includes(res.msg)) { |
| 123 | - // const res = response.data | 109 | + res.show = false; |
| 124 | - // // Toast.clear(); | ||
| 125 | - // // if the custom code is not 20000, it is judged as an error. | ||
| 126 | - // if (res.code !== 100000) { | ||
| 127 | - // // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; | ||
| 128 | - // if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | ||
| 129 | - // // to re-login | ||
| 130 | - // // Toast.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { | ||
| 131 | - // // confirmButtonText: 'Re-Login', | ||
| 132 | - // // cancelButtonText: 'Cancel', | ||
| 133 | - // // type: 'warning' | ||
| 134 | - // // }).then(() => { | ||
| 135 | - // // // store.dispatch('user/resetToken').then(() => { | ||
| 136 | - // // // location.reload() | ||
| 137 | - // // // }) | ||
| 138 | - // // }) | ||
| 139 | - // } else { | ||
| 140 | - // // Toast.fail({ | ||
| 141 | - // // message: res.message, | ||
| 142 | - // // duration: 1.5 * 1000 | ||
| 143 | - // // }) | ||
| 144 | - // // Tips.error(res.message, false) | ||
| 145 | - // } | ||
| 146 | - // return Promise.reject(new Error(res.message || 'Error')) | ||
| 147 | - // } else { | ||
| 148 | - // return res | ||
| 149 | - // } | ||
| 150 | - | ||
| 151 | - /** | ||
| 152 | - * 处理401未授权状态 | ||
| 153 | - * 清除本地sessionid并跳转到登录页 | ||
| 154 | - */ | ||
| 155 | - if (response.data.code === 401) { | ||
| 156 | - // 清除无效的sessionid | ||
| 157 | - clearSessionId(); | ||
| 158 | - /** | ||
| 159 | - * 未授权跳转登录页 | ||
| 160 | - * 授权完成后 返回当前页面 | ||
| 161 | - */ | ||
| 162 | - setTimeout(() => { | ||
| 163 | - Taro.navigateTo({ | ||
| 164 | - url: '../../pages/auth/index?url=' + routerStore().url | ||
| 165 | - }); | ||
| 166 | - }, 1000); | ||
| 167 | } | 110 | } |
| 111 | + | ||
| 168 | return response | 112 | return response |
| 169 | }, | 113 | }, |
| 170 | error => { | 114 | error => { |
| 171 | - // Toast.clear(); | 115 | + console.log('err' + error) // for debug |
| 172 | - console.error('err' + error) // for debug | 116 | + // Taro.showToast({ |
| 173 | - // Toast.fail({ | 117 | + // title: error.message, |
| 174 | - // message: error.message, | 118 | + // icon: 'none', |
| 175 | - // duration: 1.5 * 1000 | 119 | + // duration: 2000 |
| 176 | // }) | 120 | // }) |
| 177 | return Promise.reject(error) | 121 | return Promise.reject(error) |
| 178 | } | 122 | } |
| 179 | ) | 123 | ) |
| 180 | 124 | ||
| 181 | -// 导出sessionid管理工具函数 | ||
| 182 | -export { getSessionId, setSessionId, clearSessionId }; | ||
| 183 | - | ||
| 184 | export default service | 125 | export default service | ... | ... |
| 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: 2022-12-07 22:09:30 | 4 | + * @LastEditTime: 2024-01-30 15:43:33 |
| 5 | - * @FilePath: /swx/src/utils/tools.js | 5 | + * @FilePath: /xyxBooking-weapp/src/utils/tools.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | -import Taro from '@tarojs/taro' | 8 | +import dayjs from 'dayjs'; |
| 9 | -import moment from '@/utils/moment.min.js' | 9 | +import Taro from '@tarojs/taro'; |
| 10 | 10 | ||
| 11 | // 格式化时间 | 11 | // 格式化时间 |
| 12 | const formatDate = (date) => { | 12 | const formatDate = (date) => { |
| 13 | - return moment(date).format('YYYY-MM-DD HH:mm') | 13 | + return dayjs(date).format('YYYY-MM-DD HH:mm'); |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | - * @description 判断浏览器属于平台 | 17 | + * @description 判断设备信息 |
| 18 | * @returns | 18 | * @returns |
| 19 | */ | 19 | */ |
| 20 | const wxInfo = () => { | 20 | const wxInfo = () => { |
| 21 | - let u = navigator.userAgent; | 21 | + const info = Taro.getSystemInfoSync(); |
| 22 | - let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端或者uc浏览器 | 22 | + const isAndroid = info.platform === 'android'; |
| 23 | - let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 | 23 | + const isiOS = info.platform === 'ios'; |
| 24 | - let uAgent = navigator.userAgent.toLowerCase(); | 24 | + // 简单模拟 |
| 25 | - let isTable = (uAgent.match(/MicroMessenger/i) == 'micromessenger') ? true : false; | ||
| 26 | - let isMobile = window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i); // 是否手机端 | ||
| 27 | - let isWx = /micromessenger/i.test(navigator.userAgent); // 是否微信 | ||
| 28 | - let isWxPc = isWx && !isMobile; // PC端微信 | ||
| 29 | return { | 25 | return { |
| 30 | isAndroid, | 26 | isAndroid, |
| 31 | isiOS, | 27 | isiOS, |
| 32 | - isTable, | 28 | + isTable: false // 小程序通常不是 tablet 模式,或者可以根据 screenWidth 判断 |
| 33 | - isWxPc | ||
| 34 | }; | 29 | }; |
| 35 | }; | 30 | }; |
| 36 | 31 | ||
| 37 | /** | 32 | /** |
| 38 | - * @description 判断多行省略文本 | ||
| 39 | - * @param {*} id 目标dom标签 | ||
| 40 | - * @returns | ||
| 41 | - */ | ||
| 42 | -const hasEllipsis = (id) => { | ||
| 43 | - let oDiv = document.getElementById(id); | ||
| 44 | - let flag = false; | ||
| 45 | - if (oDiv.scrollHeight > oDiv.clientHeight) { | ||
| 46 | - flag = true | ||
| 47 | - } | ||
| 48 | - return flag | ||
| 49 | -} | ||
| 50 | - | ||
| 51 | -/** | ||
| 52 | * @description 解析URL参数 | 33 | * @description 解析URL参数 |
| 53 | * @param {*} url | 34 | * @param {*} url |
| 54 | * @returns | 35 | * @returns |
| 55 | */ | 36 | */ |
| 56 | const parseQueryString = url => { | 37 | const parseQueryString = url => { |
| 38 | + if (!url) return {}; | ||
| 57 | var json = {}; | 39 | var json = {}; |
| 58 | var arr = url.indexOf('?') >= 0 ? url.substr(url.indexOf('?') + 1).split('&') : []; | 40 | var arr = url.indexOf('?') >= 0 ? url.substr(url.indexOf('?') + 1).split('&') : []; |
| 59 | arr.forEach(item => { | 41 | arr.forEach(item => { |
| ... | @@ -70,31 +52,19 @@ const parseQueryString = url => { | ... | @@ -70,31 +52,19 @@ const parseQueryString = url => { |
| 70 | * @returns 包含状态 | 52 | * @returns 包含状态 |
| 71 | */ | 53 | */ |
| 72 | const strExist = (array, str) => { | 54 | const strExist = (array, str) => { |
| 55 | + if (!str) return false; | ||
| 73 | const exist = array.filter(arr => { | 56 | const exist = array.filter(arr => { |
| 74 | if (str.indexOf(arr) >= 0) return str; | 57 | if (str.indexOf(arr) >= 0) return str; |
| 75 | }) | 58 | }) |
| 76 | return exist.length > 0 | 59 | return exist.length > 0 |
| 77 | } | 60 | } |
| 78 | 61 | ||
| 79 | -const randomId = (n) => { | 62 | +const formatDatetime = (data) => { // 格式化日期 |
| 80 | - const charts = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; | 63 | + if (!data) return ''; |
| 81 | - var res = ''; | 64 | + let begin_time = data?.begin_time.slice(0, -6); |
| 82 | - for (var i = 0; i < n; i++) { | 65 | + let end_time = data?.end_time.slice(0, -6); |
| 83 | - undefined | 66 | + let str = begin_time + ' ' + end_time; |
| 84 | - var id = Math.ceil(Math.random() * 35); | 67 | + return `${str.split(' ')[0]} ${str.split(' ')[1]}-${str.split(' ')[3]}`; |
| 85 | - res += charts[id]; | ||
| 86 | - } | ||
| 87 | - return res; | ||
| 88 | -} | ||
| 89 | - | ||
| 90 | -/** | ||
| 91 | - * 获取页面query参数 | ||
| 92 | - */ | ||
| 93 | -const pageQuery = () => { | ||
| 94 | - const instance = Taro.getCurrentInstance(); | ||
| 95 | - let $query = ''; | ||
| 96 | - $query = JSON.stringify(instance.router.params); | ||
| 97 | - return JSON.parse($query) | ||
| 98 | } | 68 | } |
| 99 | 69 | ||
| 100 | -export { formatDate, wxInfo, hasEllipsis, parseQueryString, strExist, randomId, pageQuery }; | 70 | +export { formatDate, wxInfo, parseQueryString, strExist, formatDatetime }; | ... | ... |
-
Please register or login to post a comment