lihui 1 week ago
commit
3f078f151d
  1. 314
      .auto-import.json
  2. 25
      .env
  3. 10
      .env.development
  4. 10
      .env.production
  5. 2
      .gitattributes
  6. 9
      .gitignore
  7. 1
      .husky/commit-msg
  8. 1
      .husky/pre-commit
  9. 5
      .idea/.gitignore
  10. 10
      .idea/UniappTool.xml
  11. 12
      .idea/art-design-pro.iml
  12. 62
      .idea/codeStyles/Project.xml
  13. 5
      .idea/codeStyles/codeStyleConfig.xml
  14. 7
      .idea/inspectionProfiles/Project_Default.xml
  15. 8
      .idea/modules.xml
  16. 7
      .idea/vcs.xml
  17. 3
      .prettierignore
  18. 20
      .prettierrc
  19. 9
      .stylelintignore
  20. 63
      .stylelintrc.cjs
  21. 3
      .vscode/settings.json
  22. 21
      LICENSE
  23. 83
      README.md
  24. 88
      README.zh-CN.md
  25. 97
      commitlint.config.cjs
  26. 84
      eslint.config.mjs
  27. 18
      index.html
  28. 205
      npminstall-debug.log
  29. 17315
      package-lock.json
  30. 116
      package.json
  31. 14162
      pnpm-lock.yaml
  32. BIN
      public/favicon.ico
  33. 880
      scripts/clean-dev.ts
  34. 50
      src/App.vue
  35. 25
      src/api/menuApi.ts
  36. 27
      src/api/usersApi.ts
  37. BIN
      src/assets/fonts/DMSans.woff2
  38. BIN
      src/assets/fonts/Montserrat.woff2
  39. 2663
      src/assets/icons/system/iconfont.css
  40. 67
      src/assets/icons/system/iconfont.js
  41. 4643
      src/assets/icons/system/iconfont.json
  42. BIN
      src/assets/icons/system/iconfont.ttf
  43. BIN
      src/assets/icons/system/iconfont.woff
  44. BIN
      src/assets/icons/system/iconfont.woff2
  45. BIN
      src/assets/img/3d/icon1.webp
  46. BIN
      src/assets/img/3d/icon2.webp
  47. BIN
      src/assets/img/3d/icon3.webp
  48. BIN
      src/assets/img/3d/icon4.webp
  49. BIN
      src/assets/img/3d/icon5.webp
  50. BIN
      src/assets/img/3d/icon6.webp
  51. BIN
      src/assets/img/3d/icon7.webp
  52. BIN
      src/assets/img/3d/icon8.webp
  53. BIN
      src/assets/img/avatar/avatar.webp
  54. BIN
      src/assets/img/avatar/avatar1.webp
  55. BIN
      src/assets/img/avatar/avatar10.webp
  56. BIN
      src/assets/img/avatar/avatar2.webp
  57. BIN
      src/assets/img/avatar/avatar3.webp
  58. BIN
      src/assets/img/avatar/avatar4.webp
  59. BIN
      src/assets/img/avatar/avatar5.webp
  60. BIN
      src/assets/img/avatar/avatar6.webp
  61. BIN
      src/assets/img/avatar/avatar7.webp
  62. BIN
      src/assets/img/avatar/avatar8.webp
  63. BIN
      src/assets/img/avatar/avatar9.webp
  64. BIN
      src/assets/img/ceremony/hb.png
  65. BIN
      src/assets/img/ceremony/sd.png
  66. BIN
      src/assets/img/ceremony/xc.png
  67. BIN
      src/assets/img/ceremony/yd.png
  68. BIN
      src/assets/img/common/logo.webp
  69. BIN
      src/assets/img/cover/img1.webp
  70. BIN
      src/assets/img/cover/img10.webp
  71. BIN
      src/assets/img/cover/img2.webp
  72. BIN
      src/assets/img/cover/img3.webp
  73. BIN
      src/assets/img/cover/img4.webp
  74. BIN
      src/assets/img/cover/img5.webp
  75. BIN
      src/assets/img/cover/img6.webp
  76. BIN
      src/assets/img/cover/img7.webp
  77. BIN
      src/assets/img/cover/img8.webp
  78. BIN
      src/assets/img/cover/img9.webp
  79. BIN
      src/assets/img/draw/draw1.png
  80. BIN
      src/assets/img/favicon.ico
  81. BIN
      src/assets/img/lock/lock_screen_1.webp
  82. BIN
      src/assets/img/login/lf_bg.webp
  83. BIN
      src/assets/img/login/lf_icon1.webp
  84. BIN
      src/assets/img/login/lf_icon2.webp
  85. BIN
      src/assets/img/safeguard/server.png
  86. BIN
      src/assets/img/settings/menu_layouts/dual_column.png
  87. BIN
      src/assets/img/settings/menu_layouts/horizontal.png
  88. BIN
      src/assets/img/settings/menu_layouts/mixed.png
  89. BIN
      src/assets/img/settings/menu_layouts/vertical.png
  90. BIN
      src/assets/img/settings/menu_styles/dark.png
  91. BIN
      src/assets/img/settings/menu_styles/design.png
  92. BIN
      src/assets/img/settings/menu_styles/light.png
  93. BIN
      src/assets/img/settings/theme_styles/dark.png
  94. BIN
      src/assets/img/settings/theme_styles/light.png
  95. BIN
      src/assets/img/settings/theme_styles/system.png
  96. BIN
      src/assets/img/state/403.png
  97. BIN
      src/assets/img/state/404.png
  98. BIN
      src/assets/img/state/500.png
  99. BIN
      src/assets/img/user/avatar.webp
  100. BIN
      src/assets/img/user/bg.webp

314
.auto-import.json

@ -0,0 +1,314 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"acceptHMRUpdate": true,
"asyncComputed": true,
"autoResetRef": true,
"computed": true,
"computedAsync": true,
"computedEager": true,
"computedInject": true,
"computedWithControl": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createInjectionState": true,
"createPinia": true,
"createReactiveFn": true,
"createReusableTemplate": true,
"createSharedComposable": true,
"createTemplatePromise": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"defineStore": true,
"eagerComputed": true,
"effectScope": true,
"extendRef": true,
"getActivePinia": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"injectLocal": true,
"isDefined": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"makeDestructurable": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onLongPress": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"pausableWatch": true,
"provide": true,
"provideLocal": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactiveComputed": true,
"reactiveOmit": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refAutoReset": true,
"refDebounced": true,
"refDefault": true,
"refThrottled": true,
"refWithControl": true,
"resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"storeToRefs": true,
"syncRef": true,
"syncRefs": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"tryOnBeforeMount": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useAnimate": true,
"useArrayDifference": true,
"useArrayEvery": true,
"useArrayFilter": true,
"useArrayFind": true,
"useArrayFindIndex": true,
"useArrayFindLast": true,
"useArrayIncludes": true,
"useArrayJoin": true,
"useArrayMap": true,
"useArrayReduce": true,
"useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBluetooth": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useCached": true,
"useClipboard": true,
"useClipboardItems": true,
"useCloned": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCurrentElement": true,
"useCycleList": true,
"useDark": true,
"useDateFormat": true,
"useDebounce": true,
"useDebounceFn": true,
"useDebouncedRefHistory": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useDropZone": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGamepad": true,
"useGeolocation": true,
"useId": true,
"useIdle": true,
"useImage": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLink": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useModel": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"useParentElement": true,
"usePerformanceObserver": true,
"usePermission": true,
"usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredContrast": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useScreenOrientation": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSorted": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSupported": true,
"useSwipe": true,
"useTemplateRef": true,
"useTemplateRefsList": true,
"useTextDirection": true,
"useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true,
"useThrottleFn": true,
"useThrottledRefHistory": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimeoutPoll": true,
"useTimestamp": true,
"useTitle": true,
"useToNumber": true,
"useToString": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVModel": true,
"useVModels": true,
"useVibrate": true,
"useVirtualList": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebSocket": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchArray": true,
"watchAtMost": true,
"watchDebounced": true,
"watchDeep": true,
"watchEffect": true,
"watchIgnorable": true,
"watchImmediate": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true,
"ElMessage": true,
"ElTag": true
}
}

