create-art-app-pino 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/dist/index.cjs +34 -6
  2. package/package.json +25 -8
  3. package/template/auth-art/_env.development +6 -0
  4. package/template/auth-art/src/router/guards/beforeEach.ts +32 -5
  5. package/template/auth-art/src/router/index.ts.ejs +37 -9
  6. package/template/auth-art/src/store/modules/user.ts +62 -12
  7. package/template/auth-art/src/utils/http/index.ts +15 -1
  8. package/template/auth-art/src/utils/http/mock.ts +94 -0
  9. package/template/auth-art/src/views/auth/login/index.vue +265 -157
  10. package/template/auth-art/src/views/auth/login/style.css +38 -0
  11. package/template/auth-zhihuishu/_env.development +9 -0
  12. package/template/auth-zhihuishu/src/router/guards/beforeEach.ts +34 -11
  13. package/template/auth-zhihuishu/src/router/index.ts.ejs +37 -9
  14. package/template/auth-zhihuishu/src/store/modules/auth.ts +22 -11
  15. package/template/auth-zhihuishu/src/utils/auth.ts +2 -1
  16. package/template/base/eslint.config.mjs +5 -0
  17. package/template/base/index.html +31 -1
  18. package/template/base/package.json.ejs +10 -2
  19. package/template/base/src/App.vue +36 -1
  20. package/template/base/src/api/system-manage.ts +25 -0
  21. package/template/base/src/assets/images/avatar/avatar.webp +0 -0
  22. package/template/base/src/assets/images/avatar/avatar1.webp +0 -0
  23. package/template/base/src/assets/images/avatar/avatar10.webp +0 -0
  24. package/template/base/src/assets/images/avatar/avatar2.webp +0 -0
  25. package/template/base/src/assets/images/avatar/avatar3.webp +0 -0
  26. package/template/base/src/assets/images/avatar/avatar4.webp +0 -0
  27. package/template/base/src/assets/images/avatar/avatar5.webp +0 -0
  28. package/template/base/src/assets/images/avatar/avatar6.webp +0 -0
  29. package/template/base/src/assets/images/avatar/avatar7.webp +0 -0
  30. package/template/base/src/assets/images/avatar/avatar8.webp +0 -0
  31. package/template/base/src/assets/images/avatar/avatar9.webp +0 -0
  32. package/template/base/src/assets/images/common/logo.webp +0 -0
  33. package/template/base/src/assets/images/draw/draw1.png +0 -0
  34. package/template/base/src/assets/images/settings/menu_layouts/dual_column.png +0 -0
  35. package/template/base/src/assets/images/settings/menu_layouts/horizontal.png +0 -0
  36. package/template/base/src/assets/images/settings/menu_layouts/mixed.png +0 -0
  37. package/template/base/src/assets/images/settings/menu_layouts/vertical.png +0 -0
  38. package/template/base/src/assets/images/settings/menu_styles/dark.png +0 -0
  39. package/template/base/src/assets/images/settings/menu_styles/design.png +0 -0
  40. package/template/base/src/assets/images/settings/menu_styles/light.png +0 -0
  41. package/template/base/src/assets/images/settings/theme_styles/dark.png +0 -0
  42. package/template/base/src/assets/images/settings/theme_styles/light.png +0 -0
  43. package/template/base/src/assets/images/settings/theme_styles/system.png +0 -0
  44. package/template/base/src/assets/images/svg/403.svg +1 -0
  45. package/template/base/src/assets/images/svg/404.svg +1 -0
  46. package/template/base/src/assets/images/svg/500.svg +5 -0
  47. package/template/base/src/assets/images/svg/login_icon.svg +1 -0
  48. package/template/base/src/assets/images/user/avatar.webp +0 -0
  49. package/template/base/src/assets/images/user/bg.webp +0 -0
  50. package/template/base/src/assets/styles/core/app.scss +292 -0
  51. package/template/base/src/assets/styles/core/dark.scss +93 -0
  52. package/template/base/src/assets/styles/core/el-dark.scss +2 -0
  53. package/template/base/src/assets/styles/core/el-light.scss +34 -0
  54. package/template/base/src/assets/styles/core/el-ui.scss +519 -0
  55. package/template/base/src/assets/styles/core/md.scss +1036 -0
  56. package/template/base/src/assets/styles/core/mixin.scss +157 -0
  57. package/template/base/src/assets/styles/core/reset.scss +41 -0
  58. package/template/base/src/assets/styles/core/router-transition.scss +104 -0
  59. package/template/base/src/assets/styles/core/tailwind.css +208 -0
  60. package/template/base/src/assets/styles/core/theme-animation.scss +63 -0
  61. package/template/base/src/assets/styles/core/theme-change.scss +11 -0
  62. package/template/base/src/assets/styles/custom/one-dark-pro.scss +98 -0
  63. package/template/base/src/assets/styles/index.scss +21 -8
  64. package/template/base/src/assets/svg/loading.ts +32 -0
  65. package/template/base/src/components/core/base/art-logo/index.vue +21 -0
  66. package/template/base/src/components/core/base/art-svg-icon/index.vue +24 -0
  67. package/template/base/src/components/core/charts/art-bar-chart/index.vue +203 -0
  68. package/template/base/src/components/core/charts/art-line-chart/index.vue +371 -0
  69. package/template/base/src/components/core/charts/art-ring-chart/index.vue +134 -0
  70. package/template/base/src/components/core/forms/art-drag-verify/index.vue +430 -0
  71. package/template/base/src/components/core/layouts/art-breadcrumb/index.vue +142 -0
  72. package/template/base/src/components/core/layouts/art-fast-enter/index.vue +113 -0
  73. package/template/base/src/components/core/layouts/art-global-component/index.vue +14 -0
  74. package/template/base/src/components/core/layouts/art-header-bar/index.vue +431 -0
  75. package/template/base/src/components/core/layouts/art-header-bar/widget/ArtUserMenu.vue +167 -0
  76. package/template/base/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue +110 -0
  77. package/template/base/src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue +106 -0
  78. package/template/base/src/components/core/layouts/art-menus/art-mixed-menu/index.vue +279 -0
  79. package/template/base/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue +354 -0
  80. package/template/base/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss +251 -0
  81. package/template/base/src/components/core/layouts/art-menus/art-sidebar-menu/theme.scss +258 -0
  82. package/template/base/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue +201 -0
  83. package/template/base/src/components/core/layouts/art-page-content/index.vue +133 -0
  84. package/template/base/src/components/core/layouts/art-work-tab/index.vue +584 -0
  85. package/template/base/src/components/core/others/art-menu-right/index.vue +415 -0
  86. package/template/base/src/components/core/tables/art-table/index.vue +344 -0
  87. package/template/base/src/components/core/tables/art-table/style.scss +94 -0
  88. package/template/base/src/components/core/text-effect/art-count-to/index.vue +310 -0
  89. package/template/base/src/components/core/theme/theme-svg/index.vue +100 -0
  90. package/template/base/src/components/core/views/exception/ArtException.vue +55 -0
  91. package/template/base/src/components/core/views/login/AuthTopBar.vue +149 -0
  92. package/template/base/src/components/core/views/login/LoginLeftView.vue +602 -0
  93. package/template/base/src/components/core/widget/art-icon-button/index.vue +23 -0
  94. package/template/base/src/config/assets/images.ts +61 -0
  95. package/template/base/src/config/index.ts +135 -0
  96. package/template/base/src/config/modules/component.ts +47 -0
  97. package/template/base/src/config/modules/fastEnter.ts.ejs +63 -0
  98. package/template/base/src/config/modules/festival.ts +51 -0
  99. package/template/base/src/config/modules/headerBar.ts +63 -0
  100. package/template/base/src/config/setting.ts +109 -0
  101. package/template/base/src/directives/business/highlight.ts +250 -0
  102. package/template/base/src/directives/business/ripple.ts +116 -0
  103. package/template/base/src/directives/core/auth.ts +66 -0
  104. package/template/base/src/directives/core/roles.ts +87 -0
  105. package/template/base/src/directives/index.ts +14 -0
  106. package/template/base/src/enums/appEnum.ts +81 -0
  107. package/template/base/src/enums/formEnum.ts +24 -0
  108. package/template/base/src/env.d.ts +9 -0
  109. package/template/base/src/hooks/core/useAppMode.ts +45 -0
  110. package/template/base/src/hooks/core/useAuth.ts +74 -0
  111. package/template/base/src/hooks/core/useCeremony.ts +184 -0
  112. package/template/base/src/hooks/core/useChart.ts +745 -0
  113. package/template/base/src/hooks/core/useCommon.ts +87 -0
  114. package/template/base/src/hooks/core/useFastEnter.ts +55 -0
  115. package/template/base/src/hooks/core/useHeaderBar.ts +179 -0
  116. package/template/base/src/hooks/core/useLayoutHeight.ts +148 -0
  117. package/template/base/src/hooks/core/useTable.ts +762 -0
  118. package/template/base/src/hooks/core/useTableColumns.ts +312 -0
  119. package/template/base/src/hooks/core/useTableHeight.ts +105 -0
  120. package/template/base/src/hooks/core/useTheme.ts +174 -0
  121. package/template/base/src/locales/index.ts +123 -0
  122. package/template/base/src/locales/langs/en.json +348 -0
  123. package/template/base/src/locales/langs/zh.json +348 -0
  124. package/template/base/src/main.ts +11 -12
  125. package/template/base/src/mock/upgrade/changeLog.ts +449 -0
  126. package/template/base/src/plugins/echarts.ts +76 -0
  127. package/template/base/src/router/core/ComponentLoader.ts +82 -0
  128. package/template/base/src/router/core/IframeRouteManager.ts +78 -0
  129. package/template/base/src/router/core/MenuProcessor.ts +280 -0
  130. package/template/base/src/router/core/RoutePermissionValidator.ts +161 -0
  131. package/template/base/src/router/core/RouteRegistry.ts +90 -0
  132. package/template/base/src/router/core/RouteTransformer.ts +132 -0
  133. package/template/base/src/router/core/RouteValidator.ts +187 -0
  134. package/template/base/src/router/core/index.ts +14 -0
  135. package/template/base/src/router/index.ts.ejs +37 -9
  136. package/template/base/src/router/routes/asyncRoutes.ts +38 -0
  137. package/template/base/src/router/routesAlias.ts +8 -0
  138. package/template/base/src/store/index.ts +49 -4
  139. package/template/base/src/store/modules/menu.ts +109 -0
  140. package/template/base/src/store/modules/setting.ts +447 -14
  141. package/template/base/src/store/modules/table.ts +97 -0
  142. package/template/base/src/store/modules/user.ts +78 -0
  143. package/template/base/src/store/modules/worktab.ts +568 -0
  144. package/template/base/src/types/api/api.d.ts +138 -0
  145. package/template/base/src/types/common/index.ts +95 -0
  146. package/template/base/src/types/common/response.ts +30 -0
  147. package/template/base/src/types/component/chart.ts +324 -0
  148. package/template/base/src/types/component/index.ts +145 -0
  149. package/template/base/src/types/config/index.ts +211 -0
  150. package/template/base/src/types/directive/directive.d.ts +15 -0
  151. package/template/base/src/types/import/auto-imports.d.ts +319 -0
  152. package/template/base/src/types/index.ts +22 -0
  153. package/template/base/src/types/router/index.ts +80 -0
  154. package/template/base/src/types/store/index.ts +157 -0
  155. package/template/base/src/utils/constants/index.ts +8 -0
  156. package/template/base/src/utils/constants/links.ts +35 -0
  157. package/template/base/src/utils/form/index.ts +12 -0
  158. package/template/base/src/utils/form/responsive.ts +122 -0
  159. package/template/base/src/utils/form/validator.ts +316 -0
  160. package/template/base/src/utils/http/error.ts +153 -0
  161. package/template/base/src/utils/http/index.ts +44 -14
  162. package/template/base/src/utils/http/status.ts +18 -0
  163. package/template/base/src/utils/index.ts +31 -0
  164. package/template/base/src/utils/navigation/index.ts +10 -0
  165. package/template/base/src/utils/navigation/jump.ts +68 -0
  166. package/template/base/src/utils/navigation/route.ts +85 -0
  167. package/template/base/src/utils/navigation/worktab.ts +67 -0
  168. package/template/base/src/utils/router.ts +61 -0
  169. package/template/base/src/utils/storage/index.ts +7 -0
  170. package/template/base/src/utils/storage/storage-config.ts +125 -0
  171. package/template/base/src/utils/storage/storage-key-manager.ts +97 -0
  172. package/template/base/src/utils/storage/storage.ts +250 -0
  173. package/template/base/src/utils/sys/error-handle.ts +143 -0
  174. package/template/base/src/utils/sys/index.ts +6 -0
  175. package/template/base/src/utils/sys/mittBus.ts +63 -0
  176. package/template/base/src/utils/sys/upgrade.ts +277 -0
  177. package/template/base/src/utils/table/tableCache.ts +267 -0
  178. package/template/base/src/utils/table/tableConfig.ts +55 -0
  179. package/template/base/src/utils/table/tableUtils.ts +297 -0
  180. package/template/base/src/utils/ui/animation.ts +80 -0
  181. package/template/base/src/utils/ui/colors.ts +273 -0
  182. package/template/base/src/utils/ui/emojo.ts +24 -0
  183. package/template/base/src/utils/ui/iconify-loader.ts +31 -0
  184. package/template/base/src/utils/ui/index.ts +11 -0
  185. package/template/base/src/utils/ui/loading.ts +84 -0
  186. package/template/base/src/utils/ui/tabs.ts +60 -0
  187. package/template/base/src/views/dashboard/analysis/index.vue +50 -0
  188. package/template/base/src/views/dashboard/analysis/modules/customer-satisfaction.vue +42 -0
  189. package/template/base/src/views/dashboard/analysis/modules/sales-mapping-by-country.vue +19 -0
  190. package/template/base/src/views/dashboard/analysis/modules/target-vs-reality.vue +69 -0
  191. package/template/base/src/views/dashboard/analysis/modules/today-sales.vue +83 -0
  192. package/template/base/src/views/dashboard/analysis/modules/top-products.vue +89 -0
  193. package/template/base/src/views/dashboard/analysis/modules/total-revenue.vue +37 -0
  194. package/template/base/src/views/dashboard/analysis/modules/visitor-insights.vue +35 -0
  195. package/template/base/src/views/dashboard/analysis/modules/volume-service-level.vue +43 -0
  196. package/template/base/src/views/dashboard/console/index.vue +41 -0
  197. package/template/base/src/views/dashboard/console/modules/about-project.vue +44 -0
  198. package/template/base/src/views/dashboard/console/modules/active-user.vue +47 -0
  199. package/template/base/src/views/dashboard/console/modules/card-list.vue +74 -0
  200. package/template/base/src/views/dashboard/console/modules/dynamic-stats.vue +79 -0
  201. package/template/base/src/views/dashboard/console/modules/new-user.vue +169 -0
  202. package/template/base/src/views/dashboard/console/modules/sales-overview.vue +43 -0
  203. package/template/base/src/views/dashboard/console/modules/todo-list.vue +71 -0
  204. package/template/base/src/views/exception/403/index.vue +18 -0
  205. package/template/base/src/views/exception/404/index.vue +18 -0
  206. package/template/base/src/views/exception/500/index.vue +18 -0
  207. package/template/base/src/views/index/index.vue +19 -112
  208. package/template/base/src/views/index/style.scss +93 -0
  209. package/template/base/src/views/outside/Iframe.vue +42 -0
  210. package/template/base/tsconfig.app.json +18 -5
  211. package/template/base/tsconfig.json +2 -14
  212. package/template/base/tsconfig.node.json +8 -2
  213. package/template/base/vite.config.ts +59 -28
  214. package/template/feature-echarts/src/plugins/echarts.ts +56 -2
  215. package/template/feature-markdown/src/components/MdPreviewWrapper.vue +9 -9
  216. package/template/feature-sse/src/utils/sse.ts +1 -1
  217. package/template/scaffold-doc-governance/AGENTS.md +32 -0
  218. package/template/scaffold-doc-governance/docs/README.md +12 -12
  219. package/template/scaffold-doc-governance/docs/adr/0001-doc-governance.md +18 -18
  220. package/template/scaffold-doc-governance/docs/getting-started/quick-start.md +62 -0
  221. package/template/scaffold-doc-governance/docs/reference/cli.md +15 -15
  222. package/template/scaffold-doc-governance/docs/templates/adr.md +5 -0
  223. package/template/scaffold-doc-governance/docs/templates/incident.md +8 -0
  224. package/template/scaffold-doc-governance/docs/templates/requirement.md +12 -0
  225. package/template/scaffold-doc-governance/scripts/docs/lint-frontmatter.mjs +17 -6
  226. package/template/scaffold-doc-governance/scripts/docs/lint-naming.mjs +17 -9
  227. package/template/base/src/views/dashboard/index.vue +0 -42
  228. package/template/base/src/views/exception/403.vue +0 -25
  229. package/template/base/src/views/exception/404.vue +0 -25
  230. package/template/scaffold-doc-governance/_github/PULL_REQUEST_TEMPLATE.md +0 -28
