@ -0,0 +1,14 @@ |
|||||
|
# http://editorconfig.org |
||||
|
root = true |
||||
|
|
||||
|
# 表示所有文件适用 |
||||
|
[*] |
||||
|
charset = utf-8 # 设置文件字符集为 utf-8 |
||||
|
end_of_line = lf # 控制换行类型(lf | cr | crlf) |
||||
|
indent_style = tab # 缩进风格(tab | space) |
||||
|
insert_final_newline = true # 始终在文件末尾插入一个新行 |
||||
|
|
||||
|
# 表示仅 md 文件适用以下规则 |
||||
|
[*.md] |
||||
|
max_line_length = off # 关闭最大行长度限制 |
||||
|
trim_trailing_whitespace = false # 关闭末尾空格修剪 |
||||
@ -0,0 +1,8 @@ |
|||||
|
## 开发环境 |
||||
|
|
||||
|
# 变量必须以 VITE_ 为前缀才能暴露给外部读取 |
||||
|
NODE_ENV='development' |
||||
|
|
||||
|
VITE_APP_TITLE = 'vue3-element-admin' |
||||
|
VITE_APP_PORT = 3000 |
||||
|
VITE_APP_BASE_API = '/dev-api' |
||||
@ -0,0 +1,5 @@ |
|||||
|
## 生产环境 |
||||
|
|
||||
|
VITE_APP_TITLE = 'vue3-element-admin' |
||||
|
VITE_APP_PORT = 3000 |
||||
|
VITE_APP_BASE_API = '/prod-api' |
||||
@ -0,0 +1,6 @@ |
|||||
|
## 模拟环境 |
||||
|
NODE_ENV='staging' |
||||
|
|
||||
|
VITE_APP_TITLE = 'vue3-element-admin' |
||||
|
VITE_APP_PORT = 3000 |
||||
|
VITE_APP_BASE_API = '/prod--api' |
||||
@ -0,0 +1,14 @@ |
|||||
|
dist |
||||
|
node_modules |
||||
|
public |
||||
|
.husky |
||||
|
.vscode |
||||
|
.idea |
||||
|
*.sh |
||||
|
*.md |
||||
|
|
||||
|
src/assets |
||||
|
|
||||
|
.eslintrc.cjs |
||||
|
.prettierrc.cjs |
||||
|
.stylelintrc.cjs |
||||
@ -0,0 +1,269 @@ |
|||||
|
{ |
||||
|
"globals": { |
||||
|
"EffectScope": true, |
||||
|
"ElForm": true, |
||||
|
"ElMessage": true, |
||||
|
"ElMessageBox": true, |
||||
|
"ElTree": 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, |
||||
|
"createReactiveFn": true, |
||||
|
"createSharedComposable": true, |
||||
|
"createUnrefFn": true, |
||||
|
"customRef": true, |
||||
|
"debouncedRef": true, |
||||
|
"debouncedWatch": true, |
||||
|
"defineAsyncComponent": true, |
||||
|
"defineComponent": true, |
||||
|
"eagerComputed": true, |
||||
|
"effectScope": true, |
||||
|
"extendRef": true, |
||||
|
"getCurrentInstance": true, |
||||
|
"getCurrentScope": true, |
||||
|
"h": true, |
||||
|
"ignorableWatch": true, |
||||
|
"inject": true, |
||||
|
"isDefined": true, |
||||
|
"isProxy": true, |
||||
|
"isReactive": true, |
||||
|
"isReadonly": true, |
||||
|
"isRef": true, |
||||
|
"makeDestructurable": true, |
||||
|
"markRaw": true, |
||||
|
"nextTick": true, |
||||
|
"onActivated": true, |
||||
|
"onBeforeMount": 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, |
||||
|
"pausableWatch": true, |
||||
|
"provide": 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, |
||||
|
"resolveDirective": true, |
||||
|
"resolveRef": true, |
||||
|
"resolveUnref": true, |
||||
|
"shallowReactive": true, |
||||
|
"shallowReadonly": true, |
||||
|
"shallowRef": true, |
||||
|
"syncRef": true, |
||||
|
"syncRefs": true, |
||||
|
"templateRef": true, |
||||
|
"throttledRef": true, |
||||
|
"throttledWatch": true, |
||||
|
"toRaw": true, |
||||
|
"toReactive": true, |
||||
|
"toRef": true, |
||||
|
"toRefs": true, |
||||
|
"triggerRef": true, |
||||
|
"tryOnBeforeMount": true, |
||||
|
"tryOnBeforeUnmount": true, |
||||
|
"tryOnMounted": true, |
||||
|
"tryOnScopeDispose": true, |
||||
|
"tryOnUnmounted": true, |
||||
|
"unref": true, |
||||
|
"unrefElement": true, |
||||
|
"until": true, |
||||
|
"useActiveElement": true, |
||||
|
"useArrayEvery": true, |
||||
|
"useArrayFilter": true, |
||||
|
"useArrayFind": true, |
||||
|
"useArrayFindIndex": true, |
||||
|
"useArrayFindLast": 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, |
||||
|
"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, |
||||
|
"useIdle": true, |
||||
|
"useImage": true, |
||||
|
"useInfiniteScroll": true, |
||||
|
"useIntersectionObserver": true, |
||||
|
"useInterval": true, |
||||
|
"useIntervalFn": true, |
||||
|
"useKeyModifier": true, |
||||
|
"useLastChanged": true, |
||||
|
"useLocalStorage": true, |
||||
|
"useMagicKeys": true, |
||||
|
"useManualRefHistory": true, |
||||
|
"useMediaControls": true, |
||||
|
"useMediaQuery": true, |
||||
|
"useMemoize": true, |
||||
|
"useMemory": 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, |
||||
|
"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, |
||||
|
"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, |
||||
|
"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, |
||||
|
"watchEffect": true, |
||||
|
"watchIgnorable": true, |
||||
|
"watchOnce": true, |
||||
|
"watchPausable": true, |
||||
|
"watchPostEffect": true, |
||||
|
"watchSyncEffect": true, |
||||
|
"watchThrottled": true, |
||||
|
"watchTriggerable": true, |
||||
|
"watchWithFilter": true, |
||||
|
"whenever": true |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
module.exports = { |
||||
|
env: { |
||||
|
browser: true, |
||||
|
es2021: true, |
||||
|
node: true, |
||||
|
}, |
||||
|
parser: "vue-eslint-parser", |
||||
|
extends: [ |
||||
|
// 参考vuejs官方的eslint配置: https://eslint.vuejs.org/user-guide/#usage |
||||
|
"plugin:vue/vue3-recommended", |
||||
|
"./.eslintrc-auto-import.json", |
||||
|
"prettier", |
||||
|
], |
||||
|
parserOptions: { |
||||
|
ecmaVersion: "latest", |
||||
|
sourceType: "module", |
||||
|
parser: "@typescript-eslint/parser", |
||||
|
}, |
||||
|
plugins: ["vue", "@typescript-eslint"], |
||||
|
rules: { |
||||
|
"vue/multi-word-component-names": "off", // 关闭组件名必须多字: https://eslint.vuejs.org/rules/multi-word-component-names.html |
||||
|
"@typescript-eslint/no-empty-function": "off", // 关闭空方法检查 |
||||
|
"@typescript-eslint/no-explicit-any": "off", // 关闭any类型的警告 |
||||
|
"vue/no-v-model-argument": "off", |
||||
|
"@typescript-eslint/no-non-null-assertion": "off", |
||||
|
}, |
||||
|
// https://eslint.org/docs/latest/use/configure/language-options#specifying-globals |
||||
|
globals: { |
||||
|
DialogOption: "readonly", |
||||
|
OptionType: "readonly", |
||||
|
}, |
||||
|
}; |
||||
@ -0,0 +1,17 @@ |
|||||
|
node_modules |
||||
|
.DS_Store |
||||
|
dist |
||||
|
dist-ssr |
||||
|
*.local |
||||
|
|
||||
|
# Editor directories and files |
||||
|
.idea |
||||
|
.vscode |
||||
|
*.suo |
||||
|
*.ntvs* |
||||
|
*.njsproj |
||||
|
*.sln |
||||
|
*.local |
||||
|
|
||||
|
package-lock.json |
||||
|
pnpm-lock.yaml |
||||
@ -0,0 +1,4 @@ |
|||||
|
#!/bin/sh |
||||
|
. "$(dirname "$0")/_/husky.sh" |
||||
|
|
||||
|
npx --no-install commitlint --edit $1 |
||||
@ -0,0 +1,4 @@ |
|||||
|
#!/bin/sh |
||||
|
. "$(dirname "$0")/_/husky.sh" |
||||
|
|
||||
|
npm run lint:lint-staged |
||||
@ -0,0 +1,10 @@ |
|||||
|
dist |
||||
|
node_modules |
||||
|
public |
||||
|
.husky |
||||
|
.vscode |
||||
|
.idea |
||||
|
*.sh |
||||
|
*.md |
||||
|
|
||||
|
src/assets |
||||
@ -0,0 +1,36 @@ |
|||||
|
module.exports = { |
||||
|
// (x)=>{},单个参数箭头函数是否显示小括号。(always:始终显示;avoid:省略括号。默认:always) |
||||
|
arrowParens: "always", |
||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false |
||||
|
bracketSameLine: false, |
||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) |
||||
|
bracketSpacing: true, |
||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) |
||||
|
embeddedLanguageFormatting: "auto", |
||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) |
||||
|
htmlWhitespaceSensitivity: "css", |
||||
|
// 当文件已经被 Prettier 格式化之后,是否会在文件顶部插入一个特殊的 @format 标记,默认false |
||||
|
insertPragma: false, |
||||
|
// 在 JSX 中使用单引号替代双引号,默认false |
||||
|
jsxSingleQuote: false, |
||||
|
// 每行最多字符数量,超出换行(默认80) |
||||
|
printWidth: 80, |
||||
|
// 超出打印宽度 (always | never | preserve ) |
||||
|
proseWrap: "preserve", |
||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) |
||||
|
quoteProps: "as-needed", |
||||
|
// 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件,默认false |
||||
|
requirePragma: false, |
||||
|
// 结尾添加分号 |
||||
|
semi: true, |
||||
|
// 使用单引号 (true:单引号;false:双引号) |
||||
|
singleQuote: false, |
||||
|
// 缩进空格数,默认2个空格 |
||||
|
tabWidth: 2, |
||||
|
// 元素末尾是否加逗号,默认es5: ES5中的 objects, arrays 等会添加逗号,TypeScript 中的 type 后不加逗号 |
||||
|
trailingComma: "es5", |
||||
|
// 指定缩进方式,空格或tab,默认false,即使用空格 |
||||
|
useTabs: false, |
||||
|
// vue 文件中是否缩进 <style> 和 <script> 标签,默认 false |
||||
|
vueIndentScriptAndStyle: false, |
||||
|
}; |
||||
@ -0,0 +1,10 @@ |
|||||
|
dist |
||||
|
node_modules |
||||
|
public |
||||
|
.husky |
||||
|
.vscode |
||||
|
.idea |
||||
|
*.sh |
||||
|
*.md |
||||
|
|
||||
|
src/assets |
||||
@ -0,0 +1,43 @@ |
|||||
|
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, // 允许无降序特异性 |
||||
|
// 允许 global 、export 、deep伪类 |
||||
|
"selector-pseudo-class-no-unknown": [ |
||||
|
true, |
||||
|
{ |
||||
|
ignorePseudoClasses: ["global", "export", "deep"], |
||||
|
}, |
||||
|
], |
||||
|
// 允许未知属性 |
||||
|
"property-no-unknown": [ |
||||
|
true, |
||||
|
{ |
||||
|
ignoreProperties: ["menuBg", "menuText", "menuActiveText"], |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
@ -0,0 +1,20 @@ |
|||||
|
# 2.3.0 (2023/5/12) |
||||
|
|
||||
|
### 📦️ build |
||||
|
- vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md)) |
||||
|
- vite 版本升级 4.3.1 → 4.3.5 |
||||
|
|
||||
|
### ♻️ refactor |
||||
|
- 使用 vue 3.3 版本新特性 `defineOptions` 在 `setup` 定义组件名称,移除重复的 `script` 标签 |
||||
|
|
||||
|
# 2.2.2 (2023/5/11) |
||||
|
|
||||
|
### ✨ feat |
||||
|
- 用户新增提交添加 `vueUse` 的 `useDebounceFn` 函数实现按钮防抖节流 |
||||
|
|
||||
|
|
||||
|
# 2.2.1 (2023/4/25) |
||||
|
|
||||
|
### 🐛 fix |
||||
|
- 图标选择器组件使用 `onClickOutside` 未排除下拉弹出框元素导致无法输入搜索。 |
||||
|
|
||||
@ -0,0 +1,93 @@ |
|||||
|
module.exports = { |
||||
|
// 继承的规则 |
||||
|
extends: ["@commitlint/config-conventional"], |
||||
|
// 自定义规则 |
||||
|
rules: { |
||||
|
// @see https://commitlint.js.org/#/reference-rules |
||||
|
|
||||
|
// 提交类型枚举,git提交type必须是以下类型 |
||||
|
"type-enum": [ |
||||
|
2, |
||||
|
"always", |
||||
|
[ |
||||
|
"feat", // 新增功能 |
||||
|
"fix", // 修复缺陷 |
||||
|
"docs", // 文档变更 |
||||
|
"style", // 代码格式(不影响功能,例如空格、分号等格式修正) |
||||
|
"refactor", // 代码重构(不包括 bug 修复、功能新增) |
||||
|
"perf", // 性能优化 |
||||
|
"test", // 添加疏漏测试或已有测试改动 |
||||
|
"build", // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等) |
||||
|
"ci", // 修改 CI 配置、脚本 |
||||
|
"revert", // 回滚 commit |
||||
|
"chore", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例) |
||||
|
], |
||||
|
], |
||||
|
"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: "特性: ✨ 新增功能", emoji: ":sparkles:" }, |
||||
|
{ value: "fix", name: "修复: 🐛 修复缺陷", emoji: ":bug:" }, |
||||
|
{ value: "docs", name: "文档: 📝 文档变更", emoji: ":memo:" }, |
||||
|
{ value: "style", name: "格式: 💄 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: ":lipstick:" }, |
||||
|
{ value: "refactor", name: "重构: ♻️ 代码重构(不包括 bug 修复、功能新增)", emoji: ":recycle:" }, |
||||
|
{ value: "perf", name: "性能: ⚡️ 性能优化", emoji: ":zap:" }, |
||||
|
{ value: "test", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: ":white_check_mark:"}, |
||||
|
{ value: "build", name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)", emoji: ":package:"}, |
||||
|
{ value: "ci", name: "集成: 🎡 修改 CI 配置、脚本", emoji: ":ferris_wheel:"}, |
||||
|
{ value: "revert", name: "回退: ⏪️ 回滚 commit",emoji: ":rewind:"}, |
||||
|
{ value: "chore", name: "其他: 🔨 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)", emoji: ":hammer:"}, |
||||
|
], |
||||
|
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: [], |
||||
|
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,18 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
|
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<link rel="icon" href="/favicon.ico" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
|
<meta name="description" content="vue-element-admin的vue3版本" /> |
||||
|
<meta name="keywords" content="vue-element-admin,vue3-element-admin" /> |
||||
|
<title>vue3-element-admin</title> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div id="app"></div> |
||||
|
<script type="module" src="/src/main.ts"></script> |
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,101 @@ |
|||||
|
{ |
||||
|
"name": "vue3-element-admin", |
||||
|
"private": true, |
||||
|
"version": "2.3.0", |
||||
|
"type": "module", |
||||
|
"scripts": { |
||||
|
"dev": "vite serve --mode development", |
||||
|
"build:prod": "vite build --mode production &&vue-tsc --noEmit", |
||||
|
"prepare": "husky install", |
||||
|
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ", |
||||
|
"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", |
||||
|
"commit": "git-cz" |
||||
|
}, |
||||
|
"config": { |
||||
|
"commitizen": { |
||||
|
"path": "node_modules/cz-git" |
||||
|
} |
||||
|
}, |
||||
|
"lint-staged": { |
||||
|
"*.{js,ts}": [ |
||||
|
"eslint --fix", |
||||
|
"prettier --write" |
||||
|
], |
||||
|
"*.{cjs,json}": [ |
||||
|
"prettier --write" |
||||
|
], |
||||
|
"*.{vue,html}": [ |
||||
|
"eslint --fix", |
||||
|
"prettier --write", |
||||
|
"stylelint --fix" |
||||
|
], |
||||
|
"*.{scss,css}": [ |
||||
|
"stylelint --fix", |
||||
|
"prettier --write" |
||||
|
], |
||||
|
"*.md": [ |
||||
|
"prettier --write" |
||||
|
] |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@vitejs/plugin-vue": "^4.2.3", |
||||
|
"@vueuse/core": "^10.1.2", |
||||
|
"@wangeditor/editor": "^5.1.23", |
||||
|
"@wangeditor/editor-for-vue": "5.1.10", |
||||
|
"axios": "^1.4.0", |
||||
|
"echarts": "^5.2.2", |
||||
|
"element-plus": "^2.3.4", |
||||
|
"nprogress": "^0.2.0", |
||||
|
"path-browserify": "^1.0.1", |
||||
|
"path-to-regexp": "^6.2.0", |
||||
|
"pinia": "^2.0.33", |
||||
|
"screenfull": "^6.0.0", |
||||
|
"vue": "^3.3.1", |
||||
|
"vue-i18n": "9.2.2", |
||||
|
"vue-router": "^4.2.0" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@commitlint/cli": "^17.6.3", |
||||
|
"@commitlint/config-conventional": "^17.6.3", |
||||
|
"@iconify-json/ep": "^1.1.10", |
||||
|
"@types/nprogress": "^0.2.0", |
||||
|
"@types/path-browserify": "^1.0.0", |
||||
|
"@typescript-eslint/eslint-plugin": "^5.59.6", |
||||
|
"@typescript-eslint/parser": "^5.59.6", |
||||
|
"autoprefixer": "^10.4.14", |
||||
|
"commitizen": "^4.3.0", |
||||
|
"cz-git": "^1.6.1", |
||||
|
"eslint": "^8.40.0", |
||||
|
"eslint-config-prettier": "^8.8.0", |
||||
|
"eslint-plugin-prettier": "^4.2.1", |
||||
|
"eslint-plugin-vue": "^9.13.0", |
||||
|
"fast-glob": "^3.2.11", |
||||
|
"husky": "^8.0.3", |
||||
|
"lint-staged": "^13.2.2", |
||||
|
"postcss": "^8.4.23", |
||||
|
"postcss-html": "^1.5.0", |
||||
|
"postcss-scss": "^4.0.6", |
||||
|
"prettier": "^2.8.8", |
||||
|
"sass": "^1.58.3", |
||||
|
"stylelint": "^15.5.0", |
||||
|
"stylelint-config-html": "^1.1.0", |
||||
|
"stylelint-config-recess-order": "^4.0.0", |
||||
|
"stylelint-config-recommended-scss": "11.0.0 ", |
||||
|
"stylelint-config-recommended-vue": "^1.4.0", |
||||
|
"stylelint-config-standard": "^33.0.0", |
||||
|
"stylelint-config-standard-scss": "^9.0.0", |
||||
|
"typescript": "^5.0.4", |
||||
|
"unocss": "^0.51.13", |
||||
|
"unplugin-auto-import": "^0.15.3", |
||||
|
"unplugin-icons": "^0.16.1", |
||||
|
"unplugin-vue-components": "^0.24.1", |
||||
|
"vite": "^4.3.5", |
||||
|
"vite-plugin-svg-icons": "^2.0.1", |
||||
|
"vue-tsc": "^1.6.5 " |
||||
|
}, |
||||
|
"repository": "https://gitee.com/youlaiorg/vue3-element-admin.git", |
||||
|
"author": "有来开源组织", |
||||
|
"license": "MIT" |
||||
|
} |
||||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,11 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { ElConfigProvider } from 'element-plus'; |
||||
|
import { useAppStore } from '@/store/modules/app'; |
||||
|
const appStore = useAppStore(); |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<el-config-provider :locale="appStore.locale" :size="appStore.size"> |
||||
|
<router-view /> |
||||
|
</el-config-provider> |
||||
|
</template> |
||||
@ -0,0 +1,39 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { CaptchaResult, LoginData, LoginResult } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 登录API |
||||
|
* |
||||
|
* @param data {LoginData} |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function loginApi(data: LoginData): AxiosPromise<LoginResult> { |
||||
|
return request({ |
||||
|
url: '/api/v1/auth/login', |
||||
|
method: 'post', |
||||
|
params: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 注销API |
||||
|
*/ |
||||
|
export function logoutApi() { |
||||
|
return request({ |
||||
|
url: '/api/v1/auth/logout', |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取验证码 |
||||
|
*/ |
||||
|
export function getCaptchaApi(): AxiosPromise<CaptchaResult> { |
||||
|
return request({ |
||||
|
url: '/api/v1/auth/captcha', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
/** |
||||
|
* 登录请求参数 |
||||
|
*/ |
||||
|
export interface LoginData { |
||||
|
/** |
||||
|
* 用户名 |
||||
|
*/ |
||||
|
username?: string; |
||||
|
/** |
||||
|
* 密码 |
||||
|
*/ |
||||
|
password?: string; |
||||
|
|
||||
|
/** |
||||
|
* 验证码缓存key |
||||
|
*/ |
||||
|
verifyCodeKey?: string; |
||||
|
|
||||
|
/** |
||||
|
* 验证码 |
||||
|
*/ |
||||
|
verifyCode?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 登录响应 |
||||
|
*/ |
||||
|
export interface LoginResult { |
||||
|
/** |
||||
|
* 访问token |
||||
|
*/ |
||||
|
accessToken?: string; |
||||
|
/** |
||||
|
* 过期时间(单位:毫秒) |
||||
|
*/ |
||||
|
expires?: number; |
||||
|
/** |
||||
|
* 刷新token |
||||
|
*/ |
||||
|
refreshToken?: string; |
||||
|
/** |
||||
|
* token 类型 |
||||
|
*/ |
||||
|
tokenType?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证码响应 |
||||
|
*/ |
||||
|
export interface CaptchaResult { |
||||
|
/** |
||||
|
* 验证码缓存key |
||||
|
*/ |
||||
|
verifyCodeKey: string; |
||||
|
/** |
||||
|
* 验证码图片Base64字符串 |
||||
|
*/ |
||||
|
verifyCodeBase64: string; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,77 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { DeptForm, DeptQuery, DeptVO } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 部门树形表格 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function listDepts(queryParams?: DeptQuery): AxiosPromise<DeptVO[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 部门下拉列表 |
||||
|
*/ |
||||
|
export function listDeptOptions(): AxiosPromise<[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept/options', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取部门详情 |
||||
|
* |
||||
|
* @param id |
||||
|
*/ |
||||
|
export function getDeptForm(id: number): AxiosPromise<DeptForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept/' + id + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增部门 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addDept(data: DeptForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改部门 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateDept(id: number, data: DeptForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除部门 |
||||
|
* |
||||
|
* @param ids |
||||
|
*/ |
||||
|
export function deleteDept(ids: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dept/' + ids, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,71 @@ |
|||||
|
/** |
||||
|
* 部门查询参数 |
||||
|
*/ |
||||
|
export interface DeptQuery { |
||||
|
keywords?: string; |
||||
|
status?: number; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 部门类型 |
||||
|
*/ |
||||
|
export interface DeptVO { |
||||
|
/** |
||||
|
* 子部门 |
||||
|
*/ |
||||
|
children?: DeptVO[]; |
||||
|
/** |
||||
|
* 创建时间 |
||||
|
*/ |
||||
|
createTime?: Date; |
||||
|
/** |
||||
|
* 部门ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 部门名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 父部门ID |
||||
|
*/ |
||||
|
parentId?: number; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 修改时间 |
||||
|
*/ |
||||
|
updateTime?: Date; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 部门表单类型 |
||||
|
*/ |
||||
|
export interface DeptForm { |
||||
|
/** |
||||
|
* 部门ID(新增不填) |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 部门名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 父部门ID |
||||
|
*/ |
||||
|
parentId: number; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { |
||||
|
DictTypeQuery, |
||||
|
DictTypePageResult, |
||||
|
DictTypeForm, |
||||
|
DictQuery, |
||||
|
DictForm, |
||||
|
DictPageResult |
||||
|
} from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 字典类型分页列表 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function getDictTypePage( |
||||
|
queryParams: DictTypeQuery |
||||
|
): AxiosPromise<DictTypePageResult> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types/page', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典类型表单数据 |
||||
|
* |
||||
|
* @param id |
||||
|
*/ |
||||
|
export function getDictTypeForm(id: number): AxiosPromise<DictTypeForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types/' + id + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增字典类型 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addDictType(data: DictTypeForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改字典类型 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateDictType(id: number, data: DictTypeForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除字典类型 |
||||
|
*/ |
||||
|
export function deleteDictTypes(ids: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types/' + ids, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取字典类型的数据项 |
||||
|
* |
||||
|
* @param typeCode 字典类型编码 |
||||
|
*/ |
||||
|
export function getDictOptions(typeCode: string): AxiosPromise<OptionType[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/types/' + typeCode + '/items', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典分页列表 |
||||
|
*/ |
||||
|
export function getDictPage( |
||||
|
queryParams: DictQuery |
||||
|
): AxiosPromise<DictPageResult> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/page', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取字典表单数据 |
||||
|
* |
||||
|
* @param id |
||||
|
*/ |
||||
|
export function getDictFormData(id: number): AxiosPromise<DictForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/' + id + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增字典 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addDict(data: DictForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改字典项 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateDict(id: number, data: DictForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除字典 |
||||
|
* |
||||
|
* @param ids 字典项ID,多个以英文逗号(,)分割 |
||||
|
*/ |
||||
|
export function deleteDict(ids: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/dict/' + ids, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,142 @@ |
|||||
|
/** |
||||
|
* 字典类型查询参数 |
||||
|
*/ |
||||
|
export interface DictTypeQuery extends PageQuery { |
||||
|
/** |
||||
|
* 关键字(字典类型名称/编码) |
||||
|
*/ |
||||
|
keywords?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典类型分页对象 |
||||
|
*/ |
||||
|
export interface DictTypePageVO { |
||||
|
/** |
||||
|
* 字典类型ID |
||||
|
*/ |
||||
|
id: number; |
||||
|
/** |
||||
|
* 类型编码 |
||||
|
*/ |
||||
|
code: string; |
||||
|
/** |
||||
|
* 类型名称 |
||||
|
*/ |
||||
|
name: string; |
||||
|
/** |
||||
|
* 状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
remark?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典分页项类型声明 |
||||
|
*/ |
||||
|
export type DictTypePageResult = PageResult<DictTypePageVO[]>; |
||||
|
|
||||
|
/** |
||||
|
* 字典表单类型声明 |
||||
|
*/ |
||||
|
export interface DictTypeForm { |
||||
|
/** |
||||
|
* 字典类型ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 类型名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 类型编码 |
||||
|
*/ |
||||
|
code?: string; |
||||
|
/** |
||||
|
* 类型状态:1:启用;0:禁用 |
||||
|
*/ |
||||
|
status: number; |
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
remark?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典查询参数 |
||||
|
*/ |
||||
|
export interface DictQuery extends PageQuery { |
||||
|
/** |
||||
|
* 字典项名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 字典类型编码 |
||||
|
*/ |
||||
|
typeCode?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典分页对象 |
||||
|
*/ |
||||
|
export interface DictPageVO { |
||||
|
/** |
||||
|
* 字典ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 字典名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 字典值 |
||||
|
*/ |
||||
|
value?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字典分页 |
||||
|
*/ |
||||
|
export type DictPageResult = PageResult<DictPageVO[]>; |
||||
|
|
||||
|
/** |
||||
|
* 字典表单 |
||||
|
*/ |
||||
|
export interface DictForm { |
||||
|
/** |
||||
|
* 字典ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 字典名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 类型编码 |
||||
|
*/ |
||||
|
typeCode?: string; |
||||
|
/** |
||||
|
* 值 |
||||
|
*/ |
||||
|
value?: string; |
||||
|
|
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
remark?: string; |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { FileInfo } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 上传文件 |
||||
|
* |
||||
|
* @param file |
||||
|
*/ |
||||
|
export function uploadFileApi(file: File): AxiosPromise<FileInfo> { |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', file); |
||||
|
return request({ |
||||
|
url: '/api/v1/files', |
||||
|
method: 'post', |
||||
|
data: formData, |
||||
|
headers: { |
||||
|
'Content-Type': 'multipart/form-data' |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除文件 |
||||
|
* |
||||
|
* @param filePath 文件完整路径 |
||||
|
*/ |
||||
|
export function deleteFileApi(filePath?: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/files', |
||||
|
method: 'delete', |
||||
|
params: { filePath: filePath } |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
/** |
||||
|
* 文件API类型声明 |
||||
|
*/ |
||||
|
export interface FileInfo { |
||||
|
name: string; |
||||
|
url: string; |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { MenuQuery, MenuVO, MenuForm } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 获取路由列表 |
||||
|
*/ |
||||
|
export function listRoutes() { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus/routes', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取菜单树形列表 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function listMenus(queryParams: MenuQuery): AxiosPromise<MenuVO[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取菜单下拉树形列表 |
||||
|
*/ |
||||
|
export function listMenuOptions(): AxiosPromise<OptionType[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus/options', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取菜单表单数据 |
||||
|
* |
||||
|
* @param id |
||||
|
*/ |
||||
|
export function getMenuForm(id: number): AxiosPromise<MenuForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus/' + id + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加菜单 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addMenu(data: MenuForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改菜单 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateMenu(id: string, data: MenuForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除菜单 |
||||
|
* |
||||
|
* @param id 菜单ID |
||||
|
*/ |
||||
|
export function deleteMenu(id: number) { |
||||
|
return request({ |
||||
|
url: '/api/v1/menus/' + id, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
import { MenuTypeEnum } from '@/enums/MenuTypeEnum'; |
||||
|
|
||||
|
/** |
||||
|
* 菜单查询参数类型 |
||||
|
*/ |
||||
|
export interface MenuQuery { |
||||
|
keywords?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 菜单视图对象类型 |
||||
|
*/ |
||||
|
export interface MenuVO { |
||||
|
/** |
||||
|
* 子菜单 |
||||
|
*/ |
||||
|
children?: MenuVO[]; |
||||
|
/** |
||||
|
* 组件路径 |
||||
|
*/ |
||||
|
component?: string; |
||||
|
/** |
||||
|
* ICON |
||||
|
*/ |
||||
|
icon?: string; |
||||
|
/** |
||||
|
* 菜单ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 菜单名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 父菜单ID |
||||
|
*/ |
||||
|
parentId?: number; |
||||
|
/** |
||||
|
* 按钮权限标识 |
||||
|
*/ |
||||
|
perm?: string; |
||||
|
/** |
||||
|
* 跳转路径 |
||||
|
*/ |
||||
|
redirect?: string; |
||||
|
/** |
||||
|
* 路由名称 |
||||
|
*/ |
||||
|
routeName?: string; |
||||
|
/** |
||||
|
* 路由相对路径 |
||||
|
*/ |
||||
|
routePath?: string; |
||||
|
/** |
||||
|
* 菜单排序(数字越小排名越靠前) |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 菜单类型 |
||||
|
*/ |
||||
|
type?: MenuTypeEnum; |
||||
|
/** |
||||
|
* 菜单是否可见(1:显示;0:隐藏) |
||||
|
*/ |
||||
|
visible?: number; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 菜单表单对象类型 |
||||
|
*/ |
||||
|
export interface MenuForm { |
||||
|
/** |
||||
|
* 菜单ID |
||||
|
*/ |
||||
|
id?: string; |
||||
|
/** |
||||
|
* 父菜单ID |
||||
|
*/ |
||||
|
parentId?: number; |
||||
|
/** |
||||
|
* 菜单名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 菜单是否可见(1:是;0:否;) |
||||
|
*/ |
||||
|
visible: number; |
||||
|
icon?: string; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort: number; |
||||
|
/** |
||||
|
* 组件路径 |
||||
|
*/ |
||||
|
component?: string; |
||||
|
/** |
||||
|
* 路由路径 |
||||
|
*/ |
||||
|
path?: string; |
||||
|
/** |
||||
|
* 跳转路由路径 |
||||
|
*/ |
||||
|
redirect?: string; |
||||
|
|
||||
|
/** |
||||
|
* 菜单类型 |
||||
|
*/ |
||||
|
type: MenuTypeEnum; |
||||
|
|
||||
|
/** |
||||
|
* 权限标识 |
||||
|
*/ |
||||
|
perm?: string; |
||||
|
} |
||||
@ -0,0 +1,112 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { RoleQuery, RolePageResult, RoleForm } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 获取角色分页数据 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function getRolePage( |
||||
|
queryParams?: RoleQuery |
||||
|
): AxiosPromise<RolePageResult> { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/page', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取角色下拉数据 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function listRoleOptions( |
||||
|
queryParams?: RoleQuery |
||||
|
): AxiosPromise<OptionType[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/options', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取角色的菜单ID集合 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function getRoleMenuIds(roleId: number): AxiosPromise<number[]> { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/' + roleId + '/menuIds', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分配菜单权限给角色 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function updateRoleMenus( |
||||
|
roleId: number, |
||||
|
data: number[] |
||||
|
): AxiosPromise<any> { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/' + roleId + '/menus', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取角色详情 |
||||
|
* |
||||
|
* @param id |
||||
|
*/ |
||||
|
export function getRoleForm(id: number): AxiosPromise<RoleForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/' + id + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加角色 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addRole(data: RoleForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新角色 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateRole(id: number, data: RoleForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量删除角色,多个以英文逗号(,)分割 |
||||
|
* |
||||
|
* @param ids |
||||
|
*/ |
||||
|
export function deleteRoles(ids: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/roles/' + ids, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
/** |
||||
|
* 角色查询参数 |
||||
|
*/ |
||||
|
export interface RoleQuery extends PageQuery { |
||||
|
keywords?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 角色分页对象 |
||||
|
*/ |
||||
|
export interface RolePageVO { |
||||
|
/** |
||||
|
* 角色编码 |
||||
|
*/ |
||||
|
code?: string; |
||||
|
|
||||
|
/** |
||||
|
* 角色ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 角色名称 |
||||
|
*/ |
||||
|
name?: string; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 角色状态 |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 创建时间 |
||||
|
*/ |
||||
|
createTime?: Date; |
||||
|
/** |
||||
|
* 修改时间 |
||||
|
*/ |
||||
|
updateTime?: Date; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 角色分页 |
||||
|
*/ |
||||
|
export type RolePageResult = PageResult<RolePageVO[]>; |
||||
|
|
||||
|
/** |
||||
|
* 角色表单对象 |
||||
|
*/ |
||||
|
export interface RoleForm { |
||||
|
/** |
||||
|
* 角色ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
|
||||
|
/** |
||||
|
* 角色编码 |
||||
|
*/ |
||||
|
code: string; |
||||
|
/** |
||||
|
* 数据权限 |
||||
|
*/ |
||||
|
dataScope?: number; |
||||
|
|
||||
|
/** |
||||
|
* 角色名称 |
||||
|
*/ |
||||
|
name: string; |
||||
|
/** |
||||
|
* 排序 |
||||
|
*/ |
||||
|
sort?: number; |
||||
|
/** |
||||
|
* 角色状态(1-正常;0-停用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
} |
||||
@ -0,0 +1,154 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { UserForm, UserInfo, UserPageVO, UserQuery } from './types'; |
||||
|
|
||||
|
/** |
||||
|
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合) |
||||
|
*/ |
||||
|
export function getUserInfo(): AxiosPromise<UserInfo> { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/me', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取用户分页列表 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
*/ |
||||
|
export function getUserPage( |
||||
|
queryParams: UserQuery |
||||
|
): AxiosPromise<PageResult<UserPageVO[]>> { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/page', |
||||
|
method: 'get', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取用户表单详情 |
||||
|
* |
||||
|
* @param userId |
||||
|
*/ |
||||
|
export function getUserForm(userId: number): AxiosPromise<UserForm> { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/' + userId + '/form', |
||||
|
method: 'get' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加用户 |
||||
|
* |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function addUser(data: any) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改用户 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param data |
||||
|
*/ |
||||
|
export function updateUser(id: number, data: UserForm) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/' + id, |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改用户状态 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param status |
||||
|
*/ |
||||
|
export function updateUserStatus(id: number, status: number) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/' + id + '/status', |
||||
|
method: 'patch', |
||||
|
params: { status: status } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改用户密码 |
||||
|
* |
||||
|
* @param id |
||||
|
* @param password |
||||
|
*/ |
||||
|
export function updateUserPassword(id: number, password: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/' + id + '/password', |
||||
|
method: 'patch', |
||||
|
params: { password: password } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除用户 |
||||
|
* |
||||
|
* @param ids |
||||
|
*/ |
||||
|
export function deleteUsers(ids: string) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/' + ids, |
||||
|
method: 'delete' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 下载用户导入模板 |
||||
|
* |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function downloadTemplateApi() { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/template', |
||||
|
method: 'get', |
||||
|
responseType: 'arraybuffer' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出用户 |
||||
|
* |
||||
|
* @param queryParams |
||||
|
* @returns |
||||
|
*/ |
||||
|
export function exportUser(queryParams: UserQuery) { |
||||
|
return request({ |
||||
|
url: '/api/v1/users/_export', |
||||
|
method: 'get', |
||||
|
params: queryParams, |
||||
|
responseType: 'arraybuffer' |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导入用户 |
||||
|
* |
||||
|
* @param file |
||||
|
*/ |
||||
|
export function importUser(deptId: number, file: File) { |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', file); |
||||
|
return request({ |
||||
|
url: '/api/v1/users/_import', |
||||
|
method: 'post', |
||||
|
params: { deptId: deptId }, |
||||
|
data: formData, |
||||
|
headers: { |
||||
|
'Content-Type': 'multipart/form-data' |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,111 @@ |
|||||
|
/** |
||||
|
* 登录用户信息 |
||||
|
*/ |
||||
|
export interface UserInfo { |
||||
|
nickname: string; |
||||
|
avatar: string; |
||||
|
roles: string[]; |
||||
|
perms: string[]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 用户查询对象类型 |
||||
|
*/ |
||||
|
export interface UserQuery extends PageQuery { |
||||
|
keywords?: string; |
||||
|
status?: number; |
||||
|
deptId?: number; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 用户分页对象 |
||||
|
*/ |
||||
|
export interface UserPageVO { |
||||
|
/** |
||||
|
* 用户头像地址 |
||||
|
*/ |
||||
|
avatar?: string; |
||||
|
/** |
||||
|
* 创建时间 |
||||
|
*/ |
||||
|
createTime?: Date; |
||||
|
/** |
||||
|
* 部门名称 |
||||
|
*/ |
||||
|
deptName?: string; |
||||
|
/** |
||||
|
* 用户邮箱 |
||||
|
*/ |
||||
|
email?: string; |
||||
|
/** |
||||
|
* 性别 |
||||
|
*/ |
||||
|
genderLabel?: string; |
||||
|
/** |
||||
|
* 用户ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
/** |
||||
|
* 手机号 |
||||
|
*/ |
||||
|
mobile?: string; |
||||
|
/** |
||||
|
* 用户昵称 |
||||
|
*/ |
||||
|
nickname?: string; |
||||
|
/** |
||||
|
* 角色名称,多个使用英文逗号(,)分割 |
||||
|
*/ |
||||
|
roleNames?: string; |
||||
|
/** |
||||
|
* 用户状态(1:启用;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 用户名 |
||||
|
*/ |
||||
|
username?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 用户表单类型 |
||||
|
*/ |
||||
|
export interface UserForm { |
||||
|
/** |
||||
|
* 用户头像 |
||||
|
*/ |
||||
|
avatar?: string; |
||||
|
/** |
||||
|
* 部门ID |
||||
|
*/ |
||||
|
deptId?: number; |
||||
|
/** |
||||
|
* 邮箱 |
||||
|
*/ |
||||
|
email?: string; |
||||
|
/** |
||||
|
* 性别 |
||||
|
*/ |
||||
|
gender?: number; |
||||
|
/** |
||||
|
* 用户ID |
||||
|
*/ |
||||
|
id?: number; |
||||
|
mobile?: string; |
||||
|
/** |
||||
|
* 昵称 |
||||
|
*/ |
||||
|
nickname?: string; |
||||
|
/** |
||||
|
* 角色ID集合 |
||||
|
*/ |
||||
|
roleIds?: number[]; |
||||
|
/** |
||||
|
* 用户状态(1:正常;0:禁用) |
||||
|
*/ |
||||
|
status?: number; |
||||
|
/** |
||||
|
* 用户名 |
||||
|
*/ |
||||
|
username?: string; |
||||
|
} |
||||
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 395 B |
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 647 B |
|
After Width: | Height: | Size: 284 B |
|
After Width: | Height: | Size: 693 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 927 B |
|
After Width: | Height: | Size: 909 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 356 B |
|
After Width: | Height: | Size: 818 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 944 B |
|
After Width: | Height: | Size: 421 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 320 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 730 B |
|
After Width: | Height: | Size: 1001 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 914 B |
|
After Width: | Height: | Size: 883 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 821 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 367 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 561 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 211 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 689 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 959 B |
|
After Width: | Height: | Size: 988 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 334 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,103 @@ |
|||||
|
<template> |
||||
|
<el-breadcrumb class="h-[50px] flex items-center"> |
||||
|
<transition-group name="breadcrumb"> |
||||
|
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path"> |
||||
|
<span |
||||
|
v-if=" |
||||
|
item.redirect === 'noredirect' || index === breadcrumbs.length - 1 |
||||
|
" |
||||
|
class="text-[var(--el-disabled-text-color)]" |
||||
|
>{{ translateRouteTitleI18n(item.meta.title) }}</span |
||||
|
> |
||||
|
<a v-else @click.prevent="handleLink(item)"> |
||||
|
{{ translateRouteTitleI18n(item.meta.title) }} |
||||
|
</a> |
||||
|
</el-breadcrumb-item> |
||||
|
</transition-group> |
||||
|
</el-breadcrumb> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { onBeforeMount, ref, watch } from "vue"; |
||||
|
import { useRoute, RouteLocationMatched } from "vue-router"; |
||||
|
import { compile } from "path-to-regexp"; |
||||
|
import router from "@/router"; |
||||
|
import { translateRouteTitleI18n } from "@/utils/i18n"; |
||||
|
|
||||
|
const currentRoute = useRoute(); |
||||
|
const pathCompile = (path: string) => { |
||||
|
const { params } = currentRoute; |
||||
|
const toPath = compile(path); |
||||
|
return toPath(params); |
||||
|
}; |
||||
|
|
||||
|
const breadcrumbs = ref([] as Array<RouteLocationMatched>); |
||||
|
|
||||
|
function getBreadcrumb() { |
||||
|
let matched = currentRoute.matched.filter( |
||||
|
(item) => item.meta && item.meta.title |
||||
|
); |
||||
|
const first = matched[0]; |
||||
|
if (!isDashboard(first)) { |
||||
|
matched = [ |
||||
|
{ path: "/dashboard", meta: { title: "dashboard" } } as any, |
||||
|
].concat(matched); |
||||
|
} |
||||
|
breadcrumbs.value = matched.filter((item) => { |
||||
|
return item.meta && item.meta.title && item.meta.breadcrumb !== false; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function isDashboard(route: RouteLocationMatched) { |
||||
|
const name = route && route.name; |
||||
|
if (!name) { |
||||
|
return false; |
||||
|
} |
||||
|
return ( |
||||
|
name.toString().trim().toLocaleLowerCase() === |
||||
|
"Dashboard".toLocaleLowerCase() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
function handleLink(item: any) { |
||||
|
const { redirect, path } = item; |
||||
|
if (redirect) { |
||||
|
router.push(redirect).catch((err) => { |
||||
|
console.warn(err); |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
router.push(pathCompile(path)).catch((err) => { |
||||
|
console.warn(err); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
watch( |
||||
|
() => currentRoute.path, |
||||
|
(path) => { |
||||
|
if (path.startsWith("/redirect/")) { |
||||
|
return; |
||||
|
} |
||||
|
getBreadcrumb(); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
onBeforeMount(() => { |
||||
|
getBreadcrumb(); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.app-breadcrumb.el-breadcrumb { |
||||
|
display: inline-block; |
||||
|
margin-left: 8px; |
||||
|
font-size: 14px; |
||||
|
line-height: 50px; |
||||
|
} |
||||
|
|
||||
|
// 覆盖 element-plus 的样式 |
||||
|
.el-breadcrumb__inner, |
||||
|
.el-breadcrumb__inner a { |
||||
|
font-weight: 400 !important; |
||||
|
} |
||||
|
</style> |
||||