feat: init

This commit is contained in:
admin 2024-09-08 11:01:57 +08:00
commit 48a6f3cabc
192 changed files with 19649 additions and 0 deletions

14
.env.development Normal file
View File

@ -0,0 +1,14 @@
# 应用端口
VITE_APP_PORT = 3000
# 代理前缀
VITE_APP_BASE_API = '/'
# /test/sh0001/api
# 线上接口地址
VITE_APP_API_URL = 'https://cloud.52zaisheng.cn'
# 开发接口地址
# VITE_APP_API_URL = http://localhost:8989
# 是否启用 Mock 服务
VITE_MOCK_DEV_SERVER = false

3
.env.production Normal file
View File

@ -0,0 +1,3 @@
# 代理前缀
VITE_APP_BASE_API = '/test'

14
.eslintignore Normal file
View File

@ -0,0 +1,14 @@
dist
node_modules
public
.husky
.vscode
.idea
*.sh
*.md
src/assets
.eslintrc.cjs
.prettierrc.cjs
.stylelintrc.cjs

284
.eslintrc-auto-import.json Normal file
View File

@ -0,0 +1,284 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ElMessage": true,
"ElMessageBox": true,
"ElNotification": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": 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,
"createReusableTemplate": true,
"createSharedComposable": true,
"createTemplatePromise": 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,
"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,
"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,
"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,
"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,
"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,
"watchDeep": true,
"watchEffect": true,
"watchIgnorable": true,
"watchImmediate": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true
}
}

88
.eslintrc.cjs Normal file
View File

@ -0,0 +1,88 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
parser: "vue-eslint-parser",
extends: [
// https://eslint.vuejs.org/user-guide/#usage
"plugin:vue/vue3-recommended",
"./.eslintrc-auto-import.json",
"prettier",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: "@typescript-eslint/parser",
project: "./tsconfig.*?.json",
createDefaultProgram: false,
extraFileExtensions: [".vue"],
},
plugins: ["vue", "@typescript-eslint"],
rules: {
// https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention
"vue/multi-word-component-names": "off",
"vue/no-v-model-argument": "off",
"vue/script-setup-uses-vars": "error",
"vue/no-reserved-component-names": "off",
"vue/custom-event-name-casing": "off",
"vue/attributes-order": "off",
"vue/one-component-per-file": "off",
"vue/html-closing-bracket-newline": "off",
"vue/max-attributes-per-line": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/attribute-hyphenation": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "off",
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "never",
component: "always",
},
svg: "always",
math: "always",
},
],
"@typescript-eslint/no-empty-function": "off", // 关闭空方法检查
"@typescript-eslint/no-explicit-any": "off", // 关闭any类型的警告
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"prettier/prettier": [
"error",
{
useTabs: false, // 不使用制表符
},
],
},
// eslint不能对html文件生效
overrides: [
{
files: ["*.html"],
processor: "vue/.vue",
},
],
// https://eslint.org/docs/latest/use/configure/language-options#specifying-globals
globals: {
OptionType: "readonly",
},
};

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.history
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
pnpm-lock.yaml
stats.html

1
.husky/commit-msg Executable file
View File

@ -0,0 +1 @@
npx --no-install commitlint --edit $1

1
.husky/pre-commit Executable file
View File

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

11
.prettierignore Normal file
View File

@ -0,0 +1,11 @@
dist
node_modules
public
.husky
.vscode
.idea
*.sh
*.md
src/assets
stats.html

46
.prettierrc.cjs Normal file
View File

@ -0,0 +1,46 @@
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: "ignore",
// 当文件已经被 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,
endOfLine: "auto",
overrides: [
{
files: "*.html",
options: {
parser: "html",
},
},
],
};

11
.stylelintignore Normal file
View File

@ -0,0 +1,11 @@
dist
node_modules
public
.husky
.vscode
.idea
*.sh
*.md
src/assets
stats.html

51
.stylelintrc.cjs Normal file
View File

@ -0,0 +1,51 @@
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"],
},
],
},
};

11
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"recommendations": [
"vue.volar",
"antfu.unocss",
"lokalise.i18n-ally",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"stylelint.vscode-stylelint",
"editorconfig.editorconfig"
]
}

81
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,81 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"npm.packageManager": "pnpm",
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"files.eol": "\n",
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
"**/*.log*": true,
"**/bower_components": true,
"**/dist": true,
"**/elehukouben": true,
"**/.git": true,
"**/.gitignore": true,
"**/.svn": true,
"**/.DS_Store": true,
"**/.idea": true,
"**/.vscode": false,
"**/yarn.lock": true,
"**/tmp": true,
"out": true,
"dist": true,
"node_modules": true,
"CHANGELOG.md": true,
"examples": true,
"res": true,
"screenshots": true,
"yarn-error.log": true,
"**/.yarn": true
},
"files.exclude": {
"**/.cache": true,
"**/.editorconfig": true,
"**/.eslintcache": true,
"**/bower_components": true,
"**/.idea": true,
"**/tmp": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.vscode/**": true,
"**/node_modules/**": true,
"**/tmp/**": true,
"**/bower_components/**": true,
"**/dist/**": true,
"**/yarn.lock": true
},
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": false,
"i18n-ally.pathMatcher": "{namespaces}/{locale}.{ext}",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": [
"vue",
"react"
],
"i18n-ally.localesPaths": [
"src/lang"
],
"scss.lint.unknownAtRules": "ignore"
}

23
.vscode/vue3.0.code-snippets vendored Normal file
View File

@ -0,0 +1,23 @@
{
"Vue3.0快速生成模板": {
"scope": "vue",
"prefix": "Vue3.0",
"body": [
"<template>",
" <div>${1:test}</div>",
"</template>",
"",
"<script lang=\"ts\">",
"export default {",
" setup() {",
" return {};",
" },",
"};",
"</script>",
"",
"<style lang=\"scss\" scoped></style>",
""
],
"description": "Vue3.0"
}
}

17
.vscode/vue3.2.code-snippets vendored Normal file
View File

@ -0,0 +1,17 @@
{
"Vue3.2+快速生成模板": {
"scope": "vue",
"prefix": "Vue3.2+",
"body": [
"<script setup lang=\"ts\"></script>",
"",
"<template>",
" <div>${1:test}</div>",
"</template>",
"",
"<style lang=\"scss\" scoped></style>",
""
],
"description": "Vue3.2+"
}
}

21
.vscode/vue3.3.code-snippets vendored Normal file
View File

@ -0,0 +1,21 @@
{
"Vue3.3+defineOptions快速生成模板": {
"scope": "vue",
"prefix": "Vue3.3+",
"body": [
"<script setup lang=\"ts\">",
"defineOptions({",
" name: \"\",",
"});",
"</script>",
"",
"<template>",
" <div>${1:test}</div>",
"</template>",
"",
"<style lang=\"scss\" scoped></style>",
""
],
"description": "Vue3.3+defineOptions快速生成模板"
}
}

386
CHANGELOG.md Normal file
View File

