Merge branch 'develop'
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# 【通用】环境变量
|
||||
|
||||
# 版本号
|
||||
VITE_VERSION = 2.4.2.4
|
||||
# 端口号
|
||||
VITE_PORT = 3006
|
||||
|
||||
# 网站地址前缀
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# API 地址前缀
|
||||
# VITE_API_URL = https://mzl.dev.hnxinyouhe.com
|
||||
VITE_API_URL = https://x-server.hnxinyouhe.com
|
||||
|
||||
# 权限模式( frontend | backend )
|
||||
VITE_ACCESS_MODE = frontend
|
||||
|
||||
# 是否打开路由信息
|
||||
VITE_OPEN_ROUTE_INFO = false
|
||||
|
||||
# 锁屏加密密钥
|
||||
VITE_LOCK_ENCRYPT_KEY = jfsfjk1938jfj
|
||||
@@ -0,0 +1,15 @@
|
||||
# 【开发】环境变量
|
||||
|
||||
# 网站地址前缀
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# API 地址前缀
|
||||
# VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
|
||||
# VITE_API_URL = http://219.157.255.213:25702
|
||||
# VITE_API_URL = https://mzl.dev.hnxinyouhe.com
|
||||
# VITE_API_URL = https://fdesk.hnxinyouhe.com
|
||||
VITE_API_URL = https://x-server.hnxinyouhe.com
|
||||
|
||||
|
||||
# Delete console
|
||||
VITE_DROP_CONSOLE = false
|
||||
@@ -0,0 +1,11 @@
|
||||
# 【生产】环境变量
|
||||
|
||||
# 网站地址前缀
|
||||
VITE_BASE_URL = /
|
||||
|
||||
# API 地址前缀
|
||||
# VITE_API_URL = https://fdesk.hnxinyouhe.com
|
||||
VITE_API_URL = https://x-server.hnxinyouhe.com
|
||||
|
||||
# Delete console
|
||||
VITE_DROP_CONSOLE = true
|
||||
@@ -0,0 +1,2 @@
|
||||
*.html linguist-detectable=false
|
||||
*.vue linguist-detectable=true
|
||||
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.cursorrules
|
||||
@@ -0,0 +1 @@
|
||||
pnpm dlx commitlint --edit $1
|
||||
@@ -0,0 +1 @@
|
||||
pnpm run lint:lint-staged
|
||||
@@ -0,0 +1,3 @@
|
||||
/node_modules/*
|
||||
/dist/*
|
||||
/src/main.ts
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
dist
|
||||
node_modules
|
||||
public
|
||||
.husky
|
||||
.vscode
|
||||
|
||||
src/components/Layout/MenuLeft/index.vue
|
||||
src/assets
|
||||
stats.html
|
||||
@@ -0,0 +1,62 @@
|
||||
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, // 允许空样式
|
||||
// 允许 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'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<html>
|
||||
<head><title>404 Not Found</title></head>
|
||||
<body>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>nginx</center>
|
||||
</body>
|
||||
@@ -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.
|
||||
@@ -0,0 +1,77 @@
|
||||
# 菜单权限控制问题修复方案
|
||||
|
||||
## 问题描述
|
||||
|
||||
在后端控制模式下,当普通用户登录后再退出登录管理员时,管理员特有的菜单会出现404错误。
|
||||
|
||||
## 问题原因
|
||||
|
||||
1. **路由注册状态未正确重置**:`isRouteRegistered` 标志位在用户切换时没有正确重置
|
||||
2. **动态路由清理不完整**:`resetRouterState` 函数只清理了带有 `meta.dynamic` 标记的路由
|
||||
3. **工作台标签页验证时机问题**:`validateWorktabs` 在路由重新注册后执行,但可能没有正确清理无效的标签页
|
||||
4. **用户信息变化检测缺失**:没有检测用户切换事件,导致路由状态没有及时更新
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 改进路由状态重置 (`src/router/guards/beforeEach.ts`)
|
||||
|
||||
- 修改 `resetRouterState` 函数,清理所有动态注册的路由(不仅仅是带有dynamic标记的)
|
||||
- 添加工作台标签页的清理
|
||||
- 使用菜单store的 `clearMenuList` 方法
|
||||
|
||||
### 2. 添加用户切换检测 (`src/router/guards/beforeEach.ts`)
|
||||
|
||||
- 在 `handleRouteGuard` 函数中添加用户信息变化检测
|
||||
- 使用 `sessionStorage` 缓存用户信息,检测用户切换
|
||||
- 当检测到用户信息变化时,强制重置路由状态
|
||||
|
||||
### 3. 改进菜单API (`src/api/menuApi.ts`)
|
||||
|
||||
- 添加用户登录状态验证
|
||||
- 改进菜单数据验证逻辑
|
||||
- 添加更详细的错误处理和日志
|
||||
|
||||
### 4. 完善用户登出逻辑 (`src/store/modules/user.ts`)
|
||||
|
||||
- 在 `logOut` 方法中添加更完整的状态清理
|
||||
- 清理用户信息缓存
|
||||
- 确保工作台标签页被正确清理
|
||||
|
||||
### 5. 增强菜单Store (`src/store/modules/menu.ts`)
|
||||
|
||||
- 添加 `clearMenuList` 方法用于清理菜单数据
|
||||
- 提供更完整的状态管理
|
||||
|
||||
### 6. 改进错误处理 (`src/router/guards/beforeEach.ts`)
|
||||
|
||||
- 修改 `handleMenuError` 函数,确保在菜单处理失败时正确清理所有状态
|
||||
- 添加更详细的状态清理逻辑
|
||||
|
||||
## 测试工具
|
||||
|
||||
创建了 `src/utils/menuPermissionTest.ts` 测试工具,包含:
|
||||
|
||||
- `testMenuPermissionSwitch()`: 测试菜单权限切换的正确性
|
||||
- `simulateUserSwitch()`: 模拟用户切换过程
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 在浏览器控制台中调用 `testMenuPermissionSwitch()` 检查当前状态
|
||||
2. 在用户切换后调用 `simulateUserSwitch()` 模拟切换过程
|
||||
3. 观察控制台输出,确认路由和菜单状态正确
|
||||
|
||||
## 预期效果
|
||||
|
||||
修复后,当用户切换时:
|
||||
|
||||
1. 所有动态路由会被正确清理
|
||||
2. 菜单数据会被重新加载
|
||||
3. 工作台标签页会被验证和清理
|
||||
4. 不会出现404错误
|
||||
5. 用户权限会正确应用
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 确保后端返回的菜单数据与用户权限匹配
|
||||
- 在开发环境中可以使用测试工具验证修复效果
|
||||
- 建议在生产环境中添加更多的日志记录用于问题排查
|
||||
@@ -0,0 +1,79 @@
|
||||
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.
|
||||
|
||||
## Demo Images
|
||||
|
||||
### Light Theme
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Dark Theme
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 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!
|
||||
|
||||

|
||||
@@ -0,0 +1,84 @@
|
||||
简体中文 | [English](./README.md)
|
||||
|
||||
## 关于 Art Design Pro
|
||||
|
||||
作为一名开发者,我在多个项目中需要搭建后台管理系统,但发现传统系统在用户体验和视觉设计上不能完全满足需求。因此,我创建了 Art Design Pro,一款专注于用户体验和快速开发的开源后台管理解决方案。基于 ElementPlus 设计规范,进行了视觉上的精心优化,提供更美观、更实用的前端界面,帮助你轻松构建高质量的后台系统。
|
||||
|
||||
## 演示图
|
||||
|
||||
### 浅色主题
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 暗黑主题
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 特点
|
||||
|
||||
- 使用最新技术栈
|
||||
- 内置常用业务组件模版
|
||||
- 提供多种主题模式,可以自定义主题
|
||||
- 漂亮的 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 等工具,以提升开发效率,让项目变得更好。感谢你的鼓励与支持!
|
||||
|
||||

|
||||
@@ -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: ''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ArtBackToTop: typeof import('./src/components/core/base/ArtBackToTop.vue')['default']
|
||||
ArtBarChart: typeof import('./src/components/core/charts/ArtBarChart.vue')['default']
|
||||
ArtBarChartCard: typeof import('./src/components/core/cards/ArtBarChartCard.vue')['default']
|
||||
ArtBasicBanner: typeof import('./src/components/core/banners/ArtBasicBanner.vue')['default']
|
||||
ArtBreadcrumb: typeof import('./src/components/core/layouts/art-breadcrumb/index.vue')['default']
|
||||
ArtButtonMore: typeof import('./src/components/core/forms/ArtButtonMore.vue')['default']
|
||||
ArtButtonTable: typeof import('./src/components/core/forms/ArtButtonTable.vue')['default']
|
||||
ArtCardBanner: typeof import('./src/components/core/banners/ArtCardBanner.vue')['default']
|
||||
ArtChatWindow: typeof import('./src/components/core/layouts/art-chat-window/index.vue')['default']
|
||||
ArtCutterImg: typeof import('./src/components/core/media/ArtCutterImg.vue')['default']
|
||||
ArtDataListCard: typeof import('./src/components/core/cards/ArtDataListCard.vue')['default']
|
||||
ArtDonutChartCard: typeof import('./src/components/core/cards/ArtDonutChartCard.vue')['default']
|
||||
ArtDragVerify: typeof import('./src/components/core/forms/ArtDragVerify.vue')['default']
|
||||
ArtDualBarCompareChart: typeof import('./src/components/core/charts/ArtDualBarCompareChart.vue')['default']
|
||||
ArtExcelExport: typeof import('./src/components/core/forms/ArtExcelExport.vue')['default']
|
||||
ArtExcelImport: typeof import('./src/components/core/forms/ArtExcelImport.vue')['default']
|
||||
ArtException: typeof import('./src/components/core/views/exception/ArtException.vue')['default']
|
||||
ArtFastEnter: typeof import('./src/components/core/layouts/art-fast-enter/index.vue')['default']
|
||||
ArtFestivalTextScroll: typeof import('./src/components/core/text-effect/ArtFestivalTextScroll.vue')['default']
|
||||
ArtFireworksEffect: typeof import('./src/components/core/layouts/art-fireworks-effect/index.vue')['default']
|
||||
ArtFormInput: typeof import('./src/components/core/forms/ArtFormInput.vue')['default']
|
||||
ArtFormSelect: typeof import('./src/components/core/forms/ArtFormSelect.vue')['default']
|
||||
ArtGlobalSearch: typeof import('./src/components/core/layouts/art-global-search/index.vue')['default']
|
||||
ArtHBarChart: typeof import('./src/components/core/charts/ArtHBarChart.vue')['default']
|
||||
ArtHeaderBar: typeof import('./src/components/core/layouts/art-header-bar/index.vue')['default']
|
||||
ArtHorizontalMenu: typeof import('./src/components/core/layouts/art-menus/art-horizontal-menu/index.vue')['default']
|
||||
ArtIconSelector: typeof import('./src/components/core/base/ArtIconSelector.vue')['default']
|
||||
ArtImageCard: typeof import('./src/components/core/cards/ArtImageCard.vue')['default']
|
||||
ArtKLineChart: typeof import('./src/components/core/charts/ArtKLineChart.vue')['default']
|
||||
ArtLineChart: typeof import('./src/components/core/charts/ArtLineChart.vue')['default']
|
||||
ArtLineChartCard: typeof import('./src/components/core/cards/ArtLineChartCard.vue')['default']
|
||||
ArtMapChart: typeof import('./src/components/core/charts/ArtMapChart.vue')['default']
|
||||
ArtMenuRight: typeof import('./src/components/core/others/ArtMenuRight.vue')['default']
|
||||
ArtMixedMenu: typeof import('./src/components/core/layouts/art-menus/art-mixed-menu/index.vue')['default']
|
||||
ArtNetwork: typeof import('./src/components/core/base/ArtNetwork.vue')['default']
|
||||
ArtNotification: typeof import('./src/components/core/layouts/art-notification/index.vue')['default']
|
||||
ArtPageContent: typeof import('./src/components/core/layouts/art-page-content/index.vue')['default']
|
||||
ArtProgressCard: typeof import('./src/components/core/cards/ArtProgressCard.vue')['default']
|
||||
ArtRadarChart: typeof import('./src/components/core/charts/ArtRadarChart.vue')['default']
|
||||
ArtRingChart: typeof import('./src/components/core/charts/ArtRingChart.vue')['default']
|
||||
ArtScatterChart: typeof import('./src/components/core/charts/ArtScatterChart.vue')['default']
|
||||
ArtScreenLock: typeof import('./src/components/core/layouts/art-screen-lock/index.vue')['default']
|
||||
ArtSettingsPanel: typeof import('./src/components/core/layouts/art-settings-panel/index.vue')['default']
|
||||
ArtSidebarMenu: typeof import('./src/components/core/layouts/art-menus/art-sidebar-menu/index.vue')['default']
|
||||
ArtStatsCard: typeof import('./src/components/core/cards/ArtStatsCard.vue')['default']
|
||||
ArtTable: typeof import('./src/components/core/tables/ArtTable.vue')['default']
|
||||
ArtTableBar: typeof import('./src/components/core/tables/ArtTableBar.vue')['default']
|
||||
ArtTextScroll: typeof import('./src/components/core/text-effect/ArtTextScroll.vue')['default']
|
||||
ArtTimelineListCard: typeof import('./src/components/core/cards/ArtTimelineListCard.vue')['default']
|
||||
ArtVideoPlayer: typeof import('./src/components/core/media/ArtVideoPlayer.vue')['default']
|
||||
ArtWangEditor: typeof import('./src/components/core/forms/ArtWangEditor.vue')['default']
|
||||
ArtWatermark: typeof import('./src/components/core/others/ArtWatermark.vue')['default']
|
||||
ArtWorkTab: typeof import('./src/components/core/layouts/art-work-tab/index.vue')['default']
|
||||
BannerWidget: typeof import('./src/components/core/BannerWidget.vue')['default']
|
||||
HorizontalSubmenu: typeof import('./src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue')['default']
|
||||
LoginLeftView: typeof import('./src/components/core/views/login/LoginLeftView.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SidebarSubmenu: typeof import('./src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default']
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// 从 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
|
||||
}
|
||||
},
|
||||
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
|
||||
]
|
||||
@@ -1,35 +1,15 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<title>恭喜,站点创建成功!</title>
|
||||
<style>
|
||||
.container {
|
||||
width: 60%;
|
||||
margin: 10% auto 0;
|
||||
background-color: #f0f0f0;
|
||||
padding: 2% 5%;
|
||||
border-radius: 10px
|
||||
}
|
||||
<head>
|
||||
<title>系统管理</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="src/assets/img/favicon.ico" />
|
||||
</head>
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
line-height: 2.3
|
||||
}
|
||||
|
||||
a {
|
||||
color: #20a53a
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>恭喜, 站点创建成功!</h1>
|
||||
<h3>这是默认index.html,本页面由系统自动生成</h3>
|
||||
</div>
|
||||
</body>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<script src="https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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]
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"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.4.0",
|
||||
"element-plus": "^2.8.0",
|
||||
"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",
|
||||
"vue3-count-to": "^1.1.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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,61 @@
|
||||
<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)
|
||||
function setCompanyFromUrl() {
|
||||
const userStore = useUserStore()
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const companyid = params.get('corp_id')
|
||||
const companyabbr = params.get('corp_abbr')
|
||||
if (companyid) {
|
||||
userStore.setCompany(companyid, companyabbr || '')
|
||||
// 你也可以加 localStorage/sessionStorage 备份
|
||||
}
|
||||
}
|
||||
const locales = {
|
||||
zh: zh,
|
||||
en: en
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
setThemeTransitionClass(true)
|
||||
setCompanyFromUrl()
|
||||
useUserStore().restoreTokenTimer()
|
||||
})
|
||||
|
||||
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>
|
||||
@@ -0,0 +1,10 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export class BrandService {
|
||||
// 获取品牌
|
||||
static getBrandInfo() {
|
||||
return request.get<Api.Brand.BrandInfo>({
|
||||
url: '/console/brand/preset'
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { asyncRoutes } from '@/router/routes/asyncRoutes'
|
||||
import { menuDataToRouter } from '@/router/utils/menuToRouter'
|
||||
import { AppRouteRecord } from '@/types/router'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
interface MenuResponse {
|
||||
menuList: AppRouteRecord[]
|
||||
}
|
||||
|
||||
// 菜单接口
|
||||
export const menuService = {
|
||||
async getMenuList(delay = 300): Promise<MenuResponse> {
|
||||
try {
|
||||
const userStore = useUserStore()
|
||||
// 验证用户登录状态
|
||||
if (!userStore.isLogin) {
|
||||
throw new Error('用户未登录')
|
||||
}
|
||||
// 模拟接口返回的菜单数据
|
||||
const menuData = userStore.info.menu
|
||||
// 验证菜单数据
|
||||
if (!menuData || !Array.isArray(menuData) || menuData.length === 0) {
|
||||
ElMessage.error('暂无系统菜单权限')
|
||||
return { menuList: [] }
|
||||
}
|
||||
|
||||
// 处理菜单数据
|
||||
const menuList = menuData.map((route: any) => menuDataToRouter(route))
|
||||
|
||||
// 验证处理后的菜单列表
|
||||
if (!menuList || menuList.length === 0) {
|
||||
ElMessage.error('菜单数据处理失败')
|
||||
return { menuList: [] }
|
||||
}
|
||||
|
||||
// 模拟接口延迟
|
||||
await new Promise((resolve) => setTimeout(resolve, delay))
|
||||
|
||||
return { menuList }
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取菜单失败:', error)
|
||||
throw error instanceof Error ? error : new Error('获取菜单失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export class UserService {
|
||||
//获取公司
|
||||
static getCompanyList() {
|
||||
return request.get<Api.Brand.BrandInfo>({
|
||||
url: '/common/preset/corps'
|
||||
})
|
||||
}
|
||||
//注册
|
||||
static register(params: any) {
|
||||
return request.post<Api.Auth.registerResponse>({
|
||||
url: '/common/auth/register',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//获取 飞书信息
|
||||
static getfeishuAppList(params: { corp_id: string }) {
|
||||
return request.get<Api.Brand.BrandInfo>({
|
||||
url: '/common/preset/feishu/app',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 登录
|
||||
static login(params: Api.Auth.LoginParams) {
|
||||
return request.post<Api.Auth.LoginResponse>({
|
||||
url: '/common/auth/login',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
// 刷新token
|
||||
static refreshToken(params: { refresh_token: string }) {
|
||||
return request.post<any>({
|
||||
url: '/common/auth/refresh/token',
|
||||
params
|
||||
})
|
||||
}
|
||||
//飞书凭证
|
||||
static getfeishuscope() {
|
||||
return request.get<Api.Auth.Authfeishuscope>({
|
||||
url: '/common/auth/feishu/scope'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
static getUserInfo() {
|
||||
return request.get<Api.User.UserInfo>({
|
||||
url: '/common/user/info'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
static getUserList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.User.UserListData>({
|
||||
url: '/api/user/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
//角色 列表
|
||||
static getRoleList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.Role.RoleListData>({
|
||||
url: '/admin/role/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export class WorkService {
|
||||
// 获取工单列表
|
||||
static getWorkList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.Work.WorkListData>({
|
||||
url: '/ticket/ticket/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 获取我的工单列表
|
||||
static getWorkselfList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.Work.WorkListData>({
|
||||
url: '/ticket/ticket/self',
|
||||
params
|
||||
})
|
||||
}
|
||||
//添加工单
|
||||
static WorkAdd(params: Api.Work.AddParams) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/ticket/add',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//工单修改 ticket/categorie/edit
|
||||
static Workedit(params:any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/ticket/edit',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//修改工单状态
|
||||
static Workstatus(params: Api.Work.StatusParams) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/ticket/status',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//工单状态下拉选择框
|
||||
static getStatus() {
|
||||
return request.get<Api.Brand.BrandInfo>({
|
||||
url: '/ticket/ticket/getStatus'
|
||||
})
|
||||
}
|
||||
//工单沟通记录
|
||||
static getconversationList(params: any) {
|
||||
return request.get<Api.Work.WorkListData>({
|
||||
url: '/ticket/conversation/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
//添加工单记录 ticket/conversation/add
|
||||
static conversationAdd(params:any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/conversation/add',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//工单分类 添加
|
||||
static WorkcategorieAdd(params:any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/categorie/add',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//工单分类 列表
|
||||
static getCategorieList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.Work.CategorieListData>({
|
||||
url: '/ticket/categorie/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
//工单分类修改 ticket/categorie/edit
|
||||
static Workcategorieedit(params:any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/categorie/edit',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//工单分类下拉
|
||||
static getcategorieselect() {
|
||||
return request.get<Api.Brand.BrandInfo>({
|
||||
url: '/ticket/categorie/getAll'
|
||||
})
|
||||
}
|
||||
//工单分类删除
|
||||
static Workcategoriedelete(params:any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/ticket/categorie/delete',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 954 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 726 B |
|
After Width: | Height: | Size: 944 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 810 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 514 B |
|
After Width: | Height: | Size: 409 B |
|
After Width: | Height: | Size: 431 B |
|
After Width: | Height: | Size: 439 B |
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 448 B |
|
After Width: | Height: | Size: 416 B |
|
After Width: | Height: | Size: 509 B |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,171 @@
|
||||
// 全局样式
|
||||
|
||||
@font-face {
|
||||
font-family: 'DMSans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(../fonts/DMSans.woff2) format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(../fonts/Montserrat.woff2) format('woff2');
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.el-btn-red {
|
||||
color: #fa6962 !important;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
// 顶部进度条颜色
|
||||
#nprogress .bar {
|
||||
background-color: color-mix(in srgb, var(--main-color) 65%, white);
|
||||
}
|
||||
|
||||
// 处理移动端组件兼容性
|
||||
@media screen and (max-width: $device-phone) {
|
||||
* {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.el-col2 {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// 背景滤镜
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
// 色弱模式
|
||||
.color-weak {
|
||||
filter: invert(80%);
|
||||
-webkit-filter: invert(80%);
|
||||
}
|
||||
|
||||
#noop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 语言切换选中样式
|
||||
.langDropDownStyle {
|
||||
// 选中项背景颜色
|
||||
.is-selected {
|
||||
background-color: rgba(var(--art-gray-200-rgb), 0.8) !important;
|
||||
}
|
||||
|
||||
// 语言切换按钮菜单样式优化
|
||||
.lang-btn-item {
|
||||
.el-dropdown-menu__item {
|
||||
padding-left: 13px !important;
|
||||
padding-right: 6px !important;
|
||||
margin-bottom: 3px !important;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.el-dropdown-menu__item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-txt {
|
||||
min-width: 60px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 盒子默认边框
|
||||
.page-content,
|
||||
.art-custom-card {
|
||||
border: 1px solid var(--art-card-border) !important;
|
||||
}
|
||||
|
||||
// 盒子边框
|
||||
[data-box-mode='border-mode'] {
|
||||
.page-content,
|
||||
.art-custom-card,
|
||||
.art-table-card {
|
||||
border: 1px solid var(--art-card-border) !important;
|
||||
}
|
||||
|
||||
.layout-sidebar {
|
||||
border-right: 1px solid var(--art-card-border) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 盒子阴影
|
||||
[data-box-mode='shadow-mode'] {
|
||||
.page-content,
|
||||
.art-custom-card,
|
||||
.art-table-card {
|
||||
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.04) !important;
|
||||
border: 1px solid rgba(var(--art-gray-300-rgb), 0.3) !important;
|
||||
}
|
||||
|
||||
.layout-sidebar {
|
||||
border-right: 1px solid rgba(var(--art-gray-300-rgb), 0.4) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 元素全屏
|
||||
.el-full-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
z-index: 500;
|
||||
margin-top: 0;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--art-main-bg-color);
|
||||
|
||||
.art-table-full-screen {
|
||||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 表格卡片
|
||||
.art-table-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 15px;
|
||||
border-radius: calc(var(--custom-radius) / 2 + 2px) !important;
|
||||
|
||||
.el-card__body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// 主题切换过渡优化,去除不适感
|
||||
.theme-change {
|
||||
* {
|
||||
transition: 0s !important;
|
||||
}
|
||||
|
||||
.el-switch__core,
|
||||
.el-switch__action {
|
||||
transition: all 0.3s !important;
|
||||
}
|
||||
}
|
||||