Browse Source

初次提交。

jiaxiaoqiang 11 tháng trước cách đây
commit
65b11e7fb2
100 tập tin đã thay đổi với 5272 bổ sung0 xóa
  1. 15 0
      .editorconfig
  2. 17 0
      .env.development
  3. 6 0
      .env.production
  4. 14 0
      .eslintignore
  5. 284 0
      .eslintrc-auto-import.json
  6. 88 0
      .eslintrc.cjs
  7. 18 0
      .gitignore
  8. 11 0
      .prettierignore
  9. 46 0
      .prettierrc.cjs
  10. 11 0
      .stylelintignore
  11. 51 0
      .stylelintrc.cjs
  12. 11 0
      .vscode/extensions.json
  13. 80 0
      .vscode/settings.json
  14. 199 0
      CHANGELOG.md
  15. 21 0
      LICENSE
  16. 4 0
      README.en-US.md
  17. 19 0
      README.md
  18. 93 0
      commitlint.config.cjs
  19. 66 0
      index.html
  20. 21 0
      licenses/vue-element-admin/LICENSE
  21. 21 0
      licenses/vue3-element-admin/LICENSE
  22. 43 0
      mock/auth.mock.ts
  23. 10 0
      mock/base.ts
  24. 147 0
      mock/dept.mock.ts
  25. 247 0
      mock/dict.mock.ts
  26. 1470 0
      mock/menu.mock.ts
  27. 335 0
      mock/role.mock.ts
  28. 175 0
      mock/user.mock.ts
  29. 124 0
      package.json
  30. BIN
      public/favicon.ico
  31. 37 0
      src/App.vue
  32. 52 0
      src/api/auth/index.ts
  33. 61 0
      src/api/auth/types.ts
  34. 77 0
      src/api/dept/index.ts
  35. 71 0
      src/api/dept/types.ts
  36. 148 0
      src/api/dict/index.ts
  37. 144 0
      src/api/dict/types.ts
  38. 34 0
      src/api/file/index.ts
  39. 7 0
      src/api/file/types.ts
  40. 88 0
      src/api/menu/index.ts
  41. 134 0
      src/api/menu/types.ts
  42. 114 0
      src/api/order/index.ts
  43. 89 0
      src/api/order/types.ts
  44. 112 0
      src/api/role/index.ts
  45. 78 0
      src/api/role/types.ts
  46. 78 0
      src/api/system/log/index.ts
  47. 140 0
      src/api/user/index.ts
  48. 116 0
      src/api/user/types.ts
  49. 1 0
      src/assets/icons/api.svg
  50. 1 0
      src/assets/icons/captcha.svg
  51. 1 0
      src/assets/icons/cascader.svg
  52. 1 0
      src/assets/icons/client.svg
  53. 1 0
      src/assets/icons/close.svg
  54. 1 0
      src/assets/icons/close_all.svg
  55. 1 0
      src/assets/icons/close_left.svg
  56. 1 0
      src/assets/icons/close_other.svg
  57. 1 0
      src/assets/icons/close_right.svg
  58. 1 0
      src/assets/icons/dict.svg
  59. 1 0
      src/assets/icons/document.svg
  60. 1 0
      src/assets/icons/download.svg
  61. 1 0
      src/assets/icons/edit.svg
  62. 1 0
      src/assets/icons/eye-open.svg
  63. 1 0
      src/assets/icons/eye.svg
  64. 1 0
      src/assets/icons/fullscreen-exit.svg
  65. 1 0
      src/assets/icons/fullscreen.svg
  66. 1 0
      src/assets/icons/github.svg
  67. 1 0
      src/assets/icons/homepage.svg
  68. 1 0
      src/assets/icons/indent-decrease.svg
  69. 1 0
      src/assets/icons/ip.svg
  70. 1 0
      src/assets/icons/language.svg
  71. 1 0
      src/assets/icons/link.svg
  72. 1 0
      src/assets/icons/lock.svg
  73. 1 0
      src/assets/icons/menu.svg
  74. 1 0
      src/assets/icons/message.svg
  75. 1 0
      src/assets/icons/money.svg
  76. 1 0
      src/assets/icons/monitor.svg
  77. 1 0
      src/assets/icons/moon.svg
  78. 1 0
      src/assets/icons/order.svg
  79. 1 0
      src/assets/icons/peoples.svg
  80. 1 0
      src/assets/icons/project.svg
  81. 1 0
      src/assets/icons/publish.svg
  82. 1 0
      src/assets/icons/refresh.svg
  83. 1 0
      src/assets/icons/role.svg
  84. 1 0
      src/assets/icons/security.svg
  85. 1 0
      src/assets/icons/setting.svg
  86. 1 0
      src/assets/icons/size.svg
  87. 1 0
      src/assets/icons/sunny.svg
  88. 1 0
      src/assets/icons/system.svg
  89. 1 0
      src/assets/icons/table.svg
  90. 1 0
      src/assets/icons/todolist.svg
  91. 1 0
      src/assets/icons/tree.svg
  92. 1 0
      src/assets/icons/user.svg
  93. 1 0
      src/assets/icons/visit.svg
  94. BIN
      src/assets/images/401.gif
  95. BIN
      src/assets/images/404.png
  96. BIN
      src/assets/images/404_cloud.png
  97. BIN
      src/assets/images/login-bg-dark.jpg
  98. BIN
      src/assets/images/login-bg.jpg
  99. BIN
      src/assets/logo.png
  100. 0 0
      src/common/configs/buttonPermission.ts

+ 15 - 0
.editorconfig

@@ -0,0 +1,15 @@
+# http://editorconfig.org
+root = true
+
+# 表示所有文件适用
+[*]
+charset = utf-8 # 设置文件字符集为 utf-8
+end_of_line = lf # 控制换行类型(lf | cr | crlf)
+indent_style = space # 缩进风格(tab | space)
+indent_size = 2 # 缩进大小
+insert_final_newline = true # 始终在文件末尾插入一个新行
+
+# 表示仅 md 文件适用以下规则
+[*.md]
+max_line_length = off # 关闭最大行长度限制
+trim_trailing_whitespace = false # 关闭末尾空格修剪

