index.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import pagesJson from 'virtual:pages-json'
  2. import type { Page } from '@uni-ku/pages-json/types'
  3. interface cousPage extends Page {
  4. islogin: boolean
  5. name?: string
  6. }
  7. function generateRoutes() {
  8. if (!pagesJson.pages)
  9. return []
  10. const routes = pagesJson.pages.map((page) => {
  11. const newPath = `/${page.path}`
  12. return { ...page, path: newPath }
  13. }) as cousPage[]
  14. if (pagesJson.subPackages && pagesJson.subPackages.length > 0) {
  15. pagesJson.subPackages.forEach((subPackage) => {
  16. const subRoutes = subPackage.pages.map((page: any) => {
  17. const newPath = `/${subPackage.root}/${page.path}`
  18. return { ...page, path: newPath }
  19. })
  20. routes.push(...subRoutes)
  21. })
  22. }
  23. return routes
  24. }
  25. const router = createRouter({
  26. routes: generateRoutes(),
  27. })
  28. /**
  29. * 过滤出所有需要登录的name 返回不需要登录的name
  30. *
  31. */
  32. function whitePathName() {
  33. return generateRoutes().filter(it => !it.islogin).map(it => it.name)
  34. }
  35. router.beforeEach((to, from, next) => {
  36. console.log('🚀 beforeEach 守卫触发:', { to, from }, '')
  37. const { token, redirectName } = storeToRefs(useUserStore())
  38. if (to.name === 'smqjh-login') {
  39. redirectName.value = appendParamsToPath(String(from.path), from.params as any)
  40. console.log(redirectName.value, ' redirectName.value')
  41. }
  42. if (!whitePathName().includes(to.name) && !token.value) {
  43. const { confirm: showConfirm } = useGlobalMessage()
  44. return new Promise<void>((resolve, reject) => {
  45. showConfirm({
  46. title: '警告',
  47. msg: '检测到当前状态未登录,是否登录',
  48. confirmButtonText: '登录',
  49. cancelButtonText: '取消',
  50. success() {
  51. redirectName.value = String(to.path)
  52. // console.log('✅ 用户确认访问,允许导航')
  53. router.replace({ name: 'smqjh-login' })
  54. // resolve()
  55. },
  56. fail() {
  57. // console.log('❌ 用户取消访问,阻止导航')
  58. next(false)
  59. reject(new Error('用户取消访问'))
  60. },
  61. })
  62. })
  63. }
  64. // 演示:基本的导航日志记录
  65. if (to.path && from.path) {
  66. console.log(`📍 导航: ${from.path} → ${to.path}`)
  67. }
  68. // 继续导航
  69. next()
  70. })
  71. router.afterEach((to, from) => {
  72. console.log('🎯 afterEach 钩子触发:', { to, from })
  73. // 演示:简单的页面切换记录
  74. if (to.path) {
  75. console.log(`📄 页面切换完成: ${to.path}`)
  76. }
  77. })
  78. export default router
  79. /**
  80. * 将 params 参数拼接到 path 路径后面
  81. * 兼容扫码拉起小程序时 q 参数为编码后的 URL 的情况
  82. * @param path 基础路径
  83. * @param params 参数对象
  84. * @returns 拼接后的完整路径
  85. */
  86. function appendParamsToPath(path: string, params: Record<string, any>): string {
  87. if (!params || Object.keys(params).length === 0) {
  88. return path
  89. }
  90. const queryParams: string[] = []
  91. Object.entries(params).forEach(([key, value]) => {
  92. if (value !== undefined && value !== null) {
  93. const strValue = String(value)
  94. // 处理扫码参数 q,可能是编码后的 URL
  95. if (key === 'q') {
  96. const extractedParams = extractParamsFromEncodedUrl(strValue)
  97. if (extractedParams) {
  98. // 将提取的参数合并到 queryParams
  99. Object.entries(extractedParams).forEach(([k, v]) => {
  100. queryParams.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
  101. })
  102. return
  103. }
  104. }
  105. // 普通参数直接编码
  106. const encodedKey = encodeURIComponent(key)
  107. const encodedValue = encodeURIComponent(strValue)
  108. queryParams.push(`${encodedKey}=${encodedValue}`)
  109. }
  110. })
  111. const queryString = queryParams.join('&')
  112. return queryString ? `${path}?${queryString}` : path
  113. }
  114. /**
  115. * 从编码后的 URL 中提取查询参数
  116. * @param encodedUrl 可能被编码的 URL 字符串
  117. * @returns 解析后的查询参数对象,如果不是有效的 URL 则返回 null
  118. */
  119. function extractParamsFromEncodedUrl(encodedUrl: string): Record<string, string> | null {
  120. try {
  121. // 尝试解码 URL
  122. let decodedUrl = encodedUrl
  123. // 可能需要多次解码(处理多次编码的情况)
  124. while (decodedUrl.includes('%')) {
  125. const newDecoded = decodeURIComponent(decodedUrl)
  126. if (newDecoded === decodedUrl)
  127. break
  128. decodedUrl = newDecoded
  129. }
  130. // 检查是否是有效的 URL 格式
  131. if (!decodedUrl.includes('http://') && !decodedUrl.includes('https://')) {
  132. return null
  133. }
  134. // 提取 ? 后面的查询参数
  135. const questionIndex = decodedUrl.indexOf('?')
  136. if (questionIndex === -1) {
  137. return null
  138. }
  139. const queryString = decodedUrl.substring(questionIndex + 1)
  140. if (!queryString) {
  141. return null
  142. }
  143. // 解析查询参数
  144. const params: Record<string, string> = {}
  145. const pairs = queryString.split('&')
  146. pairs.forEach((pair) => {
  147. const equalIndex = pair.indexOf('=')
  148. if (equalIndex > 0) {
  149. const key = decodeURIComponent(pair.substring(0, equalIndex))
  150. const val = decodeURIComponent(pair.substring(equalIndex + 1))
  151. params[key] = val
  152. }
  153. else if (pair) {
  154. params[decodeURIComponent(pair)] = ''
  155. }
  156. })
  157. return Object.keys(params).length > 0 ? params : null
  158. }
  159. catch {
  160. return null
  161. }
  162. }