25
.env

@ -0,0 +1,25 @@
# 【通用】环境变量
# 版本号
VITE_VERSION = 2.5.3
# 端口号
VITE_PORT = 3006
# 网站地址前缀
VITE_BASE_URL = /art-design-pro/
# API 地址前缀
VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
# 权限模式( frontend | backend )
VITE_ACCESS_MODE = frontend
# 跨域请求时是否携带 Cookie(开启前需确保后端支持)
VITE_WITH_CREDENTIALS = false
# 是否打开路由信息
VITE_OPEN_ROUTE_INFO = false
# 锁屏加密密钥
VITE_LOCK_ENCRYPT_KEY = s3cur3k3y4adpro

10
.env.development

@ -0,0 +1,10 @@
# 【开发】环境变量
# 网站地址前缀
VITE_BASE_URL = /
# API 地址前缀
VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
# Delete console
VITE_DROP_CONSOLE = false

10
.env.production

@ -0,0 +1,10 @@
# 【生产】环境变量
# 网站地址前缀
VITE_BASE_URL = /art-design-pro/
# API 地址前缀
VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
# Delete console
VITE_DROP_CONSOLE = true

2
.gitattributes

@ -0,0 +1,2 @@
*.html linguist-detectable=false
*.vue linguist-detectable=true

9
.gitignore

@ -0,0 +1,9 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.cursorrules
src/types/auto-imports.d.ts
src/types/components.d.ts

1
.husky/commit-msg

@ -0,0 +1 @@
pnpm dlx commitlint --edit $1

1
.husky/pre-commit

@ -0,0 +1 @@
pnpm run lint:lint-staged

5
.idea/.gitignore

@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

10
.idea/UniappTool.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="cn.fjdmy.uniapp.UniappProjectDataService">
<option name="generalBasePath" value="$PROJECT_DIR$" />
<option name="manifestPath" value="$PROJECT_DIR$/manifest.json" />
<option name="pagesPath" value="$PROJECT_DIR$/pages.json" />
<option name="scanNum" value="1" />
<option name="type" value="store" />
</component>
</project>

12
.idea/art-design-pro.iml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

62
.idea/codeStyles/Project.xml

@ -0,0 +1,62 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INDENT_CHILDREN_OF_TOP_LEVEL" value="template, script, style" />
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="100" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="100" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="100" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="100" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

7
.idea/inspectionProfiles/Project_Default.xml

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>

8
.idea/modules.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/art-design-pro.iml" filepath="$PROJECT_DIR$/.idea/art-design-pro.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

3
.prettierignore

@ -0,0 +1,3 @@
/node_modules/*
/dist/*
/src/main.ts

20
.prettierrc

@ -0,0 +1,20 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"vueIndentScriptAndStyle": true,
"singleQuote": true,
"quoteProps": "as-needed",
"bracketSpacing": true,
"trailingComma": "none",
"bracketSameLine": false,
"jsxSingleQuote": false,
"arrowParens": "always",
"insertPragma": false,
"requirePragma": false,
"proseWrap": "never",
"htmlWhitespaceSensitivity": "strict",
"endOfLine": "auto",
"rangeStart": 0
}

9
.stylelintignore

@ -0,0 +1,9 @@
dist
node_modules
public
.husky
.vscode
src/components/Layout/MenuLeft/index.vue
src/assets
stats.html

63
.stylelintrc.cjs

@ -0,0 +1,63 @@
module.exports = {
// 继承推荐规范配置
extends: [
'stylelint-config-standard',
'stylelint-config-recommended-scss',
'stylelint-config-recommended-vue/scss',
'stylelint-config-html/vue',
'stylelint-config-recess-order'
],
// 指定不同文件对应的解析器
overrides: [
{
files: ['**/*.{vue,html}'],
customSyntax: 'postcss-html'
},
{
files: ['**/*.{css,scss}'],
customSyntax: 'postcss-scss'
}
],
// 自定义规则
rules: {
'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url")
'selector-class-pattern': null, // 选择器类名命名规则
'custom-property-pattern': null, // 自定义属性命名规则
'keyframes-name-pattern': null, // 动画帧节点样式命名规则
'no-descending-specificity': null, // 允许无降序特异性
'no-empty-source': null, // 允许空样式
'property-no-vendor-prefix': null, // 允许属性前缀
// 允许 global 、export 、deep伪类
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['global', 'export', 'deep']
}
],
// 允许未知属性
'property-no-unknown': [
true,
{
ignoreProperties: []
}
],
// 允许未知规则
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'apply',
'use',
'mixin',
'include',
'extend',
'each',
'if',
'else',
'for',
'while'
]
}
]
}
}

3
.vscode/settings.json

@ -0,0 +1,3 @@
{
"volar.inlayHints.eventArgumentInInlineHandlers": true
}

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 SuperManTT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

83
README.md