+ 17 - 0
.env.development

@@ -0,0 +1,17 @@
+## 开发环境
+NODE_ENV='development'
+
+# 应用端口
+VITE_APP_PORT = 3005
+
+# 代理前缀
+VITE_APP_BASE_API = '/dev-api'
+
+# 线上接口地址
+# VITE_APP_API_URL = http://vapi.youlai.tech
+# 开发接口地址
+# VITE_APP_API_URL = 'http://192.168.101.4:8078'
+VITE_APP_API_URL = 'http://192.168.101.51:8078'
+
+# 是否启用 Mock 服务
+VITE_MOCK_DEV_SERVER = false

+ 6 - 0
.env.production

@@ -0,0 +1,6 @@
+## 生产环境
+NODE_ENV='production'
+
+# 代理前缀
+VITE_APP_BASE_API = '/prod-api'
+

+ 14 - 0
.eslintignore

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

+ 284 - 0
.eslintrc-auto-import.json

@@ -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 - 0
.eslintrc.cjs

@@ -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 - 0
.gitignore

@@ -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

+ 11 - 0
.prettierignore

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

+ 46 - 0
.prettierrc.cjs

@@ -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: "css",
+  // 当文件已经被 Prettier 格式化之后,是否会在文件顶部插入一个特殊的 @format 标记,默认false
+  insertPragma: false,
+  // 在 JSX 中使用单引号替代双引号,默认false
+  jsxSingleQuote: false,
+  // 每行最多字符数量,超出换行(默认80)
+  printWidth: 80,
+  // 超出打印宽度 (always | never | preserve )
+  proseWrap: "preserve",
+  // 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;)
+  quoteProps: "as-needed",
+  // 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件,默认false
+  requirePragma: false,
+  // 结尾添加分号
+  semi: true,
+  // 使用单引号 (true:单引号;false:双引号)
+  singleQuote: false,
+  // 缩进空格数,默认2个空格
+  tabWidth: 2,
+  // 元素末尾是否加逗号,默认es5: ES5中的 objects, arrays 等会添加逗号,TypeScript 中的 type 后不加逗号
+  trailingComma: "es5",
+  // 指定缩进方式,空格或tab,默认false,即使用空格
+  useTabs: false,
+  // vue 文件中是否缩进 <style> 和 <script> 标签,默认 false
+  vueIndentScriptAndStyle: false,
+
+  endOfLine: "auto",
+  overrides: [
+    {
+      files: "*.html",
+      options: {
+        parser: "html",
+      },
+    },
+  ],
+};

+ 11 - 0
.stylelintignore

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

+ 51 - 0
.stylelintrc.cjs

@@ -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 - 0
.vscode/extensions.json

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

+ 80 - 0
.vscode/settings.json

@@ -0,0 +1,80 @@
+{
+  "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": "{locale}/{namespaces}.{ext}",
+  "i18n-ally.enabledParsers": ["ts"],
+  "i18n-ally.sourceLanguage": "en",
+  "i18n-ally.displayLanguage": "zh-CN",
+  "i18n-ally.enabledFrameworks": [
+    "vue",
+    "react"
+  ],
+  "i18n-ally.localesPaths": [
+    "src/lang"
+  ],
+}

+ 199 - 0
CHANGELOG.md

@@ -0,0 +1,199 @@
+# 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
+- 项目配置按钮移入navbar(author 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
+- 新增 Mock(author by [ygcaicn](https://github.com/ygcaicn))
+- 图标 DEMO(author 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 - 0
LICENSE

@@ -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.

+ 4 - 0
README.en-US.md

@@ -0,0 +1,4 @@
+详见中文readme
+
+
+

+ 19 - 0
README.md

@@ -0,0 +1,19 @@
+项目启动
+# 克隆代码
+git clone https://gitee.com/icemelonreagon/vue-admin.git
+# 安装 pnpm
+npm install pnpm -g
+# 安装依赖
+pnpm install
+# 启动运行
+pnpm run dev
+
+
+
+项目和编码规范:
+1.配置: 在common/configs里面配置按钮权限,字典数据等。
+2.Git: 提交代码必须说明做了什么事情。 模块,页面,功能。例如:1.菜单管理列表新增按钮权限。2.xxxx。 3.xxxx。
+3.启动项目后需打开检查,控制台不能有警告和报错信息。
+
+代码示例:
+和crud相关代码可以参看hooksDemo.vue (目前不够特别全面,需要什么后续可以在userCrud.ts里面添加)

+ 93 - 0
commitlint.config.cjs

@@ -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: "",
+  },
+};

+ 66 - 0
index.html

@@ -0,0 +1,66 @@
+<!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>综合管控采集平台</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 {
+      position: relative;
+      width: 40px;
+      aspect-ratio: 0.577;
+      overflow: hidden;
+      clip-path: polygon(0 0, 100% 100%, 0 100%, 100% 0);
+      animation: l19 2s infinite linear;
+    }
+
+    .loader::before {
+      position: absolute;
+      inset: -150%;
+      content: "";
+      background: repeating-conic-gradient(
+        from 30deg,
+        #ffabab 0 60deg,
+        #abe4ff 0 120deg,
+        #ff7373 0 180deg
+      );
+      animation: inherit;
+      animation-direction: reverse;
+    }
+
+    @keyframes l19 {
+      100% {
+        transform: rotate(360deg);
+      }
+    }
+  </style>
+</html>

+ 21 - 0
licenses/vue-element-admin/LICENSE

@@ -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.

+ 21 - 0
licenses/vue3-element-admin/LICENSE

@@ -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.

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 43 - 0
mock/auth.mock.ts


+ 10 - 0
mock/base.ts

@@ -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
+  );
+});

+ 147 - 0
mock/dept.mock.ts