package/dist/index.cjs CHANGED
@@ -97,7 +97,7 @@ async function getProjectOptions(argv) {
97
97
  { title: ".reference \u53C2\u8003\u9879\u76EE\uFF08\u514B\u9686 art-design-pro \u6700\u65B0\u4EE3\u7801\uFF09", value: "reference", selected: true },
98
98
  { title: ".vscode \u7EDF\u4E00\u7F16\u8F91\u5668\u914D\u7F6E", value: "vscode", selected: true },
99
99
  { title: "AGENTS.md AI \u5F00\u53D1\u7EA6\u675F\u6587\u4EF6", value: "agentsMd", selected: true },
100
- { title: "\u6587\u6863\u6CBB\u7406\uFF08docs/ + 4 \u9053\u62A4\u680F + PR \u6A21\u677F\uFF09", value: "docGovernance", selected: true }
100
+ { title: "\u6587\u6863\u6CBB\u7406\uFF08docs/ + 4 \u9053\u62A4\u680F\uFF09", value: "docGovernance", selected: true }
101
101
  ]
102
102
  },
103
103
  {
@@ -171,6 +171,24 @@ function getFeatureDeps(features) {
171
171
  var import_node_fs = __toESM(require("fs"), 1);
172
172
  var import_node_path = __toESM(require("path"), 1);
173
173
  var import_ejs = __toESM(require("ejs"), 1);
174
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
175
+ ".png",
176
+ ".jpg",
177
+ ".jpeg",
178
+ ".webp",
179
+ ".gif",
180
+ ".ico",
181
+ ".bmp",
182
+ ".avif",
183
+ ".pdf",
184
+ ".zip",
185
+ ".gz",
186
+ ".tgz",
187
+ ".woff",
188
+ ".woff2",
189
+ ".ttf",
190
+ ".eot"
191
+ ]);
174
192
  async function renderTemplate(templateDir, targetDir, options, skipFiles = []) {
175
193
  const stats = import_node_fs.default.statSync(templateDir);
176
194
  if (!stats.isDirectory()) return;
@@ -191,21 +209,31 @@ async function renderTemplate(templateDir, targetDir, options, skipFiles = []) {
191
209
  }
192
210
  async function renderFile(srcPath, targetDir, fileName, options) {
193
211
  let destName = fileName;
194
- let content;
212
+ let textContent = null;
213
+ let binaryContent = null;
195
214
  if (fileName.endsWith(".ejs")) {
196
215
  destName = fileName.slice(0, -4);
197
216
  const template = import_node_fs.default.readFileSync(srcPath, "utf-8");
198
- content = import_ejs.default.render(template, { options });
199
- if (!content.trim()) return;
217
+ textContent = import_ejs.default.render(template, { options });
218
+ if (!textContent.trim()) return;
219
+ } else if (isBinaryTemplateFile(srcPath)) {
220
+ binaryContent = import_node_fs.default.readFileSync(srcPath);
200
221
  } else {
201
- content = import_node_fs.default.readFileSync(srcPath, "utf-8");
222
+ textContent = import_node_fs.default.readFileSync(srcPath, "utf-8");
202
223
  }
203
224
  if (destName.startsWith("_")) {
204
225
  destName = `.${destName.slice(1)}`;
205
226
  }
206
227
  const destPath = import_node_path.default.join(targetDir, destName);
207
228
  import_node_fs.default.mkdirSync(import_node_path.default.dirname(destPath), { recursive: true });
208
- import_node_fs.default.writeFileSync(destPath, content);
229
+ if (binaryContent) {
230
+ import_node_fs.default.writeFileSync(destPath, binaryContent);
231
+ return;
232
+ }
233
+ import_node_fs.default.writeFileSync(destPath, textContent ?? "");
234
+ }
235
+ function isBinaryTemplateFile(filePath) {
236
+ return BINARY_EXTENSIONS.has(import_node_path.default.extname(filePath).toLowerCase());
209
237
  }
210
238
  async function renderEjsInPlace(targetDir, options) {
211
239
  const files = getAllFiles(targetDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-art-app-pino",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI scaffold tool for creating Art Design Pro based projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,12 @@
10
10
  "dist",
11
11
  "template"
12
12
  ],
13
+ "scripts": {
14
+ "dev": "tsup --watch",
15
+ "build": "tsup",
16
+ "start": "node dist/index.cjs",
17
+ "prepublishOnly": "pnpm build"
18
+ },
13
19
  "keywords": [
14
20
  "cli",
15
21
  "scaffold",
@@ -26,19 +32,30 @@
26
32
  "prompts": "^2.4.2"
27
33
  },
28
34
  "devDependencies": {
35
+ "@element-plus/icons-vue": "^2.3.2",
36
+ "@iconify/vue": "^5.0.1",
29
37
  "@types/ejs": "^3.1.5",
30
38
  "@types/minimist": "^1.2.5",
31
39
  "@types/node": "^22.10.0",
40
+ "@types/nprogress": "^0.2.3",
32
41
  "@types/prompts": "^2.4.9",
42
+ "@vueuse/core": "^14.3.0",
43
+ "axios": "^1.18.0",
44
+ "echarts": "^6.1.0",
45
+ "element-plus": "^2.14.2",
46
+ "highlight.js": "^11.11.1",
47
+ "mitt": "^3.0.1",
48
+ "nprogress": "^0.2.0",
49
+ "ohash": "^2.0.11",
50
+ "pinia": "^3.0.4",
51
+ "pinia-plugin-persistedstate": "^4.7.1",
33
52
  "tsup": "^8.3.5",
34
- "typescript": "^5.7.2"
53
+ "typescript": "^5.7.2",
54
+ "vue": "^3.5.38",
55
+ "vue-i18n": "^11.4.5",
56
+ "vue-router": "^5.1.0"
35
57
  },
36
58
  "publishConfig": {
37
59
  "registry": "https://registry.npmjs.org"
38
- },
39
- "scripts": {
40
- "dev": "tsup --watch",
41
- "build": "tsup",
42
- "start": "node dist/index.cjs"
43
60
  }
44
- }
61
+ }
@@ -1,2 +1,8 @@
1
1
  # API 基础地址(开发环境)