@ -0,0 +1,83 @@
English | [简体中文](./README.zh-CN.md)
## About Art Design Pro
As a developer, I needed to build admin management systems for multiple projects but found that traditional systems couldn't fully meet the requirements for user experience and visual design. Therefore, I created Art Design Pro, an open-source admin management solution focused on user experience and rapid development. Based on the ElementPlus design specifications, it has been visually optimized to provide a more beautiful and practical front-end interface, helping you easily build high-quality admin systems.
## Official Website
[Visit the official documentation](https://www.lingchen.kim/art-design-pro/docs/en/)
## Demo Images
### Light Theme
![Light Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover1.png)
![Light Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover2.png)
### Dark Theme
![Dark Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover3.png)
![Dark Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover4.png)
## Features
- Uses the latest technology stack
- Built-in common business component templates
- Provides multiple theme modes and customizable themes
- Beautiful UI design, excellent user experience, and attention to detail
- System fully supports customization, meeting your personalized needs
## Functionality
- Rich theme switching
- Global search
- Lock screen
- Multi-tabs
- Global breadcrumbs
- Multi-language support
- Icon library
- Rich text editor
- Echarts charts
- Utils toolkit
- Network exception handling
- Route-level authentication
- Sidebar menu authentication
- Authentication directives
- Mobile adaptation
- Excellent persistent storage solution
- Local data storage validation
- Code commit validation and formatting
- Code commit standardization
## Compatibility
- Supports modern mainstream browsers such as Chrome, Safari, Firefox, etc.
## Installation and Running
```bash
# Install dependencies
pnpm install
# If pnpm install fails, try using the following command to install dependencies
pnpm install --ignore-scripts
# Start local development environment
pnpm dev
# Build for production
pnpm build
```
## Technical Support
QQ Group: <a href="https://qm.qq.com/cgi-bin/qm/qr?k=Gg6yzZLFaNgmRhK0T5Qcjf7-XcAFWWXm&jump_from=webapi&authKey=YpRKVJQyFKYbGTiKw0GJ/YQXnNF+GdXNZC5beQQqnGZTvuLlXoMO7nw5fNXvmVhA">821834289</a> (Click the link to join the group chat)
## Donation
If my project has been helpful to you, donations are welcome! Your support will be used to purchase tools like ChatGPT, Cursor, etc., to improve development efficiency and make the project even better. Thank you for your encouragement and support!
![Donation QR Code](https://www.qiniu.lingchen.kim/%E7%BB%84%202%402x%202.png)

88
README.zh-CN.md

@ -0,0 +1,88 @@
简体中文 | [English](./README.md)
## 关于 Art Design Pro
作为一名开发者,我在多个项目中需要搭建后台管理系统,但发现传统系统在用户体验和视觉设计上不能完全满足需求。因此,我创建了 Art Design Pro,一款专注于用户体验和快速开发的开源后台管理解决方案。基于 ElementPlus 设计规范,进行了视觉上的精心优化,提供更美观、更实用的前端界面,帮助你轻松构建高质量的后台系统。
## 官方网站
[访问官方文档](https://www.lingchen.kim/art-design-pro/docs/)
## 演示图
### 浅色主题
![浅色主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover1.png)
![浅色主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover2.png)
### 暗黑主题
![暗黑主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover3.png)
![暗黑主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover4.png)
## 特点
- 使用最新技术栈
- 内置常用业务组件模版
- 提供多种主题模式,可以自定义主题
- 漂亮的 UI设计、极致的用户体验和细节处理
- 系统全面支持自定义设置,满足您的个性化需求
## 技术栈
- 开发框架:Vue3、TypeScript、Vite、Element-Plus
- 代码规范:Eslint、Prettier、Stylelint、Husky、Lint-staged、cz-git
## 功能
- 丰富主题切换
- 全局搜索
- 锁屏
- 多标签页
- 全局面包屑
- 多语言
- 图标库
- 富文本编辑器
- Echarts 图表
- Utils工具包
- 网络异常处理
- 路由级别鉴权
- 侧边栏菜单鉴权
- 鉴权指令
- 移动端适配
- 优秀的持久化存储方案
- 本地数据存储校验
- 代码提交校验与格式化
- 代码提交规范化
## 兼容性
- 支持 Chrome、Safari、Firefox 等现代主流浏览器。
## 安装运行
```bash
# 安装依赖
pnpm install
# 如果 pnpm install 安装失败,尝试使用下面的命令安装依赖
pnpm install --ignore-scripts
# 本地开发环境启动
pnpm dev
# 生产环境打包
pnpm build
```
## 技术支持
QQ群:<a href="https://qm.qq.com/cgi-bin/qm/qr?k=Gg6yzZLFaNgmRhK0T5Qcjf7-XcAFWWXm&jump_from=webapi&authKey=YpRKVJQyFKYbGTiKw0GJ/YQXnNF+GdXNZC5beQQqnGZTvuLlXoMO7nw5fNXvmVhA">821834289</a>(点击链接加入群聊)
## 捐赠
如果我的项目对你有所帮助,欢迎捐赠支持!你的支持将用于购买 ChatGPT、Cursor 等工具,以提升开发效率,让项目变得更好。感谢你的鼓励与支持!
![捐赠二维码](https://www.qiniu.lingchen.kim/%E7%BB%84%202%402x%202.png)

97
commitlint.config.cjs

@ -0,0 +1,97 @@
/**
* commitlint 配置文件
* 文档
* https://commitlint.js.org/#/reference-rules
* https://cz-git.qbb.sh/zh/guide/
*/
module.exports = {
// 继承的规则
extends: ['@commitlint/config-conventional'],
// 自定义规则
rules: {
// 提交类型枚举,git提交type必须是以下类型
'type-enum': [
2,
'always',
[
'feat', // 新增功能
'fix', // 修复缺陷
'docs', // 文档变更
'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
'refactor', // 代码重构(不包括 bug 修复、功能新增)
'perf', // 性能优化
'test', // 添加疏漏测试或已有测试改动
'build', // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
'ci', // 修改 CI 配置、脚本
'revert', // 回滚 commit
'chore', // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
'wip' // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
]
],
'subject-case': [0] // subject大小写不做校验
},
prompt: {
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围(可选):',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
footerPrefixesSelect: '选择关联issue前缀(可选):',
customFooterPrefix: '输入自定义issue前缀 :',
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
generatingByAI: '正在通过 AI 生成你的提交简短描述...',
generatedSelectByAI: '选择一个 AI 生成的简短描述:',
confirmCommit: '是否提交或修改commit ?'
},
// prettier-ignore
types: [
{ value: "feat", name: "特性: 新增功能" },
{ value: "fix", name: "修复: 修复缺陷" },
{ value: "docs", name: "文档: 文档变更(更新README文件,或者注释)" },
{ value: "style", name: "格式: 代码格式(空格、格式化、缺失的分号等)" },
{ value: "refactor", name: "重构: 代码重构(不修复错误也不添加特性的代码更改)" },
{ value: "perf", name: "性能: 性能优化" },
{ value: "test", name: "测试: 添加疏漏测试或已有测试改动" },
{ value: "build", name: "构建: 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)" },
{ value: "ci", name: "集成: 修改 CI 配置、脚本" },
{ value: "revert", name: "回退: 回滚 commit" },
{ value: "chore", name: "其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)" },
],
useEmoji: true,
emojiAlign: 'center',
useAI: false,
aiNumber: 1,
themeColorCode: '',
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: 'bottom',
customScopesAlias: 'custom',
emptyScopesAlias: 'empty',
upperCaseSubject: false,
markBreakingChangeMode: false,
allowBreakingChanges: ['feat', 'fix'],
breaklineNumber: 100,
breaklineChar: '|',
skipQuestions: ['breaking', 'footerPrefix', 'footer'], // 跳过的步骤
issuePrefixes: [{ value: 'closed', name: 'closed: ISSUES has been processed' }],
customIssuePrefixAlign: 'top',
emptyIssuePrefixAlias: 'skip',
customIssuePrefixAlias: 'custom',
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: '',
defaultIssues: '',
defaultScope: '',
defaultSubject: ''
}
}

84
eslint.config.mjs

@ -0,0 +1,84 @@
// 从 URL 和路径模块中导入必要的功能
import fs from 'fs'
import path, { dirname } from 'path'
import { fileURLToPath } from 'url'
// 从 ESLint 插件中导入推荐配置
import pluginJs from '@eslint/js'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import pluginVue from 'eslint-plugin-vue'
import globals from 'globals'
import tseslint from 'typescript-eslint'
// 使用 import.meta.url 获取当前模块的路径
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
// 读取 .auto-import.json 文件的内容,并将其解析为 JSON 对象
const autoImportConfig = JSON.parse(
fs.readFileSync(path.resolve(__dirname, '.auto-import.json'), 'utf-8')
)
export default [
// 指定文件匹配规则
{
files: ['**/*.{js,mjs,cjs,ts,vue}']
},
// 指定全局变量和环境
{
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
},
// 扩展配置
pluginJs.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs['flat/essential'],
// 自定义规则
{
// 针对所有 JavaScript、TypeScript 和 Vue 文件应用以下配置
files: ['**/*.{js,mjs,cjs,ts,vue}'],
languageOptions: {
globals: {
// 合并从 autoImportConfig 中读取的全局变量配置
...autoImportConfig.globals,
// TypeScript 全局命名空间
Api: 'readonly',
Form: 'readonly'
}
},
rules: {
quotes: ['error', 'single'], // 使用单引号
semi: ['error', 'never'], // 语句末尾不加分号
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'@typescript-eslint/no-explicit-any': 'off', // 禁用 any 检查
'vue/multi-word-component-names': 'off', // 禁用对 Vue 组件名称的多词要求检查
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-unexpected-multiline': 'error' // 禁止空余的多行
}
},
// vue 规则
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: { parser: tseslint.parser }
}
},
// 忽略文件
{
ignores: [
'node_modules',
'dist',
'public',
'.vscode/**',
'src/assets/**',
'src/utils/console.ts'
]
},
// prettier 配置
eslintPluginPrettierRecommended
]

18
index.html

@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<title>Art Design Pro</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="Art Design Pro - A modern admin dashboard template built with Vue 3, TypeScript, and Element Plus."
/>
<link rel="shortcut icon" type="image/x-icon" href="src/assets/img/favicon.ico" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

205
npminstall-debug.log

@ -0,0 +1,205 @@
{
root: '/Users/tt/Downloads/art-design-pro',
registry: 'https://registry.npmmirror.com',
pkgs: [
{
name: '',
version: '/Users/tt/Downloads/art-design-pro/@types/vite/client',
type: 'directory',
alias: undefined,
arg: [Result]
}
],
production: false,
cacheStrict: false,
cacheDir: '/Users/tt/.npminstall_tarball',
env: {
npm_config_registry: 'https://registry.npmmirror.com',
npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=/Users/tt/.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","--save-dev","@types/vite/client"],"original":["--fix-bug-versions","--china","--userconfig=/Users/tt/.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","--save-dev","@types/vite/client"]}',
npm_config_user_agent: 'npminstall/7.12.0 npm/? node/v18.20.4 darwin x64',
npm_config_cache: '/Users/tt/.npminstall_tarball',
NODE: '/Users/tt/.nvm/versions/node/v18.20.4/bin/node',
npm_node_execpath: '/Users/tt/.nvm/versions/node/v18.20.4/bin/node',
npm_execpath: '/usr/local/lib/node_modules/cnpm/node_modules/npminstall/bin/install.js',
npm_config_userconfig: '/Users/tt/.cnpmrc',
npm_config_disturl: 'https://cdn.npmmirror.com/binaries/node',
npm_config_r: 'https://registry.npmmirror.com',
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver',
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
RE2_DOWNLOAD_SKIP_PATH: 'true',
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs',
npm_rootpath: '/Users/tt/Downloads/art-design-pro',
INIT_CWD: '/Users/tt/Downloads/art-design-pro'
},
binaryMirrors: {
ENVS: {
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver',
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
RE2_DOWNLOAD_SKIP_PATH: 'true',
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs'
},
'@ali/s2': { host: 'https://cdn.npmmirror.com/binaries/looksgood-s2' },
sharp: { replaceHostFiles: [Array], replaceHostMap: [Object] },
'@tensorflow/tfjs-node': {
replaceHostFiles: [Array],
replaceHostRegExpMap: [Object],
replaceHostMap: [Object]
},
cypress: {
host: 'https://cdn.npmmirror.com/binaries/cypress',
newPlatforms: [Object]
},
'utf-8-validate': {
host: 'https://cdn.npmmirror.com/binaries/utf-8-validate/v{version}'
},
xprofiler: {
remote_path: './xprofiler/v{version}/',
host: 'https://cdn.npmmirror.com/binaries'
},
leveldown: { host: 'https://cdn.npmmirror.com/binaries/leveldown/v{version}' },
couchbase: { host: 'https://cdn.npmmirror.com/binaries/couchbase/v{version}' },
gl: { host: 'https://cdn.npmmirror.com/binaries/gl/v{version}' },
sqlite3: {
host: 'https://cdn.npmmirror.com/binaries/sqlite3',
remote_path: 'v{version}'
},
'@journeyapps/sqlcipher': { host: 'https://cdn.npmmirror.com/binaries' },
grpc: {
host: 'https://cdn.npmmirror.com/binaries',
remote_path: '{name}/v{version}'
},
'grpc-tools': { host: 'https://cdn.npmmirror.com/binaries' },
wrtc: {
host: 'https://cdn.npmmirror.com/binaries',
remote_path: '{name}/v{version}'
},
fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' },
nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' },
canvas: { host: 'https://cdn.npmmirror.com/binaries/canvas' },
'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' },
'flow-bin': {
replaceHost: 'https://github.com/facebook/flow/releases/download/v',
host: 'https://cdn.npmmirror.com/binaries/flow/v'
},
'jpegtran-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpegtran-bin'
},
'cwebp-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/cwebp-bin'
},
'zopflipng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/zopflipng-bin'
},
'optipng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/optipng-bin'
},
mozjpeg: {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/mozjpeg-bin'
},
gifsicle: {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/gifsicle-bin'
},
'pngquant-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngquant-bin',
replaceHostMap: [Object]
},
'pngcrush-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngcrush-bin'
},
'jpeg-recompress-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpeg-recompress-bin'
},
'advpng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/advpng-bin'
},
'pngout-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngout-bin'
},
'jpegoptim-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpegoptim-bin'
},
argon2: { host: 'https://cdn.npmmirror.com/binaries/argon2' },
'ali-zeromq': { host: 'https://cdn.npmmirror.com/binaries/ali-zeromq' },
'ali-usb_ctl': { host: 'https://cdn.npmmirror.com/binaries/ali-usb_ctl' },
'gdal-async': { host: 'https://cdn.npmmirror.com/binaries/node-gdal-async' },
'libpg-query': { host: 'https://cdn.npmmirror.com/binaries' }
},
forbiddenLicenses: null,
flatten: false,
proxy: undefined,
prune: false,
disableFallbackStore: false,
workspacesMap: Map(0) {},
enableWorkspace: false,
workspaceRoot: '/Users/tt/Downloads/art-design-pro',
isWorkspaceRoot: true,
isWorkspacePackage: false,
offline: false,
strictSSL: true,
ignoreScripts: false,
foregroundScripts: false,
ignoreOptionalDependencies: false,
detail: false,
forceLinkLatest: false,
trace: false,
engineStrict: false,
registryOnly: false,
client: false,
autoFixVersion: [Function: autoFixVersion]
}