@@ -0,0 +1,147 @@
+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: "有来技术",
+          sort: 1,
+          status: 1,
+          children: [
+            {
+              id: 2,
+              parentId: 1,
+              name: "研发部门",
+              sort: 1,
+              status: 1,
+              children: [],
+              createTime: null,
+              updateTime: "2022-04-19 12:46",
+            },
+            {
+              id: 3,
+              parentId: 1,
+              name: "测试部门",
+              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: "有来技术",
+    parentId: 0,
+    status: 1,
+    sort: 1,
+  },
+  2: {
+    id: 2,
+    name: "研发部门",
+    parentId: 1,
+    status: 1,
+    sort: 1,
+  },
+  3: {
+    id: 3,
+    name: "测试部门",
+    parentId: 1,
+    status: 1,
+    sort: 1,
+  },
+};

+ 247 - 0
mock/dict.mock.ts

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

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1470 - 0
mock/menu.mock.ts


+ 335 - 0
mock/role.mock.ts

@@ -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,
+  },
+};

+ 175 - 0
mock/user.mock.ts

@@ -0,0 +1,175 @@
+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: ["ADMIN"],
+        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:reset_pwd",
+          "sys:dept:add",
+          "sys:role:delete",
+          "sys:dict_type:delete",
+          "sys:menu:edit",
+          "sys:dict:add",
+          "sys:role:add",
+        ],
+      },
+      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,
+      };
+    },
+  },
+]);
+
+// 用户映射表数据
+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],
+  },
+};

+ 124 - 0
package.json

@@ -0,0 +1,124 @@
+{
+  "name": "综合管控采集平台",
+  "version": "1.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "preinstall": "npx only-allow pnpm",
+    "dev": "vite serve --mode development",
+    "build:prod": "vite build --mode production && vue-tsc --noEmit",
+    "prepare": "husky",
+    "lint:eslint": "eslint  --fix --ext .ts,.js,.vue ./src ",
+    "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
+    "lint:stylelint": "stylelint  \"**/*.{css,scss,vue}\" --fix",
+    "lint:lint-staged": "lint-staged",
+    "commit": "git-cz"
+  },
+  "config": {
+    "commitizen": {
+      "path": "node_modules/cz-git"
+    }
+  },
+  "lint-staged": {
+    "*.{js,ts}": [
+      "eslint --fix",
+      "prettier --write"
+    ],
+    "*.{cjs,json}": [
+      "prettier --write"
+    ],
+    "*.{vue,html}": [
+      "eslint --fix",
+      "prettier --write",
+      "stylelint --fix"
+    ],
+    "*.{scss,css}": [
+      "stylelint --fix",
+      "prettier --write"
+    ],
+    "*.md": [
+      "prettier --write"
+    ]
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "@smallwei/avue": "^3.3.3",
+    "@types/smallwei__avue": "^3.0.5",
+    "@vueuse/core": "^10.9.0",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "5.1.10",
+    "animate.css": "^4.1.1",
+    "axios": "^1.6.7",
+    "echarts": "^5.5.0",
+    "element-plus": "^2.6.0",
+    "lodash-es": "^4.17.21",
+    "net": "^1.0.2",
+    "nprogress": "^0.2.0",
+    "path-browserify": "^1.0.1",
+    "path-to-regexp": "^6.2.1",
+    "pinia": "^2.1.7",
+    "sockjs-client": "1.6.1",
+    "sortablejs": "^1.15.2",
+    "stompjs": "^2.3.3",
+    "vue": "^3.4.21",
+    "vue-i18n": "9.9.1",
+    "vue-pdf-embed": "^2.0.2",
+    "vue-router": "^4.3.0",
+    "vue3-pdfjs": "^0.1.6",
+    "xlsx": "^0.18.5"
+  },
+  "devDependencies": {
+    "@commitlint/cli": "^18.6.1",
+    "@commitlint/config-conventional": "^18.6.2",
+    "@iconify-json/ep": "^1.1.14",
+    "@types/lodash": "^4.14.202",
+    "@types/node": "^20.11.24",
+    "@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",
+    "@typescript-eslint/eslint-plugin": "^7.1.1",
+    "@typescript-eslint/parser": "^7.1.1",
+    "@vitejs/plugin-vue": "^5.0.4",
+    "@vitejs/plugin-vue-jsx": "^3.1.0",
+    "autoprefixer": "^10.4.18",
+    "commitizen": "^4.3.0",
+    "cz-git": "^1.9.0",
+    "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.22.0",
+    "fast-glob": "^3.3.2",
+    "husky": "^9.0.11",
+    "lint-staged": "^15.2.2",
+    "postcss": "^8.4.35",
+    "postcss-html": "^1.6.0",
+    "postcss-scss": "^4.0.9",
+    "prettier": "^3.2.5",
+    "sass": "^1.71.1",
+    "stylelint": "^16.2.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.0",
+    "terser": "^5.28.1",
+    "typescript": "^5.3.3",
+    "unocss": "^0.58.5",
+    "unplugin-auto-import": "^0.17.5",
+    "unplugin-icons": "^0.18.5",
+    "unplugin-vue-components": "^0.26.0",
+    "vite": "^5.1.5",
+    "vite-plugin-mock-dev-server": "^1.4.7",
+    "vite-plugin-svg-icons": "^2.0.1",
+    "vue-tsc": "^2.0.4"
+  },
+  "repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
+  "author": "有来开源组织",
+  "license": "MIT",
+  "engines": {
+    "node": ">=18.0.0"
+  }
+}

BIN
public/favicon.ico


+ 37 - 0
src/App.vue

@@ -0,0 +1,37 @@
+<template>
+  <el-config-provider :locale="locale" :size="size">
+    <!-- 开启水印 -->
+    <el-watermark
+      v-if="watermarkEnabled"
+      :font="{ color: fontColor }"
+      :content="defaultSettings.watermarkContent"
+      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";
+
+const appStore = useAppStore();
+const settingsStore = useSettingsStore();
+
+const locale = computed(() => appStore.locale);
+const size = computed(
+  () => appStore.size as "default" | "small" | "large" | undefined
+);
+const watermarkEnabled = computed(() => settingsStore.watermarkEnabled);
+
+// 明亮/暗黑主题水印字体颜色适配
+const fontColor = computed(() => {
+  return settingsStore.theme === ThemeEnum.DARK
+    ? "rgba(255, 255, 255, .15)"
+    : "rgba(0, 0, 0, .15)";
+});
+</script>

