router.txt 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import { getCurrentInstance, type App } from 'vue'
  2. import { useUserLoginStore } from '@/store/login'
  3. import { Pages } from './pages'
  4. import { LoginPopupViewer } from './loginPopupServices'
  5. import Loading from './Loading'
  6. /** 实时判断用户是否已登录(避免 computed 缓存) */
  7. function isUserLoggedIn(): boolean {
  8. return useUserLoginStore().isLoggedIn
  9. }
  10. // 路由相关配置
  11. // 这里可以根据实际情况调整
  12. // 例如:需要登录验证的页面等
  13. // 以及登录页面、会员中心页面等
  14. // 需要登录验证的页面
  15. const authPages = [
  16. Pages.USER_INFO_EDIT,
  17. Pages.VIP_CENTER,
  18. //Pages.PRODUCT_LIST,
  19. //Pages.PRODUCT_DETAILS,
  20. Pages.USER_ACCOUNT_SECURITY,
  21. Pages.USER_EDIT_NICKNAME,
  22. Pages.USER_ORDER_LIST,
  23. Pages.USER_ORDER_DETAILS,
  24. Pages.USER_MOBILE,
  25. Pages.DISTRIBUTION_CENTER,
  26. Pages.DISTRIBUTION_CENTER_DETAILS,
  27. Pages.USER_MOBILE_CHANGE,
  28. Pages.USER_PERSONAL_INFO,
  29. Pages.USER_REMARK,
  30. Pages.PRODUCT_ORDER_CONFIRM,
  31. Pages.PRODUCT_PAY_MODE,
  32. Pages.COUPON_CENTER,
  33. Pages.COUPON_LIST,
  34. Pages.CUSTOMER_SERVICE,
  35. Pages.SHIPPING_ADDRESS_ADDED_OR_EDIT,
  36. Pages.SHIPPING_ADDRESS_LIST,
  37. Pages.USER_PASSWORD_CONFIG,
  38. Pages.WITHDRAWAL,
  39. Pages.WITHDRAWAL_RECORD_LIST,
  40. ]
  41. /** 判断是否需要登录 */
  42. function getBasePath(url: string): string {
  43. const index = url.indexOf('?')
  44. return index !== -1 ? url.substring(0, index) : url
  45. }
  46. function isAuthRequired(url: string): boolean {
  47. const cleanUrl = getBasePath(url)
  48. console.log(`URL数据源:${authPages}`)
  49. console.log(`URL原始值: ${url}`)
  50. console.log(`URL过滤值: ${cleanUrl}`)
  51. return authPages.some((item) => item === cleanUrl)
  52. }
  53. /** 缓存跳转路径 */
  54. function cacheRedirect(url: string) {
  55. uni.setStorageSync('pending_redirect', url)
  56. }
  57. /** 读取并清除缓存跳转路径 */
  58. function consumeRedirect(): string | null {
  59. const url = uni.getStorageSync('pending_redirect')
  60. uni.removeStorageSync('pending_redirect')
  61. return url || null
  62. }
  63. /** 路由核心跳转方法 */
  64. async function internalNavigate(
  65. type: 'navigateTo' | 'redirectTo' | 'switchTab' | 'reLaunch',
  66. url: string,
  67. options: Record<string, any> = {},
  68. ) {
  69. const originUrl: string = url.startsWith('/') ? url : `/${url}`
  70. const isAuthPage = isAuthRequired(originUrl)
  71. console.log(`[Router][${type}] 跳转到:`, originUrl, '需要登录:', isAuthPage)
  72. console.log(`[Router][${type}] 是否登录:`, isUserLoggedIn)
  73. // 如果需要登录但未登录,则弹出登录框
  74. if (isAuthPage && !isUserLoggedIn()) {
  75. cacheRedirect(originUrl)
  76. const loginResult = await LoginPopupViewer.open()
  77. console.log(`[Router][${type}] 登录弹窗结果:`, loginResult)
  78. // 如果登录失败(或用户取消),中断跳转
  79. if (!loginResult) {
  80. console.log(`[Router][${type}] 已终止跳转,原因:用户未登录或取消登录`)
  81. Loading.showError({ msg: '已取消登录' })
  82. return
  83. }
  84. }
  85. // 登录状态已满足,可以安全跳转
  86. try {
  87. switch (type) {
  88. case 'navigateTo':
  89. return await uniNavigateTo(originUrl, options)
  90. case 'redirectTo':
  91. return await uniRedirectTo(originUrl, options)
  92. case 'switchTab':
  93. return await uniSwitchTab(originUrl)
  94. case 'reLaunch':
  95. return await uniReLaunch(originUrl)
  96. }
  97. } catch (error) {
  98. console.error(`[Router][${type}] 跳转失败:`, error)
  99. }
  100. }
  101. /** ✅ Promise 封装 uni API **/
  102. function uniNavigateTo(url: string, options: any) {
  103. return new Promise((resolve, reject) => {
  104. uni.navigateTo({
  105. url,
  106. ...options,
  107. success: resolve,
  108. fail: reject,
  109. })
  110. })
  111. }
  112. function uniRedirectTo(url: string, options: any) {
  113. return new Promise((resolve, reject) => {
  114. uni.redirectTo({
  115. url,
  116. ...options,
  117. success: resolve,
  118. fail: reject,
  119. })
  120. })
  121. }
  122. function uniSwitchTab(url: string) {
  123. return new Promise((resolve, reject) => {
  124. uni.switchTab({
  125. url,
  126. success: resolve,
  127. fail: reject,
  128. })
  129. })
  130. }
  131. function uniReLaunch(url: string) {
  132. return new Promise((resolve, reject) => {
  133. uni.reLaunch({
  134. url,
  135. success: resolve,
  136. fail: reject,
  137. })
  138. })
  139. }
  140. // ✅ Router API 对象
  141. // ✅ Router API 对象
  142. export const Router = {
  143. // 页面跳转,支持登录鉴权
  144. async navigateTo(opt: { url: string; requiresAuth?: boolean } & Record<string, any>) {
  145. return await internalNavigate('navigateTo', opt.url, opt)
  146. },
  147. // 页面重定向,支持登录鉴权
  148. async redirectTo(opt: { url: string; requiresAuth?: boolean } & Record<string, any>) {
  149. return await internalNavigate('redirectTo', opt.url, opt)
  150. },
  151. // tab 页面切换
  152. async switchTab(opt: { url: string }) {
  153. return await internalNavigate('switchTab', opt.url, opt)
  154. },
  155. // 重新启动应用跳转
  156. async reLaunch(opt: { url: string }) {
  157. return await internalNavigate('reLaunch', opt.url, opt)
  158. },
  159. // 重定向别名
  160. async replace(opt: { url: string; requiresAuth?: boolean } & Record<string, any>) {
  161. return await internalNavigate('redirectTo', opt.url, opt)
  162. },
  163. // 返回上一级
  164. async back(delta = 1) {
  165. return await new Promise((resolve, reject) => {
  166. uni.navigateBack({
  167. delta,
  168. success: resolve,
  169. fail: reject,
  170. })
  171. })
  172. },
  173. consumeRedirect,
  174. }
  175. let cachedRouter: typeof Router | null = null
  176. /**
  177. * ✅ 全局安全获取 $Router 实例(推荐使用)
  178. */
  179. export function useRouter(): typeof Router {
  180. if (cachedRouter) return cachedRouter
  181. const instance = getCurrentInstance()
  182. if (!instance) {
  183. throw new Error('useRouter() 必须在 setup() 或生命周期中调用')
  184. }
  185. const router = instance.appContext.config.globalProperties.$Router
  186. if (!router) {
  187. throw new Error('$Router 尚未注入,请在 main.ts 中使用 app.use(RouterPlugin)')
  188. }
  189. cachedRouter = router
  190. return router
  191. }
  192. /** ✅ 注册为全局插件 */
  193. export default {
  194. install(app: App) {
  195. app.config.globalProperties.$Router = Router
  196. },
  197. }