hookehuyr

refactor(auth): 重构授权逻辑,优化会话管理和错误处理

- 将授权相关功能抽离到独立模块 authRedirect.js
- 实现静默续期和请求重放机制
- 优化授权失败后的降级处理
- 统一管理页面跳转和路径保存逻辑
- 移除未使用的代码和组件
...@@ -10,7 +10,6 @@ declare module 'vue' { ...@@ -10,7 +10,6 @@ declare module 'vue' {
10 NutButton: typeof import('@nutui/nutui-taro')['Button'] 10 NutButton: typeof import('@nutui/nutui-taro')['Button']
11 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox'] 11 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox']
12 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup'] 12 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup']
13 - NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider']
14 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] 13 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker']
15 NutInput: typeof import('@nutui/nutui-taro')['Input'] 14 NutInput: typeof import('@nutui/nutui-taro')['Input']
16 NutPicker: typeof import('@nutui/nutui-taro')['Picker'] 15 NutPicker: typeof import('@nutui/nutui-taro')['Picker']
......
...@@ -45,29 +45,19 @@ ...@@ -45,29 +45,19 @@
45 </template> 45 </template>
46 46
47 <script setup> 47 <script setup>
48 -import { ref } from 'vue' 48 +import Taro, { useShareAppMessage } from '@tarojs/taro'
49 -import Taro, { useDidShow, useShareAppMessage } from '@tarojs/taro'
50 // import { showSuccessToast, showFailToast } from 'vant'; // NutUI 或 Taro API 49 // import { showSuccessToast, showFailToast } from 'vant'; // NutUI 或 Taro API
51 -import { billListAPI } from '@/api/index';
52 import { useGo } from '@/hooks/useGo' 50 import { useGo } from '@/hooks/useGo'
53 import icon_1 from '@/assets/images/立即预约@2x.png' 51 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' 52 import icon_3 from '@/assets/images/首页02@2x.png'
56 import icon_4 from '@/assets/images/二维码icon.png' 53 import icon_4 from '@/assets/images/二维码icon.png'
57 import icon_5 from '@/assets/images/我的01@2x.png' 54 import icon_5 from '@/assets/images/我的01@2x.png'
58 -import icon_6 from '@/assets/images/luru@2x.png'
59 55
60 const go = useGo(); 56 const go = useGo();
61 57
62 const toBooking = () => { // 跳转到预约须知 58 const toBooking = () => { // 跳转到预约须知
63 go('/notice'); 59 go('/notice');
64 } 60 }
65 -const toRecord = () => { // 跳转到预约记录
66 - go('/bookingList');
67 -}
68 -const toSearch = () => { // 跳转到寺院录入
69 - go('/search');
70 -}
71 const toCode = () => { // 跳转到预约码 61 const toCode = () => { // 跳转到预约码
72 Taro.redirectTo({ 62 Taro.redirectTo({
73 url: '/pages/bookingCode/index' 63 url: '/pages/bookingCode/index'
...@@ -79,12 +69,6 @@ const toMy = () => { // 跳转到我的 ...@@ -79,12 +69,6 @@ const toMy = () => { // 跳转到我的
79 }) 69 })
80 } 70 }
81 71
82 -useDidShow(async () => {
83 - // TAG: 触发授权页面 (检查 session 或调用接口触发 401)
84 - // 小程序中,request.js 拦截器会处理 401 跳转
85 - await billListAPI({ page: 1, row_num: 1 });
86 -});
87 -
88 useShareAppMessage(() => { 72 useShareAppMessage(() => {
89 return { 73 return {
90 title: '西园寺预约', 74 title: '西园寺预约',
......
This diff is collapsed. Click to expand it.
1 /* 1 /*
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: 2026-01-07 21:44:54 4 + * @LastEditTime: 2026-01-08 16:27:50
5 * @FilePath: /xyxBooking-weapp/src/utils/request.js 5 * @FilePath: /xyxBooking-weapp/src/utils/request.js
6 * @Description: 简单axios封装,后续按实际处理 6 * @Description: 简单axios封装,后续按实际处理
7 */ 7 */
...@@ -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 qs from 'qs' 11 // import qs from 'qs'
12 // import { strExist } from './tools' 12 // import { strExist } from './tools'
13 -import { routerStore } from '@/stores/router' 13 +import { refreshSession, saveCurrentPagePath, navigateToAuth } from './authRedirect'
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'
...@@ -30,25 +30,6 @@ const getSessionId = () => { ...@@ -30,25 +30,6 @@ const getSessionId = () => {
30 } 30 }
31 }; 31 };
32 32
33 -const getCurrentPageFullPath = () => {
34 - try {
35 - const pages = Taro.getCurrentPages()
36 - if (!pages || pages.length === 0) return ''
37 -
38 - const currentPage = pages[pages.length - 1]
39 - const route = currentPage.route
40 - const options = currentPage.options || {}
41 -
42 - const queryParams = Object.keys(options)
43 - .map(key => `${key}=${encodeURIComponent(options[key])}`)
44 - .join('&')
45 -
46 - return queryParams ? `${route}?${queryParams}` : route
47 - } catch (error) {
48 - return ''
49 - }
50 -}
51 -
52 // const isPlainObject = (value) => { 33 // const isPlainObject = (value) => {
53 // if (value === null || typeof value !== 'object') return false 34 // if (value === null || typeof value !== 'object') return false
54 // return Object.prototype.toString.call(value) === '[object Object]' 35 // return Object.prototype.toString.call(value) === '[object Object]'
...@@ -114,33 +95,49 @@ service.interceptors.request.use( ...@@ -114,33 +95,49 @@ service.interceptors.request.use(
114 // response interceptor 95 // response interceptor
115 service.interceptors.response.use( 96 service.interceptors.response.use(
116 /** 97 /**
117 - * If you want to get http information such as headers or status 98 + * 响应拦截器说明
118 - * Please return response => response 99 + * - 这里统一处理后端自定义 code(例如 401 未授权)
100 + * - 如需拿到 headers/status 等原始信息,直接返回 response 即可
119 */ 101 */
120 - 102 + async response => {
121 - /**
122 - * Determine the request status by custom code
123 - * Here is just an example
124 - * You can also judge the status by HTTP Status Code
125 - */
126 - response => {
127 const res = response.data 103 const res = response.data
128 104
129 // 401 未授权处理 105 // 401 未授权处理
130 if (res.code === 401) { 106 if (res.code === 401) {
131 - // 跳转到授权页 107 + const config = response?.config || {}
132 - // 避免死循环,如果已经在 auth 页则不跳 108 + /**
109 + * 避免死循环/重复授权:
110 + * - __is_auth_request:本次请求就是“换取会话”的授权请求,不应再次触发刷新
111 + * - __is_retry:本次请求是 401 后的重试请求,如果仍 401,不再继续重试
112 + */
113 + if (config.__is_auth_request || config.__is_retry) {
114 + return response
115 + }
116 +
117 + /**
118 + * 记录来源页:用于授权成功后回跳
119 + * - 避免死循环:如果已经在 auth 页则不重复记录/跳转
120 + */
133 const pages = Taro.getCurrentPages(); 121 const pages = Taro.getCurrentPages();
134 const currentPage = pages[pages.length - 1]; 122 const currentPage = pages[pages.length - 1];
135 if (currentPage && currentPage.route !== 'pages/auth/index') { 123 if (currentPage && currentPage.route !== 'pages/auth/index') {
136 - const router = routerStore() 124 + saveCurrentPagePath()
137 - const currentPath = getCurrentPageFullPath() 125 + }
138 - if (currentPath) { 126 +
139 - router.add(currentPath) 127 + try {
140 - } 128 + // 优先走静默续期:成功后重放原请求
141 - // Taro.navigateTo({ url: '/pages/auth/index' }); 129 + await refreshSession()
130 + const retry_config = { ...config, __is_retry: true }
131 + return await service(retry_config)
132 + } catch (error) {
133 + // 静默续期失败:降级跳转到授权页(由授权页完成授权并回跳)
134 + const pages_retry = Taro.getCurrentPages();
135 + const current_page_retry = pages_retry[pages_retry.length - 1];
136 + if (current_page_retry && current_page_retry.route !== 'pages/auth/index') {
137 + navigateToAuth()
138 + }
139 + return response
142 } 140 }
143 - return response; // 返回 response 以便业务代码处理(或者这里 reject)
144 } 141 }
145 142
146 if (['预约ID不存在'].includes(res.msg)) { 143 if (['预约ID不存在'].includes(res.msg)) {
......