+ 52 - 0
src/api/auth/index.ts

@@ -0,0 +1,52 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { CaptchaResult, LoginData, LoginResult } from "./types";
+
+/**
+ * 登录API
+ *
+ * @param data {LoginData}
+ * @returns
+ */
+export function loginApi(data: LoginData): AxiosPromise<LoginResult> {
+  // const formData = new FormData();
+  // formData.append("userName", data.username);
+  // formData.append("password", data.password);
+  // formData.append("captchaKey", data.captchaKey || "");
+  // formData.append("captchaCode", data.captchaCode || "");
+  return request({
+    url: "/api/auth/backLogin",
+    method: "post",
+    data: data,
+    // headers: {
+    //   "Content-Type": "multipart/form-data",
+    // },
+  });
+}
+
+/**
+ * 注销API
+ */
+export function logoutApi() {
+  return request({
+    url: "/api/auth/loginOut",
+    method: "post",
+  });
+}
+
+/**
+ * 获取验证码
+ */
+export function getCaptchaApi(): AxiosPromise<CaptchaResult> {
+  return request({
+    url: "/api/v1/auth/captcha",
+    method: "get",
+  });
+}
+
+export function getOrgListApi(): AxiosPromise<any[]> {
+  return request({
+    url: "/api/v1/sys/dept/orgList",
+    method: "get",
+  });
+}

+ 61 - 0
src/api/auth/types.ts

@@ -0,0 +1,61 @@
+/**
+ * 登录请求参数
+ */
+export interface LoginData {
+  /**
+   * 用户名
+   */
+  userName: string;
+  /**
+   * 密码
+   */
+  password: string;
+
+  /**
+   * 验证码缓存key
+   */
+  captchaKey?: string;
+
+  /**
+   * 验证码
+   */
+  captchaCode?: string;
+
+  orgId: number;
+}
+
+/**
+ * 登录响应
+ */
+export interface LoginResult {
+  /**
+   * 访问token
+   */
+  accessToken?: string;
+  /**
+   * 过期时间(单位:毫秒)
+   */
+  expires?: number;
+  /**
+   * 刷新token
+   */
+  refreshToken?: string;
+  /**
+   * token 类型
+   */
+  tokenType?: string;
+}
+
+/**
+ * 验证码响应
+ */
+export interface CaptchaResult {
+  /**
+   * 验证码缓存key
+   */
+  captchaKey: string;
+  /**
+   * 验证码图片Base64字符串
+   */
+  captchaBase64: string;
+}

+ 77 - 0
src/api/dept/index.ts