@ -0,0 +1,386 @@
# 2.11.5 (2024/6/18)
## ✨ feat
- 支持后端文件导入([#142](https://github.com/youlaitech/vue3-element-admin/pull/142)) [@cshaptx4869](https://github.com/cshaptx4869)
## 🐛 fix
- vue-dev-tools 插件导致菜单路由切换卡死,暂时关闭 ([28349e](https://github.com/youlaitech/vue3-element-admin/commit/28349efe147afab36531ba148eaac3a448fe6c71)) [@haoxianrui](https://github.com/haoxianrui)
# 2.11.4 (2024/6/16)
## ✨ feat
- 操作栏增加render配置参数([#138](https://github.com/youlaitech/vue3-element-admin/pull/140)) [@cshaptx4869](https://github.com/cshaptx4869)
- 左侧工具栏增加type配置参数([#141](https://github.com/youlaitech/vue3-element-admin/pull/141)) [@diamont1001](https://github.com/diamont1001)
## ♻️ refactor
- 更换权限分配弹窗类型为 drawer 并添加父子联动开关([2d9193](https://github.com/youlaitech/vue3-element-admin/commit/2d9193c47fd224f01f82b9c0b2bbeb5e7cb33584)) [@haoxianrui](https://github.com/haoxianrui)
# 2.11.3 (2024/6/11)
## ✨ feat
- 支持默认工具栏的导入([#138](https://github.com/youlaitech/vue3-element-admin/pull/138)) [@cshaptx4869](https://github.com/cshaptx4869)
- 添加CURD导入示例([19e7bb](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869)
## ♻️ refactor
- 修改导出全量数据选项文本([904fec](https://github.com/youlaitech/vue3-element-admin/commit/904fecad65217650482fcdbb10ffb7f3d27eb9ea)) [@cshaptx4869](https://github.com/cshaptx4869)
## 🐛 fix
- 菜单列表未适配el-icon导致图标不显示问题修复([e72b68](https://github.com/youlaitech/vue3-element-admin/commit/e72b68337562b5a7ea24ad55bbe00023e1266b40)) [@haoxianrui](https://github.com/haoxianrui)
# 2.11.2 (2024/6/8)
## ✨ feat
- 支持表格远程筛选([#131](https://github.com/youlaitech/vue3-element-admin/pull/131)) [@cshaptx4869](https://github.com/cshaptx4869)
- 支持标签输入框([#132](https://github.com/youlaitech/vue3-element-admin/pull/132)) [@cshaptx4869](https://github.com/cshaptx4869)
- 表单项支持tips配置([#133](https://github.com/youlaitech/vue3-element-admin/pull/133)) [@cshaptx4869](https://github.com/cshaptx4869)
- 前端导出支持全量数据([#134](https://github.com/youlaitech/vue3-element-admin/pull/134)) [@cshaptx4869](https://github.com/cshaptx4869)
- 支持选中数据导出([#135](https://github.com/youlaitech/vue3-element-admin/pull/135)) [@cshaptx4869](https://github.com/cshaptx4869)
- 表格默认工具栏的导出、搜索按钮增加权限点控制([883128](https://github.com/youlaitech/vue3-element-admin/commit/8831289b655f2cc086ecdababaa89f8d8a087c42)) [@cshaptx4869](https://github.com/cshaptx4869)
- 页签title支持动态设置([23876a](https://github.com/youlaitech/vue3-element-admin/commit/23876aa396143bf77cb5c86af8d6023d9ff6555a)) [@haoxianrui](https://github.com/haoxianrui)
## ♻️ refactor
- 默认工具栏支持自定义([#136](https://github.com/youlaitech/vue3-element-admin/pull/136)) [@cshaptx4869](https://github.com/cshaptx4869)
- 未配置全量导出接口时选项隐藏([eab91ef](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869)
## 🐛 fix
- 修复注销登出后redirect跳转路由参数丢失([5626017](https://github.com/youlaitech/vue3-element-admin/commit/562601736731afd20bb1a5140d856f6515720159)) [@haoxianrui](https://github.com/haoxianrui)
# 2.11.1 (2024/6/6)
## ✨ feat
- 增加pagination、request、parseData配置参数([#119](https://github.com/youlaitech/vue3-element-admin/pull/119)) [@cshaptx4869](https://github.com/cshaptx4869)
- 增加返回顶部功能([#120](https://github.com/youlaitech/vue3-element-admin/pull/120)) [@cshaptx4869](https://github.com/cshaptx4869)
- 支持前端导出([#126](https://github.com/youlaitech/vue3-element-admin/pull/126)) [@cshaptx4869](https://github.com/cshaptx4869)
## ♻️ refactor
- 重构布局样式(解决页面抖动问题)([#116](https://github.com/youlaitech/vue3-element-admin/pull/116)) [@cshaptx4869](https://github.com/cshaptx4869)
- 修改CURD示例编辑弹窗尺寸([#121](https://github.com/youlaitech/vue3-element-admin/pull/121)) [@cshaptx4869](https://github.com/cshaptx4869)
- 统一注册vue插件([#122](https://github.com/youlaitech/vue3-element-admin/pull/122)) [@cshaptx4869](https://github.com/cshaptx4869)
- 默认主题跟随系统([#128](https://github.com/youlaitech/vue3-element-admin/pull/128)) [@cshaptx4869](https://github.com/cshaptx4869)
- 增加"scss.lint.unknownAtRules": "ignore"代码解决style中使用@apply提示unknow at rules@apply提示问题([Gitee#22](https://gitee.com/youlaiorg/vue3-element-admin/pulls/22)) [@zjsy521](https://gitee.com/zjsy521)
## 🐛 fix
- 修复左侧布局移动端菜单弹出样式 ([#117](https://github.com/youlaitech/vue3-element-admin/pull/117)) [@cshaptx4869](https://github.com/cshaptx4869)
- 修复编辑后未清空id再新增菜单覆盖的问题([0e78eeb](https://github.com/youlaitech/vue3-element-admin/commit/0e78eeb75008fa8e9732b1b4e7d7a1ea345c7a1b)) [@haoxianrui](https://github.com/haoxianrui)
- 修复水印层级问题([#123](https://github.com/youlaitech/vue3-element-admin/pull/123)) [@cshaptx4869](https://github.com/cshaptx4869)
- 修复混合布局样式问题([#124](https://github.com/youlaitech/vue3-element-admin/pull/124)) [@cshaptx4869](https://github.com/cshaptx4869)
- 修复关闭弹窗时没有clearValidate问题([#125](https://github.com/youlaitech/vue3-element-admin/pull/125)) [@andm31](https://github.com/andm31)
# 2.11.0 (2024/5/27)
## ✨ feat
- 菜单添加路由参数设置author by [haoxianrui](https://github.com/haoxianrui)
- 增加列表选择组件author by [cshaptx4869](https://github.com/cshaptx4869)
- 增加列表选择组件使用示例author by [cshaptx4869](https://github.com/cshaptx4869)
- 增加defaultToolbar配置参数author by [cshaptx4869](https://github.com/cshaptx4869)
- 表单弹窗支持drawer模式author by [cshaptx4869](https://github.com/cshaptx4869)
- 表单项增加computed和watchEffect配置author by [cshaptx4869](https://github.com/cshaptx4869)
- 支持switch属性修改author by [cshaptx4869](https://github.com/cshaptx4869)
- 表单项增加文本类型支持author by [cshaptx4869](https://github.com/cshaptx4869)
- 列表列增加show配置项author by [cshaptx4869](https://github.com/cshaptx4869)
- 支持搜索表单显隐控制author by [cshaptx4869](https://github.com/cshaptx4869)
- 支持input属性修改author by [cshaptx4869](https://github.com/cshaptx4869)
- search配置新增函数能力拓展author by [xiudaozhe](https://github.com/xiudaozhe)
- 表格新增列设置控制author by [haoxianrui](https://github.com/haoxianrui)
- 搜索添加展开和收缩author by [haoxianrui](https://github.com/haoxianrui)
- watch函数增加配置项参数返回author by [cshaptx4869](https://github.com/cshaptx4869)
## ♻️ refactor
- 重构图标选择组件author by [cshaptx4869](https://github.com/cshaptx4869)
- 重构列表选择组件默认样式 author by [cshaptx4869](https://github.com/cshaptx4869)
- 加强对话框表单组件和列表选择组件author by [cshaptx4869](https://github.com/cshaptx4869)
- routeMeta增加alwaysShow字段声明author by [cshaptx4869](https://github.com/cshaptx4869)
- 分页组件增加溢出滚动效果author by [cshaptx4869](https://github.com/cshaptx4869)
- 修正登录表单的Ref类型author by [cshaptx4869](https://github.com/cshaptx4869)
- 点击表格刷新按钮不重置页码author by [cshaptx4869](https://github.com/cshaptx4869)
- 筛选列超出一定高度滚动author by [cshaptx4869](https://github.com/cshaptx4869)
- 优化加强initFn函数表单项增加initFn函数author by [cshaptx4869](https://github.com/cshaptx4869)
- 重构watch、computed、watchEffect调用author by [cshaptx4869](https://github.com/cshaptx4869)
- 修改操作成功提示author by [cshaptx4869](https://github.com/cshaptx4869)
- PageSearch 改用card作为容器,样式改用unocss写法author by [cshaptx4869](https://github.com/cshaptx4869)
- 优化首页 loading 动画效果author by [haoxianrui](https://github.com/haoxianrui)
## 🐛 fix
- 路由是否始终显示不限制只有顶级目录才有的配置,开放至菜单 author by [haoxianrui](https://github.com/haoxianrui)
- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 author by [haoxianrui](https://github.com/haoxianrui)
- 发送用户重启密码功能最少为6位字符小于6位登陆时不允许的问题 author by [dreamnyj](https://gitee.com/dreamnyj)
- 修复系统设置面板滚动条问题author by [cshaptx4869](https://github.com/cshaptx4869)
- 修复表单插槽失效问题author by [cshaptx4869](https://github.com/cshaptx4869)
- 修改tagsview刷新丢失query问题author by [xiudaozhe](https://github.com/xiudaozhe)
## 📦️ build
- 升级 NPM 包版本至最新 author by [haoxianrui](https://github.com/haoxianrui)
## ⚙️ ci
- 规整脚本执行命令author by [cshaptx4869](https://github.com/cshaptx4869)
# 2.10.1 (2024/5/4)
## ♻️ refactor
- 抽离CURD的使用部分代码为Hooks实现author by [cshaptx4869](https://github.com/cshaptx4869)
- 修改CURD导入权限点标识名author by [cshaptx4869](https://github.com/cshaptx4869)
- cURD表单字段支持watch监听author by [cshaptx4869](https://github.com/cshaptx4869)
- cURD表单input支持number修饰author by [cshaptx4869](https://github.com/cshaptx4869)
- cURD表单组件支持checkbox多选框author by [cshaptx4869](https://github.com/cshaptx4869)
- 优化axios响应数据TS类型提示author by [cshaptx4869](https://github.com/cshaptx4869)
- 修改CURD表单组件自定义类型的attrs传值author by [cshaptx4869](https://github.com/cshaptx4869)
- 同步重置密码按钮权限标识重命名author by [haoxianrui](https://github.com/haoxianrui)
- 重构API为静态方法实现模块化管理并将types.ts重命名为model.ts用于存放接口模型定义author by [haoxianrui](https://github.com/haoxianrui)
## 🐛 fix
- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 author by [haoxianrui](https://github.com/haoxianrui)
- 主题颜色设置覆盖暗黑模式下el-table行激活的背景色问题修复 author by [haoxianrui](https://github.com/haoxianrui)
- 修复因API接口调整而影响的调用页面的问题 author by [haoxianrui](https://github.com/haoxianrui)
## 📦️ build
- 升级 NPM 包版本至最新 author by [haoxianrui](https://github.com/haoxianrui)
# 2.10.0 (2024/4/26)
## ✨ feat
- 封装增删改查组件author by [cshaptx4869](https://github.com/cshaptx4869)
- 集成 vite-plugin-vue-devtools 插件author by [Tricker39](https://github.com/Tricker39)
- 增加CURD配置化实现author by [cshaptx4869](https://github.com/cshaptx4869)
# 2.9.3 (2024/04/14)
## ✨ feat
- 增加vue文件代码片段author by [cshaptx4869](https://github.com/cshaptx4869)
- 菜单 hover 背景色添加值全局SCSS变量进行控制author by [haoxianrui](https://github.com/haoxianrui)
## ♻️ refactor
- 加强基础国际化author by [cshaptx4869](https://github.com/cshaptx4869)
- 增加语言和布局大小枚举类型author by [cshaptx4869](https://github.com/cshaptx4869)
- 增加侧边栏状态枚举类型author by [cshaptx4869](https://github.com/cshaptx4869)
- 使用布局枚举替换字面量author by [haoxianrui](https://github.com/haoxianrui)
- 控制台使用静态数据循环渲染author by [april](mailto:april@zen-game.cn)
- 本地缓存的 token 变量重命名author by [haoxianrui](https://github.com/haoxianrui)
- 完善 Vite 环境变量类型声明author by [haoxianrui](https://github.com/haoxianrui)
## 🐛 fix
- 修复构建时提示iconComponent.name可能为undefined的报错 author by [wangji1042](https://github.com/wangji1042)
- 修复浏览器密码自动填充时可能存在的报错 author by [cshaptx4869](https://github.com/cshaptx4869)
- 修复eslint报错author by [cshaptx4869](https://github.com/cshaptx4869)
- 移动端下点击左侧菜单节点后关闭侧边栏author by [haoxianrui](https://github.com/haoxianrui)
- 添加 size 类型断言修复类型报错author by [haoxianrui](https://github.com/haoxianrui)
## 📦️ build
- husky9.x版本适配 author by [cshaptx4869](https://github.com/cshaptx4869)
- 升级 npm 包版本至最新author by [haoxianrui](https://github.com/haoxianrui)
# 2.9.2 (2024/03/05)
## ✨ feat
- vscode开发扩展推荐author by [cshaptx4869](https://github.com/cshaptx4869)
- 完善基础增删改查Mock接口author by [haoxianrui](https://github.com/haoxianrui)
## ♻️ refactor
- 修改login密码框功能实现author by [cshaptx4869](https://github.com/cshaptx4869)
- 弱化页面进入动画效果author by [cshaptx4869](https://github.com/cshaptx4869)
- 取消推荐TypeScript Vue Plugin author by [cshaptx4869](https://github.com/cshaptx4869)
- 网站加载动画替换 author by [haoxianrui](https://github.com/haoxianrui)
- 优化主题和主题色监听,避免多个页面重复初始化 author by [haoxianrui](https://github.com/haoxianrui)
## 🐛 fix
- AppMain 高度在非固定头部不正确导致出现滚动条问题修复 author by [haoxianrui](https://github.com/haoxianrui)
- 修复混合模式开启固定Head时的样式问题 author by [cshaptx4869](https://github.com/cshaptx4869)
- 设置面板统一字体大小 author by [cshaptx4869](https://github.com/cshaptx4869)
## 📦build
- 通过env配置控制mock服务 author by [cshaptx4869](https://github.com/cshaptx4869)
- 升级依赖包至最新版本 author by [haoxianrui](https://github.com/haoxianrui)
- 定义vite全局常量替换项目标题和版本 author by [cshaptx4869](https://github.com/cshaptx4869)
# 2.9.1 (2024/02/28)
## ♻️ refactor
- 项目配置按钮移入navbarauthor by [cshaptx4869](https://github.com/cshaptx4869)
- 优化user数据定义author by [cshaptx4869](https://github.com/cshaptx4869)
- 统一设置栏的 SVG 图标风格
## 🐛 fix
- 规整一些开发依赖author by [cshaptx4869](https://github.com/cshaptx4869)
- 修复登录页主题切换问题 author by [cshaptx4869](https://github.com/cshaptx4869)
## 🚀 pref
- 压缩图片资源 author by [cshaptx4869](https://github.com/cshaptx4869)
# 2.9.0 (2024/02/25)
## ✨ feat
- 引入 animate.css 动画库
- 新增水印和配置
- 动态路由菜单支持 element plus 的图标
## ♻️ refactor
- Layout 布局重构和相关问题修复
- sass 使用 @use 替代 @import 引入外部文件指令
## 🐛 fix
- 修复管理页面部分弹窗无法打开问题
- 主题颜色设置按钮 hover 等未变化问题修复
# 2.8.1 (2024/01/10)
## ✨ feat
- 替换 Mock 解决方案 vite-plugin-mock 为 vite-plugin-mock-dev-server 适配 Vite5
# 2.8.0 (2023/12/27)
## ⬆️ chore
- 升级 Vite4 至 Vite5
# 2.7.1 (2023/12/12)
## ♻️ refactor
- 将打包后的文件进行分类 author by [ityangzhiwen](https://gitee.com/ityangzhiwen)
# 2.7.0 (2023/11/19)
## ♻️ refactor
- 代码重构优化
- 修改自动导入组件类型声明文件路径
- 完善 typescript 类型
## 🐛 fix
- 修复管理页面部分弹窗无法打开问题
# 2.7.0 (2023/11/19)
## ♻️ refactor
- 代码重构
- 修改自动导入组件类型声明文件路径
- 完善 typescript 类型
## 🐛 fix
- 修复管理页面部分弹窗无法打开问题
# 2.6.3 (2023/10/22)
## ✨ feat
- 菜单管理新增目录只有一级子路由是否始终显示(alwaysShow)和路由页面是否缓存(keepAlive)的配置
- 接口文档新增 swagger、knife4j
- 引入和支持 tsx
## ♻️ refactor
- 代码瘦身,整理并删除未使用的 svg
- 控制台样式优化
## 🐛 fix
- 菜单栏折叠和展开的图标暗黑模式显示问题修复
# 2.6.2 (2023/10/11)
## 🐛 fix
- 主题设置未持久化问题
- UnoCSS 插件无智能提示
## ♻️ refactor
- WebSocket 演示样式和代码优化
- 用户管理代码重构
# 2.6.1 (2023/9/4)
## 🐛 fix
- 导航顶部模式、混合模式样式在固定 Header 出现的样式问题修复
- 固定 Header 没有持久化问题修复
- 字典回显兼容 String 和 Number 类型
# 2.6.0 (2023/8/24)💥💥💥
## ✨ feat
- 导航顶部模式、混合模式支持author by [april-tong](https://april-tong.com/)
- 平台文档(内嵌)author by [april-tong](https://april-tong.com/)
# 2.5.0 (2023/8/8)
## ✨ feat
- 新增 Mockauthor by [ygcaicn](https://github.com/ygcaicn)
- 图标 DEMOauthor by [ygcaicn](https://github.com/ygcaicn)
## 🐛 fix
- 字典支持 Number 类型
# 2.4.1 (2023/7/20)
## ✨ feat
- 整合 vite-plugin-compression 插件打包优化(3.66MB → 1.58MB) author by [april-tong](https://april-tong.com/)
- 字典组件封装author by [haoxr](https://juejin.cn/user/4187394044331261/posts)
## 🐛 fix
- 分页组件hidden无效
- 签名无法保存至后端
- Git 提交 stylelint 校验部分机器报错
# 2.4.0 (2023/6/17)
## ✨ feat
- 新增组件标签输入框author by [april-tong](https://april-tong.com/)
- 新增组件签名author by [april-tong](https://april-tong.com/)
- 新增组件表格author by [april-tong](https://april-tong.com/)
- Echarts 图表添加下载功能 author by [april-tong](https://april-tong.com/)
## ♻️ refactor
- 限制包管理器为 pnpm 和 node 版本16+
- 自定义组件自动导入配置
- 搜索框样式写法优化
## 🐛 fix
- 用户导入的部门回显成数字问题修复
## ⬆️ chore
- element-plus 版本升级 2.3.5 → 2.3.6
# 2.3.1 (2023/5/21)
## 🔄 refactor
- 组件示例文件名称优化
# 2.2.2 (2023/5/11)
## ✨ feat
- 组件封装示例添加源码地址
- 角色、菜单、部门、字段按钮添加权限控制
# 2.3.0 (2023/5/12)
## ⬆️ chore
- 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` 未排除下拉弹出框元素导致无法输入搜索。

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present 有来开源组织
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.

161
README.en-US.md Normal file
View File

@ -0,0 +1,161 @@
<div align="center">
<img src="https://img.shields.io/badge/Vue-3.4.29-brightgreen.svg"/>
<img src="https://img.shields.io/badge/Vite-5.3.1-green.svg"/>
<img src="https://img.shields.io/badge/Element Plus-2.7.5-blue.svg"/>
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
<a href="https://gitee.com/youlaiorg" target="_blank">
<img src="https://img.shields.io/badge/Author-有来开源组织-orange.svg"/>
</a>
<div align="center"> 中文 | <a href="./README.en-US.md">English</div>
</div>
![](https://foruda.gitee.com/images/1708618984641188532/a7cca095_716974.png "rainbow.png")
<div align="center">
<a target="_blank" href="http://vue3.youlai.tech">👀 Live Preview</a> | <a target="_blank" href="https://juejin.cn/post/7228990409909108793">📖 Read Documentation</a>
</div>
## Introduction
[vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) is a free and open-source admin template for backend management frontend, built with popular technologies such as Vue3, Vite5, TypeScript, Element-Plus, and Pinia (with accompanying [backend source code](https://gitee.com/youlaiorg/youlai-boot)).
## Project Features
- **Simple and Easy-to-use**: Upgraded version of [vue-element-admin](https://gitee.com/panjiachen/vue-element-admin) for Vue3, with minimal encapsulation and easy to get started.
- **Data Interaction**: Support both local `Mock` data and remote API. Comes with [Java backend source code](https://gitee.com/youlaiorg/youlai-boot) and online API documentation.
- **Permission Management**: Complete permission system for users, roles, menus, dictionaries, and departments.
- **Essential Infrastructure**: Dynamic routing, button permissions, internationalization, code style, Git commit conventions, and common component encapsulation.
- **Continuous Updates**: Since 2021, the project has maintained an open-source status with continuous updates, integrating new tools and dependencies in real time, and has accumulated a broad user base.
## Project Preview
![Light Mode](https://foruda.gitee.com/images/1709651876583793739/0ba1ee1c_716974.png)
![Dark Mode](https://foruda.gitee.com/images/1709651875494206224/2a2b0b53_716974.png)
![API Documentation](https://foruda.gitee.com/images/1687755822857820115/96054330_716974.png)
## Project Links
| Project | Gitee | Github | GitCode |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Frontend | [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | [vue3-element-admin](https://github.com/youlaitech/vue3-element-admin) | [vue3-element-admin](https://gitcode.net/youlai/vue3-element-admin) |
| Backend | [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) | [youlai-boot](https://github.com/haoxianrui/youlai-boot.git) | [youlai-boot](https://gitcode.net/youlai/youlai-boot) |
## Environment Setup
| Environment | Name and Version | Download Link |
| -------------------- | :----------------------------------------------------------- | ------------------------------------------------------------ |
| **Development Tool** | VSCode | [Download](https://code.visualstudio.com/Download) |
| **Runtime Environment** | Node ≥18 | [Download](http://nodejs.cn/download) |
## Project Setup
```bash
# Clone the repository
git clone https://gitee.com/youlaiorg/vue3-element-admin.git
# Change directory
cd vue3-element-admin
# Install pnpm
npm install pnpm -g
# Install dependencies
pnpm install
# Start the project
pnpm run dev
```
## Project Deployment
```bash
# Build the project
pnpm run build
# Upload files to the remote server
Copy the files generated in the `dist` directory to the `/usr/share/nginx/html` directory.
# nginx.cofig configuration
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# Reverse proxy configuration
location /prod-api/ {
proxy_pass http://vapi.youlai.tech/; # Replace vapi.youlai.tech with your backend API address
}
}
```
## Local Mock
The project supports both online API and local mock API. By default, it uses the online API. If you want to switch to the mock API, modify the value of `VITE_MOCK_DEV_SERVER` in the `.env.development` file to `true`.
## Backend API
> If you have a basic understanding of Java development, follow these steps to convert online API to local backend API and set up a full-stack development environment.
1. Get the backend source code based on `Java` and `SpringBoot` from [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git).
2. Follow the instructions in the backend project's README.md to set up the local environment.
3. Modify the value of `VITE_APP_API_URL` in the `.env.development` file to `http://localhost:8989`, replacing it with the backend API URL.
## Notes
- **Auto import plugin is disabled by default**
Component type declarations have been automatically generated for the template project. If you add and use new components, follow the instructions in the screenshot to enable automatic generation. After automatic generation is complete, remember to set it back to `false` to avoid conflicts.
![](https://foruda.gitee.com/images/1687755823137387608/412ea803_716974.png)
- **Blank page when accessing the project**
Try upgrading your browser, as older browser engines may not support certain new JavaScript syntax, such as optional chaining operator `?.`.
- **Red highlight on project components, functions, and imports**
Restart VSCode to try again.
- **Other issues**
If you have any other issues or suggestions, please open an [issue](https://gitee.com/youlaiorg/vue3-element-admin/issues/new).
## Project Documentation
- [Building a Backend Management System from Scratch with Vue3, Vite, TypeScript, and Element-Plus](https://blog.csdn.net/u013737132/article/details/130191394)
- [ESLint+Prettier+Stylelint+EditorConfig for Standardized and Unified Frontend Code Style](https://blog.csdn.net/u013737132/article/details/130190788)
- [Git Commit Conventions with Husky, Lint-staged, Commitlint, Commitizen, and cz-git](https://blog.csdn.net/u013737132/article/details/130191363)
## Commit Conventions
Execute `pnpm run commit` to invoke interactive git commit and complete the information input and selection according to the prompts.
![](https://foruda.gitee.com/images/1687755823165218215/c1705416_716974.png)
## Community 🚀
> **Follow "Youlai Tech" WeChat Official Account to get the QR code for the community.**
>
> If the QR code for the community has expired, please add my WeChat (haoxianrui) and indicate whether you are interested in "Frontend", "Backend", or "Full Stack" to get the latest QR code.
>
> This measure is taken to ensure the quality of the community and prevent marketing advertising from infiltrating. Thank you for your understanding!
| Official Account | Community |
|:----:|:----:|
| ![Youlai Tech WeChat Official Account QR Code](https://foruda.gitee.com/images/1687689212187063809/3c69eaee_716974.png) | ![Community QR Code](https://foruda.gitee.com/images/1687689212139273561/6a65ef69_716974.png) |

182
README.md Normal file
View File

@ -0,0 +1,182 @@
<div align="center">
<img src="https://img.shields.io/badge/Vue-3.4.29-brightgreen.svg"/>
<img src="https://img.shields.io/badge/Vite-5.3.1-green.svg"/>
<img src="https://img.shields.io/badge/Element Plus-2.7.5-blue.svg"/>
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
<a href="https://gitee.com/youlaiorg" target="_blank">
<img src="https://img.shields.io/badge/Author-有来开源组织-orange.svg"/>
</a>
<div align="center"> 中文 | <a href="./README.en-US.md">English</div>
</div>
![](https://foruda.gitee.com/images/1708618984641188532/a7cca095_716974.png "rainbow.png")
<div align="center">
<a target="_blank" href="http://vue3.youlai.tech">👀 在线预览</a> | <a target="_blank" href="https://juejin.cn/post/7228990409909108793">📖 阅读文档</a>
</div>
## 项目简介
[vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) 是基于 Vue3 + Vite5+ TypeScript5 + Element-Plus + Pinia 等主流技术栈构建的免费开源的后台管理前端模板(配套[后端源码](https://gitee.com/youlaiorg/youlai-boot))。
## 项目特色
- **简洁易用**:基于 [vue-element-admin](https://gitee.com/panjiachen/vue-element-admin) 升级的 Vue3 版本,无过渡封装 ,易上手。
- **数据交互**:同时支持本地 `Mock` 和线上接口,配套 [Java 后端源码](https://gitee.com/youlaiorg/youlai-boot)和[在线接口文档](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5)。
- **权限管理**:用户、角色、菜单、字典、部门等完善的权限系统功能。
- **基础设施**动态路由、按钮权限、国际化、代码规范、Git 提交规范、常用组件封装。
- **持续更新**:项目持续开源更新,实时更新工具和依赖。
## 项目预览
![明亮模式](https://foruda.gitee.com/images/1709651876583793739/0ba1ee1c_716974.png)
![暗黑模式](https://foruda.gitee.com/images/1709651875494206224/2a2b0b53_716974.png)
![接口文档](https://foruda.gitee.com/images/1687755822857820115/96054330_716974.png)
## 项目地址
| 项目 | Gitee | Github |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 前端 | [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | [vue3-element-admin](https://github.com/youlaitech/vue3-element-admin) | [vue3-element-admin](https://gitcode.net/youlai/vue3-element-admin) |
| 精简版 | [vue3-element-admin-thin](https://gitee.com/cshaptx4869/vue3-element-admin-thin) | [vue3-element-admin-thin](https://github.com/youlaitech/vue3-element-admin-thin) |
| 后端 | [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) | [youlai-boot](https://github.com/haoxianrui/youlai-boot.git) |
## 环境准备
| 环境 | 名称版本 | 下载地址 |
| -------------------- | :----------------------------------------------------------- | ------------------------------------------------------------ |
| **开发工具** | VSCode | [下载](https://code.visualstudio.com/Download) |
| **运行环境** | Node ≥18 (其中 20.6.0 版本不可用) | [下载](http://nodejs.cn/download) |
## 项目启动
```bash
# 克隆代码
git clone https://gitee.com/youlaiorg/vue3-element-admin.git
# 切换目录
cd vue3-element-admin
# 安装 pnpm
npm install pnpm -g
# 安装依赖
pnpm install
# 启动运行
pnpm run dev
```
## 项目部署
```bash
# 项目打包
pnpm run build
# 上传文件至远程服务器
将打包生成在 `dist` 目录下的文件拷贝至 `/usr/share/nginx/html` 目录
# nginx.cofig 配置
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# 反向代理配置
location /prod-api/ {
# vapi.youlai.tech 替换后端API地址注意保留后面的斜杠 /
proxy_pass http://vapi.youlai.tech/;
}
}
```
## 本地Mock
项目同时支持在线和本地 Mock 接口,默认使用线上接口,如需替换为 Mock 接口,修改文件 `.env.development``VITE_MOCK_DEV_SERVER``true` **即可**
## 后端接口
> 如果您具备Java开发基础按照以下步骤将在线接口转为本地后端接口创建企业级前后端分离开发环境助您走向全栈之路。
1. 获取基于 `Java``SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码。
2. 根据后端工程的说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动。
3. 修改 `.env.development` 文件中的 `VITE_APP_API_URL` 的值,将其从 http://vapi.youlai.tech 更改为 http://localhost:8989。
## 注意事项
- **自动导入插件自动生成默认关闭**
模板项目的组件类型声明已自动生成。如果添加和使用新的组件,请按照图示方法开启自动生成。在自动生成完成后,记得将其设置为 `false`,避免重复执行引发冲突。
![](https://foruda.gitee.com/images/1687755823137387608/412ea803_716974.png)
- **项目启动浏览器访问空白**
请升级浏览器尝试,低版本浏览器内核可能不支持某些新的 JavaScript 语法,比如可选链操作符 `?.`
- **项目同步仓库更新升级**
项目同步仓库更新升级之后,建议 `pnpm install` 安装更新依赖之后启动 。
- **项目组件、函数和引用爆红**
重启 VSCode 尝试
- **其他问题**
如果有其他问题或者建议,建议 [ISSUE](https://gitee.com/youlaiorg/vue3-element-admin/issues/new)
## 项目文档
- [基于 Vue3 + Vite + TypeScript + Element-Plus 从0到1搭建后台管理系统](https://blog.csdn.net/u013737132/article/details/130191394)
- [ESLint+Prettier+Stylelint+EditorConfig 约束和统一前端代码规范](https://blog.csdn.net/u013737132/article/details/130190788)
- [Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交规范](https://blog.csdn.net/u013737132/article/details/130191363)
## 提交规范
执行 `pnpm run commit` 唤起 git commit 交互,根据提示完成信息的输入和选择。
![](https://foruda.gitee.com/images/1687755823165218215/c1705416_716974.png)
## 项目统计
![Alt](https://repobeats.axiom.co/api/embed/aa7cca3d6fa9c308fc659fa6e09af9a1910506c3.svg "Repobeats analytics image")
Thanks to all the contributors!
[![contributors](https://contrib.rocks/image?repo=youlaitech/vue3-element-admin)](https://github.com/youlaitech/vue3-element-admin/graphs/contributors)
## 交流群🚀
> **关注「有来技术」公众号,获取交流群二维码。**
>
> 如果交流群的二维码过期,请加微信(haoxianrui)并备注「前端」、「后端」或「全栈」以获取最新二维码。
>
> 为确保交流群质量,防止营销广告人群混入,我们采取了此措施。望各位理解!
| 公众号 | 交流群 |
|:----:|:----:|
| ![有来技术公众号二维码](https://foruda.gitee.com/images/1687689212187063809/3c69eaee_716974.png) | ![交流群二维码](https://foruda.gitee.com/images/1687689212139273561/6a65ef69_716974.png) |

93
commitlint.config.cjs Normal file
View File

@ -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: "文档: 📝 文档变更(更新README文件或者注释)", emoji: ":memo:" },
{ value: "style", name: "格式: 🌈 代码格式(空格、格式化、缺失的分号等)", emoji: ":lipstick:" },
{ value: "refactor", name: "重构: 🔄 代码重构(不修复错误也不添加特性的代码更改)", 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: "",
},
};

61
index.html Normal file
View File

@ -0,0 +1,61 @@
<!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="Vue3 + Vite5 + TypeScript5 + Element-Plus 的后台管理模板配套接口文档和后端源码vue-element-admin 的 Vue3 版本"
/>
<meta
name="keywords"
content="vue,element-plus,typescript,vue-element-admin,vue3-element-admin"
/>
<title>vue3-element-admin</title>
</head>
<body>
<div id="app">
<div class="loader"></div>
</div>
</body>
<script type="module" src="/src/main.ts"></script>
<style>
html,
body,
#app {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.loader {
--d: 22px;
width: 4px;
height: 4px;
color: #25b09b;
border-radius: 50%;
box-shadow:
calc(1 * var(--d)) calc(0 * var(--d)) 0 0,
calc(0.707 * var(--d)) calc(0.707 * var(--d)) 0 1px,
calc(0 * var(--d)) calc(1 * var(--d)) 0 2px,
calc(-0.707 * var(--d)) calc(0.707 * var(--d)) 0 3px,
calc(-1 * var(--d)) calc(0 * var(--d)) 0 4px,
calc(-0.707 * var(--d)) calc(-0.707 * var(--d)) 0 5px,
calc(0 * var(--d)) calc(-1 * var(--d)) 0 6px;
animation: l27 1s infinite steps(8);
}
@keyframes l27 {
100% {
transform: rotate(1turn);
}
}
</style>
</html>

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-present PanJiaChen
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.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present 有来开源组织
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.

43
mock/auth.mock.ts Normal file
View File

@ -0,0 +1,43 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "auth/captcha",
method: ["GET"],
body: {
code: "00000",
data: {
captchaKey: "534b8ef2b0a24121bec76391ddd159f9",
captchaBase64:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAAkCAIAAADNSmkJAAAFKUlEQVR4Xu2ZXUwcVRiGV70wMWo08V5NvPXCrDbFaGpMaZW2hqQxaoiJTRsaMBCNSYtpa2JTKiFSelFa+Q/QZcMWqEhBlh+htbEpZhMrBQrlJ0hBywLLyrJ0WZbje3bqOvPNLHPWrDvdOE9ONmfe78zkzMs335wzWJhJQrBQweS/wTQ6QWgYHdoIOcecOe05O+t2WkutO+p2ZF3Ksg/YV9ZW6FATYajR3nveg60H9327r3O8c35lHgp+r05dPdJzBL73TPSQ8SaCKIxGLsPlop+K0JHrEkPuoT31e5qGmmjARACF0agYyGVNlyVm/pzZXrN9fHGcBkz0UBid+31u93i3XFFT80vN8cvHqWqih8Lo1NpUqS5vwh3vnd223VQ10UNh9NbyrcFQUK6oCawHUipSqGqiB83oBf+CXFGDMp1mS6OqiR4Ko7FexkpOrqhpHGw82nOUqiZ6KIzGrkRuorW0dJMmOy+hOCfYGzb2RBFv6HRO0gEJw/U7y+pgL1bwmTxexN6sZ31TdEwEhdG+gA+7EqyXpUO1uZH20cWL8hMTRt1N9tBXzCJrOIRoCPJpSO2RAp4HmtCdIfZ+2JWgEBN9LbR28seTGU0Zue1tMLp+YIAMSADzfvbkKX4/eb28j4YODiGin3heqmIlLja5hAUCu+nmGY3JWKvpMAlqNGgebsauBOvlqSX+JEx7p7EbTLen53XlzfmWUioqXikrc68Y8N2juJ/fyVsNChGHEE//rBANYWaZz+TRQqpLaBgNsPfDrgSpbS21YtV87IdjrlkX9JZbt5DOma2t9ITo5F+5glN22WwL/n+yDv00mw06orKxOqQ5+J04hhViwzAXETIcJDVm8uxZqktoGx2Nj9t43Wgaul/ERQiGQvtbWnDWgZYW9CXlQFjZ/7ciyHNn+Z2MexTimIeLz59TiIln0M1e+IbPpOAaDUnEYPTi6iqKxpbycs/qKo1tCslfKcffPn9enuMiPPY1vxO/ckeFQ4h46cdGqUWoidE/y54q5tPY5WDrGzQqIXot4BgchEE57e00IMCw2/1qZSVO/7SjA78o9INzcxsbrL+fnTnDDh9mmZn8F30oG1Hm+nABv5mQMopDS/h1HxtqTzWbABMe9sxpPoe9zezeOo1GELqWhPS8t46M0IAYHbdvR1aHbaOjbjfLz2eFhez6dba4yAfgF30o0BFVE8+Mjh/wFxPI+I5mAEHU6Ls+38vhTFwOBGhMDF8gkFpbC5ffsdv/uBs6dIj19dExEtARVXv9YNbop8NFY3aZ6gRRo+tu3IBHnzmdNCBMXldXJKPfL74WzWUJRE+coDUknqsOdZXQbAJYwluVTbOZI3Qt8GFzMwxyjo3RgBiN4fr+elXVpZGRLWXl6PdOTtJBSlBDUK/lnIrjOlrtqWYTQDJaF6FrTXu9sOa1ysrVoM5HVE1GFxZQcyJ/p+xzv6K/rbr6N6+XDpUBl0tKFIrbz78qWB6YnWFMCBld4XLBms+7df75ook/GNzb0GCV7U1Qfz9p64TyQWNjYD3qe9rj4SMJtQP3MyjSDPzWIRHPjH7X4YAvfXoPuyZf9Pbi3PcuXIh4mp3NllYC6XY79C+jl2o8PBipxjnBttn4MgMNnWgfcRJGPI2OL8hTj3LloIlmRicvBhiNykvecpqoa3RSY4DRcLAwyicuOepVR1JjgNFYHWONHL04czTX0UmNAUYD7Pr+xc4wqTHGaBb2OtZvHUmNYUazcA2J6etdUmOk0f8rTKMTxF91RG0D1SwYGwAAAABJRU5ErkJggg==",
},
msg: "一切ok",
},
},
{
url: "auth/login",
method: ["POST"],
body: {
code: "00000",
data: {
accessToken:
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImp0aSI6IjE2YWJkNTlkOTAxNzQwZDliYmI3ZjczODBhZDkyNzNhIiwidXNlcklkIjoyLCJ1c2VybmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJkYXRhU2NvcGUiOjEsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwiZXhwIjoxNjkxMTAzMzgyfQ.P4cuIfmPepl3HuguhMS7NXn5a7IUPpsLbmtA_rHOhHk",
tokenType: "Bearer",
refreshToken: null,
expires: null,
},
msg: "一切ok",
},
},
{
url: "auth/logout",
method: ["DELETE"],
body: {
code: "00000",
data: {},
msg: "string",
},
},
]);

10
mock/base.ts Normal file
View File

@ -0,0 +1,10 @@
import path from "path";
import { createDefineMock } from "vite-plugin-mock-dev-server";
export const defineMock = createDefineMock((mock) => {
// 拼接url
mock.url = path.join(
import.meta.env.VITE_APP_BASE_API + "/api/v1/",
mock.url
);
});

153
mock/dept.mock.ts Normal file
View File

@ -0,0 +1,153 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "dept/options",
method: ["GET"],
body: {
code: "00000",
data: [
{
value: 1,
label: "有来技术",
children: [
{
value: 2,
label: "研发部门",
},
{
value: 3,
label: "测试部门",
},
],
},
],
msg: "一切ok",
},
},
{
url: "dept",
method: ["GET"],
body: {
code: "00000",
data: [
{
id: 1,
parentId: 0,
name: "有来技术",
code: "YOULAI",
sort: 1,
status: 1,
children: [
{
id: 2,
parentId: 1,
name: "研发部门",
code: "RD001",
sort: 1,
status: 1,
children: [],
createTime: null,
updateTime: "2022-04-19 12:46",
},
{
id: 3,
parentId: 1,
name: "测试部门",
code: "QA001",
sort: 1,
status: 1,
children: [],
createTime: null,
updateTime: "2022-04-19 12:46",
},
],
createTime: null,
updateTime: null,
},
],
msg: "一切ok",
},
},
// 新增部门
{
url: "dept",
method: ["POST"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "新增部门" + body.name + "成功",
};
},
},
// 获取部门表单数据
{
url: "dept/:id/form",
method: ["GET"],
body: ({ params }) => {
return {
code: "00000",
data: deptMap[params.id],
msg: "一切ok",
};
},
},
// 修改部门
{
url: "dept/:id",
method: ["PUT"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "修改部门" + body.name + "成功",
};
},
},
// 删除部门
{
url: "dept/:id",
method: ["DELETE"],
body({ params }) {
return {
code: "00000",
data: null,
msg: "删除部门" + params.id + "成功",
};
},
},
]);
// 部门映射表数据
const deptMap: Record<string, any> = {
1: {
id: 1,
name: "有来技术",
code: "YOULAI",
parentId: 0,
status: 1,
sort: 1,
},
2: {
id: 2,
name: "研发部门",
code: "RD001",
parentId: 1,
status: 1,
sort: 1,
},
3: {
id: 3,
name: "测试部门",
code: "QA001",
parentId: 1,
status: 1,
sort: 1,
},
};

168
mock/dict.mock.ts Normal file
View File

@ -0,0 +1,168 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "dict/:code/options",
method: ["GET"],
body: ({ params }) => {
const code = params.code;
let list = null;
if (code == "gender") {
list = [
{
value: "1",
label: "男",
},
{
value: "2",
label: "女",
},
{
value: "0",
label: "保密",
},
];
}
return {
code: "00000",
data: list,
msg: "一切ok",
};
},
},
{
url: "dict/page",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 1,
name: "性别",
code: "gender",
status: 1,
dictItems: [
{
id: 1,
name: "男",
value: "1",
sort: 1,
status: 1,
},
{
id: 2,
name: "女",
value: "2",
sort: 2,
status: 1,
},
{
id: 3,
name: "保密",
value: "0",
sort: 3,
status: 1,
},
],
},
],
total: 1,
},
msg: "一切ok",
},
},
// 新增字典
{
url: "dict",
method: ["POST"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "新增字典" + body.name + "成功",
};
},
},
// 获取字典表单数据
{
url: "dict/:id/form",
method: ["GET"],
body: ({ params }) => {
return {
code: "00000",
data: dictMap[params.id],
msg: "一切ok",
};
},
},
// 修改字典
{
url: "dict/:id",
method: ["PUT"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "修改字典" + body.name + "成功",
};
},
},
// 删除字典
{
url: "dict/:id",
method: ["DELETE"],
body({ params }) {
return {
code: "00000",
data: null,
msg: "删除字典" + params.id + "成功",
};
},
},
]);
// 字典映射表数据
const dictMap: Record<string, any> = {
1: {
code: "00000",
data: {
id: 1,
name: "性别",
code: "gender",
status: 1,
dictItems: [
{
id: 1,
name: "男",
value: "1",
sort: 1,
status: 1,
},
{
id: 2,
name: "女",
value: "2",
sort: 2,
status: 1,
},
{
id: 3,
name: "未知",
value: "0",
sort: 3,
status: 1,
},
],
},
msg: "一切ok",
},
};

225
mock/log.mock.ts Normal file
View File

@ -0,0 +1,225 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "logs/page",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 36192,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 5,
createBy: null,
createTime: "2024-07-07 20:38:47",
operator: "系统管理员",
},
{
id: 36190,
module: "字典",
content: "字典分页列表",
requestUri: "/api/v1/dict/page",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 9,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36193,
module: "部门",
content: "部门列表",
requestUri: "/api/v1/dept",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 27,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36191,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 39,
createBy: null,
createTime: "2024-07-07 20:38:44",
operator: "系统管理员",
},
{
id: 36189,
module: "角色",
content: "角色分页列表",
requestUri: "/api/v1/roles/page",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 55,
createBy: null,
createTime: "2024-07-07 20:38:43",
operator: "系统管理员",
},
{
id: 36188,
module: "用户",
content: "用户分页列表",
requestUri: "/api/v1/users/page",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 92,
createBy: null,
createTime: "2024-07-07 20:38:42",
operator: "系统管理员",
},
{
id: 36187,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19340,
createBy: null,
createTime: "2024-07-07 20:38:09",
operator: "系统管理员",
},
{
id: 36186,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19869,
createBy: null,
createTime: "2024-07-07 20:37:59",
operator: "系统管理员",
},
{
id: 36185,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "112.103.111.59",
region: "黑龙江省 哈尔滨市",
browser: "Chrome 97.0.4692.98",
os: "Android",
executionTime: 96,
createBy: null,
createTime: "2024-07-07 20:37:21",
operator: "系统管理员",
},
{
id: 36184,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "114.86.204.190",
region: "上海 上海市",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 89,
createBy: null,
createTime: "2024-07-07 20:29:37",
operator: "系统管理员",
},
],
total: 36188,
},
msg: "一切ok",
},
},
{
url: "logs/visit-trend",
method: ["GET"],
body: {
code: "00000",
data: {
dates: [
"2024-06-30",
"2024-07-01",
"2024-07-02",
"2024-07-03",
"2024-07-04",
"2024-07-05",
"2024-07-06",
"2024-07-07",
],
pvList: [1751, 5168, 4882, 5301, 4721, 4885, 1901, 1003],
uvList: null,
ipList: [207, 566, 565, 631, 579, 496, 222, 152],
},
msg: "一切ok",
},
},
{
url: "logs/visit-stats",
method: ["GET"],
body: {
code: "00000",
data: [
{
type: "pv",
title: "浏览量",
todayCount: 1003,
totalCount: 36193,
growthRate: -0.35,
granularityLabel: "日",
},
{
type: "uv",
title: "访客数",
todayCount: 100,
totalCount: 2000,
growthRate: 0,
granularityLabel: "日",
},
{
type: "ip",
title: "IP数",
todayCount: 152,
totalCount: 3234,
growthRate: -0.2,
granularityLabel: "日",
},
],
msg: "一切ok",
},
},
]);

1620
mock/menu.mock.ts Normal file

File diff suppressed because it is too large Load Diff

335
mock/role.mock.ts Normal file
View File

@ -0,0 +1,335 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "roles/options",
method: ["GET"],
body: {
code: "00000",
data: [
{
value: 2,
label: "系统管理员",
},
{
value: 4,
label: "系统管理员1",
},
{
value: 5,
label: "系统管理员2",
},
{
value: 6,
label: "系统管理员3",
},
{
value: 7,
label: "系统管理员4",
},
{
value: 8,
label: "系统管理员5",
},
{
value: 9,
label: "系统管理员6",
},
{
value: 10,
label: "系统管理员7",
},
{
value: 11,
label: "系统管理员8",
},
{
value: 12,
label: "系统管理员9",
},
{
value: 3,
label: "访问游客",
},
],
msg: "一切ok",
},
},
{
url: "roles/page",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 2,
name: "系统管理员",
code: "ADMIN",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 3,
name: "访问游客",
code: "GUEST",
status: 1,
sort: 3,
createTime: "2021-05-26 15:49:05",
updateTime: "2019-05-05 16:00:00",
},
{
id: 4,
name: "系统管理员1",
code: "ADMIN1",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 5,
name: "系统管理员2",
code: "ADMIN2",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 6,
name: "系统管理员3",
code: "ADMIN3",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 7,
name: "系统管理员4",
code: "ADMIN4",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 8,
name: "系统管理员5",
code: "ADMIN5",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 9,
name: "系统管理员6",
code: "ADMIN6",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: "2023-12-04 11:43:15",
},
{
id: 10,
name: "系统管理员7",
code: "ADMIN7",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 11,
name: "系统管理员8",
code: "ADMIN8",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
],
total: 10,
},
msg: "一切ok",
},
},
// 新增角色
{
url: "roles",
method: ["POST"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "新增角色" + body.name + "成功",
};
},
},
// 获取角色表单数据
{
url: "roles/:id/form",
method: ["GET"],
body: ({ params }) => {
return {
code: "00000",
data: roleMap[params.id],
msg: "一切ok",
};
},
},
// 修改角色
{
url: "roles/:id",
method: ["PUT"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "修改角色" + body.name + "成功",
};
},
},
// 删除角色
{
url: "roles/:id",
method: ["DELETE"],
body({ params }) {
return {
code: "00000",
data: null,
msg: "删除角色" + params.id + "成功",
};
},
},
// 获取角色拥有的菜单ID
{
url: "roles/:id/menuIds",
method: ["GET"],
body: ({ params }) => {
return {
code: "00000",
data: [
1, 2, 31, 32, 33, 88, 3, 70, 71, 72, 4, 73, 75, 74, 5, 76, 77, 78, 6,
79, 81, 84, 85, 86, 87, 40, 41, 26, 30, 20, 21, 22, 23, 24, 89, 90,
91, 36, 37, 38, 39, 93, 94, 95, 97, 102, 89, 90, 91, 93, 94, 95, 97,
102, 103, 104,
],
msg: "一切ok",
};
},
},
// 保存角色菜单
{
url: "roles/:id/menus",
method: ["PUT"],
body: {
code: "00000",
data: null,
msg: "一切ok",
},
},
]);
// 角色映射表数据
const roleMap: Record<string, any> = {
2: {
id: 2,
name: "系统管理员",
code: "ADMIN",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
3: {
id: 3,
name: "访问游客",
code: "GUEST",
status: 1,
sort: 3,
createTime: "2021-05-26 15:49:05",
updateTime: "2019-05-05 16:00:00",
},
4: {
id: 4,
name: "系统管理员1",
code: "ADMIN1",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
5: {
id: 5,
name: "系统管理员2",
code: "ADMIN2",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
6: {
id: 6,
name: "系统管理员3",
code: "ADMIN3",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
7: {
id: 7,
name: "系统管理员4",
code: "ADMIN4",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
8: {
id: 8,
name: "系统管理员5",
code: "ADMIN5",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
9: {
id: 9,
name: "系统管理员6",
code: "ADMIN6",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: "2023-12-04 11:43:15",
},
10: {
id: 10,
name: "系统管理员7",
code: "ADMIN7",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
11: {
id: 11,
name: "系统管理员8",
code: "ADMIN8",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
};

189
mock/user.mock.ts Normal file
View File

@ -0,0 +1,189 @@
import { defineMock } from "./base";
export default defineMock([
{
url: "users/me",
method: ["GET"],
body: {
code: "00000",
data: {
userId: 2,
nickname: "系统管理员",
username: "admin",
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
roles: ["ROOT"],
perms: [
"sys:menu:delete",
"sys:dept:edit",
"sys:dict_type:add",
"sys:dict:edit",
"sys:dict:delete",
"sys:dict_type:edit",
"sys:menu:add",
"sys:user:add",
"sys:role:edit",
"sys:dept:delete",
"sys:user:edit",
"sys:user:delete",
"sys:user:password:reset",
"sys:dept:add",
"sys:role:delete",
"sys:dict_type:delete",
"sys:menu:edit",
"sys:dict:add",
"sys:role:add",
"sys:user:query",
"sys:user:export",
],
},
msg: "一切ok",
},
},
{
url: "users/page",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 2,
username: "admin",
nickname: "系统管理员",
mobile: "17621210366",
gender: 1,
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
email: "",
status: 1,
deptId: 1,
roleIds: [2],
},
{
id: 3,
username: "test",
nickname: "测试小用户",
mobile: "17621210366",
gender: 1,
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
email: "youlaitech@163.com",
status: 1,
deptId: 3,
roleIds: [3],
},
],
total: 2,
},
msg: "一切ok",
},
},
// 新增用户
{
url: "users",
method: ["POST"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "新增用户" + body.nickname + "成功",
};
},
},
// 获取用户表单数据
{
url: "users/:userId/form",
method: ["GET"],
body: ({ params }) => {
return {
code: "00000",
data: userMap[params.userId],
msg: "一切ok",
};
},
},
// 修改用户
{
url: "users/:userId",
method: ["PUT"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "修改用户" + body.nickname + "成功",
};
},
},
// 删除用户
{
url: "users/:userId",
method: ["DELETE"],
body({ params }) {
return {
code: "00000",
data: null,
msg: "删除用户" + params.id + "成功",
};
},
},
// 重置密码
{
url: "users/:userId/password",
method: ["PATCH"],
body({ query }) {
return {
code: "00000",
data: null,
msg: "重置密码成功,新密码为:" + query.password,
};
},
},
// 导出Excel
{
url: "users/_export",
method: ["GET"],
headers: {
"Content-Disposition":
"attachment; filename=%E7%94%A8%E6%88%B7%E5%88%97%E8%A1%A8.xlsx",
"Content-Type":
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
},
},
]);
// 用户映射表数据
const userMap: Record<string, any> = {
2: {
id: 2,
username: "admin",
nickname: "系统管理员",
mobile: "17621210366",
gender: 1,
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
email: "",
status: 1,
deptId: 1,
roleIds: [2],
},
3: {
id: 3,
username: "test",
nickname: "测试小用户",
mobile: "17621210366",
gender: 1,
avatar:
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
email: "youlaitech@163.com",
status: 1,
deptId: 3,
roleIds: [3],
},
};

133
package.json Normal file
View File

@ -0,0 +1,133 @@
{
"name": "在生万有货场ERP后台",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit & vite build",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"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 --allow-empty-input",
"lint:lint-staged": "lint-staged",
"preinstall": "npx only-allow pnpm",
"prepare": "husky",
"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 --allow-empty-input"
],
"*.{scss,css}": [
"stylelint --fix --allow-empty-input",
"prettier --write"
],
"*.md": [
"prettier --write"
]
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^10.11.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "5.1.10",
"animate.css": "^4.1.1",
"axios": "^1.7.2",
"color": "^4.2.3",
"echarts": "^5.5.1",
"element-plus": "^2.7.6",
"exceljs": "^4.4.0",
"json-bigint": "^1.0.0",
"lodash-es": "^4.17.21",
"net": "^1.0.2",
"nprogress": "^0.2.0",
"path-browserify": "^1.0.1",
"path-to-regexp": "^6.2.2",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"sockjs-client": "1.6.1",
"sortablejs": "^1.15.2",
"stompjs": "^2.3.3",
"underscore": "^1.13.7",
"vue": "^3.4.31",
"vue-i18n": "9.9.1",
"vue-router": "^4.4.0",
"vue3-license-plate": "^1.0.2",
"ws": "^8.18.0"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.6.3",
"@iconify-json/ep": "^1.1.15",
"@types/color": "^3.0.6",
"@types/lodash": "^4.17.6",
"@types/node": "^20.14.10",
"@types/nprogress": "^0.2.3",
"@types/path-browserify": "^1.0.2",
"@types/sockjs-client": "^1.5.4",
"@types/sortablejs": "^1.15.8",
"@types/stompjs": "^2.3.9",
"@types/underscore": "^1.11.15",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.19",
"commitizen": "^4.3.0",
"cz-git": "^1.9.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.27.0",
"fast-glob": "^3.3.2",
"husky": "^9.0.11",
"lint-staged": "^15.2.7",
"postcss": "^8.4.39",
"postcss-html": "^1.7.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.3.2",
"sass": "^1.77.6",
"stylelint": "^16.6.1",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended-scss": "^14.0.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^36.0.1",
"terser": "^5.31.1",
"typescript": "^5.5.3",
"unocss": "^0.58.9",
"unplugin-auto-import": "^0.17.6",
"unplugin-icons": "^0.18.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.3.3",
"vite-plugin-mock-dev-server": "^1.5.1",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-devtools": "^7.3.5",
"vue-tsc": "^2.0.26"
},
"repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
"author": "有来开源组织",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"packageManager": "pnpm@9.1.3+sha512.7c2ea089e1a6af306409c4fc8c4f0897bdac32b772016196c469d9428f1fe2d5a21daf8ad6512762654ac645b5d9136bb210ec9a00afa8dbc4677843ba362ecd"
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

37
src/App.vue Normal file
View File

@ -0,0 +1,37 @@
<template>
<el-config-provider :locale="locale" :size="size">
<!-- 开启水印 -->
<el-watermark
v-if="watermarkEnabled"
:font="{ color: fontColor }"
:content="defaultSettings.watermarkContent"
:z-index="9999"
class="wh-full"
>
<router-view />
</el-watermark>
<!-- 关闭水印 -->
<router-view v-else />
</el-config-provider>
</template>
<script setup lang="ts">
import { useAppStore, useSettingsStore } from "@/store";
import defaultSettings from "@/settings";
import { ThemeEnum } from "@/enums/ThemeEnum";
import { SizeEnum } from "@/enums/SizeEnum";
const appStore = useAppStore();
const settingsStore = useSettingsStore();
const locale = computed(() => appStore.locale);
const size = computed(() => appStore.size as SizeEnum);
const watermarkEnabled = computed(() => settingsStore.watermarkEnabled);
// /
const fontColor = computed(() => {
return settingsStore.theme === ThemeEnum.DARK
? "rgba(255, 255, 255, .15)"
: "rgba(0, 0, 0, .15)";
});
</script>

81
src/api/auth.ts Normal file
View File

@ -0,0 +1,81 @@
import request from "@/utils/request";
import { MenuVO } from "./menu";
import { UserForm } from "./user";
const AUTH_BASE_URL = "/api";
class AuthAPI {
/** 登录 接口*/
static login(data: LoginData) {
return request<any, LoginResult>({
url: `/api/user/loginPhone`,
method: "get",
params: data,
});
}
/** 注销 接口*/
static logout() {
return request({
url: `/api/user/logOut`,
method: "POST",
});
}
/** 获取验证码 接口*/
static getCaptcha(data: { phone: string }) {
return request<any, CaptchaResult>({
url: `/api/user/sendMsg`,
method: "get",
params: data,
});
}
// 查询手机号绑定货场
static getCommonDbPhone(data: { phone: string }) {
return request<any, DbPhoneResult[]>({
url: `/api/db/getCommonDbPhone`,
method: "get",
params: data,
});
}
}
export default AuthAPI;
/** 登录请求参数 */
export interface LoginData {
/** 用户名 */
phone: string;
/** 密码 */
code: string;
}
/** 登录响应 */
export interface LoginResult {
/** 访问token */
token?: string;
menusList?: MenuVO[];
roleList?: any;
userId?: string;
userInfo?: UserForm;
userName?: string;
}
/** 验证码响应 */
export interface CaptchaResult {
/** 验证码缓存key */
captchaKey: string;
/** 验证码图片Base64字符串 */
captchaBase64: string;
}
// 查询手机号绑定货场相应
export interface DbPhoneResult {
id: number;
mechanismName: string;
phone: string;
mechanismCode: string;
desc: string;
isDefault: string;
}

130
src/api/dept.ts Normal file
View File

@ -0,0 +1,130 @@
import request from "@/utils/request";
const DEPT_BASE_URL = "/api/v1/dept";
class DeptAPI {
/**
*
*
* @param queryParams
* @returns
*/
static getList(queryParams?: DeptQuery) {
return request<any, DeptVO[]>({
url: `${DEPT_BASE_URL}`,
method: "get",
params: queryParams,
});
}
/** 获取部门下拉列表 */
static getOptions() {
return request<any, OptionType[]>({
url: `${DEPT_BASE_URL}/options`,
method: "get",
});
}
/**
*
*
* @param id ID
* @returns
*/
static getFormData(id: number) {
return request<any, DeptForm>({
url: `${DEPT_BASE_URL}/${id}/form`,
method: "get",
});
}
/**
*
*
* @param data
* @returns
*/
static add(data: DeptForm) {
return request({
url: `${DEPT_BASE_URL}`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @param data
* @returns
*/
static update(id: number, data: DeptForm) {
return request({
url: `${DEPT_BASE_URL}/${id}`,
method: "put",
data: data,
});
}
/**
*
*
* @param ids ID(,)
* @returns
*/
static deleteByIds(ids: string) {
return request({
url: `${DEPT_BASE_URL}/${ids}`,
method: "delete",
});
}
}
export default DeptAPI;
/** 部门查询参数 */
export interface DeptQuery {
/** 搜索关键字 */
keywords?: string;
/** 状态 */
status?: number;
}
/** 部门类型 */
export interface DeptVO {
/** 子部门 */
children?: DeptVO[];
/** 创建时间 */
createTime?: Date;
/** 部门ID */
id?: number;
/** 部门名称 */
name?: string;
/** 部门编号 */
code?: string;
/** 父部门ID */
parentId?: number;
/** 排序 */
sort?: number;
/** 状态(1:启用0:禁用) */
status?: number;
/** 修改时间 */
updateTime?: Date;
}
/** 部门表单类型 */
export interface DeptForm {
/** 部门ID(新增不填) */
id?: number;
/** 部门名称 */
name?: string;
/** 部门编号 */
code?: string;
/** 父部门ID */
parentId: number;
/** 排序 */
sort?: number;
/** 状态(1:启用0禁用) */
status?: number;
}

183
src/api/dict.ts Normal file
View File

@ -0,0 +1,183 @@
import request from "@/utils/request";
const DICT_BASE_URL = "/api/v1/dict";
class DictAPI {
/**
*
*
* @param queryParams
* @returns
*/
static getPage(queryParams: DictPageQuery) {
return request<any, PageResult<DictPageVO[]>>({
url: `${DICT_BASE_URL}/page`,
method: "get",
params: queryParams,
});
}
/**
*
*
* @param id ID
* @returns
*/
static getFormData(id: number) {
return request<any, ResponseData<DictForm>>({
url: `${DICT_BASE_URL}/${id}/form`,
method: "get",
});
}
/**
*
*
* @param data
* @returns
*/
static add(data: DictForm) {
return request({
url: `${DICT_BASE_URL}`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @param data
* @returns
*/
static update(id: number, data: DictForm) {
return request({
url: `${DICT_BASE_URL}/${id}`,
method: "put",
data: data,
});
}
/**
*
*
* @param ids ID(,)
* @returns
*/
static deleteByIds(ids: string) {
return request({
url: `${DICT_BASE_URL}/${ids}`,
method: "delete",
});
}
/**
*
*
* @param typeCode
* @returns
*/
static getOptions(code: string) {
return request<any, OptionType[]>({
url: `${DICT_BASE_URL}/${code}/options`,
method: "get",
});
}
}
export default DictAPI;
/**
*
*/
export interface DictPageQuery extends PageQuery {
/**
* (/)
*/
keywords?: string;
}
/**
*
*/
export interface DictPageVO {
/**
* ID
*/
id: number;
/**
*
*/
name: string;
/**
*
*/
code: string;
/**
* 1-0-
*/
status: number;
/**
*
*/
dictItems: DictItem[];
}
/**
*
*/
export interface DictItem {
/**
* ID
*/
id?: number;
/**
*
*/
name?: string;
/**
*
*/
value?: string;
/**
*
*/
sort?: number;
/**
* 1-0-
*/
status?: number;
}
// TypeScript 类型声明
/**
*
*/
export interface DictForm {
/**
* ID
*/
id?: number;
/**
*
*/
name?: string;
/**
*
*/
code?: string;
/**
* 1-0-
*/
status?: number;
/**
*
*/
remark?: string;
/**
*
*/
dictItems?: DictItem[];
}

46
src/api/file.ts Normal file
View File

@ -0,0 +1,46 @@
import request from "@/utils/request";
class FileAPI {
/**
*
*
* @param file
*/
static upload(file: File) {
const formData = new FormData();
formData.append("file", file);
return request<any, FileInfo>({
url: "/api/v1/files",
method: "post",
data: formData,
headers: {
"Content-Type": "multipart/form-data",
},
});
}
/**
*
*
* @param filePath
*/
static deleteByPath(filePath?: string) {
return request({
url: "/api/v1/files",
method: "delete",
params: { filePath: filePath },
});
}
}
export default FileAPI;
/**
* API类型声明
*/
export interface FileInfo {
/** 文件名 */
name: string;
/** 文件路径 */
url: string;
}

216
src/api/menu.ts Normal file
View File

@ -0,0 +1,216 @@
import request from "@/utils/request";
class MenuAPI {
/**
*
* <p/>
* token获取角色自行判断是否拥有路由的权限
*
* @returns
*/
static getRoutes() {
return request<any, RouteVO[]>({
url: `/api/new/menus/routes`,
method: "get",
});
}
/**
*
*
* @param queryParams
* @returns
*/
static getList(queryParams: MenuQuery) {
return request<any, MenuVO[]>({
url: `/api/new/menus/listMenus`,
method: "get",
params: queryParams,
});
}
/**
*
*
* @returns
*/
static getOptions() {
return request<any, OptionType[]>({
url: `/api/new/menus/options`,
method: "get",
});
}
/**
*
*
* @param id ID
*/
static getFormData(data: { id: number }) {
return request<any, MenuForm>({
url: `/api/new/menus/getMenuForm`,
method: "get",
params: data,
});
}
/**
*
*
* @param data
* @returns
*/
static add(data: MenuForm) {
return request({
url: `/api/new/menus/addMenu`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @param data
* @returns
*/
static update(id: string, data: MenuForm) {
return request({
url: `/api/new/menus/updateMenu`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @returns
*/
static deleteById(data: { id: number }) {
return request({
url: `/api/new/menus/deleteMenu`,
method: "get",
params: data,
});
}
static updateMenuVisible(data: { menuId: number; visible: number }) {
return request({
url: `/api/new/menus/updateMenuVisible`,
method: "get",
params: data,
});
}
}
export default MenuAPI;
import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
/** 菜单查询参数 */
export interface MenuQuery {
/** 搜索关键字 */
name?: 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 */
icon?: string;
/** 排序 */
sort?: number;
/** 路由名称 */
routeName?: string;
/** 路由路径 */
routePath?: string;
/** 组件路径 */
component?: string;
/** 跳转路由路径 */
redirect?: string;
/** 菜单 */
type?: MenuTypeEnum;
/** 权限标识 */
perm?: string;
/** 【菜单】是否开启页面缓存 */
keepAlive?: number;
/** 【目录】只有一个子路由是否始终显示 */
alwaysShow?: number;
/** 参数 */
params?: KeyValue[];
}
interface KeyValue {
key: string;
value: string;
}
/** RouteVO路由对象 */
export interface RouteVO {
/** 子路由列表 */
children: RouteVO[];
/** 组件路径 */
component?: string;
/** 路由属性 */
meta?: Meta;
/** 路由名称 */
name?: string;
/** 路由路径 */
path?: string;
/** 跳转链接 */
redirect?: string;
}
/** Meta路由属性 */
export interface Meta {
/** 【目录】只有一个子路由是否始终显示 */
alwaysShow?: boolean;
/** 是否隐藏(true-是 false-否) */
hidden?: boolean;
/** ICON */
icon?: string;
/** 【菜单】是否开启页面缓存 */
keepAlive?: boolean;
/** 路由title */
title?: string;
}

122
src/api/role.ts Normal file
View File

@ -0,0 +1,122 @@
import request from "@/utils/request";
class RoleAPI {
/** 获取角色分页数据 */
static getPage(queryParams?: RolePageQuery) {
return request<any, PageResult<RoleDTO[]>>({
url: `/api/role/getPageRole`,
method: "get",
params: queryParams,
});
}
static getAllRole() {
return request<any, RoleDTO[]>({
url: `/api/role/getRoleList`,
method: "get",
});
}
/** 添加角色 */
static addRole(data: RoleForm) {
return request<any, string>({
url: `api/role/addRole`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @param data
*/
static updateRole(data: RoleForm) {
return request({
url: `/api/role/updateRole`,
method: "post",
data: data,
});
}
static getMenuList() {
return request<any, MenuDTO[]>({
url: `/api/menus/getList`,
method: "get",
});
}
static queryRoleById(data: { roleId: number }) {
return request<any, MenuRoleDTO[]>({
url: `/api/role/getMenusRole`,
method: "get",
params: data,
});
}
}
export default RoleAPI;
/** 角色分页查询参数 */
export interface RolePageQuery extends PageQuery {
/** 搜索关键字 */
roleName?: string;
}
/** 角色分页对象 */
export interface RoleDTO {
createTime?: string;
createUserId?: number;
createUserName?: string;
id: number;
isDeleted?: boolean;
roleCode?: string;
roleName?: string;
state?: number;
updateTime?: string;
updateUserId?: number;
updateUserName?: string;
}
/** 角色表单对象 */
export interface RoleForm {
id?: number;
roleName?: string;
list?: Menu[];
isDeleted?: boolean;
}
export interface Menu {
menusId?: number;
state?: number;
}
export interface MenuDTO {
createTime?: string;
createUserId?: number;
createUserName?: string;
id?: number;
name?: string;
note?: string;
parentId?: string;
permission?: string;
sort?: number;
state?: string;
type?: number;
updateTime?: string;
updateUserId?: number;
updateUserName?: string;
url?: string;
}
export interface MenuRoleDTO {
createTime?: string;
createUserId?: number;
id?: number;
menusId?: number;
menusName?: string;
roleId?: number;
state?: number;
updateTime?: string;
updateUserId?: number;
}

118
src/api/user.ts Normal file
View File

@ -0,0 +1,118 @@
import request from "@/utils/request";
import { RoleDTO } from "./role";
class UserAPI {
/**
*
*
* @param queryParams
*/
static getPage(queryParams: PageQuery) {
return request<any, PageResult<UserPageVO[]>>({
url: `/api/user/getUserPage`,
method: "get",
params: queryParams,
});
}
/**
*
*
* @param data
*/
static add(data: UserForm) {
return request<any, string>({
url: `/api/user/addUser`,
method: "post",
data: data,
});
}
/**
*
*
* @param id ID
* @param data
*/
static updateUserById(data: UserForm) {
return request({
url: `/api/user/updateUserById`,
method: "post",
data: data,
});
}
/**
* (,)
*
* @param ids ID字符串(,)
*/
static updateUserByIdOffline(data: { id: number }) {
return request<any, string>({
url: `/api/user/updateUserByIdOffline`,
method: "post",
data: data,
});
}
/**
*
*/
static getUserInfo() {
return request<any, any>({
url: `/api/user/getUserInfo`,
method: "GET",
});
}
}
export default UserAPI;
/**
*
*/
export interface UserPageQuery extends PageQuery {
/** 搜索关键字 */
name?: string;
phone?: string;
roleId?: number;
}
/** 用户分页对象 */
export interface UserPageVO {
areaId?: string;
cardCode?: string;
citiyId?: string;
createTime?: string;
createUserId?: number;
createUserName?: string;
factoryAddress?: string;
factoryName?: string;
gender?: number;
id: number;
isDeleted?: string;
name?: string;
password?: string;
phone?: string;
provinceId?: string;
roleVos?: RoleDTO[];
state?: number;
updateTime?: string;
updateUserId?: number;
updateUserName?: string;
userName?: string;
userType?: number;
}
/** 用户表单类型 */
export interface UserForm {
userType?: number;
gender?: number;
name?: string;
roleName?: string;
roleIds?: number[];
phone?: string;
id?: number;
roleId?: number;
}

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,373 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4666703" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe643;</span>
<div class="name">设置</div>
<div class="code-name">&amp;#xe643;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe602;</span>
<div class="name">出库</div>
<div class="code-name">&amp;#xe602;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe606;</span>
<div class="name">入库</div>
<div class="code-name">&amp;#xe606;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe655;</span>
<div class="name">参数</div>
<div class="code-name">&amp;#xe655;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xeb66;</span>
<div class="name">数据看板</div>
<div class="code-name">&amp;#xeb66;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe607;</span>
<div class="name">收货</div>
<div class="code-name">&amp;#xe607;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe629;</span>
<div class="name">我的账本</div>
<div class="code-name">&amp;#xe629;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe653;</span>
<div class="name">出货</div>
<div class="code-name">&amp;#xe653;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1724812140996') format('woff2'),
url('iconfont.woff?t=1724812140996') format('woff'),
url('iconfont.ttf?t=1724812140996') format('truetype'),
url('iconfont.svg?t=1724812140996#iconfont') format('svg');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-shezhi"></span>
<div class="name">
设置
</div>
<div class="code-name">.icon-shezhi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chuku"></span>
<div class="name">
出库
</div>
<div class="code-name">.icon-chuku
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-ruku"></span>
<div class="name">
入库
</div>
<div class="code-name">.icon-ruku
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-canshu"></span>
<div class="name">
参数
</div>
<div class="code-name">.icon-canshu
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shujukanban"></span>
<div class="name">
数据看板
</div>
<div class="code-name">.icon-shujukanban
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shouhuo"></span>
<div class="name">
收货
</div>
<div class="code-name">.icon-shouhuo
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-wodezhangben"></span>
<div class="name">
我的账本
</div>
<div class="code-name">.icon-wodezhangben
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chuhuo"></span>
<div class="name">
出货
</div>
<div class="code-name">.icon-chuhuo
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shezhi"></use>
</svg>
<div class="name">设置</div>
<div class="code-name">#icon-shezhi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chuku"></use>
</svg>
<div class="name">出库</div>
<div class="code-name">#icon-chuku</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-ruku"></use>
</svg>
<div class="name">入库</div>
<div class="code-name">#icon-ruku</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-canshu"></use>
</svg>
<div class="name">参数</div>
<div class="code-name">#icon-canshu</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shujukanban"></use>
</svg>
<div class="name">数据看板</div>
<div class="code-name">#icon-shujukanban</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shouhuo"></use>
</svg>
<div class="name">收货</div>
<div class="code-name">#icon-shouhuo</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-wodezhangben"></use>
</svg>
<div class="name">我的账本</div>
<div class="code-name">#icon-wodezhangben</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chuhuo"></use>
</svg>
<div class="name">出货</div>
<div class="code-name">#icon-chuhuo</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@ -0,0 +1,48 @@
@font-face {
font-family: "iconfont"; /* Project id 4666703 */
src: url('iconfont.woff2?t=1724812140996') format('woff2'),
url('iconfont.woff?t=1724812140996') format('woff'),
url('iconfont.ttf?t=1724812140996') format('truetype'),
url('iconfont.svg?t=1724812140996#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-shezhi:before {
content: "\e643";
}
.icon-chuku:before {
content: "\e602";
}
.icon-ruku:before {
content: "\e606";
}
.icon-canshu:before {
content: "\e655";
}
.icon-shujukanban:before {
content: "\eb66";
}
.icon-shouhuo:before {
content: "\e607";
}
.icon-wodezhangben:before {
content: "\e629";
}
.icon-chuhuo:before {
content: "\e653";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,65 @@
{
"id": "4666703",
"name": "ava",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "爱梵达图标集合",
"glyphs": [
{
"icon_id": "1167181",
"name": "设置",
"font_class": "shezhi",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "3239723",
"name": "出库",
"font_class": "chuku",
"unicode": "e602",
"unicode_decimal": 58882
},
{
"icon_id": "3239733",
"name": "入库",
"font_class": "ruku",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "3851337",
"name": "参数",
"font_class": "canshu",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "3868281",
"name": "数据看板",
"font_class": "shujukanban",
"unicode": "eb66",
"unicode_decimal": 60262
},
{
"icon_id": "9922131",
"name": "收货",
"font_class": "shouhuo",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "10037047",
"name": "我的账本",
"font_class": "wodezhangben",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "11586060",
"name": "出货",
"font_class": "chuhuo",
"unicode": "e653",
"unicode_decimal": 58963
}
]
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Created by iconfont</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024">
<font-face
font-family="iconfont"
font-weight="400"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="shezhi" unicode="&#58947;" d="M1072.147851 489.773633c-6.331285 33.456782-26.762037 55.073399-52.047135 55.073399-0.323417 0-0.651455-0.003081-0.830105-0.009241l-4.655674 0c-73.124722 0-132.618162 59.491899-132.618162 132.618162 0 23.731152 11.447443 50.336101 11.546009 50.565574 13.104573 29.498767 3.023185 65.672257-23.427755 84.127081l-1.601687 1.127342-134.400039 74.661726-1.700252 0.745401c-8.753836 3.805547-18.334698 5.735272-28.479231 5.735272-20.789593 0-41.235746-8.344174-54.683758-22.306575-14.741683-15.216028-65.622973-58.649474-104.721083-58.649474-39.450789 0-90.633935 44.286652-105.438762 59.784516-13.518857 14.247316-34.128258 22.753199-55.127302 22.753199-9.945862 0-19.354234-1.861961-27.958682-5.531982l-1.746455-0.74078-139.141957-76.431283-1.643269-1.139662c-26.537186-18.437884-36.675557-54.579032-23.584845-84.062398 0.115506-0.264895 11.579891-26.725075 11.579891-50.634877 0-73.126262-59.491899-132.618162-132.618162-132.618162l-4.581749 0c-0.318797 0.00616-0.636055 0.01078-0.951772 0.01078-25.260456 0-45.672728-21.618157-52.002472-55.0811-0.462025-2.453354-11.313456-60.622322-11.313456-106.117939 0-45.494078 10.85143-103.659965 11.314996-106.119479 6.334365-33.458322 26.758957-55.076479 52.036353-55.076479 0.320337 0 0.651455 0.00616 0.842426 0.012321l4.655674 0c73.126262 0 132.618162-59.491899 132.618162-132.616622 0-23.760413-11.444363-50.333021-11.546009-50.565574-13.093793-29.474125-3.041666-65.646075 23.395414-84.151722l1.569346-1.093459 131.838879-73.726895 1.675611-0.7377c8.750757-3.84251 18.305437-5.790715 28.397607-5.790715 21.082208 0 41.676209 8.706094 55.0888 23.290689 18.724339 20.347588 69.527086 62.362616 107.04815 62.362616 40.625872 0 92.72537-47.100385 107.759669-63.583903 13.441852-14.831008 34.176001-23.689571 55.470741-23.695731l0.00616 0c9.895039 0 19.27877 1.883523 27.893999 5.598205l1.711034 0.73924 136.659342 75.531873 1.617088 1.128882c26.492523 18.456365 36.601633 54.600594 23.538642 84.016195-0.115506 0.267974-11.595291 27.082374-11.595291 50.67646 0 73.124722 59.49344 132.616622 132.618162 132.616622l4.517066 0.00154c0.300316-0.00616 0.599092-0.009241 0.899409-0.009241 25.331299 0.00154 45.785153 21.619697 52.107197 55.054918 0.112426 0.589852 11.325776 59.507301 11.325776 106.14104C1083.464388 429.359224 1072.609877 487.32644 1072.147851 489.773633zM377.486862-49.656142l-115.32764 64.487932c5.082277 13.052211 15.437801 43.51815 15.437801 75.017486 0 109.382917-84.176364 199.816642-192.587488 208.134635-2.647404 15.427021-8.873963 54.967133-8.873963 85.667166 0 30.65691 6.223479 70.232445 8.869343 85.671786 108.415744 8.311832 192.592108 98.745557 192.592108 208.134635 0 31.416171-10.300081 61.797405-15.371577 74.854236l122.721583 67.40331c0.003081 0 0.00462-0.00154 0.007701-0.00154 4.423121-4.518606 22.121764-22.080182 46.558275-39.493911 39.929754-28.46229 77.952885-42.894416 113.014434-42.894416 34.716571 0 72.437845 14.151831 112.115025 42.06431 24.282503 17.07953 41.896442 34.302288 46.308782 38.74543 0.009241 0.00154 0.018481 0.00462 0.026182 0.00616l118.301542-65.726159c-5.077657-13.055291-15.416239-43.499669-15.416239-74.958962 0-109.389077 84.174824-199.822802 192.590568-208.134635 2.645865-15.462442 8.872423-55.107281 8.872423-85.671786 0-30.687711-6.223479-70.241685-8.869343-85.673326C890.042174 289.665916 805.86427 199.232191 805.86427 89.841574c0-31.450053 10.317022-61.851309 15.393138-74.903519l-119.783103-66.198965c-5.168521 5.490399-22.603811 23.363073-46.740005 41.288109-40.701336 30.224145-79.662378 45.549521-115.800446 45.549521-35.79155 0-74.458435-15.038919-114.927219-44.694774C400.22004-26.554885 382.666163-44.255068 377.486862-49.656142zM731.271848 384.353353c0 105.803762-86.081448 191.88059-191.888289 191.88059-105.803762 0-191.88059-86.076827-191.88059-191.88059 0-105.803762 86.076827-191.882129 191.88059-191.882129C645.19194 192.471223 731.271848 278.549591 731.271848 384.353353zM539.383558 500.096816c63.825696 0 115.751164-51.922387 115.751164-115.743463 0-63.825696-51.925468-115.751164-115.751164-115.751164-63.821076 0-115.743463 51.925468-115.743463 115.751164C423.640095 448.175969 475.562482 500.096816 539.383558 500.096816z" horiz-adv-x="1084" />
<glyph glyph-name="chuku" unicode="&#58882;" d="M850.7 310.17l-0.48 0.51c-4.11 4.22-13.73 14.1-30.82 14.1-11.16 0-22.46-4.9-31-13.43s-13.4-19.84-13.4-31v-31.63c-30.71-4.14-57.7-12.9-80.45-26.15a164.36 164.36 0 0 1-58.74-57.83c-25.3-42-28.65-88.11-30.26-110.27-0.24-3.32-0.45-6.19-0.66-8.06a24.21 24.21 0 0 1-0.16-2.75c0-24.19 21.63-41 41-41 15.06 0 26.65 7.45 34.47 22.16 26.06 41.28 55.89 62.49 94.67 66.6v-39c0-23.4 17.66-41 41.09-41 16.5 0 25.88 9.14 30.39 13.53l0.07 0.07q0.56 0.55 1.09 1.14L940 128.7c7.73 7.64 20 20.2 20.14 39.9a55.21 55.21 0 0 1-17 40.91z m54.71-147.42l-1-1-81-89.86v44.26a24.28 24.28 0 0 1-23 24.24c-35.61 1.9-67.55-5.38-95-21.62-17.91-10.61-34.09-25-49-43.56 8.74 60.08 37.78 121 144.14 127.22a24.28 24.28 0 0 1 22.86 24.24V268l84.53-92q0.68-0.74 1.42-1.43a6.66 6.66 0 0 0 2.15-5c-0.89-1.68-4.37-5.11-6.1-6.82zM538.13 40.38h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.5 4.39-24.89 24.89-24.89h52.7c20.5 0 24.89 4.39 24.89 24.89v54.15c-1.46 20.51-5.85 24.89-24.89 24.89zM362.48 40.38h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.5 4.39-24.89 24.89-24.89h52.7c20.49 0 24.88 4.39 24.88 24.89v54.15c-1.47 20.51-5.86 24.89-24.88 24.89zM362.48 228.1h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-52.7c0-20.49 4.39-24.88 24.89-24.88h52.7c20.49 0 24.88 4.39 24.88 24.88v54.15c-1.47 19.04-5.86 23.43-24.88 23.43zM485.43 405.22c-20.49 0-24.88-4.39-24.88-24.88v-54.16c0-20.5 4.39-24.89 24.88-24.89h52.7c20.49 0 24.88 4.39 24.88 24.89v54.16c-1.46 20.49-5.85 24.88-24.88 24.88zM538.13 228.1h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-52.7c0-20.49 4.39-24.88 24.89-24.88h52.7c20.5 0 24.89 4.39 24.89 24.88v54.15c-1.46 19.04-5.85 23.43-24.89 23.43zM362.48 405.22h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.49 4.39-24.88 24.89-24.88h52.7c20.49 0 24.88 4.39 24.88 24.88v54.16c-1.47 21.95-5.86 24.88-24.88 24.88zM914.29 468.07A28.7 28.7 0 1 1 948.68 514l-419 313.65a28.7 28.7 0 0 1-34.37 0L75.53 514a28.7 28.7 0 1 1 34.35-46l40.54 30.3v-533.17a28.69 28.69 0 0 1 57.38 0v576.1l304.65 227.63z" horiz-adv-x="1024" />
<glyph glyph-name="ruku" unicode="&#58886;" d="M621.67 209.51a55.21 55.21 0 0 1-17-40.91c0.13-19.7 12.42-32.26 20.14-39.9l92.51-102.64q0.53-0.59 1.09-1.14l0.07-0.07c4.51-4.39 13.89-13.53 30.39-13.53 23.42 0 41.09 17.65 41.09 41v39c38.78-4.11 68.62-25.32 94.67-66.6 7.82-14.71 19.41-22.16 34.47-22.16 19.41 0 41 16.86 41 41a24.21 24.21 0 0 1-0.16 2.75c-0.21 1.87-0.42 4.74-0.66 8.06-1.61 22.17-5 68.29-30.26 110.27a164.36 164.36 0 0 1-58.74 57.83c-22.75 13.25-49.74 22-80.45 26.15v31.73c0 11.16-4.9 22.46-13.43 31s-19.83 13.43-31 13.43c-17.09 0-26.72-9.88-30.82-14.1l-0.48-0.51z m31.59-39.92a6.66 6.66 0 0 0 2.15 5q0.74 0.68 1.42 1.43l84.53 92v-41.31a24.28 24.28 0 0 1 22.86-24.24c106.36-6.23 135.4-67.14 144.14-127.22-14.88 18.58-31.06 32.95-49 43.56C832 135 800 142.29 764.44 140.39a24.28 24.28 0 0 1-23-24.24v-44.28l-81 89.86q-0.47 0.53-1 1c-1.69 1.73-5.17 5.16-6.18 6.85zM538.13 40.38h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.5 4.39-24.89 24.89-24.89h52.7c20.5 0 24.89 4.39 24.89 24.89v54.15c-1.46 20.51-5.85 24.89-24.89 24.89zM362.48 40.38h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.5 4.39-24.89 24.89-24.89h52.7c20.49 0 24.88 4.39 24.88 24.89v54.15c-1.47 20.51-5.86 24.89-24.88 24.89zM362.48 228.1h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-52.7c0-20.49 4.39-24.88 24.89-24.88h52.7c20.49 0 24.88 4.39 24.88 24.88v54.15c-1.47 19.04-5.86 23.43-24.88 23.43zM485.43 405.22c-20.49 0-24.88-4.39-24.88-24.88v-54.16c0-20.5 4.39-24.89 24.88-24.89h52.7c20.49 0 24.88 4.39 24.88 24.89v54.16c-1.46 20.49-5.85 24.88-24.88 24.88zM538.13 228.1h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-52.7c0-20.49 4.39-24.88 24.89-24.88h52.7c20.5 0 24.89 4.39 24.89 24.88v54.15c-1.46 19.04-5.85 23.43-24.89 23.43zM362.48 405.22h-52.7c-20.49 0-24.89-4.39-24.89-24.88v-54.16c0-20.49 4.39-24.88 24.89-24.88h52.7c20.49 0 24.88 4.39 24.88 24.88v54.16c-1.47 21.95-5.86 24.88-24.88 24.88zM914.29 468.07A28.7 28.7 0 1 1 948.68 514l-419 313.65a28.7 28.7 0 0 1-34.37 0L75.53 514a28.7 28.7 0 1 1 34.35-46l40.54 30.3v-533.17a28.69 28.69 0 0 1 57.38 0v576.1l304.65 227.63z" horiz-adv-x="1024" />
<glyph glyph-name="canshu" unicode="&#58965;" d="M278.8 275.6V767.9h-46v-492.3c-54.6-10.7-95.9-59-95.9-116.7s41.3-105.9 95.9-116.7v-42h46v42c54.6 10.7 95.9 59 95.9 116.7 0 57.8-41.3 106-95.9 116.7z m-23-189.6c-40.2 0-72.9 32.7-72.9 72.9s32.7 72.9 72.9 72.9 72.9-32.7 72.9-72.9c0-40.1-32.7-72.9-72.9-72.9zM534.8 501.9v266h-46v-266.3c-54.2-11.1-95-59.1-95-116.5s40.9-105.4 95-116.5v-268.3h46v268c55 10.4 96.8 58.8 96.8 116.8s-41.7 106.4-96.8 116.8z m-22.1-189.7c-40.2 0-72.9 32.7-72.9 72.9s32.7 72.9 72.9 72.9 72.9-32.7 72.9-72.9-32.7-72.9-72.9-72.9zM887.2 608.1c0 57.8-41.5 106.2-96.3 116.7v42.9h-46v-43.1c-54.4-10.9-95.5-59-95.5-116.6 0-57.6 41.1-105.7 95.5-116.6V0h46V491.2c54.7 10.7 96.3 59 96.3 116.9z m-119-73c-40.2 0-72.9 32.7-72.9 72.9s32.7 72.9 72.9 72.9 72.9-32.7 72.9-72.9c0.1-40.2-32.7-72.9-72.9-72.9z" horiz-adv-x="1024" />
<glyph glyph-name="shujukanban" unicode="&#60262;" d="M979.2 737.152a32 32 0 0 1-38.4 23.936l-166.848-38.656a32 32 0 0 1-15.808-53.408L794.56 631.36l-194.56-173.568-101.024 95.68a32 32 0 0 1-45.152-1.152l-216.736-227.264A64 64 0 1 1 288 262.4c0 6.944-1.376 13.472-3.424 19.712l193.536 202.944 99.232-93.952a32 32 0 0 1 43.296-0.64L839.04 585.28l41.504-42.976a32 32 0 0 1 53.92 13.92l44.448 165.408a31.84 31.84 0 0 1 0.288 15.52zM928 445.536a32 32 0 0 1-32-32V160a32 32 0 0 0-32-32H160a32 32 0 0 0-32 32V736a32 32 0 0 0 32 32h530.656a32 32 0 0 1 0 64H160a96 96 0 0 1-96-96v-576a96 96 0 0 1 96-96h704a96 96 0 0 1 96 96v253.536a32 32 0 0 1-32 32zM912 0h-800a32 32 0 0 1 0-64h800a32 32 0 0 1 0 64z" horiz-adv-x="1024" />
<glyph glyph-name="shouhuo" unicode="&#58887;" d="M995.555556-93.866667c0-17.066667-11.377778-34.133333-28.444445-34.133333H56.888889c-17.066667 0-28.444444 17.066667-28.444445 34.133333V327.111111l164.977778 278.755556c5.688889 11.377778 22.755556 5.688889 34.133334 5.688889H312.888889c17.066667 0 28.444444-5.688889 28.444444-28.444445-5.688889-11.377778-17.066667-28.444444-34.133333-28.444444H238.933333L102.4 332.8H921.6L785.066667 554.666667h-68.266667c-17.066667 0-34.133333 17.066667-28.444444 34.133333 0 22.755556 5.688889 22.755556 22.755555 22.755556h85.333333c11.377778 0 28.444444 0 34.133334-11.377778L995.555556 327.111111v-420.977778zM938.666667 270.222222H85.333333v-341.333333h853.333334v341.333333zM534.755556 395.377778c-5.688889-5.688889-11.377778-11.377778-22.755556-11.377778-5.688889 0-17.066667 5.688889-22.755556 11.377778L381.155556 492.088889c-11.377778 17.066667-17.066667 34.133333 0 51.2 11.377778 11.377778 28.444444 11.377778 45.511111 0l56.888889-51.2V861.866667c0 17.066667 11.377778 34.133333 34.133333 34.133333 17.066667 0 22.755556-17.066667 22.755555-34.133333v-369.777778l62.577778 51.2c11.377778 11.377778 34.133333 11.377778 45.511111 0 11.377778-11.377778 11.377778-34.133333 0-45.511111l-113.777777-102.4z" horiz-adv-x="1024" />
<glyph glyph-name="wodezhangben" unicode="&#58921;" d="M179.2 358.4H25.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h153.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM179.2 204.8H25.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h153.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM179.2 512H25.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h153.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM547.84 476.16l-107.52 107.52c-10.24 10.24-10.24 25.6 0 35.84 10.24 10.24 25.6 10.24 35.84 0l107.52-107.52c10.24-10.24 10.24-25.6 0-35.84-10.24-10.24-25.6-10.24-35.84 0zM542.72 512l107.52 107.52c10.24 10.24 25.6 10.24 35.84 0 10.24-10.24 10.24-25.6 0-35.84l-107.52-107.52c-10.24-10.24-25.6-10.24-35.84 0-10.24 10.24-10.24 25.6 0 35.84zM716.8 445.44H409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h307.2c15.36 0 25.6-10.24 25.6-25.6 0-12.8-10.24-25.6-25.6-25.6zM716.8 291.84H409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h307.2c15.36 0 25.6-10.24 25.6-25.6 0-12.8-10.24-25.6-25.6-25.6zM537.6 163.84v307.2c0 15.36 10.24 25.6 25.6 25.6s25.6-10.24 25.6-25.6v-307.2c0-15.36-10.24-25.6-25.6-25.6s-25.6 12.8-25.6 25.6zM921.6 896H153.6C97.28 896 51.2 849.92 51.2 793.6v-102.4c0-15.36 10.24-25.6 25.6-25.6s25.6 10.24 25.6 25.6V793.6c0 28.16 23.04 51.2 51.2 51.2h768c28.16 0 51.2-23.04 51.2-51.2v-819.2c0-28.16-23.04-51.2-51.2-51.2H153.6c-28.16 0-51.2 23.04-51.2 51.2v102.4c0 15.36-10.24 25.6-25.6 25.6s-25.6-10.24-25.6-25.6v-102.4c0-56.32 46.08-102.4 102.4-102.4h768c56.32 0 102.4 46.08 102.4 102.4V793.6c0 56.32-46.08 102.4-102.4 102.4z" horiz-adv-x="1024" />
<glyph glyph-name="chuhuo" unicode="&#58963;" d="M484.864 693.76v-333.994667h54.272V693.76l113.664-108.202667 37.546667 35.84L512 791.381333l-178.346667-169.984 37.546667-35.84zM752.981333 666.112v-51.029333h84.992l85.845334-204.288H618.837333V155.306667H405.162667V410.794667H100.352l85.845333 204.288h84.992v51.029333H147.626667L15.701333 352.085333v-375.296h992.426667V352.085333l-131.925333 314.026667h-123.221334zM954.026667 27.648H69.973333V359.765333h280.917334v-255.317333h322.218666V359.765333H954.026667v-332.117333z" horiz-adv-x="1024" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
src/assets/icons/api.svg Normal file
View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M499.2 671.232v-261.12h102.4c16.384 0 28.672 1.024 37.888 2.56 13.312 2.048 24.576 6.656 34.816 13.312 9.728 6.656 17.92 16.384 23.552 28.16 6.144 12.288 8.704 25.6 8.192 38.4 0 23.552-7.68 44.032-23.04 59.904-15.36 16.896-40.96 25.088-78.848 25.088h-43.52v93.184l-61.44.512zm281.6 0h-61.952v-261.12H780.8v261.12zm-287.744 0h-69.12L396.8 601.6h-73.728l-25.088 69.632h-66.56l100.352-261.12h54.272l107.008 261.12zM343.552 545.28h32.256l-15.872-42.496c0-.512-.512-1.024-.512-1.536l-15.872 44.032zm217.6-26.112h43.52c20.48 0 28.16-4.608 31.232-7.168 4.608-4.096 7.168-10.752 7.168-18.944 0-6.656-1.536-11.776-4.096-15.36-2.56-3.584-6.144-6.144-10.752-7.68-1.536-.512-6.656-1.536-24.064-1.536h-43.008v50.688z"/><path d="M747.52 842.752H512c-8.704 0-16.384-3.584-22.016-9.728-6.144-6.144-9.216-14.336-8.704-22.528.512-16.896 14.336-30.72 31.232-31.232H747.52c115.712 0 209.408-94.208 209.408-209.408 0-104.96-78.848-194.56-183.296-207.872l-22.528-3.072-4.608-22.016C724.992 231.936 631.808 156.16 524.288 156.16c-124.928 0-226.304 101.376-226.304 226.304v8.704l1.536 36.352-36.352-4.096c-6.144-1.024-12.288-1.024-18.432-1.024-98.304 0-178.176 79.872-178.176 178.176 0 98.304 79.872 178.176 178.176 178.176h63.488c8.704 0 16.384 3.584 22.016 9.728 6.144 6.144 9.216 14.336 8.704 22.528-.512 16.896-14.336 30.72-31.232 31.232h-64c-64 0-123.904-25.088-169.472-70.144C28.16 726.528 3.072 665.6 3.072 601.088c0-129.536 103.936-236.544 232.448-241.152 12.288-157.184 149.504-276.48 307.2-266.24 59.904 3.584 118.784 27.136 165.888 65.536 45.568 37.376 77.824 87.04 94.208 143.872 125.952 26.112 217.088 137.728 217.088 266.752.512 151.04-121.856 272.896-272.384 272.896z"/><path d="M572.416 930.816c-8.192 0-15.872-3.072-21.504-8.704L431.616 812.544l113.152-117.76c6.144-6.144 13.824-9.216 22.528-9.216 8.704 0 16.384 3.072 22.528 9.216 11.776 11.776 12.288 31.232 1.024 44.032l-68.608 70.656 71.68 66.048c6.144 5.632 9.728 13.312 10.24 22.016.512 8.704-2.56 16.384-8.192 23.04-6.656 6.656-14.848 10.24-23.552 10.24z"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2.88 18.054a35.9 35.9 0 0 1 8.531-16.32.8.8 0 0 1 1.178 0q.25.27.413.455a35.9 35.9 0 0 1 8.118 15.865c-2.141.451-4.34.747-6.584.874l-2.089 4.178a.5.5 0 0 1-.894 0l-2.089-4.178a44 44 0 0 1-6.584-.874m6.698-1.123 1.157.066L12 19.527l1.265-2.53 1.157-.066a42 42 0 0 0 4.227-.454A33.9 33.9 0 0 0 12 4.09a33.9 33.9 0 0 0-6.649 12.387q2.093.334 4.227.454M12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6m0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg>

After

Width:  |  Height:  |  Size: 533 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M917.6 267.2c-36.1-2.5-72.4-9.3-103.6-19.3-10.1-3-20.2-6.4-30.3-10-21.4-6.3-50.5-18.8-83.6-36.6-.4-.2-.7-.4-1.1-.6-7.8-4.2-15.7-8.7-23.8-13.4-10.9-6.3-21.7-12.9-32.5-19.9-.4-.3-.8-.5-1.2-.8-7.7-5-15.5-10.2-23.1-15.5-5-3.4-10-7.1-15-10.7-3.8-2.8-7.5-5.3-11.3-8.2-27.4-20.5-54.5-43.5-79.9-68.3-25.4 24.8-52.5 47.8-79.9 68.3-3.7 2.8-7.5 5.4-11.3 8.2-5 3.6-10 7.3-15 10.7-7.7 5.4-15.4 10.5-23.1 15.5-.4.3-.8.5-1.2.8-10.8 6.9-21.6 13.6-32.5 19.9-8.1 4.7-16 9.2-23.8 13.4-.3.2-.7.4-1 .6-33 17.8-62.2 30.3-83.6 36.6-10.1 3.6-20.2 7-30.3 10-31.1 10-67.4 16.8-103.6 19.3h.1c1.1 16.2 2.1 37.7 3.4 60.9h.7c6.1 86.8 23.5 210.2 49.7 282.8 1.2 3.2 2.2 6.5 3.3 9.6.6 1.5 1.2 2.8 1.8 4.3 62.8 162.1 171.9 280.1 303 323.4v.4c17.3 5.7 31.9 9.3 43.5 11.5 11.5-2.2 26.1-5.8 43.5-11.5v-.4C687 905 796.1 787 858.9 624.8c.6-1.5 1.2-2.8 1.8-4.3 1.2-3.1 2.2-6.4 3.3-9.6 26.2-72.5 43.6-196 49.7-282.8h.7c1.1-23.3 2.2-44.7 3.2-60.9zm-47.4 41.9-.5 9.5c-.5 2.2-.9 4.4-1 6.6C863 406 847 525.7 821.3 596.7c-.7 1.9-1.4 3.9-2 5.8-.4 1.2-.8 2.5-1.4 4.1-.5 1.2-1 2.5-1.4 3.4C758.1 760.8 657.7 869.3 541 907.8c-1.9.6-3.7 1.4-5.5 2.2-7.9 2.5-15.7 4.6-23.2 6.3-7.5-1.7-15.2-3.8-23.1-6.3-1.8-.9-3.6-1.6-5.5-2.2-116.7-38.5-217.1-147-275.4-297.5-.5-1.2-.9-2.4-1.7-4.1-.4-1.2-.8-2.4-1.3-3.6-.7-2-1.3-3.9-1.9-5.6-25.8-71.2-41.7-191-47.4-271.7-.2-2.3-.5-4.5-1-6.6l-.5-9.3c-.1-1.5-.2-3-.2-4.5 24.6-3.8 48.4-9.3 70-16.2 10.1-3 20.4-6.4 31.4-10.4 25.2-7.6 56.5-21.2 90.5-39.6.6-.3 1.2-.6 1.7-.9 8.2-4.4 16.7-9.2 24.8-14 10.7-6.1 22-13 34.5-21.1.4-.2 1-.6 1.3-.8 8.2-5.3 16.4-10.8 24.1-16.2 4.5-3.1 9.1-6.4 13.7-9.7l2.4-1.8 4-2.9c2.6-1.9 5.2-3.7 7.5-5.5 17.9-13.4 35.3-27.5 52-42.1 16.7 14.7 34 28.7 51.8 42 2.6 1.9 5.1 3.8 7.7 5.6l4.3 3.1 1.5 1.1c4.8 3.5 9.6 6.9 14 9.9 8.1 5.7 16.3 11.2 23.7 16l2.1 1.3c12.4 8 23.7 14.9 34.1 20.8 8.6 5 17 9.8 25 14.1.4.2 1 .5 1.5.8 34.2 18.4 65.6 32.1 90.9 39.7 11 3.9 21.3 7.3 30.6 10.1 22.1 7.1 46.1 12.6 70.8 16.5.1 1.5.1 3 0 4.4z"/><path d="M710.6 411.2 476.1 651.6l-120-123c-8.3-8.5-21.8-8.5-30.1 0s-8.3 22.3 0 30.9L461.1 698c4.2 4.3 9.6 6.4 15.1 6.4 5.4 0 10.9-2.1 15-6.4l249.5-255.7c8.3-8.5 8.3-22.3 0-30.9-8.3-8.7-21.8-8.7-30.1-.2z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M832.128 768c33.195 0 60.501 25.173 63.573 57.813L896 832a64 64 0 0 1-63.872 64H533.205a63.787 63.787 0 0 1-63.872-64 64 64 0 0 1 63.872-64h298.923zM213.333 874.667c-23.722 0-42.666-19.072-42.666-42.624V362.667A42.667 42.667 0 0 1 213.333 320l4.992.299C239.66 322.73 256 340.779 256 362.624l-.043 128.043h128.299c21.248 0 39.595 16.469 42.112 37.674l.299 4.992-.299 4.992A42.368 42.368 0 0 1 384.256 576H256l.043 213.333h128.256c22.869 0 42.41 19.115 42.41 42.667l-.298 4.992a42.368 42.368 0 0 1-42.112 37.675zm618.795-405.334c33.195 0 60.501 25.174 63.573 57.814l.299 6.186a64 64 0 0 1-63.872 64H533.205a63.787 63.787 0 0 1-63.872-64 64 64 0 0 1 63.872-64h298.923zM576.171 128c33.194 0 60.458 25.173 63.573 57.813L640 192c0 35.328-29.013 64-63.83 64H191.83A63.744 63.744 0 0 1 128 192c0-35.328 29.013-64 63.83-64h384.34z"/></svg>

After

Width:  |  Height:  |  Size: 941 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M962.184 55.874H61.818C27.732 55.874 0 83.606 0 117.692v621.64c0 34.086 27.732 61.818 61.818 61.818h308.52v44.98c0 41.234-33.547 74.782-74.781 74.782h-67.995c-13.036 0-23.606 10.568-23.606 23.606 0 13.038 10.57 23.606 23.606 23.606h568.874c13.036 0 23.606-10.568 23.606-23.606 0-13.038-10.57-23.606-23.606-23.606h-67.997c-41.234 0-74.782-33.548-74.782-74.782v-44.978h308.52c34.087 0 61.821-27.732 61.821-61.819v-621.64c.004-34.087-27.728-61.819-61.814-61.819zM391.84 920.916c16.092-20.672 25.714-46.616 25.714-74.782v-44.98h188.894v44.98c0 28.166 9.622 54.112 25.714 74.782H391.841zm584.95-181.583c0 8.054-6.552 14.608-14.608 14.608H61.818c-8.054 0-14.608-6.552-14.608-14.608V615.267h929.58v124.066zm0-171.28H47.212v-450.36c0-8.055 6.552-14.609 14.608-14.609h900.362c8.054 0 14.61 6.552 14.61 14.608v450.361z"/><path d="M486.531 684.611a25.476 25.476 0 1 0 50.952 0 25.476 25.476 0 1 0-50.952 0zm65.946-466.103c-9.22-9.218-24.162-9.218-33.386 0L352.263 385.337c-9.218 9.218-9.218 24.166 0 33.386a23.534 23.534 0 0 0 16.694 6.914 23.526 23.526 0 0 0 16.692-6.914l166.828-166.829c9.218-9.218 9.218-24.166 0-33.386zm98.88 96.679c-9.216-9.218-24.158-9.218-33.384-.002l-66.46 66.456c-9.218 9.22-9.218 24.168 0 33.386a23.53 23.53 0 0 0 16.692 6.914c6.04 0 12.082-2.304 16.692-6.914l66.46-66.456c9.218-9.218 9.218-24.166 0-33.384z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 36 36"><path d="m19.41 18 8.29-8.29a1 1 0 0 0-1.41-1.41L18 16.59l-8.29-8.3a1 1 0 0 0-1.42 1.42l8.3 8.29-8.3 8.29A1 1 0 1 0 9.7 27.7l8.3-8.29 8.29 8.29a1 1 0 0 0 1.41-1.41z" fill="currentColor"/></svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 36 36"><path d="M26 17H10a1 1 0 0 0 0 2h16a1 1 0 0 0 0-2z" fill="currentColor"/></svg>

After

Width:  |  Height:  |  Size: 183 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="m7 12 7 7m-7-7 7-7" stroke-linejoin="round"/><path d="M21 12H7.5"/><path d="M3 3v18" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20"><path d="M3 5h14V3H3v2zm12 8V7H5v6h10zM3 17h14v-2H3v2z" fill="currentColor"/></svg>

After

Width:  |  Height:  |  Size: 187 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="m17 12-7 7m7-7-7-7" stroke-linejoin="round"/><path d="M3 12h13.5"/><path d="M21 3v18" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 311 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 4h18v2H3V4zm0 15h18v2H3v-2zm8-5h10v2H11v-2zm0-5h10v2H11V9zm-8 3.5L7 9v7l-4-3.5z"/></svg>

After

Width:  |  Height:  |  Size: 180 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M449.6 116.2H303.8c-14.2 0-25.7-11.5-25.7-25.7s11.5-25.7 25.7-25.7h145.8c14.2 0 25.7 11.5 25.7 25.7s-11.5 25.7-25.7 25.7zm0 0"/><path d="M160.1 859.3c-14.2 0-25.7-11.5-25.7-25.7V167.4c0-56.6 46-102.6 102.6-102.6h66.8c14.2 0 25.7 11.5 25.7 25.7s-11.5 25.7-25.7 25.7H237c-28.2 0-51.1 22.9-51.1 51.1v666.2c-.1 14.3-11.6 25.8-25.8 25.8zm373.5-512.6c-6.3 0-12.4-1.3-17.6-3.5-13.5-5.8-21.9-17.9-21.9-31.6v-221c0-14.2 11.5-25.7 25.7-25.7s25.7 11.5 25.7 25.7v189l27.7-26.6c14.1-13.5 36.1-13.5 50.1 0l22.1 21.3V90.5c0-14.2 11.5-25.7 25.7-25.7s25.7 11.5 25.7 25.7v219.6c0 14.5-8.6 27.5-22 33.2-13.3 5.7-28.7 2.9-39.2-7.2l-37.5-36-37.5 36c-7.6 7.6-17.5 10.6-27 10.6zm0 0"/><path d="M846.1 958.9H236.9c-56.6 0-102.6-46-102.6-102.6v-22.8c0-14.2 11.5-25.7 25.7-25.7s25.7 11.5 25.7 25.7v22.8c0 28.2 22.9 51.1 51.1 51.1H846c14.2 0 25.7 11.5 25.7 25.7.1 14.3-11.4 25.8-25.6 25.8zm0 0"/><path d="M160.1 876h-.9c-14.2-.5-25.3-12.4-24.8-26.6 1-28.2 6.3-48.5 16.7-63.6 13.8-20.1 35.4-30.3 64.3-30.3h615c3.2-2.7 6.4-6.1 8.6-8.6V133.1c-1.8-5.1-11.7-15-16.8-16.8H449.6c-14.2 0-25.7-11.5-25.7-25.7s11.5-25.7 25.7-25.7h373.6c19.8 0 36.7 13.9 45 22.2 8.3 8.3 22.2 25.2 22.2 45v621.6c0 10.8-6.2 19.6-12.3 26.7-4.6 5.4-10.3 11-15.6 15.4-1 .9-2.1 1.7-3.2 2.5-5.4 4.1-12.9 8.8-22.3 8.8H215.3c-15 0-28 0-29.5 44.2-.5 13.8-11.9 24.7-25.7 24.7zm0 0"/><path d="M284.4 806.4c-14.2 0-25.7-11.5-25.7-25.7V90.5c0-14.2 11.5-25.7 25.7-25.7s25.7 11.5 25.7 25.7v690.1c0 14.3-11.5 25.8-25.7 25.8zM844.9 959h-1.6c-6.6-.3-30-2.3-52.2-16.9-19.5-12.7-42.6-38-42.6-86.3 0-62.3 35.7-101 93.1-101 14.2 0 25.7 11.5 25.7 25.7s-11.5 25.7-25.7 25.7c-12.5 0-41.7 0-41.7 49.6 0 21 6.6 35.3 20.1 43.8 10.6 6.6 22.1 7.8 25 8 1.4-.1 2.9 0 4.4.2 13.7 1.7 23.6 14 22.5 27.7-.9 9.5-8.8 23.5-27 23.5zm-1.8-51.3c-1.1.1-2.3.3-3.4.6 1.1-.3 2.2-.5 3.4-.6zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M832.1 185.1H609.4l-17.1-62c-9.6-34.6-40.5-58.8-75.3-58.8H196c-43.2 0-78.3 36.4-78.3 81.1V897c0 35.3 28.7 64 64 64H832c35.3 0 64-28.7 64-64V249c.1-35.2-28.6-63.9-63.9-63.9zm-644.4-39.7c0-6.6 4.4-11.1 8.3-11.1h321c3.4 0 6.6 3.1 7.8 7.4l12 43.4H187.7v-39.7zm638.4 745.8H187.7V255.1h638.4v636.1z"/><path d="M311.1 415.1a35 35 0 1 0 70 0 35 35 0 1 0-70 0zm151.2-35h257.8v70H462.3zM311.1 582.3a35 35 0 1 0 70 0 35 35 0 1 0-70 0zm151.2-35h257.8v70H462.3zM311.1 749.5a35 35 0 1 0 70 0 35 35 0 1 0-70 0zm151.2-35h257.8v70H462.3z"/></svg>

After

Width:  |  Height:  |  Size: 640 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M624 706.3h-74.1V464c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v242.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.7c3.2 4.1 9.4 4.1 12.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9z"/><path d="M811.4 366.7C765.6 245.9 648.9 160 512.2 160S258.8 245.8 213 366.6C127.3 389.1 64 467.2 64 560c0 110.5 89.5 200 199.9 200H304c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8h-40.1c-33.7 0-65.4-13.4-89-37.7-23.5-24.2-36-56.8-34.9-90.6.9-26.4 9.9-51.2 26.2-72.1 16.7-21.3 40.1-36.8 66.1-43.7l37.9-9.9 13.9-36.6c8.6-22.8 20.6-44.1 35.7-63.4 14.9-19.2 32.6-35.9 52.4-49.9 41.1-28.9 89.5-44.2 140-44.2s98.9 15.3 140 44.2c19.9 14 37.5 30.8 52.4 49.9 15.1 19.3 27.1 40.7 35.7 63.4l13.8 36.5 37.8 10C846.1 454.5 884 503.8 884 560c0 33.1-12.9 64.3-36.3 87.7-23.4 23.4-54.5 36.3-87.6 36.3H720c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h40.1C870.5 760 960 670.5 960 560c0-92.7-63.1-170.7-148.6-193.3z"/></svg>

After

Width:  |  Height:  |  Size: 962 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"/></svg>

After

Width:  |  Height:  |  Size: 175 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8 3v2H4v4H2V3h6zM2 21v-6h2v4h4v2H2zm20 0h-6v-2h4v-4h2v6zm0-12h-2V5h-4V3h6v6z"/></svg>

After

Width:  |  Height:  |  Size: 175 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M511.543 14.057C228.914 13.943 0 242.743 0 525.143 0 748.457 143.2 938.286 342.629 1008c26.857 6.743 22.742-12.343 22.742-25.371v-88.572C210.286 912.23 204 809.6 193.6 792.457c-21.029-35.886-70.743-45.028-55.886-62.171 35.315-18.172 71.315 4.571 113.029 66.171 30.171 44.686 89.028 37.143 118.857 29.714 6.514-26.857 20.457-50.857 39.657-69.485C248.571 727.886 181.6 629.829 181.6 513.257c0-56.571 18.629-108.571 55.2-150.514-23.314-69.143 2.171-128.343 5.6-137.143 66.4-5.943 135.429 47.543 140.8 51.771C420.914 267.2 464 261.83 512.229 261.83c48.457 0 91.657 5.6 129.714 15.885 12.914-9.828 76.914-55.771 138.628-50.171 3.315 8.8 28.229 66.628 6.286 134.857 37.029 42.057 55.886 94.514 55.886 151.2 0 116.8-67.429 214.971-228.572 243.314a145.714 145.714 0 0 1 43.543 104v128.572c.915 10.285 0 20.457 17.143 20.457 202.4-68.229 348.114-259.429 348.114-484.686 0-282.514-229.028-511.2-511.428-511.2z"/></svg>

After

Width:  |  Height:  |  Size: 1019 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M958.401 451.55a20.01 20.01 0 0 0-6.966-14.972L524.345 69.511c-7.499-6.446-18.581-6.446-26.08 0L309.583 231.676V129.657c0-11.05-8.902-19.533-19.952-19.533h-88.034c-11.048 0-19.928 8.482-19.928 19.533v211.954L71.176 436.578a20.003 20.003 0 0 0-6.968 15.174v105.5a20.007 20.007 0 0 0 33.052 15.172l53.298-45.826V850.7c0 60.678 49.364 110.042 110.042 110.042h504.192c60.678 0 110.043-49.364 110.043-110.042V527.026l51.586 44.336a20.001 20.001 0 0 0 21.48 2.966 20.006 20.006 0 0 0 11.566-18.343l-1.066-104.436zM221.579 150.033h48.095v115.942l-48.095 41.336V150.034zm349.14 770.692H436.665V700.642c0-11.03 8.977-20.007 20.008-20.007h94.036c11.03 0 20.007 8.976 20.007 20.007v220.084zm264.1-424.83v354.803c0 38.612-31.415 70.027-70.028 70.027H610.733V700.642c0-33.096-26.927-60.023-60.023-60.023h-94.036c-33.097 0-60.023 26.927-60.023 60.023v220.085H260.599c-38.612 0-70.027-31.415-70.027-70.027V495.895a20.07 20.07 0 0 0-.315-3.432L512.37 215.504l322.703 277.349a20.158 20.158 0 0 0-.255 3.042zM525.41 173.947c-7.502-6.446-18.587-6.447-26.086.003l-395.1 339.714v-52.727l407.081-349.87 407.177 349.952.522 51.205L525.41 173.948z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

1
src/assets/icons/ip.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1719843722868" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="226927" width="200" height="200"><path d="M276.854606 340.74413h468.523178v298.151114H276.854606z" fill="#0ee41c" p-id="226928"></path><path d="M511.116195 1.76761c-282.285215 0-511.116195 228.83098-511.116195 511.116195s228.83098 511.116195 511.116195 511.116195 511.116195-228.83098 511.116195-511.116195c0-282.263919-228.83098-511.116195-511.116195-511.116195z m276.854605 670.712227C787.9708 686.343864 759.284404 724.081276 745.420377 724.081276H575.005719v15.354782l42.593017 33.478111V787.9708H404.633654v-15.077927l42.593017-33.478111V724.081276h-170.414658C262.926689 724.081276 234.261589 686.343864 234.261589 672.479837V337.762619c0-13.864027 28.6651-39.611505 42.550424-39.611505h468.608364C759.284404 298.151114 787.9708 323.898592 787.9708 337.762619v334.717218z" fill="#0ee41c" p-id="226929"></path></svg>

After

Width:  |  Height:  |  Size: 937 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="m18.5 10 4.4 11h-2.155l-1.201-3h-4.09l-1.199 3h-2.154L16.5 10h2zM10 2v2h6v2h-1.968a18.221 18.221 0 0 1-3.62 6.301 14.865 14.865 0 0 0 2.335 1.707l-.75 1.878A17.016 17.016 0 0 1 9 13.725a16.677 16.677 0 0 1-6.201 3.548l-.536-1.929a14.7 14.7 0 0 0 5.327-3.042A18.078 18.078 0 0 1 4.767 8h2.24A16.031 16.031 0 0 0 9 10.877a16.165 16.165 0 0 0 2.91-4.876L2 6V4h6V2h2zm7.5 10.885L16.253 16h2.492L17.5 12.885z"/></svg>

After

Width:  |  Height:  |  Size: 501 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M374.272 440.832H127.488c-33.792 0-61.44-27.648-61.44-61.44V132.608c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c-.512 33.792-27.648 60.928-61.952 60.928zM127.488 132.608v247.296h247.296V132.608H127.488zM762.88 492.032c-16.384 0-31.744-6.144-43.52-17.92L544.768 299.52c-11.776-11.776-17.92-27.136-17.92-43.52s6.144-31.744 17.92-43.52L719.36 37.888c11.776-11.776 27.136-17.92 43.52-17.92s31.744 6.144 43.52 17.92L980.992 212.48c11.776 11.776 17.92 27.136 17.92 43.52s-6.144 31.744-17.92 43.52L806.4 474.112c-11.776 11.776-27.136 17.92-43.52 17.92zm0-410.624L588.288 256 762.88 430.592 937.472 256 762.88 81.408zM374.272 952.832H127.488c-33.792 0-61.44-27.648-61.44-61.44V644.096c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c-.512 34.304-27.648 61.44-61.952 61.44zM127.488 644.608v247.296h247.296V644.608H127.488zm758.784 308.224H638.976c-33.792 0-61.44-27.648-61.44-61.44V644.096c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c0 34.304-27.136 61.44-61.44 61.44zM639.488 644.608v247.296h247.296V644.608H639.488z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg t="1719845783644" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="277659" width="200" height="200"><path d="M392.297931 841.021793a130.01269 128.635586 90 1 0 257.271172 0 130.01269 128.635586 90 1 0-257.271172 0Z" fill="#FFD08D" p-id="277660"></path><path d="M456.174345 52.965517m50.458483 0l-0.035311 0q50.458483 0 50.458483 50.458483l0 59.568552q0 50.458483-50.458483 50.458482l0.035311 0q-50.458483 0-50.458483-50.458482l0-59.568552q0-50.458483 50.458483-50.458483Z" fill="#FFD293" p-id="277661"></path><path d="M520.933517 1006.344828c-90.641655 0-163.945931-74.081103-163.945931-165.323035 0-91.206621 73.304276-165.323034 163.945931-165.323034 90.606345 0 163.945931 74.116414 163.945931 165.323034 0 91.241931-73.339586 165.323034-163.945931 165.323035z m0-70.62069c51.447172 0 93.325241-42.301793 93.325242-94.702345 0-52.365241-41.878069-94.702345-93.325242-94.702345-51.482483 0-93.325241 42.337103-93.325241 94.702345 0 52.400552 41.842759 94.702345 93.325241 94.702345z" fill="#FCA100" p-id="277662"></path><path d="M506.632828 88.275862a15.148138 15.148138 0 0 0-15.148138 15.148138v59.603862a15.148138 15.148138 0 0 0 30.296276 0V103.424a15.148138 15.148138 0 0 0-15.183449-15.148138z m85.768827 15.148138v59.603862a85.768828 85.768828 0 1 1-171.537655 0V103.424a85.768828 85.768828 0 1 1 171.537655 0z" fill="#FB9C00" p-id="277663"></path><path d="M177.893517 494.344828c0-183.472552 147.173517-332.270345 328.739311-332.270345 181.530483 0 346.394483 148.797793 346.394482 332.270345v260.025379l100.034207 129.977379H77.85931l100.034207-129.977379V494.344828z" fill="#FFA300" p-id="277664"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style>@font-face{font-family:rbicon;src:url(chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2) format(&quot;woff2&quot;);font-weight:400;font-style:normal}</style></defs><path d="M64 64v576h832V64H64zM0 0h960v704H0V0z"/><path d="M192 896h576v64H192zm256-256h64v256h-64zm31.232-78.396 309.99-348.33-47.803-42.548-259.567 291.67-177.895-222.387L163.21 438.605l52.224 37.009 91.622-129.28z"/></svg>

After

Width:  |  Height:  |  Size: 525 B

View File

@ -0,0 +1 @@
<svg t="1719844718926" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="266272" width="200" height="200"><path d="M138.0173018 383.04044608h747.9653964c7.09277447 0 12.89595271-5.80317818 12.89595812-12.89595273v-64.47977419c0-28.37110348-23.21271811-51.58382158-51.58382153-51.58382161H497.81445089c-24.50231446 0-47.71503251-11.60636172-62.54538509-31.59508902l-24.50231442-33.52948343c-14.83034722-19.98873261-38.04306533-31.59508889-62.54537971-31.59509427h-145.72429566c-42.55665253 0-77.37573228 34.81907982-77.37573233 77.37573236v135.40753016c0 7.09277447 5.80317818 12.89595271 12.89595812 12.89595273zM885.9826982 415.2803386h-747.9653964c-7.09277447 0-12.89595271 5.80317818-12.89595812 12.89595272V787.97344057c0 42.55665253 34.81907982 77.37573228 77.37573233 77.37573223l619.00584798 1.28959637c42.55665253 0 77.37573228-34.81907982 77.37573233-77.37573236v-361.08674549c0-7.09277447-5.80317818-12.89595271-12.89595812-12.89595272z m-606.1098899 310.14771686c-1.28959636 1.93439451-3.22399088 3.86878903-5.8031835 5.80318347-32.88468534 20.63353074-67.05896691-13.54075089-46.4254362-46.42544153 1.28959636-1.93439451 3.22399088-3.86878903 5.80317822-5.80317821 32.88468534-20.63353074 67.70376514 14.18554911 46.42544148 46.42543627z m0-137.98671761c-1.28959636 1.93439451-3.22399088 3.86878903-5.8031835 5.80317817-32.88468534 20.63353074-67.05896691-13.54075089-46.4254362-46.4254362 1.28959636-1.93439451 3.22399088-3.86878903 5.80317822-5.80317818 32.88468534-21.27832364 67.70376514 13.54075089 46.42544148 46.42543621z m361.08674562 149.59307926h-264.36708411c-6.44797635 0-12.25115989-2.57919268-16.11994359-7.73757266-21.27832364-27.08150713-2.57919268-56.74220161 23.212718-56.74220164h264.36708417c6.44797635 0 12.25115989 2.57919268 16.11994364 7.73757283 21.27832364 27.08150713 2.57919268 56.74220161-23.21271811 56.74220147z m128.95954853-137.98671756h-393.32663264c-6.44797635 0-12.25115989-2.57919268-16.11994359-7.73757269-21.27832364-27.08150713-2.57919268-56.74220161 23.212718-56.74220692h393.32663275c6.44797635 0 12.25115989 2.57919268 16.11994354 7.7375727 21.27832364 27.08150713 2.57919268 56.74220161-23.21271806 56.74220691z" fill="#08D19F" p-id="266273"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

1
src/assets/icons/pv.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1719843111735" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="146261" width="200" height="200"><path d="M512 42.7C252.8 42.7 42.7 252.8 42.7 512c0 259.2 210.1 469.3 469.3 469.3S981.3 771.2 981.3 512c0-259.2-210.1-469.3-469.3-469.3z m93.3 225.9c16.1 0 29.1 13 29.1 29.1s-13.1 29.1-29.1 29.1c-16.1 0-29.1-13.1-29.1-29.1-0.1-16 13-29.1 29.1-29.1zM506.2 257c19.3 0 35 15.7 35 35s-15.7 35-35 35-35-15.7-35-35c0-19.4 15.7-35 35-35zM343 321.1c0-29 23.5-52.5 52.5-52.5s52.5 23.5 52.5 52.5-23.5 52.5-52.5 52.5c-29.1 0-52.5-23.5-52.5-52.5z m303.1 247.7c-11.7 35 11.7 81.6-11.7 128.2-23.3 46.6-58.3 69.9-93.3 69.9s-104.9 0-104.9-93.3c0-70 35-58.3 35-104.9s-23.3-23.3-58.3-81.6 0-93.3 0-93.3 58.3-58.3 174.9-23.3c116.6 35.1 69.9 163.4 58.3 198.3z m11.6-198.2c-12.9 0-23.3-10.4-23.3-23.3s10.4-23.3 23.3-23.3 23.3 10.4 23.3 23.3-10.4 23.3-23.3 23.3z" fill="#FFBD27" p-id="146262"></path></svg>

After

Width:  |  Height:  |  Size: 933 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="1em" height="1em" viewBox="0 0 512 512"><path d="m400 148-21.12-24.57A191.43 191.43 0 0 0 240 64C134 64 48 150 48 256s86 192 192 192a192.09 192.09 0 0 0 181.07-128" fill="none" stroke="currentColor" stroke-linecap="square" stroke-miterlimit="10" stroke-width="32"/><path d="M464 68.45V220a4 4 0 0 1-4 4H308.45a4 4 0 0 1-2.83-6.83L457.17 65.62a4 4 0 0 1 6.83 2.83z" fill="currentColor"/></svg>

After

Width:  |  Height:  |  Size: 458 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="256" height="256"><path d="M79.238 961.896v-25.442c0-109.28 28.835-214.892 81.139-297.416 48.427-76.396 115.304-131.573 195.508-161.896A240.785 240.785 0 0 1 279.488 300.5c0-131.538 104.331-238.535 232.547-238.535S744.546 168.962 744.546 300.5a240.854 240.854 0 0 1-76.742 176.988c190.87 73.004 276.992 277.131 276.992 458.966v25.442H79.238zM694.908 300.5c0-103.43-82.039-187.615-182.873-187.615-100.835 0-182.873 84.184-182.873 187.615 0 103.465 82.038 187.65 182.873 187.65 100.834 0 182.873-84.185 182.873-187.65zm-79.166 213.508a226.454 226.454 0 0 1-103.707 25.096A225.935 225.935 0 0 1 407.912 513.8C212.888 564.927 136.804 752.854 129.5 910.977h765.035c-7.997-167.4-95.227-347.746-278.793-396.97zm-143.411 37.246h79.407l39.739-8.48-45.242 65.664 30.6 227.527-64.8 56.908-69.197-56.908 40.535-227.527-50.78-65.665 39.738 8.48z"/></svg>

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="m12 1 9.5 5.5v11L12 23l-9.5-5.5v-11L12 1zm0 2.311L4.5 7.653v8.694l7.5 4.342 7.5-4.342V7.653L12 3.311zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10 6v15H8V6H2V4h14v2h-6zm8 8v7h-2v-7h-3v-2h8v2h-3z"/></svg>

After

Width:  |  Height:  |  Size: 149 B

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M139 669.6V164.3c0-12.7 10.3-23.1 23.1-23.1h694.4c12.7 0 23.1 10.4 23.1 23.1v248.5h70V164.3c0-51.3-41.8-93.1-93.1-93.1H162c-51.3.1-93 41.8-93 93.1v505.3c0 51.3 41.8 93.1 93.1 93.1h224.7v-70H162c-12.7 0-23-10.4-23-23.1zm-34.3 131h282v70h-282z"/><path d="m954.9 599.4-5.1-15c-11.5-33.9-29.4-64.9-53.2-91.9l-10.5-11.9h-83.2l-41.7-72.2-15.6-3.1c-34.8-6.9-71.3-6.9-106.1 0l-15.6 3.1-41.7 72.2H499l-10.5 11.9c-23.8 27.1-41.7 58-53.2 91.9l-5.1 15 41.7 72.2-41.7 72.2 5.1 15c11.5 33.9 29.4 64.9 53.2 91.9l10.5 11.9h83.2l41.7 72.2 15.6 3.1c17.4 3.5 35.3 5.2 53.1 5.2s35.6-1.8 53.1-5.2l15.6-3.1 41.7-72.2h83.2l10.5-11.9c23.8-27.1 41.7-58 53.2-91.9l5.1-15-41.7-72.2 41.6-72.2zm-76.8 151.2c-6.4 14.9-14.5 29-24.3 42h-91.2l-45.6 79c-16.1 1.9-32.4 1.9-48.5 0l-45.6-79h-91.2c-9.8-13-17.9-27-24.3-42l45.6-79.1-45.6-79.1c6.4-14.9 14.5-29 24.3-42h91.2l45.6-79c16.1-1.9 32.4-1.9 48.5 0l45.6 79h91.2c9.8 13 17.9 27 24.3 42l-45.6 79.1 45.6 79.1z"/><path d="M692.7 560.2c-61.4 0-111.3 49.9-111.3 111.3s49.9 111.3 111.3 111.3S804 732.9 804 671.5c0-61.3-49.9-111.3-111.3-111.3zm0 152.7c-22.8 0-41.3-18.5-41.3-41.3s18.5-41.3 41.3-41.3 41.3 18.5 41.3 41.3-18.5 41.3-41.3 41.3z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M0 64v896h1024V64H0zm384 576V448h256v192H384zm256 64v192H384V704h256zm0-512v192H384V192h256zm-320 0v192H64V192h256zM64 448h256v192H64V448zm640 0h256v192H704V448zm0-64V192h256v192H704zM64 704h256v192H64V704zm640 192V704h256v192H704z"/></svg>

After

Width:  |  Height:  |  Size: 351 B

View File

@ -0,0 +1 @@
<svg t="1719844784164" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="269353" width="200" height="200"><path d="M920.78 322.56L700.878 102.656c-36.199-36.198-94.925-36.198-131.123 0s-36.199 94.925 0 131.123l23.5 23.501-86.272 86.323c-123.033-75.11-285.798-59.494-392.192 46.9l-37.376 37.375L293.94 644.403l-89.088 89.088c-23.5 23.501-23.5 61.645 0 85.146s61.645 23.5 85.146 0l89.088-89.088L595.61 946.074l37.376-37.376c106.393-106.394 122.01-269.21 46.899-392.192l86.323-86.324 23.5 23.501c36.2 36.199 94.926 36.199 131.124 0s36.198-94.925-0.051-131.123z m-454.758 132.3a41.206 41.206 0 0 1-34.304 18.28 41.057 41.057 0 0 1-22.988-7.015c-55.91-37.581-122.266-8.09-122.932-7.783-20.633 9.728-45.21 0.87-54.886-19.763a41.196 41.196 0 0 1 19.763-54.886c4.403-2.048 108.851-50.023 204.083 13.926 18.893 12.698 23.962 38.349 11.264 57.242z" fill="#FF5C64" p-id="269354"></path><path d="M569.754 102.656c-36.199 36.198-36.199 94.925 0 131.123l23.5 23.501-86.272 86.323c-123.033-75.11-285.798-59.494-392.192 46.9l-37.376 37.375L293.94 644.403l-89.088 89.088c-23.5 23.501-23.5 61.645 0 85.146s61.645 23.5 85.146 0l89.088-89.088 105.83 105.83c99.226-42.445 182.119-115.558 236.851-207.462a319.145 319.145 0 0 0-41.881-111.411l86.323-86.324 20.173 20.173c4.3-26.624 6.656-53.862 6.656-81.664 0-82.073-19.61-159.539-54.221-228.147l-37.888-37.888c-36.25-36.198-94.976-36.198-131.174 0zM466.022 454.861a41.206 41.206 0 0 1-34.304 18.278 41.057 41.057 0 0 1-22.988-7.014c-55.91-37.581-122.266-8.09-122.932-7.783-20.633 9.728-45.21 0.87-54.886-19.763a41.196 41.196 0 0 1 19.763-54.886c4.403-2.048 108.851-50.023 204.083 13.926 18.893 12.698 23.962 38.349 11.264 57.242z" fill="#FF5C64" p-id="269355"></path><path d="M253.85 684.442c228.812-49.152 400.332-252.468 400.332-495.924 0-38.758-4.505-76.441-12.697-112.69-25.754-1.69-52.07 7.167-71.731 26.88-36.199 36.198-36.199 94.924 0 131.122l23.5 23.501-86.272 86.272c-123.033-75.11-285.798-59.494-392.192 46.9l-37.376 37.375L293.94 644.403l-40.09 40.039z m32-226.15c-20.634 9.727-45.21 0.87-54.887-19.764a41.196 41.196 0 0 1 19.763-54.886c4.404-2.048 108.852-50.023 204.084 13.926 18.892 12.698 23.961 38.349 11.264 57.242a41.206 41.206 0 0 1-34.304 18.278 41.057 41.057 0 0 1-22.99-7.014c-55.96-37.53-122.316-8.09-122.93-7.783z" fill="#FF5C64" p-id="269356"></path><path d="M230.912 438.58a41.196 41.196 0 0 1 19.763-54.887c3.226-1.536 60.058-27.546 127.642-16.333 18.022-18.074 34.662-37.53 49.817-58.112-107.827-30.618-228.505-3.584-313.395 81.306L77.363 427.93l71.629 71.628a502.748 502.748 0 0 0 103.885-40.243 41.861 41.861 0 0 1-21.965-20.736z" fill="#FF5C64" p-id="269357"></path></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M977.455 558.545h-34.91V453.818c0-44.218-37.236-81.454-81.454-81.454H546.909v-93.091h197.818c25.6 0 46.546-20.946 46.546-46.546V93.091c0-25.6-20.946-46.546-46.546-46.546H279.273c-25.6 0-46.546 20.946-46.546 46.546v139.636c0 25.6 20.946 46.546 46.546 46.546H477.09v93.09H162.909c-44.218 0-81.454 37.237-81.454 81.455v104.727h-34.91C20.945 558.545 0 579.491 0 605.091v325.818c0 25.6 20.945 46.546 46.545 46.546h139.637c25.6 0 46.545-20.946 46.545-46.546V605.091c0-25.6-20.945-46.546-46.545-46.546h-34.91V453.818c0-6.982 4.655-11.636 11.637-11.636h314.182v116.363h-34.91c-25.6 0-46.545 20.946-46.545 46.546v325.818c0 25.6 20.946 46.546 46.546 46.546h139.636c25.6 0 46.546-20.946 46.546-46.546V605.091c0-25.6-20.946-46.546-46.546-46.546H546.91V442.182h314.182c6.982 0 11.636 4.654 11.636 11.636v104.727h-34.909c-25.6 0-46.545 20.946-46.545 46.546v325.818c0 25.6 20.945 46.546 46.545 46.546h139.637c25.6 0 46.545-20.946 46.545-46.546V605.091c0-25.6-20.945-46.546-46.545-46.546zm-814.546 69.819v279.272H69.82V628.364h93.09zm395.636 0v279.272h-93.09V628.364h93.09zm-256-418.91v-93.09h418.91v93.09h-418.91zm651.637 698.182H861.09V628.364h93.09v279.272z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg t="1719843414729" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="175406" width="200" height="200"><path d="M512 1024C229.236364 1024 0 794.763636 0 512S229.236364 0 512 0s512 229.236364 512 512-229.236364 512-512 512z m56.599273-542.72a153.134545 153.134545 0 0 0 97.652363-142.149818C666.251636 254.789818 597.038545 186.181818 512 186.181818S357.794909 254.789818 357.794909 339.130182a153.134545 153.134545 0 0 0 97.605818 142.149818C328.471273 507.345455 232.727273 619.054545 232.727273 752.500364c0 32.488727 22.993455 43.240727 41.425454 51.851636l1.070546 0.465455c74.333091 26.065455 181.992727 33.000727 233.797818 33.000727 56.552727 0 167.191273-9.122909 240.686545-34.304 27.601455-10.472727 41.565091-27.648 41.565091-51.013818 0-133.492364-95.744-245.201455-222.673454-271.220364z" fill="#17E3C7" p-id="175407"></path></svg>

After

Width:  |  Height:  |  Size: 890 B

1
src/assets/icons/uv.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1719764607585" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="61790" width="200" height="200"><path d="M597.8 316.59c-8.82 0-17.64 1.26-25.2 3.78 18.9 27.72 28.98 60.48 28.98 97.03 0 39.06-13.86 76.87-37.8 108.37l-2.52 2.52v1.26c-2.52 2.52-6.3 6.3-7.56 10.08 0 1.26 0 1.26 1.26 1.26 2.52 1.26 6.3 2.52 10.08 2.52h1.26l5.04 2.52c51.66 16.38 95.77 45.36 124.75 81.91 12.6 16.38 20.16 35.28 20.16 55.44 0 11.34-2.52 20.16-6.3 30.24h36.54c28.98 0 51.66-21.42 51.66-49.14-1.26-13.86-5.04-23.94-12.6-32.76-21.42-26.46-54.18-49.14-95.77-61.74 0 0-16.38-3.78-21.42-6.3-8.82-6.3-13.86-16.38-13.86-27.72 0-12.6 10.08-22.68 16.38-28.98 16.38-20.16 26.46-46.62 26.46-76.87 0-61.76-44.1-113.42-99.54-113.42z m-142.4-27.72c-61.74 0-112.15 57.96-112.15 128.53 0 34.02 11.34 64.26 28.98 86.95 11.34 6.3 18.9 20.16 18.9 34.02 0 12.6-6.3 23.94-16.38 31.5v1.26c-1.26 0-2.52 1.26-2.52 1.26-6.3 3.78-12.6 6.3-20.16 6.3-47.88 16.38-88.21 41.58-112.15 73.09h1.26c-6.3 8.82-8.82 18.9-8.82 28.98 0 30.24 25.2 55.44 56.7 55.44h332.67c32.76 0 57.96-23.94 57.96-55.44 0-12.6-5.04-23.94-11.34-34.02-23.94-31.5-61.74-55.44-108.37-70.57 0 0-3.47-0.93-7.84-2.18l-9.15-2.78c-2.94-0.96-5.51-1.88-6.95-2.6-10.08-6.3-16.38-18.9-16.38-31.5 0-13.86 11.34-25.2 18.9-34.02 18.9-22.68 28.98-52.92 28.98-86.95 0.01-70.57-50.39-127.27-112.14-127.27zM511.95 65.2c247.06 0 447.33 200.28 447.33 447.33S759.01 959.87 511.95 959.87 64.62 759.59 64.62 512.53 264.9 65.2 511.95 65.2z" fill="#FF6800" p-id="61791"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/assets/images/401.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
src/assets/images/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,38 @@
<template>
<component :is="linkType" v-bind="linkProps(to)">
<slot></slot>
</component>
</template>
<script setup lang="ts">
defineOptions({
name: "AppLink",
inheritAttrs: false,
});
import { isExternal } from "@/utils/index";
const props = defineProps({
to: {
type: Object,
required: true,
},
});
const isExternalLink = computed(() => {
return isExternal(props.to.path || "");
});
const linkType = computed(() => (isExternalLink.value ? "a" : "router-link"));
const linkProps = (to: any) => {
if (isExternalLink.value) {
return {
href: to.path,
target: "_blank",
rel: "noopener noreferrer",
};
}
return { to: to };
};
</script>

View File

@ -0,0 +1,74 @@
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from "echarts/core";
// 引入内置组件组件后缀都为Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DatasetComponent, // 数据集组件
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
TransformComponent, // 数据转换器组件(filter, sort)
} from "echarts/components";
// 引入渲染器echarst默认使用canvas渲染引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from "echarts/features";
// 引入图表类型后缀都为Chart
import {
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
PictorialBarChart,
} from "echarts/charts";
// 注册必须的组件
echarts.use([
// 内置组件
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DatasetComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
TransformComponent,
// 渲染器
CanvasRenderer,
SVGRenderer,
// 特性
LabelLayout,
UniversalTransition,
// 图表
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
PictorialBarChart,
]);
export default echarts;

View File

@ -0,0 +1,43 @@
<template>
<div
:style="{
width: width,
height: height,
}"
ref="echartsRef"
></div>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, PropType } from "vue";
import { useEcharts, EChartsCoreOption } from "@/hooks/useEcharts"; // hooks
const props = defineProps({
options: { type: Object as PropType<EChartsCoreOption>, required: true },
height: { type: String, default: "100%" },
width: { type: String, default: "100%" },
themeColors: { type: Array as PropType<string[]>, default: () => [] },
});
const echartsRef = ref();
const { setOptions, initCharts } = useEcharts(echartsRef, props.options);
watch(
() => props.options,
(nVal) => {
let targetOptions: EChartsCoreOption = {};
if (props.themeColors && props.themeColors.length > 0) {
targetOptions = { ...nVal };
targetOptions.color = props.themeColors;
} else {
targetOptions = { ...nVal };
}
setOptions(targetOptions);
}
);
onMounted(() => {
initCharts();
});
</script>

View File

@ -0,0 +1,97 @@
<template>
<el-breadcrumb class="flex-y-center">
<transition-group
enter-active-class="animate__animated animate__fadeInRight"
>
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
<span
v-if="
item.redirect === 'noredirect' || index === breadcrumbs.length - 1
"
class="color-gray-400"
>{{ translateRouteTitle(item.meta.title) }}</span
>
<a v-else @click.prevent="handleLink(item)">
{{ translateRouteTitle(item.meta.title) }}
</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script setup lang="ts">
import { RouteLocationMatched } from "vue-router";
import { compile } from "path-to-regexp";
import router from "@/router";
import { translateRouteTitle } from "@/utils/i18n";
const currentRoute = useRoute();
const pathCompile = (path: string) => {
const { params } = currentRoute;
const toPath = compile(path);
return toPath(params);
};
const breadcrumbs = ref<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>
// element-plus
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
<template>
<el-form
ref="formRef"
label-width="auto"
v-bind="form"
:model="formData"
:rules="formRules"
>
<el-row :gutter="20">
<template v-for="item in formItems" :key="item.prop">
<el-col v-show="!item.hidden" v-bind="item.col">
<el-form-item :label="item.label" :prop="item.prop">
<!-- Label -->
<template #label v-if="item.tips">
<span>
{{ item.label }}
<el-tooltip
placement="bottom"
effect="light"
:content="item.tips"
:raw-content="true"
>
<el-icon style="vertical-align: -0.15em" size="16">
<QuestionFilled />
</el-icon>
</el-tooltip>
</span>
</template>
<!-- Input 输入框 -->
<template v-if="item.type === 'input' || item.type === undefined">
<el-input v-model="formData[item.prop]" v-bind="item.attrs" />
</template>
<!-- Select 选择器 -->
<template v-else-if="item.type === 'select'">
<el-select v-model="formData[item.prop]" v-bind="item.attrs">
<template v-for="option in item.options" :key="option.value">
<el-option v-bind="option" />
</template>
</el-select>
</template>
<!-- Radio 单选框 -->
<template v-else-if="item.type === 'radio'">
<el-radio-group v-model="formData[item.prop]" v-bind="item.attrs">
<template v-for="option in item.options" :key="option.value">
<el-radio v-bind="option" />
</template>
</el-radio-group>
</template>
<!-- Checkbox 多选框 -->
<template v-else-if="item.type === 'checkbox'">
<el-checkbox-group
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template v-for="option in item.options" :key="option.value">
<el-checkbox v-bind="option" />
</template>
</el-checkbox-group>
</template>
<!-- Input Number 数字输入框 -->
<template v-else-if="item.type === 'input-number'">
<el-input-number
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- TreeSelect 树形选择 -->
<template v-else-if="item.type === 'tree-select'">
<el-tree-select
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- DatePicker 日期选择器 -->
<template v-else-if="item.type === 'date-picker'">
<el-date-picker
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- Text 文本 -->
<template v-else-if="item.type === 'text'">
<el-text v-bind="item.attrs">{{ formData[item.prop] }}</el-text>
</template>
<!-- 自定义 -->
<template v-else-if="item.type === 'custom'">
<slot
:name="item.slotName ?? item.prop"
:prop="item.prop"
:formData="formData"
:attrs="item.attrs"
></slot>
</template>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from "element-plus";
import { reactive, ref, watch, watchEffect } from "vue";
import { IObject, IPageForm } from "./types";
//
const props = withDefaults(defineProps<IPageForm>(), {
pk: "id",
});
const formRef = ref<FormInstance>();
const formItems = reactive(props.formItems);
const formData = reactive<IObject>({});
const formRules: FormRules = {};
const prepareFuncs = [];
for (const item of formItems) {
item.initFn && item.initFn(item);
formData[item.prop] = item.initialValue ?? "";
formRules[item.prop] = item.rules ?? [];
if (item.watch !== undefined) {
prepareFuncs.push(() => {
watch(
() => formData[item.prop],
(newValue, oldValue) => {
item.watch && item.watch(newValue, oldValue, formData, formItems);
}
);
});
}
if (item.computed !== undefined) {
prepareFuncs.push(() => {
watchEffect(() => {
item.computed && (formData[item.prop] = item.computed(formData));
});
});
}
if (item.watchEffect !== undefined) {
prepareFuncs.push(() => {
watchEffect(() => {
item.watchEffect && item.watchEffect(formData);
});
});
}
}
prepareFuncs.forEach((func) => func());
//
function getFormData(key?: string) {
return key === undefined ? formData : formData[key] ?? undefined;
}
//
function setFormData(data: IObject) {
for (const key in formData) {
if (formData.hasOwnProperty(key) && key in data) {
formData[key] = data[key];
}
}
if (data?.hasOwnProperty(props.pk)) {
formData[props.pk] = data[props.pk];
}
}
//
function setFormItemData(key: string, value: any) {
formData[key] = value;
}
//
defineExpose({ formRef, getFormData, setFormData, setFormItemData });
</script>

View File

@ -0,0 +1,405 @@
<template>
<!-- drawer -->
<template v-if="modalConfig.component === 'drawer'">
<el-drawer
v-model="modalVisible"
:append-to-body="true"
v-bind="modalConfig.drawer"
@close="handleCloseModal"
>
<!-- 表单 -->
<el-form
ref="formRef"
label-width="auto"
v-bind="modalConfig.form"
:model="formData"
:rules="formRules"
>
<el-row :gutter="20">
<template v-for="item in formItems" :key="item.prop">
<el-col v-show="!item.hidden" v-bind="item.col">
<el-form-item :label="item.label" :prop="item.prop">
<!-- Label -->
<template #label v-if="item.tips">
<span>
{{ item.label }}
<el-tooltip
placement="bottom"
effect="light"
:content="item.tips"
:raw-content="true"
>
<el-icon style="vertical-align: -0.15em" size="16">
<QuestionFilled />
</el-icon>
</el-tooltip>
</span>
</template>
<!-- Input 输入框 -->
<template
v-if="item.type === 'input' || item.type === undefined"
>
<el-input v-model="formData[item.prop]" v-bind="item.attrs" />
</template>
<!-- Select 选择器 -->
<template v-else-if="item.type === 'select'">
<el-select v-model="formData[item.prop]" v-bind="item.attrs">
<template
v-for="option in item.options"
:key="option.value"
>
<el-option v-bind="option" />
</template>
</el-select>
</template>
<!-- Radio 单选框 -->
<template v-else-if="item.type === 'radio'">
<el-radio-group
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template
v-for="option in item.options"
:key="option.value"
>
<el-radio v-bind="option" />
</template>
</el-radio-group>
</template>
<!-- Checkbox 多选框 -->
<template v-else-if="item.type === 'checkbox'">
<el-checkbox-group
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template
v-for="option in item.options"
:key="option.value"
>
<el-checkbox v-bind="option" />
</template>
</el-checkbox-group>
</template>
<!-- Input Number 数字输入框 -->
<template v-else-if="item.type === 'input-number'">
<el-input-number
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- TreeSelect 树形选择 -->
<template v-else-if="item.type === 'tree-select'">
<el-tree-select
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- DatePicker 日期选择器 -->
<template v-else-if="item.type === 'date-picker'">
<el-date-picker
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- Text 文本 -->
<template v-else-if="item.type === 'text'">
<el-text v-bind="item.attrs">
{{ formData[item.prop] }}
</el-text>
</template>
<!-- 自定义 -->
<template v-else-if="item.type === 'custom'">
<slot
:name="item.slotName ?? item.prop"
:prop="item.prop"
:formData="formData"
:attrs="item.attrs"
></slot>
</template>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<!-- 弹窗底部操作按钮 -->
<template #footer>
<div>
<el-button type="primary" @click="handleSubmit"> </el-button>
<el-button @click="handleCloseModal"> </el-button>
</div>
</template>
</el-drawer>
</template>
<!-- dialog -->
<template v-else>
<el-dialog
v-model="modalVisible"
:align-center="true"
:append-to-body="true"
width="70vw"
v-bind="modalConfig.dialog"
style="padding-right: 0"
@close="handleCloseModal"
>
<!-- 滚动 -->
<el-scrollbar max-height="60vh">
<!-- 表单 -->
<el-form
ref="formRef"
label-width="auto"
v-bind="modalConfig.form"
style="padding-right: var(--el-dialog-padding-primary)"
:model="formData"
:rules="formRules"
>
<el-row :gutter="20">
<template v-for="item in formItems" :key="item.prop">
<el-col v-show="!item.hidden" v-bind="item.col">
<el-form-item :label="item.label" :prop="item.prop">
<!-- Label -->
<template #label v-if="item.tips">
<span>
{{ item.label }}
<el-tooltip
placement="bottom"
effect="light"
:content="item.tips"
:raw-content="true"
>
<el-icon style="vertical-align: -0.15em" size="16">
<QuestionFilled />
</el-icon>
</el-tooltip>
</span>
</template>
<!-- Input 输入框 -->
<template
v-if="item.type === 'input' || item.type === undefined"
>
<el-input
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- Select 选择器 -->
<template v-else-if="item.type === 'select'">
<el-select
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template
v-for="option in item.options"
:key="option.value"
>
<el-option v-bind="option" />
</template>
</el-select>
</template>
<!-- Radio 单选框 -->
<template v-else-if="item.type === 'radio'">
<el-radio-group
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template
v-for="option in item.options"
:key="option.value"
>
<el-radio v-bind="option" />
</template>
</el-radio-group>
</template>
<!-- Checkbox 多选框 -->
<template v-else-if="item.type === 'checkbox'">
<el-checkbox-group
v-model="formData[item.prop]"
v-bind="item.attrs"
>
<template
v-for="option in item.options"
:key="option.value"
>
<el-checkbox v-bind="option" />
</template>
</el-checkbox-group>
</template>
<!-- Input Number 数字输入框 -->
<template v-else-if="item.type === 'input-number'">
<el-input-number
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- TreeSelect 树形选择 -->
<template v-else-if="item.type === 'tree-select'">
<el-tree-select
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- DatePicker 日期选择器 -->
<template v-else-if="item.type === 'date-picker'">
<el-date-picker
v-model="formData[item.prop]"
v-bind="item.attrs"
/>
</template>
<!-- Text 文本 -->
<template v-else-if="item.type === 'text'">
<el-text v-bind="item.attrs">
{{ formData[item.prop] }}
</el-text>
</template>
<!-- 自定义 -->
<template v-else-if="item.type === 'custom'">
<slot
:name="item.slotName ?? item.prop"
:prop="item.prop"
:formData="formData"
:attrs="item.attrs"
></slot>
</template>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
</el-scrollbar>
<!-- 弹窗底部操作按钮 -->
<template #footer>
<div style="padding-right: var(--el-dialog-padding-primary)">
<el-button type="primary" @click="handleSubmit"> </el-button>
<el-button @click="handleCloseModal"> </el-button>
</div>
</template>
</el-dialog>
</template>
</template>
<script setup lang="ts">
import { useThrottleFn } from "@vueuse/core";
import type { FormInstance, FormRules } from "element-plus";
import { nextTick, reactive, ref, watch, watchEffect } from "vue";
import type { IModalConfig, IObject } from "./types";
//
const props = defineProps<{
modalConfig: IModalConfig;
}>();
//
const emit = defineEmits<{
submitClick: [];
}>();
const pk = props.modalConfig.pk ?? "id";
const modalVisible = ref(false);
const formRef = ref<FormInstance>();
const formItems = reactive(props.modalConfig.formItems);
const formData = reactive<IObject>({});
const formRules: FormRules = {};
const prepareFuncs = [];
for (const item of formItems) {
item.initFn && item.initFn(item);
formData[item.prop] = item.initialValue ?? "";
formRules[item.prop] = item.rules ?? [];
if (item.watch !== undefined) {
prepareFuncs.push(() => {
watch(
() => formData[item.prop],
(newValue, oldValue) => {
item.watch && item.watch(newValue, oldValue, formData, formItems);
}
);
});
}
if (item.computed !== undefined) {
prepareFuncs.push(() => {
watchEffect(() => {
item.computed && (formData[item.prop] = item.computed(formData));
});
});
}
if (item.watchEffect !== undefined) {
prepareFuncs.push(() => {
watchEffect(() => {
item.watchEffect && item.watchEffect(formData);
});
});
}
}
prepareFuncs.forEach((func) => func());
//
function getFormData(key?: string) {
return key === undefined ? formData : formData[key] ?? undefined;
}
//
function setFormData(data: IObject) {
for (const key in formData) {
if (formData.hasOwnProperty(key) && key in data) {
formData[key] = data[key];
}
}
if (data?.hasOwnProperty(pk)) {
formData[pk] = data[pk];
}
}
//
function setFormItemData(key: string, value: any) {
formData[key] = value;
}
// modal
function setModalVisible(data: IObject = {}) {
modalVisible.value = true;
// nextTick
nextTick(() => {
Object.values(data).length > 0 && setFormData(data);
});
}
//
const handleSubmit = useThrottleFn(() => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
if (typeof props.modalConfig.beforeSubmit === "function") {
props.modalConfig.beforeSubmit(formData);
}
props.modalConfig.formAction(formData).then(() => {
let msg = "操作成功";
if (props.modalConfig.component === "drawer") {
if (props.modalConfig.drawer?.title) {
msg = `${props.modalConfig.drawer?.title}成功`;
}
} else {
if (props.modalConfig.dialog?.title) {
msg = `${props.modalConfig.dialog?.title}成功`;
}
}
ElMessage.success(msg);
emit("submitClick");
handleCloseModal();
});
}
});
}, 3000);
//
function handleCloseModal() {
modalVisible.value = false;
formRef.value?.resetFields();
nextTick(() => {
formRef.value?.clearValidate();
});
}
//
defineExpose({ setModalVisible, getFormData, setFormData, setFormItemData });
</script>
<style lang="scss" scoped></style>

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