17315
package-lock.json
File diff suppressed because it is too large
View File

116
package.json

@ -0,0 +1,116 @@
{
"name": "art-design-pro",
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --open",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview",
"lint": "eslint",
"fix": "eslint --fix",
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix",
"lint:lint-staged": "lint-staged",
"prepare": "husky",
"commit": "git-cz",
"clean:dev": "tsx scripts/clean-dev.ts"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
"lint-staged": {
"*.{js,ts,mjs,mts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{cjs,json,jsonc}": [
"prettier --write"
],
"*.vue": [
"eslint --fix",
"stylelint --fix --allow-empty-input",
"prettier --write"
],
"*.{html,htm}": [
"prettier --write"
],
"*.{scss,css,less}": [
"stylelint --fix --allow-empty-input",
"prettier --write"
],
"*.{md,mdx}": [
"prettier --write"
],
"*.{yaml,yml}": [
"prettier --write"
]
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vue/reactivity": "^3.4.35",
"@vueuse/core": "^11.0.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "next",
"axios": "^1.7.5",
"crypto-js": "^4.2.0",
"echarts": "^5.6.0",
"element-plus": "^2.10.2",
"file-saver": "^2.0.5",
"highlight.js": "^11.10.0",
"md-editor-v3": "^4.17.0",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.2",
"pinia-plugin-persistedstate": "^4.3.0",
"qrcode.vue": "^3.6.0",
"vue": "^3.5.12",
"vue-draggable-plus": "^0.6.0",
"vue-i18n": "^9.14.0",
"vue-router": "^4.4.2",
"xgplayer": "^3.0.20",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^19.4.1",
"@commitlint/config-conventional": "^19.4.1",
"@eslint/js": "^9.9.1",
"@types/node": "^22.1.0",
"@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/compiler-sfc": "^3.0.5",
"commitizen": "^4.3.0",
"cz-git": "^1.11.1",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.27.0",
"globals": "^15.9.0",
"husky": "^9.1.5",
"lint-staged": "^15.5.2",
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.81.0",
"stylelint": "^16.20.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^36.0.1",
"terser": "^5.36.0",
"tsx": "^4.20.3",
"typescript": "~5.6.3",
"typescript-eslint": "^8.9.0",
"unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4",
"vite": "^6.1.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-vue-devtools": "^7.7.6",
"vue-demi": "^0.14.9",
"vue-img-cutter": "^3.0.5",
"vue-tsc": "~2.1.6"
}
}

14162
pnpm-lock.yaml
File diff suppressed because it is too large
View File

BIN
public/favicon.ico

880
scripts/clean-dev.ts

@ -0,0 +1,880 @@
// scripts/clean-dev.ts
import fs from 'fs/promises'
import path from 'path'
// 现代化颜色主题
const theme = {
// 基础颜色
reset: '\x1b[0m',
bold: '\x1b[1m',
dim: '\x1b[2m',
// 前景色
primary: '\x1b[38;5;75m', // 亮蓝色
success: '\x1b[38;5;82m', // 亮绿色
warning: '\x1b[38;5;220m', // 亮黄色
error: '\x1b[38;5;196m', // 亮红色
info: '\x1b[38;5;159m', // 青色
purple: '\x1b[38;5;141m', // 紫色
orange: '\x1b[38;5;208m', // 橙色
gray: '\x1b[38;5;245m', // 灰色
white: '\x1b[38;5;255m', // 白色
// 背景色
bgDark: '\x1b[48;5;235m', // 深灰背景
bgBlue: '\x1b[48;5;24m', // 蓝色背景
bgGreen: '\x1b[48;5;22m', // 绿色背景
bgRed: '\x1b[48;5;52m' // 红色背景
}
// 现代化图标集
const icons = {
rocket: '🚀',
fire: '🔥',
star: '⭐',
gem: '💎',
crown: '👑',
magic: '✨',
warning: '⚠️',
success: '✅',
error: '❌',
info: 'ℹ️',
folder: '📁',
file: '📄',
image: '🖼️',
code: '💻',
data: '📊',
globe: '🌐',
map: '🗺️',
chat: '💬',
bolt: '⚡',
shield: '🛡️',
key: '🔑',
link: '🔗',
clean: '🧹',
trash: '🗑️',
check: '✓',
cross: '✗',
arrow: '→',
loading: '⏳'
}
// 格式化工具
const fmt = {
title: (text: string) => `${theme.bold}${theme.primary}${text}${theme.reset}`,
subtitle: (text: string) => `${theme.purple}${text}${theme.reset}`,
success: (text: string) => `${theme.success}${text}${theme.reset}`,
error: (text: string) => `${theme.error}${text}${theme.reset}`,
warning: (text: string) => `${theme.warning}${text}${theme.reset}`,
info: (text: string) => `${theme.info}${text}${theme.reset}`,
highlight: (text: string) => `${theme.bold}${theme.white}${text}${theme.reset}`,
dim: (text: string) => `${theme.dim}${theme.gray}${text}${theme.reset}`,
orange: (text: string) => `${theme.orange}${text}${theme.reset}`,
// 带背景的文本
badge: (text: string, bg: string = theme.bgBlue) =>
`${bg}${theme.white}${theme.bold} ${text} ${theme.reset}`,
// 渐变效果模拟
gradient: (text: string) => {
const colors = ['\x1b[38;5;75m', '\x1b[38;5;81m', '\x1b[38;5;87m', '\x1b[38;5;159m']
const chars = text.split('')
return chars.map((char, i) => `${colors[i % colors.length]}${char}`).join('') + theme.reset
}
}
// 创建现代化标题横幅
function createModernBanner() {
console.log()
console.log(
fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
)
console.log(
fmt.gradient(' ║ ║')
)
console.log(
`${icons.rocket} ${fmt.title('ART DESIGN PRO')} ${fmt.subtitle('· 代码精简程序')} ${icons.magic}`
)
console.log(
`${fmt.dim('为项目移除演示数据,快速切换至开发模式')}`
)
console.log(
fmt.gradient(' ║ ║')
)
console.log(
fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
)
console.log()
}
// 创建分割线
function createDivider(char = '─', color = theme.primary) {
console.log(`${color}${' ' + char.repeat(66)}${theme.reset}`)
}
// 创建卡片样式容器
function createCard(title: string, content: string[]) {
console.log(` ${fmt.badge('', theme.bgBlue)} ${fmt.title(title)}`)
console.log()
content.forEach((line) => {
console.log(` ${line}`)
})
console.log()
}
// 进度条动画
function createProgressBar(current: number, total: number, text: string, width = 40) {
const percentage = Math.round((current / total) * 100)
const filled = Math.round((current / total) * width)
const empty = width - filled
const filledBar = '█'.repeat(filled)
const emptyBar = '░'.repeat(empty)
process.stdout.write(
`\r ${fmt.info('进度')} [${theme.success}${filledBar}${theme.gray}${emptyBar}${theme.reset}] ${fmt.highlight(percentage + '%')})}`
)
if (current === total) {
console.log()
}
}
// 统计信息
const stats = {
deletedFiles: 0,
deletedPaths: 0,
failedPaths: 0,
startTime: Date.now(),
totalFiles: 0
}
// 清理目标
const targets = [
'README.md',
'README.zh-CN.md',
'src/views/change',
'src/views/safeguard',
'src/views/article',
'src/views/examples',
'src/views/system/nested',
'src/views/widgets',
'src/views/template',
'src/views/dashboard/analysis',
'src/views/dashboard/ecommerce',
'src/mock/json',
'src/mock/temp/articleList.ts',
'src/mock/temp/commentDetail.ts',
'src/mock/temp/commentList.ts',
'src/assets/img/cover',
'src/assets/img/safeguard',
'src/assets/img/3d',
'src/components/core/charts/art-map-chart',
'src/components/custom/comment-widget'
]
// 递归统计文件数量
async function countFiles(targetPath: string): Promise<number> {
const fullPath = path.resolve(process.cwd(), targetPath)
try {
const stat = await fs.stat(fullPath)
if (stat.isFile()) {
return 1
} else if (stat.isDirectory()) {
const entries = await fs.readdir(fullPath)
let count = 0
for (const entry of entries) {
const entryPath = path.join(targetPath, entry)
count += await countFiles(entryPath)
}
return count
}
} catch {
return 0
}
return 0
}
// 统计所有目标的文件数量
async function countAllFiles(): Promise<number> {
let totalCount = 0
for (const target of targets) {
const count = await countFiles(target)
totalCount += count
}
return totalCount
}
// 删除文件和目录
async function remove(targetPath: string, index: number) {
const fullPath = path.resolve(process.cwd(), targetPath)
createProgressBar(index + 1, targets.length, targetPath)
try {
const fileCount = await countFiles(targetPath)
await fs.rm(fullPath, { recursive: true, force: true })
stats.deletedFiles += fileCount
stats.deletedPaths++
await new Promise((resolve) => setTimeout(resolve, 50))
} catch (err) {
stats.failedPaths++
console.log()
console.log(` ${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(targetPath)}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
// 清理异步路由
async function cleanAsyncRoutes() {
const asyncRoutesPath = path.resolve(process.cwd(), 'src/router/routes/asyncRoutes.ts')
try {
const cleanedRoutes = `import { RoutesAlias } from '../routesAlias'
import { AppRouteRecord } from '@/types/router'
/**
*
*
* :
* - 使
* -
*
* title:
* i18n key'用户列表'
*
* RoutesAlias.Layout component /index/index
* meta asyncRoutes staticRoutes
*/
export const asyncRoutes: AppRouteRecord[] = [
{
name: 'Dashboard',
path: '/dashboard',
component: RoutesAlias.Layout,
meta: {
title: 'menus.dashboard.title',
icon: '&#xe721;',
roles: ['R_SUPER', 'R_ADMIN']
},
children: [
{
path: 'console',
name: 'Console',
component: RoutesAlias.Dashboard,
meta: {
title: 'menus.dashboard.console',
keepAlive: false,
fixedTab: true
}
}
]
},
{
path: '/system',
name: 'System',
component: RoutesAlias.Layout,
meta: {
title: 'menus.system.title',
icon: '&#xe7b9;',
roles: ['R_SUPER', 'R_ADMIN']
},
children: [
{
path: 'user',
name: 'User',
component: RoutesAlias.User,
meta: {
title: 'menus.system.user',
keepAlive: true,
roles: ['R_SUPER', 'R_ADMIN']
}
},
{
path: 'role',
name: 'Role',
component: RoutesAlias.Role,
meta: {
title: 'menus.system.role',
keepAlive: true,
roles: ['R_SUPER']
}
},
{
path: 'user-center',
name: 'UserCenter',
component: RoutesAlias.UserCenter,
meta: {
title: 'menus.system.userCenter',
isHide: true,
keepAlive: true,
isHideTab: true
}
},
{
path: 'menu',
name: 'Menus',
component: RoutesAlias.Menu,
meta: {
title: 'menus.system.menu',
keepAlive: true,
roles: ['R_SUPER'],
authList: [
{
title: '新增',
authMark: 'add'
},
{
title: '编辑',
authMark: 'edit'
},
{
title: '删除',
authMark: 'delete'
}
]
}
}
]
},
{
path: '/result',
name: 'Result',
component: RoutesAlias.Layout,
meta: {
title: 'menus.result.title',
icon: '&#xe715;'
},
children: [
{
path: 'success',
name: 'ResultSuccess',
component: RoutesAlias.Success,
meta: {
title: 'menus.result.success',
keepAlive: true
}
},
{
path: 'fail',
name: 'ResultFail',
component: RoutesAlias.Fail,
meta: {
title: 'menus.result.fail',
keepAlive: true
}
}
]
},
{
path: '/exception',
name: 'Exception',
component: RoutesAlias.Layout,
meta: {
title: 'menus.exception.title',
icon: '&#xe820;'
},
children: [
{
path: '403',
name: '403',
component: RoutesAlias.Exception403,
meta: {
title: 'menus.exception.forbidden',
keepAlive: true
}
},
{
path: '404',
name: '404',
component: RoutesAlias.Exception404,
meta: {
title: 'menus.exception.notFound',
keepAlive: true
}
},
{
path: '500',
name: '500',
component: RoutesAlias.Exception500,
meta: {
title: 'menus.exception.serverError',
keepAlive: true
}
}
]
}
]
`
await fs.writeFile(asyncRoutesPath, cleanedRoutes, 'utf-8')
console.log(` ${icons.success} ${fmt.success('重写异步路由配置完成')}`)
} catch (err) {
console.log(` ${icons.error} ${fmt.error('清理异步路由失败')}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
// 清理路由别名
async function cleanRoutesAlias() {
const routesAliasPath = path.resolve(process.cwd(), 'src/router/routesAlias.ts')
try {
const cleanedAlias = `/**
* 便
*/
export enum RoutesAlias {
// 布局和认证
Layout = '/index/index', // 布局容器
Login = '/auth/login', // 登录
Register = '/auth/register', // 注册
ForgetPassword = '/auth/forget-password', // 忘记密码
// 异常页面
Exception403 = '/exception/403', // 403
Exception404 = '/exception/404', // 404
Exception500 = '/exception/500', // 500
// 结果页面
Success = '/result/success', // 成功
Fail = '/result/fail', // 失败
// 仪表板
Dashboard = '/dashboard/console', // 工作台
// 系统管理
User = '/system/user', // 账户
Role = '/system/role', // 角色
UserCenter = '/system/user-center', // 用户中心
Menu = '/system/menu' // 菜单
}
`
await fs.writeFile(routesAliasPath, cleanedAlias, 'utf-8')
console.log(` ${icons.success} ${fmt.success('重写路由别名配置完成')}`)
} catch (err) {
console.log(` ${icons.error} ${fmt.error('清理路由别名失败')}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
// 清理变更日志
async function cleanChangeLog() {
const changeLogPath = path.resolve(process.cwd(), 'src/mock/upgrade/changeLog.ts')
try {
const cleanedChangeLog = `import { ref } from 'vue'
interface UpgradeLog {
version: string // 版本号
title: string // 更新标题
date: string // 更新日期
detail?: string[] // 更新内容
requireReLogin?: boolean // 是否需要重新登录
remark?: string // 备注
}
export const upgradeLogList = ref<UpgradeLog[]>([])
`
await fs.writeFile(changeLogPath, cleanedChangeLog, 'utf-8')
console.log(` ${icons.success} ${fmt.success('清空变更日志数据完成')}`)
} catch (err) {
console.log(` ${icons.error} ${fmt.error('清理变更日志失败')}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
// 清理语言文件
async function cleanLanguageFiles() {
const languageFiles = [
{ path: 'src/locales/langs/zh.json', name: '中文语言文件' },
{ path: 'src/locales/langs/en.json', name: '英文语言文件' }
]
for (const { path: langPath, name } of languageFiles) {
try {
const fullPath = path.resolve(process.cwd(), langPath)
const content = await fs.readFile(fullPath, 'utf-8')
const langData = JSON.parse(content)
const menusToRemove = [
'widgets',
'template',
'article',
'examples',
'safeguard',
'plan',
'help'
]
if (langData.menus) {
menusToRemove.forEach((menuKey) => {
if (langData.menus[menuKey]) {
delete langData.menus[menuKey]
}
})
if (langData.menus.dashboard) {
if (langData.menus.dashboard.analysis) {
delete langData.menus.dashboard.analysis
}
if (langData.menus.dashboard.ecommerce) {
delete langData.menus.dashboard.ecommerce
}
}
if (langData.menus.system) {
const systemKeysToRemove = [
'nested',
'menu1',
'menu2',
'menu21',
'menu3',
'menu31',
'menu32',
'menu321'
]
systemKeysToRemove.forEach((key) => {
if (langData.menus.system[key]) {
delete langData.menus.system[key]
}
})
}
}
await fs.writeFile(fullPath, JSON.stringify(langData, null, 2), 'utf-8')
console.log(` ${icons.success} ${fmt.success(`清理${name}完成`)}`)
} catch (err) {
console.log(` ${icons.error} ${fmt.error(`清理${name}失败`)}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
}
// 清理快速入口组件
async function cleanFastEnterComponent() {
const fastEnterPath = path.resolve(process.cwd(), 'src/config/fastEnter.ts')
try {
const cleanedFastEnter = `/**
*
*
*/
import { RoutesAlias } from '@/router/routesAlias'
import { WEB_LINKS } from '@/utils/constants'
import type { FastEnterConfig } from '@/types/config'
const fastEnterConfig: FastEnterConfig = {
// 显示条件(屏幕宽度)
minWidth: 1200,
// 应用列表
applications: [
{
name: '工作台',
description: '系统概览与数据统计',
icon: '&#xe721;',
iconColor: '#377dff',
path: RoutesAlias.Dashboard,
enabled: true,
order: 1
},
{
name: '官方文档',
description: '使用指南与开发文档',
icon: '&#xe788;',
iconColor: '#ffb100',
path: WEB_LINKS.DOCS,
enabled: true,
order: 2
},
{
name: '技术支持',
description: '技术支持与问题反馈',
icon: '&#xe86e;',
iconColor: '#ff6b6b',
path: WEB_LINKS.COMMUNITY,
enabled: true,
order: 3
},
{
name: '哔哩哔哩',
description: '技术分享与交流',
icon: '&#xe6b4;',
iconColor: '#FB7299',
path: WEB_LINKS.BILIBILI,
enabled: true,
order: 4
}
],
// 快速链接
quickLinks: [
{
name: '登录',
path: RoutesAlias.Login,
enabled: true,
order: 1
},
{
name: '注册',
path: RoutesAlias.Register,
enabled: true,
order: 2
},
{
name: '忘记密码',
path: RoutesAlias.ForgetPassword,
enabled: true,
order: 3
},
{
name: '个人中心',
path: RoutesAlias.UserCenter,
enabled: true,
order: 4
}
]
}
export default Object.freeze(fastEnterConfig)
`
await fs.writeFile(fastEnterPath, cleanedFastEnter, 'utf-8')
console.log(` ${icons.success} ${fmt.success('清理快速入口配置完成')}`)
} catch (err) {
console.log(` ${icons.error} ${fmt.error('清理快速入口配置失败')}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
}
}
// 用户确认函数
async function getUserConfirmation(): Promise<boolean> {
const { createInterface } = await import('readline')
return new Promise((resolve) => {
const rl = createInterface({
input: process.stdin,
output: process.stdout
})
console.log(
` ${fmt.highlight('请输入')} ${fmt.success('yes')} ${fmt.highlight('确认执行清理操作,或按 Enter 取消')}`
)
console.log()
process.stdout.write(` ${icons.arrow} `)
rl.question('', (answer: string) => {
rl.close()
resolve(answer.toLowerCase().trim() === 'yes')
})
})
}
// 显示清理警告
async function showCleanupWarning() {
createCard('安全警告', [
`${fmt.warning('此操作将永久删除以下演示内容,且无法恢复!')}`,
`${fmt.dim('请仔细阅读清理列表,确认后再继续操作')}`
])
const cleanupItems = [
{
icon: icons.image,
name: '图片资源',
desc: '演示用的封面图片、3D图片、运维图片等',
color: theme.orange
},
{
icon: icons.file,
name: '演示页面',
desc: 'widgets、template、article、examples、safeguard等页面',
color: theme.purple
},
{
icon: icons.code,
name: '动态路由文件',
desc: '重写asyncRoutes.ts,只保留核心路由',
color: theme.primary
},
{
icon: icons.link,
name: '路由别名',
desc: '重写routesAlias.ts,移除演示路由别名',
color: theme.info
},
{
icon: icons.data,
name: 'Mock数据',
desc: '演示用的JSON数据、文章列表、评论数据等',
color: theme.success
},
{
icon: icons.globe,
name: '多语言文件',
desc: '清理中英文语言包中的演示菜单项',
color: theme.warning
},
{ icon: icons.map, name: '地图组件', desc: '移除art-map-chart地图组件', color: theme.error },
{ icon: icons.chat, name: '评论组件', desc: '移除comment-widget评论组件', color: theme.orange },
{
icon: icons.bolt,
name: '快速入口',
desc: '移除分析页、礼花效果、聊天、更新日志、定价、留言管理等无效项目',
color: theme.purple
}
]
console.log(` ${fmt.badge('', theme.bgRed)} ${fmt.title('将要清理的内容')}`)
console.log()
cleanupItems.forEach((item, index) => {
console.log(` ${item.color}${theme.reset} ${fmt.highlight(`${index + 1}. ${item.name}`)}`)
console.log(` ${fmt.dim(item.desc)}`)
})
console.log()
console.log(` ${fmt.badge('', theme.bgGreen)} ${fmt.title('保留的功能模块')}`)
console.log()
const preservedModules = [
{ name: 'Dashboard', desc: '工作台页面' },
{ name: 'System', desc: '系统管理模块' },
{ name: 'Result', desc: '结果页面' },
{ name: 'Exception', desc: '异常页面' },
{ name: 'Auth', desc: '登录注册功能' },
{ name: 'Core Components', desc: '核心组件库' }
]
preservedModules.forEach((module) => {
console.log(` ${icons.check} ${fmt.success(module.name)} ${fmt.dim(`- ${module.desc}`)}`)
})
console.log()
createDivider()
console.log()
}
// 显示统计信息
async function showStats() {
const duration = Date.now() - stats.startTime
const seconds = (duration / 1000).toFixed(2)
console.log()
createCard('清理统计', [
`${fmt.success('成功删除')}: ${fmt.highlight(stats.deletedFiles.toString())} 个文件`,
`${fmt.info('涉及路径')}: ${fmt.highlight(stats.deletedPaths.toString())} 个目录/文件`,
...(stats.failedPaths > 0
? [
`${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(stats.failedPaths.toString())} 个路径`
]
: []),
`${fmt.info('耗时')}: ${fmt.highlight(seconds)}`
])
}
// 创建成功横幅
function createSuccessBanner() {
console.log()
console.log(
fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
)
console.log(
fmt.gradient(' ║ ║')
)
console.log(
`${icons.star} ${fmt.success('清理完成!项目已准备就绪')} ${icons.rocket}`
)
console.log(
`${fmt.dim('现在可以开始您的开发之旅了!')}`
)
console.log(
fmt.gradient(' ║ ║')
)
console.log(
fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
)
console.log()
}
// 主函数
async function main() {
// 清屏并显示横幅
console.clear()
createModernBanner()
// 显示清理警告
await showCleanupWarning()
// 统计文件数量
console.log(` ${fmt.info('正在统计文件数量...')}`)
stats.totalFiles = await countAllFiles()
console.log(` ${fmt.info('即将清理')}: ${fmt.highlight(stats.totalFiles.toString())} 个文件`)
console.log(` ${fmt.dim(`涉及 ${targets.length} 个目录/文件路径`)}`)
console.log()
// 用户确认
const confirmed = await getUserConfirmation()
if (!confirmed) {
console.log(` ${fmt.warning('操作已取消,清理中止')}`)
console.log()
return
}
console.log()
console.log(` ${icons.check} ${fmt.success('确认成功,开始清理...')}`)
console.log()
// 开始清理过程
console.log(` ${fmt.badge('步骤 1/6', theme.bgBlue)} ${fmt.title('删除演示文件')}`)
console.log()
for (let i = 0; i < targets.length; i++) {
await remove(targets[i], i)
}
console.log()
console.log(` ${fmt.badge('步骤 2/6', theme.bgBlue)} ${fmt.title('重写路由配置')}`)
console.log()
await cleanAsyncRoutes()
console.log()
console.log(` ${fmt.badge('步骤 3/6', theme.bgBlue)} ${fmt.title('重写路由别名')}`)
console.log()
await cleanRoutesAlias()
console.log()
console.log(` ${fmt.badge('步骤 4/6', theme.bgBlue)} ${fmt.title('清空变更日志')}`)
console.log()
await cleanChangeLog()
console.log()
console.log(` ${fmt.badge('步骤 5/6', theme.bgBlue)} ${fmt.title('清理语言文件')}`)
console.log()
await cleanLanguageFiles()
console.log()
console.log(` ${fmt.badge('步骤 6/6', theme.bgBlue)} ${fmt.title('清理快速入口')}`)
console.log()
await cleanFastEnterComponent()
// 显示统计信息
await showStats()
// 显示成功横幅
createSuccessBanner()
}
main().catch((err) => {
console.log()
console.log(` ${icons.error} ${fmt.error('清理脚本执行出错')}`)
console.log(` ${fmt.dim('错误详情: ' + err)}`)
console.log()
process.exit(1)
})

50
src/App.vue

@ -0,0 +1,50 @@
<template>
<ElConfigProvider size="default" :locale="locales[language]" :z-index="3000">
<RouterView></RouterView>
</ElConfigProvider>
</template>
<script setup lang="ts">
import { useUserStore } from './store/modules/user'
import zh from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import { systemUpgrade } from './utils/sys'
import { UserService } from './api/usersApi'
import { setThemeTransitionClass } from './utils/theme/animation'
import { checkStorageCompatibility } from './utils/storage'
const userStore = useUserStore()
const { language } = storeToRefs(userStore)
const locales = {
zh: zh,
en: en
}
onBeforeMount(() => {
setThemeTransitionClass(true)
})
onMounted(() => {
//
checkStorageCompatibility()
//
setThemeTransitionClass(false)
//
systemUpgrade()
//
getUserInfo()
})
//
const getUserInfo = async () => {
if (userStore.isLogin) {
try {
const data = await UserService.getUserInfo()
userStore.setUserInfo(data)
} catch (error) {
console.error('获取用户信息失败', error)
}
}
}
</script>

25
src/api/menuApi.ts

@ -0,0 +1,25 @@
import { asyncRoutes } from '@/router/routes/asyncRoutes'
import { menuDataToRouter } from '@/router/utils/menuToRouter'
import { AppRouteRecord } from '@/types/router'
interface MenuResponse {
menuList: AppRouteRecord[]
}
// 菜单接口
export const menuService = {
async getMenuList(delay = 300): Promise<MenuResponse> {
try {
// 模拟接口返回的菜单数据
const menuData = asyncRoutes
// 处理菜单数据
const menuList = menuData.map((route) => menuDataToRouter(route))
// 模拟接口延迟
await new Promise((resolve) => setTimeout(resolve, delay))
return { menuList }
} catch (error) {
throw error instanceof Error ? error : new Error('获取菜单失败')
}
}
}

27
src/api/usersApi.ts

@ -0,0 +1,27 @@
import request from '@/utils/http'
export class UserService {
// 登录
static login(params: Api.Auth.LoginParams) {
return request.post<Api.Auth.LoginResponse>({
url: '/api/auth/login',
params
// showErrorMessage: false // 不显示错误消息
})
}
// 获取用户信息
static getUserInfo() {
return request.get<Api.User.UserInfo>({
url: '/api/user/info'
})
}
// 获取用户列表
static getUserList(params: Api.Common.PaginatingSearchParams) {
return request.get<Api.User.UserListData>({
url: '/api/user/list',
params
})
}
}

BIN
src/assets/fonts/DMSans.woff2

BIN
src/assets/fonts/Montserrat.woff2

2663
src/assets/icons/system/iconfont.css
File diff suppressed because it is too large
View File

67
src/assets/icons/system/iconfont.js
File diff suppressed because it is too large
View File

4643
src/assets/icons/system/iconfont.json
File diff suppressed because it is too large
View File

BIN
src/assets/icons/system/iconfont.ttf

BIN
src/assets/icons/system/iconfont.woff

BIN
src/assets/icons/system/iconfont.woff2

BIN
src/assets/img/3d/icon1.webp

BIN
src/assets/img/3d/icon2.webp

BIN
src/assets/img/3d/icon3.webp

BIN
src/assets/img/3d/icon4.webp

BIN
src/assets/img/3d/icon5.webp

BIN
src/assets/img/3d/icon6.webp

BIN
src/assets/img/3d/icon7.webp

BIN
src/assets/img/3d/icon8.webp

BIN
src/assets/img/avatar/avatar.webp

BIN
src/assets/img/avatar/avatar1.webp

BIN
src/assets/img/avatar/avatar10.webp

BIN
src/assets/img/avatar/avatar2.webp

BIN
src/assets/img/avatar/avatar3.webp

BIN
src/assets/img/avatar/avatar4.webp

BIN
src/assets/img/avatar/avatar5.webp

BIN
src/assets/img/avatar/avatar6.webp

BIN
src/assets/img/avatar/avatar7.webp

BIN
src/assets/img/avatar/avatar8.webp

BIN
src/assets/img/avatar/avatar9.webp

BIN
src/assets/img/ceremony/hb.png

After

Width: 256  |  Height: 256  |  Size: 2.2 KiB

BIN
src/assets/img/ceremony/sd.png

After

Width: 256  |  Height: 256  |  Size: 4.6 KiB

BIN
src/assets/img/ceremony/xc.png

After

Width: 256  |  Height: 256  |  Size: 4.8 KiB

BIN
src/assets/img/ceremony/yd.png

After

Width: 256  |  Height: 256  |  Size: 4.5 KiB

BIN
src/assets/img/common/logo.webp

BIN
src/assets/img/cover/img1.webp

BIN
src/assets/img/cover/img10.webp

BIN
src/assets/img/cover/img2.webp

BIN
src/assets/img/cover/img3.webp

BIN
src/assets/img/cover/img4.webp

BIN
src/assets/img/cover/img5.webp

BIN
src/assets/img/cover/img6.webp

BIN
src/assets/img/cover/img7.webp

BIN
src/assets/img/cover/img8.webp

BIN
src/assets/img/cover/img9.webp

BIN
src/assets/img/draw/draw1.png

After

Width: 452  |  Height: 353  |  Size: 11 KiB

BIN
src/assets/img/favicon.ico

BIN
src/assets/img/lock/lock_screen_1.webp

BIN
src/assets/img/login/lf_bg.webp

BIN
src/assets/img/login/lf_icon1.webp

BIN
src/assets/img/login/lf_icon2.webp

BIN
src/assets/img/safeguard/server.png

After

Width: 256  |  Height: 256  |  Size: 2.1 KiB

BIN
src/assets/img/settings/menu_layouts/dual_column.png

After

Width: 220  |  Height: 146  |  Size: 514 B

BIN
src/assets/img/settings/menu_layouts/horizontal.png

After

Width: 220  |  Height: 146  |  Size: 409 B

BIN
src/assets/img/settings/menu_layouts/mixed.png

After

Width: 220  |  Height: 146  |  Size: 431 B

BIN
src/assets/img/settings/menu_layouts/vertical.png

After

Width: 220  |  Height: 146  |  Size: 439 B

BIN
src/assets/img/settings/menu_styles/dark.png

After

Width: 220  |  Height: 146  |  Size: 292 B

BIN
src/assets/img/settings/menu_styles/design.png

After

Width: 220  |  Height: 146  |  Size: 286 B

BIN
src/assets/img/settings/menu_styles/light.png

After

Width: 220  |  Height: 146  |  Size: 293 B

BIN
src/assets/img/settings/theme_styles/dark.png

After

Width: 220  |  Height: 146  |  Size: 448 B

BIN
src/assets/img/settings/theme_styles/light.png

After

Width: 220  |  Height: 146  |  Size: 416 B

BIN
src/assets/img/settings/theme_styles/system.png

After

Width: 220  |  Height: 146  |  Size: 509 B

BIN
src/assets/img/state/403.png

After

Width: 1024  |  Height: 1024  |  Size: 17 KiB

BIN
src/assets/img/state/404.png

After

Width: 1024  |  Height: 1024  |  Size: 17 KiB

BIN
src/assets/img/state/500.png

After

Width: 1024  |  Height: 1024  |  Size: 17 KiB

BIN
src/assets/img/user/avatar.webp

BIN
src/assets/img/user/bg.webp

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save