@@ -0,0 +1,77 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { DeptForm, DeptQuery, DeptVO } from "./types";
+
+/**
+ * 部门树形表格
+ *
+ * @param queryParams
+ */
+export function listDepts(queryParams?: DeptQuery): AxiosPromise<DeptVO[]> {
+  return request({
+    url: "/api/v1/dept",
+    method: "get",
+    params: queryParams,
+  });
+}
+
+/**
+ * 部门下拉列表
+ */
+export function getDeptOptions(): AxiosPromise<OptionType[]> {
+  return request({
+    url: "/api/v1/dept/options",
+    method: "get",
+  });
+}
+
+/**
+ * 获取部门详情
+ *
+ * @param id
+ */
+export function getDeptForm(id: number): AxiosPromise<DeptForm> {
+  return request({
+    url: "/api/v1/dept/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 新增部门
+ *
+ * @param data
+ */
+export function addDept(data: DeptForm) {
+  return request({
+    url: "/api/v1/dept",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ *  修改部门
+ *
+ * @param id
+ * @param data
+ */
+export function updateDept(id: number, data: DeptForm) {
+  return request({
+    url: "/api/v1/dept/" + id,
+    method: "put",
+    data: data,
+  });
+}
+
+/**
+ * 删除部门
+ *
+ * @param ids
+ */
+export function deleteDept(ids: string) {
+  return request({
+    url: "/api/v1/dept/" + ids,
+    method: "delete",
+  });
+}

+ 71 - 0
src/api/dept/types.ts

@@ -0,0 +1,71 @@
+/**
+ * 部门查询参数
+ */
+export interface DeptQuery {
+  keywords?: string;
+  status?: number;
+}
+
+/**
+ * 部门类型
+ */
+export interface DeptVO {
+  /**
+   * 子部门
+   */
+  children?: DeptVO[];
+  /**
+   * 创建时间
+   */
+  createTime?: Date;
+  /**
+   * 部门ID
+   */
+  id?: number;
+  /**
+   * 部门名称
+   */
+  name?: string;
+  /**
+   * 父部门ID
+   */
+  parentId?: number;
+  /**
+   * 排序
+   */
+  sort?: number;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 修改时间
+   */
+  updateTime?: Date;
+}
+
+/**
+ * 部门表单类型
+ */
+export interface DeptForm {
+  /**
+   * 部门ID(新增不填)
+   */
+  id?: number;
+  /**
+   * 部门名称
+   */
+  name?: string;
+  /**
+   * 父部门ID
+   */
+  parentId: number;
+  /**
+   * 排序
+   */
+  sort?: number;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+}

+ 148 - 0
src/api/dict/index.ts

@@ -0,0 +1,148 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import {
+  DictTypeQuery,
+  DictTypePageResult,
+  DictTypeForm,
+  DictQuery,
+  DictForm,
+  DictPageResult,
+} from "./types";
+
+/**
+ * 字典类型分页列表
+ *
+ * @param queryParams
+ */
+export function getDictTypePage(queryParams: object): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/dictType/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 字典类型表单数据
+ *
+ * @param id
+ */
+export function getDictTypeForm(id: number): AxiosPromise<DictTypeForm> {
+  return request({
+    url: "/api/v1/dict/types/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 新增字典类型
+ *
+ * @param data
+ */
+export function addDictType(data: DictTypeForm) {
+  return request({
+    url: "/api/v1/sys/dictType/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改字典类型
+ *
+ * @param id
+ * @param data
+ */
+export function updateDictType(data: DictTypeForm) {
+  return request({
+    url: "/api/v1/sys/dictType/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除字典类型
+ */
+export function deleteDictTypes(id: string) {
+  return request({
+    url: "/api/v1/sys/dictType/del",
+    method: "post",
+    data: { id: id },
+  });
+}
+
+/**
+ * 获取字典类型的数据项
+ *
+ * @param typeCode 字典类型编码
+ */
+export function getDictOptions(typeCode: string): AxiosPromise<OptionType[]> {
+  return request({
+    url: "/api/v1/dict/" + typeCode + "/options",
+    method: "get",
+  });
+}
+
+/**
+ * 字典分页列表
+ */
+export function getDictPage(queryParams: object): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/dictData/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 获取字典表单数据
+ *
+ * @param id
+ */
+export function getDictFormData(id: number): AxiosPromise<DictForm> {
+  return request({
+    url: "/api/v1/dict/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 新增字典
+ *
+ * @param data
+ */
+export function addDict(data: DictForm) {
+  return request({
+    url: "/api/v1/sys/dictData/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改字典项
+ *
+ * @param id
+ * @param data
+ */
+export function updateDict(data: DictForm) {
+  return request({
+    url: "/api/v1/sys/dictData/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除字典
+ *
+ * @param ids 字典项ID,多个以英文逗号(,)分割
+ */
+export function deleteDict(ids: Array<string>) {
+  return request({
+    url: "/api/v1/sys/dictData/batch-del",
+    method: "post",
+    data: { ids: ids },
+  });
+}

+ 144 - 0
src/api/dict/types.ts

@@ -0,0 +1,144 @@
+/**
+ * 字典类型查询参数
+ */
+export interface DictTypeQuery extends PageQuery {
+  /**
+   * 关键字(字典类型名称/编码)
+   */
+  keywords?: string;
+}
+
+/**
+ * 字典类型分页对象
+ */
+export interface DictTypePageVO {
+  /**
+   * 字典类型ID
+   */
+  id: number;
+  /**
+   * 类型编码
+   */
+  code: string;
+  /**
+   * 类型名称
+   */
+  name: string;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+/**
+ * 字典分页项类型声明
+ */
+export type DictTypePageResult = PageResult<DictTypePageVO[]>;
+
+/**
+ * 字典表单类型声明
+ */
+export interface DictTypeForm {
+  /**
+   * 字典类型ID
+   */
+  id?: number;
+  /**
+   * 类型名称
+   */
+  dictName?: string;
+  /**
+   * 类型编码
+   */
+  dictType?: string;
+  /**
+   * 类型状态:0-禁用;1-启用
+   */
+  state: number;
+  /**
+   * 备注
+   */
+  remark?: string;
+  // 字典类别 0 用户字典 1 系统字典
+  type?: string;
+}
+
+/**
+ * 字典查询参数
+ */
+export interface DictQuery extends PageQuery {
+  /**
+   * 字典项名称
+   */
+  name?: string;
+  /**
+   * 字典类型编码
+   */
+  typeCode?: string;
+}
+
+/**
+ * 字典分页对象
+ */
+export interface DictPageVO {
+  /**
+   * 字典ID
+   */
+  id?: number;
+  /**
+   * 字典名称
+   */
+  name?: string;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 字典值
+   */
+  value?: string;
+}
+
+/**
+ * 字典分页
+ */
+export type DictPageResult = PageResult<DictPageVO[]>;
+
+/**
+ * 字典表单
+ */
+export interface DictForm {
+  /**
+   * 字典ID
+   */
+  id?: number;
+  /**
+   * 字典名称
+   */
+  dictLabel?: string;
+  /**
+   * 排序
+   */
+  dictSort?: number;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  state?: number;
+  /**
+   * 类型编码
+   */
+  dictCode?: string;
+  /**
+   * 值
+   */
+  dictValue?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}

+ 34 - 0
src/api/file/index.ts

@@ -0,0 +1,34 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { FileInfo } from "./types";
+
+/**
+ * 上传文件
+ *
+ * @param file
+ */
+export function uploadFileApi(file: File): AxiosPromise<FileInfo> {
+  const formData = new FormData();
+  formData.append("file", file);
+  return request({
+    url: "/api/v1/files",
+    method: "post",
+    data: formData,
+    headers: {
+      "Content-Type": "multipart/form-data",
+    },
+  });
+}
+
+/**
+ * 删除文件
+ *
+ * @param filePath 文件完整路径
+ */
+export function deleteFileApi(filePath?: string) {
+  return request({
+    url: "/api/v1/files",
+    method: "delete",
+    params: { filePath: filePath },
+  });
+}

+ 7 - 0
src/api/file/types.ts

@@ -0,0 +1,7 @@
+/**
+ * 文件API类型声明
+ */
+export interface FileInfo {
+  name: string;
+  url: string;
+}

+ 88 - 0
src/api/menu/index.ts

@@ -0,0 +1,88 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { MenuQuery, MenuVO, MenuForm } from "./types";
+
+/**
+ * 获取路由列表
+ */
+export function listRoutes() {
+  return request({
+    url: "/api/v1/menus/routes",
+    method: "get",
+  });
+}
+
+/**
+ * 获取菜单树形列表
+ *
+ * @param queryParams
+ */
+export function listMenus(): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/menu/tree",
+    method: "POST",
+  });
+}
+
+/**
+ * 获取菜单下拉树形列表
+ */
+export function getMenuOptions(): AxiosPromise {
+  return request({
+    url: "/api/v1/sys/menu/tree",
+    method: "post",
+  });
+}
+
+/**
+ * 获取菜单表单数据
+ *
+ * @param id
+ */
+export function getMenuForm(id: string): AxiosPromise<MenuForm> {
+  return request({
+    url: "/api/v1/sys/menu/get",
+    method: "post",
+    data: { id: id },
+  });
+}
+
+/**
+ * 添加菜单
+ *
+ * @param data
+ */
+export function addMenu(data: any) {
+  return request({
+    url: "/api/v1/sys/menu/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改菜单
+ *
+ * @param id
+ * @param data
+ */
+export function updateMenu(id: string, data: MenuForm) {
+  return request({
+    url: "/api/v1/sys/menu/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除菜单
+ *
+ * @param id 菜单ID
+ */
+export function deleteMenu(id: string) {
+  return request({
+    url: "/api/v1/sys/menu/del",
+    method: "post",
+    data: { id: id },
+  });
+}

+ 134 - 0
src/api/menu/types.ts

@@ -0,0 +1,134 @@
+import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
+
+/**
+ * 菜单查询参数类型
+ */
+export interface MenuQuery {
+  keywords?: string;
+}
+
+/**
+ * 菜单视图对象类型
+ */
+export interface MenuVO {
+  /**
+   * 子菜单
+   */
+  children?: MenuVO[];
+  /**
+   * 组件路径
+   */
+  component?: string;
+  /**
+   * ICON
+   */
+  icon?: string;
+  /**
+   * 菜单ID
+   */
+  id?: number;
+  /**
+   * 菜单名称
+   */
+  name?: string;
+  /**
+   * 父菜单ID
+   */
+  parentId?: number;
+  /**
+   * 按钮权限标识
+   */
+  perm?: string;
+  /**
+   * 跳转路径
+   */
+  redirect?: string;
+  /**
+   * 路由名称
+   */
+  routeName?: string;
+  /**
+   * 路由相对路径
+   */
+  routePath?: string;
+  /**
+   * 菜单排序(数字越小排名越靠前)
+   */
+  sort?: number;
+  /**
+   * 菜单类型
+   */
+  type?: MenuTypeEnum;
+  /**
+   * 菜单是否可见(1:显示;0:隐藏)
+   */
+  visible?: number;
+}
+
+/**
+ * 菜单表单对象类型
+ */
+export interface MenuForm {
+  /**
+   * 菜单ID
+   */
+  id?: string;
+  /**
+   * 父菜单ID
+   */
+  parentId?: string;
+  /**
+   * 菜单名称
+   */
+  menuName?: string;
+  /**
+   * 菜单是否可见(1:是;0:否;)
+   */
+  visible: number;
+  icon?: string;
+  /**
+   * 排序
+   */
+  orderNum: number;
+  /**
+   * 组件路径
+   */
+  component?: string;
+  /**
+   * 路由路径
+   */
+  path?: string;
+  /**
+   * 跳转路由路径
+   */
+  redirect?: string;
+
+  /**
+   * 菜单类型
+   */
+  type: MenuTypeEnum;
+
+  /**
+   * 权限标识
+   */
+  perms?: string;
+  /**
+   * 【菜单】是否开启页面缓存
+   */
+  keepAlive?: number;
+
+  /**
+   * 【目录】只有一个子路由是否始终显示
+   */
+  alwaysShow?: number;
+
+  /**
+   * 【是否为外链
+   */
+  isFrame?: number;
+
+  /**
+   * 账号状态;0-启用;1-禁用;
+   */
+  state?: number;
+}

+ 114 - 0
src/api/order/index.ts

@@ -0,0 +1,114 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { OrderForm, OrderInfo, OrderInfoPageVO, OrderInfoQuery } from "./types";
+
+/**
+ * 获取订单分页列表
+ *
+ * @param queryParams
+ */
+export function getOrderPage(
+  queryParams: object
+): AxiosPromise<PageResult<OrderInfoPageVO[]>> {
+  return request({
+    url: "/api/v1/plan/order/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 获取用户表单详情
+ *
+ * @param userId
+ */
+export function getExpandAlias(tableType: String): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/alias/queryByType/" + tableType,
+    method: "get",
+  });
+}
+
+/**
+ * 添加订单
+ *
+ * @param data
+ */
+export function addOrder(data: any) {
+  return request({
+    url: "/api/v1/plan/order/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改订单
+ *
+ * @param id
+ * @param data
+ */
+export function updateOrder(data: OrderForm) {
+  return request({
+    url: "/api/v1/plan/order/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除订单
+ *
+ * @param ids
+ */
+export function deleteOrders(ids: string[]) {
+  return request({
+    url: "/api/v1/plan/order/batch-del",
+    method: "post",
+    data: { ids: ids },
+  });
+}
+
+/**
+ * 下载导入模板
+ *
+ * @returns
+ */
+export function downloadTemplateApi() {
+  return request({
+    url: "/api/v1/plan/order/template",
+    method: "get",
+    responseType: "arraybuffer",
+  });
+}
+
+/**
+ * 导出
+ *
+ * @param queryParams
+ * @returns
+ */
+export function exportOrder(queryParams: OrderInfoQuery) {
+  return request({
+    url: "/api/v1/plan/order/export",
+    method: "post",
+    data: queryParams,
+    responseType: "arraybuffer",
+  });
+}
+
+/**
+ * 导入
+ *
+ * @param file
+ */
+export function importOrder(importData: any) {
+  return request({
+    url: "/api/v1/plan/order/import",
+    method: "post",
+    data: importData,
+    headers: {
+      "Content-Type": "multipart/form-data",
+    },
+  });
+}

+ 89 - 0
src/api/order/types.ts

@@ -0,0 +1,89 @@
+/**
+ * 订单信息
+ */
+export interface OrderInfo {
+  id?: number;
+  orderCode?: string;
+  orderName?: string;
+  projectCode?: string;
+  erpCode: string[];
+  materialCode: string[];
+  materialName?: string;
+}
+
+/**
+ * 订单信息查询对象类型
+ */
+export interface OrderInfoQuery extends PageQuery {
+  orderCode?: string;
+}
+
+/**
+ * 订单信息分页对象
+ */
+export interface OrderInfoPageVO {
+  /**
+   * id
+   */
+  id?: number;
+  /**
+   * 订单编码
+   */
+  orderCode?: string;
+  /**
+   * 订单名称
+   */
+  orderName?: string;
+  /**
+   * 项目编码
+   */
+  projectCode?: string;
+  /**
+   * erp编码
+   */
+  erpCode: string;
+  /**
+   * 物料编码
+   */
+  materialCode: string;
+  /**
+   * 物料名称
+   */
+  materialName?: string;
+}
+
+/**
+ * 表单类型
+ */
+export interface OrderForm {
+  /**
+   * id
+   */
+  id?: number;
+  /**
+   * 订单编码
+   */
+  orderCode?: string;
+  /**
+   * 订单名称
+   */
+  orderName?: string;
+  /**
+   * 项目编码
+   */
+  projectCode?: string;
+  /**
+   * erp编码
+   */
+  erpCode: string;
+  /**
+   * 物料编码
+   */
+  materialCode: string;
+  /**
+   * 物料名称
+   */
+  materialName?: string;
+
+  orderNum?: number;
+}

+ 112 - 0
src/api/role/index.ts

@@ -0,0 +1,112 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { RoleQuery, RolePageResult, RoleForm } from "./types";
+
+/**
+ * 获取角色分页数据
+ *
+ * @param queryParams
+ */
+export function getRolePage(
+  queryParams?: RoleQuery
+): AxiosPromise<RolePageResult> {
+  return request({
+    url: "/api/v1/roles/page",
+    method: "get",
+    params: queryParams,
+  });
+}
+
+/**
+ * 获取角色下拉数据
+ *
+ * @param queryParams
+ */
+export function getRoleOptions(
+  queryParams?: RoleQuery
+): AxiosPromise<OptionType[]> {
+  return request({
+    url: "/api/v1/roles/options",
+    method: "get",
+    params: queryParams,
+  });
+}
+
+/**
+ * 获取角色的菜单ID集合
+ *
+ * @param queryParams
+ */
+export function getRoleMenuIds(roleId: number): AxiosPromise<number[]> {
+  return request({
+    url: "/api/v1/roles/" + roleId + "/menuIds",
+    method: "get",
+  });
+}
+
+/**
+ * 分配菜单权限给角色
+ *
+ * @param queryParams
+ */
+export function updateRoleMenus(
+  roleId: number,
+  data: number[]
+): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/roles/" + roleId + "/menus",
+    method: "put",
+    data: data,
+  });
+}
+
+/**
+ * 获取角色详情
+ *
+ * @param id
+ */
+export function getRoleForm(id: number): AxiosPromise<RoleForm> {
+  return request({
+    url: "/api/v1/roles/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 添加角色
+ *
+ * @param data
+ */
+export function addRole(data: RoleForm) {
+  return request({
+    url: "/api/v1/roles",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 更新角色
+ *
+ * @param id
+ * @param data
+ */
+export function updateRole(id: number, data: RoleForm) {
+  return request({
+    url: "/api/v1/roles/" + id,
+    method: "put",
+    data: data,
+  });
+}
+
+/**
+ * 批量删除角色,多个以英文逗号(,)分割
+ *
+ * @param ids
+ */
+export function deleteRoles(ids: string) {
+  return request({
+    url: "/api/v1/roles/" + ids,
+    method: "delete",
+  });
+}

+ 78 - 0
src/api/role/types.ts

@@ -0,0 +1,78 @@
+/**
+ * 角色查询参数
+ */
+export interface RoleQuery extends PageQuery {
+  keywords?: string;
+}
+
+/**
+ * 角色分页对象
+ */
+export interface RolePageVO {
+  /**
+   * 角色编码
+   */
+  code?: string;
+
+  /**
+   * 角色ID
+   */
+  id?: number;
+  /**
+   * 角色名称
+   */
+  name?: string;
+  /**
+   * 排序
+   */
+  sort?: number;
+  /**
+   * 角色状态
+   */
+  status?: number;
+  /**
+   * 创建时间
+   */
+  createTime?: Date;
+  /**
+   * 修改时间
+   */
+  updateTime?: Date;
+}
+
+/**
+ * 角色分页
+ */
+export type RolePageResult = PageResult<RolePageVO[]>;
+
+/**
+ * 角色表单对象
+ */
+export interface RoleForm {
+  /**
+   * 角色ID
+   */
+  id?: number;
+
+  /**
+   * 角色编码
+   */
+  code: string;
+  /**
+   * 数据权限
+   */
+  dataScope?: number;
+
+  /**
+   * 角色名称
+   */
+  name: string;
+  /**
+   * 排序
+   */
+  sort?: number;
+  /**
+   * 角色状态(1-正常;0-停用)
+   */
+  status?: number;
+}

+ 78 - 0
src/api/system/log/index.ts

@@ -0,0 +1,78 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+
+/**
+ * 获取登录日志分页
+ * @param queryParams
+ */
+export function getLoginLogPage(
+  queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+  return request({
+    url: "/api/v1/log/loginLog/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 获取操作日志分页
+ * @param queryParams
+ */
+export function getOperaLogPage(
+  queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+  return request({
+    url: "/api/v1/log/operLog/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 清空操作日志
+ *
+ * @param userId
+ */
+export function clearOperaLog(): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/log/operLog/clear",
+    method: "get",
+  });
+}
+/**
+ * 清空登录日志
+ *
+ * @param userId
+ */
+export function clearLoginLog(): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/log/loginLog/clear",
+    method: "get",
+  });
+}
+
+/**
+ * 删除登录日志
+ *
+ * @param ids
+ */
+export function deleteLoginLogs(ids: string[]) {
+  return request({
+    url: "/api/v1/log/loginLog/batch-del",
+    method: "post",
+    data: { ids: ids },
+  });
+}
+/**
+ * 删除操作日志
+ *
+ * @param ids
+ */
+export function deleteOperaLogs(ids: string[]) {
+  return request({
+    url: "/api/v1/log/operLog/batch-del",
+    method: "post",
+    data: { ids: ids },
+  });
+}

+ 140 - 0
src/api/user/index.ts

@@ -0,0 +1,140 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
+
+/**
+ * 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
+ */
+export function getUserInfoApi(): AxiosPromise {
+  return request({
+    url: "/api/auth",
+    method: "get",
+  });
+}
+
+/**
+ * 获取用户分页列表
+ *
+ * @param queryParams
+ */
+export function getUserPage(
+  queryParams: UserQuery
+): AxiosPromise<PageResult<UserPageVO[]>> {
+  return request({
+    url: "/api/v1/users/page",
+    method: "get",
+    params: queryParams,
+  });
+}
+
+/**
+ * 获取用户表单详情
+ *
+ * @param userId
+ */
+export function getUserForm(userId: number): AxiosPromise<UserForm> {
+  return request({
+    url: "/api/v1/users/" + userId + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 添加用户
+ *
+ * @param data
+ */
+export function addUser(data: any) {
+  return request({
+    url: "/api/v1/users",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改用户
+ *
+ * @param id
+ * @param data
+ */
+export function updateUser(id: number, data: UserForm) {
+  return request({
+    url: "/api/v1/users/" + id,
+    method: "put",
+    data: data,
+  });
+}
+
+/**
+ * 修改用户密码
+ *
+ * @param id
+ * @param password
+ */
+export function updateUserPassword(id: number, password: string) {
+  return request({
+    url: "/api/v1/users/" + id + "/password",
+    method: "patch",
+    params: { password: password },
+  });
+}
+
+/**
+ * 删除用户
+ *
+ * @param ids
+ */
+export function deleteUsers(ids: string) {
+  return request({
+    url: "/api/v1/users/" + ids,
+    method: "delete",
+  });
+}
+
+/**
+ * 下载用户导入模板
+ *
+ * @returns
+ */
+export function downloadTemplateApi() {
+  return request({
+    url: "/api/v1/users/template",
+    method: "get",
+    responseType: "arraybuffer",
+  });
+}
+
+/**
+ * 导出用户
+ *
+ * @param queryParams
+ * @returns
+ */
+export function exportUser(queryParams: UserQuery) {
+  return request({
+    url: "/api/v1/users/_export",
+    method: "get",
+    params: queryParams,
+    responseType: "arraybuffer",
+  });
+}
+
+/**
+ * 导入用户
+ *
+ * @param file
+ */
+export function importUser(deptId: number, file: File) {
+  const formData = new FormData();
+  formData.append("file", file);
+  return request({
+    url: "/api/v1/users/_import",
+    method: "post",
+    params: { deptId: deptId },
+    data: formData,
+    headers: {
+      "Content-Type": "multipart/form-data",
+    },
+  });
+}

+ 116 - 0
src/api/user/types.ts

@@ -0,0 +1,116 @@
+/**
+ * 登录用户信息
+ */
+export interface UserInfo {
+  userId?: number;
+  username?: string;
+  nickname?: string;
+  avatar?: string;
+  roles: string[];
+  perms: string[];
+  deptId?: string;
+}
+
+/**
+ * 用户查询对象类型
+ */
+export interface UserQuery extends PageQuery {
+  keywords?: string;
+  status?: number;
+  deptId?: number;
+  startTime?: string;
+  endTime?: string;
+}
+
+/**
+ * 用户分页对象
+ */
+export interface UserPageVO {
+  /**
+   * 用户头像地址
+   */
+  avatar?: string;
+  /**
+   * 创建时间
+   */
+  createTime?: Date;
+  /**
+   * 部门名称
+   */
+  deptName?: string;
+  /**
+   * 用户邮箱
+   */
+  email?: string;
+  /**
+   * 性别
+   */
+  genderLabel?: string;
+  /**
+   * 用户ID
+   */
+  id?: number;
+  /**
+   * 手机号
+   */
+  mobile?: string;
+  /**
+   * 用户昵称
+   */
+  nickname?: string;
+  /**
+   * 角色名称,多个使用英文逗号(,)分割
+   */
+  roleNames?: string;
+  /**
+   * 用户状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 用户名
+   */
+  username?: string;
+}
+
+/**
+ * 用户表单类型
+ */
+export interface UserForm {
+  /**
+   * 用户头像
+   */
+  avatar?: string;
+  /**
+   * 部门ID
+   */
+  deptId?: number;
+  /**
+   * 邮箱
+   */
+  email?: string;
+  /**
+   * 性别
+   */
+  gender?: number;
+  /**
+   * 用户ID
+   */
+  id?: number;
+  mobile?: string;
+  /**
+   * 昵称
+   */
+  nickname?: string;
+  /**
+   * 角色ID集合
+   */
+  roleIds?: number[];
+  /**
+   * 用户状态(1:正常;0:禁用)
+   */
+  status?: number;
+  /**
+   * 用户名
+   */
+  username?: string;
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/api.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/captcha.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/cascader.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/client.svg


+ 1 - 0
src/assets/icons/close.svg

@@ -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>

+ 1 - 0
src/assets/icons/close_all.svg

@@ -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>

+ 1 - 0
src/assets/icons/close_left.svg

@@ -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>

+ 1 - 0
src/assets/icons/close_other.svg

@@ -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>

+ 1 - 0
src/assets/icons/close_right.svg

@@ -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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/dict.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/document.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/download.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/edit.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/eye-open.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/eye.svg


+ 1 - 0
src/assets/icons/fullscreen-exit.svg

@@ -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>

+ 1 - 0
src/assets/icons/fullscreen.svg

@@ -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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/github.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/homepage.svg


+ 1 - 0
src/assets/icons/indent-decrease.svg

@@ -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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/ip.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/language.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/link.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/lock.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/menu.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/message.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/money.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/monitor.svg


+ 1 - 0
src/assets/icons/moon.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></svg>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/order.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/peoples.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/project.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/publish.svg


+ 1 - 0
src/assets/icons/refresh.svg

@@ -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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/role.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/security.svg


+ 1 - 0
src/assets/icons/setting.svg

@@ -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>

+ 1 - 0
src/assets/icons/size.svg

@@ -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>

+ 1 - 0
src/assets/icons/sunny.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85 1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></svg>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/system.svg


+ 1 - 0
src/assets/icons/table.svg

@@ -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>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/todolist.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/tree.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/user.svg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
src/assets/icons/visit.svg


BIN
src/assets/images/401.gif


BIN
src/assets/images/404.png


BIN
src/assets/images/404_cloud.png


BIN
src/assets/images/login-bg-dark.jpg


BIN
src/assets/images/login-bg.jpg


BIN
src/assets/logo.png


+ 0 - 0
src/common/configs/buttonPermission.ts


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác