小说网站前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
7.6 KiB

  1. import { createRouter, createWebHistory } from 'vue-router';
  2. import { AUTH_INJECTION_KEY } from '../components/auth/AuthProvider.vue';
  3. import layout from '../layout/index.vue';
  4. const routes = [
  5. {
  6. path: '/',
  7. name: 'layout',
  8. component: layout,
  9. children: [
  10. {
  11. path: '',
  12. name: 'Home',
  13. component: () => import('../views/home/Home.vue')
  14. },
  15. {
  16. path: 'book/:id',
  17. name: 'BookDetail',
  18. component: () => import('../views/book/index.vue'),
  19. props: true
  20. },
  21. {
  22. path: 'book/:id/chapter/:chapterId',
  23. name: 'ChapterDetail',
  24. component: () => import('../views/book/chapter.vue'),
  25. props: true
  26. },
  27. {
  28. path: 'category',
  29. name: 'Category',
  30. component: () => import('../views/home/category.vue'),
  31. props: true
  32. },
  33. {
  34. path: 'category/:id',
  35. name: 'CategoryDetail',
  36. component: () => import('../views/home/category.vue'),
  37. props: true
  38. },
  39. {
  40. path: 'ranking',
  41. name: 'ranking',
  42. component: () => import('../views/home/ranking.vue')
  43. },
  44. {
  45. path: 'bookshelf',
  46. name: 'Bookshelf',
  47. component: () => import('../views/home/Bookshelf.vue'),
  48. meta: { requiresAuth: true }
  49. },
  50. {
  51. path: 'author',
  52. name: 'authorCenter',
  53. component: () => import('../views/author/AuthorCenter.vue'),
  54. meta: { requiresAuth: true, requiresAuthor: true },
  55. redirect: { name: 'authorWorks' },
  56. children: [
  57. {
  58. path: 'works',
  59. name: 'authorWorks',
  60. component: () => import('../views/author/components/WorksManagement.vue'),
  61. meta: { requiresAuth: true, requiresAuthor: true }
  62. },
  63. {
  64. path: 'readers',
  65. name: 'authorReaders',
  66. component: () => import('../views/author/components/ReadersManagement.vue'),
  67. meta: { requiresAuth: true, requiresAuthor: true }
  68. }
  69. ]
  70. },
  71. {
  72. path: 'author/work/create',
  73. name: 'createWork',
  74. component: () => import('../views/author/CreateWork.vue'),
  75. meta: { requiresAuth: true, requiresAuthor: true }
  76. },
  77. {
  78. path: 'author/work/:id/setup',
  79. name: 'workSetup',
  80. component: () => import('../views/author/WorkSetup.vue'),
  81. meta: { requiresAuth: true, requiresAuthor: true }
  82. },
  83. {
  84. path: 'author/work/:id/edit',
  85. name: 'workEdit',
  86. component: () => import('../views/author/WorkEdit.vue'),
  87. meta: { requiresAuth: true, requiresAuthor: true }
  88. }
  89. ]
  90. },
  91. {
  92. path: '/:pathMatch(.*)*',
  93. name: 'NotFound',
  94. component: () => import('../views/NotFound.vue')
  95. }
  96. ];
  97. const router = createRouter({
  98. history: createWebHistory(),
  99. routes
  100. });
  101. // 创建一个事件总线用于通信
  102. export const routerEvents = {
  103. triggerLogin: null
  104. };
  105. // 全局路由守卫
  106. router.beforeEach((to, from, next) => {
  107. // 调试信息
  108. console.log('[Router] 路由切换:', {
  109. from: from.path,
  110. to: to.path,
  111. meta: to.meta
  112. });
  113. // 首先尝试从localStorage获取登录和作家状态
  114. const token = localStorage.getItem('token');
  115. const isLoggedIn = !!token;
  116. const isAuthor = localStorage.getItem('isAuthor') === 'true';
  117. // 输出当前状态
  118. console.log('[Router] 当前状态:', { isLoggedIn, isAuthor });
  119. // 获取路由需要的权限
  120. const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  121. const requiresAuthor = to.matched.some(record => record.meta.requiresAuthor);
  122. // 如果路由不需要任何权限,直接放行
  123. if (!requiresAuth && !requiresAuthor) {
  124. next();
  125. return;
  126. }
  127. // 处理需要登录的路由
  128. if (requiresAuth && !isLoggedIn) {
  129. const targetRoute = to.fullPath;
  130. console.log('[Router] 需要登录权限,未登录,跳转到首页');
  131. // 尝试调用登录弹窗
  132. setTimeout(() => {
  133. const authContext = window.$authContext;
  134. if (authContext && typeof authContext.openLogin === 'function') {
  135. authContext.openLogin(() => {
  136. // 登录成功后导航到原来想要去的页面
  137. router.push(targetRoute);
  138. });
  139. } else {
  140. // 如果authContext还未挂载,则设置事件供之后触发
  141. routerEvents.triggerLogin = () => {
  142. const context = window.$authContext;
  143. if (context && typeof context.openLogin === 'function') {
  144. context.openLogin(() => {
  145. router.push(targetRoute);
  146. });
  147. }
  148. };
  149. }
  150. }, 0);
  151. // 跳转到首页
  152. next({ path: '/' });
  153. return;
  154. }
  155. // 处理需要作家权限的路由
  156. if (requiresAuthor) {
  157. // 如果已经是作家,直接放行
  158. if (isAuthor) {
  159. console.log('[Router] 需要作家权限,已是作家,直接放行');
  160. next();
  161. return;
  162. }
  163. console.log('[Router] 需要作家权限,非作家,跳转到首页');
  164. // 未登录或不是作家,需要先登录再申请成为作家
  165. if (!isLoggedIn) {
  166. const targetRoute = to.fullPath;
  167. setTimeout(() => {
  168. const authContext = window.$authContext;
  169. if (authContext && typeof authContext.openLogin === 'function') {
  170. authContext.openLogin(() => {
  171. // 登录成功后显示作家申请
  172. const authorContext = window.$authorApplicationContext;
  173. if (authorContext && typeof authorContext.openApplicationModal === 'function') {
  174. authorContext.openApplicationModal(() => {
  175. // 申请成功后导航到作家专区
  176. router.push(targetRoute);
  177. });
  178. }
  179. });
  180. }
  181. }, 0);
  182. } else {
  183. // 已登录但不是作家,直接显示作家申请
  184. setTimeout(() => {
  185. const authorContext = window.$authorApplicationContext;
  186. if (authorContext && typeof authorContext.openApplicationModal === 'function') {
  187. authorContext.openApplicationModal(() => {
  188. // 申请成功后导航到作家专区
  189. router.push(to.fullPath);
  190. });
  191. }
  192. }, 0);
  193. }
  194. // 跳转到首页
  195. next({ path: '/' });
  196. return;
  197. }
  198. // 通过所有检查
  199. console.log('[Router] 通过所有权限检查');
  200. next();
  201. });
  202. export default router;