2
2
  VITE_API_BASE_URL=http://localhost:3000
3
+
4
+ # 本地 Mock 模式(admin/admin 即可登录,无需真实后端)
5
+ VITE_MOCK_ENABLED=true
6
+
7
+ # 路由权限模式(frontend:前端静态菜单,backend:后端接口动态获取)
8
+ VITE_ACCESS_MODE=frontend
@@ -1,7 +1,11 @@
1
1
  import type { Router } from 'vue-router'
2
2
  import NProgress from 'nprogress'
3
- import { useUserStore } from '@/store/modules/user'
4
3
  import { fetchGetUserInfo } from '@/api/auth'
4
+ import { useUserStore } from '@/store/modules/user'
5
+ import { useMenuStore } from '@/store/modules/menu'
6
+ import { setWorktab } from '@/utils/navigation'
7
+ import { setPageTitle } from '@/utils/router'
8
+ import { MenuProcessor, RouteRegistry } from '@/router/core'
5
9
 
6
10
  // 是否已获取过用户信息
7
11
  let hasLoadedUserInfo = false
@@ -25,8 +29,9 @@ export function setupBeforeEachGuard(router: Router): void {
25
29
  // 访问登录页直接放行
26
30
  if (to.path === '/login') {
27
31
  if (userStore.isLogin) {
28
- next('/')
29
- } else {
32
+ next('/dashboard/console')
33
+ }
34
+ else {
30
35
  next()
31
36
  }
32
37
  return
@@ -45,9 +50,10 @@ export function setupBeforeEachGuard(router: Router): void {
45
50
  if (!hasLoadedUserInfo) {
46
51
  try {
47
52
  const userInfo = await fetchGetUserInfo()
48
- userStore.setUserInfo(userInfo as any)
53
+ userStore.setUserInfo(userInfo)
49
54
  hasLoadedUserInfo = true
50
- } catch (error) {
55
+ }
56
+ catch (error) {
51
57
  console.error('[Router] 获取用户信息失败:', error)
52
58
  userStore.logOut()
53
59
  next({ path: '/login' })
@@ -55,6 +61,27 @@ export function setupBeforeEachGuard(router: Router): void {
55
61
  }
56
62
  }
57
63
 
64
+ // 初始化菜单和动态路由
65
+ const menuStore = useMenuStore()
66
+ if (menuStore.menuList.length === 0) {
67
+ try {
68
+ const menuProcessor = new MenuProcessor()
69
+ const menuList = await menuProcessor.getMenuList()
70
+ menuStore.setMenuList(menuList)
71
+
72
+ const routeRegistry = new RouteRegistry(router)
73
+ routeRegistry.register(menuList)
74
+
75
+ // 注册动态路由后,进行重定向跳转以使新路由生效
76
+ next({ ...to, replace: true })
77
+ return
78
+ } catch (error) {
79
+ console.error('[Router] 初始化菜单或路由失败:', error)
80
+ }
81
+ }
82
+
83
+ setWorktab(to)
84
+ setPageTitle(to)
58
85
  next()
59
86
  })
60
87
 
@@ -1,5 +1,5 @@
1
- import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
2
1
  import type { RouteRecordRaw } from 'vue-router'
2
+ import { createRouter, <%- options.routerMode === 'hash' ? 'createWebHashHistory' : 'createWebHistory' %> } from 'vue-router'
3
3
  import { setupBeforeEachGuard } from './guards/beforeEach'
4
4
 
5
5
  const routes: RouteRecordRaw[] = [
@@ -11,30 +11,56 @@ const routes: RouteRecordRaw[] = [
11
11
  },
12
12
  {
13
13
  path: '/',
14
- name: 'Layout',
14
+ redirect: '/dashboard/console',
15
+ },
16
+ {
17
+ path: '/dashboard',
18
+ name: 'Dashboard',
15
19
  component: () => import('@/views/index/index.vue'),
16
- redirect: '/dashboard',
20
+ redirect: '/dashboard/console',
21
+ meta: { title: '仪表盘', icon: 'ri:pie-chart-line' },
17
22
  children: [
18
23
  {
19
- path: 'dashboard',
20
- name: 'Dashboard',
21
- component: () => import('@/views/dashboard/index.vue'),
22
- meta: { title: '仪表盘', icon: 'ep:home-filled' },
24
+ path: 'console',
25
+ name: 'Console',
26
+ component: () => import('@/views/dashboard/console/index.vue'),
27
+ meta: {
28
+ title: '工作台',
29
+ icon: 'ri:home-smile-2-line',
30
+ keepAlive: false,
31
+ fixedTab: true,
32
+ },
33
+ },
34
+ {
35
+ path: 'analysis',
36
+ name: 'Analysis',
37
+ component: () => import('@/views/dashboard/analysis/index.vue'),
38
+ meta: {
39
+ title: '分析页',
40
+ icon: 'ri:align-item-bottom-line',
41
+ keepAlive: false,
42
+ },
23
43
  },
24
44
  ],
25
45
  },
26
46
  {
27
47
  path: '/403',
28
48
  name: 'Forbidden',
29
- component: () => import('@/views/exception/403.vue'),
49
+ component: () => import('@/views/exception/403/index.vue'),
30
50
  meta: { title: '403' },
31
51
  },
32
52
  {
33
53
  path: '/404',
34
54
  name: 'NotFound',
35
- component: () => import('@/views/exception/404.vue'),
55
+ component: () => import('@/views/exception/404/index.vue'),
36
56
  meta: { title: '404' },
37
57
  },
58
+ {
59
+ path: '/500',
60
+ name: 'ServerError',
61
+ component: () => import('@/views/exception/500/index.vue'),
62
+ meta: { title: '500' },
63
+ },
38
64
  {
39
65
  path: '/:pathMatch(.*)*',
40
66
  redirect: '/404',
@@ -49,4 +75,6 @@ const router = createRouter({
49
75
  // 设置路由守卫
50
76
  setupBeforeEachGuard(router)
51
77
 
78
+ export const HOME_PAGE_PATH = ''
79
+ export { router }
52
80
  export default router
@@ -1,56 +1,106 @@
1
+ /**
2
+ * 用户状态管理(auth-art 版本)
3
+ * 管理用户登录状态、个人信息、语言设置等
4
+ * 基于 Art Design Pro 的 user store 适配
5
+ */
1
6
  import { defineStore } from 'pinia'
2
- import { ref, computed } from 'vue'
3
- import { useRouter } from 'vue-router'
7
+ import { computed, ref } from 'vue'
8
+ import { LanguageEnum } from '@/enums/appEnum'
9
+ import { router } from '@/router'
10
+ import { useSettingStore } from './setting'
11
+ import { useMenuStore } from './menu'
12
+ import { setPageTitle } from '@/utils/router'
13
+ import { resetRouterState } from '@/router/guards/beforeEach'
14
+
15
+ export interface UserInfo {
16
+ roles?: string[]
17
+ buttons?: string[]
18
+ userId?: string | number
19
+ [key: string]: any
20
+ }
4
21
 
5
22
  export const useUserStore = defineStore(
6
23
  'userStore',
7
24
  () => {
8
- const router = useRouter()
9
-
25
+ const language = ref(LanguageEnum.ZH)
10
26
  const isLogin = ref(false)
27
+ const isLock = ref(false)
28
+ const lockPassword = ref('')
29
+ const info = ref<UserInfo>({})
30
+ const searchHistory = ref<Record<string, unknown>[]>([])
11
31
  const accessToken = ref('')
12
32
  const refreshToken = ref('')
13
- const info = ref<Record<string, any>>({})
14
33
 
15
34
  const getUserInfo = computed(() => info.value)
35
+ const getSettingState = computed(() => useSettingStore().$state)
16
36
 
17
- function setUserInfo(newInfo: Record<string, any>) {
37
+ const setUserInfo = (newInfo: UserInfo) => {
18
38
  info.value = newInfo
19
39
  }
20
40
 
21
- function setLoginStatus(status: boolean) {
41
+ const setLoginStatus = (status: boolean) => {
22
42
  isLogin.value = status
23
43
  }
24
44
 
25
- function setToken(newAccessToken: string, newRefreshToken?: string) {
45
+ const setLanguage = (lang: LanguageEnum) => {
46
+ setPageTitle(router.currentRoute.value)
47
+ language.value = lang
48
+ }
49
+
50
+ const setSearchHistory = (list: Record<string, unknown>[]) => {
51
+ searchHistory.value = list
52
+ }
53
+
54
+ const setLockStatus = (status: boolean) => {
55
+ isLock.value = status
56
+ }
57
+
58
+ const setLockPassword = (password: string) => {
59
+ lockPassword.value = password
60
+ }
61
+
62
+ const setToken = (newAccessToken: string, newRefreshToken?: string) => {
26
63
  accessToken.value = newAccessToken
27
64
  if (newRefreshToken) {
28
65
  refreshToken.value = newRefreshToken
29
66
  }
30
67
  }
31
68
 
32
- function logOut() {
69
+ const logOut = () => {
33
70
  info.value = {}
34
71
  isLogin.value = false
72
+ isLock.value = false
73
+ lockPassword.value = ''
35
74
  accessToken.value = ''
36
75
  refreshToken.value = ''
37
-
76
+ sessionStorage.removeItem('iframeRoutes')
77
+ useMenuStore().setHomePath('')
78
+ resetRouterState()
38
79
  const currentRoute = router.currentRoute.value
39
80
  const redirect = currentRoute.path !== '/login' ? currentRoute.fullPath : undefined
40
81
  router.push({
41
- path: '/login',
82
+ name: 'Login',
42
83
  query: redirect ? { redirect } : undefined,
43
84
  })
44
85
  }
45
86
 
46
87
  return {
88
+ language,
47
89
  isLogin,
90
+ isLock,
91
+ lockPassword,
92
+ info,
93
+ searchHistory,
48
94
  accessToken,
49
95
  refreshToken,
50
- info,
51
96
  getUserInfo,
97
+ getSettingState,
52
98
  setUserInfo,
53
99
  setLoginStatus,
100
+ setLanguage,
101
+ setSearchHistory,
102
+ setLockStatus,
103
+ setLockPassword,
54
104
  setToken,
55
105
  logOut,
56
106
  }
@@ -2,12 +2,16 @@ import type { AxiosRequestConfig } from 'axios'
2
2
  import axios from 'axios'
3
3
  import { ElMessage } from 'element-plus'
4
4
  import { useUserStore } from '@/store/modules/user'
5
+ import { setupMock } from './mock'
5
6
 
6
7
  const http = axios.create({
7
8
  baseURL: import.meta.env.VITE_API_BASE_URL || '',
8
9
  timeout: 30000,
9
10
  })
10
11
 
12
+ // 启用 Mock 拦截器(仅 VITE_MOCK_ENABLED=true 时生效)
13
+ setupMock(http)
14
+
11
15
  // 请求拦截器:注入 token
12
16
  http.interceptors.request.use(
13
17
  (config) => {
@@ -23,7 +27,17 @@ http.interceptors.request.use(
23
27
  // 响应拦截器:处理 401 和业务错误
24
28
  http.interceptors.response.use(
25
29
  (response) => {
26
- return response.data
30
+ const res = response.data
31
+ // 剥离业务响应包装
32
+ if (res && typeof res === 'object' && 'code' in res) {
33
+ if (res.code === 0) {
34
+ return res.data
35
+ }
36
+ const message = res.message || '请求失败'
37
+ ElMessage.error(message)
38
+ return Promise.reject(new Error(message))
39
+ }
40
+ return res
27
41
  },
28
42
  (error) => {
29
43
  if (error.response?.status === 401) {
@@ -0,0 +1,94 @@
1
+ import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios'
2
+
3
+ interface MockRoute {
4
+ method: string
5
+ url: string
6
+ handler: (config: InternalAxiosRequestConfig) => unknown
7
+ }
8
+
9
+ const MOCK_TOKEN = 'mock-art-token-local-dev'
10
+
11
+ const mockRoutes: MockRoute[] = [
12
+ {
13
+ method: 'post',
14
+ url: '/api/auth/login',
15
+ handler: (config) => {
16
+ const body = typeof config.data === 'string' ? JSON.parse(config.data) : config.data
17
+ const username = body?.userName?.toLowerCase()
18
+ const password = body?.password
19
+
20
+ const isValid = (
21
+ (username === 'super' && password === '123456') ||
22
+ (username === 'admin' && password === '123456') ||
23
+ (username === 'user' && password === '123456') ||
24
+ (username === 'admin' && password === 'admin')
25
+ )
26
+
27
+ if (isValid) {
28
+ const role = username === 'super' ? 'R_SUPER' : (username === 'user' ? 'R_USER' : 'R_ADMIN')
29
+ return { code: 0, data: { token: `${MOCK_TOKEN}-${role}`, refreshToken: MOCK_TOKEN } }
30
+ }
31
+ return { code: 401, message: '用户名或密码错误' }
32
+ },
33
+ },
34
+ {
35
+ method: 'get',
36
+ url: '/api/user/info',
37
+ handler: (config) => {
38
+ const authHeader = (config.headers as any)?.Authorization as string || ''
39
+ const role = authHeader.includes('R_ADMIN') ? 'R_ADMIN' : (authHeader.includes('R_USER') ? 'R_USER' : 'R_SUPER')
40
+ const name = role === 'R_SUPER' ? 'Super' : (role === 'R_USER' ? 'User' : 'Admin')
41
+
42
+ return {
43
+ code: 0,
44
+ data: { userId: 1, userName: name, roles: [role], avatar: '/src/assets/images/user/avatar.webp' },
45
+ }
46
+ },
47
+ },
48
+ {
49
+ method: 'get',
50
+ url: '/api/v3/system/menus',
51
+ handler: () => ({
52
+ code: 0,
53
+ data: [
54
+ {
55
+ path: '/dashboard',
56
+ name: 'Dashboard',
57
+ component: '/dashboard/console/index',
58
+ meta: { title: '仪表盘', icon: 'ep:home-filled' },
59
+ }
60
+ ],
61
+ }),
62
+ },
63
+ ]
64
+
65
+ /**
66
+ * 在 VITE_MOCK_ENABLED=true 时启用本地 mock 拦截器
67
+ * 无需后端即可 admin/admin 登录并获取用户信息
68
+ */
69
+ export function setupMock(instance: AxiosInstance) {
70
+ if (import.meta.env.VITE_MOCK_ENABLED !== 'true')
71
+ return
72
+
73
+ instance.interceptors.request.use((config) => {
74
+ const matched = mockRoutes.find(
75
+ r => r.method === (config.method || 'get').toLowerCase()
76
+ && config.url?.includes(r.url),
77
+ )
78
+
79
+ if (matched) {
80
+ // 标记为 mock 请求,用 adapter 直接返回数据
81
+ const result = matched.handler(config)
82
+ config.adapter = () =>
83
+ Promise.resolve({
84
+ data: result,
85
+ status: 200,
86
+ statusText: 'OK',
87
+ headers: {},
88
+ config,
89
+ })
90
+ }
91
+
92
+ return config
93
+ })
94
+ }