feat(offline): 添加离线模式支持并优化网络检测功能
新增离线预约记录页面和网络工具函数 将网络检测逻辑提取到独立工具模块 优化页面跳转时的网络状态检查
Showing
8 changed files
with
90 additions
and
53 deletions
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-08-24 09:42:27 | 2 | * @Date: 2023-08-24 09:42:27 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-12 18:38:52 | 4 | + * @LastEditTime: 2026-01-13 14:52:29 |
| 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js | 5 | * @FilePath: /xyxBooking-weapp/src/api/index.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -21,6 +21,7 @@ const Api = { | ... | @@ -21,6 +21,7 @@ const Api = { |
| 21 | QRCODE_LIST: '/srv/?a=api&t=qrcode_list', | 21 | QRCODE_LIST: '/srv/?a=api&t=qrcode_list', |
| 22 | QRCODE_STATUS: '/srv/?a=api&t=qrcode_status', | 22 | QRCODE_STATUS: '/srv/?a=api&t=qrcode_status', |
| 23 | BILL_LIST: '/srv/?a=api&t=bill_list', | 23 | BILL_LIST: '/srv/?a=api&t=bill_list', |
| 24 | + BILL_OFFLINE_ALL: '/srv/?a=api&t=bill_offline_all', | ||
| 24 | ICBC_REFUND: '/srv/?a=icbc_refund', | 25 | ICBC_REFUND: '/srv/?a=icbc_refund', |
| 25 | BILL_PREPARE: '/srv/?a=api&t=bill_person', | 26 | BILL_PREPARE: '/srv/?a=api&t=bill_person', |
| 26 | BILL_PAY_STATUS: '/srv/?a=api&t=bill_pay_status', | 27 | BILL_PAY_STATUS: '/srv/?a=api&t=bill_pay_status', |
| ... | @@ -182,6 +183,12 @@ export const qrcodeStatusAPI = (params) => fn(fetch.get(Api.QRCODE_STATUS, param | ... | @@ -182,6 +183,12 @@ export const qrcodeStatusAPI = (params) => fn(fetch.get(Api.QRCODE_STATUS, param |
| 182 | export const billListAPI = (params) => fn(fetch.get(Api.BILL_LIST, params)); | 183 | export const billListAPI = (params) => fn(fetch.get(Api.BILL_LIST, params)); |
| 183 | 184 | ||
| 184 | /** | 185 | /** |
| 186 | + * @description: 离线预约记录全量数据(列表+详情) | ||
| 187 | + * @returns {String} | ||
| 188 | + */ | ||
| 189 | +export const billOfflineAllAPI = (params) => fn(fetch.get(Api.BILL_OFFLINE_ALL, params)); | ||
| 190 | + | ||
| 191 | +/** | ||
| 185 | * @description: 取消预约 | 192 | * @description: 取消预约 |
| 186 | * @param {String} pay_id | 193 | * @param {String} pay_id |
| 187 | * @returns {String} | 194 | * @returns {String} | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-06-28 10:33:00 | 2 | * @Date: 2025-06-28 10:33:00 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-13 13:55:59 | 4 | + * @LastEditTime: 2026-01-13 15:22:40 |
| 5 | * @FilePath: /xyxBooking-weapp/src/app.js | 5 | * @FilePath: /xyxBooking-weapp/src/app.js |
| 6 | * @Description: 应用入口文件 | 6 | * @Description: 应用入口文件 |
| 7 | */ | 7 | */ |
| ... | @@ -12,6 +12,7 @@ import './app.less' | ... | @@ -12,6 +12,7 @@ import './app.less' |
| 12 | import { saveCurrentPagePath, hasAuth, silentAuth, navigateToAuth } from '@/utils/authRedirect' | 12 | import { saveCurrentPagePath, hasAuth, silentAuth, navigateToAuth } from '@/utils/authRedirect' |
| 13 | import Taro from '@tarojs/taro' | 13 | import Taro from '@tarojs/taro' |
| 14 | import { refresh_offline_booking_cache, has_offline_booking_cache } from '@/composables/useOfflineBookingCache' | 14 | import { refresh_offline_booking_cache, has_offline_booking_cache } from '@/composables/useOfflineBookingCache' |
| 15 | +import { is_usable_network, get_network_type } from '@/utils/network' | ||
| 15 | 16 | ||
| 16 | let has_shown_network_modal = false | 17 | let has_shown_network_modal = false |
| 17 | 18 | ||
| ... | @@ -54,28 +55,6 @@ const App = createApp({ | ... | @@ -54,28 +55,6 @@ const App = createApp({ |
| 54 | } | 55 | } |
| 55 | }) | 56 | }) |
| 56 | 57 | ||
| 57 | - const is_usable_network = (network_type) => { | ||
| 58 | - return ['wifi', '4g', '5g', '3g'].includes(network_type) | ||
| 59 | - } | ||
| 60 | - | ||
| 61 | - /** | ||
| 62 | - * 获取当前网络类型 | ||
| 63 | - * @returns {string} 当前网络类型,如 wifi、4g、5g、3g、none 等 | ||
| 64 | - */ | ||
| 65 | - const get_network_type = async () => { | ||
| 66 | - try { | ||
| 67 | - const result = await new Promise((resolve, reject) => { | ||
| 68 | - Taro.getNetworkType({ | ||
| 69 | - success: resolve, | ||
| 70 | - fail: reject, | ||
| 71 | - }) | ||
| 72 | - }) | ||
| 73 | - return result?.networkType || 'unknown' | ||
| 74 | - } catch (e) { | ||
| 75 | - return 'unknown' | ||
| 76 | - } | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | /** | 58 | /** |
| 80 | * 处理在启动时出现的不良网络情况 | 59 | * 处理在启动时出现的不良网络情况 |
| 81 | * - 当网络连接不良且有离线预约记录缓存时,提示用户是否使用缓存进入离线模式 | 60 | * - 当网络连接不良且有离线预约记录缓存时,提示用户是否使用缓存进入离线模式 | ... | ... |
| ... | @@ -10,33 +10,12 @@ import Taro from '@tarojs/taro' | ... | @@ -10,33 +10,12 @@ import Taro from '@tarojs/taro' |
| 10 | import { billOfflineAllAPI } from '@/api/index' | 10 | import { billOfflineAllAPI } from '@/api/index' |
| 11 | import { hasAuth } from '@/utils/authRedirect' | 11 | import { hasAuth } from '@/utils/authRedirect' |
| 12 | import { formatDatetime } from '@/utils/tools' | 12 | import { formatDatetime } from '@/utils/tools' |
| 13 | +import { is_usable_network, get_network_type } from '@/utils/network' | ||
| 13 | 14 | ||
| 14 | export const OFFLINE_BOOKING_CACHE_KEY = 'OFFLINE_BOOKING_DATA' | 15 | export const OFFLINE_BOOKING_CACHE_KEY = 'OFFLINE_BOOKING_DATA' |
| 15 | 16 | ||
| 16 | let refresh_promise = null | 17 | let refresh_promise = null |
| 17 | 18 | ||
| 18 | -const is_usable_network = (network_type) => { | ||
| 19 | - return ['wifi', '4g', '5g', '3g'].includes(network_type) | ||
| 20 | -} | ||
| 21 | - | ||
| 22 | -/** | ||
| 23 | - * 获取当前网络类型 | ||
| 24 | - * @returns {Promise<string>} 网络类型(wifi, 4g, 5g, 3g, unknown) | ||
| 25 | - */ | ||
| 26 | -const get_network_type = async () => { | ||
| 27 | - try { | ||
| 28 | - const result = await new Promise((resolve, reject) => { | ||
| 29 | - Taro.getNetworkType({ | ||
| 30 | - success: resolve, | ||
| 31 | - fail: reject, | ||
| 32 | - }) | ||
| 33 | - }) | ||
| 34 | - return result?.networkType || 'unknown' | ||
| 35 | - } catch (e) { | ||
| 36 | - return 'unknown' | ||
| 37 | - } | ||
| 38 | -} | ||
| 39 | - | ||
| 40 | /** | 19 | /** |
| 41 | * 格式化预约记录项 | 20 | * 格式化预约记录项 |
| 42 | * @param {Object} item - 原始预约记录项 | 21 | * @param {Object} item - 原始预约记录项 | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2024-01-16 10:06:47 | 2 | * @Date: 2024-01-16 10:06:47 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-13 15:19:11 | 4 | + * @LastEditTime: 2026-01-13 15:24:06 |
| 5 | * @FilePath: /xyxBooking-weapp/src/pages/bookingCode/index.vue | 5 | * @FilePath: /xyxBooking-weapp/src/pages/bookingCode/index.vue |
| 6 | - * @Description: 文件描述 | 6 | + * @Description: 预约码页面 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| 9 | <view class="booking-code-page"> | 9 | <view class="booking-code-page"> |
| ... | @@ -42,13 +42,14 @@ import icon_4 from '@/assets/images/二维码icon.png' | ... | @@ -42,13 +42,14 @@ import icon_4 from '@/assets/images/二维码icon.png' |
| 42 | import icon_5 from '@/assets/images/我的01@2x.png' | 42 | import icon_5 from '@/assets/images/我的01@2x.png' |
| 43 | import { useGo } from '@/hooks/useGo' | 43 | import { useGo } from '@/hooks/useGo' |
| 44 | import { has_offline_booking_cache } from '@/composables/useOfflineBookingCache' | 44 | import { has_offline_booking_cache } from '@/composables/useOfflineBookingCache' |
| 45 | +import { is_usable_network } from '@/utils/network' | ||
| 45 | 46 | ||
| 46 | const go = useGo(); | 47 | const go = useGo(); |
| 47 | 48 | ||
| 48 | useDidShow(() => { | 49 | useDidShow(() => { |
| 49 | Taro.getNetworkType({ | 50 | Taro.getNetworkType({ |
| 50 | success: (res) => { | 51 | success: (res) => { |
| 51 | - const isConnected = ['wifi', '4g', '5g', '3g'].includes(res.networkType); | 52 | + const isConnected = is_usable_network(res.networkType); |
| 52 | if (!isConnected) { | 53 | if (!isConnected) { |
| 53 | if (has_offline_booking_cache()) { | 54 | if (has_offline_booking_cache()) { |
| 54 | Taro.redirectTo({ url: '/pages/offlineBookingList/index' }) | 55 | Taro.redirectTo({ url: '/pages/offlineBookingList/index' }) | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2023-06-21 10:23:09 | 2 | * @Date: 2023-06-21 10:23:09 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2026-01-09 18:08:03 | 4 | + * @LastEditTime: 2026-01-13 15:35:17 |
| 5 | * @FilePath: /xyxBooking-weapp/src/pages/index/index.vue | 5 | * @FilePath: /xyxBooking-weapp/src/pages/index/index.vue |
| 6 | * @Description: 预约页首页 | 6 | * @Description: 预约页首页 |
| 7 | --> | 7 | --> | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | <view class="my-page"> | 2 | <view class="my-page"> |
| 3 | - <view v-for="(item, index) in menu_list" :key="index" class="my-item" @tap="go(item.to)"> | 3 | + <view v-for="(item, index) in menu_list" :key="index" class="my-item" @tap="on_menu_tap(item)"> |
| 4 | <view class="left"> | 4 | <view class="left"> |
| 5 | <image :src="item.icon" style="width: 38rpx; height: 38rpx; margin-right: 16rpx;" /> | 5 | <image :src="item.icon" style="width: 38rpx; height: 38rpx; margin-right: 16rpx;" /> |
| 6 | {{ item.name }} | 6 | {{ item.name }} |
| ... | @@ -35,6 +35,8 @@ import { IconFont } from '@nutui/icons-vue-taro' | ... | @@ -35,6 +35,8 @@ import { IconFont } from '@nutui/icons-vue-taro' |
| 35 | import icon_3 from '@/assets/images/首页01@2x.png' | 35 | import icon_3 from '@/assets/images/首页01@2x.png' |
| 36 | import icon_4 from '@/assets/images/二维码icon.png' | 36 | import icon_4 from '@/assets/images/二维码icon.png' |
| 37 | import icon_5 from '@/assets/images/我的02@2x.png' | 37 | import icon_5 from '@/assets/images/我的02@2x.png' |
| 38 | +import { has_offline_booking_cache } from '@/composables/useOfflineBookingCache' | ||
| 39 | +import { is_usable_network, get_network_type } from '@/utils/network' | ||
| 38 | 40 | ||
| 39 | import icon_booking from '@/assets/images/预约记录@2x.png' | 41 | import icon_booking from '@/assets/images/预约记录@2x.png' |
| 40 | import icon_visitor from '@/assets/images/我的01@2x.png' | 42 | import icon_visitor from '@/assets/images/我的01@2x.png' |
| ... | @@ -42,6 +44,33 @@ import icon_invite from '@/assets/images/二维码@2x2.png' | ... | @@ -42,6 +44,33 @@ import icon_invite from '@/assets/images/二维码@2x2.png' |
| 42 | 44 | ||
| 43 | const go = useGo(); | 45 | const go = useGo(); |
| 44 | 46 | ||
| 47 | +const on_menu_tap = async (item) => { | ||
| 48 | + if (!item?.to) return | ||
| 49 | + | ||
| 50 | + if (item.to === '/pages/bookingList/index') { | ||
| 51 | + const network_type = await get_network_type() | ||
| 52 | + const is_weak_network = !is_usable_network(network_type) | ||
| 53 | + if (is_weak_network) { | ||
| 54 | + if (has_offline_booking_cache()) { | ||
| 55 | + const modal_res = await Taro.showModal({ | ||
| 56 | + title: '网络连接不畅', | ||
| 57 | + content: '当前网络信号较弱,是否进入离线预约记录?', | ||
| 58 | + confirmText: '离线记录', | ||
| 59 | + cancelText: '知道了', | ||
| 60 | + }) | ||
| 61 | + if (modal_res?.confirm) { | ||
| 62 | + go('/pages/offlineBookingList/index') | ||
| 63 | + } | ||
| 64 | + return | ||
| 65 | + } | ||
| 66 | + Taro.showToast({ title: '网络连接不畅', icon: 'none', duration: 2000 }) | ||
| 67 | + return | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + go(item.to) | ||
| 72 | +} | ||
| 73 | + | ||
| 45 | const toCode = () => { // 跳转到预约码 | 74 | const toCode = () => { // 跳转到预约码 |
| 46 | Taro.redirectTo({ | 75 | Taro.redirectTo({ |
| 47 | url: '/pages/bookingCode/index' | 76 | url: '/pages/bookingCode/index' | ... | ... |
| 1 | +<!-- | ||
| 2 | + * @Date: 2026-01-13 14:55:05 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2026-01-13 15:25:25 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/pages/offlineBookingList/index.vue | ||
| 6 | + * @Description: 离线预约记录页面 | ||
| 7 | +--> | ||
| 1 | <template> | 8 | <template> |
| 2 | <view class="offline-booking-list-page"> | 9 | <view class="offline-booking-list-page"> |
| 3 | <view class="header-tip"> | 10 | <view class="header-tip"> |
| 4 | - <IconFont name="tips" size="15" color="#A67939" /> | 11 | + <IconFont name="tips" size="15" color="#A67939" /> |
| 5 | <text>您当前处于离线模式,仅展示本地缓存的预约记录</text> | 12 | <text>您当前处于离线模式,仅展示本地缓存的预约记录</text> |
| 6 | </view> | 13 | </view> |
| 7 | 14 | ||
| ... | @@ -83,7 +90,7 @@ useDidShow(() => { | ... | @@ -83,7 +90,7 @@ useDidShow(() => { |
| 83 | color: #FFF; | 90 | color: #FFF; |
| 84 | border-radius: 16rpx; | 91 | border-radius: 16rpx; |
| 85 | font-size: 32rpx; | 92 | font-size: 32rpx; |
| 86 | - padding: 22rpx 0; | 93 | + padding: 12rpx 0; |
| 87 | } | 94 | } |
| 88 | } | 95 | } |
| 89 | } | 96 | } | ... | ... |
src/utils/network.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2026-01-13 15:34:47 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2026-01-13 15:36:37 | ||
| 5 | + * @FilePath: /xyxBooking-weapp/src/utils/network.js | ||
| 6 | + * @Description: 网络相关工具函数 | ||
| 7 | + */ | ||
| 8 | +import Taro from '@tarojs/taro' | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * @description: 判断网络是否可用(wifi, 4g, 5g, 3g) | ||
| 12 | + * @param {string} network_type - 网络类型 | ||
| 13 | + * @returns {boolean} 是否可用 | ||
| 14 | + */ | ||
| 15 | +export const is_usable_network = (network_type) => { | ||
| 16 | + return ['wifi', '4g', '5g', '3g'].includes(network_type) | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * @description: 获取当前网络类型 | ||
| 21 | + * @returns {Promise<string>} 网络类型(wifi, 4g, 5g, 3g, unknown) | ||
| 22 | + */ | ||
| 23 | +export const get_network_type = async () => { | ||
| 24 | + try { | ||
| 25 | + const result = await new Promise((resolve, reject) => { | ||
| 26 | + Taro.getNetworkType({ | ||
| 27 | + success: resolve, | ||
| 28 | + fail: reject, | ||
| 29 | + }) | ||
| 30 | + }) | ||
| 31 | + return result?.networkType || 'unknown' | ||
| 32 | + } catch (e) { | ||
| 33 | + return 'unknown' | ||
| 34 | + } | ||
| 35 | +} |
-
Please register or login to post a comment