Browse Source

!64 版本升级
* Merge branch 'dev' of gitee.com:JavaLionLi/plus-ui into ts
* 升级依赖
* !61 fix: 删除重复环境变量ElUploadInstance
* fix: 删除重复环境变量ElUploadInstance

ahaos 1 year ago
parent
commit
b06f6a316b
98 changed files with 3183 additions and 3143 deletions
  1. 1 1
      .eslintignore
  2. 15 8
      .eslintrc.js
  3. 20 0
      .prettierrc
  4. 34 29
      package.json
  5. 5 5
      src/App.vue
  6. 2 2
      src/api/tool/gen/index.ts
  7. 19 20
      src/components/Breadcrumb/index.vue
  8. 33 36
      src/components/BuildCode/index.vue
  9. 31 36
      src/components/BuildCode/render.vue
  10. 28 32
      src/components/DictTag/index.vue
  11. 81 77
      src/components/Editor/index.vue
  12. 125 115
      src/components/FileUpload/index.vue
  13. 4 4
      src/components/Hamburger/index.vue
  14. 49 47
      src/components/HeaderSearch/index.vue
  15. 11 13
      src/components/IconSelect/index.vue
  16. 7 11
      src/components/ImagePreview/index.vue
  17. 119 120
      src/components/ImageUpload/index.vue
  18. 3 4
      src/components/LangSelect/index.vue
  19. 47 47
      src/components/Pagination/index.vue
  20. 24 26
      src/components/RightToolbar/index.vue
  21. 1 1
      src/components/RuoYiDoc/index.vue
  22. 1 1
      src/components/RuoYiGit/index.vue
  23. 6 6
      src/components/SizeSelect/index.vue
  24. 10 10
      src/components/SvgIcon/index.vue
  25. 50 48
      src/components/TopNav/index.vue
  26. 56 67
      src/components/TreeSelect/index.vue
  27. 6 6
      src/components/iFrame/index.vue
  28. 2 2
      src/directive/permission/index.ts
  29. 12 9
      src/layout/components/AppMain.vue
  30. 7 5
      src/layout/components/IframeToggle/index.vue
  31. 5 8
      src/layout/components/InnerLink/index.vue
  32. 46 45
      src/layout/components/Navbar.vue
  33. 88 88
      src/layout/components/Settings/index.vue
  34. 22 22
      src/layout/components/Sidebar/Link.vue
  35. 15 11
      src/layout/components/Sidebar/Logo.vue
  36. 59 63
      src/layout/components/Sidebar/SidebarItem.vue
  37. 20 21
      src/layout/components/Sidebar/index.vue
  38. 1 4
      src/layout/components/SocialCallback/index.vue
  39. 55 55
      src/layout/components/TagsView/ScrollPane.vue
  40. 169 168
      src/layout/components/TagsView/index.vue
  41. 93 94
      src/layout/components/TopBar/search.vue
  42. 10 13
      src/layout/components/notice/index.vue
  43. 33 33
      src/layout/index.vue
  44. 3 2
      src/permission.ts
  45. 9 9
      src/plugins/tab.ts
  46. 3 3
      src/router/index.ts
  47. 1 1
      src/store/modules/notice.ts
  48. 32 33
      src/store/modules/permission.ts
  49. 23 15
      src/store/modules/settings.ts
  50. 11 11
      src/store/modules/tagsView.ts
  51. 3 3
      src/types/element.d.ts
  52. 3 2
      src/types/env.d.ts
  53. 72 1
      src/types/global.d.ts
  54. 22 24
      src/types/router.d.ts
  55. 0 70
      src/types/setting.d.ts
  56. 1 0
      src/utils/propTypes.ts
  57. 0 2
      src/utils/request.ts
  58. 2 2
      src/utils/websocket.ts
  59. 48 56
      src/views/demo/demo/index.vue
  60. 55 68
      src/views/demo/tree/index.vue
  61. 2 2
      src/views/error/401.vue
  62. 4 4
      src/views/error/404.vue
  63. 6 6
      src/views/index.vue
  64. 29 26
      src/views/login.vue
  65. 37 37
      src/views/monitor/cache/index.vue
  66. 73 69
      src/views/monitor/logininfor/index.vue
  67. 9 9
      src/views/monitor/online/index.vue
  68. 38 35
      src/views/monitor/operlog/index.vue
  69. 4 4
      src/views/redirect/index.vue
  70. 31 34
      src/views/register.vue
  71. 58 66
      src/views/system/client/index.vue
  72. 49 45
      src/views/system/config/index.vue
  73. 62 64
      src/views/system/dept/index.vue
  74. 60 59
      src/views/system/dict/data.vue
  75. 47 44
      src/views/system/dict/index.vue
  76. 66 66
      src/views/system/menu/index.vue
  77. 37 39
      src/views/system/notice/index.vue
  78. 72 81
      src/views/system/oss/config.vue
  79. 65 67
      src/views/system/oss/index.vue
  80. 43 39
      src/views/system/post/index.vue
  81. 28 29
      src/views/system/role/authUser.vue
  82. 126 126
      src/views/system/role/index.vue
  83. 17 18
      src/views/system/role/selectUser.vue
  84. 65 63
      src/views/system/tenant/index.vue
  85. 48 45
      src/views/system/tenantPackage/index.vue
  86. 13 13
      src/views/system/user/authRole.vue
  87. 160 128
      src/views/system/user/index.vue
  88. 25 25
      src/views/system/user/profile/index.vue
  89. 25 19
      src/views/system/user/profile/resetPwd.vue
  90. 19 20
      src/views/system/user/profile/thirdParty.vue
  91. 19 21
      src/views/system/user/profile/userAvatar.vue
  92. 19 14
      src/views/system/user/profile/userInfo.vue
  93. 11 11
      src/views/tool/gen/basicInfoForm.vue
  94. 16 16
      src/views/tool/gen/editTable.vue
  95. 26 23
      src/views/tool/gen/genInfoForm.vue
  96. 20 20
      src/views/tool/gen/importTable.vue
  97. 37 37
      src/views/tool/gen/index.vue
  98. 4 4
      tsconfig.json

+ 1 - 1
.eslintignore

@@ -14,4 +14,4 @@ dist
 .eslintrc.js
 prettier.config.js
 src/assets
-tailwind.config.js
+tailwind.config.js

+ 15 - 8
.eslintrc.js

@@ -1,28 +1,35 @@
 module.exports = {
   env: {
     browser: true,
-    es2021: true,
-    node: true
+    node: true,
+    es6: true
   },
   parser: 'vue-eslint-parser',
   extends: [
-    'eslint:recommended',
-    'plugin:vue/vue3-essential',
-    'plugin:@typescript-eslint/recommended',
+    'plugin:vue/vue3-recommended',
     './.eslintrc-auto-import.json',
-    'plugin:prettier/recommended'
+    'plugin:@typescript-eslint/recommended',
+    "prettier",
+    'plugin:prettier/recommended',
   ],
   parserOptions: {
     ecmaVersion: '2020',
     sourceType: 'module',
+    project: "./tsconfig.*?.json",
     parser: '@typescript-eslint/parser'
   },
-  plugins: ['vue', '@typescript-eslint'],
+  plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'],
   rules: {
-    'vue/multi-word-component-names': 'off',
     '@typescript-eslint/no-empty-function': 'off',
     '@typescript-eslint/no-explicit-any': 'off',
+
+    // vue
+    'vue/multi-word-component-names': 'off',
+    'vue/valid-define-props': 'off',
     'vue/no-v-model-argument': 'off',
+    'prefer-rest-params': 'off',
+    // prettier
+    'prettier/prettier': 'error',
     '@typescript-eslint/ban-types': [
       'error',
       {

+ 20 - 0
.prettierrc

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

+ 34 - 29
package.json

@@ -6,9 +6,10 @@
   "license": "MIT",
   "scripts": {
     "dev": "vite serve --mode development",
-    "build:prod": "vite build --mode production &&vue-tsc --noEmit",
+    "build:prod": "vite build --mode production",
+    "build:dev": "vite build --mode development",
     "preview": "vite preview",
-    "lint": "eslint src/**/*.{ts,js,vue} --fix",
+    "lint:eslint": "eslint  --fix --ext .ts,.js,.vue ./src ",
     "prepare": "husky install",
     "prettier": "prettier --write ."
   },
@@ -19,28 +20,28 @@
   "dependencies": {
     "@element-plus/icons-vue": "2.1.0",
     "@vueup/vue-quill": "1.2.0",
-    "@vueuse/core": "9.5.0",
+    "@vueuse/core": "10.7.0",
     "animate.css": "4.1.1",
     "await-to-js": "^3.0.0",
     "axios": "^1.3.4",
+    "crypto-js": "^4.1.1",
     "echarts": "5.4.0",
-    "element-plus": "2.2.27",
+    "element-plus": "2.4.3",
     "file-saver": "2.0.5",
     "fuse.js": "6.6.2",
     "js-cookie": "3.0.1",
     "jsencrypt": "3.3.1",
-    "crypto-js": "^4.1.1",
     "nprogress": "0.2.0",
     "path-browserify": "1.0.1",
     "path-to-regexp": "6.2.0",
-    "pinia": "2.0.22",
+    "pinia": "2.1.7",
     "screenfull": "6.0.0",
     "vform3-builds": "3.0.8",
-    "vue": "3.2.45",
+    "vue": "3.3.11",
     "vue-cropper": "1.0.3",
     "vue-i18n": "9.2.2",
-    "vue-router": "4.1.4",
-    "vue-types": "^5.0.3"
+    "vue-router": "4.2.5",
+    "vue-types": "5.1.1"
   },
   "devDependencies": {
     "@iconify/json": "^2.2.40",
@@ -51,34 +52,38 @@
     "@types/node": "18.14.2",
     "@types/nprogress": "0.2.0",
     "@types/path-browserify": "^1.0.0",
-    "@typescript-eslint/eslint-plugin": "5.56.0",
-    "@typescript-eslint/parser": "5.56.0",
-    "@unocss/preset-attributify": "^0.50.6",
-    "@unocss/preset-icons": "^0.50.6",
-    "@unocss/preset-uno": "^0.50.6",
-    "@vitejs/plugin-vue": "4.0.0",
+    "@typescript-eslint/eslint-plugin": "6.14.0",
+    "@typescript-eslint/parser": "6.14.0",
+    "@unocss/preset-attributify": "^0.58.0",
+    "@unocss/preset-icons": "^0.58.0",
+    "@unocss/preset-uno": "^0.58.0",
     "@vue/compiler-sfc": "3.2.45",
+    "@vitejs/plugin-vue": "4.5.2",
     "autoprefixer": "10.4.14",
-    "eslint": "8.36.0",
-    "eslint-config-prettier": "8.8.0",
-    "eslint-plugin-prettier": "4.2.1",
-    "eslint-plugin-vue": "9.9.0",
+    "eslint": "8.55.0",
+    "eslint-config-prettier": "9.1.0",
+    "eslint-define-config": "2.0.0",
+    "eslint-plugin-prettier": "5.0.1",
+    "eslint-plugin-promise": "6.1.1",
+    "eslint-plugin-node": "11.1.0",
+    "eslint-plugin-import": "2.29.0",
+    "eslint-plugin-vue": "9.19.2",
     "fast-glob": "^3.2.11",
     "husky": "7.0.4",
     "postcss": "^8.4.21",
-    "prettier": "2.8.6",
+    "prettier": "3.1.1",
     "sass": "1.56.1",
-    "typescript": "4.9.5",
-    "unocss": "^0.50.6",
-    "unplugin-auto-import": "0.13.0",
-    "unplugin-icons": "0.15.1",
-    "unplugin-vue-components": "0.23.0",
-    "vite": "4.3.1",
+    "typescript": "5.2.2",
+    "unocss": "^0.58.0",
+    "unplugin-auto-import": "0.17.2",
+    "unplugin-icons": "0.18.1",
+    "unplugin-vue-components": "0.26.0",
+    "unplugin-vue-setup-extend-plus": "0.4.9",
     "vite-plugin-compression": "0.5.1",
     "vite-plugin-svg-icons": "2.0.1",
-    "unplugin-vue-setup-extend-plus": "0.4.9",
     "vitest": "^0.29.7",
-    "vue-eslint-parser": "9.1.0",
-    "vue-tsc": "0.35.0"
+    "vue-eslint-parser": "9.3.2",
+    "vue-tsc": "0.35.0",
+    "vite": "5.0.4"
   }
 }

+ 5 - 5
src/App.vue

@@ -5,8 +5,8 @@
 </template>
 
 <script setup lang="ts">
-import useSettingsStore from '@/store/modules/settings'
-import { handleThemeStyle } from '@/utils/theme'
+import useSettingsStore from '@/store/modules/settings';
+import { handleThemeStyle } from '@/utils/theme';
 import useAppStore from '@/store/modules/app';
 
 const appStore = useAppStore();
@@ -15,7 +15,7 @@ const size = computed(() => appStore.size as any);
 onMounted(() => {
   nextTick(() => {
     // 初始化主题样式
-    handleThemeStyle(useSettingsStore().theme)
-  })
-})
+    handleThemeStyle(useSettingsStore().theme);
+  });
+});
 </script>

+ 2 - 2
src/api/tool/gen/index.ts

@@ -28,7 +28,7 @@ export const getGenTable = (tableId: string | number): AxiosPromise<GenTableVO>
 };
 
 // 修改代码生成信息
-export const updateGenTable = (data: DbTableForm) => {
+export const updateGenTable = (data: DbTableForm): AxiosPromise<GenTableVO> => {
   return request({
     url: '/tool/gen',
     method: 'put',
@@ -37,7 +37,7 @@ export const updateGenTable = (data: DbTableForm) => {
 };
 
 // 导入表
-export const importTable = (data: { tables: string; dataName: string }) => {
+export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<GenTableVO> => {
   return request({
     url: '/tool/gen/importTable',
     method: 'post',

+ 19 - 20
src/components/Breadcrumb/index.vue

@@ -2,8 +2,7 @@
   <el-breadcrumb class="app-breadcrumb" separator="/">
     <transition-group name="breadcrumb">
       <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
-        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{
-          item.meta?.title }}</span>
+        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta?.title }}</span>
         <a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a>
       </el-breadcrumb-item>
     </transition-group>
@@ -11,42 +10,42 @@
 </template>
 
 <script setup lang="ts">
-import { RouteLocationMatched } from 'vue-router'
+import { RouteLocationMatched } from 'vue-router';
 
 const route = useRoute();
 const router = useRouter();
-const levelList = ref<RouteLocationMatched[]>([])
+const levelList = ref<RouteLocationMatched[]>([]);
 
 const getBreadcrumb = () => {
   // only show routes with meta.title
-  let matched = route.matched.filter(item => item.meta && item.meta.title);
-  const first = matched[0]
+  let matched = route.matched.filter((item) => item.meta && item.meta.title);
+  const first = matched[0];
   // 判断是否为首页
   if (!isDashboard(first)) {
-    matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
+    matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched);
   }
-  levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
-}
+  levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false);
+};
 const isDashboard = (route: RouteLocationMatched) => {
-  const name = route && route.name as string
+  const name = route && (route.name as string);
   if (!name) {
-    return false
+    return false;
   }
-  return name.trim() === 'Index'
-}
+  return name.trim() === 'Index';
+};
 const handleLink = (item: RouteLocationMatched) => {
-  const { redirect, path } = item
-  redirect ? router.push(redirect as string) : router.push(path)
-}
+  const { redirect, path } = item;
+  redirect ? router.push(redirect as string) : router.push(path);
+};
 
 watchEffect(() => {
   // if you go to the redirect page, do not update the breadcrumbs
-  if (route.path.startsWith('/redirect/')) return
-  getBreadcrumb()
-})
+  if (route.path.startsWith('/redirect/')) return;
+  getBreadcrumb();
+});
 onMounted(() => {
   getBreadcrumb();
-})
+});
 </script>
 
 <style lang="scss" scoped>

+ 33 - 36
src/components/BuildCode/index.vue

@@ -1,53 +1,50 @@
-<!-- 代码构建 -->
+<template>
+  <!-- 代码构建 -->
+  <div>
+    <v-form-designer
+      ref="buildRef"
+      class="build"
+      :designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
+    >
+      <template v-if="showBtn" #customToolButtons>
+        <el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
+      </template>
+    </v-form-designer>
+  </div>
+</template>
+
 <script setup lang="ts">
+interface Props {
+  showBtn: boolean;
+  formJson: any;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  showBtn: true,
+  formJson: ''
+});
 
-const props = defineProps({
-  showBtn: {
-    type: Boolean,
-    default: false
-  },
-  formJson: {
-    type: Object,
-    default: undefined
-  }
-})
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const buildRef = ref();
 const emits = defineEmits(['reJson', 'saveDesign']);
 
-
-
 //获取表单json
 const getJson = () => {
-  const formJson = JSON.stringify(buildRef.value.getFormJson())
-  const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets())
+  const formJson = JSON.stringify(buildRef.value.getFormJson());
+  const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets());
   let data = {
-    formJson, fieldJson
-  }
-  emits("saveDesign", data)
-}
+    formJson,
+    fieldJson
+  };
+  emits('saveDesign', data);
+};
 
 onMounted(() => {
   if (props.formJson) {
-    buildRef.value.setFormJson(props.formJson)
+    buildRef.value.setFormJson(props.formJson);
   }
-})
+});
 </script>
 
-<template>
-  <div>
-    <v-form-designer
-      class="build"
-      ref="buildRef"
-      :designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
-    >
-      <template #customToolButtons v-if="showBtn">
-        <el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
-      </template>
-    </v-form-designer>
-  </div>
-</template>
-
 <style lang="scss">
 .build {
   margin: 0 !important;

+ 31 - 36
src/components/BuildCode/render.vue

@@ -1,26 +1,28 @@
+<template>
+  <div class="">
+    <v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
+  </div>
+</template>
+
 <!-- 动态表单渲染 -->
-<script setup name="Render">
+<script setup name="Render" lang="ts">
+interface Props {
+  formJson: string | object;
+  formData: string | object;
+  isView: boolean;
+}
 
-const props = defineProps({
-  formJson: {
-    type: [String, Object],
-    default: ""
-  },
-  formData: {
-    type: [String, Object],
-    default: ""
-  },
-  isView: {
-    type: Boolean,
-    default: false
-  }
-})
+const props = withDefaults(defineProps<Props>(), {
+  formJson: '',
+  formData: '',
+  isView: false
+});
 
-const vFormRef = ref(null)
+const vFormRef = ref(null);
 // 获取表单数据-异步
 const getFormData = () => {
-  return vFormRef.value.getFormData()
-}
+  return vFormRef.value.getFormData();
+};
 
 /**
  * 设置表单内容
@@ -28,35 +30,28 @@ const getFormData = () => {
  * formConfig:{ formTemplate:表单模板,formData:表单数据,hiddenField:需要隐藏的字段字符串集合,disabledField:需要禁用的自读字符串集合}
  */
 const initForm = (formConf) => {
-  const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf)
+  const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf);
   if (formTemplate) {
-    vFormRef.value.setFormJson(formTemplate)
+    vFormRef.value.setFormJson(formTemplate);
     if (formData) {
-      vFormRef.value.setFormData(formData)
+      vFormRef.value.setFormData(formData);
     }
     if (disabledField && disabledField.length > 0) {
       setTimeout(() => {
-        vFormRef.value.disableWidgets(disabledField)
-      }, 200)
+        vFormRef.value.disableWidgets(disabledField);
+      }, 200);
     }
     if (hiddenField && hiddenField.length > 0) {
       setTimeout(() => {
-        vFormRef.value.hideWidgets(hiddenField)
-      }, 200)
+        vFormRef.value.hideWidgets(hiddenField);
+      }, 200);
     }
     if (props.isView) {
-      console.log(props.isView)
       setTimeout(() => {
-        vFormRef.value.disableForm()
-      }, 100)
+        vFormRef.value.disableForm();
+      }, 100);
     }
   }
-}
-defineExpose({ getFormData, initForm })
+};
+defineExpose({ getFormData, initForm });
 </script>
-
-<template>
-  <div class="">
-    <v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
-  </div>
-</template>

+ 28 - 32
src/components/DictTag/index.vue

@@ -8,13 +8,13 @@
         </span>
         <el-tag
           v-else
-          :disable-transitions="true"
           :key="item.value + ''"
+          :disable-transitions="true"
           :index="index"
           :type="(item.elTagType === 'primary' || item.elTagType === 'default')? '' : item.elTagType"
           :class="item.elTagClass"
         >
-          {{ item.label + " " }}
+          {{ item.label + ' ' }}
         </el-tag>
       </template>
     </template>
@@ -25,57 +25,53 @@
 </template>
 
 <script setup lang="ts">
-import { propTypes } from '@/utils/propTypes';
-
-
-const props = defineProps({
-  // 数据
-  options: {
-    type: Array as PropType<DictDataOption[]>,
-    default: null,
-  },
-  // 当前的值
-  value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
-  // 当未找到匹配的数据时,显示value
-  showValue: propTypes.bool.def(true),
-  separator: propTypes.string.def(","),
+interface Props {
+  options: Array<DictDataOption>;
+  value: number | string | Array<number | string>;
+  showValue: boolean;
+  separator: string;
+}
+const props = withDefaults(defineProps<Props>(), {
+  showValue: true,
+  separator: ','
 });
+
 const values = computed(() => {
-  if (props.value === '' || props.value === null || typeof props.value === "undefined") return []
-  return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator);
+  if (props.value === '' || props.value === null || typeof props.value === 'undefined') return [];
+  return Array.isArray(props.value) ? props.value.map((item) => '' + item) : String(props.value).split(props.separator);
 });
 
 const unmatch = computed(() => {
-  if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === "undefined") return false
+  if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === 'undefined') return false;
   // 传入值为非数组
-  values.value.forEach(item => {
-    if (!props.options.some(v => v.value === item)) {
-      return true // 如果有未匹配项,将标志设置为true
+  values.value.forEach((item) => {
+    if (!props.options.some((v) => v.value === item)) {
+      return true; // 如果有未匹配项,将标志设置为true
     }
-  })
-  return false // 返回标志的值
+  });
+  return false; // 返回标志的值
 });
 
 const unmatchArray = computed(() => {
-// 记录未匹配的项
+  // 记录未匹配的项
   const itemUnmatchArray: Array<string | number> = [];
-  if (props.value !== '' && props.value !== null && typeof props.value !== "undefined") {
-    values.value.forEach(item => {
-      if (!props.options.some(v => v.value === item)) {
+  if (props.value !== '' && props.value !== null && typeof props.value !== 'undefined') {
+    values.value.forEach((item) => {
+      if (!props.options.some((v) => v.value === item)) {
         itemUnmatchArray.push(item);
       }
-    })
+    });
   }
   // 没有value不显示
   return handleArray(itemUnmatchArray);
 });
 
 const handleArray = (array: Array<string | number>) => {
-  if (array.length === 0) return "";
+  if (array.length === 0) return '';
   return array.reduce((pre, cur) => {
-    return pre + " " + cur;
+    return pre + ' ' + cur;
   });
-}
+};
 </script>
 
 <style scoped>

+ 81 - 77
src/components/Editor/index.vue

@@ -1,6 +1,8 @@
 <template>
   <div>
     <el-upload
+      v-if="type === 'url'"
+      ref="uploadRef"
       :action="upload.url"
       :before-upload="handleBeforeUpload"
       :on-success="handleUploadSuccess"
@@ -9,18 +11,16 @@
       name="file"
       :show-file-list="false"
       :headers="upload.headers"
-      ref="uploadRef"
-      v-if="type === 'url'"
     >
     </el-upload>
     <div class="editor">
       <quill-editor
         ref="quillEditorRef"
         v-model:content="content"
-        contentType="html"
-        @textChange="(e: any) => $emit('update:modelValue', content)"
+        content-type="html"
         :options="options"
         :style="styles"
+        @text-change="(e: any) => $emit('update:modelValue', content)"
       />
     </div>
   </div>
@@ -30,7 +30,7 @@
 import { QuillEditor, Quill } from '@vueup/vue-quill';
 import '@vueup/vue-quill/dist/vue-quill.snow.css';
 import { propTypes } from '@/utils/propTypes';
-import { globalHeaders } from "@/utils/request";
+import { globalHeaders } from '@/utils/request';
 
 const props = defineProps({
   /* 编辑器的内容 */
@@ -52,42 +52,42 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const upload = reactive<UploadOption>({
   headers: globalHeaders(),
   url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
-})
+});
 const quillEditorRef = ref();
 
 const options = ref({
-  theme: "snow",
+  theme: 'snow',
   bounds: document.body,
-  debug: "warn",
+  debug: 'warn',
   modules: {
     // 工具栏配置
     toolbar: {
       container: [
-        ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
-        ["blockquote", "code-block"],                    // 引用  代码块
-        [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
-        [{ indent: "-1" }, { indent: "+1" }],            // 缩进
-        [{ size: ["small", false, "large", "huge"] }],   // 字体大小
-        [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
-        [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
-        [{ align: [] }],                                 // 对齐方式
-        ["clean"],                                       // 清除文本格式
-        ["link", "image", "video"]                       // 链接、图片、视频
+        ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
+        ['blockquote', 'code-block'], // 引用  代码块
+        [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
+        [{ indent: '-1' }, { indent: '+1' }], // 缩进
+        [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
+        [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
+        [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
+        [{ align: [] }], // 对齐方式
+        ['clean'], // 清除文本格式
+        ['link', 'image', 'video'] // 链接、图片、视频
       ],
       handlers: {
         image: function (value: any) {
           if (value) {
             // 调用element图片上传
-            (document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
+            (document.querySelector('.editor-img-uploader>.el-upload') as HTMLDivElement)?.click();
           } else {
-            Quill.format("image", true);
+            Quill.format('image', true);
           }
-        },
-      },
+        }
+      }
     }
   },
-  placeholder: "请输入内容",
-  readOnly: props.readOnly,
+  placeholder: '请输入内容',
+  readOnly: props.readOnly
 });
 
 const styles = computed(() => {
@@ -99,14 +99,18 @@ const styles = computed(() => {
     style.height = `${props.height}px`;
   }
   return style;
-})
+});
 
-const content = ref("");
-watch(() => props.modelValue, (v) => {
-  if (v !== content.value) {
-    content.value = v === undefined ? "<p></p>" : v;
-  }
-}, { immediate: true });
+const content = ref('');
+watch(
+  () => props.modelValue,
+  (v) => {
+    if (v !== content.value) {
+      content.value = v === undefined ? '<p></p>' : v;
+    }
+  },
+  { immediate: true }
+);
 
 // 图片上传成功返回图片地址
 const handleUploadSuccess = (res: any) => {
@@ -117,7 +121,7 @@ const handleUploadSuccess = (res: any) => {
     // 获取光标位置
     let length = quill.selection.savedRange.index;
     // 插入图片,res为服务器返回的图片链接地址
-    quill.insertEmbed(length, "image", res.data.url);
+    quill.insertEmbed(length, 'image', res.data.url);
     // 调整光标到最后
     quill.setSelection(length + 1);
     proxy?.$modal.closeLoading();
@@ -125,11 +129,11 @@ const handleUploadSuccess = (res: any) => {
     proxy?.$modal.loading(res.msg);
     proxy?.$modal.closeLoading();
   }
-}
+};
 
 // 图片上传前拦截
 const handleBeforeUpload = (file: any) => {
-  const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
+  const type = ['image/jpeg', 'image/jpg', 'image/png', 'image/svg'];
   const isJPG = type.includes(file.type);
   //检验文件格式
   if (!isJPG) {
@@ -146,13 +150,13 @@ const handleBeforeUpload = (file: any) => {
   }
   proxy?.$modal.loading('正在上传文件,请稍候...');
   return true;
-}
+};
 
 // 图片失败拦截
 const handleUploadError = (err: any) => {
   console.error(err);
   proxy?.$modal.msgError('上传文件失败');
-}
+};
 </script>
 
 <style>
@@ -167,71 +171,71 @@ const handleUploadError = (err: any) => {
 .quill-img {
   display: none;
 }
-.ql-snow .ql-tooltip[data-mode="link"]::before {
-  content: "请输入链接地址:";
+.ql-snow .ql-tooltip[data-mode='link']::before {
+  content: '请输入链接地址:';
 }
 .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
   border-right: 0;
-  content: "保存";
+  content: '保存';
   padding-right: 0;
 }
-.ql-snow .ql-tooltip[data-mode="video"]::before {
-  content: "请输入视频地址:";
+.ql-snow .ql-tooltip[data-mode='video']::before {
+  content: '请输入视频地址:';
 }
 .ql-snow .ql-picker.ql-size .ql-picker-label::before,
 .ql-snow .ql-picker.ql-size .ql-picker-item::before {
-  content: "14px";
+  content: '14px';
 }
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
-  content: "10px";
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
+  content: '10px';
 }
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
-  content: "18px";
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
+  content: '18px';
 }
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
-  content: "32px";
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
+  content: '32px';
 }
 .ql-snow .ql-picker.ql-header .ql-picker-label::before,
 .ql-snow .ql-picker.ql-header .ql-picker-item::before {
-  content: "文本";
+  content: '文本';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
-  content: "标题1";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
+  content: '标题1';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
-  content: "标题2";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
+  content: '标题2';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
-  content: "标题3";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
+  content: '标题3';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
-  content: "标题4";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
+  content: '标题4';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
-  content: "标题5";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
+  content: '标题5';
 }
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
-  content: "标题6";
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
+  content: '标题6';
 }
 .ql-snow .ql-picker.ql-font .ql-picker-label::before,
 .ql-snow .ql-picker.ql-font .ql-picker-item::before {
-  content: "标准字体";
+  content: '标准字体';
 }
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
-  content: "衬线字体";
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
+  content: '衬线字体';
 }
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
-  content: "等宽字体";
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
+  content: '等宽字体';
 }
 </style>

+ 125 - 115
src/components/FileUpload/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="upload-file">
     <el-upload
+      ref="fileUploadRef"
       multiple
       :action="uploadFileUrl"
       :before-upload="handleBeforeUpload"
@@ -12,30 +13,29 @@
       :show-file-list="false"
       :headers="headers"
       class="upload-file-uploader"
-      ref="fileUploadRef"
     >
       <!-- 上传按钮 -->
       <el-button type="primary">选取文件</el-button>
     </el-upload>
     <!-- 上传提示 -->
-    <div class="el-upload__tip" v-if="showTip">
+    <div v-if="showTip" class="el-upload__tip">
       请上传
       <template v-if="fileSize">
         大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
       </template>
       <template v-if="fileType">
-        格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
       </template>
       的文件
     </div>
     <!-- 文件列表 -->
     <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
-      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
+      <li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
         <el-link :href="`${file.url}`" :underline="false" target="_blank">
           <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
         </el-link>
         <div class="ele-upload-list__item-content-action">
-          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
+          <el-link :underline="false" type="danger" @click="handleDelete(index)">删除</el-link>
         </div>
       </li>
     </transition-group>
@@ -43,20 +43,20 @@
 </template>
 
 <script setup lang="ts">
-import { listByIds, delOss } from "@/api/system/oss";
+import { listByIds, delOss } from '@/api/system/oss';
 import { propTypes } from '@/utils/propTypes';
-import { globalHeaders } from "@/utils/request";
+import { globalHeaders } from '@/utils/request';
 
 const props = defineProps({
-    modelValue: [String, Object, Array],
-    // 数量限制
-    limit: propTypes.number.def(5),
-    // 大小限制(MB)
-    fileSize: propTypes.number.def(5),
-    // 文件类型, 例如['png', 'jpg', 'jpeg']
-    fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
-    // 是否显示提示
-    isShowTip: propTypes.bool.def(true),
+  modelValue: [String, Object, Array],
+  // 数量限制
+  limit: propTypes.number.def(5),
+  // 大小限制(MB)
+  fileSize: propTypes.number.def(5),
+  // 文件类型, 例如['png', 'jpg', 'jpeg']
+  fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']),
+  // 是否显示提示
+  isShowTip: propTypes.bool.def(true)
 });
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -65,153 +65,163 @@ const number = ref(0);
 const uploadList = ref<any[]>([]);
 
 const baseUrl = import.meta.env.VITE_APP_BASE_API;
-const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // 上传文件服务器地址
+const uploadFileUrl = ref(baseUrl + '/resource/oss/upload'); // 上传文件服务器地址
 const headers = ref(globalHeaders());
 
 const fileList = ref<any[]>([]);
-const showTip = computed(
-    () => props.isShowTip && (props.fileType || props.fileSize)
-);
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
 
 const fileUploadRef = ref<ElUploadInstance>();
 
-watch(() => props.modelValue, async val => {
+watch(
+  () => props.modelValue,
+  async (val) => {
     if (val) {
-        let temp = 1;
-        // 首先将值转为数组
-        let list = [];
-        if (Array.isArray(val)) {
-            list = val;
-        } else {
-            const res = await listByIds(val as string)
-            list = res.data.map((oss) => {
-                const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
-                return data;
-            });
-        }
-        // 然后将数组转为对象数组
-        fileList.value = list.map(item => {
-            item = { name: item.name, url: item.url, ossId: item.ossId };
-            item.uid = item.uid || new Date().getTime() + temp++;
-            return item;
+      let temp = 1;
+      // 首先将值转为数组
+      let list = [];
+      if (Array.isArray(val)) {
+        list = val;
+      } else {
+        const res = await listByIds(val as string);
+        list = res.data.map((oss) => {
+          const data = {
+            name: oss.originalName,
+            url: oss.url,
+            ossId: oss.ossId
+          };
+          return data;
         });
+      }
+      // 然后将数组转为对象数组
+      fileList.value = list.map((item) => {
+        item = { name: item.name, url: item.url, ossId: item.ossId };
+        item.uid = item.uid || new Date().getTime() + temp++;
+        return item;
+      });
     } else {
-        fileList.value = [];
-        return [];
+      fileList.value = [];
+      return [];
     }
-}, { deep: true, immediate: true });
+  },
+  { deep: true, immediate: true }
+);
 
 // 上传前校检格式和大小
 const handleBeforeUpload = (file: any) => {
-    // 校检文件类型
-    if (props.fileType.length) {
-        const fileName = file.name.split('.');
-        const fileExt = fileName[fileName.length - 1];
-        const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
-        if (!isTypeOk) {
-            proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
-            return false;
-        }
+  // 校检文件类型
+  if (props.fileType.length) {
+    const fileName = file.name.split('.');
+    const fileExt = fileName[fileName.length - 1];
+    const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
+    if (!isTypeOk) {
+      proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`);
+      return false;
     }
-    // 校检文件大小
-    if (props.fileSize) {
-        const isLt = file.size / 1024 / 1024 < props.fileSize;
-        if (!isLt) {
-            proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
-            return false;
-        }
+  }
+  // 校检文件大小
+  if (props.fileSize) {
+    const isLt = file.size / 1024 / 1024 < props.fileSize;
+    if (!isLt) {
+      proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
+      return false;
     }
-    proxy?.$modal.loading("正在上传文件,请稍候...");
-    number.value++;
-    return true;
-}
+  }
+  proxy?.$modal.loading('正在上传文件,请稍候...');
+  number.value++;
+  return true;
+};
 
 // 文件个数超出
 const handleExceed = () => {
-    proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
-}
+  proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
+};
 
 // 上传失败
 const handleUploadError = () => {
-    proxy?.$modal.msgError("上传文件失败");
-}
+  proxy?.$modal.msgError('上传文件失败');
+};
 
 // 上传成功回调
 const handleUploadSuccess = (res: any, file: UploadFile) => {
-    if (res.code === 200) {
-        uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
-        uploadedSuccessfully();
-    } else {
-        number.value--;
-        proxy?.$modal.closeLoading();
-        proxy?.$modal.msgError(res.msg);
-        fileUploadRef.value?.handleRemove(file);
-        uploadedSuccessfully();
-    }
-}
+  if (res.code === 200) {
+    uploadList.value.push({
+      name: res.data.fileName,
+      url: res.data.url,
+      ossId: res.data.ossId
+    });
+    uploadedSuccessfully();
+  } else {
+    number.value--;
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgError(res.msg);
+    fileUploadRef.value?.handleRemove(file);
+    uploadedSuccessfully();
+  }
+};
 
 // 删除文件
 const handleDelete = (index: number) => {
-    let ossId = fileList.value[index].ossId;
-    delOss(ossId);
-    fileList.value.splice(index, 1);
-    emit("update:modelValue", listToString(fileList.value));
-}
+  let ossId = fileList.value[index].ossId;
+  delOss(ossId);
+  fileList.value.splice(index, 1);
+  emit('update:modelValue', listToString(fileList.value));
+};
 
 // 上传结束处理
 const uploadedSuccessfully = () => {
-    if (number.value > 0 && uploadList.value.length === number.value) {
-        fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
-        uploadList.value = [];
-        number.value = 0;
-        emit("update:modelValue", listToString(fileList.value));
-        proxy?.$modal.closeLoading();
-    }
-}
+  if (number.value > 0 && uploadList.value.length === number.value) {
+    fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
+    uploadList.value = [];
+    number.value = 0;
+    emit('update:modelValue', listToString(fileList.value));
+    proxy?.$modal.closeLoading();
+  }
+};
 
 // 获取文件名称
 const getFileName = (name: string) => {
-    // 如果是url那么取最后的名字 如果不是直接返回
-    if (name.lastIndexOf("/") > -1) {
-        return name.slice(name.lastIndexOf("/") + 1);
-    } else {
-        return name;
-    }
-}
+  // 如果是url那么取最后的名字 如果不是直接返回
+  if (name.lastIndexOf('/') > -1) {
+    return name.slice(name.lastIndexOf('/') + 1);
+  } else {
+    return name;
+  }
+};
 
 // 对象转成指定字符串分隔
 const listToString = (list: any[], separator?: string) => {
-    let strs = "";
-    separator = separator || ",";
-    list.forEach(item => {
-        if (item.ossId) {
-            strs += item.ossId + separator;
-        }
-    })
-    return strs != "" ? strs.substring(0, strs.length - 1) : "";
-}
+  let strs = '';
+  separator = separator || ',';
+  list.forEach((item) => {
+    if (item.ossId) {
+      strs += item.ossId + separator;
+    }
+  });
+  return strs != '' ? strs.substring(0, strs.length - 1) : '';
+};
 </script>
 
 <style scoped lang="scss">
 .upload-file-uploader {
-    margin-bottom: 5px;
+  margin-bottom: 5px;
 }
 
 .upload-file-list .el-upload-list__item {
-    border: 1px solid #e4e7ed;
-    line-height: 2;
-    margin-bottom: 10px;
-    position: relative;
+  border: 1px solid #e4e7ed;
+  line-height: 2;
+  margin-bottom: 10px;
+  position: relative;
 }
 
 .upload-file-list .ele-upload-list__item-content {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    color: inherit;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  color: inherit;
 }
 
 .ele-upload-list__item-content-action .el-link {
-    margin-right: 10px;
+  margin-right: 10px;
 }
 </style>

+ 4 - 4
src/components/Hamburger/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div style="padding: 0 15px;" @click="toggleClick">
+  <div style="padding: 0 15px" @click="toggleClick">
     <svg :class="{ 'is-active': isActive }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
       <path
         d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
@@ -13,12 +13,12 @@ import { propTypes } from '@/utils/propTypes';
 
 defineProps({
   isActive: propTypes.bool.def(false)
-})
+});
 
-const emit = defineEmits(['toggleClick'])
+const emit = defineEmits(['toggleClick']);
 const toggleClick = () => {
   emit('toggleClick');
-}
+};
 </script>
 
 <style scoped>

+ 49 - 47
src/components/HeaderSearch/index.vue

@@ -1,6 +1,6 @@
 <template>
-  <div :class="{ 'show': show }" class="header-search">
-    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click"/>
+  <div :class="{ show: show }" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
     <el-select
       ref="headerSearchSelectRef"
       v-model="search"
@@ -12,23 +12,22 @@
       class="header-search-select"
       @change="change"
     >
-      <el-option v-for="option in options" :key="option.item.path" :value="option.item"
-                 :label="option.item.title.join(' > ')"/>
+      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
     </el-select>
   </div>
 </template>
 
 <script setup lang="ts" name="HeaderSearch">
 import Fuse from 'fuse.js';
-import {getNormalPath} from '@/utils/ruoyi';
-import {isHttp} from '@/utils/validate';
+import { getNormalPath } from '@/utils/ruoyi';
+import { isHttp } from '@/utils/validate';
 import usePermissionStore from '@/store/modules/permission';
-import {RouteOption} from 'vue-router';
+import { RouteRecordRaw } from 'vue-router';
 
 type Router = Array<{
   path: string;
   title: string[];
-}>
+}>;
 
 const search = ref('');
 const options = ref<any>([]);
@@ -40,36 +39,36 @@ const router = useRouter();
 const routes = computed(() => usePermissionStore().routes);
 
 const click = () => {
-  show.value = !show.value
+  show.value = !show.value;
   if (show.value) {
-    headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
+    headerSearchSelectRef.value && headerSearchSelectRef.value.focus();
   }
 };
 const close = () => {
-  headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
-  options.value = []
-  show.value = false
-}
+  headerSearchSelectRef.value && headerSearchSelectRef.value.blur();
+  options.value = [];
+  show.value = false;
+};
 const change = (val: any) => {
   const path = val.path;
   const query = val.query;
   if (isHttp(path)) {
     // http(s):// 路径新窗口打开
-    const pindex = path.indexOf("http");
-    window.open(path.substr(pindex, path.length), "_blank");
+    const pindex = path.indexOf('http');
+    window.open(path.substr(pindex, path.length), '_blank');
   } else {
     if (query) {
       router.push({ path: path, query: JSON.parse(query) });
     } else {
-      router.push(path)
+      router.push(path);
     }
   }
-  search.value = ''
-  options.value = []
+  search.value = '';
+  options.value = [];
   nextTick(() => {
-    show.value = false
-  })
-}
+    show.value = false;
+  });
+};
 const initFuse = (list: Router) => {
   fuse.value = new Fuse(list, {
     shouldSort: true,
@@ -77,20 +76,23 @@ const initFuse = (list: Router) => {
     location: 0,
     distance: 100,
     minMatchCharLength: 1,
-    keys: [{
-      name: 'title',
-      weight: 0.7
-    }, {
-      name: 'path',
-      weight: 0.3
-    }]
-  })
-}
+    keys: [
+      {
+        name: 'title',
+        weight: 0.7
+      },
+      {
+        name: 'path',
+        weight: 0.3
+      }
+    ]
+  });
+};
 // Filter out the routes that can be displayed in the sidebar
 // And generate the internationalized title
-const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
-  let res: Router = []
-  routes.forEach(r => {
+const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => {
+  let res: Router = [];
+  routes.forEach((r) => {
     // skip hidden router
     if (!r.hidden) {
       const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
@@ -98,7 +100,7 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
         path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
         title: [...prefixTitle],
         query: ''
-      }
+      };
       if (r.meta && r.meta.title) {
         data.title = [...data.title, r.meta.title];
         if (r.redirect !== 'noRedirect') {
@@ -109,7 +111,7 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
       }
 
       if (r.query) {
-        data.query = r.query
+        data.query = r.query;
       }
 
       // recursive child routes
@@ -120,20 +122,20 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin
         }
       }
     }
-  })
+  });
   return res;
-}
+};
 const querySearch = (query: string) => {
   if (query !== '') {
-    options.value = fuse.value.search(query)
+    options.value = fuse.value.search(query);
   } else {
-    options.value = []
+    options.value = [];
   }
-}
+};
 
 onMounted(() => {
   searchPool.value = generateRoutes(routes.value);
-})
+});
 
 // watchEffect(() => {
 //     searchPool.value = generateRoutes(routes.value)
@@ -141,15 +143,15 @@ onMounted(() => {
 
 watch(show, (value) => {
   if (value) {
-    document.body.addEventListener('click', close)
+    document.body.addEventListener('click', close);
   } else {
-    document.body.removeEventListener('click', close)
+    document.body.removeEventListener('click', close);
   }
-})
+});
 
 watch(searchPool, (list) => {
-  initFuse(list)
-})
+  initFuse(list);
+});
 </script>
 
 <style lang="scss" scoped>

+ 11 - 13
src/components/IconSelect/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="relative" :style="{ width: width }">
-    <el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="点击选择图标">
+    <el-input v-model="modelValue" readonly placeholder="点击选择图标" @click="visible = !visible">
       <template #prepend>
         <svg-icon :icon-class="modelValue" />
       </template>
@@ -8,18 +8,18 @@
 
     <el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450">
       <template #reference>
-        <div @click="visible = !visible" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]">
+        <div class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]" @click="visible = !visible">
           <i-ep-caret-top v-show="visible"></i-ep-caret-top>
           <i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom>
         </div>
       </template>
 
-      <el-input class="p-2" v-model="filterValue" placeholder="搜索图标" clearable @input="filterIcons" />
+      <el-input v-model="filterValue" class="p-2" placeholder="搜索图标" clearable @input="filterIcons" />
 
       <el-scrollbar height="w-[200px]">
         <ul class="icon-list">
           <el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light">
-            <li :class="['icon-item', {active: modelValue == iconName}]" @click="selectedIcon(iconName)">
+            <li :class="['icon-item', { active: modelValue == iconName }]" @click="selectedIcon(iconName)">
               <svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" />
             </li>
           </el-tooltip>
@@ -50,13 +50,11 @@ const filterValue = ref('');
  */
 const filterIcons = () => {
   if (filterValue.value) {
-    iconNames.value = icons.filter(iconName =>
-      iconName.includes(filterValue.value)
-    );
+    iconNames.value = icons.filter((iconName) => iconName.includes(filterValue.value));
   } else {
     iconNames.value = icons;
   }
-}
+};
 /**
  * 选择图标
  * @param iconName 选择的图标名称
@@ -64,12 +62,12 @@ const filterIcons = () => {
 const selectedIcon = (iconName: string) => {
   emit('update:modelValue', iconName);
   visible.value = false;
-}
+};
 </script>
 
 <style scoped lang="scss">
 .el-scrollbar {
-  max-height: calc(50vh - 100px)!important;
+  max-height: calc(50vh - 100px) !important;
   overflow-y: auto;
 }
 .el-divider--horizontal {
@@ -99,8 +97,8 @@ const selectedIcon = (iconName: string) => {
     }
   }
   .active {
-      border-color: var(--el-color-primary);
-      color: var(--el-color-primary);
-    }
+    border-color: var(--el-color-primary);
+    color: var(--el-color-primary);
+  }
 }
 </style>

+ 7 - 11
src/components/ImagePreview/index.vue

@@ -15,11 +15,11 @@ const props = defineProps({
   src: propTypes.string.def(''),
   width: {
     type: [Number, String],
-    default: ""
+    default: ''
   },
   height: {
     type: [Number, String],
-    default: ""
+    default: ''
   }
 });
 
@@ -27,7 +27,7 @@ const realSrc = computed(() => {
   if (!props.src) {
     return;
   }
-  let real_src = props.src.split(",")[0];
+  let real_src = props.src.split(',')[0];
   return real_src;
 });
 
@@ -35,21 +35,17 @@ const realSrcList = computed(() => {
   if (!props.src) {
     return;
   }
-  let real_src_list = props.src.split(",");
+  let real_src_list = props.src.split(',');
   let srcList: string[] = [];
-  real_src_list.forEach(item => {
+  real_src_list.forEach((item) => {
     return srcList.push(item);
   });
   return srcList;
 });
 
-const realWidth = computed(() =>
-  typeof props.width == "string" ? props.width : `${props.width}px`
-);
+const realWidth = computed(() => (typeof props.width == 'string' ? props.width : `${props.width}px`));
 
-const realHeight = computed(() =>
-  typeof props.height == "string" ? props.height : `${props.height}px`
-);
+const realHeight = computed(() => (typeof props.height == 'string' ? props.height : `${props.height}px`));
 </script>
 
 <style lang="scss" scoped>

+ 119 - 120
src/components/ImageUpload/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="component-upload-image">
     <el-upload
+      ref="imageUpload"
       multiple
       :action="uploadImgUrl"
       list-type="picture-card"
@@ -9,7 +10,6 @@
       :limit="limit"
       :on-error="handleUploadError"
       :on-exceed="handleExceed"
-      ref="imageUpload"
       :before-remove="handleDelete"
       :show-file-list="true"
       :headers="headers"
@@ -22,13 +22,13 @@
       </el-icon>
     </el-upload>
     <!-- 上传提示 -->
-    <div class="el-upload__tip" v-if="showTip">
+    <div v-if="showTip" class="el-upload__tip">
       请上传
       <template v-if="fileSize">
         大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
       </template>
       <template v-if="fileType">
-        格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
       </template>
       的文件
     </div>
@@ -40,177 +40,176 @@
 </template>
 
 <script setup lang="ts">
-import { listByIds, delOss } from "@/api/system/oss";
-import { ComponentInternalInstance } from "vue";
-import { OssVO } from "@/api/system/oss/types";
+import { listByIds, delOss } from '@/api/system/oss';
+import { OssVO } from '@/api/system/oss/types';
 import { propTypes } from '@/utils/propTypes';
-import {globalHeaders} from "@/utils/request";
+import { globalHeaders } from '@/utils/request';
 
 const props = defineProps({
-    modelValue: [String, Object, Array],
-    // 图片数量限制
-    limit: propTypes.number.def(5),
-    // 大小限制(MB)
-    fileSize: propTypes.number.def(5),
-    // 文件类型, 例如['png', 'jpg', 'jpeg']
-    fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
-    // 是否显示提示
-    isShowTip: {
-        type: Boolean,
-        default: true
-    },
+  modelValue: [String, Object, Array],
+  // 图片数量限制
+  limit: propTypes.number.def(5),
+  // 大小限制(MB)
+  fileSize: propTypes.number.def(5),
+  // 文件类型, 例如['png', 'jpg', 'jpeg']
+  fileType: propTypes.array.def(['png', 'jpg', 'jpeg']),
+  // 是否显示提示
+  isShowTip: {
+    type: Boolean,
+    default: true
+  }
 });
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const emit = defineEmits(['update:modelValue']);
 const number = ref(0);
 const uploadList = ref<any[]>([]);
-const dialogImageUrl = ref("");
+const dialogImageUrl = ref('');
 const dialogVisible = ref(false);
 
 const baseUrl = import.meta.env.VITE_APP_BASE_API;
-const uploadImgUrl = ref(baseUrl + "/resource/oss/upload"); // 上传的图片服务器地址
+const uploadImgUrl = ref(baseUrl + '/resource/oss/upload'); // 上传的图片服务器地址
 const headers = ref(globalHeaders());
 
 const fileList = ref<any[]>([]);
-const showTip = computed(
-    () => props.isShowTip && (props.fileType || props.fileSize)
-);
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
 
 const imageUploadRef = ref<ElUploadInstance>();
 
-watch(() => props.modelValue, async val => {
+watch(
+  () => props.modelValue,
+  async (val) => {
     if (val) {
-        // 首先将值转为数组
-        let list: OssVO[] = [];
-        if (Array.isArray(val)) {
-            list = val as OssVO[];
+      // 首先将值转为数组
+      let list: OssVO[] = [];
+      if (Array.isArray(val)) {
+        list = val as OssVO[];
+      } else {
+        const res = await listByIds(val as string);
+        list = res.data;
+      }
+      // 然后将数组转为对象数组
+      fileList.value = list.map((item) => {
+        // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
+        let itemData;
+        if (typeof item === 'string') {
+          itemData = { name: item, url: item };
         } else {
-            const res = await listByIds(val as string)
-            list = res.data
+          // 此处name使用ossId 防止删除出现重名
+          itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
         }
-        // 然后将数组转为对象数组
-        fileList.value = list.map(item => {
-            // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
-            let itemData;
-            if (typeof item === "string") {
-                itemData = { name: item, url: item };
-            } else {
-                // 此处name使用ossId 防止删除出现重名
-                itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
-            }
-            return itemData;
-        });
+        return itemData;
+      });
     } else {
-        fileList.value = [];
-        return [];
+      fileList.value = [];
+      return [];
     }
-}, { deep: true, immediate: true });
+  },
+  { deep: true, immediate: true }
+);
 
 /** 上传前loading加载 */
 const handleBeforeUpload = (file: any) => {
-    let isImg = false;
-    if (props.fileType.length) {
-        let fileExtension = "";
-        if (file.name.lastIndexOf(".") > -1) {
-            fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
-        }
-        isImg = props.fileType.some((type: any) => {
-            if (file.type.indexOf(type) > -1) return true;
-            if (fileExtension && fileExtension.indexOf(type) > -1) return true;
-            return false;
-        });
-    } else {
-        isImg = file.type.indexOf("image") > -1;
+  let isImg = false;
+  if (props.fileType.length) {
+    let fileExtension = '';
+    if (file.name.lastIndexOf('.') > -1) {
+      fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1);
     }
-    if (!isImg) {
-        proxy?.$modal.msgError(
-            `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
-        );
-        return false;
+    isImg = props.fileType.some((type: any) => {
+      if (file.type.indexOf(type) > -1) return true;
+      if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+      return false;
+    });
+  } else {
+    isImg = file.type.indexOf('image') > -1;
+  }
+  if (!isImg) {
+    proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`);
+    return false;
+  }
+  if (props.fileSize) {
+    const isLt = file.size / 1024 / 1024 < props.fileSize;
+    if (!isLt) {
+      proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
+      return false;
     }
-    if (props.fileSize) {
-        const isLt = file.size / 1024 / 1024 < props.fileSize;
-        if (!isLt) {
-            proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
-            return false;
-        }
-    }
-    proxy?.$modal.loading("正在上传图片,请稍候...");
-    number.value++;
-}
+  }
+  proxy?.$modal.loading('正在上传图片,请稍候...');
+  number.value++;
+};
 
 // 文件个数超出
 const handleExceed = () => {
-    proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
-}
+  proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
+};
 
 // 上传成功回调
 const handleUploadSuccess = (res: any, file: UploadFile) => {
-    if (res.code === 200) {
-        uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
-        uploadedSuccessfully();
-    } else {
-        number.value--;
-        proxy?.$modal.closeLoading();
-        proxy?.$modal.msgError(res.msg);
-        imageUploadRef.value?.handleRemove(file);
-        uploadedSuccessfully();
-    }
-}
+  if (res.code === 200) {
+    uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
+    uploadedSuccessfully();
+  } else {
+    number.value--;
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgError(res.msg);
+    imageUploadRef.value?.handleRemove(file);
+    uploadedSuccessfully();
+  }
+};
 
 // 删除图片
 const handleDelete = (file: UploadFile): boolean => {
-    const findex = fileList.value.map(f => f.name).indexOf(file.name);
-    if (findex > -1 && uploadList.value.length === number.value) {
-        let ossId = fileList.value[findex].ossId;
-        delOss(ossId);
-        fileList.value.splice(findex, 1);
-        emit("update:modelValue", listToString(fileList.value));
-        return false;
-    }
-    return true;
-}
+  const findex = fileList.value.map((f) => f.name).indexOf(file.name);
+  if (findex > -1 && uploadList.value.length === number.value) {
+    let ossId = fileList.value[findex].ossId;
+    delOss(ossId);
+    fileList.value.splice(findex, 1);
+    emit('update:modelValue', listToString(fileList.value));
+    return false;
+  }
+  return true;
+};
 
 // 上传结束处理
 const uploadedSuccessfully = () => {
-    if (number.value > 0 && uploadList.value.length === number.value) {
-        fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
-        uploadList.value = [];
-        number.value = 0;
-        emit("update:modelValue", listToString(fileList.value));
-        proxy?.$modal.closeLoading();
-    }
-}
+  if (number.value > 0 && uploadList.value.length === number.value) {
+    fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
+    uploadList.value = [];
+    number.value = 0;
+    emit('update:modelValue', listToString(fileList.value));
+    proxy?.$modal.closeLoading();
+  }
+};
 
 // 上传失败
 const handleUploadError = () => {
-    proxy?.$modal.msgError("上传图片失败");
-    proxy?.$modal.closeLoading();
-}
+  proxy?.$modal.msgError('上传图片失败');
+  proxy?.$modal.closeLoading();
+};
 
 // 预览
 const handlePictureCardPreview = (file: any) => {
-    dialogImageUrl.value = file.url;
-    dialogVisible.value = true;
-}
+  dialogImageUrl.value = file.url;
+  dialogVisible.value = true;
+};
 
 // 对象转成指定字符串分隔
 const listToString = (list: any[], separator?: string) => {
-    let strs = "";
-    separator = separator || ",";
-    for (let i in list) {
-        if (undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
-            strs += list[i].ossId + separator;
-        }
+  let strs = '';
+  separator = separator || ',';
+  for (let i in list) {
+    if (undefined !== list[i].ossId && list[i].url.indexOf('blob:') !== 0) {
+      strs += list[i].ossId + separator;
     }
-    return strs != "" ? strs.substring(0, strs.length - 1) : "";
-}
+  }
+  return strs != '' ? strs.substring(0, strs.length - 1) : '';
+};
 </script>
 
 <style scoped lang="scss">
 // .el-upload--picture-card 控制加号部分
 :deep(.hide .el-upload--picture-card) {
-    display: none;
+  display: none;
 }
 </style>

+ 3 - 4
src/components/LangSelect/index.vue

@@ -20,16 +20,15 @@ import { useAppStore } from '@/store/modules/app';
 const appStore = useAppStore();
 const { locale } = useI18n();
 
-
 const message: any = {
   zh_CN: '切换语言成功!',
-  en_US: 'Switch Language Successful!',
-}
+  en_US: 'Switch Language Successful!'
+};
 const handleLanguageChange = (lang: string) => {
   locale.value = lang;
   appStore.changeLanguage(lang);
   ElMessage.success(message[lang] || '切换语言成功!');
-}
+};
 </script>
 
 <style lang="scss" scoped>

+ 47 - 47
src/components/Pagination/index.vue

@@ -1,9 +1,9 @@
 <template>
-  <div :class="{ 'hidden': hidden }" class="pagination-container">
+  <div :class="{ hidden: hidden }" class="pagination-container">
     <el-pagination
-      :background="background"
       v-model:current-page="currentPage"
       v-model:page-size="pageSize"
+      :background="background"
       :layout="layout"
       :page-sizes="pageSizes"
       :pager-count="pagerCount"
@@ -16,69 +16,69 @@
 
 <script lang="ts">
 export default {
-    name: 'Pagination'
-}
+  name: 'Pagination'
+};
 </script>
 
 <script setup lang="ts">
-import { scrollTo } from '@/utils/scroll-to'
-import { propTypes } from "@/utils/propTypes";
+import { scrollTo } from '@/utils/scroll-to';
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-    total: propTypes.number,
-    page: propTypes.number.def(1),
-    limit: propTypes.number.def(20),
-    pageSizes: {
-      type: Array as PropType<number[]>,
-      default: () => [10, 20, 30, 50]
-    },
-    // 移动端页码按钮的数量端默认值5
-    pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
-    layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
-    background: propTypes.bool.def(true),
-    autoScroll: propTypes.bool.def(true),
-    hidden: propTypes.bool.def(false),
-    float: propTypes.string.def('right')
-})
+  total: propTypes.number,
+  page: propTypes.number.def(1),
+  limit: propTypes.number.def(20),
+  pageSizes: {
+    type: Array,
+    default: () => [10, 20, 30, 50]
+  },
+  // 移动端页码按钮的数量端默认值5
+  pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
+  layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
+  background: propTypes.bool.def(true),
+  autoScroll: propTypes.bool.def(true),
+  hidden: propTypes.bool.def(false),
+  float: propTypes.string.def('right')
+});
 
 const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
 const currentPage = computed({
-    get() {
-        return props.page
-    },
-    set(val) {
-        emit('update:page', val)
-    }
-})
+  get() {
+    return props.page;
+  },
+  set(val) {
+    emit('update:page', val);
+  }
+});
 const pageSize = computed({
-    get() {
-        return props.limit
-    },
-    set(val){
-        emit('update:limit', val)
-    }
-})
+  get() {
+    return props.limit;
+  },
+  set(val) {
+    emit('update:limit', val);
+  }
+});
 function handleSizeChange(val: number) {
-    if (currentPage.value * val > props.total) {
-        currentPage.value = 1
-    }
-    emit('pagination', { page: currentPage.value, limit: val })
-    if (props.autoScroll) {
-        scrollTo(0, 800)
-    }
+  if (currentPage.value * val > props.total) {
+    currentPage.value = 1;
+  }
+  emit('pagination', { page: currentPage.value, limit: val });
+  if (props.autoScroll) {
+    scrollTo(0, 800);
+  }
 }
 function handleCurrentChange(val: number) {
-    emit('pagination', { page: val, limit: pageSize.value })
-    if (props.autoScroll) {
-        scrollTo(0, 800)
-    }
+  emit('pagination', { page: val, limit: pageSize.value });
+  if (props.autoScroll) {
+    scrollTo(0, 800);
+  }
 }
 </script>
 
 <style lang="scss" scoped>
 .pagination-container {
   padding: 32px 16px;
-  .el-pagination{
+  .el-pagination {
     float: v-bind(float);
   }
 }

+ 24 - 26
src/components/RightToolbar/index.vue

@@ -1,13 +1,13 @@
 <template>
   <div class="top-right-btn" :style="style">
     <el-row>
-      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
+      <el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
         <el-button circle icon="Search" @click="toggleSearch()" />
       </el-tooltip>
       <el-tooltip class="item" effect="dark" content="刷新" placement="top">
         <el-button circle icon="Refresh" @click="refresh()" />
       </el-tooltip>
-      <el-tooltip class="item" effect="dark" content="显示/隐藏列" placement="top" v-if="columns">
+      <el-tooltip v-if="columns" class="item" effect="dark" content="显示/隐藏列" placement="top">
         <div class="show-btn">
           <el-popover placement="bottom" trigger="click">
             <div class="tree-header">显示/隐藏列</div>
@@ -15,9 +15,9 @@
               ref="columnRef"
               :data="columns"
               show-checkbox
-              @check="columnChange"
               node-key="key"
               :props="{ label: 'label', children: 'children' }"
+              @check="columnChange"
             ></el-tree>
             <template #reference>
               <el-button circle icon="Menu" />
@@ -33,51 +33,49 @@
 import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-    showSearch: propTypes.bool.def(true),
-    columns: {
-        type: Array as PropType<FieldOption[]>,
-    },
-    search: propTypes.bool.def(true),
-    gutter: propTypes.number.def(10),
-})
+  showSearch: propTypes.bool.def(true),
+  columns: propTypes.fieldOption,
+  search: propTypes.bool.def(true),
+  gutter: propTypes.number.def(10)
+});
 
 const columnRef = ref<ElTreeInstance>();
 const emits = defineEmits(['update:showSearch', 'queryTable']);
 
 const style = computed(() => {
-    const ret: any = {};
-    if (props.gutter) {
-        ret.marginRight = `${props.gutter / 2}px`;
-    }
-    return ret;
+  const ret: any = {};
+  if (props.gutter) {
+    ret.marginRight = `${props.gutter / 2}px`;
+  }
+  return ret;
 });
 
 // 搜索
 function toggleSearch() {
-    emits("update:showSearch", !props.showSearch);
+  emits('update:showSearch', !props.showSearch);
 }
 
 // 刷新
 function refresh() {
-    emits("queryTable");
+  emits('queryTable');
 }
 
 // 更改数据列的显示和隐藏
 function columnChange(...args: any[]) {
   props.columns?.forEach((item) => {
     item.visible = args[1].checkedKeys.includes(item.key);
-  })
+  });
 }
 
 // 显隐列初始默认隐藏列
 onMounted(() => {
-    props.columns?.forEach((item) => {
-        if (item.visible) {
-          columnRef.value?.setChecked(item.key, true, false);
-            // value.value.push(item.key);
-        }
-    })
-})
+  props.columns?.forEach((item) => {
+    if (item.visible) {
+      columnRef.value?.setChecked(item.key, true, false);
+      // value.value.push(item.key);
+    }
+  });
+});
 </script>
 
 <style lang="scss" scoped>
@@ -93,7 +91,7 @@ onMounted(() => {
 .my-el-transfer {
   text-align: center;
 }
-.tree-header{
+.tree-header {
   width: 100%;
   line-height: 24px;
   text-align: center;

+ 1 - 1
src/components/RuoYiDoc/index.vue

@@ -8,6 +8,6 @@
 const url = ref('https://plus-doc.dromara.org/');
 
 function goto() {
-  window.open(url.value)
+  window.open(url.value);
 }
 </script>

+ 1 - 1
src/components/RuoYiGit/index.vue

@@ -8,6 +8,6 @@
 const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus');
 
 function goto() {
-  window.open(url.value)
+  window.open(url.value);
 }
 </script>

+ 6 - 6
src/components/SizeSelect/index.vue

@@ -16,20 +16,20 @@
 </template>
 
 <script setup lang="ts">
-import useAppStore from "@/store/modules/app";
+import useAppStore from '@/store/modules/app';
 
 const appStore = useAppStore();
 const size = computed(() => appStore.size);
 
 const sizeOptions = ref([
-    { label: "较大", value: "large" },
-    { label: "默认", value: "default" },
-    { label: "稍小", value: "small" },
+  { label: '较大', value: 'large' },
+  { label: '默认', value: 'default' },
+  { label: '稍小', value: 'small' }
 ]);
 
 const handleSetSize = (size: string) => {
-    appStore.setSize(size);
-}
+  appStore.setSize(size);
+};
 </script>
 
 <style lang="scss" scoped>

+ 10 - 10
src/components/SvgIcon/index.vue

@@ -8,17 +8,17 @@
 import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-    iconClass: propTypes.string.isRequired,
-    className: propTypes.string.def(''),
-    color: propTypes.string.def(''),
-})
-const iconName =  computed(() => `#icon-${props.iconClass}`);
+  iconClass: propTypes.string.isRequired,
+  className: propTypes.string.def(''),
+  color: propTypes.string.def('')
+});
+const iconName = computed(() => `#icon-${props.iconClass}`);
 const svgClass = computed(() => {
-    if (props.className) {
-        return `svg-icon ${props.className}`
-    }
-    return 'svg-icon'
-})
+  if (props.className) {
+    return `svg-icon ${props.className}`;
+  }
+  return 'svg-icon';
+});
 </script>
 
 <style scope lang="scss">

+ 50 - 48
src/components/TopNav/index.vue

@@ -1,19 +1,18 @@
 <template>
-  <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
+  <el-menu :default-active="activeMenu" mode="horizontal" :ellipsis="false" @select="handleSelect">
     <template v-for="(item, index) in topMenus">
-      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
-        ><svg-icon
-        v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
-        :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
+      <el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path"
+        ><svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" />
+        {{ item.meta?.title }}</el-menu-item
       >
     </template>
 
     <!-- 顶部菜单超出数量折叠 -->
-    <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
+    <el-sub-menu v-if="topMenus.length > visibleNumber" :style="{ '--theme': theme }" index="more">
       <template #title>更多菜单</template>
       <template v-for="(item, index) in topMenus">
-        <el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber"
-          ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
+        <el-menu-item v-if="index >= visibleNumber" :key="index" :index="item.path"
+          ><svg-icon :icon-class="item.meta ? item.meta.icon : ''" /> {{ item.meta?.title }}</el-menu-item
         >
       </template>
     </el-sub-menu>
@@ -26,7 +25,7 @@ import { isHttp } from '@/utils/validate';
 import useAppStore from '@/store/modules/app';
 import useSettingsStore from '@/store/modules/settings';
 import usePermissionStore from '@/store/modules/permission';
-import { RouteOption } from 'vue-router';
+import { RouteRecordRaw } from 'vue-router';
 
 // 顶部栏初始数
 const visibleNumber = ref<number>(-1);
@@ -35,9 +34,9 @@ const currentIndex = ref<string>();
 // 隐藏侧边栏路由
 const hideList = ['/index', '/user/profile'];
 
-const appStore = useAppStore()
-const settingsStore = useSettingsStore()
-const permissionStore = usePermissionStore()
+const appStore = useAppStore();
+const settingsStore = useSettingsStore();
+const permissionStore = usePermissionStore();
 const route = useRoute();
 const router = useRouter();
 
@@ -48,73 +47,73 @@ const routers = computed(() => permissionStore.topbarRouters);
 
 // 顶部显示菜单
 const topMenus = computed(() => {
-  let topMenus:RouteOption[] = [];
+  let topMenus: RouteRecordRaw[] = [];
   routers.value.map((menu) => {
     if (menu.hidden !== true) {
       // 兼容顶部栏一级菜单内部跳转
-      if (menu.path === "/") {
-          topMenus.push(menu.children? menu.children[0] : menu);
+      if (menu.path === '/') {
+        topMenus.push(menu.children ? menu.children[0] : menu);
       } else {
-          topMenus.push(menu);
+        topMenus.push(menu);
       }
     }
-  })
+  });
   return topMenus;
-})
+});
 
 // 设置子路由
 const childrenMenus = computed(() => {
-  let childrenMenus:RouteOption[] = [];
+  let childrenMenus: RouteRecordRaw[] = [];
   routers.value.map((router) => {
     router.children?.forEach((item) => {
       if (item.parentPath === undefined) {
-        if(router.path === "/") {
-          item.path = "/" + item.path;
+        if (router.path === '/') {
+          item.path = '/' + item.path;
         } else {
-          if(!isHttp(item.path)) {
-            item.path = router.path + "/" + item.path;
+          if (!isHttp(item.path)) {
+            item.path = router.path + '/' + item.path;
           }
         }
         item.parentPath = router.path;
       }
       childrenMenus.push(item);
-    })
-  })
+    });
+  });
   return constantRoutes.concat(childrenMenus);
-})
+});
 
 // 默认激活的菜单
 const activeMenu = computed(() => {
   const path = route.path;
   let activePath = path;
-  if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
+  if (path !== undefined && path.lastIndexOf('/') > 0 && hideList.indexOf(path) === -1) {
     const tmpPath = path.substring(1, path.length);
-    activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
+    activePath = '/' + tmpPath.substring(0, tmpPath.indexOf('/'));
     if (!route.meta.link) {
-        appStore.toggleSideBarHide(false);
+      appStore.toggleSideBarHide(false);
     }
-  } else if(!route.children) {
+  } else if (!route.children) {
     activePath = path;
     appStore.toggleSideBarHide(true);
   }
   activeRoutes(activePath);
   return activePath;
-})
+});
 
 const setVisibleNumber = () => {
   const width = document.body.getBoundingClientRect().width / 3;
   visibleNumber.value = parseInt(String(width / 85));
-}
+};
 
 const handleSelect = (key: string) => {
   currentIndex.value = key;
-  const route = routers.value.find(item => item.path === key);
+  const route = routers.value.find((item) => item.path === key);
   if (isHttp(key)) {
     // http(s):// 路径新窗口打开
-    window.open(key, "_blank");
+    window.open(key, '_blank');
   } else if (!route || !route.children) {
     // 没有子路由路径内部打开
-    const routeMenu = childrenMenus.value.find(item => item.path === key);
+    const routeMenu = childrenMenus.value.find((item) => item.path === key);
     if (routeMenu && routeMenu.query) {
       let query = JSON.parse(routeMenu.query);
       router.push({ path: key, query: query });
@@ -127,35 +126,35 @@ const handleSelect = (key: string) => {
     activeRoutes(key);
     appStore.toggleSideBarHide(false);
   }
-}
+};
 
 const activeRoutes = (key: string) => {
-  let routes:RouteOption[] = [];
+  let routes: RouteRecordRaw[] = [];
   if (childrenMenus.value && childrenMenus.value.length > 0) {
     childrenMenus.value.map((item) => {
-      if (key == item.parentPath || (key == "index" && "" == item.path)) {
+      if (key == item.parentPath || (key == 'index' && '' == item.path)) {
         routes.push(item);
       }
     });
   }
-  if(routes.length > 0) {
+  if (routes.length > 0) {
     permissionStore.setSidebarRouters(routes);
   } else {
     appStore.toggleSideBarHide(true);
   }
   return routes;
-}
+};
 
 onMounted(() => {
-  window.addEventListener('resize', setVisibleNumber)
-})
+  window.addEventListener('resize', setVisibleNumber);
+});
 onBeforeUnmount(() => {
-  window.removeEventListener('resize', setVisibleNumber)
-})
+  window.removeEventListener('resize', setVisibleNumber);
+});
 
 onMounted(() => {
-  setVisibleNumber()
-})
+  setVisibleNumber();
+});
 </script>
 
 <style lang="scss">
@@ -168,7 +167,8 @@ onMounted(() => {
   margin: 0 10px !important;
 }
 
-.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
+.topmenu-container.el-menu--horizontal > .el-menu-item.is-active,
+.el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
   border-bottom: 2px solid #{'var(--theme)'} !important;
   color: #303133;
 }
@@ -184,7 +184,9 @@ onMounted(() => {
 }
 
 /* 背景色隐藏 */
-.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
+.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):focus,
+.topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):hover,
+.topmenu-container.el-menu--horizontal > .el-submenu .el-submenu__title:hover {
   background-color: #ffffff !important;
 }
 

+ 56 - 67
src/components/TreeSelect/index.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="el-tree-select">
     <el-select
-      style="width: 100%"
-      v-model="valueId"
       ref="treeSelect"
+      v-model="valueId"
+      style="width: 100%"
       :filterable="true"
       :clearable="true"
-      @clear="clearHandle"
       :filter-method="selectFilterData"
       :placeholder="placeholder"
+      @clear="clearHandle"
     >
       <el-option :value="valueId" :label="valueTitle">
         <el-tree
@@ -29,43 +29,32 @@
 </template>
 
 <script setup lang="ts">
+interface ObjMap {
+  value: string;
+  label: string;
+  children: string;
+}
+interface Props {
+  objMap: ObjMap;
+  accordion: boolean;
+  value: string | number;
+  options: any[];
+  placeholder: string;
+}
 
-const props = defineProps({
-  /* 配置项 */
-  objMap: {
-    type: Object,
-    default: () => {
-      return {
-        value: 'id', // ID字段名
-        label: 'label', // 显示名称
-        children: 'children' // 子级字段名
-      }
-    }
-  },
-  /* 自动收起 */
-  accordion: {
-    type: Boolean,
-    default: () => {
-      return false
-    }
-  },
-  /**当前双向数据绑定的值 */
-  value: {
-    type: [String, Number],
-    default: ''
+const props = withDefaults(defineProps<Props>(), {
+  objMap: () => {
+    return {
+      value: 'id',
+      label: 'label',
+      children: 'children'
+    };
   },
-  /**当前的数据 */
-  options: {
-    type: Array,
-    default: () => []
-  },
-  /**输入框内部的文字 */
-  placeholder: {
-    type: String,
-    default: ''
-  }
-})
-
+  accordion: false,
+  value: '',
+  options: () => [],
+  placeholder: ''
+});
 
 const selectTree = ref<ElTreeSelectInstance>();
 
@@ -74,7 +63,7 @@ const emit = defineEmits(['update:value']);
 const valueId = computed({
   get: () => props.value,
   set: (val) => {
-    emit('update:value', val)
+    emit('update:value', val);
   }
 });
 const valueTitle = ref('');
@@ -83,54 +72,54 @@ const defaultExpandedKey = ref<any[]>([]);
 const initHandle = () => {
   nextTick(() => {
     const selectedValue = valueId.value;
-    if (selectedValue !== null && typeof (selectedValue) !== 'undefined') {
-      const node = selectTree.value?.getNode(selectedValue)
+    if (selectedValue !== null && typeof selectedValue !== 'undefined') {
+      const node = selectTree.value?.getNode(selectedValue);
       if (node) {
-        valueTitle.value = node.data[props.objMap.label]
-        selectTree.value?.setCurrentKey(selectedValue) // 设置默认选中
-        defaultExpandedKey.value = [selectedValue] // 设置默认展开
+        valueTitle.value = node.data[props.objMap.label];
+        selectTree.value?.setCurrentKey(selectedValue); // 设置默认选中
+        defaultExpandedKey.value = [selectedValue]; // 设置默认展开
       }
     } else {
-      clearHandle()
+      clearHandle();
     }
-  })
-}
+  });
+};
 const handleNodeClick = (node: any) => {
-  valueTitle.value = node[props.objMap.label]
+  valueTitle.value = node[props.objMap.label];
   valueId.value = node[props.objMap.value];
   defaultExpandedKey.value = [];
-  selectTree.value?.blur()
-  selectFilterData('')
-}
+  selectTree.value?.blur();
+  selectFilterData('');
+};
 const selectFilterData = (val: any) => {
-  selectTree.value?.filter(val)
-}
+  selectTree.value?.filter(val);
+};
 const filterNode = (value: any, data: any) => {
-  if (!value) return true
-  return data[props.objMap['label']].indexOf(value) !== -1
-}
+  if (!value) return true;
+  return data[props.objMap['label']].indexOf(value) !== -1;
+};
 const clearHandle = () => {
-  valueTitle.value = ''
-  valueId.value = ''
+  valueTitle.value = '';
+  valueId.value = '';
   defaultExpandedKey.value = [];
-  clearSelected()
-}
+  clearSelected();
+};
 const clearSelected = () => {
-  const allNode = document.querySelectorAll('#tree-option .el-tree-node')
-  allNode.forEach((element) => element.classList.remove('is-current'))
-}
+  const allNode = document.querySelectorAll('#tree-option .el-tree-node');
+  allNode.forEach((element) => element.classList.remove('is-current'));
+};
 
 onMounted(() => {
-  initHandle()
-})
+  initHandle();
+});
 
 watch(valueId, () => {
   initHandle();
-})
+});
 </script>
 
 <style lang="scss" scoped>
-@import "@/assets/styles/variables.module.scss";
+@import '@/assets/styles/variables.module.scss';
 
 .el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
   padding: 0;

+ 6 - 6
src/components/iFrame/index.vue

@@ -9,18 +9,18 @@ import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
   src: propTypes.string.isRequired
-})
+});
 
-const height = ref(document.documentElement.clientHeight - 94.5 + "px;")
-const loading = ref(true)
-const url = computed(() => props.src)
+const height = ref(document.documentElement.clientHeight - 94.5 + 'px;');
+const loading = ref(true);
+const url = computed(() => props.src);
 
 onMounted(() => {
   setTimeout(() => {
     loading.value = false;
   }, 300);
   window.onresize = function temp() {
-    height.value = document.documentElement.clientHeight - 94.5 + "px;";
+    height.value = document.documentElement.clientHeight - 94.5 + 'px;';
   };
-})
+});
 </script>

+ 2 - 2
src/directive/permission/index.ts

@@ -9,7 +9,7 @@ export const hasPermi: Directive = {
     // 「其他角色」按钮权限校验
     const { value } = binding;
     if (value && value instanceof Array && value.length > 0) {
-      const hasPermission = permissions.some((permi) => {
+      const hasPermission = permissions.some((permi: string) => {
         return permi === '*:*:*' || value.includes(permi);
       });
       if (!hasPermission) {
@@ -30,7 +30,7 @@ export const hasRoles: Directive = {
     const { value } = binding;
     const { roles } = useUserStore();
     if (value && value instanceof Array && value.length > 0) {
-      const hasRole = roles.some((role) => {
+      const hasRole = roles.some((role: string) => {
         return role === 'admin' || value.includes(role);
       });
       if (!hasRole) {

+ 12 - 9
src/layout/components/AppMain.vue

@@ -3,7 +3,7 @@
     <router-view v-slot="{ Component, route }">
       <transition :enter-active-class="animante" mode="out-in">
         <keep-alive :include="tagsViewStore.cachedViews">
-          <component v-if="!route.meta.link" :is="Component" :key="route.path" />
+          <component :is="Component" v-if="!route.meta.link" :key="route.path" />
         </keep-alive>
       </transition>
     </router-view>
@@ -14,22 +14,25 @@
 <script setup name="AppMain" lang="ts">
 import useTagsViewStore from '@/store/modules/tagsView';
 import useSettingsStore from '@/store/modules/settings';
-import IframeToggle  from './IframeToggle/index.vue'
-import { ComponentInternalInstance } from "vue";
+import IframeToggle from './IframeToggle/index.vue';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const tagsViewStore = useTagsViewStore();
 
 // 随机动画集合
 const animante = ref<string>('');
 const animationEnable = ref(useSettingsStore().animationEnable);
-watch(()=> useSettingsStore().animationEnable, (val) => {
+watch(
+  () => useSettingsStore().animationEnable,
+  (val) => {
     animationEnable.value = val;
     if (val) {
-        animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
+      animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
     } else {
-        animante.value = proxy?.animate.defaultAnimate as string;
+      animante.value = proxy?.animate.defaultAnimate as string;
     }
-}, { immediate: true });
+  },
+  { immediate: true }
+);
 </script>
 
 <style lang="scss" scoped>
@@ -41,7 +44,7 @@ watch(()=> useSettingsStore().animationEnable, (val) => {
   overflow: hidden;
 }
 
-.fixed-header+.app-main {
+.fixed-header + .app-main {
   padding-top: 50px;
 }
 
@@ -51,7 +54,7 @@ watch(()=> useSettingsStore().animationEnable, (val) => {
     min-height: calc(100vh - 84px);
   }
 
-  .fixed-header+.app-main {
+  .fixed-header + .app-main {
     padding-top: 84px;
   }
 }

+ 7 - 5
src/layout/components/IframeToggle/index.vue

@@ -2,16 +2,16 @@
   <transition-group name="fade-transform" mode="out-in">
     <inner-link
       v-for="(item, index) in tagsViewStore.iframeViews"
-      :key="item.path"
-      :iframeId="'iframe' + index"
       v-show="route.path === item.path"
+      :key="item.path"
+      :iframe-id="'iframe' + index"
       :src="iframeUrl(item.meta ? item.meta.link : '', item.query)"
     ></inner-link>
   </transition-group>
 </template>
 
 <script setup lang="ts">
-import InnerLink from "../InnerLink/index.vue";
+import InnerLink from '../InnerLink/index.vue';
 import useTagsViewStore from '@/store/modules/tagsView';
 
 const route = useRoute();
@@ -19,8 +19,10 @@ const tagsViewStore = useTagsViewStore();
 
 function iframeUrl(url: string, query: any) {
   if (Object.keys(query).length > 0) {
-    let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
-    return url + "?" + params;
+    let params = Object.keys(query)
+      .map((key) => key + '=' + query[key])
+      .join('&');
+    return url + '?' + params;
   }
   return url;
 }

+ 5 - 8
src/layout/components/InnerLink/index.vue

@@ -5,14 +5,11 @@
 </template>
 
 <script setup lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
 const props = defineProps({
-    src: {
-        type: String,
-        default: "/"
-    },
-    iframeId: {
-        type: String
-    }
+  src: propTypes.string.def('/'),
+  iframeId: propTypes.string.isRequired
 });
-const height = ref(document.documentElement.clientHeight - 94.5 + "px");
+const height = ref(document.documentElement.clientHeight - 94.5 + 'px');
 </script>

+ 46 - 45
src/layout/components/Navbar.vue

@@ -1,18 +1,18 @@
 <template>
   <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
-    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
-    <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
+    <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
+    <breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
+    <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
 
     <div class="right-menu flex align-center">
       <template v-if="appStore.device !== 'mobile'">
         <el-select
+          v-if="userId === 1 && tenantEnabled"
           v-model="companyName"
           clearable
           filterable
           reserve-keyword
           :placeholder="$t('navbar.selectTenant')"
-          v-if="userId === 1 && tenantEnabled"
           @change="dynamicTenantEvent"
           @clear="dynamicClearEvent"
         >
@@ -63,17 +63,17 @@
         </el-tooltip>
       </template>
       <div class="avatar-container">
-        <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
+        <el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
           <div class="avatar-wrapper">
             <img :src="userStore.avatar" class="user-avatar" />
             <el-icon><caret-bottom /></el-icon>
           </div>
           <template #dropdown>
             <el-dropdown-menu>
-              <router-link to="/user/profile" v-if="!dynamic">
+              <router-link v-if="!dynamic" to="/user/profile">
                 <el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
               </router-link>
-              <el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
+              <el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
                 <span>{{ $t('navbar.layoutSetting') }}</span>
               </el-dropdown-item>
               <el-dropdown-item divided command="logout">
@@ -92,10 +92,9 @@ import SearchMenu from './TopBar/search.vue';
 import useAppStore from '@/store/modules/app';
 import useUserStore from '@/store/modules/user';
 import useSettingsStore from '@/store/modules/settings';
-import { getTenantList } from "@/api/login";
-import { dynamicClear, dynamicTenant } from "@/api/system/tenant";
-import { ComponentInternalInstance } from "vue";
-import { TenantVO } from "@/api/types";
+import { getTenantList } from '@/api/login';
+import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
+import { TenantVO } from '@/api/types';
 import notice from './notice/index.vue';
 import useNoticeStore from '@/store/modules/notice';
 
@@ -119,7 +118,7 @@ const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
 
 const openSearchMenu = () => {
   searchMenuRef.value?.openSearch();
-}
+};
 
 // 动态切换
 const dynamicTenantEvent = async (tenantId: string) => {
@@ -129,14 +128,14 @@ const dynamicTenantEvent = async (tenantId: string) => {
     proxy?.$tab.closeAllPage();
     proxy?.$router.push('/');
   }
-}
+};
 
 const dynamicClearEvent = async () => {
   await dynamicClear();
   dynamic.value = false;
   proxy?.$tab.closeAllPage();
   proxy?.$router.push('/');
-}
+};
 
 /** 租户列表 */
 const initTenantList = async () => {
@@ -145,56 +144,58 @@ const initTenantList = async () => {
   if (tenantEnabled.value) {
     tenantList.value = data.voList;
   }
-}
+};
 
 defineExpose({
-  initTenantList,
-})
+  initTenantList
+});
 
 const toggleSideBar = () => {
   appStore.toggleSideBar(false);
-}
+};
 
 const logout = async () => {
-    await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
-      type: 'warning'
-    })
-    await userStore.logout()
-    location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
-}
+  await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  });
+  await userStore.logout();
+  location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
+};
 
-const emits = defineEmits(['setLayout'])
+const emits = defineEmits(['setLayout']);
 const setLayout = () => {
-    emits('setLayout');
-}
+  emits('setLayout');
+};
 // 定义Command方法对象 通过key直接调用方法
-const commandMap: {[key: string]: any} = {
-    setLayout,
-    logout
+const commandMap: { [key: string]: any } = {
+  setLayout,
+  logout
 };
 const handleCommand = (command: string) => {
-    // 判断是否存在该方法
-    if (commandMap[command]) {
-        commandMap[command]();
-    }
-}
-
+  // 判断是否存在该方法
+  if (commandMap[command]) {
+    commandMap[command]();
+  }
+};
 //用深度监听 消息
-watch(() => noticeStore.state.value.notices, (newVal, oldVal) => {
-  newNotice.value = newVal.filter((item: any) => !item.read).length;
-}, { deep: true });
+watch(
+  () => noticeStore.state.value.notices,
+  (newVal) => {
+    newNotice.value = newVal.filter((item: any) => !item.read).length;
+  },
+  { deep: true }
+);
 </script>
 
 <style lang="scss" scoped>
-
 :deep(.el-select .el-input__wrapper) {
-  height:30px;
+  height: 30px;
 }
 
-:deep(.el-badge__content.is-fixed){
-    top: 12px;
+:deep(.el-badge__content.is-fixed) {
+  top: 12px;
 }
 
 .flex {

+ 88 - 88
src/layout/components/Settings/index.vue

@@ -1,11 +1,11 @@
 <template>
-  <el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
+  <el-drawer v-model="showSettings" :with-header="false" direction="rtl" size="300px" close-on-click-modal>
     <h3 class="drawer-title">主题风格设置</h3>
 
     <div class="setting-drawer-block-checbox">
       <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.DARK)">
         <img src="@/assets/images/dark.svg" alt="dark" />
-        <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+        <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block">
           <i aria-label="图标: check" class="anticon anticon-check">
             <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
               <path
@@ -17,7 +17,7 @@
       </div>
       <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.LIGHT)">
         <img src="@/assets/images/light.svg" alt="light" />
-        <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+        <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block">
           <i aria-label="图标: check" class="anticon anticon-check">
             <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class>
               <path
@@ -37,7 +37,7 @@
     <div class="drawer-item">
       <span>深色模式</span>
       <span class="comp-style">
-        <el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" />
+        <el-switch v-model="isDark" class="drawer-switch" @change="toggleDark" />
       </span>
     </div>
 
@@ -88,126 +88,126 @@
 </template>
 
 <script setup lang="ts">
-import { useDynamicTitle } from '@/utils/dynamicTitle'
-import useAppStore from '@/store/modules/app'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
-import { handleThemeStyle } from '@/utils/theme'
-import { ComponentInternalInstance } from "vue";
-import { SettingTypeEnum } from "@/enums/SettingTypeEnum";
-import { SideThemeEnum } from "@/enums/SideThemeEnum";
+import { useDynamicTitle } from '@/utils/dynamicTitle';
+import useAppStore from '@/store/modules/app';
+import useSettingsStore from '@/store/modules/settings';
+import usePermissionStore from '@/store/modules/permission';
+import { handleThemeStyle } from '@/utils/theme';
+import { SettingTypeEnum } from '@/enums/SettingTypeEnum';
+import { SideThemeEnum } from '@/enums/SideThemeEnum';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const appStore = useAppStore()
-const settingsStore = useSettingsStore()
-const permissionStore = usePermissionStore()
-
+const appStore = useAppStore();
+const settingsStore = useSettingsStore();
+const permissionStore = usePermissionStore();
 
 const showSettings = ref(false);
 const theme = ref(settingsStore.theme);
 const sideTheme = ref(settingsStore.sideTheme);
 const storeSettings = computed(() => settingsStore);
-const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
+const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']);
 
 // 是否暗黑模式
 const isDark = useDark({
   storageKey: 'useDarkKey',
   valueDark: 'dark',
-  valueLight: 'light',
+  valueLight: 'light'
 });
-watch(isDark, ()=> {
+watch(isDark, () => {
   if (isDark.value) {
-    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
+    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK });
   } else {
-    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value })
+    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value });
   }
-})
+});
 const toggleDark = () => useToggle(isDark);
 
 /** 是否需要topNav */
 const topNav = computed({
-    get: () => storeSettings.value.topNav,
-    set: (val) => {
-        settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val })
-        if (!val) {
-            appStore.toggleSideBarHide(false);
-            permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
-        }
+  get: () => storeSettings.value.topNav,
+  set: (val) => {
+    settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val });
+    if (!val) {
+      appStore.toggleSideBarHide(false);
+      permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
     }
-})
+  }
+});
 /** 是否需要tagview */
 const tagsView = computed({
-    get: () => storeSettings.value.tagsView,
-    set: (val) => {
-        settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val })
-    }
-})
+  get: () => storeSettings.value.tagsView,
+  set: (val) => {
+    settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val });
+  }
+});
 /**是否需要固定头部 */
 const fixedHeader = computed({
-    get: () => storeSettings.value.fixedHeader,
-    set: (val) => {
-        settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val })
-    }
-})
+  get: () => storeSettings.value.fixedHeader,
+  set: (val) => {
+    settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val });
+  }
+});
 /**是否需要侧边栏的logo */
 const sidebarLogo = computed({
-    get: () => storeSettings.value.sidebarLogo,
-    set: (val) => {
-        settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val })
-    }
-})
+  get: () => storeSettings.value.sidebarLogo,
+  set: (val) => {
+    settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val });
+  }
+});
 /**是否需要侧边栏的动态网页的title */
 const dynamicTitle = computed({
-    get: () => storeSettings.value.dynamicTitle,
-    set: (val) => {
-        settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val })
-        // 动态设置网页标题
-        useDynamicTitle()
-    }
-})
+  get: () => storeSettings.value.dynamicTitle,
+  set: (val) => {
+    settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val });
+    // 动态设置网页标题
+    useDynamicTitle();
+  }
+});
 
-const themeChange = (val: string | null) => {
-    settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val })
-    theme.value = val;
-    if (val) {
-        handleThemeStyle(val);
-    }
-}
+const themeChange = (val: string) => {
+  settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val });
+  theme.value = val;
+  if (val) {
+    handleThemeStyle(val);
+  }
+};
 const handleTheme = (val: string) => {
-    sideTheme.value = val;
-    if (isDark.value && val === SideThemeEnum.LIGHT) {
-      // 暗黑模式颜色不变
-      settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
-      return
-    }
-    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
-}
+  sideTheme.value = val;
+  if (isDark.value && val === SideThemeEnum.LIGHT) {
+    // 暗黑模式颜色不变
+    settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK });
+    return;
+  }
+  settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val });
+};
 const saveSetting = () => {
-    proxy?.$modal.loading("正在保存到本地,请稍候...");
-    let layoutSetting = {
-        "topNav": storeSettings.value.topNav,
-        "tagsView": storeSettings.value.tagsView,
-        "fixedHeader": storeSettings.value.fixedHeader,
-        "sidebarLogo": storeSettings.value.sidebarLogo,
-        "dynamicTitle": storeSettings.value.dynamicTitle,
-        "sideTheme": storeSettings.value.sideTheme,
-        "theme": storeSettings.value.theme
-    };
-    localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
-    setTimeout(() => {proxy?.$modal.closeLoading()}, 1000)
-}
+  proxy?.$modal.loading('正在保存到本地,请稍候...');
+  let layoutSetting = {
+    topNav: storeSettings.value.topNav,
+    tagsView: storeSettings.value.tagsView,
+    fixedHeader: storeSettings.value.fixedHeader,
+    sidebarLogo: storeSettings.value.sidebarLogo,
+    dynamicTitle: storeSettings.value.dynamicTitle,
+    sideTheme: storeSettings.value.sideTheme,
+    theme: storeSettings.value.theme
+  };
+  localStorage.setItem('layout-setting', JSON.stringify(layoutSetting));
+  setTimeout(() => {
+    proxy?.$modal.closeLoading();
+  }, 1000);
+};
 const resetSetting = () => {
-    proxy?.$modal.loading("正在清除设置缓存并刷新,请稍候...");
-    localStorage.removeItem("layout-setting")
-    setTimeout("window.location.reload()", 1000)
-}
+  proxy?.$modal.loading('正在清除设置缓存并刷新,请稍候...');
+  localStorage.removeItem('layout-setting');
+  setTimeout('window.location.reload()', 1000);
+};
 const openSetting = () => {
-    showSettings.value = true;
-}
+  showSettings.value = true;
+};
 
 defineExpose({
-    openSetting,
-})
+  openSetting
+});
 </script>
 
 <style lang="scss" scoped>

+ 22 - 22
src/layout/components/Sidebar/Link.vue

@@ -5,36 +5,36 @@
 </template>
 
 <script setup lang="ts">
-import { isExternal } from '@/utils/validate'
+import { isExternal } from '@/utils/validate';
 
 const props = defineProps({
-    to: {
-        type: [String, Object],
-        required: true
-    }
-})
+  to: {
+    type: [String, Object],
+    required: true
+  }
+});
 
 const isExt = computed(() => {
-    return isExternal(props.to as string)
-})
+  return isExternal(props.to as string);
+});
 
 const type = computed(() => {
-    if (isExt.value) {
-        return 'a'
-    }
-    return 'router-link'
-})
+  if (isExt.value) {
+    return 'a';
+  }
+  return 'router-link';
+});
 
 function linkProps() {
-    if (isExt.value) {
-        return {
-            href: props.to,
-            target: '_blank',
-            rel: 'noopener'
-        }
-    }
+  if (isExt.value) {
     return {
-        to: props.to
-    }
+      href: props.to,
+      target: '_blank',
+      rel: 'noopener'
+    };
+  }
+  return {
+    to: props.to
+  };
 }
 </script>

+ 15 - 11
src/layout/components/Sidebar/Logo.vue

@@ -1,7 +1,7 @@
 <template>
   <div
     class="sidebar-logo-container"
-    :class="{ 'collapse': collapse }"
+    :class="{ collapse: collapse }"
     :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }"
   >
     <transition :enter-active-class="proxy?.animate.logoAnimate.enter" mode="out-in">
@@ -22,18 +22,17 @@
 </template>
 
 <script setup lang="ts">
-import variables from '@/assets/styles/variables.module.scss'
-import logo from '@/assets/logo/logo.png'
-import useSettingsStore from '@/store/modules/settings'
-import { ComponentInternalInstance } from "vue";
+import variables from '@/assets/styles/variables.module.scss';
+import logo from '@/assets/logo/logo.png';
+import useSettingsStore from '@/store/modules/settings';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 defineProps({
-    collapse: {
-        type: Boolean,
-        required: true
-    }
-})
+  collapse: {
+    type: Boolean,
+    required: true
+  }
+});
 
 const title = ref('RuoYi-Vue-Plus');
 const settingsStore = useSettingsStore();
@@ -77,7 +76,12 @@ const sideTheme = computed(() => settingsStore.sideTheme);
       font-weight: 600;
       line-height: 50px;
       font-size: 14px;
-      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+      font-family:
+        Avenir,
+        Helvetica Neue,
+        Arial,
+        Helvetica,
+        sans-serif;
       vertical-align: middle;
     }
   }

+ 59 - 63
src/layout/components/Sidebar/SidebarItem.vue

@@ -13,7 +13,7 @@
 
     <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
       <template v-if="item.meta" #title>
-        <svg-icon :icon-class="item.meta ? item.meta.icon : '' " />
+        <svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
         <span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
       </template>
 
@@ -30,79 +30,75 @@
 </template>
 
 <script setup lang="ts">
-import { isExternal } from '@/utils/validate'
-import AppLink from './Link.vue'
-import { getNormalPath } from '@/utils/ruoyi'
-import { RouteOption } from "vue-router";
+import { isExternal } from '@/utils/validate';
+import AppLink from './Link.vue';
+import { getNormalPath } from '@/utils/ruoyi';
+import { RouteRecordRaw } from 'vue-router';
 
 const props = defineProps({
-    // route object
-    item: {
-        type: Object as PropType<RouteOption>,
-        required: true
-    },
-    isNest: {
-        type: Boolean,
-        default: false
-    },
-    basePath: {
-        type: String,
-        default: ''
-    }
-})
+  // route object
+  item: {
+    type: Object as PropType<RouteRecordRaw>,
+    required: true
+  },
+  isNest: {
+    type: Boolean,
+    default: false
+  },
+  basePath: {
+    type: String,
+    default: ''
+  }
+});
 
 const onlyOneChild = ref<any>({});
 
-const hasOneShowingChild = (parent: RouteOption, children?:RouteOption[]) => {
-    if (!children) {
-        children = [];
+const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
+  if (!children) {
+    children = [];
+  }
+  const showingChildren = children.filter((item) => {
+    if (item.hidden) {
+      return false;
+    } else {
+      // Temp set(will be used if only has one showing child)
+      onlyOneChild.value = item;
+      return true;
     }
-    const showingChildren = children.filter(item => {
-        if (item.hidden) {
-            return false
-        } else {
-            // Temp set(will be used if only has one showing child)
-            onlyOneChild.value = item
-            return true
-        }
-    })
+  });
 
-    // When there is only one child router, the child router is displayed by default
-    if (showingChildren.length === 1) {
-        return true
-    }
+  // When there is only one child router, the child router is displayed by default
+  if (showingChildren.length === 1) {
+    return true;
+  }
 
-    // Show parent if there are no child router to display
-    if (showingChildren.length === 0) {
-        onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
-        if (parent.name === '2222') {
-          console.log(onlyOneChild.value)
-        }
-        return true
-    }
+  // Show parent if there are no child router to display
+  if (showingChildren.length === 0) {
+    onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
+    return true;
+  }
 
-
-    return false
+  return false;
 };
 
-const resolvePath = (routePath:string, routeQuery?:string): any => {
-    if (isExternal(routePath)) {
-        return routePath
-    }
-    if (isExternal(props.basePath)) {
-        return props.basePath
-    }
-    if (routeQuery) {
-        let query = JSON.parse(routeQuery);
-        return { path: getNormalPath(props.basePath + '/' + routePath), query: query }
-    }
-    return getNormalPath(props.basePath + '/' + routePath)
-}
+const resolvePath = (routePath: string, routeQuery?: string): any => {
+  if (isExternal(routePath)) {
+    return routePath;
+  }
+  if (isExternal(props.basePath)) {
+    return props.basePath;
+  }
+  if (routeQuery) {
+    let query = JSON.parse(routeQuery);
+    return { path: getNormalPath(props.basePath + '/' + routePath), query: query };
+  }
+  return getNormalPath(props.basePath + '/' + routePath);
+};
 
 const hasTitle = (title: string | undefined): string => {
-    if(!title || title.length <= 5) {
-        return "";
-    }
-    return title;
-}
+  if (!title || title.length <= 5) {
+    return '';
+  }
+  return title;
+};
 </script>

+ 20 - 21
src/layout/components/Sidebar/index.vue

@@ -21,35 +21,34 @@
 </template>
 
 <script setup lang="ts">
-import Logo from './Logo.vue'
-import SidebarItem from './SidebarItem.vue'
-import variables from '@/assets/styles/variables.module.scss'
-import useAppStore from '@/store/modules/app'
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
-import { RouteOption } from "vue-router";
+import Logo from './Logo.vue';
+import SidebarItem from './SidebarItem.vue';
+import variables from '@/assets/styles/variables.module.scss';
+import useAppStore from '@/store/modules/app';
+import useSettingsStore from '@/store/modules/settings';
+import usePermissionStore from '@/store/modules/permission';
+import { RouteRecordRaw } from 'vue-router';
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const route = useRoute();
-const appStore = useAppStore()
-const settingsStore = useSettingsStore()
-const permissionStore = usePermissionStore()
-
-const sidebarRouters =  computed<RouteOption[]>(() => permissionStore.sidebarRouters);
+const appStore = useAppStore();
+const settingsStore = useSettingsStore();
+const permissionStore = usePermissionStore();
+const sidebarRouters = computed<RouteRecordRaw[]>(() => permissionStore.sidebarRouters);
 const showLogo = computed(() => settingsStore.sidebarLogo);
 const sideTheme = computed(() => settingsStore.sideTheme);
 const theme = computed(() => settingsStore.theme);
 const isCollapse = computed(() => !appStore.sidebar.opened);
 
 const activeMenu = computed(() => {
-    const { meta, path } = route;
-    // if set path, the sidebar will highlight the path you set
-    if (meta.activeMenu) {
-        return meta.activeMenu;
-    }
-    return path;
-})
+  const { meta, path } = route;
+  // if set path, the sidebar will highlight the path you set
+  if (meta.activeMenu) {
+    return meta.activeMenu;
+  }
+  return path;
+});
 
-const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground);
-const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor);
+const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground));
+const textColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor));
 </script>

+ 1 - 4
src/layout/components/SocialCallback/index.vue

@@ -10,7 +10,6 @@ import { LoginData } from '@/api/types';
 const route = useRoute();
 const loading = ref(true);
 
-
 /**
  * 接收Route传递的参数
  * @param {Object} route.query.
@@ -18,8 +17,7 @@ const loading = ref(true);
 const code = route.query.code as string;
 const state = route.query.state as string;
 const source = route.query.source as string;
-const tenantId = localStorage.getItem("tenantId") ? localStorage.getItem("tenantId") as string : '000000';
-
+const tenantId = localStorage.getItem('tenantId') ? (localStorage.getItem('tenantId') as string) : '000000';
 
 const processResponse = async (res: any) => {
   if (res.code !== 200) {
@@ -52,7 +50,6 @@ const callbackByCode = async (data: LoginData) => {
 };
 
 const loginByCode = async (data: LoginData) => {
-  console.log(2)
   try {
     const res = await login(data);
     await processResponse(res);

+ 55 - 55
src/layout/components/TagsView/ScrollPane.vue

@@ -5,84 +5,84 @@
 </template>
 
 <script setup lang="ts">
-import useTagsViewStore from '@/store/modules/tagsView'
-import { TagView } from 'vue-router'
+import useTagsViewStore from '@/store/modules/tagsView';
+import { TagView } from 'vue-router';
 const tagAndTagSpacing = ref(4);
 
-const scrollContainerRef = ref<ElScrollbarInstance>()
+const scrollContainerRef = ref<ElScrollbarInstance>();
 const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any);
 
 onMounted(() => {
-    scrollWrapper.value?.addEventListener('scroll', emitScroll, true)
-})
+  scrollWrapper.value?.addEventListener('scroll', emitScroll, true);
+});
 onBeforeUnmount(() => {
-    scrollWrapper.value?.removeEventListener('scroll', emitScroll)
-})
+  scrollWrapper.value?.removeEventListener('scroll', emitScroll);
+});
 
 const handleScroll = (e: WheelEvent) => {
-    const eventDelta = (e as any).wheelDelta || - e.deltaY * 40
-    const $scrollWrapper = scrollWrapper.value;
-    $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
-}
-const emits = defineEmits(['scroll'])
+  const eventDelta = (e as any).wheelDelta || -e.deltaY * 40;
+  const $scrollWrapper = scrollWrapper.value;
+  $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4;
+};
+const emits = defineEmits(['scroll']);
 const emitScroll = () => {
-    emits('scroll')
-}
+  emits('scroll');
+};
 
-const tagsViewStore = useTagsViewStore()
+const tagsViewStore = useTagsViewStore();
 const visitedViews = computed(() => tagsViewStore.visitedViews);
 
 const moveToTarget = (currentTag: TagView) => {
-    const $container = scrollContainerRef.value?.$el
-    const $containerWidth = $container.offsetWidth
-    const $scrollWrapper = scrollWrapper.value;
+  const $container = scrollContainerRef.value?.$el;
+  const $containerWidth = $container.offsetWidth;
+  const $scrollWrapper = scrollWrapper.value;
 
-    let firstTag = null
-    let lastTag = null
+  let firstTag = null;
+  let lastTag = null;
 
-    // find first tag and last tag
-    if (visitedViews.value.length > 0) {
-        firstTag = visitedViews.value[0]
-        lastTag = visitedViews.value[visitedViews.value.length - 1]
-    }
+  // find first tag and last tag
+  if (visitedViews.value.length > 0) {
+    firstTag = visitedViews.value[0];
+    lastTag = visitedViews.value[visitedViews.value.length - 1];
+  }
 
-    if (firstTag === currentTag) {
-        $scrollWrapper.scrollLeft = 0
-    } else if (lastTag === currentTag) {
-        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
-    } else {
-        const tagListDom: any = document.getElementsByClassName('tags-view-item');
-        const currentIndex = visitedViews.value.findIndex(item => item === currentTag)
-        let prevTag = null
-        let nextTag = null
+  if (firstTag === currentTag) {
+    $scrollWrapper.scrollLeft = 0;
+  } else if (lastTag === currentTag) {
+    $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth;
+  } else {
+    const tagListDom: any = document.getElementsByClassName('tags-view-item');
+    const currentIndex = visitedViews.value.findIndex((item) => item === currentTag);
+    let prevTag = null;
+    let nextTag = null;
 
-        for (const k in tagListDom) {
-            if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
-                if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
-                    prevTag = tagListDom[k];
-                }
-                if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
-                    nextTag = tagListDom[k];
-                }
-            }
+    for (const k in tagListDom) {
+      if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
+        if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
+          prevTag = tagListDom[k];
+        }
+        if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
+          nextTag = tagListDom[k];
         }
+      }
+    }
 
-        // the tag's offsetLeft after of nextTag
-        const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value
+    // the tag's offsetLeft after of nextTag
+    const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value;
 
-        // the tag's offsetLeft before of prevTag
-        const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value
-        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
-            $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
-        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
-            $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
-        }
+    // the tag's offsetLeft before of prevTag
+    const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value;
+    if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+      $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth;
+    } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+      $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft;
     }
-}
+  }
+};
 
 defineExpose({
-    moveToTarget,
-})
+  moveToTarget
+});
 </script>
 
 <style lang="scss" scoped>

+ 169 - 168
src/layout/components/TagsView/index.vue

@@ -14,36 +14,35 @@
       >
         {{ tag.title }}
         <span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)">
-          <close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" />
+          <close class="el-icon-close" style="width: 1em; height: 1em; vertical-align: middle" />
         </span>
       </router-link>
     </scroll-pane>
     <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em;" /> 刷新页面</li>
-      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em;" /> 关闭当前</li>
-      <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em;" /> 关闭其他</li>
-      <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em;" /> 关闭左侧</li>
-      <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em;" /> 关闭右侧</li>
-      <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em;" /> 全部关闭</li>
+      <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em" /> 刷新页面</li>
+      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em" /> 关闭当前</li>
+      <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em" /> 关闭其他</li>
+      <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em" /> 关闭左侧</li>
+      <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em" /> 关闭右侧</li>
+      <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em" /> 全部关闭</li>
     </ul>
   </div>
 </template>
 
 <script setup lang="ts">
-import ScrollPane from './ScrollPane.vue'
-import { getNormalPath } from '@/utils/ruoyi'
-import useTagsViewStore from "@/store/modules/tagsView";
-import useSettingsStore from '@/store/modules/settings'
-import usePermissionStore from '@/store/modules/permission'
-import { ComponentInternalInstance } from "vue";
-import { RouteOption, TagView, RouteLocationRaw } from "vue-router";
+import ScrollPane from './ScrollPane.vue';
+import { getNormalPath } from '@/utils/ruoyi';
+import useTagsViewStore from '@/store/modules/tagsView';
+import useSettingsStore from '@/store/modules/settings';
+import usePermissionStore from '@/store/modules/permission';
+import { RouteRecordRaw, TagView } from 'vue-router';
 
 const visible = ref(false);
 const top = ref(0);
 const left = ref(0);
 const selectedTag = ref<TagView>({});
 const affixTags = ref<TagView[]>([]);
-const scrollPaneRef = ref(ScrollPane);
+const scrollPaneRef = ref<InstanceType<typeof ScrollPane>>();
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const route = useRoute();
@@ -54,186 +53,186 @@ const routes = computed(() => usePermissionStore().routes);
 const theme = computed(() => useSettingsStore().theme);
 
 watch(route, () => {
-    addTags();
-    moveToCurrentTag();
-})
+  addTags();
+  moveToCurrentTag();
+});
 watch(visible, (value) => {
-    if (value) {
-        document.body.addEventListener('click', closeMenu);
-    } else {
-        document.body.removeEventListener('click', closeMenu);
-    }
-})
+  if (value) {
+    document.body.addEventListener('click', closeMenu);
+  } else {
+    document.body.removeEventListener('click', closeMenu);
+  }
+});
 
 const isActive = (r: TagView): boolean => {
-    return r.path === route.path;
-}
+  return r.path === route.path;
+};
 const activeStyle = (tag: TagView) => {
-    if (!isActive(tag)) return {};
-    return {
-        "background-color": theme.value,
-        "border-color": theme.value
-    };
-}
+  if (!isActive(tag)) return {};
+  return {
+    'background-color': theme.value,
+    'border-color': theme.value
+  };
+};
 const isAffix = (tag: TagView) => {
-    return tag.meta && tag.meta.affix;
-}
+  return tag.meta && tag.meta.affix;
+};
 const isFirstView = () => {
-    try {
-        return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath;
-    } catch (err) {
-        return false;
-    }
-}
+  try {
+    return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath;
+  } catch (err) {
+    return false;
+  }
+};
 const isLastView = () => {
-    try {
-        return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath;
-    } catch (err) {
-        return false;
+  try {
+    return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath;
+  } catch (err) {
+    return false;
+  }
+};
+const filterAffixTags = (routes: RouteRecordRaw[], basePath = '') => {
+  let tags: TagView[] = [];
+
+  routes.forEach((route) => {
+    if (route.meta && route.meta.affix) {
+      const tagPath = getNormalPath(basePath + '/' + route.path);
+      tags.push({
+        fullPath: tagPath,
+        path: tagPath,
+        name: route.name as string,
+        meta: { ...route.meta }
+      });
     }
-}
-const filterAffixTags = (routes:RouteOption [], basePath = '') => {
-    let tags:TagView[] = []
-    routes.forEach(route => {
-        if (route.meta && route.meta.affix) {
-            const tagPath = getNormalPath(basePath + '/' + route.path);
-            tags.push({
-                fullPath: tagPath,
-                path: tagPath,
-                name: route.name,
-                meta: { ...route.meta }
-            })
-        }
-        if (route.children) {
-            const tempTags = filterAffixTags(route.children, route.path);
-            if (tempTags.length >= 1) {
-                tags = [...tags, ...tempTags];
-            }
-        }
-    })
-    return tags
-}
+    if (route.children) {
+      const tempTags = filterAffixTags(route.children, route.path);
+      if (tempTags.length >= 1) {
+        tags = [...tags, ...tempTags];
+      }
+    }
+  });
+  return tags;
+};
 const initTags = () => {
-    const res = filterAffixTags(routes.value);
-    affixTags.value = res;
-    for (const tag of res) {
-        // Must have tag name
-        if (tag.name) {
-            useTagsViewStore().addVisitedView(tag);
-        }
+  const res = filterAffixTags(routes.value as any);
+  affixTags.value = res;
+  for (const tag of res) {
+    // Must have tag name
+    if (tag.name) {
+      useTagsViewStore().addVisitedView(tag);
     }
-}
+  }
+};
 const addTags = () => {
-    const { name } = route;
-    if(route.query.title) {
-        route.meta.title = route.query.title;
-    }
-    if (name) {
-        useTagsViewStore().addView(route);
-        if (route.meta.link) {
-            useTagsViewStore().addIframeView(route);
-        }
+  const { name } = route;
+  if (route.query.title) {
+    route.meta.title = route.query.title as string;
+  }
+  if (name) {
+    useTagsViewStore().addView(route as any);
+    if (route.meta.link) {
+      useTagsViewStore().addIframeView(route as any);
     }
-    return false
-}
+  }
+  return false;
+};
 const moveToCurrentTag = () => {
-    nextTick(() => {
-        for (const r of visitedViews.value) {
-            if (r.path === route.path) {
-                scrollPaneRef.value.moveToTarget(r);
-                // when query is different then update
-                if (r.fullPath !== route.fullPath) {
-                    useTagsViewStore().updateVisitedView(route);
-                }
-            }
+  nextTick(() => {
+    for (const r of visitedViews.value) {
+      if (r.path === route.path) {
+        scrollPaneRef.value?.moveToTarget(r);
+        // when query is different then update
+        if (r.fullPath !== route.fullPath) {
+          useTagsViewStore().updateVisitedView(route);
         }
-    })
-}
-const refreshSelectedTag = (view: TagView) => {
-    proxy?.$tab.refreshPage(view);
-    if (route.meta.link) {
-        useTagsViewStore().delIframeView(route);
+      }
     }
-}
+  });
+};
+const refreshSelectedTag = (view: TagView) => {
+  proxy?.$tab.refreshPage(view);
+  if (route.meta.link) {
+    useTagsViewStore().delIframeView(route as any);
+  }
+};
 const closeSelectedTag = (view: TagView) => {
-    proxy?.$tab.closePage(view).then(({ visitedViews }: any) => {
-        if (isActive(view)) {
-            toLastView(visitedViews, view);
-        }
-    })
-}
+  proxy?.$tab.closePage(view).then(({ visitedViews }: any) => {
+    if (isActive(view)) {
+      toLastView(visitedViews, view);
+    }
+  });
+};
 const closeRightTags = () => {
-    proxy?.$tab.closeRightPage(selectedTag.value).then(visitedViews => {
-        if (!visitedViews.find(i => i.fullPath === route.fullPath)) {
-            toLastView(visitedViews);
-        }
-    })
-}
+  proxy?.$tab.closeRightPage(selectedTag.value).then((visitedViews) => {
+    if (!visitedViews.find((i) => i.fullPath === route.fullPath)) {
+      toLastView(visitedViews);
+    }
+  });
+};
 const closeLeftTags = () => {
-    proxy?.$tab.closeLeftPage(selectedTag.value).then(visitedViews => {
-        if (!visitedViews.find(i => i.fullPath === route.fullPath)) {
-            toLastView(visitedViews);
-        }
-    })
-}
+  proxy?.$tab.closeLeftPage(selectedTag.value).then((visitedViews) => {
+    if (!visitedViews.find((i: TagView) => i.fullPath === route.fullPath)) {
+      toLastView(visitedViews);
+    }
+  });
+};
 const closeOthersTags = () => {
-    router.push(selectedTag.value as RouteLocationRaw).catch(() => { });
-    proxy?.$tab.closeOtherPage(selectedTag.value).then(() => {
-        moveToCurrentTag();
-    })
-}
+  router.push(selectedTag.value).catch(() => {});
+  proxy?.$tab.closeOtherPage(selectedTag.value).then(() => {
+    moveToCurrentTag();
+  });
+};
 const closeAllTags = (view: TagView) => {
-    proxy?.$tab.closeAllPage().then(({ visitedViews }) => {
-        if (affixTags.value.some(tag => tag.path === route.path)) {
-            return;
-        }
-        toLastView(visitedViews, view);
-    })
-}
-const toLastView = (visitedViews:TagView[], view?: TagView) => {
-    const latestView = visitedViews.slice(-1)[0];
-    if (latestView) {
-        router.push(latestView.fullPath as string);
+  proxy?.$tab.closeAllPage().then(({ visitedViews }) => {
+    if (affixTags.value.some((tag) => tag.path === route.path)) {
+      return;
+    }
+    toLastView(visitedViews, view);
+  });
+};
+const toLastView = (visitedViews: TagView[], view?: TagView) => {
+  const latestView = visitedViews.slice(-1)[0];
+  if (latestView) {
+    router.push(latestView.fullPath as string);
+  } else {
+    // now the default is to redirect to the home page if there is no tags-view,
+    // you can adjust it according to your needs.
+    if (view?.name === 'Dashboard') {
+      // to reload home page
+      router.replace({ path: '/redirect' + view?.fullPath });
     } else {
-        // now the default is to redirect to the home page if there is no tags-view,
-        // you can adjust it according to your needs.
-        if (view?.name === 'Dashboard') {
-            // to reload home page
-            router.replace({ path: '/redirect' + view?.fullPath });
-        } else {
-            router.push('/');
-        }
+      router.push('/');
     }
-}
+  }
+};
 const openMenu = (tag: TagView, e: MouseEvent) => {
-    const menuMinWidth = 105;
-    const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left
-    const offsetWidth = proxy?.$el.offsetWidth; // container width
-    const maxLeft = offsetWidth - menuMinWidth; // left boundary
-    const l = e.clientX - offsetLeft + 15; // 15: margin right
+  const menuMinWidth = 105;
+  const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left
+  const offsetWidth = proxy?.$el.offsetWidth; // container width
+  const maxLeft = offsetWidth - menuMinWidth; // left boundary
+  const l = e.clientX - offsetLeft + 15; // 15: margin right
 
-    if (l > maxLeft) {
-        left.value = maxLeft;
-    } else {
-        left.value = l;
-    }
+  if (l > maxLeft) {
+    left.value = maxLeft;
+  } else {
+    left.value = l;
+  }
 
-    top.value = e.clientY
-    visible.value = true;
-    selectedTag.value = tag;
-}
+  top.value = e.clientY;
+  visible.value = true;
+  selectedTag.value = tag;
+};
 const closeMenu = () => {
-    visible.value = false;
-}
+  visible.value = false;
+};
 const handleScroll = () => {
-    closeMenu();
-}
-
+  closeMenu();
+};
 
 onMounted(() => {
-    initTags();
-    addTags();
-})
+  initTags();
+  addTags();
+});
 </script>
 
 <style lang="scss" scoped>
@@ -242,7 +241,9 @@ onMounted(() => {
   width: 100%;
   background-color: var(--el-bg-color);
   border: 1px solid var(--el-border-color-light);
-  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
+  box-shadow:
+    0 1px 3px 0 rgba(0, 0, 0, 0.12),
+    0 0 3px 0 rgba(0, 0, 0, 0.04);
   .tags-view-wrapper {
     .tags-view-item {
       display: inline-block;
@@ -271,7 +272,7 @@ onMounted(() => {
         color: #fff;
         border-color: #42b983;
         &::before {
-          content: "";
+          content: '';
           background: #fff;
           display: inline-block;
           width: 8px;

+ 93 - 94
src/layout/components/TopBar/search.vue

@@ -3,12 +3,12 @@
     <el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
       <template #footer>
         <el-autocomplete
+          ref="layoutMenuAutocompleteRef"
           v-model="state.menuQuery"
           :fetch-suggestions="menuSearch"
           placeholder="搜索"
-          ref="layoutMenuAutocompleteRef"
-          @select="onHandleSelect"
           :fit-input-width="true"
+          @select="onHandleSelect"
         >
           <template #prefix>
             <svg-icon class-name="search-icon" icon-class="search" />
@@ -29,130 +29,129 @@
 import { getNormalPath } from '@/utils/ruoyi';
 import { isHttp } from '@/utils/validate';
 import usePermissionStore from '@/store/modules/permission';
-import { RouteOption } from 'vue-router';
+import { RouteRecordRaw } from 'vue-router';
 type Router = Array<{
-	path: string;
-	icon: string;
-	title: string[];
-}>
+  path: string;
+  icon: string;
+  title: string[];
+}>;
 type SearchState<T = any> = {
-	isShowSearch: boolean;
-	menuQuery: string;
-	menuList: T[];
+  isShowSearch: boolean;
+  menuQuery: string;
+  menuList: T[];
 };
 // 定义变量内容
 const layoutMenuAutocompleteRef = ref();
 const router = useRouter();
 const routes = computed(() => usePermissionStore().routes);
 const state = reactive<SearchState>({
-	isShowSearch: false,
-	menuQuery: '',
-	menuList: [],
+  isShowSearch: false,
+  menuQuery: '',
+  menuList: []
 });
 
 // 搜索弹窗打开
 const openSearch = () => {
-	state.menuQuery = '';
-	state.isShowSearch = true;
-	state.menuList = generateRoutes(routes.value);
-	nextTick(() => {
-		setTimeout(() => {
-			layoutMenuAutocompleteRef.value.focus();
-		});
-	});
+  state.menuQuery = '';
+  state.isShowSearch = true;
+  state.menuList = generateRoutes(routes.value);
+  nextTick(() => {
+    setTimeout(() => {
+      layoutMenuAutocompleteRef.value.focus();
+    });
+  });
 };
 // 搜索弹窗关闭
 const closeSearch = () => {
-	state.isShowSearch = false;
+  state.isShowSearch = false;
 };
 // 菜单搜索数据过滤
 const menuSearch = (queryString: string, cb: Function) => {
-	let options = state.menuList.filter((item) => {
-		return item.title.indexOf(queryString) > -1;
-	});
-	cb(options);
+  let options = state.menuList.filter((item) => {
+    return item.title.indexOf(queryString) > -1;
+  });
+  cb(options);
 };
 
 // Filter out the routes that can be displayed in the sidebar
 // And generate the internationalized title
-const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
-	let res: Router = []
-	routes.forEach(r => {
-        // skip hidden router
-		if (!r.hidden) {
-			const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
-				const data: any = {
-					path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
-					icon: r.meta?.icon,
-					title: [...prefixTitle]
-				}
-				if (r.meta && r.meta.title) {
-					data.title = [...data.title, r.meta.title];
-					if (r.redirect !== 'noRedirect') {
-						// only push the routes with title
-						// special case: need to exclude parent router without redirect
-            res.push(data);
-					}
-				}
-				// recursive child routes
-				if (r.children) {
-						const tempRoutes = generateRoutes(r.children, data.path, data.title);
-						if (tempRoutes.length >= 1) {
-								res = [...res, ...tempRoutes];
-						}
-				}
-		}
-	})
-	res.forEach((item: any) => {
-		if (item.title instanceof Array) {
-			item.title = item.title.join('/');
-		}
-	});
-	return res;
-}
+const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => {
+  let res: Router = [];
+  routes.forEach((r) => {
+    // skip hidden router
+    if (!r.hidden) {
+      const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
+      const data: any = {
+        path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
+        icon: r.meta?.icon,
+        title: [...prefixTitle]
+      };
+      if (r.meta && r.meta.title) {
+        data.title = [...data.title, r.meta.title];
+        if (r.redirect !== 'noRedirect') {
+          // only push the routes with title
+          // special case: need to exclude parent router without redirect
+          res.push(data);
+        }
+      }
+      // recursive child routes
+      if (r.children) {
+        const tempRoutes = generateRoutes(r.children, data.path, data.title);
+        if (tempRoutes.length >= 1) {
+          res = [...res, ...tempRoutes];
+        }
+      }
+    }
+  });
+  res.forEach((item: any) => {
+    if (item.title instanceof Array) {
+      item.title = item.title.join('/');
+    }
+  });
+  return res;
+};
 // 当前菜单选中时
 const onHandleSelect = (val: any) => {
-	const paths = val.path;
-	if (isHttp(paths)) {
-		// http(s):// 路径新窗口打开
-		const pindex = paths.indexOf("http");
-		window.open(paths.substring(pindex, paths.length), "_blank");
-	} else {
-		router.push(paths);
-	}
-	state.menuQuery = ''
-	closeSearch();
-
+  const paths = val.path;
+  if (isHttp(paths)) {
+    // http(s):// 路径新窗口打开
+    const pindex = paths.indexOf('http');
+    window.open(paths.substring(pindex, paths.length), '_blank');
+  } else {
+    router.push(paths);
+  }
+  state.menuQuery = '';
+  closeSearch();
 };
 
 // 暴露变量
 defineExpose({
-	openSearch
+  openSearch
 });
 </script>
 
 <style scoped lang="scss">
 .layout-search-dialog {
-	position: relative;
-	:deep(.el-dialog) {
-		.el-dialog__header,
-		.el-dialog__body {
-			display: none;
-		}
-		.el-dialog__footer {
-			width: 100%;
-			position: absolute;
-			left: 50%;
-			transform: translateX(-50%);
-			top: -53vh;
-		}
-	}
-	:deep(.el-autocomplete) {
-		width: 560px;
-		position: absolute;
-		top: 150px;
-		left: 50%;
-		transform: translateX(-50%);
-	}
+  position: relative;
+  :deep(.el-dialog) {
+    .el-dialog__header,
+    .el-dialog__body {
+      display: none;
+    }
+    .el-dialog__footer {
+      width: 100%;
+      position: absolute;
+      left: 50%;
+      transform: translateX(-50%);
+      top: -53vh;
+    }
+  }
+  :deep(.el-autocomplete) {
+    width: 560px;
+    position: absolute;
+    top: 150px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
 }
 </style>

+ 10 - 13
src/layout/components/notice/index.vue

@@ -1,12 +1,12 @@
 <template>
-  <div class="layout-navbars-breadcrumb-user-news" v-loading="state.loading">
+  <div v-loading="state.loading" class="layout-navbars-breadcrumb-user-news">
     <div class="head-box">
       <div class="head-box-title">通知公告</div>
       <div class="head-box-btn" @click="readAll">全部已读</div>
     </div>
-    <div class="content-box" v-loading="state.loading">
+    <div v-loading="state.loading" class="content-box">
       <template v-if="newsList.length > 0">
-        <div class="content-box-item" v-for="(v, k) in newsList" :key="k" @click="onNewsClick(k)">
+        <div v-for="(v, k) in newsList" :key="k" class="content-box-item" @click="onNewsClick(k)">
           <div class="item-conten">
             <div>{{ v.message }}</div>
             <div class="content-box-msg"></div>
@@ -17,26 +17,24 @@
           <span v-else class="el-tag el-tag--danger el-tag--mini read">未读</span>
         </div>
       </template>
-      <el-empty :description="'消息为空'" v-else></el-empty>
+      <el-empty v-else :description="'消息为空'"></el-empty>
     </div>
-    <div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">前往gitee</div>
+    <div v-if="newsList.length > 0" class="foot-box" @click="onGoToGiteeClick">前往gitee</div>
   </div>
 </template>
 
 <script setup lang="ts" name="layoutBreadcrumbUserNews">
-import { ref } from "vue";
-import { storeToRefs } from 'pinia'
-import { nextTick, onMounted, reactive } from "vue";
+import { storeToRefs } from 'pinia';
 import useNoticeStore from '@/store/modules/notice';
 
 const noticeStore = storeToRefs(useNoticeStore());
-const {readAll} = useNoticeStore();
+const { readAll } = useNoticeStore();
 
 // 定义变量内容
 const state = reactive({
-  loading: false,
+  loading: false
 });
-const newsList =ref([]) as any;
+const newsList = ref([]) as any;
 
 /**
  * 初始化数据
@@ -48,7 +46,6 @@ const getTableData = async () => {
   state.loading = false;
 };
 
-
 //点击消息,写入已读
 const onNewsClick = (item: any) => {
   newsList.value[item].read = true;
@@ -58,7 +55,7 @@ const onNewsClick = (item: any) => {
 
 // 前往通知中心点击
 const onGoToGiteeClick = () => {
-  window.open("https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/");
+  window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/');
 };
 
 onMounted(() => {

+ 33 - 33
src/layout/index.vue

@@ -12,7 +12,7 @@
         <settings ref="settingRef" />
       </el-scrollbar> -->
       <div :class="{ 'fixed-header': fixedHeader }">
-        <navbar ref="navbarRef" @setLayout="setLayout" />
+        <navbar ref="navbarRef" @set-layout="setLayout" />
         <tags-view v-if="needTagsView" />
       </div>
       <app-main />
@@ -22,12 +22,12 @@
 </template>
 
 <script setup lang="ts">
-import SideBar from './components/Sidebar/index.vue'
-import { AppMain, Navbar, Settings, TagsView } from './components'
-import useAppStore from '@/store/modules/app'
-import useSettingsStore from '@/store/modules/settings'
+import SideBar from './components/Sidebar/index.vue';
+import { AppMain, Navbar, Settings, TagsView } from './components';
+import useAppStore from '@/store/modules/app';
+import useSettingsStore from '@/store/modules/settings';
 
-const settingsStore = useSettingsStore()
+const settingsStore = useSettingsStore();
 const theme = computed(() => settingsStore.theme);
 const sidebar = computed(() => useAppStore().sidebar);
 const device = computed(() => useAppStore().device);
@@ -35,48 +35,48 @@ const needTagsView = computed(() => settingsStore.tagsView);
 const fixedHeader = computed(() => settingsStore.fixedHeader);
 
 const classObj = computed(() => ({
-    hideSidebar: !sidebar.value.opened,
-    openSidebar: sidebar.value.opened,
-    withoutAnimation: sidebar.value.withoutAnimation,
-    mobile: device.value === 'mobile'
-}))
+  hideSidebar: !sidebar.value.opened,
+  openSidebar: sidebar.value.opened,
+  withoutAnimation: sidebar.value.withoutAnimation,
+  mobile: device.value === 'mobile'
+}));
 
 const { width } = useWindowSize();
 const WIDTH = 992; // refer to Bootstrap's responsive design
 
 watchEffect(() => {
-    if (device.value === 'mobile' && sidebar.value.opened) {
-        useAppStore().closeSideBar({ withoutAnimation: false })
-    }
-    if (width.value - 1 < WIDTH) {
-        useAppStore().toggleDevice('mobile')
-        useAppStore().closeSideBar({ withoutAnimation: true })
-    } else {
-        useAppStore().toggleDevice('desktop')
-    }
-})
-
-const navbarRef = ref(Navbar);
-const settingRef = ref(Settings);
+  if (device.value === 'mobile' && sidebar.value.opened) {
+    useAppStore().closeSideBar({ withoutAnimation: false });
+  }
+  if (width.value - 1 < WIDTH) {
+    useAppStore().toggleDevice('mobile');
+    useAppStore().closeSideBar({ withoutAnimation: true });
+  } else {
+    useAppStore().toggleDevice('desktop');
+  }
+});
+
+const navbarRef = ref<InstanceType<typeof Navbar>>();
+const settingRef = ref<InstanceType<typeof Settings>>();
 
 onMounted(() => {
   nextTick(() => {
-    navbarRef.value.initTenantList();
-  })
-})
+    navbarRef.value?.initTenantList();
+  });
+});
 
 const handleClickOutside = () => {
-  useAppStore().closeSideBar({ withoutAnimation: false })
-}
+  useAppStore().closeSideBar({ withoutAnimation: false });
+};
 
 const setLayout = () => {
-  settingRef.value.openSetting();
-}
+  settingRef.value?.openSetting();
+};
 </script>
 
 <style lang="scss" scoped>
-  @import "@/assets/styles/mixin.scss";
-  @import "@/assets/styles/variables.module.scss";
+@import '@/assets/styles/mixin.scss';
+@import '@/assets/styles/variables.module.scss';
 
 .app-wrapper {
   @include clearfix;

+ 3 - 2
src/permission.ts

@@ -8,6 +8,7 @@ import { isRelogin } from '@/utils/request';
 import useUserStore from '@/store/modules/user';
 import useSettingsStore from '@/store/modules/settings';
 import usePermissionStore from '@/store/modules/permission';
+import { RouteRecordRaw } from 'vue-router';
 
 NProgress.configure({ showSpinner: false });
 const whiteList = ['/login', '/register', '/social-callback'];
@@ -35,7 +36,7 @@ router.beforeEach(async (to, from, next) => {
           isRelogin.show = false;
           const accessRoutes = await usePermissionStore().generateRoutes();
           // 根据roles权限生成可访问的路由表
-          accessRoutes.forEach((route) => {
+          accessRoutes.forEach((route: RouteRecordRaw) => {
             if (!isHttp(route.path)) {
               router.addRoute(route); // 动态添加可访问路由表
             }
@@ -48,7 +49,7 @@ router.beforeEach(async (to, from, next) => {
     }
   } else {
     // 没有token
-    if (whiteList.indexOf(to.path) !== -1) {
+    if (whiteList.indexOf(to.path as string) !== -1) {
       // 在免登录白名单,直接进入
       next();
     } else {

+ 9 - 9
src/plugins/tab.ts

@@ -1,6 +1,6 @@
 import { useTagsViewStore } from '@/store/modules/tagsView';
 import router from '@/router';
-import { TagView, RouteLocationRaw } from 'vue-router';
+import { TagView, RouteLocationMatched } from 'vue-router';
 
 export default {
   /**
@@ -10,7 +10,7 @@ export default {
   async refreshPage(obj?: TagView): Promise<void> {
     const { path, query, matched } = router.currentRoute.value;
     if (obj === undefined) {
-      matched.forEach((m) => {
+      matched.forEach((m: RouteLocationMatched) => {
         if (m.components && m.components.default && m.components.default.name) {
           if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
             obj = { name: m.components.default.name, path: path, query: query };
@@ -31,8 +31,8 @@ export default {
     });
   },
   // 关闭当前tab页签,打开新页签
-  closeOpenPage(obj: RouteLocationRaw): void {
-    useTagsViewStore().delView(router.currentRoute.value);
+  closeOpenPage(obj: TagView): void {
+    useTagsViewStore().delView(router.currentRoute.value as any);
     if (obj !== undefined) {
       router.push(obj);
     }
@@ -41,10 +41,10 @@ export default {
   async closePage(obj?: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] } | any> {
     if (obj === undefined) {
       // prettier-ignore
-      const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any
+      const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value as any)
       const latestView = visitedViews.slice(-1)[0];
       if (latestView) {
-        return router.push(latestView.fullPath);
+        return router.push(latestView.fullPath as any);
       }
       return router.push('/');
     }
@@ -56,15 +56,15 @@ export default {
   },
   // 关闭左侧tab页签
   closeLeftPage(obj?: TagView) {
-    return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
+    return useTagsViewStore().delLeftTags(obj || (router.currentRoute.value as any));
   },
   // 关闭右侧tab页签
   closeRightPage(obj?: TagView) {
-    return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
+    return useTagsViewStore().delRightTags(obj || (router.currentRoute.value as any));
   },
   // 关闭其他tab页签
   closeOtherPage(obj?: TagView) {
-    return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
+    return useTagsViewStore().delOthersViews(obj || (router.currentRoute.value as any));
   },
   /**
    * 打开tab页签

+ 3 - 3
src/router/index.ts

@@ -1,4 +1,4 @@
-import { createWebHistory, createRouter, RouteOption } from 'vue-router';
+import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router';
 /* Layout */
 import Layout from '@/layout/index.vue';
 
@@ -25,7 +25,7 @@ import Layout from '@/layout/index.vue';
  */
 
 // 公共路由
-export const constantRoutes: RouteOption[] = [
+export const constantRoutes: RouteRecordRaw[] = [
   {
     path: '/redirect',
     component: Layout,
@@ -92,7 +92,7 @@ export const constantRoutes: RouteOption[] = [
 ];
 
 // 动态路由,基于用户权限动态去加载
-export const dynamicRoutes: RouteOption[] = [
+export const dynamicRoutes: RouteRecordRaw[] = [
   {
     path: '/system/user-auth',
     component: Layout,

+ 1 - 1
src/store/modules/notice.ts

@@ -22,7 +22,7 @@ export const useNoticeStore = defineStore('notice', () => {
 
   //实现全部已读
   const readAll = () => {
-    state.notices.forEach((item) => {
+    state.notices.forEach((item: any) => {
       item.read = true;
     });
   };

+ 32 - 33
src/store/modules/permission.ts

@@ -2,35 +2,36 @@ import { defineStore } from 'pinia';
 import router, { constantRoutes, dynamicRoutes } from '@/router';
 import store from '@/store';
 import { getRouters } from '@/api/menu';
+import auth from '@/plugins/auth';
+import { RouteRecordRaw } from 'vue-router';
+
 import Layout from '@/layout/index.vue';
 import ParentView from '@/components/ParentView/index.vue';
 import InnerLink from '@/layout/components/InnerLink/index.vue';
-import auth from '@/plugins/auth';
-import { RouteOption } from 'vue-router';
+
 // 匹配views里面所有的.vue文件
 const modules = import.meta.glob('./../../views/**/*.vue');
-
 export const usePermissionStore = defineStore('permission', () => {
-  const routes = ref<RouteOption[]>([]);
-  const addRoutes = ref<RouteOption[]>([]);
-  const defaultRoutes = ref<RouteOption[]>([]);
-  const topbarRouters = ref<RouteOption[]>([]);
-  const sidebarRouters = ref<RouteOption[]>([]);
+  const routes = ref<RouteRecordRaw[]>([]);
+  const addRoutes = ref<RouteRecordRaw[]>([]);
+  const defaultRoutes = ref<RouteRecordRaw[]>([]);
+  const topbarRouters = ref<RouteRecordRaw[]>([]);
+  const sidebarRouters = ref<RouteRecordRaw[]>([]);
 
-  const setRoutes = (newRoutes: RouteOption[]): void => {
+  const setRoutes = (newRoutes: RouteRecordRaw[]): void => {
     addRoutes.value = newRoutes;
     routes.value = constantRoutes.concat(newRoutes);
   };
-  const setDefaultRoutes = (routes: RouteOption[]): void => {
+  const setDefaultRoutes = (routes: RouteRecordRaw[]): void => {
     defaultRoutes.value = constantRoutes.concat(routes);
   };
-  const setTopbarRoutes = (routes: RouteOption[]): void => {
+  const setTopbarRoutes = (routes: RouteRecordRaw[]): void => {
     topbarRouters.value = routes;
   };
-  const setSidebarRouters = (routes: RouteOption[]): void => {
+  const setSidebarRouters = (routes: RouteRecordRaw[]): void => {
     sidebarRouters.value = routes;
   };
-  const generateRoutes = async (): Promise<RouteOption[]> => {
+  const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
     const res = await getRouters();
     const { data } = res;
     const sdata = JSON.parse(JSON.stringify(data));
@@ -47,7 +48,7 @@ export const usePermissionStore = defineStore('permission', () => {
     setSidebarRouters(constantRoutes.concat(sidebarRoutes));
     setDefaultRoutes(sidebarRoutes);
     setTopbarRoutes(defaultRoutes);
-    return new Promise<RouteOption[]>((resolve) => resolve(rewriteRoutes));
+    return new Promise<RouteRecordRaw[]>((resolve) => resolve(rewriteRoutes));
   };
 
   /**
@@ -56,22 +57,20 @@ export const usePermissionStore = defineStore('permission', () => {
    * @param lastRouter 上一级路由
    * @param type 是否是重写路由
    */
-  const filterAsyncRouter = (asyncRouterMap: RouteOption[], lastRouter?: RouteOption, type = false): RouteOption[] => {
+  const filterAsyncRouter = (asyncRouterMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw, type = false): RouteRecordRaw[] => {
     return asyncRouterMap.filter((route) => {
       if (type && route.children) {
         route.children = filterChildren(route.children, undefined);
       }
-      if (route.component) {
-        // Layout ParentView 组件特殊处理
-        if (route.component === 'Layout') {
-          route.component = Layout;
-        } else if (route.component === 'ParentView') {
-          route.component = ParentView;
-        } else if (route.component === 'InnerLink') {
-          route.component = InnerLink;
-        } else {
-          route.component = loadView(route.component);
-        }
+      // Layout ParentView 组件特殊处理
+      if (route.component?.toString() === 'Layout') {
+        route.component = Layout;
+      } else if (route.component?.toString() === 'ParentView') {
+        route.component = ParentView;
+      } else if (route.component?.toString() === 'InnerLink') {
+        route.component = InnerLink;
+      } else {
+        route.component = loadView(route.component);
       }
       if (route.children != null && route.children && route.children.length) {
         route.children = filterAsyncRouter(route.children, route, type);
@@ -82,11 +81,11 @@ export const usePermissionStore = defineStore('permission', () => {
       return true;
     });
   };
-  const filterChildren = (childrenMap: RouteOption[], lastRouter?: RouteOption): RouteOption[] => {
-    let children: RouteOption[] = [];
+  const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => {
+    let children: RouteRecordRaw[] = [];
     childrenMap.forEach((el) => {
       if (el.children && el.children.length) {
-        if (el.component === 'ParentView' && !lastRouter) {
+        if (el.component?.toString() === 'ParentView' && !lastRouter) {
           el.children.forEach((c) => {
             c.path = el.path + '/' + c.path;
             if (c.children && c.children.length) {
@@ -101,8 +100,8 @@ export const usePermissionStore = defineStore('permission', () => {
       if (lastRouter) {
         el.path = lastRouter.path + '/' + el.path;
         if (el.children && el.children.length) {
-          children = children.concat(filterChildren(el.children, el))
-          return
+          children = children.concat(filterChildren(el.children, el));
+          return;
         }
       }
       children = children.concat(el);
@@ -113,8 +112,8 @@ export const usePermissionStore = defineStore('permission', () => {
 });
 
 // 动态路由遍历,验证是否具备权限
-export const filterDynamicRoutes = (routes: RouteOption[]) => {
-  const res: RouteOption[] = [];
+export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => {
+  const res: RouteRecordRaw[] = [];
   routes.forEach((route) => {
     if (route.permissions) {
       if (auth.hasPermiOr(route.permissions)) {

+ 23 - 15
src/store/modules/settings.ts

@@ -2,27 +2,35 @@ import { defineStore } from 'pinia';
 import defaultSettings from '@/settings';
 import { SettingTypeEnum } from '@/enums/SettingTypeEnum';
 import { useDynamicTitle } from '@/utils/dynamicTitle';
-import { Ref } from 'vue';
-
 export const useSettingsStore = defineStore('setting', () => {
   const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}');
+  const title = ref<string>(defaultSettings.title);
+  const theme = ref<string>(storageSetting.theme || defaultSettings.theme);
+  const sideTheme = ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme);
+  const showSettings = ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings);
+  const topNav = ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav);
+  const tagsView = ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView);
+  const fixedHeader = ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader);
+  const sidebarLogo = ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo);
+  const dynamicTitle = ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle);
+  const animationEnable = ref<boolean>(
+    storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable
+  );
+  const dark = ref<boolean>(storageSetting.dark || defaultSettings.dark);
 
   const prop: { [key: string]: Ref<any> } = {
-    title: ref<string>(''),
-    theme: ref<string>(storageSetting.theme || defaultSettings.theme),
-    sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme),
-    showSettings: ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings),
-    topNav: ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav),
-    tagsView: ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView),
-    fixedHeader: ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader),
-    sidebarLogo: ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo),
-    dynamicTitle: ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle),
-    animationEnable: ref<boolean>(storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable),
-    dark: ref<boolean>(storageSetting.dark || defaultSettings.dark)
+    theme,
+    sideTheme,
+    showSettings,
+    topNav,
+    tagsView,
+    fixedHeader,
+    sidebarLogo,
+    dynamicTitle,
+    animationEnable,
+    dark
   };
 
-  const { title, theme, sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, animationEnable, dark } = prop;
-
   // actions
   const changeSetting = (param: { key: SettingTypeEnum; value: any }) => {
     const { key, value } = param;

+ 11 - 11
src/store/modules/tagsView.ts

@@ -11,7 +11,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
   };
 
   const addIframeView = (view: TagView): void => {
-    if (iframeViews.value.some((v) => v.path === view.path)) return;
+    if (iframeViews.value.some((v: TagView) => v.path === view.path)) return;
     iframeViews.value.push(
       Object.assign({}, view, {
         title: view.meta?.title || 'no-name'
@@ -20,12 +20,12 @@ export const useTagsViewStore = defineStore('tagsView', () => {
   };
   const delIframeView = (view: TagView): Promise<TagView[]> => {
     return new Promise((resolve) => {
-      iframeViews.value = iframeViews.value.filter((item) => item.path !== view.path);
+      iframeViews.value = iframeViews.value.filter((item: TagView) => item.path !== view.path);
       resolve([...iframeViews.value]);
     });
   };
   const addVisitedView = (view: TagView): void => {
-    if (visitedViews.value.some((v) => v.path === view.path)) return;
+    if (visitedViews.value.some((v: TagView) => v.path === view.path)) return;
     visitedViews.value.push(
       Object.assign({}, view, {
         title: view.meta?.title || 'no-name'
@@ -80,7 +80,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
 
   const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => {
     return new Promise((resolve) => {
-      visitedViews.value = visitedViews.value.filter((v) => {
+      visitedViews.value = visitedViews.value.filter((v: TagView) => {
         return v.meta?.affix || v.path === view.path;
       });
       resolve([...visitedViews.value]);
@@ -111,7 +111,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
   };
   const delAllVisitedViews = (): Promise<TagView[]> => {
     return new Promise((resolve) => {
-      visitedViews.value = visitedViews.value.filter((tag) => tag.meta?.affix);
+      visitedViews.value = visitedViews.value.filter((tag: TagView) => tag.meta?.affix);
       resolve([...visitedViews.value]);
     });
   };
@@ -123,7 +123,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
     });
   };
 
-  const updateVisitedView = (view: TagView): void => {
+  const updateVisitedView = (view: TagView | RouteLocationNormalized): void => {
     for (let v of visitedViews.value) {
       if (v.path === view.path) {
         v = Object.assign(v, view);
@@ -133,11 +133,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
   };
   const delRightTags = (view: TagView): Promise<TagView[]> => {
     return new Promise((resolve) => {
-      const index = visitedViews.value.findIndex((v) => v.path === view.path);
+      const index = visitedViews.value.findIndex((v: TagView) => v.path === view.path);
       if (index === -1) {
         return;
       }
-      visitedViews.value = visitedViews.value.filter((item, idx) => {
+      visitedViews.value = visitedViews.value.filter((item: TagView, idx: number) => {
         if (idx <= index || (item.meta && item.meta.affix)) {
           return true;
         }
@@ -152,11 +152,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
   };
   const delLeftTags = (view: TagView): Promise<TagView[]> => {
     return new Promise((resolve) => {
-      const index = visitedViews.value.findIndex((v) => v.path === view.path);
+      const index = visitedViews.value.findIndex((v: TagView) => v.path === view.path);
       if (index === -1) {
         return;
       }
-      visitedViews.value = visitedViews.value.filter((item, idx) => {
+      visitedViews.value = visitedViews.value.filter((item: TagView, idx: number) => {
         if (idx >= index || (item.meta && item.meta.affix)) {
           return true;
         }
@@ -170,7 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
     });
   };
 
-  const addCachedView = (view: TagView): void => {
+  const addCachedView = (view: TagView | RouteLocationNormalized): void => {
     const viewName = view.name as string;
     if (!viewName) return;
     if (cachedViews.value.includes(viewName)) return;

+ 3 - 3
src/types/element.d.ts

@@ -1,12 +1,12 @@
 import type * as ep from 'element-plus';
 declare global {
   declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
-  declare type ElFormInstance = InstanceType<typeof ep.ElForm>;
-  declare type ElTableInstance = InstanceType<typeof ep.ElTable>;
+  declare type ElFormInstance = ep.FormInstance;
+  declare type ElTableInstance = ep.TableInstance;
+  declare type ElUploadInstance = ep.UploadInstance;
   declare type ElTreeInstance = InstanceType<typeof ep.ElTree>;
   declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>;
   declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>;
-  declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
   declare type ElCardInstance = InstanceType<typeof ep.ElCard>;
   declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>;
   declare type ElInputInstance = InstanceType<typeof ep.ElInput>;

+ 3 - 2
src/types/env.d.ts

@@ -1,8 +1,9 @@
 declare module '*.vue' {
   import { DefineComponent } from 'vue';
-  const component: DefineComponent<{}, {}, any>;
-  export default component;
+  const Component: DefineComponent<{}, {}, any>;
+  export default Component;
 }
+
 declare module '*.avif' {
   const src: string;
   export default src;

+ 72 - 1
src/types/global.d.ts

@@ -1,4 +1,4 @@
-import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue';
+import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue/runtime-core';
 
 declare global {
   /** vue Instance */
@@ -87,5 +87,76 @@ declare global {
     pageNum: number;
     pageSize: number;
   }
+
+  declare type DefaultSettings = {
+    /**
+     * 网页标题
+     */
+    title: string;
+
+    /**
+     * 侧边栏主题 theme-dark | theme-light
+     */
+    sideTheme?: string;
+
+    /**
+     * 是否显示系统布局设置
+     */
+    showSettings?: boolean;
+
+    /**
+     * 是否显示顶部导航
+     */
+    topNav?: boolean;
+
+    /**
+     * 是否显示多标签导航
+     */
+    tagsView?: boolean;
+    /**
+     * 是否固定头部
+     */
+    fixedHeader?: boolean;
+    /**
+     * 是否显示侧边栏Logo
+     */
+    sidebarLogo?: boolean;
+    /**
+     * 导航栏布局
+     */
+    layout?: string;
+    /**
+     * 主题模式
+     */
+    theme?: string;
+
+    /**
+     * 布局大小
+     */
+    size?: string;
+
+    /**
+     * 语言
+     */
+    language?: string;
+
+    /**
+     * 是否显示动态标题
+     */
+    dynamicTitle?: boolean;
+    /**
+     * 是否启用动画效果
+     */
+    animationEnable?: boolean;
+    /**
+     *  是否启用暗黑模式
+     *
+     * true:暗黑模式
+     * false: 明亮模式
+     */
+    dark?: boolean;
+
+    errorLog?: string;
+  };
 }
 export {};

+ 22 - 24
src/types/router.d.ts

@@ -1,36 +1,34 @@
-import { RouteRecordRaw } from 'vue-router';
-
+import { LocationQuery, type RouteMeta as VRouteMeta } from 'vue-router';
 declare module 'vue-router' {
-  declare type RouteOption = {
-    hidden?: boolean;
+  interface RouteMeta extends VRouteMeta {
+    link?: string;
+    title?: string;
+    affix?: boolean;
+    noCache?: boolean;
+    activeMenu?: string;
+    icon?: string;
+    breadcrumb?: boolean;
+  }
+
+  interface _RouteRecordBase {
+    hidden?: boolean | string | number;
     permissions?: string[];
     roles?: string[];
-    component?: any;
-    children?: RouteOption[];
     alwaysShow?: boolean;
-    parentPath?: string;
-    meta?: {
-      title: string;
-      icon: string;
-    };
     query?: string;
-  } & RouteRecordRaw;
-
-  declare interface _RouteLocationBase {
-    children?: RouteOption[];
   }
 
-  declare interface RouteLocationOptions {
-    fullPath?: string;
+  interface _RouteLocationBase {
+    children?: _RouteRecordBase[];
+    path?: string;
   }
 
-  declare interface TagView extends Partial<_RouteLocationBase> {
+  interface TagView {
+    fullPath?: string;
+    name?: string;
+    path?: string;
     title?: string;
-    meta?: {
-      link?: string;
-      title?: string;
-      affix?: boolean;
-      noCache?: boolean;
-    };
+    meta?: RouteMeta;
+    query?: LocationQuery;
   }
 }

+ 0 - 70
src/types/setting.d.ts

@@ -1,70 +0,0 @@
-declare type DefaultSettings = {
-  /**
-   * 网页标题
-   */
-  title?: string;
-
-  /**
-   * 侧边栏主题 theme-dark | theme-light
-   */
-  sideTheme?: string;
-
-  /**
-   * 是否显示系统布局设置
-   */
-  showSettings?: boolean;
-
-  /**
-   * 是否显示顶部导航
-   */
-  topNav?: boolean;
-
-  /**
-   * 是否显示多标签导航
-   */
-  tagsView?: boolean;
-  /**
-   * 是否固定头部
-   */
-  fixedHeader?: boolean;
-  /**
-   * 是否显示侧边栏Logo
-   */
-  sidebarLogo?: boolean;
-  /**
-   * 导航栏布局
-   */
-  layout?: string;
-  /**
-   * 主题模式
-   */
-  theme?: string;
-
-  /**
-   * 布局大小
-   */
-  size?: string;
-
-  /**
-   * 语言
-   */
-  language?: string;
-
-  /**
-   * 是否显示动态标题
-   */
-  dynamicTitle?: boolean;
-  /**
-   * 是否启用动画效果
-   */
-  animationEnable?: boolean;
-  /**
-   *  是否启用暗黑模式
-   *
-   * true:暗黑模式
-   * false: 明亮模式
-   */
-  dark?: boolean;
-
-  errorLog?: string;
-};

+ 1 - 0
src/utils/propTypes.ts

@@ -3,6 +3,7 @@ import VueTypes, { createTypes, toValidableType, VueTypeValidableDef, VueTypesIn
 
 type PropTypes = VueTypesInterface & {
   readonly style: VueTypeValidableDef<CSSProperties>;
+  readonly fieldOption: VueTypeValidableDef<Array<FieldOption>>;
 };
 
 const propTypes = createTypes({

+ 0 - 2
src/utils/request.ts

@@ -89,7 +89,6 @@ service.interceptors.request.use(
     return config;
   },
   (error: any) => {
-    console.log(error);
     return Promise.reject(error);
   }
 );
@@ -138,7 +137,6 @@ service.interceptors.response.use(
       }
       return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
     } else if (code === HttpStatus.SERVER_ERROR) {
-      console.log(msg);
       ElMessage({ message: msg, type: 'error' });
       return Promise.reject(new Error(msg));
     } else if (code === HttpStatus.WARN) {

+ 2 - 2
src/utils/websocket.ts

@@ -20,7 +20,7 @@
 
 import { getToken } from '@/utils/auth';
 import useNoticeStore from '@/store/modules/notice';
-import { ElNotification } from "element-plus";
+import { ElNotification } from 'element-plus';
 
 const { addNotice } = useNoticeStore();
 
@@ -135,7 +135,7 @@ export const websocketonmessage = () => {
       message: e.data,
       type: 'success',
       duration: 3000
-    })
+    });
     return e.data;
   };
 };

+ 48 - 56
src/views/demo/demo/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="部门id" prop="deptId">
               <el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -32,26 +32,26 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">新增</el-button>
+            <el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
+            <el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']"
+            <el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
               >删除</el-button
             >
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
+            <el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="id" v-if="true" />
+        <el-table-column v-if="true" label="主键" align="center" prop="id" />
         <el-table-column label="部门id" align="center" prop="deptId" />
         <el-table-column label="用户id" align="center" prop="userId" />
         <el-table-column label="排序号" align="center" prop="orderNum" />
@@ -60,19 +60,19 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button>
+              <el-button v-hasPermi="['demo:demo:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button>
+              <el-button v-hasPermi="['demo:demo:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改测试单对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="部门id" prop="deptId">
           <el-input v-model="form.deptId" placeholder="请输入部门id" />
@@ -129,8 +129,8 @@ const initFormData: DemoForm = {
   userId: undefined,
   orderNum: undefined,
   testKey: undefined,
-  value: undefined,
-}
+  value: undefined
+};
 const data = reactive<PageData<DemoForm, DemoQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -140,27 +140,15 @@ const data = reactive<PageData<DemoForm, DemoQuery>>({
     userId: undefined,
     orderNum: undefined,
     testKey: undefined,
-    value: undefined,
+    value: undefined
   },
   rules: {
-    id: [
-      { required: true, message: "主键不能为空", trigger: "blur" }
-    ],
-    deptId: [
-      { required: true, message: "部门id不能为空", trigger: "blur" }
-    ],
-    userId: [
-      { required: true, message: "用户id不能为空", trigger: "blur" }
-    ],
-    orderNum: [
-      { required: true, message: "排序号不能为空", trigger: "blur" }
-    ],
-    testKey: [
-      { required: true, message: "key键不能为空", trigger: "blur" }
-    ],
-    value: [
-      { required: true, message: "值不能为空", trigger: "blur" }
-    ],
+    id: [{ required: true, message: '主键不能为空', trigger: 'blur' }],
+    deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }],
+    userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }],
+    orderNum: [{ required: true, message: '排序号不能为空', trigger: 'blur' }],
+    testKey: [{ required: true, message: 'key键不能为空', trigger: 'blur' }],
+    value: [{ required: true, message: '值不能为空', trigger: 'blur' }]
   }
 });
 
@@ -173,55 +161,55 @@ const getList = async () => {
   demoList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   demoFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DemoVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加测试单";
-}
+  dialog.title = '添加测试单';
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: DemoVO) => {
   reset();
-  const _id = row?.id || ids.value[0]
+  const _id = row?.id || ids.value[0];
   const res = await getDemo(_id);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改测试单";
-}
+  dialog.title = '修改测试单';
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -229,32 +217,36 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateDemo(form.value).finally(() => buttonLoading.value = false);
+        await updateDemo(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addDemo(form.value).finally(() => buttonLoading.value = false);
+        await addDemo(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("修改成功");
+      proxy?.$modal.msgSuccess('修改成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: DemoVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
   await delDemo(_ids);
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   await getList();
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('demo/demo/export', {
-    ...queryParams.value
-  }, `demo_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'demo/demo/export',
+    {
+      ...queryParams.value
+    },
+    `demo_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
   getList();

+ 55 - 68
src/views/demo/tree/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="树节点名" prop="treeName">
               <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -20,21 +20,21 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">新增</el-button>
+            <el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
       <el-table
+        ref="treeTableRef"
         v-loading="loading"
         :data="treeList"
         row-key="id"
         :default-expand-all="isExpandAll"
-        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
-        ref="treeTableRef"
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       >
         <el-table-column label="父id" align="center" prop="parentId" />
         <el-table-column label="部门id" align="center" prop="deptId" />
@@ -43,20 +43,20 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']" />
+              <el-button v-hasPermi="['demo:tree:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
             </el-tooltip>
             <el-tooltip content="新增" placement="top">
-              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']" />
+              <el-button v-hasPermi="['demo:tree:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']" />
+              <el-button v-hasPermi="['demo:tree:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
     </el-card>
     <!-- 添加或修改测试树对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="treeFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="父id" prop="parentId">
           <el-tree-select
@@ -89,18 +89,16 @@
 </template>
 
 <script setup name="Tree" lang="ts">
-import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
+import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree';
 import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
 
-
 type TreeOption = {
   id: number;
   treeName: string;
   children?: TreeOption[];
-}
-
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
+};
 
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const treeList = ref<TreeVO[]>([]);
 const treeOptions = ref<TreeOption[]>([]);
@@ -111,46 +109,35 @@ const loading = ref(false);
 
 const queryFormRef = ref<ElFormInstance>();
 const treeFormRef = ref<ElFormInstance>();
-const treeTableRef = ref<ElTableInstance>()
+const treeTableRef = ref<ElTableInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
-
 const initFormData: TreeForm = {
-    id: undefined,
-    parentId: undefined,
-    deptId: undefined,
-    userId: undefined,
-    treeName: undefined,
-}
+  id: undefined,
+  parentId: undefined,
+  deptId: undefined,
+  userId: undefined,
+  treeName: undefined
+};
 
 const data = reactive<PageData<TreeForm, TreeQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     parentId: undefined,
     deptId: undefined,
     userId: undefined,
-    treeName: undefined,
+    treeName: undefined
   },
   rules: {
-    id: [
-      { required: true, message: "主键不能为空", trigger: "blur" }
-    ],
-    parentId: [
-      { required: true, message: "父id不能为空", trigger: "blur" }
-    ],
-    deptId: [
-      { required: true, message: "部门id不能为空", trigger: "blur" }
-    ],
-    userId: [
-      { required: true, message: "用户id不能为空", trigger: "blur" }
-    ],
-    treeName: [
-      { required: true, message: "值不能为空", trigger: "blur" }
-    ],
+    id: [{ required: true, message: '主键不能为空', trigger: 'blur' }],
+    parentId: [{ required: true, message: '父id不能为空', trigger: 'blur' }],
+    deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }],
+    userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }],
+    treeName: [{ required: true, message: '值不能为空', trigger: 'blur' }]
   }
 });
 
@@ -160,44 +147,44 @@ const { queryParams, form, rules } = toRefs(data);
 const getList = async () => {
   loading.value = true;
   const res = await listTree(queryParams.value);
-  const data = proxy?.handleTree<TreeVO>(res.data, "id", "parentId");
+  const data = proxy?.handleTree<TreeVO>(res.data, 'id', 'parentId');
   if (data) {
     treeList.value = data;
     loading.value = false;
   }
-}
+};
 
 /** 查询测试树下拉树结构 */
 const getTreeselect = async () => {
   const res = await listTree();
   treeOptions.value = [];
   const data: TreeOption = { id: 0, treeName: '顶级节点', children: [] };
-  data.children = proxy?.handleTree<TreeOption>(res.data, "id", "parentId");
+  data.children = proxy?.handleTree<TreeOption>(res.data, 'id', 'parentId');
   treeOptions.value.push(data);
-}
+};
 
 // 取消按钮
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 // 表单重置
 const reset = () => {
-  form.value = {...initFormData}
+  form.value = { ...initFormData };
   treeFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = (row?: TreeVO) => {
@@ -209,22 +196,22 @@ const handleAdd = (row?: TreeVO) => {
     form.value.parentId = 0;
   }
   dialog.visible = true;
-  dialog.title = "添加测试树";
-}
+  dialog.title = '添加测试树';
+};
 
 /** 展开/折叠操作 */
 const handleToggleExpandAll = () => {
   isExpandAll.value = !isExpandAll.value;
-  toggleExpandAll(treeList.value, isExpandAll.value)
-}
+  toggleExpandAll(treeList.value, isExpandAll.value);
+};
 
 /** 展开/折叠操作 */
 const toggleExpandAll = (data: TreeVO[], status: boolean) => {
   data.forEach((item) => {
-    treeTableRef.value?.toggleRowExpansion(item, status)
-    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
-  })
-}
+    treeTableRef.value?.toggleRowExpansion(item, status);
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
+  });
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row: TreeVO) => {
@@ -236,8 +223,8 @@ const handleUpdate = async (row: TreeVO) => {
   const res = await getTree(row.id);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改测试树";
-}
+  dialog.title = '修改测试树';
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -245,25 +232,25 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateTree(form.value).finally(() => buttonLoading.value = false);
+        await updateTree(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addTree(form.value).finally(() => buttonLoading.value = false);
+        await addTree(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row: TreeVO) => {
   await proxy?.$modal.confirm('是否确认删除测试树编号为"' + row.id + '"的数据项?');
   loading.value = true;
-  await delTree(row.id).finally(() => loading.value = false);
+  await delTree(row.id).finally(() => (loading.value = false));
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();

+ 2 - 2
src/views/error/401.vue

@@ -24,11 +24,11 @@ import errImage from '@/assets/401_images/401.gif';
 
 let { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
-const errGif = ref(errImage + "?" + +new Date());
+const errGif = ref(errImage + '?' + +new Date());
 
 function back() {
   if (proxy?.$route.query.noGoBack) {
-    proxy.$router.push({ path: "/" });
+    proxy.$router.push({ path: '/' });
   } else {
     proxy?.$router.go(-1);
   }

+ 4 - 4
src/views/error/404.vue

@@ -23,13 +23,13 @@
 
 <script setup lang="ts">
 let message = computed(() => {
-  return '找不到网页!'
-})
+  return '找不到网页!';
+});
 </script>
 
 <style lang="scss" scoped>
-.wscn-http404-container{
-  transform: translate(-50%,-50%);
+.wscn-http404-container {
+  transform: translate(-50%, -50%);
   position: absolute;
   top: 40%;
   left: 50%;

+ 6 - 6
src/views/index.vue

@@ -99,13 +99,13 @@
 import { initWebSocket } from '@/utils/websocket';
 
 onMounted(() => {
-  let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'
-  initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket");
+  let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
+  initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket');
 });
 
-const goTarget = (url:string) => {
-  window.open(url, '__blank')
-}
+const goTarget = (url: string) => {
+  window.open(url, '__blank');
+};
 </script>
 
 <style scoped lang="scss">
@@ -131,7 +131,7 @@ const goTarget = (url:string) => {
     margin: 0;
   }
 
-  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
   font-size: 13px;
   color: #676a6c;
   overflow-x: hidden;

+ 29 - 26
src/views/login.vue

@@ -2,7 +2,7 @@
   <div class="login">
     <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
       <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
-      <el-form-item prop="tenantId" v-if="tenantEnabled">
+      <el-form-item v-if="tenantEnabled" prop="tenantId">
         <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
@@ -18,16 +18,16 @@
           <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
         </el-input>
       </el-form-item>
-      <el-form-item prop="code" v-if="captchaEnabled">
+      <el-form-item v-if="captchaEnabled" prop="code">
         <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
           <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
         </el-input>
         <div class="login-code">
-          <img :src="codeUrl" @click="getCode" class="login-code-img" />
+          <img :src="codeUrl" class="login-code-img" @click="getCode" />
         </div>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
-      <el-form-item style="float: right;">
+      <el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 0px">记住密码</el-checkbox>
+      <el-form-item style="float: right">
         <el-button circle title="微信登录" @click="doSocialLogin('wechat')">
           <svg-icon icon-class="wechat" />
         </el-button>
@@ -41,12 +41,12 @@
           <svg-icon icon-class="github" />
         </el-button>
       </el-form-item>
-      <el-form-item style="width:100%;">
-        <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
+      <el-form-item style="width: 100%">
+        <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
           <span v-if="!loading">登 录</span>
           <span v-else>登 录 中...</span>
         </el-button>
-        <div style="float: right;" v-if="register">
+        <div v-if="register" style="float: right">
           <router-link class="link-type" :to="'/register'">立即注册</router-link>
         </div>
       </el-form-item>
@@ -64,7 +64,7 @@ import { authBinding } from '@/api/system/social/auth';
 import { useUserStore } from '@/store/modules/user';
 import { LoginData, TenantVO } from '@/api/types';
 import { to } from 'await-to-js';
-import { HttpStatus } from "@/enums/RespEnum";
+import { HttpStatus } from '@/enums/RespEnum';
 
 const userStore = useUserStore();
 const router = useRouter();
@@ -79,7 +79,7 @@ const loginForm = ref<LoginData>({
 } as LoginData);
 
 const loginRules: ElFormRules = {
-  tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
+  tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
   username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
   password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
   code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
@@ -92,7 +92,6 @@ const captchaEnabled = ref(true);
 // 租户开关
 const tenantEnabled = ref(true);
 
-
 // 注册开关
 const register = ref(false);
 const redirect = ref(undefined);
@@ -100,9 +99,13 @@ const loginRef = ref<ElFormInstance>();
 // 租户列表
 const tenantList = ref<TenantVO[]>([]);
 
-watch(() => router.currentRoute.value, (newRoute: any) => {
-  redirect.value = newRoute.query && newRoute.query.redirect;
-}, { immediate: true });
+watch(
+  () => router.currentRoute.value,
+  (newRoute: any) => {
+    redirect.value = newRoute.query && newRoute.query.redirect;
+  },
+  { immediate: true }
+);
 
 const handleLogin = () => {
   loginRef.value?.validate(async (valid: boolean, fields: any) => {
@@ -110,13 +113,13 @@ const handleLogin = () => {
       loading.value = true;
       // 勾选了需要记住密码设置在 localStorage 中设置记住用户名和密码
       if (loginForm.value.rememberMe) {
-        localStorage.setItem("tenantId", String(loginForm.value.tenantId));
+        localStorage.setItem('tenantId', String(loginForm.value.tenantId));
         localStorage.setItem('username', String(loginForm.value.username));
         localStorage.setItem('password', String(loginForm.value.password));
         localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
       } else {
         // 否则移除
-        localStorage.removeItem("tenantId");
+        localStorage.removeItem('tenantId');
         localStorage.removeItem('username');
         localStorage.removeItem('password');
         localStorage.removeItem('rememberMe');
@@ -153,7 +156,7 @@ const getCode = async () => {
 };
 
 const getLoginData = () => {
-  const tenantId = localStorage.getItem("tenantId");
+  const tenantId = localStorage.getItem('tenantId');
   const username = localStorage.getItem('username');
   const password = localStorage.getItem('password');
   const rememberMe = localStorage.getItem('rememberMe');
@@ -163,8 +166,7 @@ const getLoginData = () => {
     password: password === null ? String(loginForm.value.password) : String(password),
     rememberMe: rememberMe === null ? false : Boolean(rememberMe)
   } as LoginData;
-}
-
+};
 
 /**
  * 获取租户列表
@@ -178,12 +180,15 @@ const initTenantList = async () => {
       loginForm.value.tenantId = tenantList.value[0].tenantId;
     }
   }
-}
+};
 
 //检测租户选择框的变化
-watch(() => loginForm.value.tenantId, () => {
-  localStorage.setItem("tenantId", String(loginForm.value.tenantId))
-});
+watch(
+  () => loginForm.value.tenantId,
+  () => {
+    localStorage.setItem('tenantId', String(loginForm.value.tenantId));
+  }
+);
 
 /**
  * 第三方登录
@@ -200,8 +205,6 @@ const doSocialLogin = (type: string) => {
   });
 };
 
-
-
 onMounted(() => {
   getCode();
   initTenantList();
@@ -215,7 +218,7 @@ onMounted(() => {
   justify-content: center;
   align-items: center;
   height: 100%;
-  background-image: url("../assets/images/login-background.jpg");
+  background-image: url('../assets/images/login-background.jpg');
   background-size: cover;
 }
 

+ 37 - 37
src/views/monitor/cache/index.vue

@@ -4,8 +4,8 @@
       <el-col :span="24" class="card-box">
         <el-card shadow="hover">
           <template #header>
-            <Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
-            <span style="vertical-align: middle;">基本信息</span>
+            <Monitor style="width: 1em; height: 1em; vertical-align: middle" />
+            <span style="vertical-align: middle">基本信息</span>
           </template>
 
           <div class="el-table el-table--enable-row-hover el-table--medium">
@@ -16,25 +16,25 @@
                     <div class="cell">Redis版本</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.redis_version }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">运行模式</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.redis_mode === "standalone" ? "单机" : "集群" }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.redis_mode === 'standalone' ? '单机' : '集群' }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">端口</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.tcp_port }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">客户端数</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.connected_clients }}</div>
                   </td>
                 </tr>
                 <tr>
@@ -42,25 +42,25 @@
                     <div class="cell">运行时间(天)</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.uptime_in_days }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">使用内存</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.used_memory_human }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">使用CPU</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div>
+                    <div v-if="cache.info" class="cell">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">内存配置</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.maxmemory_human }}</div>
                   </td>
                 </tr>
                 <tr>
@@ -68,25 +68,25 @@
                     <div class="cell">AOF是否开启</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.aof_enabled === "0" ? "否" : "是" }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.aof_enabled === '0' ? '否' : '是' }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">RDB是否成功</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div>
+                    <div v-if="cache.info" class="cell">{{ cache.info.rdb_last_bgsave_status }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">Key数量</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.dbSize">{{ cache.dbSize }}</div>
+                    <div v-if="cache.dbSize" class="cell">{{ cache.dbSize }}</div>
                   </td>
                   <td class="el-table__cell is-leaf">
                     <div class="cell">网络入口/出口</div>
                   </td>
                   <td class="el-table__cell is-leaf">
-                    <div class="cell" v-if="cache.info">
+                    <div v-if="cache.info" class="cell">
                       {{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps
                     </div>
                   </td>
@@ -100,8 +100,8 @@
       <el-col :span="12" class="card-box">
         <el-card shadow="hover">
           <template #header>
-            <PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
-            <span style="vertical-align: middle;">命令统计</span>
+            <PieChart style="width: 1em; height: 1em; vertical-align: middle" />
+            <span style="vertical-align: middle">命令统计</span>
           </template>
           <div class="el-table el-table--enable-row-hover el-table--medium">
             <div ref="commandstats" style="height: 420px" />
@@ -112,7 +112,7 @@
       <el-col :span="12" class="card-box">
         <el-card shadow="hover">
           <template #header>
-            <Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
+            <Odometer style="width: 1em; height: 1em; vertical-align: middle" /> <span style="vertical-align: middle">内存信息</span>
           </template>
           <div class="el-table el-table--enable-row-hover el-table--medium">
             <div ref="usedmemory" style="height: 420px" />
@@ -133,38 +133,38 @@ const usedmemory = ref();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const getList = async () => {
-  proxy?.$modal.loading("正在加载缓存监控数据,请稍候!");
+  proxy?.$modal.loading('正在加载缓存监控数据,请稍候!');
   const res = await getCache();
   proxy?.$modal.closeLoading();
   cache.value = res.data;
-  const commandstatsIntance = echarts.init(commandstats.value, "macarons");
+  const commandstatsIntance = echarts.init(commandstats.value, 'macarons');
   commandstatsIntance.setOption({
     tooltip: {
-      trigger: "item",
-      formatter: "{a} <br/>{b} : {c} ({d}%)"
+      trigger: 'item',
+      formatter: '{a} <br/>{b} : {c} ({d}%)'
     },
     series: [
       {
-        name: "命令",
-        type: "pie",
-        roseType: "radius",
+        name: '命令',
+        type: 'pie',
+        roseType: 'radius',
         radius: [15, 95],
-        center: ["50%", "38%"],
+        center: ['50%', '38%'],
         data: res.data.commandStats,
-        animationEasing: "cubicInOut",
+        animationEasing: 'cubicInOut',
         animationDuration: 1000
       }
     ]
   });
-  const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
+  const usedmemoryInstance = echarts.init(usedmemory.value, 'macarons');
   usedmemoryInstance.setOption({
     tooltip: {
-      formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human
+      formatter: '{b} <br/>{a} : ' + cache.value.info.used_memory_human
     },
     series: [
       {
-        name: "峰值",
-        type: "gauge",
+        name: '峰值',
+        type: 'gauge',
         min: 0,
         max: 1000,
         detail: {
@@ -173,19 +173,19 @@ const getList = async () => {
         data: [
           {
             value: parseFloat(cache.value.info.used_memory_human),
-            name: "内存消耗"
+            name: '内存消耗'
           }
         ]
       }
     ]
-  })
-  window.addEventListener("resize",()=>{
-    commandstatsIntance.resize()
-    usedmemoryInstance.resize()
   });
-}
+  window.addEventListener('resize', () => {
+    commandstatsIntance.resize();
+    usedmemoryInstance.resize();
+  });
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 73 - 69
src/views/monitor/logininfor/index.vue

@@ -1,14 +1,14 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="登录地址" prop="ipaddr">
-              <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
+              <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item label="用户名称" prop="userName">
-              <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px;" @keyup.enter="handleQuery" />
+              <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item label="状态" prop="status">
               <el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
@@ -39,22 +39,22 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']">
+            <el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">清空</el-button>
+            <el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" @click="handleClean">清空</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']">
+            <el-button v-hasPermi="['monitor:logininfor:unlock']" type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock">
               解锁
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导出</el-button>
+            <el-button v-hasPermi="['monitor:logininfor:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
@@ -62,8 +62,8 @@
         ref="loginInfoTableRef"
         v-loading="loading"
         :data="loginInfoList"
-        @selection-change="handleSelectionChange"
         :default-sort="defaultSort"
+        @selection-change="handleSelectionChange"
         @sort-change="handleSortChange"
       >
         <el-table-column type="selection" width="55" align="center" />
@@ -99,18 +99,18 @@
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
   </div>
 </template>
 
 <script setup name="Logininfor" lang="ts">
-import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
-import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
+import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from '@/api/monitor/loginInfo';
+import { LoginInfoQuery, LoginInfoVO } from '@/api/monitor/loginInfo/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
-const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
+const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
+const { sys_common_status } = toRefs<any>(proxy?.useDict('sys_common_status'));
 
 const loginInfoList = ref<LoginInfoVO[]>([]);
 const loading = ref(true);
@@ -120,85 +120,89 @@ const single = ref(true);
 const multiple = ref(true);
 const selectName = ref<Array<string>>([]);
 const total = ref(0);
-const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
-const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
+const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
+const defaultSort = ref<any>({ prop: 'loginTime', order: 'descending' });
 
 const queryFormRef = ref<ElFormInstance>();
 const loginInfoTableRef = ref<ElTableInstance>();
 // 查询参数
 const queryParams = ref<LoginInfoQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    ipaddr: '',
-    userName: '',
-    status: '',
-    orderByColumn: defaultSort.value.prop,
-    isAsc: defaultSort.value.order
+  pageNum: 1,
+  pageSize: 10,
+  ipaddr: '',
+  userName: '',
+  status: '',
+  orderByColumn: defaultSort.value.prop,
+  isAsc: defaultSort.value.order
 });
 
 /** 查询登录日志列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
-    loginInfoList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
-}
+  loading.value = true;
+  const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
+  loginInfoList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
-}
+  queryParams.value.pageNum = 1;
+  getList();
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
-    dateRange.value = ['', ''];
-    queryFormRef.value?.resetFields();
-    queryParams.value.pageNum = 1;
-    loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
-}
+  dateRange.value = ['', ''];
+  queryFormRef.value?.resetFields();
+  queryParams.value.pageNum = 1;
+  loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: LoginInfoVO[]) => {
-    ids.value = selection.map(item => item.infoId);
-    multiple.value = !selection.length;
-    single.value = selection.length != 1;
-    selectName.value = selection.map(item => item.userName);
-}
+  ids.value = selection.map((item) => item.infoId);
+  multiple.value = !selection.length;
+  single.value = selection.length != 1;
+  selectName.value = selection.map((item) => item.userName);
+};
 /** 排序触发事件 */
 const handleSortChange = (column: any) => {
-    queryParams.value.orderByColumn = column.prop;
-    queryParams.value.isAsc = column.order;
-    getList();
-}
+  queryParams.value.orderByColumn = column.prop;
+  queryParams.value.isAsc = column.order;
+  getList();
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: LoginInfoVO) => {
-    const infoIds = row?.infoId || ids.value;
-    await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
-    await delLoginInfo(infoIds);
-    await getList();
-    proxy?.$modal.msgSuccess("删除成功");
-}
+  const infoIds = row?.infoId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
+  await delLoginInfo(infoIds);
+  await getList();
+  proxy?.$modal.msgSuccess('删除成功');
+};
 /** 清空按钮操作 */
 const handleClean = async () => {
-    await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
-    await cleanLoginInfo();
-    await getList();
-    proxy?.$modal.msgSuccess("清空成功");
-}
+  await proxy?.$modal.confirm('是否确认清空所有登录日志数据项?');
+  await cleanLoginInfo();
+  await getList();
+  proxy?.$modal.msgSuccess('清空成功');
+};
 /** 解锁按钮操作 */
 const handleUnlock = async () => {
-    const username = selectName.value;
-    await proxy?.$modal.confirm('是否确认解锁用户"' + username + '"数据项?');
-    await unlockLoginInfo(username);
-    proxy?.$modal.msgSuccess("用户" + username + "解锁成功");
-}
+  const username = selectName.value;
+  await proxy?.$modal.confirm('是否确认解锁用户"' + username + '"数据项?');
+  await unlockLoginInfo(username);
+  proxy?.$modal.msgSuccess('用户' + username + '解锁成功');
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-    proxy?.download("monitor/logininfor/export", {
-        ...queryParams.value,
-    }, `config_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'monitor/logininfor/export',
+    {
+      ...queryParams.value
+    },
+    `config_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
-    getList();
-})
+  getList();
+});
 </script>

+ 9 - 9
src/views/monitor/online/index.vue

@@ -2,7 +2,7 @@
   <div class="p-2">
     <div class="mb-[10px]">
       <el-card shadow="hover">
-        <el-form :model="queryParams" ref="queryFormRef" :inline="true">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true">
           <el-form-item label="登录地址" prop="ipaddr">
             <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
           </el-form-item>
@@ -20,7 +20,7 @@
       <el-table
         v-loading="loading"
         :data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
-        style="width: 100%;"
+        style="width: 100%"
       >
         <el-table-column label="序号" width="50" type="index" align="center">
           <template #default="scope">
@@ -48,14 +48,14 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="强退" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']">
+              <el-button v-hasPermi="['monitor:online:forceLogout']" link type="primary" icon="Delete" @click="handleForceLogout(scope.row)">
               </el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" />
     </el-card>
   </div>
 </template>
@@ -67,7 +67,7 @@ import api from "@/api/system/user";
 import {to} from "await-to-js";
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
+const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
 
 const onlineList = ref<OnlineVO[]>([]);
 const loading = ref(true);
@@ -89,17 +89,17 @@ const getList = async () => {
   onlineList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 强退按钮操作 */
 const handleForceLogout = async (row: OnlineVO) => {
   const [err] = await to(proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?') as any);
@@ -112,5 +112,5 @@ const handleForceLogout = async (row: OnlineVO) => {
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 38 - 35
src/views/monitor/operlog/index.vue

@@ -3,15 +3,15 @@
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="操作地址" prop="operIp">
-              <el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable style="width: 240px;" @keyup.enter="handleQuery"/>
+              <el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item label="系统模块" prop="title">
-              <el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
+              <el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item label="操作人员" prop="operName">
-              <el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" @keyup.enter="handleQuery" />
+              <el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item label="类型" prop="businessType">
               <el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
@@ -47,17 +47,17 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:operlog:remove']">
+            <el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="WarnTriangleFilled" @click="handleClean" v-hasPermi="['monitor:operlog:remove']">清空</el-button>
+            <el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="WarnTriangleFilled" @click="handleClean">清空</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:operlog:export']">导出</el-button>
+            <el-button v-hasPermi="['monitor:operlog:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
@@ -65,8 +65,8 @@
         ref="operLogTableRef"
         v-loading="loading"
         :data="operlogList"
-        @selection-change="handleSelectionChange"
         :default-sort="defaultSort"
+        @selection-change="handleSelectionChange"
         @sort-change="handleSortChange"
       >
         <el-table-column type="selection" width="50" align="center" />
@@ -114,20 +114,20 @@
         <el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="详细" placement="top">
-              <el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:operlog:query']"> </el-button>
+              <el-button v-hasPermi="['monitor:operlog:query']" link type="primary" icon="View" @click="handleView(scope.row)"> </el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 操作日志详细 -->
-    <el-dialog title="操作日志详细" v-model="dialog.visible" width="700px" append-to-body>
+    <el-dialog v-model="dialog.visible" title="操作日志详细" width="700px" append-to-body>
       <el-form :model="form" label-width="100px">
         <el-row>
           <el-col :span="24">
-            <el-form-item label="登录信息:">{{ form.operName }} / {{form.deptName}} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
+            <el-form-item label="登录信息:">{{ form.operName }} / {{ form.deptName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="请求信息:">{{ form.requestMethod }} {{ form.operUrl }}</el-form-item>
@@ -157,7 +157,7 @@
             <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
           </el-col>
           <el-col :span="24">
-            <el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
+            <el-form-item v-if="form.status === 1" label="异常信息:">{{ form.errorMsg }}</el-form-item>
           </el-col>
         </el-row>
       </el-form>
@@ -175,7 +175,7 @@ import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
 import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type", "sys_common_status"));
+const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict('sys_oper_type', 'sys_common_status'));
 
 const operlogList = ref<OperLogVO[]>([]);
 const loading = ref(true);
@@ -184,7 +184,7 @@ const ids = ref<Array<number | string>>([]);
 const multiple = ref(true);
 const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
+const defaultSort = ref<any>({ prop: 'operTime', order: 'descending' });
 
 const operLogTableRef = ref<ElTableInstance>();
 const queryFormRef = ref<ElFormInstance>();
@@ -194,7 +194,6 @@ const dialog = reactive<DialogOption>({
   title: ''
 });
 
-
 const data = reactive<PageData<OperLogForm, OperLogQuery>>({
   form: {
     operId: undefined,
@@ -240,63 +239,67 @@ const getList = async () => {
   operlogList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 操作日志类型字典翻译 */
 const typeFormat = (row: OperLogForm) => {
   return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   queryParams.value.pageNum = 1;
   operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: OperLogVO[]) => {
-  ids.value = selection.map(item => item.operId);
+  ids.value = selection.map((item) => item.operId);
   multiple.value = !selection.length;
-}
+};
 /** 排序触发事件 */
 const handleSortChange = (column: any) => {
   queryParams.value.orderByColumn = column.prop;
   queryParams.value.isAsc = column.order;
   getList();
-}
+};
 /** 详细按钮操作 */
 const handleView = (row: OperLogVO) => {
   dialog.visible = true;
   form.value = row;
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: OperLogVO) => {
   const operIds = row?.operId || ids.value;
   await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
   await delOperlog(operIds);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 /** 清空按钮操作 */
 const handleClean = async () => {
-  await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
+  await proxy?.$modal.confirm('是否确认清空所有操作日志数据项?');
   await cleanOperlog();
   await getList();
-  proxy?.$modal.msgSuccess("清空成功");
-}
+  proxy?.$modal.msgSuccess('清空成功');
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("monitor/operlog/export", {
-    ...queryParams.value,
-  }, `config_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'monitor/operlog/export',
+    {
+      ...queryParams.value
+    },
+    `config_${new Date().getTime()}.xlsx`
+  );
+};
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 4 - 4
src/views/redirect/index.vue

@@ -3,12 +3,12 @@
 </template>
 
 <script setup>
-import { useRoute, useRouter } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router';
 
 const route = useRoute();
 const router = useRouter();
-const { params, query } = route
-const { path } = params
+const { params, query } = route;
+const { path } = params;
 
-router.replace({ path: '/' + path, query })
+router.replace({ path: '/' + path, query });
 </script>

+ 31 - 34
src/views/register.vue

@@ -2,7 +2,7 @@
   <div class="register">
     <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
       <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3>
-      <el-form-item prop="tenantId" v-if="tenantEnabled">
+      <el-form-item v-if="tenantEnabled" prop="tenantId">
         <el-select v-model="registerForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%">
           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
@@ -30,20 +30,20 @@
           <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
         </el-input>
       </el-form-item>
-      <el-form-item prop="code" v-if="captchaEnabled">
-        <el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
+      <el-form-item v-if="captchaEnabled" prop="code">
+        <el-input v-model="registerForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleRegister">
           <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
         </el-input>
         <div class="register-code">
-          <img :src="codeUrl" @click="getCode" class="register-code-img" />
+          <img :src="codeUrl" class="register-code-img" @click="getCode" />
         </div>
       </el-form-item>
-      <el-form-item style="width:100%;">
-        <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister">
+      <el-form-item style="width: 100%">
+        <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleRegister">
           <span v-if="!loading">注 册</span>
           <span v-else>注 册 中...</span>
         </el-button>
-        <div style="float: right;">
+        <div style="float: right">
           <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
         </div>
       </el-form-item>
@@ -63,46 +63,43 @@ import { to } from 'await-to-js';
 const router = useRouter();
 
 const registerForm = ref<RegisterForm>({
-  tenantId: "",
-  username: "",
-  password: "",
-  confirmPassword: "",
-  code: "",
-  uuid: "",
-  userType: "sys_user"
+  tenantId: '',
+  username: '',
+  password: '',
+  confirmPassword: '',
+  code: '',
+  uuid: '',
+  userType: 'sys_user'
 });
 
 // 租户开关
 const tenantEnabled = ref(true);
 
-
 const equalToPassword = (rule: any, value: string, callback: any) => {
   if (registerForm.value.password !== value) {
-    callback(new Error("两次输入的密码不一致"));
+    callback(new Error('两次输入的密码不一致'));
   } else {
     callback();
   }
 };
 
 const registerRules: ElFormRules = {
-  tenantId: [
-    { required: true, trigger: "blur", message: "请输入您的租户编号" }
-  ],
+  tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
   username: [
-    { required: true, trigger: "blur", message: "请输入您的账号" },
-    { min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
+    { required: true, trigger: 'blur', message: '请输入您的账号' },
+    { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
   ],
   password: [
-    { required: true, trigger: "blur", message: "请输入您的密码" },
-    { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }
+    { required: true, trigger: 'blur', message: '请输入您的密码' },
+    { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
   ],
   confirmPassword: [
-    { required: true, trigger: "blur", message: "请再次输入您的密码" },
-    { required: true, validator: equalToPassword, trigger: "blur" }
+    { required: true, trigger: 'blur', message: '请再次输入您的密码' },
+    { required: true, validator: equalToPassword, trigger: 'blur' }
   ],
-  code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+  code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
 };
-const codeUrl = ref("");
+const codeUrl = ref('');
 const loading = ref(false);
 const captchaEnabled = ref(true);
 const registerRef = ref<ElFormInstance>();
@@ -116,11 +113,11 @@ const handleRegister = () => {
       const [err] = await to(register(registerForm.value));
       if (!err) {
         const username = registerForm.value.username;
-        await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
+        await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + ' 注册成功!</font>', '系统提示', {
           dangerouslyUseHTMLString: true,
-          type: "success",
+          type: 'success'
         });
-        await router.push("/login");
+        await router.push('/login');
       } else {
         loading.value = false;
         if (captchaEnabled) {
@@ -129,7 +126,7 @@ const handleRegister = () => {
       }
     }
   });
-}
+};
 
 const getCode = async () => {
   const res = await getCodeImg();
@@ -150,12 +147,12 @@ const initTenantList = async () => {
       registerForm.value.tenantId = tenantList.value[0].tenantId;
     }
   }
-}
+};
 
 onMounted(() => {
   getCode();
   initTenantList();
-})
+});
 </script>
 
 <style lang="scss" scoped>
@@ -164,7 +161,7 @@ onMounted(() => {
   justify-content: center;
   align-items: center;
   height: 100%;
-  background-image: url("../assets/images/login-background.jpg");
+  background-image: url('../assets/images/login-background.jpg');
   background-size: cover;
 }
 

+ 58 - 66
src/views/system/client/index.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="search" v-show="showSearch">
-        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
+      <div v-show="showSearch" class="search">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
           <el-form-item label="客户端key" prop="clientKey">
             <el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable style="width: 240px" @keyup.enter="handleQuery" />
           </el-form-item>
@@ -26,28 +26,28 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:client:add']">新增</el-button>
+            <el-button v-hasPermi="['system:client:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:client:edit']">
+            <el-button v-hasPermi="['system:client:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
               修改
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:client:remove']">
+            <el-button v-hasPermi="['system:client:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:client:export']">导出</el-button>
+            <el-button v-hasPermi="['system:client:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="id" align="center" prop="id" v-if="true" />
+        <el-table-column v-if="true" label="id" align="center" prop="id" />
         <el-table-column label="客户端id" align="center" prop="clientId" />
         <el-table-column label="客户端key" align="center" prop="clientKey" />
         <el-table-column label="客户端秘钥" align="center" prop="clientSecret" />
@@ -63,7 +63,7 @@
         </el-table-column>
         <el-table-column label="Token活跃超时时间" align="center" prop="activeTimeout" />
         <el-table-column label="Token固定超时时间" align="center" prop="timeout" />
-        <el-table-column label="状态" align="center" key="status">
+        <el-table-column key="status" label="状态" align="center">
           <template #default="scope">
             <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
           </template>
@@ -71,19 +71,19 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:client:edit']"></el-button>
+              <el-button v-hasPermi="['system:client:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:client:remove']"></el-button>
+              <el-button v-hasPermi="['system:client:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改客户端管理对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="clientFormRef" :model="form" :rules="rules" label-width="100px">
         <el-form-item label="客户端key" prop="clientKey">
           <el-input v-model="form.clientKey" :disabled="form.id != null" placeholder="请输入客户端key" />
@@ -146,9 +146,9 @@ import { listClient, getClient, delClient, addClient, updateClient, changeStatus
 import { ClientVO, ClientQuery, ClientForm } from '@/api/system/client/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
-const { sys_grant_type } = toRefs<any>(proxy?.useDict("sys_grant_type"));
-const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
+const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
+const { sys_grant_type } = toRefs<any>(proxy?.useDict('sys_grant_type'));
+const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
 
 const clientList = ref<ClientVO[]>([]);
 const buttonLoading = ref(false);
@@ -176,10 +176,10 @@ const initFormData: ClientForm = {
   deviceType: undefined,
   activeTimeout: undefined,
   timeout: undefined,
-  status: undefined,
-}
+  status: undefined
+};
 const data = reactive<PageData<ClientForm, ClientQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
@@ -190,27 +190,15 @@ const data = reactive<PageData<ClientForm, ClientQuery>>({
     deviceType: undefined,
     activeTimeout: undefined,
     timeout: undefined,
-    status: undefined,
+    status: undefined
   },
   rules: {
-    id: [
-      { required: true, message: "id不能为空", trigger: "blur" }
-    ],
-    clientId: [
-      { required: true, message: "客户端id不能为空", trigger: "blur" }
-    ],
-    clientKey: [
-      { required: true, message: "客户端key不能为空", trigger: "blur" }
-    ],
-    clientSecret: [
-      { required: true, message: "客户端秘钥不能为空", trigger: "blur" }
-    ],
-    grantTypeList: [
-      { required: true, message: "授权类型不能为空", trigger: "change" }
-    ],
-    deviceType: [
-      { required: true, message: "设备类型不能为空", trigger: "change" }
-    ],
+    id: [{ required: true, message: 'id不能为空', trigger: 'blur' }],
+    clientId: [{ required: true, message: '客户端id不能为空', trigger: 'blur' }],
+    clientKey: [{ required: true, message: '客户端key不能为空', trigger: 'blur' }],
+    clientSecret: [{ required: true, message: '客户端秘钥不能为空', trigger: 'blur' }],
+    grantTypeList: [{ required: true, message: '授权类型不能为空', trigger: 'change' }],
+    deviceType: [{ required: true, message: '设备类型不能为空', trigger: 'change' }]
   }
 });
 
@@ -223,55 +211,55 @@ const getList = async () => {
   clientList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
+  form.value = { ...initFormData };
   clientFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: ClientVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加客户端管理";
-}
+  dialog.title = '添加客户端管理';
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: ClientVO) => {
   reset();
-  const _id = row?.id || ids.value[0]
+  const _id = row?.id || ids.value[0];
   const res = await getClient(_id);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改客户端管理";
-}
+  dialog.title = '修改客户端管理';
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -279,44 +267,48 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateClient(form.value).finally(() =>  buttonLoading.value = false);
+        await updateClient(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addClient(form.value).finally(() =>  buttonLoading.value = false);
+        await addClient(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("修改成功");
+      proxy?.$modal.msgSuccess('修改成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: ClientVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除客户端管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await proxy?.$modal.confirm('是否确认删除客户端管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
   await delClient(_ids);
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   await getList();
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('system/client/export', {
-    ...queryParams.value
-  }, `client_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'system/client/export',
+    {
+      ...queryParams.value
+    },
+    `client_${new Date().getTime()}.xlsx`
+  );
+};
 
 /** 状态修改  */
 const handleStatusChange = async (row: ClientVO) => {
-  let text = row.status === "0" ? "启用" : "停用"
+  let text = row.status === '0' ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '"吗?');
     await changeStatus(row.id, row.status);
-    proxy?.$modal.msgSuccess(text + "成功");
+    proxy?.$modal.msgSuccess(text + '成功');
   } catch (err) {
-    row.status = row.status === "0" ? "1" : "0";
+    row.status = row.status === '0' ? '1' : '0';
   }
-}
+};
 
 onMounted(() => {
   getList();

+ 49 - 45
src/views/system/config/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="参数名称" prop="configName">
               <el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -15,7 +15,7 @@
                 <el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
-            <el-form-item label="创建时间" style="width: 308px;">
+            <el-form-item label="创建时间" style="width: 308px">
               <el-date-picker
                 v-model="dateRange"
                 value-format="YYYY-MM-DD HH:mm:ss"
@@ -38,31 +38,31 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:config:add']">新增</el-button>
+            <el-button v-hasPermi="['system:config:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:config:edit']">
+            <el-button v-hasPermi="['system:config:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
               修改
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:config:remove']">
+            <el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:config:export']">导出</el-button>
+            <el-button v-hasPermi="['system:config:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:config:remove']">刷新缓存</el-button>
+            <el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="参数主键" align="center" prop="configId" v-if="false" />
+        <el-table-column v-if="false" label="参数主键" align="center" prop="configId" />
         <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
         <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
         <el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
@@ -80,19 +80,19 @@
         <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']"></el-button>
+              <el-button v-hasPermi="['system:config:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']"></el-button>
+              <el-button v-hasPermi="['system:config:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
 
     <!-- 添加或修改参数配置对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="configFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="参数名称" prop="configName">
           <el-input v-model="form.configName" placeholder="请输入参数名称" />
@@ -123,11 +123,11 @@
 </template>
 
 <script setup name="Config" lang="ts">
-import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
-import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from '@/api/system/config';
+import { ConfigForm, ConfigQuery, ConfigVO } from '@/api/system/config/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
+const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no'));
 
 const configList = ref<ConfigVO[]>([]);
 const loading = ref(true);
@@ -149,9 +149,9 @@ const initFormData: ConfigForm = {
   configName: '',
   configKey: '',
   configValue: '',
-  configType: "Y",
+  configType: 'Y',
   remark: ''
-}
+};
 const data = reactive<PageData<ConfigForm, ConfigQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -159,12 +159,12 @@ const data = reactive<PageData<ConfigForm, ConfigQuery>>({
     pageSize: 10,
     configName: '',
     configKey: '',
-    configType: '',
+    configType: ''
   },
   rules: {
-    configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
-    configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
-    configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
+    configName: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
+    configKey: [{ required: true, message: '参数键名不能为空', trigger: 'blur' }],
+    configValue: [{ required: true, message: '参数键值不能为空', trigger: 'blur' }]
   }
 });
 
@@ -177,40 +177,40 @@ const getList = async () => {
   configList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   configFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: ConfigVO[]) => {
-  ids.value = selection.map(item => item.configId);
+  ids.value = selection.map((item) => item.configId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加参数";
-}
+  dialog.title = '添加参数';
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: ConfigVO) => {
   reset();
@@ -218,40 +218,44 @@ const handleUpdate = async (row?: ConfigVO) => {
   const res = await getConfig(configId);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改参数";
-}
+  dialog.title = '修改参数';
+};
 /** 提交按钮 */
 const submitForm = () => {
   configFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: ConfigVO) => {
   const configIds = row?.configId || ids.value;
   await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
   await delConfig(configIds);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/config/export", {
-    ...queryParams.value
-  }, `config_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'system/config/export',
+    {
+      ...queryParams.value
+    },
+    `config_${new Date().getTime()}.xlsx`
+  );
+};
 /** 刷新缓存按钮操作 */
 const handleRefreshCache = async () => {
   await refreshCache();
-  proxy?.$modal.msgSuccess("刷新缓存成功");
-}
+  proxy?.$modal.msgSuccess('刷新缓存成功');
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 62 - 64
src/views/system/dept/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="部门名称" prop="deptName">
@@ -25,21 +25,21 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">新增 </el-button>
+            <el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table
+        ref="deptTableRef"
         v-loading="loading"
         :data="deptList"
         row-key="deptId"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
-        ref="deptTableRef"
         :default-expand-all="isExpandAll"
       >
         <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
@@ -57,23 +57,23 @@
         <el-table-column fixed="right" align="center" label="操作">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" />
+              <el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
             </el-tooltip>
             <el-tooltip content="新增" placement="top">
-              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" />
+              <el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" />
+              <el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
     </el-card>
 
-    <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="600px">
+    <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="600px">
       <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
         <el-row>
-          <el-col :span="24" v-if="form.parentId !== 0">
+          <el-col v-if="form.parentId !== 0" :span="24">
             <el-form-item label="上级部门" prop="parentId">
               <el-tree-select
                 v-model="form.parentId"
@@ -115,8 +115,7 @@
           <el-col :span="12">
             <el-form-item label="部门状态">
               <el-radio-group v-model="form.status">
-                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label
-                }}</el-radio>
+                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -133,26 +132,25 @@
 </template>
 
 <script setup name="Dept" lang="ts">
-import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
-import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
-import {UserVO} from "@/api/system/user/types";
-import {listUserByDeptId} from "@/api/system/user";
+import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from '@/api/system/dept';
+import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types';
+import { UserVO } from '@/api/system/user/types';
+import { listUserByDeptId } from '@/api/system/user';
 
 interface DeptOptionsType {
   deptId: number | string;
   deptName: string;
   children: DeptOptionsType[];
-
 }
 
-const { proxy } = getCurrentInstance() as ComponentInternalInstance
-const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
-const deptList = ref<DeptVO[]>([])
-const loading = ref(true)
-const showSearch = ref(true)
-const deptOptions = ref<DeptOptionsType[]>([])
-const isExpandAll = ref(true)
+const deptList = ref<DeptVO[]>([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const deptOptions = ref<DeptOptionsType[]>([]);
+const isExpandAll = ref(true);
 const deptUserList = ref<UserVO[]>([]);
 
 const dialog = reactive<DialogOption>({
@@ -172,8 +170,8 @@ const initFormData: DeptForm = {
   leader: undefined,
   phone: undefined,
   email: undefined,
-  status: "0"
-}
+  status: '0'
+};
 const data = reactive<PageData<DeptForm, DeptQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -183,30 +181,30 @@ const data = reactive<PageData<DeptForm, DeptQuery>>({
     status: undefined
   },
   rules: {
-    parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
-    deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
-    orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
-    email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
-    phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
-  },
-})
+    parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
+    deptName: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
+    orderNum: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
+    email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
+    phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }]
+  }
+});
 
-const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data)
+const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data);
 
 /** 查询菜单列表 */
 const getList = async () => {
   loading.value = true;
   const res = await listDept(queryParams.value);
-  const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
+  const data = proxy?.handleTree<DeptVO>(res.data, 'deptId');
   if (data) {
-    deptList.value = data
+    deptList.value = data;
   }
-  loading.value = false
-}
+  loading.value = false;
+};
 
 /** 查询当前部门的所有用户 */
 async function getDeptAllUser(deptId: any) {
-  if (deptId !== null && deptId !== "" && deptId !== undefined) {
+  if (deptId !== null && deptId !== '' && deptId !== undefined) {
     const res = await listUserByDeptId(deptId);
     deptUserList.value = res.data;
   }
@@ -214,52 +212,52 @@ async function getDeptAllUser(deptId: any) {
 
 /** 取消按钮 */
 const cancel = () => {
-  reset()
-  dialog.visible = false
-}
+  reset();
+  dialog.visible = false;
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   deptFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
-  handleQuery()
-}
+  handleQuery();
+};
 
 /** 展开/折叠操作 */
 const handleToggleExpandAll = () => {
   isExpandAll.value = !isExpandAll.value;
-  toggleExpandAll(deptList.value, isExpandAll.value)
-}
+  toggleExpandAll(deptList.value, isExpandAll.value);
+};
 /** 展开/折叠所有 */
 const toggleExpandAll = (data: DeptVO[], status: boolean) => {
   data.forEach((item) => {
-    deptTableRef.value?.toggleRowExpansion(item, status)
-    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
-  })
-}
+    deptTableRef.value?.toggleRowExpansion(item, status);
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
+  });
+};
 
 /** 新增按钮操作 */
 const handleAdd = async (row?: DeptVO) => {
   reset();
   const res = await listDept();
-  const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
+  const data = proxy?.handleTree<DeptOptionsType>(res.data, 'deptId');
   if (data) {
-    deptOptions.value = data
+    deptOptions.value = data;
     if (row && row.deptId) {
       form.value.parentId = row?.deptId;
     }
     dialog.visible = true;
-    dialog.title = "添加部门";
+    dialog.title = '添加部门';
   }
-}
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row: DeptVO) => {
@@ -267,9 +265,9 @@ const handleUpdate = async (row: DeptVO) => {
   //查询当前部门所有用户
   getDeptAllUser(row.deptId);
   const res = await getDept(row.deptId);
-  form.value = res.data
+  form.value = res.data;
   const response = await listDeptExcludeChild(row.deptId);
-  const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
+  const data = proxy?.handleTree<DeptOptionsType>(response.data, 'deptId');
   if (data) {
     deptOptions.value = data;
     if (data.length === 0) {
@@ -282,26 +280,26 @@ const handleUpdate = async (row: DeptVO) => {
     }
   }
   dialog.visible = true;
-  dialog.title = "修改部门";
-}
+  dialog.title = '修改部门';
+};
 /** 提交按钮 */
 const submitForm = () => {
   deptFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
-  })
-}
+  });
+};
 /** 删除按钮操作 */
 const handleDelete = async (row: DeptVO) => {
   await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
   await delDept(row.deptId);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();

+ 60 - 59
src/views/system/dict/data.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="字典名称" prop="dictType">
               <el-select v-model="queryParams.dictType" style="width: 200px">
                 <el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" />
@@ -24,29 +24,29 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
+            <el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
+            <el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
+            <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
+            <el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
+        <el-table-column v-if="false" label="字典编码" align="center" prop="dictCode" />
         <el-table-column label="字典标签" align="center" prop="dictLabel">
           <template #default="scope">
             <span v-if="(scope.row.listClass === '' || scope.row.listClass === 'default') && (scope.row.cssClass === '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
@@ -64,19 +64,19 @@
         <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
+              <el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
+              <el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改参数配置对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="字典类型">
           <el-input v-model="form.dictType" :disabled="true" />
@@ -118,13 +118,13 @@
 </template>
 
 <script setup name="Data" lang="ts">
-import useDictStore from '@/store/modules/dict'
-import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
-import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
+import useDictStore from '@/store/modules/dict';
+import { optionselect as getDictOptionselect, getType } from '@/api/system/dict/type';
+import { listData, getData, delData, addData, updateData } from '@/api/system/dict/data';
 import { DictTypeVO } from '@/api/system/dict/type/types';
-import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
+import { DictDataForm, DictDataQuery, DictDataVO } from '@/api/system/dict/data/types';
 
-const { proxy } = getCurrentInstance() as ComponentInternalInstance
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const route = useRoute();
 
 const dataList = ref<DictDataVO[]>([]);
@@ -134,26 +134,25 @@ const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
-const defaultDictType = ref("");
+const defaultDictType = ref('');
 const typeOptions = ref<DictTypeVO[]>([]);
 
 const dataFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
 
-
 const dialog = reactive<DialogOption>({
   visible: false,
   title: ''
 });
 
 // 数据标签回显样式
-const listClassOptions = ref<Array<{ value: string, label: string }>>([
-  { value: "default", label: "默认" },
-  { value: "primary", label: "主要" },
-  { value: "success", label: "成功" },
-  { value: "info", label: "信息" },
-  { value: "warning", label: "警告" },
-  { value: "danger", label: "危险" }
+const listClassOptions = ref<Array<{ value: string; label: string }>>([
+  { value: 'default', label: '默认' },
+  { value: 'primary', label: '主要' },
+  { value: 'success', label: '成功' },
+  { value: 'info', label: '信息' },
+  { value: 'warning', label: '警告' },
+  { value: 'danger', label: '危险' }
 ]);
 
 const initFormData: DictDataForm = {
@@ -161,10 +160,10 @@ const initFormData: DictDataForm = {
   dictLabel: '',
   dictValue: '',
   cssClass: '',
-  listClass: "default",
+  listClass: 'default',
   dictSort: 0,
   remark: ''
-}
+};
 const data = reactive<PageData<DictDataForm, DictDataQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -175,9 +174,9 @@ const data = reactive<PageData<DictDataForm, DictDataQuery>>({
     dictLabel: ''
   },
   rules: {
-    dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
-    dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
-    dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
+    dictLabel: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
+    dictValue: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }],
+    dictSort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }]
   }
 });
 
@@ -189,13 +188,13 @@ const getTypes = async (dictId: string | number) => {
   queryParams.value.dictType = data.dictType;
   defaultDictType.value = data.dictType;
   getList();
-}
+};
 
 /** 查询字典类型列表 */
 const getTypeList = async () => {
-  const res = await getDictOptionselect()
+  const res = await getDictOptionselect();
   typeOptions.value = res.data;
-}
+};
 /** 查询字典数据列表 */
 const getList = async () => {
   loading.value = true;
@@ -203,46 +202,46 @@ const getList = async () => {
   dataList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   dialog.visible = false;
   reset();
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   dataFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 返回按钮操作 */
 const handleClose = () => {
-  const obj = { path: "/system/dict" };
+  const obj = { path: '/system/dict' };
   proxy?.$tab.closeOpenPage(obj);
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   queryParams.value.dictType = defaultDictType.value;
   handleQuery();
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   form.value.dictType = queryParams.value.dictType;
   dialog.visible = true;
-  dialog.title = "添加字典数据";
-}
+  dialog.title = '添加字典数据';
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DictDataVO[]) => {
-  ids.value = selection.map(item => item.dictCode);
+  ids.value = selection.map((item) => item.dictCode);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: DictDataVO) => {
   reset();
@@ -250,40 +249,42 @@ const handleUpdate = async (row?: DictDataVO) => {
   const res = await getData(dictCode);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改字典数据";
-}
+  dialog.title = '修改字典数据';
+};
 /** 提交按钮 */
 const submitForm = () => {
   dataFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.dictCode ? await updateData(form.value) : await addData(form.value);
       useDictStore().removeDict(queryParams.value.dictType);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
-
     }
   });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: DictDataVO) => {
   const dictCodes = row?.dictCode || ids.value;
   await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
   await delData(dictCodes);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   useDictStore().removeDict(queryParams.value.dictType);
-
-}
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/dict/data/export", {
-    ...queryParams.value
-  }, `dict_data_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'system/dict/data/export',
+    {
+      ...queryParams.value
+    },
+    `dict_data_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
-  getTypes(route.params && route.params.dictId as string);
+  getTypes(route.params && (route.params.dictId as string));
   getTypeList();
-})
+});
 </script>

+ 47 - 44
src/views/system/dict/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="字典名称" prop="dictName">
               <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -33,29 +33,29 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button>
+            <el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">修改</el-button>
+            <el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']">
+            <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>
+            <el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">刷新缓存</el-button>
+            <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">刷新缓存</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="字典编号" align="center" prop="dictId" v-if="false" />
+        <el-table-column v-if="false" label="字典编号" align="center" prop="dictId" />
         <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
         <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
           <template #default="scope">
@@ -73,19 +73,19 @@
         <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button>
+              <el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button>
+              <el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改参数配置对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="字典名称" prop="dictName">
           <el-input v-model="form.dictName" placeholder="请输入字典名称" />
@@ -108,9 +108,9 @@
 </template>
 
 <script setup name="Dict" lang="ts">
-import useDictStore from '@/store/modules/dict'
-import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
-import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
+import useDictStore from '@/store/modules/dict';
+import { listType, getType, delType, addType, updateType, refreshCache } from '@/api/system/dict/type';
+import { DictTypeForm, DictTypeQuery, DictTypeVO } from '@/api/system/dict/type/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -126,7 +126,6 @@ const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const dictFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
 
-
 const dialog = reactive<DialogOption>({
   visible: false,
   title: ''
@@ -137,7 +136,7 @@ const initFormData: DictTypeForm = {
   dictName: '',
   dictType: '',
   remark: ''
-}
+};
 const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -147,9 +146,9 @@ const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
     dictType: ''
   },
   rules: {
-    dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
-    dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
-  },
+    dictName: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],
+    dictType: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
@@ -157,45 +156,45 @@ const { queryParams, form, rules } = toRefs(data);
 /** 查询字典类型列表 */
 const getList = () => {
   loading.value = true;
-  listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
+  listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
     typeList.value = res.rows;
     total.value = res.total;
     loading.value = false;
   });
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   dictFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加字典类型";
-}
+  dialog.title = '添加字典类型';
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DictTypeVO[]) => {
-  ids.value = selection.map(item => item.dictId);
+  ids.value = selection.map((item) => item.dictId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: DictTypeVO) => {
   reset();
@@ -203,41 +202,45 @@ const handleUpdate = async (row?: DictTypeVO) => {
   const res = await getType(dictId);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改字典类型";
-}
+  dialog.title = '修改字典类型';
+};
 /** 提交按钮 */
 const submitForm = () => {
   dictFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.dictId ? await updateType(form.value) : await addType(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       getList();
     }
   });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: DictTypeVO) => {
   const dictIds = row?.dictId || ids.value;
   await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
   await delType(dictIds);
   getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/dict/type/export", {
-    ...queryParams.value
-  }, `dict_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'system/dict/type/export',
+    {
+      ...queryParams.value
+    },
+    `dict_${new Date().getTime()}.xlsx`
+  );
+};
 /** 刷新缓存按钮操作 */
 const handleRefreshCache = async () => {
   await refreshCache();
-  proxy?.$modal.msgSuccess("刷新成功");
+  proxy?.$modal.msgSuccess('刷新成功');
   useDictStore().cleanDict();
-}
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 66 - 66
src/views/system/menu/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="菜单名称" prop="menuName">
@@ -25,21 +25,21 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:menu:add']">新增 </el-button>
+            <el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table
+        ref="menuTableRef"
         v-loading="loading"
         :data="menuList"
         row-key="menuId"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
-        ref="menuTableRef"
         :default-expand-all="isExpandAll"
       >
         <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
@@ -64,20 +64,20 @@
         <el-table-column fixed="right" label="操作" width="180">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']" />
+              <el-button v-hasPermi="['system:menu:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
             </el-tooltip>
             <el-tooltip content="新增" placement="top">
-              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']" />
+              <el-button v-hasPermi="['system:menu:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']" />
+              <el-button v-hasPermi="['system:menu:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
     </el-card>
 
-    <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="750px">
+    <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="750px">
       <el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px">
         <el-row>
           <el-col :span="24">
@@ -101,7 +101,7 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="24" v-if="form.menuType !== 'F'">
+          <el-col v-if="form.menuType !== 'F'" :span="24">
             <el-form-item label="菜单图标" prop="icon">
               <!-- 图标选择器 -->
               <icon-select v-model="form.icon" />
@@ -117,7 +117,7 @@
               <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType !== 'F'">
+          <el-col v-if="form.menuType !== 'F'" :span="12">
             <el-form-item>
               <template #label>
                 <span>
@@ -134,7 +134,7 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType !== 'F'">
+          <el-col v-if="form.menuType !== 'F'" :span="12">
             <el-form-item prop="path">
               <template #label>
                 <span>
@@ -149,7 +149,7 @@
               <el-input v-model="form.path" placeholder="请输入路由地址" />
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType === 'C'">
+          <el-col v-if="form.menuType === 'C'" :span="12">
             <el-form-item prop="component">
               <template #label>
                 <span>
@@ -164,7 +164,7 @@
               <el-input v-model="form.component" placeholder="请输入组件路径" />
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType !== 'M'">
+          <el-col v-if="form.menuType !== 'M'" :span="12">
             <el-form-item>
               <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
               <template #label>
@@ -179,7 +179,7 @@
               </template>
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType === 'C'">
+          <el-col v-if="form.menuType === 'C'" :span="12">
             <el-form-item>
               <el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
               <template #label>
@@ -194,7 +194,7 @@
               </template>
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType === 'C'">
+          <el-col v-if="form.menuType === 'C'" :span="12">
             <el-form-item>
               <template #label>
                 <span>
@@ -212,7 +212,7 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="12" v-if="form.menuType !== 'F'">
+          <el-col v-if="form.menuType !== 'F'" :span="12">
             <el-form-item>
               <template #label>
                 <span>
@@ -271,14 +271,14 @@ interface MenuOptionsType {
   children: MenuOptionsType[] | undefined;
 }
 
-const { proxy } = getCurrentInstance() as ComponentInternalInstance
-const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable"));
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable'));
 
-const menuList = ref<MenuVO[]>([])
-const loading = ref(true)
-const showSearch = ref(true)
-const menuOptions = ref<MenuOptionsType[]>([])
-const isExpandAll = ref(false)
+const menuList = ref<MenuVO[]>([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const menuOptions = ref<MenuOptionsType[]>([]);
+const isExpandAll = ref(false);
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -295,11 +295,11 @@ const initFormData = {
   icon: '',
   menuType: MenuTypeEnum.M,
   orderNum: 1,
-  isFrame: "1",
-  isCache: "0",
-  visible: "0",
-  status: "0"
-}
+  isFrame: '1',
+  isCache: '0',
+  visible: '0',
+  status: '0'
+};
 const data = reactive<PageData<MenuForm, MenuQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -307,73 +307,73 @@ const data = reactive<PageData<MenuForm, MenuQuery>>({
     status: undefined
   },
   rules: {
-    menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
-    orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
-    path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
-  },
-})
+    menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
+    orderNum: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }],
+    path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }]
+  }
+});
 
 const menuTableRef = ref<ElTableInstance>();
 
-const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
+const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data);
 /** 查询菜单列表 */
 const getList = async () => {
-  loading.value = true
+  loading.value = true;
   const res = await listMenu(queryParams.value);
-  const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
+  const data = proxy?.handleTree<MenuVO>(res.data, 'menuId');
   if (data) {
-    menuList.value = data
+    menuList.value = data;
   }
-  loading.value = false
-}
+  loading.value = false;
+};
 /** 查询菜单下拉树结构 */
 const getTreeselect = async () => {
-  menuOptions.value = []
+  menuOptions.value = [];
   const response = await listMenu();
-  const menu: MenuOptionsType = { menuId: 0, menuName: "主类目", children: [] }
-  menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId")
-  menuOptions.value.push(menu)
-}
+  const menu: MenuOptionsType = { menuId: 0, menuName: '主类目', children: [] };
+  menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId');
+  menuOptions.value.push(menu);
+};
 /** 取消按钮 */
 const cancel = () => {
-  reset()
-  dialog.visible = false
-}
+  reset();
+  dialog.visible = false;
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   menuFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 新增按钮操作 */
 const handleAdd = (row?: MenuVO) => {
   reset();
   getTreeselect();
-  row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
+  row && row.menuId ? (form.value.parentId = row.menuId) : (form.value.parentId = 0);
   dialog.visible = true;
-  dialog.title = "添加菜单";
-}
+  dialog.title = '添加菜单';
+};
 /** 展开/折叠操作 */
 const handleToggleExpandAll = () => {
   isExpandAll.value = !isExpandAll.value;
-  toggleExpandAll(menuList.value, isExpandAll.value)
-}
+  toggleExpandAll(menuList.value, isExpandAll.value);
+};
 /** 展开/折叠所有 */
 const toggleExpandAll = (data: MenuVO[], status: boolean) => {
   data.forEach((item: MenuVO) => {
-    menuTableRef.value?.toggleRowExpansion(item, status)
-    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
-  })
-}
+    menuTableRef.value?.toggleRowExpansion(item, status);
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
+  });
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row: MenuVO) => {
   reset();
@@ -383,26 +383,26 @@ const handleUpdate = async (row: MenuVO) => {
     form.value = data;
   }
   dialog.visible = true;
-  dialog.title = "修改菜单";
-}
+  dialog.title = '修改菜单';
+};
 /** 提交按钮 */
 const submitForm = () => {
   menuFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
-  })
-}
+  });
+};
 /** 删除按钮操作 */
 const handleDelete = async (row: MenuVO) => {
   await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
   await delMenu(row.menuId);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();

+ 37 - 39
src/views/system/notice/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="公告标题" prop="noticeTitle">
               <el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -28,25 +28,25 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
+            <el-button v-hasPermi="['system:notice:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']"
+            <el-button v-hasPermi="['system:notice:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
               >修改</el-button
             >
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']">
+            <el-button v-hasPermi="['system:notice:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="序号" align="center" prop="noticeId" width="100" v-if="false" />
+        <el-table-column v-if="false" label="序号" align="center" prop="noticeId" width="100" />
         <el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
         <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
           <template #default="scope">
@@ -67,19 +67,19 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button>
+              <el-button v-hasPermi="['system:notice:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button>
+              <el-button v-hasPermi="['system:notice:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改公告对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="780px" append-to-body>
       <el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px">
         <el-row>
           <el-col :span="12">
@@ -97,8 +97,7 @@
           <el-col :span="24">
             <el-form-item label="状态">
               <el-radio-group v-model="form.status">
-                <el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label
-                }}</el-radio>
+                <el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -120,11 +119,11 @@
 </template>
 
 <script setup name="Notice" lang="ts">
-import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
-import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
+import { listNotice, getNotice, delNotice, addNotice, updateNotice } from '@/api/system/notice';
+import { NoticeForm, NoticeQuery, NoticeVO } from '@/api/system/notice/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
+const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict('sys_notice_status', 'sys_notice_type'));
 
 const noticeList = ref<NoticeVO[]>([]);
 const loading = ref(true);
@@ -137,7 +136,6 @@ const total = ref(0);
 const queryFormRef = ref<ElFormInstance>();
 const noticeFormRef = ref<ElFormInstance>();
 
-
 const dialog = reactive<DialogOption>({
   visible: false,
   title: ''
@@ -148,10 +146,10 @@ const initFormData: NoticeForm = {
   noticeTitle: '',
   noticeType: '',
   noticeContent: '',
-  status: "0",
+  status: '0',
   remark: '',
   createByName: ''
-}
+};
 const data = reactive<PageData<NoticeForm, NoticeQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -163,9 +161,9 @@ const data = reactive<PageData<NoticeForm, NoticeQuery>>({
     noticeType: ''
   },
   rules: {
-    noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
-    noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
-  },
+    noticeTitle: [{ required: true, message: '公告标题不能为空', trigger: 'blur' }],
+    noticeType: [{ required: true, message: '公告类型不能为空', trigger: 'change' }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
@@ -177,39 +175,39 @@ const getList = async () => {
   noticeList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   noticeFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: NoticeVO[]) => {
-  ids.value = selection.map(item => item.noticeId);
+  ids.value = selection.map((item) => item.noticeId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加公告";
-}
+  dialog.title = '添加公告';
+};
 /**修改按钮操作 */
 const handleUpdate = async (row?: NoticeVO) => {
   reset();
@@ -217,29 +215,29 @@ const handleUpdate = async (row?: NoticeVO) => {
   const { data } = await getNotice(noticeId);
   Object.assign(form.value, data);
   dialog.visible = true;
-  dialog.title = "修改公告";
-}
+  dialog.title = '修改公告';
+};
 /** 提交按钮 */
 const submitForm = () => {
   noticeFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
-      proxy?.$modal.msgSuccess("修改成功");
+      proxy?.$modal.msgSuccess('修改成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: NoticeVO) => {
-  const noticeIds = row?.noticeId || ids.value
+  const noticeIds = row?.noticeId || ids.value;
   await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
   await delNotice(noticeIds);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 72 - 81
src/views/system/oss/config.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="配置key" prop="configKey">
               <el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -39,27 +39,27 @@
               删除
             </el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" />
-        <el-table-column label="配置key" align="center" prop="configKey" v-if="columns[1].visible" />
-        <el-table-column label="访问站点" align="center" prop="endpoint" v-if="columns[2].visible" width="200" />
-        <el-table-column label="自定义域名" align="center" prop="domain" v-if="columns[3].visible" width="200" />
-        <el-table-column label="桶名称" align="center" prop="bucketName" v-if="columns[4].visible" />
-        <el-table-column label="前缀" align="center" prop="prefix" v-if="columns[5].visible" />
-        <el-table-column label="域" align="center" prop="region" v-if="columns[6].visible" />
-        <el-table-column label="桶权限类型" align="center" prop="accessPolicy" v-if="columns[7].visible">
+        <el-table-column v-if="columns[0].visible" label="主建" align="center" prop="ossConfigId" />
+        <el-table-column v-if="columns[1].visible" label="配置key" align="center" prop="configKey" />
+        <el-table-column v-if="columns[2].visible" label="访问站点" align="center" prop="endpoint" width="200" />
+        <el-table-column v-if="columns[3].visible" label="自定义域名" align="center" prop="domain" width="200" />
+        <el-table-column v-if="columns[4].visible" label="桶名称" align="center" prop="bucketName" />
+        <el-table-column v-if="columns[5].visible" label="前缀" align="center" prop="prefix" />
+        <el-table-column v-if="columns[6].visible" label="域" align="center" prop="region" />
+        <el-table-column v-if="columns[7].visible" label="桶权限类型" align="center" prop="accessPolicy">
           <template #default="scope">
-            <el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag>
-            <el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag>
-            <el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag>
+            <el-tag v-if="scope.row.accessPolicy === '0'" type="warning">private</el-tag>
+            <el-tag v-if="scope.row.accessPolicy === '1'" type="success">public</el-tag>
+            <el-tag v-if="scope.row.accessPolicy === '2'" type="info">custom</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="是否默认" align="center" prop="status" v-if="columns[8].visible">
+        <el-table-column v-if="columns[8].visible" label="是否默认" align="center" prop="status">
           <template #default="scope">
             <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
           </template>
@@ -76,10 +76,10 @@
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改对象存储配置对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body>
       <el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px">
         <el-form-item label="配置key" prop="configKey">
           <el-input v-model="form.configKey" placeholder="请输入配置key" />
@@ -132,19 +132,11 @@
 </template>
 
 <script setup name="OssConfig" lang="ts">
-import {
-  listOssConfig,
-  getOssConfig,
-  delOssConfig,
-  addOssConfig,
-  updateOssConfig,
-  changeOssConfigStatus
-} from "@/api/system/ossConfig";
-import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
+import { listOssConfig, getOssConfig, delOssConfig, addOssConfig, updateOssConfig, changeOssConfigStatus } from '@/api/system/ossConfig';
+import { OssConfigForm, OssConfigQuery, OssConfigVO } from '@/api/system/ossConfig/types';
 
-
-const { proxy } = getCurrentInstance() as ComponentInternalInstance
-const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no'));
 
 const ossConfigList = ref<OssConfigVO[]>([]);
 const buttonLoading = ref(false);
@@ -176,7 +168,6 @@ const columns = ref<FieldOption[]>([
   { key: 8, label: `状态`, visible: true }
 ]);
 
-
 const initFormData: OssConfigForm = {
   ossConfigId: undefined,
   configKey: '',
@@ -186,12 +177,12 @@ const initFormData: OssConfigForm = {
   prefix: '',
   endpoint: '',
   domain: '',
-  isHttps: "N",
-  accessPolicy: "1",
+  isHttps: 'N',
+  accessPolicy: '1',
   region: '',
-  status: "1",
-  remark: '',
-}
+  status: '1',
+  remark: ''
+};
 const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
   form: { ...initFormData },
   // 查询参数
@@ -200,47 +191,47 @@ const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
     pageSize: 10,
     configKey: '',
     bucketName: '',
-    status: '',
+    status: ''
   },
   rules: {
-    configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
+    configKey: [{ required: true, message: 'configKey不能为空', trigger: 'blur' }],
     accessKey: [
-      { required: true, message: "accessKey不能为空", trigger: "blur" },
+      { required: true, message: 'accessKey不能为空', trigger: 'blur' },
       {
         min: 2,
         max: 200,
-        message: "accessKey长度必须介于 2 和 100 之间",
-        trigger: "blur",
-      },
+        message: 'accessKey长度必须介于 2 和 100 之间',
+        trigger: 'blur'
+      }
     ],
     secretKey: [
-      { required: true, message: "secretKey不能为空", trigger: "blur" },
+      { required: true, message: 'secretKey不能为空', trigger: 'blur' },
       {
         min: 2,
         max: 100,
-        message: "secretKey长度必须介于 2 和 100 之间",
-        trigger: "blur",
-      },
+        message: 'secretKey长度必须介于 2 和 100 之间',
+        trigger: 'blur'
+      }
     ],
     bucketName: [
-      { required: true, message: "bucketName不能为空", trigger: "blur" },
+      { required: true, message: 'bucketName不能为空', trigger: 'blur' },
       {
         min: 2,
         max: 100,
-        message: "bucketName长度必须介于 2 和 100 之间",
-        trigger: "blur",
-      },
+        message: 'bucketName长度必须介于 2 和 100 之间',
+        trigger: 'blur'
+      }
     ],
     endpoint: [
-      { required: true, message: "endpoint不能为空", trigger: "blur" },
+      { required: true, message: 'endpoint不能为空', trigger: 'blur' },
       {
         min: 2,
         max: 100,
-        message: "endpoint名称长度必须介于 2 和 100 之间",
-        trigger: "blur",
-      },
+        message: 'endpoint名称长度必须介于 2 和 100 之间',
+        trigger: 'blur'
+      }
     ],
-    accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
+    accessPolicy: [{ required: true, message: 'accessPolicy不能为空', trigger: 'blur' }]
   }
 });
 
@@ -253,39 +244,39 @@ const getList = async () => {
   ossConfigList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   dialog.visible = false;
   reset();
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   ossConfigFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 选择条数  */
 const handleSelectionChange = (selection: OssConfigVO[]) => {
-  ids.value = selection.map(item => item.ossConfigId);
+  ids.value = selection.map((item) => item.ossConfigId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加对象存储配置";
-}
+  dialog.title = '添加对象存储配置';
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: OssConfigVO) => {
   reset();
@@ -293,49 +284,49 @@ const handleUpdate = async (row?: OssConfigVO) => {
   const res = await getOssConfig(ossConfigId);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改对象存储配置";
-}
+  dialog.title = '修改对象存储配置';
+};
 /** 提交按钮 */
 const submitForm = () => {
   ossConfigFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.ossConfigId) {
-        await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
+        await updateOssConfig(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addOssConfig(form.value).finally(() => buttonLoading.value = false);
+        await addOssConfig(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("新增成功");
+      proxy?.$modal.msgSuccess('新增成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 /** 状态修改  */
 const handleStatusChange = async (row: OssConfigVO) => {
-  let text = row.status === "0" ? "启用" : "停用";
+  let text = row.status === '0' ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
     await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
-    await getList()
-    proxy?.$modal.msgSuccess(text + "成功");
-  } catch { return } finally {
-    row.status = row.status === "0" ? "1" : "0";
+    await getList();
+    proxy?.$modal.msgSuccess(text + '成功');
+  } catch {
+    return;
+  } finally {
+    row.status = row.status === '0' ? '1' : '0';
   }
-
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: OssConfigVO) => {
   const ossConfigIds = row?.ossConfigId || ids.value;
   await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
   loading.value = true;
-  await delOssConfig(ossConfigIds).finally(() => loading.value = false);
+  await delOssConfig(ossConfigIds).finally(() => (loading.value = false));
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 65 - 67
src/views/system/oss/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="文件名" prop="fileName">
               <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -40,44 +40,42 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">上传文件</el-button>
+            <el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleFile">上传文件</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">上传图片</el-button>
+            <el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">上传图片</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']">
+            <el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button
+              v-hasPermi="['system:oss:edit']"
               :type="previewListResource ? 'danger' : 'warning'"
               plain
               @click="handlePreviewListResource(!previewListResource)"
-              v-hasPermi="['system:oss:edit']"
-              >预览开关 :
-              {{
-                previewListResource ? "禁用" : "启用" }}</el-button
+              >预览开关 : {{ previewListResource ? '禁用' : '启用' }}</el-button
             >
           </el-col>
           <el-col :span="1.5">
-            <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">配置管理</el-button>
+            <el-button v-hasPermi="['system:oss:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table
+        v-if="showTable"
         v-loading="loading"
         :data="ossList"
-        @selection-change="handleSelectionChange"
         :header-cell-class-name="handleHeaderClass"
+        @selection-change="handleSelectionChange"
         @header-click="handleHeaderCLick"
-        v-if="showTable"
       >
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false" />
+        <el-table-column v-if="false" label="对象存储主键" align="center" prop="ossId" />
         <el-table-column label="文件名" align="center" prop="fileName" />
         <el-table-column label="原名" align="center" prop="originalName" />
         <el-table-column label="文件后缀" align="center" prop="fileSuffix" />
@@ -90,7 +88,7 @@
               :src="scope.row.url"
               :preview-src-list="[scope.row.url]"
             />
-            <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" />
+            <span v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" v-text="scope.row.url" />
           </template>
         </el-table-column>
         <el-table-column label="创建时间" align="center" prop="createTime" width="180" sortable="custom">
@@ -103,23 +101,23 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="下载" placement="top">
-              <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button>
+              <el-button v-hasPermi="['system:oss:download']" link type="primary" icon="Download" @click="handleDownload(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button>
+              <el-button v-hasPermi="['system:oss:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改OSS对象存储对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="文件名">
-          <fileUpload v-model="form.file" v-if="type === 0" />
-          <imageUpload v-model="form.file" v-if="type === 1" />
+          <fileUpload v-if="type === 0" v-model="form.file" />
+          <imageUpload v-if="type === 1" v-model="form.file" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -133,9 +131,9 @@
 </template>
 
 <script setup name="Oss" lang="ts">
-import { listOss, delOss } from "@/api/system/oss";
-import ImagePreview from "@/components/ImagePreview/index.vue";
-import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
+import { listOss, delOss } from '@/api/system/oss';
+import ImagePreview from '@/components/ImagePreview/index.vue';
+import { OssForm, OssQuery, OssVO } from '@/api/system/oss/types';
 
 const router = useRouter();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -165,8 +163,8 @@ const ossFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
 
 const initFormData = {
-  file: undefined,
-}
+  file: undefined
+};
 const data = reactive<PageData<OssForm, OssQuery>>({
   form: { ...initFormData },
   // 查询参数
@@ -182,9 +180,7 @@ const data = reactive<PageData<OssForm, OssQuery>>({
     isAsc: defaultSort.value.order
   },
   rules: {
-    file: [
-      { required: true, message: "文件不能为空", trigger: "blur" }
-    ]
+    file: [{ required: true, message: '文件不能为空', trigger: 'blur' }]
   }
 });
 
@@ -193,17 +189,17 @@ const { queryParams, form, rules } = toRefs(data);
 /** 查询OSS对象存储列表 */
 const getList = async () => {
   loading.value = true;
-  const res = await proxy?.getConfigKey("sys.oss.previewListResource");
+  const res = await proxy?.getConfigKey('sys.oss.previewListResource');
   previewListResource.value = res?.data === undefined ? true : res.data === 'true';
-  const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime"));
+  const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime'));
   ossList.value = response.rows;
   total.value = response.total;
   loading.value = false;
   showTable.value = true;
-}
+};
 function checkFileSuffix(fileSuffix: string[]) {
-  let arr = ["png", "jpg", "jpeg"];
-  return arr.some(type => {
+  let arr = ['png', 'jpg', 'jpeg'];
+  return arr.some((type) => {
     return fileSuffix.indexOf(type) > -1;
   });
 }
@@ -233,18 +229,18 @@ function resetQuery() {
 }
 /** 选择条数  */
 function handleSelectionChange(selection: OssVO[]) {
-  ids.value = selection.map(item => item.ossId);
+  ids.value = selection.map((item) => item.ossId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
 }
 /** 设置列的排序为我们自定义的排序 */
 const handleHeaderClass = ({ column }: any): any => {
-  column.order = column.multiOrder
-}
+  column.order = column.multiOrder;
+};
 /** 点击表头进行排序 */
 const handleHeaderCLick = (column: any) => {
   if (column.sortable !== 'custom') {
-    return
+    return;
   }
   switch (column.multiOrder) {
     case 'descending':
@@ -257,20 +253,20 @@ const handleHeaderCLick = (column: any) => {
       column.multiOrder = 'descending';
       break;
   }
-  handleOrderChange(column.property, column.multiOrder)
-}
+  handleOrderChange(column.property, column.multiOrder);
+};
 const handleOrderChange = (prop: string, order: string) => {
-  let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : [];
-  let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : [];
-  let propIndex = orderByArr.indexOf(prop)
+  let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(',') : [];
+  let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(',') : [];
+  let propIndex = orderByArr.indexOf(prop);
   if (propIndex !== -1) {
     if (order) {
       //排序里已存在 只修改排序
       isAscArr[propIndex] = order;
     } else {
       //如果order为null 则删除排序字段和属性
-      isAscArr.splice(propIndex, 1);//删除排序
-      orderByArr.splice(propIndex, 1);//删除属性
+      isAscArr.splice(propIndex, 1); //删除排序
+      orderByArr.splice(propIndex, 1); //删除属性
     }
   } else {
     //排序里不存在则新增排序
@@ -278,58 +274,60 @@ const handleOrderChange = (prop: string, order: string) => {
     isAscArr.push(order);
   }
   //合并排序
-  queryParams.value.orderByColumn = orderByArr.join(",");
-  queryParams.value.isAsc = isAscArr.join(",");
+  queryParams.value.orderByColumn = orderByArr.join(',');
+  queryParams.value.isAsc = isAscArr.join(',');
   getList();
-}
+};
 /** 任务日志列表查询 */
 const handleOssConfig = () => {
-  router.push('/system/oss-config/index')
-}
+  router.push('/system/oss-config/index');
+};
 /** 文件按钮操作 */
 const handleFile = () => {
   reset();
   type.value = 0;
   dialog.visible = true;
-  dialog.title = "上传文件";
-}
+  dialog.title = '上传文件';
+};
 /** 图片按钮操作 */
 const handleImage = () => {
   reset();
   type.value = 1;
   dialog.visible = true;
-  dialog.title = "上传图片";
-}
+  dialog.title = '上传图片';
+};
 /** 提交按钮 */
 const submitForm = () => {
   dialog.visible = false;
   getList();
-}
+};
 /** 下载按钮操作 */
 const handleDownload = (row: OssVO) => {
-  proxy?.$download.oss(row.ossId)
-}
+  proxy?.$download.oss(row.ossId);
+};
 /** 用户状态修改  */
 const handlePreviewListResource = async (preview: boolean) => {
-  let text = preview ? "启用" : "停用";
+  let text = preview ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
-    await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
-    await getList()
-    proxy?.$modal.msgSuccess(text + "成功");
-  } catch { return }
-}
+    await proxy?.updateConfigByKey('sys.oss.previewListResource', preview);
+    await getList();
+    proxy?.$modal.msgSuccess(text + '成功');
+  } catch {
+    return;
+  }
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: OssVO) => {
   const ossIds = row?.ossId || ids.value;
   await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
   loading.value = true;
-  await delOss(ossIds).finally(() => loading.value = false);
+  await delOss(ossIds).finally(() => (loading.value = false));
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 43 - 39
src/views/system/post/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="70">
             <el-form-item label="岗位编码" prop="postCode">
               <el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -27,26 +27,26 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button>
+            <el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">修改</el-button>
+            <el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']">
+            <el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导出</el-button>
+            <el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="岗位编号" align="center" prop="postId" v-if="false" />
+        <el-table-column v-if="false" label="岗位编号" align="center" prop="postId" />
         <el-table-column label="岗位编码" align="center" prop="postCode" />
         <el-table-column label="岗位名称" align="center" prop="postName" />
         <el-table-column label="岗位排序" align="center" prop="postSort" />
@@ -63,20 +63,20 @@
         <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button>
+              <el-button v-hasPermi="['system:post:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button>
+              <el-button v-hasPermi="['system:post:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
 
     <!-- 添加或修改岗位对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="岗位名称" prop="postName">
           <el-input v-model="form.postName" placeholder="请输入岗位名称" />
@@ -107,11 +107,11 @@
 </template>
 
 <script setup name="Post" lang="ts">
-import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
-import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
+import { listPost, addPost, delPost, getPost, updatePost } from '@/api/system/post';
+import { PostForm, PostQuery, PostVO } from '@/api/system/post/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
+const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
 const postList = ref<PostVO[]>([]);
 const loading = ref(true);
@@ -134,9 +134,9 @@ const initFormData: PostForm = {
   postCode: '',
   postName: '',
   postSort: 0,
-  status: "0",
+  status: '0',
   remark: ''
-}
+};
 
 const data = reactive<PageData<PostForm, PostQuery>>({
   form: { ...initFormData },
@@ -148,9 +148,9 @@ const data = reactive<PageData<PostForm, PostQuery>>({
     status: ''
   },
   rules: {
-    postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
-    postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
-    postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
+    postName: [{ required: true, message: '岗位名称不能为空', trigger: 'blur' }],
+    postCode: [{ required: true, message: '岗位编码不能为空', trigger: 'blur' }],
+    postSort: [{ required: true, message: '岗位顺序不能为空', trigger: 'blur' }]
   }
 });
 
@@ -163,39 +163,39 @@ const getList = async () => {
   postList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
   postFormRef.value?.resetFields();
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: PostVO[]) => {
-  ids.value = selection.map(item => item.postId);
+  ids.value = selection.map((item) => item.postId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = "添加岗位";
-}
+  dialog.title = '添加岗位';
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: PostVO) => {
   reset();
@@ -203,33 +203,37 @@ const handleUpdate = async (row?: PostVO) => {
   const res = await getPost(postId);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改岗位";
-}
+  dialog.title = '修改岗位';
+};
 /** 提交按钮 */
 const submitForm = () => {
   postFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.postId ? await updatePost(form.value) : await addPost(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: PostVO) => {
   const postIds = row?.postId || ids.value;
   await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
   await delPost(postIds);
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/post/export", {
-    ...queryParams.value
-  }, `post_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download(
+    'system/post/export',
+    {
+      ...queryParams.value
+    },
+    `post_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
   getList();

+ 28 - 29
src/views/system/role/authUser.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="search" v-show="showSearch">
-        <el-form :model="queryParams" ref="queryFormRef" :inline="true">
+      <div v-show="showSearch" class="search">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true">
           <el-form-item label="用户名称" prop="userName">
             <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
           </el-form-item>
@@ -20,17 +20,17 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
+            <el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="openSelectUser">添加用户</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll" v-hasPermi="['system:role:remove']">
+            <el-button v-hasPermi="['system:role:remove']" type="danger" plain icon="CircleClose" :disabled="multiple" @click="cancelAuthUserAll">
               批量取消授权
             </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button type="warning" plain icon="Close" @click="handleClose">关闭</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :search="true"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" :search="true" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
       <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
@@ -52,28 +52,27 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="取消授权" placement="top">
-              <el-button link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)" v-hasPermi="['system:role:remove']"> </el-button>
+              <el-button v-hasPermi="['system:role:remove']" link type="primary" icon="CircleClose" @click="cancelAuthUser(scope.row)"> </el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-      <select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
+      <select-user ref="selectRef" :role-id="queryParams.roleId" @ok="handleQuery" />
     </el-card>
   </div>
 </template>
 
 <script setup name="AuthUser" lang="ts">
-import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
-import { UserQuery } from "@/api/system/user/types";
-import { UserVO } from "@/api/system/user/types";
-import SelectUser from "./selectUser.vue";
-
+import { allocatedUserList, authUserCancel, authUserCancelAll } from '@/api/system/role';
+import { UserQuery } from '@/api/system/user/types';
+import { UserVO } from '@/api/system/user/types';
+import SelectUser from './selectUser.vue';
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
+const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
 const userList = ref<UserVO[]>([]);
 const loading = ref(true);
@@ -90,7 +89,7 @@ const queryParams = reactive<UserQuery>({
   pageSize: 10,
   roleId: route.params.roleId as string,
   userName: undefined,
-  phonenumber: undefined,
+  phonenumber: undefined
 });
 
 /** 查询授权用户列表 */
@@ -100,47 +99,47 @@ const getList = async () => {
   userList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 // 返回按钮
 const handleClose = () => {
-  const obj = { path: "/system/role" };
+  const obj = { path: '/system/role' };
   proxy?.$tab.closeOpenPage(obj);
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 // 多选框选中数据
 const handleSelectionChange = (selection: UserVO[]) => {
-  userIds.value = selection.map(item => item.userId);
+  userIds.value = selection.map((item) => item.userId);
   multiple.value = !selection.length;
-}
+};
 /** 打开授权用户表弹窗 */
 const openSelectUser = () => {
   selectRef.value?.show();
-}
+};
 /** 取消授权按钮操作 */
 const cancelAuthUser = async (row: UserVO) => {
   await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
   await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
   await getList();
-  proxy?.$modal.msgSuccess("取消授权成功");
-}
+  proxy?.$modal.msgSuccess('取消授权成功');
+};
 /** 批量取消授权按钮操作 */
 const cancelAuthUserAll = async () => {
   const roleId = queryParams.roleId;
-  const uIds = userIds.value.join(",");
-  await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
+  const uIds = userIds.value.join(',');
+  await proxy?.$modal.confirm('是否取消选中用户授权数据项?');
   await authUserCancelAll({ roleId: roleId, userIds: uIds });
   await getList();
-  proxy?.$modal.msgSuccess("取消授权成功");
-}
+  proxy?.$modal.msgSuccess('取消授权成功');
+};
 
 onMounted(() => {
   getList();

+ 126 - 126
src/views/system/role/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
           <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="角色名称" prop="roleName">
@@ -28,8 +28,8 @@
             </el-form-item>
 
             <el-form-item>
-              <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
-              <el-button @click="resetQuery" icon="Refresh">重置</el-button>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
             </el-form-item>
           </el-form>
         </el-card>
@@ -40,24 +40,24 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button type="primary" plain @click="handleAdd()" icon="Plus" v-hasPermi="['system:role:add']">新增</el-button>
+            <el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain @click="handleUpdate()" :disabled="single" icon="Edit" v-hasPermi="['system:role:edit']">修改</el-button>
+            <el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain :disabled="ids.length === 0" @click="handleDelete()" v-hasPermi="['system:role:delete']">删除</el-button>
+            <el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:role:export']">导出</el-button>
+            <el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="角色编号" prop="roleId" width="120" v-if="false" />
+        <el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
         <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
         <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
         <el-table-column label="显示顺序" prop="roleSort" width="100" />
@@ -74,17 +74,17 @@
 
         <el-table-column fixed="right" label="操作" width="180">
           <template #default="scope">
-            <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
+            <el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
+              <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
+            <el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
+              <el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
-              <el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
+            <el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
+              <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
-              <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
+            <el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
+              <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
@@ -99,7 +99,7 @@
       />
     </el-card>
 
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
         <el-form-item label="角色名称" prop="roleName">
           <el-input v-model="form.roleName" placeholder="请输入角色名称" />
@@ -120,9 +120,7 @@
         </el-form-item>
         <el-form-item label="状态">
           <el-radio-group v-model="form.status">
-            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
-              dict.label
-            }}</el-radio>
+            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="菜单权限">
@@ -130,10 +128,10 @@
           <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
           <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
           <el-tree
+            ref="menuRef"
             class="tree-border"
             :data="menuOptions"
             show-checkbox
-            ref="menuRef"
             node-key="id"
             :check-strictly="!form.menuCheckStrictly"
             empty-text="加载中,请稍候"
@@ -153,8 +151,8 @@
     </el-dialog>
 
     <!-- 分配角色数据权限对话框 -->
-    <el-dialog :title="dialog.title" v-model="openDataScope" width="500px" append-to-body>
-      <el-form :model="form" label-width="80px" ref="dataScopeRef">
+    <el-dialog v-model="openDataScope" :title="dialog.title" width="500px" append-to-body>
+      <el-form ref="dataScopeRef" :model="form" label-width="80px">
         <el-form-item label="角色名称">
           <el-input v-model="form.roleName" :disabled="true" />
         </el-form-item>
@@ -166,16 +164,16 @@
             <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item label="数据权限" v-show="form.dataScope === '2'">
+        <el-form-item v-show="form.dataScope === '2'" label="数据权限">
           <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
           <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
           <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
           <el-tree
+            ref="deptRef"
             class="tree-border"
             :data="deptOptions"
             show-checkbox
             default-expand-all
-            ref="deptRef"
             node-key="id"
             :check-strictly="!form.deptCheckStrictly"
             empty-text="加载中,请稍候"
@@ -194,7 +192,7 @@
 </template>
 
 <script setup name="Role" lang="ts">
-import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
+import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from '@/api/system/role';
 import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
 import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
 import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
@@ -204,29 +202,29 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
 const roleList = ref<RoleVO[]>();
-const loading = ref(true)
-const showSearch = ref(true)
-const ids = ref<Array<string | number>>([])
-const single = ref(true)
-const multiple = ref(true)
-const total = ref(0)
-const dateRange = ref<[DateModelType, DateModelType]>(['', ''])
-const menuOptions = ref<MenuTreeOption[]>([])
-const menuExpand = ref(false)
-const menuNodeAll = ref(false)
-const deptExpand = ref(true)
-const deptNodeAll = ref(false)
-const deptOptions = ref<DeptTreeOption[]>([])
-const openDataScope = ref(false)
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
+const menuOptions = ref<MenuTreeOption[]>([]);
+const menuExpand = ref(false);
+const menuNodeAll = ref(false);
+const deptExpand = ref(true);
+const deptNodeAll = ref(false);
+const deptOptions = ref<DeptTreeOption[]>([]);
+const openDataScope = ref(false);
 
 /** 数据范围选项*/
 const dataScopeOptions = ref([
-  { value: "1", label: "全部数据权限" },
-  { value: "2", label: "自定数据权限" },
-  { value: "3", label: "本部门数据权限" },
-  { value: "4", label: "本部门及以下数据权限" },
-  { value: "5", label: "仅本人数据权限" }
-])
+  { value: '1', label: '全部数据权限' },
+  { value: '2', label: '自定数据权限' },
+  { value: '3', label: '本部门数据权限' },
+  { value: '4', label: '本部门及以下数据权限' },
+  { value: '5', label: '仅本人数据权限' }
+]);
 
 const queryFormRef = ref<ElFormInstance>();
 const roleFormRef = ref<ElFormInstance>();
@@ -245,8 +243,8 @@ const initForm: RoleForm = {
   remark: '',
   dataScope: '1',
   menuIds: [],
-  deptIds: [],
-}
+  deptIds: []
+};
 
 const data = reactive<PageData<RoleForm, RoleQuery>>({
   form: { ...initForm },
@@ -255,15 +253,15 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
     pageSize: 10,
     roleName: '',
     roleKey: '',
-    status: '',
+    status: ''
   },
   rules: {
-    roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
-    roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
-    roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
+    roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
+    roleKey: [{ required: true, message: '权限字符不能为空', trigger: 'blur' }],
+    roleSort: [{ required: true, message: '角色顺序不能为空', trigger: 'blur' }]
   }
-})
-const { form, queryParams, rules } = toRefs(data)
+});
+const { form, queryParams, rules } = toRefs(data);
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -274,13 +272,13 @@ const dialog = reactive<DialogOption>({
  * 查询角色列表
  */
 const getList = () => {
-  loading.value = true
-  listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
-    roleList.value = res.rows
-    total.value = res.total
-    loading.value = false
-  })
-}
+  loading.value = true;
+  listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => {
+    roleList.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+  });
+};
 
 /**
  * 搜索按钮操作
@@ -288,14 +286,14 @@ const getList = () => {
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置 */
 const resetQuery = () => {
-  dateRange.value = ['', '']
+  dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /**删除按钮操作 */
 const handleDelete = async (row?: RoleVO) => {
   const roleids = row?.roleId || ids.value;
@@ -303,43 +301,47 @@ const handleDelete = async (row?: RoleVO) => {
   await delRole(roleids);
   getList();
   proxy?.$modal.msgSuccess('删除成功');
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/role/export", {
-    ...queryParams.value,
-  }, `role_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'system/role/export',
+    {
+      ...queryParams.value
+    },
+    `role_${new Date().getTime()}.xlsx`
+  );
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: RoleVO[]) => {
   ids.value = selection.map((item: RoleVO) => item.roleId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 角色状态修改 */
 const handleStatusChange = async (row: RoleVO) => {
-  let text = row.status === "0" ? "启用" : "停用";
+  let text = row.status === '0' ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
     await changeRoleStatus(row.roleId, row.status);
-    proxy?.$modal.msgSuccess(text + "成功");
+    proxy?.$modal.msgSuccess(text + '成功');
   } catch {
-    row.status = row.status === "0" ? "1" : "0";
+    row.status = row.status === '0' ? '1' : '0';
   }
-}
+};
 
 /** 分配用户 */
 const handleAuthUser = (row: RoleVO) => {
-  router.push("/system/role-auth/user/" + row.roleId);
-}
+  router.push('/system/role-auth/user/' + row.roleId);
+};
 
 /** 查询菜单树结构 */
 const getMenuTreeselect = async () => {
   const res = await menuTreeselect();
   menuOptions.value = res.data;
-}
+};
 /** 所有部门节点数据 */
 const getDeptAllCheckedKeys = (): any => {
   // 目前被选中的部门节点
@@ -349,67 +351,65 @@ const getDeptAllCheckedKeys = (): any => {
   if (halfCheckedKeys) {
     checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
   }
-  return checkedKeys
-}
+  return checkedKeys;
+};
 /** 重置新增的表单以及其他数据  */
 const reset = () => {
   menuRef.value?.setCheckedKeys([]);
-  menuExpand.value = false
-  menuNodeAll.value = false
-  deptExpand.value = true
-  deptNodeAll.value = false
+  menuExpand.value = false;
+  menuNodeAll.value = false;
+  deptExpand.value = true;
+  deptNodeAll.value = false;
   form.value = { ...initForm };
   roleFormRef.value?.resetFields();
-
-}
+};
 
 /** 添加角色 */
 const handleAdd = () => {
   reset();
   getMenuTreeselect();
   dialog.visible = true;
-  dialog.title = "添加角色";
-}
+  dialog.title = '添加角色';
+};
 /** 修改角色 */
 const handleUpdate = async (row?: RoleVO) => {
   reset();
-  const roleId = row?.roleId || ids.value[0]
+  const roleId = row?.roleId || ids.value[0];
   const { data } = await getRole(roleId);
   Object.assign(form.value, data);
   form.value.roleSort = Number(form.value.roleSort);
   const res = await getRoleMenuTreeselect(roleId);
-  dialog.title = "修改角色";
+  dialog.title = '修改角色';
   dialog.visible = true;
   res.checkedKeys.forEach((v) => {
     nextTick(() => {
       menuRef.value?.setChecked(v, true, false);
-    })
-  })
-
-}
+    });
+  });
+};
 /** 根据角色ID查询菜单树结构 */
 const getRoleMenuTreeselect = (roleId: string | number) => {
   return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
     menuOptions.value = res.data.menus;
     return res.data;
-  })
-}
+  });
+};
 /** 根据角色ID查询部门树结构 */
 const getRoleDeptTreeSelect = async (roleId: string | number) => {
   const res = await deptTreeSelect(roleId);
   deptOptions.value = res.data.depts;
   return res.data;
-}
+};
 /** 树权限(展开/折叠)*/
 const handleCheckedTreeExpand = (value: boolean, type: string) => {
-  if (type == "menu") {
+  if (type == 'menu') {
     let treeList = menuOptions.value;
     for (let i = 0; i < treeList.length; i++) {
       if (menuRef.value) {
         menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
       }
     }
-  } else if (type == "dept") {
+  } else if (type == 'dept') {
     let treeList = deptOptions.value;
     for (let i = 0; i < treeList.length; i++) {
       if (deptRef.value) {
@@ -417,23 +417,23 @@ const handleCheckedTreeExpand = (value: boolean, type: string) => {
       }
     }
   }
-}
+};
 /** 树权限(全选/全不选) */
 const handleCheckedTreeNodeAll = (value: any, type: string) => {
-  if (type == "menu") {
-    menuRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
-  } else if (type == "dept") {
-    deptRef.value?.setCheckedNodes(value ? deptOptions.value as any : []);
+  if (type == 'menu') {
+    menuRef.value?.setCheckedNodes(value ? (menuOptions.value as any) : []);
+  } else if (type == 'dept') {
+    deptRef.value?.setCheckedNodes(value ? (deptOptions.value as any) : []);
   }
-}
+};
 /** 树权限(父子联动) */
 const handleCheckedTreeConnect = (value: any, type: string) => {
-  if (type == "menu") {
+  if (type == 'menu') {
     form.value.menuCheckStrictly = value;
-  } else if (type == "dept") {
+  } else if (type == 'dept') {
     form.value.deptCheckStrictly = value;
   }
-}
+};
 /** 所有菜单节点数据 */
 const getMenuAllCheckedKeys = (): any => {
   // 目前被选中的菜单节点
@@ -444,57 +444,57 @@ const getMenuAllCheckedKeys = (): any => {
     checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
   }
   return checkedKeys;
-}
+};
 /** 提交按钮 */
 const submitForm = () => {
   roleFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
-      form.value.menuIds = getMenuAllCheckedKeys()
+      form.value.menuIds = getMenuAllCheckedKeys();
       form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
-      proxy?.$modal.msgSuccess("操作成功")
-      dialog.visible = false
-      getList()
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      getList();
     }
-  })
-}
+  });
+};
 /** 取消按钮 */
 const cancel = () => {
-  reset()
+  reset();
   dialog.visible = false;
-}
+};
 /** 选择角色权限范围触发 */
 const dataScopeSelectChange = (value: string) => {
-  if (value !== "2") {
-    deptRef.value?.setCheckedKeys([])
+  if (value !== '2') {
+    deptRef.value?.setCheckedKeys([]);
   }
-}
+};
 /** 分配数据权限操作 */
 const handleDataScope = async (row: RoleVO) => {
   const response = await getRole(row.roleId);
   Object.assign(form.value, response.data);
   const res = await getRoleDeptTreeSelect(row.roleId);
   openDataScope.value = true;
-  dialog.title = "分配数据权限";
+  dialog.title = '分配数据权限';
   await nextTick(() => {
     deptRef.value?.setCheckedKeys(res.checkedKeys);
-  })
-}
+  });
+};
 /** 提交按钮(数据权限) */
 const submitDataScope = async () => {
   if (form.value.roleId) {
     form.value.deptIds = getDeptAllCheckedKeys();
     await dataScope(form.value);
-    proxy?.$modal.msgSuccess("修改成功");
+    proxy?.$modal.msgSuccess('修改成功');
     openDataScope.value = false;
     getList();
   }
-}
+};
 /** 取消按钮(数据权限)*/
 const cancelDataScope = () => {
   dataScopeRef.value?.resetFields();
   form.value = { ...initForm };
   openDataScope.value = false;
-}
+};
 
 onMounted(() => {
   getList();

+ 17 - 18
src/views/system/role/selectUser.vue

@@ -1,7 +1,7 @@
 <template>
   <el-row>
-    <el-dialog title="选择用户" v-model="visible" width="800px" top="5vh" append-to-body>
-      <el-form :model="queryParams" ref="queryFormRef" :inline="true">
+    <el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body>
+      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
         <el-form-item label="用户名称" prop="userName">
           <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
         </el-form-item>
@@ -14,7 +14,7 @@
         </el-form-item>
       </el-form>
       <el-row>
-        <el-table @row-click="clickRow" ref="tableRef" :data="userList" @selection-change="handleSelectionChange" height="260px">
+        <el-table ref="tableRef" :data="userList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
           <el-table-column type="selection" width="55"></el-table-column>
           <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
           <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
@@ -31,7 +31,7 @@
             </template>
           </el-table-column>
         </el-table>
-        <pagination v-if="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        <pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
       </el-row>
       <template #footer>
         <div class="dialog-footer">
@@ -44,16 +44,15 @@
 </template>
 
 <script setup name="SelectUser" lang="ts">
-import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
+import { authUserSelectAll, unallocatedUserList } from '@/api/system/role';
 import { UserVO } from '@/api/system/user/types';
 import { UserQuery } from '@/api/system/user/types';
 
-
 const props = defineProps({
   roleId: {
     type: [Number, String]
   }
-})
+});
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
@@ -69,7 +68,7 @@ const queryParams = reactive<UserQuery>({
   roleId: undefined,
   userName: undefined,
   phonenumber: undefined
-})
+});
 
 const tableRef = ref<ElTableInstance>();
 const queryFormRef = ref<ElFormInstance>();
@@ -78,7 +77,7 @@ const show = () => {
   queryParams.roleId = props.roleId;
   getList();
   visible.value = true;
-}
+};
 
 /**
  * 选择行
@@ -86,35 +85,35 @@ const show = () => {
 const clickRow = (row: any) => {
   // ele的bug
   tableRef.value?.toggleRowSelection(row, false);
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: UserVO[]) => {
   userIds.value = selection.map((item: UserVO) => item.userId);
-}
+};
 
 /** 查询数据 */
 const getList = async () => {
   const res = await unallocatedUserList(queryParams);
   userList.value = res.rows;
   total.value = res.total;
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   getList();
-}
+};
 
-const emit = defineEmits(["ok"]);
+const emit = defineEmits(['ok']);
 /**选择授权用户操作 */
 const handleSelectUser = async () => {
   const roleId = queryParams.roleId;
   const ids = userIds.value.join(',');
-  if (ids == "") {
+  if (ids == '') {
     proxy?.$modal.msgError('请选择要分配的用户');
     return;
   }
@@ -122,10 +121,10 @@ const handleSelectUser = async () => {
   proxy?.$modal.msgSuccess('分配成功');
   emit('ok');
   visible.value = false;
-}
+};
 // 暴露
 defineExpose({
-  show,
+  show
 });
 </script>
 

+ 65 - 63
src/views/system/tenant/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="租户编号" prop="tenantId">
               <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -29,28 +29,28 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenant:add']">新增</el-button>
+            <el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenant:edit']"
+            <el-button v-hasPermi="['system:tenant:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
               >修改</el-button
             >
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenant:remove']">
+            <el-button v-hasPermi="['system:tenant:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenant:export']">导出</el-button>
+            <el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="tenantList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="id" align="center" prop="id" v-if="false" />
+        <el-table-column v-if="false" label="id" align="center" prop="id" />
         <el-table-column label="租户编号" align="center" prop="tenantId" />
         <el-table-column label="联系人" align="center" prop="contactUserName" />
         <el-table-column label="联系电话" align="center" prop="contactPhone" />
@@ -69,23 +69,23 @@
         <el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
+              <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="同步套餐" placement="top">
-              <el-button link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)" v-hasPermi="['system:tenant:edit']">
+              <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)">
               </el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenant:remove']"></el-button>
+              <el-button v-hasPermi="['system:tenant:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
     <!-- 添加或修改租户对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="企业名称" prop="companyName">
           <el-input v-model="form.companyName" placeholder="请输入企业名称" />
@@ -100,7 +100,7 @@
           <el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
         </el-form-item>
         <el-form-item v-if="!form.id" label="用户密码" prop="password">
-          <el-input type="password" v-model="form.password" placeholder="请输入系统用户密码" maxlength="20" />
+          <el-input v-model="form.password" type="password" placeholder="请输入系统用户密码" maxlength="20" />
         </el-form-item>
         <el-form-item label="租户套餐" prop="packageId">
           <el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
@@ -108,7 +108,7 @@
           </el-select>
         </el-form-item>
         <el-form-item label="过期时间" prop="expireTime">
-          <el-date-picker clearable v-model="form.expireTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
+          <el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
           </el-date-picker>
         </el-form-item>
         <el-form-item label="用户数量" prop="accountCount">
@@ -124,7 +124,7 @@
           <el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
         </el-form-item>
         <el-form-item label="企业简介" prop="intro">
-          <el-input type="textarea" v-model="form.intro" placeholder="请输入企业简介" />
+          <el-input v-model="form.intro" type="textarea" placeholder="请输入企业简介" />
         </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" placeholder="请输入备注" />
@@ -182,8 +182,8 @@ const initFormData: TenantForm = {
   packageId: '',
   expireTime: '',
   accountCount: 0,
-  status: '0',
-}
+  status: '0'
+};
 const data = reactive<PageData<TenantForm, TenantQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -195,17 +195,17 @@ const data = reactive<PageData<TenantForm, TenantQuery>>({
     companyName: ''
   },
   rules: {
-    id: [{ required: true, message: "id不能为空", trigger: "blur" }],
-    tenantId: [{ required: true, message: "租户编号不能为空", trigger: "blur" }],
-    contactUserName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
-    contactPhone: [{ required: true, message: "联系电话不能为空", trigger: "blur" }],
-    companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
+    id: [{ required: true, message: 'id不能为空', trigger: 'blur' }],
+    tenantId: [{ required: true, message: '租户编号不能为空', trigger: 'blur' }],
+    contactUserName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
+    contactPhone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
+    companyName: [{ required: true, message: '企业名称不能为空', trigger: 'blur' }],
     username: [
-      { required: true, message: "用户名不能为空", trigger: "blur" },
+      { required: true, message: '用户名不能为空', trigger: 'blur' },
       { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
     ],
     password: [
-      { required: true, message: "密码不能为空", trigger: "blur" },
+      { required: true, message: '密码不能为空', trigger: 'blur' },
       { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
     ]
   }
@@ -215,9 +215,9 @@ const { queryParams, form, rules } = toRefs(data);
 
 /** 查询所有租户套餐 */
 const getTenantPackage = async () => {
-  const res = await selectTenantPackage()
+  const res = await selectTenantPackage();
   packageList.value = res.data;
-}
+};
 
 /** 查询租户列表 */
 const getList = async () => {
@@ -226,60 +226,58 @@ const getList = async () => {
   tenantList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 
 // 租户套餐状态修改
 const handleStatusChange = async (row: TenantVO) => {
-  let text = row.status === "0" ? "启用" : "停用";
+  let text = row.status === '0' ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
     await changeTenantStatus(row.id, row.tenantId, row.status);
-    proxy?.$modal.msgSuccess(text + "成功");
+    proxy?.$modal.msgSuccess(text + '成功');
   } catch {
-    row.status = row.status === "0" ? "1" : "0";
+    row.status = row.status === '0' ? '1' : '0';
   }
-
-
-}
+};
 
 // 取消按钮
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 // 表单重置
 const reset = () => {
   form.value = { ...initFormData };
   tenantFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 
 // 多选框选中数据
 const handleSelectionChange = (selection: TenantVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
   reset();
   getTenantPackage();
   dialog.visible = true;
-  dialog.title = "添加租户";
-}
+  dialog.title = '添加租户';
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: TenantVO) => {
@@ -287,10 +285,10 @@ const handleUpdate = async (row?: TenantVO) => {
   await getTenantPackage();
   const _id = row?.id || ids.value[0];
   const res = await getTenant(_id);
-  Object.assign(form.value, res.data)
+  Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = "修改租户";
-}
+  dialog.title = '修改租户';
+};
 
 /** 提交按钮 */
 const submitForm = () => {
@@ -298,28 +296,26 @@ const submitForm = () => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
-        await updateTenant(form.value).finally(() => buttonLoading.value = false);
+        await updateTenant(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addTenant(form.value).finally(() => buttonLoading.value = false);
+        await addTenant(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
   });
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
+  await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?');
   loading.value = true;
-  await delTenant(_ids).finally(() => loading.value = false);
+  await delTenant(_ids).finally(() => (loading.value = false));
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
-
-
-}
+  proxy?.$modal.msgSuccess('删除成功');
+};
 
 /** 同步租户套餐按钮操作 */
 const handleSyncTenantPackage = async (row: TenantVO) => {
@@ -328,20 +324,26 @@ const handleSyncTenantPackage = async (row: TenantVO) => {
     loading.value = true;
     await syncTenantPackage(row.tenantId, row.packageId);
     await getList();
-    proxy?.$modal.msgSuccess("同步成功");
-  } catch { return } finally {
+    proxy?.$modal.msgSuccess('同步成功');
+  } catch {
+    return;
+  } finally {
     loading.value = false;
   }
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('system/tenant/export', {
-    ...queryParams.value
-  }, `tenant_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'system/tenant/export',
+    {
+      ...queryParams.value
+    },
+    `tenant_${new Date().getTime()}.xlsx`
+  );
+};
 
 onMounted(() => {
   getList();
-})
+});
 </script>

+ 48 - 45
src/views/system/tenantPackage/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="套餐名称" prop="packageName">
               <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
@@ -20,28 +20,28 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']"> 新增 </el-button>
+            <el-button v-hasPermi="['system:tenantPackage:add']" type="primary" plain icon="Plus" @click="handleAdd"> 新增 </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']">
+            <el-button v-hasPermi="['system:tenantPackage:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
               修改
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']">
+            <el-button v-hasPermi="['system:tenantPackage:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出 </el-button>
+            <el-button v-hasPermi="['system:tenantPackage:export']" type="warning" plain icon="Download" @click="handleExport">导出 </el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" :data="tenantPackageList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="租户套餐id" align="center" prop="packageId" v-if="false" />
+        <el-table-column v-if="false" label="租户套餐id" align="center" prop="packageId" />
         <el-table-column label="套餐名称" align="center" prop="packageName" />
         <el-table-column label="备注" align="center" prop="remark" />
         <el-table-column label="状态" align="center" prop="status">
@@ -52,20 +52,20 @@
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></el-button>
+              <el-button v-hasPermi="['system:tenantPackage:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"></el-button>
+              <el-button v-hasPermi="['system:tenantPackage:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
 
     <!-- 添加或修改租户套餐对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
       <el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="套餐名称" prop="packageName">
           <el-input v-model="form.packageName" placeholder="请输入套餐名称" />
@@ -75,10 +75,10 @@
           <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选 </el-checkbox>
           <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动 </el-checkbox>
           <el-tree
+            ref="menuTreeRef"
             class="tree-border"
             :data="menuOptions"
             show-checkbox
-            ref="menuTreeRef"
             node-key="id"
             :check-strictly="!form.menuCheckStrictly"
             empty-text="加载中,请稍候"
@@ -107,11 +107,11 @@ import {
   addTenantPackage,
   updateTenantPackage,
   changePackageStatus
-} from "@/api/system/tenantPackage";
-import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
-import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
-import { MenuTreeOption } from "@/api/system/menu/types";
-import to from "await-to-js";
+} from '@/api/system/tenantPackage';
+import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from '@/api/system/menu';
+import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from '@/api/system/tenantPackage/types';
+import { MenuTreeOption } from '@/api/system/menu/types';
+import to from 'await-to-js';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -133,15 +133,14 @@ const tenantPackageFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
   visible: false,
-  title: ""
+  title: ''
 });
 
-
 const initFormData: TenantPkgForm = {
   packageId: undefined,
-  packageName: "",
-  menuIds: "",
-  remark: "",
+  packageName: '',
+  menuIds: '',
+  remark: '',
   menuCheckStrictly: true
 };
 const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
@@ -149,11 +148,11 @@ const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
   queryParams: {
     pageNum: 1,
     pageSize: 10,
-    packageName: ""
+    packageName: ''
   },
   rules: {
-    packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
-    packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
+    packageId: [{ required: true, message: '租户套餐id不能为空', trigger: 'blur' }],
+    packageName: [{ required: true, message: '套餐名称不能为空', trigger: 'blur' }]
   }
 });
 
@@ -195,13 +194,13 @@ const getList = async () => {
 
 // 租户套餐状态修改
 const handleStatusChange = async (row: TenantPkgVO) => {
-  let text = row.status === "0" ? "启用" : "停用";
-  const [err] = await to(proxy?.$modal.confirm("确认要\"" + text + "\"\"" + row.packageName + "\"套餐吗?") as Promise<any>);
+  let text = row.status === '0' ? '启用' : '停用';
+  const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>);
   if (err) {
-    row.status = row.status === "0" ? "1" : "0";
+    row.status = row.status === '0' ? '1' : '0';
   } else {
     await changePackageStatus(row.packageId, row.status);
-    proxy?.$modal.msgSuccess(text + "成功");
+    proxy?.$modal.msgSuccess(text + '成功');
   }
 };
 
@@ -234,14 +233,14 @@ const resetQuery = () => {
 
 // 多选框选中数据
 const handleSelectionChange = (selection: TenantPkgVO[]) => {
-  ids.value = selection.map(item => item.packageId);
+  ids.value = selection.map((item) => item.packageId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
 };
 
 // 树权限(展开/折叠)
 const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
-  if (type == "menu") {
+  if (type == 'menu') {
     let treeList = menuOptions.value;
     for (let i = 0; i < treeList.length; i++) {
       if (menuTreeRef.value) {
@@ -253,14 +252,14 @@ const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
 
 // 树权限(全选/全不选)
 const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
-  if (type == "menu") {
-    menuTreeRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
+  if (type == 'menu') {
+    menuTreeRef.value?.setCheckedNodes(value ? (menuOptions.value as any) : []);
   }
 };
 
 // 树权限(父子联动)
 const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
-  if (type == "menu") {
+  if (type == 'menu') {
     form.value.menuCheckStrictly = value as boolean;
   }
 };
@@ -270,7 +269,7 @@ const handleAdd = () => {
   reset();
   getMenuTreeselect();
   dialog.visible = true;
-  dialog.title = "添加租户套餐";
+  dialog.title = '添加租户套餐';
 };
 
 /** 修改按钮操作 */
@@ -281,7 +280,7 @@ const handleUpdate = async (row?: TenantPkgVO) => {
   form.value = response.data;
   const res = await getPackageMenuTreeselect(_packageId);
   dialog.visible = true;
-  dialog.title = "修改租户套餐";
+  dialog.title = '修改租户套餐';
   res.data.checkedKeys.forEach((v) => {
     nextTick(() => {
       menuTreeRef.value?.setChecked(v, true, false);
@@ -296,11 +295,11 @@ const submitForm = () => {
       buttonLoading.value = true;
       form.value.menuIds = getMenuAllCheckedKeys();
       if (form.value.packageId != null) {
-        await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
+        await updateTenantPackage(form.value).finally(() => (buttonLoading.value = false));
       } else {
-        await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
+        await addTenantPackage(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
@@ -310,20 +309,24 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantPkgVO) => {
   const _packageIds = row?.packageId || ids.value;
-  await proxy?.$modal.confirm("是否确认删除租户套餐编号为\"" + _packageIds + "\"的数据项?").finally(() => {
+  await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
     loading.value = false;
   });
   await delTenantPackage(_packageIds);
   loading.value = true;
   await getList();
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
 };
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/tenantPackage/export", {
-    ...queryParams.value
-  }, `tenantPackage_${new Date().getTime()}.xlsx`);
+  proxy?.download(
+    'system/tenantPackage/export',
+    {
+      ...queryParams.value
+    },
+    `tenantPackage_${new Date().getTime()}.xlsx`
+  );
 };
 
 onMounted(() => {

+ 13 - 13
src/views/system/user/authRole.vue

@@ -21,12 +21,12 @@
       <h4 class="panel-title">角色信息</h4>
       <div>
         <el-table
+          ref="tableRef"
           v-loading="loading"
           :row-key="getRowKey"
+          :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
           @row-click="clickRow"
-          ref="tableRef"
           @selection-change="handleSelectionChange"
-          :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
         >
           <el-table-column label="序号" width="55" type="index" align="center">
             <template #default="scope">
@@ -43,8 +43,8 @@
             </template>
           </el-table-column>
         </el-table>
-        <pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
-        <div style="text-align: center;margin-left:-120px;margin-top:30px;">
+        <pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
+        <div style="text-align: center; margin-left: -120px; margin-top: 30px">
           <el-button type="primary" @click="submitForm()">提交</el-button>
           <el-button @click="close()">返回</el-button>
         </div>
@@ -55,9 +55,9 @@
 </template>
 
 <script setup name="AuthRole" lang="ts">
-import { RoleVO } from "@/api/system/role/types";
-import { getAuthRole, updateAuthRole } from "@/api/system/user";
-import { UserForm } from "@/api/system/user/types";
+import { RoleVO } from '@/api/system/role/types';
+import { getAuthRole, updateAuthRole } from '@/api/system/user';
+import { UserForm } from '@/api/system/user/types';
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -70,7 +70,7 @@ const roleIds = ref<Array<string | number>>([]);
 const roles = ref<RoleVO[]>([]);
 const form = ref<Partial<UserForm>>({
   nickName: undefined,
-  userName: "",
+  userName: '',
   userId: undefined
 });
 
@@ -83,7 +83,7 @@ const clickRow = (row: RoleVO) => {
 };
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: RoleVO[]) => {
-  roleIds.value = selection.map(item => item.roleId);
+  roleIds.value = selection.map((item) => item.roleId);
 };
 /** 保存选中的数据编号 */
 const getRowKey = (row: RoleVO): string => {
@@ -91,15 +91,15 @@ const getRowKey = (row: RoleVO): string => {
 };
 /** 关闭按钮 */
 const close = () => {
-  const obj = { path: "/system/user" };
+  const obj = { path: '/system/user' };
   proxy?.$tab.closeOpenPage(obj);
 };
 /** 提交按钮 */
 const submitForm = async () => {
   const userId = form.value.userId;
-  const rIds = roleIds.value.join(",");
+  const rIds = roleIds.value.join(',');
   await updateAuthRole({ userId: userId as string, roleIds: rIds });
-  proxy?.$modal.msgSuccess("授权成功");
+  proxy?.$modal.msgSuccess('授权成功');
   close();
 };
 
@@ -112,7 +112,7 @@ const getList = async () => {
     Object.assign(roles.value, res.data.roles);
     total.value = roles.value.length;
     await nextTick(() => {
-      roles.value.forEach(row => {
+      roles.value.forEach((row) => {
         if (row?.flag) {
           tableRef.value?.toggleRowSelection(row, true);
         }

+ 160 - 128
src/views/system/user/index.vue

@@ -6,8 +6,8 @@
         <el-card shadow="hover">
           <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
           <el-tree
-            class="mt-2"
             ref="deptTreeRef"
+            class="mt-2"
             node-key="id"
             :data="deptOptions"
             :props="{ label: 'label', children: 'children' }"
@@ -21,7 +21,7 @@
       </el-col>
       <el-col :lg="20" :xs="24">
         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-          <div class="mb-[10px]" v-show="showSearch">
+          <div v-show="showSearch" class="mb-[10px]">
             <el-card shadow="hover">
               <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
                 <el-form-item label="用户名称" prop="userName">
@@ -42,7 +42,7 @@
                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                   </el-select>
                 </el-form-item>
-                <el-form-item label="创建时间" style="width: 308px;">
+                <el-form-item label="创建时间" style="width: 308px">
                   <el-date-picker
                     v-model="dateRange"
                     value-format="YYYY-MM-DD"
@@ -53,8 +53,8 @@
                   ></el-date-picker>
                 </el-form-item>
                 <el-form-item>
-                  <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
-                  <el-button @click="resetQuery" icon="Refresh">重置</el-button>
+                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                 </el-form-item>
               </el-form>
             </el-card>
@@ -65,15 +65,15 @@
           <template #header>
             <el-row :gutter="10">
               <el-col :span="1.5">
-                <el-button type="primary" plain @click="handleAdd()" v-has-permi="['system:user:add']" icon="Plus">新增</el-button>
+                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
               </el-col>
               <el-col :span="1.5">
-                <el-button type="success" plain @click="handleUpdate()" :disabled="single" v-has-permi="['system:user:add']" icon="Edit">
+                <el-button v-has-permi="['system:user:add']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
                   修改
                 </el-button>
               </el-col>
               <el-col :span="1.5">
-                <el-button type="danger" plain @click="handleDelete()" :disabled="multiple" v-has-permi="['system:user:delete']" icon="Delete">
+                <el-button v-has-permi="['system:user:delete']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
                   删除
                 </el-button>
               </el-col>
@@ -85,38 +85,38 @@
                   ></el-button>
                   <template #dropdown>
                     <el-dropdown-menu>
-                      <el-dropdown-item @click="importTemplate" icon="Download">下载模板</el-dropdown-item>
-                      <el-dropdown-item @click="handleImport" icon="Top"> 导入数据</el-dropdown-item>
-                      <el-dropdown-item @click="handleExport" icon="Download"> 导出数据</el-dropdown-item>
+                      <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
+                      <el-dropdown-item icon="Top" @click="handleImport"> 导入数据</el-dropdown-item>
+                      <el-dropdown-item icon="Download" @click="handleExport"> 导出数据</el-dropdown-item>
                     </el-dropdown-menu>
                   </template>
                 </el-dropdown>
               </el-col>
-              <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" :search="true"></right-toolbar>
+              <right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
             </el-row>
           </template>
 
           <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
             <el-table-column type="selection" width="50" align="center" />
-            <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
-            <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
-            <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
+            <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
+            <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
+            <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
             <el-table-column
+              v-if="columns[3].visible"
+              key="deptName"
               label="部门"
               align="center"
-              key="deptName"
               prop="dept.deptName"
-              v-if="columns[3].visible"
               :show-overflow-tooltip="true"
             />
-            <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
-            <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
+            <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
+            <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
               <template #default="scope">
                 <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
               </template>
             </el-table-column>
 
-            <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
+            <el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
               <template #default="scope">
                 <span>{{ scope.row.createTime }}</span>
               </template>
@@ -124,19 +124,19 @@
 
             <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
               <template #default="scope">
-                <el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
-                  <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
+                <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
+                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
                 </el-tooltip>
-                <el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
-                  <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
+                <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
+                  <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
                 </el-tooltip>
 
-                <el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
-                  <el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
+                <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
+                  <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
                 </el-tooltip>
 
-                <el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
-                  <el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
+                <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
+                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
                 </el-tooltip>
               </template>
             </el-table-column>
@@ -144,9 +144,9 @@
 
           <pagination
             v-show="total > 0"
-            :total="total"
             v-model:page="queryParams.pageNum"
             v-model:limit="queryParams.pageSize"
+            :total="total"
             @pagination="getList"
           />
         </el-card>
@@ -154,8 +154,8 @@
     </el-row>
 
     <!-- 添加或修改用户配置对话框 -->
-    <el-dialog ref="formDialogRef" :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
-      <el-form :model="form" :rules="rules" ref="userFormRef" label-width="80px">
+    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
+      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
         <el-row>
           <el-col :span="12">
             <el-form-item label="用户昵称" prop="nickName">
@@ -210,8 +210,7 @@
           <el-col :span="12">
             <el-form-item label="状态">
               <el-radio-group v-model="form.status">
-                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{
-                  dict.label }}</el-radio>
+                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -261,7 +260,7 @@
     </el-dialog>
 
     <!-- 用户导入对话框 -->
-    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
+    <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
       <el-upload
         ref="uploadRef"
         :limit="1"
@@ -282,7 +281,7 @@
           <div class="text-center el-upload__tip">
             <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
             <span>仅允许导入xls、xlsx格式文件。</span>
-            <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
+            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
           </div>
         </template>
       </el-upload>
@@ -297,22 +296,22 @@
 </template>
 
 <script setup name="User" lang="ts">
-import api from "@/api/system/user"
+import api from '@/api/system/user';
 import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
-import { treeselect } from "@/api/system/dept";
-import { DeptVO } from "@/api/system/dept/types";
-import { RoleVO } from "@/api/system/role/types";
-import { PostVO } from "@/api/system/post/types";
-import { to } from "await-to-js";
-import { globalHeaders } from "@/utils/request";
+import { treeselect } from '@/api/system/dept';
+import { DeptVO } from '@/api/system/dept/types';
+import { RoleVO } from '@/api/system/role/types';
+import { PostVO } from '@/api/system/post/types';
+import { to } from 'await-to-js';
+import { globalHeaders } from '@/utils/request';
 
 const router = useRouter();
-const { proxy } = getCurrentInstance() as ComponentInternalInstance
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
 
 const userList = ref<UserVO[]>();
 const loading = ref(true);
-const showSearch = ref(true)
+const showSearch = ref(true);
 const ids = ref<Array<number | string>>([]);
 const single = ref(true);
 const multiple = ref(true);
@@ -320,7 +319,7 @@ const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const deptName = ref('');
 const deptOptions = ref<DeptVO[]>([]);
-const initPassword = ref<String>('');
+const initPassword = ref<string>('');
 const postOptions = ref<PostVO[]>([]);
 const roleOptions = ref<RoleVO[]>([]);
 /*** 用户导入参数 */
@@ -328,7 +327,7 @@ const upload = reactive<ImportOption>({
   // 是否显示弹出层(用户导入)
   open: false,
   // 弹出层标题(用户导入)
-  title: "",
+  title: '',
   // 是否禁用上传
   isUploading: false,
   // 是否更新已经存在的用户数据
@@ -336,19 +335,18 @@ const upload = reactive<ImportOption>({
   // 设置上传的请求头部
   headers: globalHeaders(),
   // 上传的地址
-  url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
-})
+  url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
+});
 // 列显隐信息
 const columns = ref<FieldOption[]>([
-  { key: 0, label: `用户编号`, visible: false,children: [] },
-  { key: 1, label: `用户名称`, visible: true,children: [] },
-  { key: 2, label: `用户昵称`, visible: true,children: [] },
-  { key: 3, label: `部门`, visible: true,children: [] },
-  { key: 4, label: `手机号码`, visible: true,children: [] },
-  { key: 5, label: `状态`, visible: true,children: [] },
-  { key: 6, label: `创建时间`, visible: true,children: [] }
-])
-
+  { key: 0, label: `用户编号`, visible: false, children: [] },
+  { key: 1, label: `用户名称`, visible: true, children: [] },
+  { key: 2, label: `用户昵称`, visible: true, children: [] },
+  { key: 3, label: `部门`, visible: true, children: [] },
+  { key: 4, label: `手机号码`, visible: true, children: [] },
+  { key: 5, label: `状态`, visible: true, children: [] },
+  { key: 6, label: `创建时间`, visible: true, children: [] }
+]);
 
 const deptTreeRef = ref<ElTreeInstance>();
 const queryFormRef = ref<ElFormInstance>();
@@ -370,11 +368,11 @@ const initFormData: UserForm = {
   phonenumber: undefined,
   email: undefined,
   sex: undefined,
-  status: "0",
+  status: '0',
   remark: '',
   postIds: [],
   roleIds: []
-}
+};
 const data = reactive<PageData<UserForm, UserQuery>>({
   form: { ...initFormData },
   queryParams: {
@@ -386,24 +384,54 @@ const data = reactive<PageData<UserForm, UserQuery>>({
     deptId: ''
   },
   rules: {
-    userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
-    nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
-    password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }],
-    email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
-    phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
+    userName: [
+      { required: true, message: '用户名称不能为空', trigger: 'blur' },
+      {
+        min: 2,
+        max: 20,
+        message: '用户名称长度必须介于 2 和 20 之间',
+        trigger: 'blur'
+      }
+    ],
+    nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
+    password: [
+      { required: true, message: '用户密码不能为空', trigger: 'blur' },
+      {
+        min: 5,
+        max: 20,
+        message: '用户密码长度必须介于 5 和 20 之间',
+        trigger: 'blur'
+      }
+    ],
+    email: [
+      {
+        type: 'email',
+        message: '请输入正确的邮箱地址',
+        trigger: ['blur', 'change']
+      }
+    ],
+    phonenumber: [
+      {
+        pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+        message: '请输入正确的手机号码',
+        trigger: 'blur'
+      }
+    ]
   }
-})
+});
 
-const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data)
+const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
 
 /** 通过条件过滤节点  */
 const filterNode = (value: string, data: any) => {
-  if (!value) return true
-  return data.label.indexOf(value) !== -1
-}
+  if (!value) return true;
+  return data.label.indexOf(value) !== -1;
+};
 /** 根据名称筛选部门树 */
 watchEffect(
-  () => { deptTreeRef.value?.filter(deptName.value); },
+  () => {
+    deptTreeRef.value?.filter(deptName.value);
+  },
   {
     flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
   }
@@ -422,29 +450,28 @@ const getList = async () => {
   loading.value = false;
   userList.value = res.rows;
   total.value = res.total;
-}
+};
 
 /** 节点单击事件 */
 const handleNodeClick = (data: DeptVO) => {
   queryParams.value.deptId = data.id;
-  handleQuery()
-}
-
+  handleQuery();
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.value.pageNum = 1
-  getList()
-}
+  queryParams.value.pageNum = 1;
+  getList();
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
-  dateRange.value = ['', '']
+  dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   queryParams.value.pageNum = 1;
   queryParams.value.deptId = undefined;
   deptTreeRef.value?.setCurrentKey(undefined);
   handleQuery();
-}
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: UserVO) => {
@@ -453,78 +480,85 @@ const handleDelete = async (row?: UserVO) => {
   if (!err) {
     await api.delUser(userIds);
     await getList();
-    proxy?.$modal.msgSuccess("删除成功");
+    proxy?.$modal.msgSuccess('删除成功');
   }
-}
+};
 
 /** 用户状态修改  */
 const handleStatusChange = async (row: UserVO) => {
-  let text = row.status === "0" ? "启用" : "停用"
+  let text = row.status === '0' ? '启用' : '停用';
   try {
     await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
     await api.changeUserStatus(row.userId, row.status);
-    proxy?.$modal.msgSuccess(text + "成功");
+    proxy?.$modal.msgSuccess(text + '成功');
   } catch (err) {
-    row.status = row.status === "0" ? "1" : "0";
+    row.status = row.status === '0' ? '1' : '0';
   }
-}
+};
 /** 跳转角色分配 */
 const handleAuthRole = (row: UserVO) => {
   const userId = row.userId;
-  router.push("/system/user-auth/role/" + userId);
-}
+  router.push('/system/user-auth/role/' + userId);
+};
 
 /** 重置密码按钮操作 */
 const handleResetPwd = async (row: UserVO) => {
-  const [err, res] = await to(ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', "提示", {
-    confirmButtonText: "确定",
-    cancelButtonText: "取消",
-    closeOnClickModal: false,
-    inputPattern: /^.{5,20}$/,
-    inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
-  }))
+  const [err, res] = await to(
+    ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      closeOnClickModal: false,
+      inputPattern: /^.{5,20}$/,
+      inputErrorMessage: '用户密码长度必须介于 5 和 20 之间'
+    })
+  );
   if (!err) {
     await api.resetUserPwd(row.userId, res.value);
-    proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
+    proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
   }
-}
+};
 
 /** 选择条数  */
 const handleSelectionChange = (selection: UserVO[]) => {
   ids.value = selection.map((item) => item.userId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 导入按钮操作 */
 const handleImport = () => {
-  upload.title = "用户导入";
+  upload.title = '用户导入';
   upload.open = true;
-}
+};
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download("system/user/export", {
-    ...queryParams.value,
-  }, `user_${new Date().getTime()}.xlsx`);
+  proxy?.download(
+    'system/user/export',
+    {
+      ...queryParams.value
+    },
+    `user_${new Date().getTime()}.xlsx`
+  );
 };
 /** 下载模板操作 */
 const importTemplate = () => {
-  proxy?.download("system/user/importTemplate", {
-  }, `user_template_${new Date().getTime()}.xlsx`);
-}
+  proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
+};
 
 /**文件上传中处理 */
 const handleFileUploadProgress = () => {
   upload.isUploading = true;
-}
+};
 /** 文件上传成功处理 */
 const handleFileSuccess = (response: any, file: UploadFile) => {
   upload.open = false;
   upload.isUploading = false;
   uploadRef.value?.handleRemove(file);
-  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
+  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
+    dangerouslyUseHTMLString: true
+  });
   getList();
-}
+};
 
 /** 提交上传文件 */
 function submitFileForm() {
@@ -538,59 +572,57 @@ const initTreeData = async () => {
     const { data } = await treeselect();
     deptOptions.value = data;
   }
-}
-
+};
 
 /** 重置操作表单 */
 const reset = () => {
   form.value = { ...initFormData };
   userFormRef.value?.resetFields();
-}
+};
 /** 取消按钮 */
 const cancel = () => {
   dialog.visible = false;
   reset();
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = async () => {
   reset();
   const { data } = await api.getUser();
   dialog.visible = true;
-  dialog.title = "新增用户";
+  dialog.title = '新增用户';
   await initTreeData();
   postOptions.value = data.posts;
   roleOptions.value = data.roles;
   form.value.password = initPassword.value.toString();
-}
+};
 /** 修改按钮操作 */
 const handleUpdate = async (row?: UserForm) => {
   reset();
-  const userId = row?.userId || ids.value[0]
-  const { data } = await api.getUser(userId)
+  const userId = row?.userId || ids.value[0];
+  const { data } = await api.getUser(userId);
   dialog.visible = true;
-  dialog.title = "修改用户";
+  dialog.title = '修改用户';
   await initTreeData();
   Object.assign(form.value, data.user);
   postOptions.value = data.posts;
   roleOptions.value = data.roles;
   form.value.postIds = data.postIds;
   form.value.roleIds = data.roleIds;
-  form.value.password = "";
-}
+  form.value.password = '';
+};
 
 /** 提交按钮 */
 const submitForm = () => {
   userFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
-      proxy?.$modal.msgSuccess("操作成功");
+      proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
       await getList();
     }
-  })
-}
-
+  });
+};
 
 /**
  * 关闭用户弹窗
@@ -598,7 +630,7 @@ const submitForm = () => {
 const closeDialog = () => {
   dialog.visible = false;
   resetForm();
-}
+};
 
 /**
  * 重置表单
@@ -609,11 +641,11 @@ const resetForm = () => {
 
   form.value.id = undefined;
   form.value.status = '1';
-}
+};
 onMounted(() => {
-  getTreeSelect() // 初始化部门数据
-  getList() // 初始化列表数据
-  proxy?.getConfigKey("sys.user.initPassword").then(response => {
+  getTreeSelect(); // 初始化部门数据
+  getList(); // 初始化列表数据
+  proxy?.getConfigKey('sys.user.initPassword').then((response) => {
     initPassword.value = response.data;
   });
 });

+ 25 - 25
src/views/system/user/profile/index.vue

@@ -3,14 +3,14 @@
     <el-row :gutter="20">
       <el-col :span="6" :xs="24">
         <el-card class="box-card">
-          <template v-slot:header>
+          <template #header>
             <div class="clearfix">
               <span>个人信息</span>
             </div>
           </template>
           <div>
             <div class="text-center">
-              <userAvatar/>
+              <userAvatar />
             </div>
             <ul class="list-group list-group-striped">
               <li class="list-group-item">
@@ -27,7 +27,7 @@
               </li>
               <li class="list-group-item">
                 <svg-icon icon-class="tree" />所属部门
-                <div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
+                <div v-if="state.user.dept" class="pull-right">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
               </li>
               <li class="list-group-item">
                 <svg-icon icon-class="peoples" />所属角色
@@ -43,7 +43,7 @@
       </el-col>
       <el-col :span="18" :xs="24">
         <el-card>
-          <template v-slot:header>
+          <template #header>
             <div class="clearfix">
               <span>基本资料</span>
             </div>
@@ -66,38 +66,38 @@
 </template>
 
 <script setup name="Profile" lang="ts">
-import UserAvatar from "./userAvatar.vue";
-import UserInfo from "./userInfo.vue";
-import ResetPwd from "./resetPwd.vue";
-import ThirdParty from "./thirdParty.vue";
-import { getAuthList } from "@/api/system/social/auth";
-import { getUserProfile } from "@/api/system/user";
+import UserAvatar from './userAvatar.vue';
+import UserInfo from './userInfo.vue';
+import ResetPwd from './resetPwd.vue';
+import ThirdParty from './thirdParty.vue';
+import { getAuthList } from '@/api/system/social/auth';
+import { getUserProfile } from '@/api/system/user';
 
-const activeTab = ref("userinfo");
+const activeTab = ref('userinfo');
 const state = ref<Record<string, any>>({
-    user: {},
-    roleGroup: '',
-    postGroup: '',
-    auths: []
+  user: {},
+  roleGroup: '',
+  postGroup: '',
+  auths: []
 });
 
 const userForm = ref({});
 
 const getUser = async () => {
-    const res = await getUserProfile();
-    state.value.user = res.data.user;
-    userForm.value = { ...res.data.user }
-    state.value.roleGroup = res.data.roleGroup;
-    state.value.postGroup = res.data.postGroup;
+  const res = await getUserProfile();
+  state.value.user = res.data.user;
+  userForm.value = { ...res.data.user };
+  state.value.roleGroup = res.data.roleGroup;
+  state.value.postGroup = res.data.postGroup;
 };
 
 const getAuths = async () => {
-    const res = await getAuthList();
-    state.value.auths = res.data;
+  const res = await getAuthList();
+  state.value.auths = res.data;
 };
 
 onMounted(() => {
-    getUser();
-    getAuths();
-})
+  getUser();
+  getAuths();
+});
 </script>

+ 25 - 19
src/views/system/user/profile/resetPwd.vue

@@ -17,37 +17,43 @@
 </template>
 
 <script setup lang="ts">
-import { updateUserPwd } from "@/api/system/user";
-import type { ResetPwdForm } from "@/api/system/user/types";
+import { updateUserPwd } from '@/api/system/user';
+import type { ResetPwdForm } from '@/api/system/user/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const pwdRef = ref<ElFormInstance>();
 const user = ref<ResetPwdForm>({
-  oldPassword: "",
-  newPassword: "",
-  confirmPassword: ""
+  oldPassword: '',
+  newPassword: '',
+  confirmPassword: ''
 });
 
 const equalToPassword = (rule: any, value: string, callback: any) => {
   if (user.value.newPassword !== value) {
-    callback(new Error("两次输入的密码不一致"));
+    callback(new Error('两次输入的密码不一致'));
   } else {
     callback();
   }
 };
 const rules = ref({
-  oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
-  newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, {
-    min: 6,
-    max: 20,
-    message: "长度在 6 到 20 个字符",
-    trigger: "blur"
-  }],
-  confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, {
-    required: true,
-    validator: equalToPassword,
-    trigger: "blur"
-  }]
+  oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'blur' }],
+  newPassword: [
+    { required: true, message: '新密码不能为空', trigger: 'blur' },
+    {
+      min: 6,
+      max: 20,
+      message: '长度在 6 到 20 个字符',
+      trigger: 'blur'
+    }
+  ],
+  confirmPassword: [
+    { required: true, message: '确认密码不能为空', trigger: 'blur' },
+    {
+      required: true,
+      validator: equalToPassword,
+      trigger: 'blur'
+    }
+  ]
 });
 
 /** 提交按钮 */
@@ -55,7 +61,7 @@ const submit = () => {
   pwdRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       await updateUserPwd(user.value.oldPassword, user.value.newPassword);
-      proxy?.$modal.msgSuccess("修改成功");
+      proxy?.$modal.msgSuccess('修改成功');
     }
   });
 };

+ 19 - 20
src/views/system/user/profile/thirdParty.vue

@@ -4,14 +4,14 @@
       <el-table-column label="序号" width="50" type="index"></el-table-column>
       <el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
       <el-table-column label="头像" width="120" align="center" prop="avatar">
-        <template v-slot="scope">
+        <template #default="scope">
           <img :src="scope.row.avatar" style="width: 45px; height: 45px" />
         </template>
       </el-table-column>
       <el-table-column label="系统账号" width="180" align="center" prop="userName" :show-overflow-tooltip="true" />
       <el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
       <el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
-        <template v-slot="scope">
+        <template #default="scope">
           <el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
         </template>
       </el-table-column>
@@ -20,25 +20,25 @@
     <div id="git-user-binding">
       <h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
       <div id="authlist" class="user-bind">
-        <a class="third-app" href="#" @click="authUrl('wechat');" title="使用 微信 账号授权登录">
+        <a class="third-app" href="#" title="使用 微信 账号授权登录" @click="authUrl('wechat')">
           <div class="git-other-login-icon">
             <svg-icon icon-class="wechat" />
           </div>
           <span class="app-name">WeiXin</span>
         </a>
-        <a class="third-app" href="#" @click="authUrl('maxkey');" title="使用 MaxKey 账号授权登录">
+        <a class="third-app" href="#" title="使用 MaxKey 账号授权登录" @click="authUrl('maxkey')">
           <div class="git-other-login-icon">
             <svg-icon icon-class="maxkey" />
           </div>
           <span class="app-name">MaxKey</span>
         </a>
-        <a class="third-app" href="#" @click="authUrl('gitee');" title="使用 Gitee 账号授权登录">
+        <a class="third-app" href="#" title="使用 Gitee 账号授权登录" @click="authUrl('gitee')">
           <div class="git-other-login-icon">
             <svg-icon icon-class="gitee" />
           </div>
           <span class="app-name">Gitee</span>
         </a>
-        <a class="third-app" href="#" @click="authUrl('github');" title="使用 GitHub 账号授权登录">
+        <a class="third-app" href="#" title="使用 GitHub 账号授权登录" @click="authUrl('github')">
           <div class="git-other-login-icon">
             <svg-icon icon-class="github" />
           </div>
@@ -50,31 +50,32 @@
 </template>
 
 <script lang="ts" setup>
-import { authUnlock, authBinding } from "@/api/system/social/auth";
-import { PropType } from "vue";
+import { authUnlock, authBinding } from '@/api/system/social/auth';
+import { PropType } from 'vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const props = defineProps({
   auths: {
-    type: Object as PropType<any>,
+    type: Object as PropType<any>
   }
 });
 const auths = computed(() => props.auths);
 
-
 const unlockAuth = (row: any) => {
   ElMessageBox.confirm('您确定要解除"' + row.source + '"的账号绑定吗?')
     .then(() => {
       return authUnlock(row.id);
-    }).then((res: any) => {
+    })
+    .then((res: any) => {
       if (res.code === 200) {
-        proxy?.$modal.msgSuccess("解绑成功");
+        proxy?.$modal.msgSuccess('解绑成功');
         proxy?.$tab.refreshPage();
       } else {
         proxy?.$modal.msgError(res.msg);
       }
-    }).catch(() => { });
+    })
+    .catch(() => {});
 };
 
 const authUrl = (source: string) => {
@@ -111,7 +112,7 @@ const authUrl = (source: string) => {
   margin-top: 10px;
 }
 
-.git-other-login-icon>img {
+.git-other-login-icon > img {
   height: 32px;
 }
 
@@ -122,15 +123,13 @@ a {
 }
 
 .provider-desc {
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
-    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Liberation Sans",
-    "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Wenquanyi Micro Hei",
-    "WenQuanYi Zen Hei", "ST Heiti", SimHei, SimSun, "WenQuanYi Zen Hei Sharp",
-    sans-serif;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
+    'Liberation Sans', 'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun,
+    'WenQuanYi Zen Hei Sharp', sans-serif;
   font-size: 1.071rem;
 }
 
-td>img {
+td > img {
   height: 20px;
   width: 20px;
   display: inline-block;

+ 19 - 21
src/views/system/user/profile/userAvatar.vue

@@ -5,16 +5,16 @@
       <el-row>
         <el-col :xs="24" :md="12" :style="{ height: '350px' }">
           <vue-cropper
+            v-if="visible"
             ref="cropper"
             :img="options.img"
             :info="true"
-            :autoCrop="options.autoCrop"
-            :autoCropWidth="options.autoCropWidth"
-            :autoCropHeight="options.autoCropHeight"
-            :fixedBox="options.fixedBox"
-            :outputType="options.outputType"
-            @realTime="realTime"
-            v-if="visible"
+            :auto-crop="options.autoCrop"
+            :auto-crop-width="options.autoCropWidth"
+            :auto-crop-height="options.autoCropHeight"
+            :fixed-box="options.fixedBox"
+            :output-type="options.outputType"
+            @real-time="realTime"
           />
         </el-col>
         <el-col :xs="24" :md="12" :style="{ height: '350px' }">
@@ -56,10 +56,10 @@
 </template>
 
 <script setup lang="ts">
-import "vue-cropper/dist/index.css";
-import { VueCropper } from "vue-cropper";
-import { uploadAvatar } from "@/api/system/user";
-import useUserStore from "@/store/modules/user";
+import 'vue-cropper/dist/index.css';
+import { VueCropper } from 'vue-cropper';
+import { uploadAvatar } from '@/api/system/user';
+import useUserStore from '@/store/modules/user';
 
 interface Options {
   img: string | any; // 裁剪图片的地址
@@ -73,13 +73,12 @@ interface Options {
   visible: boolean;
 }
 
-
 const userStore = useUserStore();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const open = ref(false);
 const visible = ref(false);
-const title = ref("修改头像");
+const title = ref('修改头像');
 
 const cropper = ref<any>({});
 //图片裁剪数据
@@ -89,8 +88,8 @@ const options = reactive<Options>({
   autoCropWidth: 200,
   autoCropHeight: 200,
   fixedBox: true,
-  outputType: "png",
-  fileName: "",
+  outputType: 'png',
+  fileName: '',
   previews: {},
   visible: false
 });
@@ -104,8 +103,7 @@ const modalOpened = () => {
   visible.value = true;
 };
 /** 覆盖默认上传行为 */
-const requestUpload = (): any => {
-};
+const requestUpload = (): any => {};
 /** 向左旋转 */
 const rotateLeft = () => {
   cropper.value.rotateLeft();
@@ -121,8 +119,8 @@ const changeScale = (num: number) => {
 };
 /** 上传预处理 */
 const beforeUpload = (file: any) => {
-  if (file.type.indexOf("image/") == -1) {
-    proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
+  if (file.type.indexOf('image/') == -1) {
+    proxy?.$modal.msgError('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。');
   } else {
     const reader = new FileReader();
     reader.readAsDataURL(file);
@@ -136,7 +134,7 @@ const beforeUpload = (file: any) => {
 const uploadImg = async () => {
   cropper.value.getCropBlob(async (data: any) => {
     let formData = new FormData();
-    formData.append("avatarfile", data, options.fileName);
+    formData.append('avatarfile', data, options.fileName);
     const res = await uploadAvatar(formData);
     open.value = false;
     options.img = res.data.imgUrl;
@@ -164,7 +162,7 @@ const closeDialog = () => {
 }
 
 .user-info-head:hover:after {
-  content: "+";
+  content: '+';
   position: absolute;
   left: 0;
   right: 0;

+ 19 - 14
src/views/system/user/profile/userInfo.vue

@@ -23,7 +23,7 @@
 </template>
 
 <script setup lang="ts">
-import { updateUserProfile } from "@/api/system/user";
+import { updateUserProfile } from '@/api/system/user';
 
 const props = defineProps({
   user: {
@@ -35,26 +35,31 @@ const userForm = computed(() => props.user);
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const userRef = ref<ElFormInstance>();
 const rules = ref<ElFormRules>({
-  nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
-  email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, {
-    type: "email",
-    message: "请输入正确的邮箱地址",
-    trigger: ["blur", "change"]
-  }],
-  phonenumber: [{
-    required: true,
-    message: "手机号码不能为空",
-    trigger: "blur"
-  }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
+  nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
+  email: [
+    { required: true, message: '邮箱地址不能为空', trigger: 'blur' },
+    {
+      type: 'email',
+      message: '请输入正确的邮箱地址',
+      trigger: ['blur', 'change']
+    }
+  ],
+  phonenumber: [
+    {
+      required: true,
+      message: '手机号码不能为空',
+      trigger: 'blur'
+    },
+    { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ]
 });
 
-
 /** 提交按钮 */
 const submit = () => {
   userRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       await updateUserProfile(props.user);
-      proxy?.$modal.msgSuccess("修改成功");
+      proxy?.$modal.msgSuccess('修改成功');
     }
   });
 };

+ 11 - 11
src/views/tool/gen/basicInfoForm.vue

@@ -3,27 +3,27 @@
     <el-row>
       <el-col :span="12">
         <el-form-item label="表名称" prop="tableName">
-          <el-input placeholder="请输入仓库名称" v-model="infoForm.tableName" />
+          <el-input v-model="infoForm.tableName" placeholder="请输入仓库名称" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
         <el-form-item label="表描述" prop="tableComment">
-          <el-input placeholder="请输入" v-model="infoForm.tableComment" />
+          <el-input v-model="infoForm.tableComment" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
         <el-form-item label="实体类名称" prop="className">
-          <el-input placeholder="请输入" v-model="infoForm.className" />
+          <el-input v-model="infoForm.className" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
         <el-form-item label="作者" prop="functionAuthor">
-          <el-input placeholder="请输入" v-model="infoForm.functionAuthor" />
+          <el-input v-model="infoForm.functionAuthor" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="24">
         <el-form-item label="备注" prop="remark">
-          <el-input type="textarea" :rows="3" v-model="infoForm.remark"></el-input>
+          <el-input v-model="infoForm.remark" type="textarea" :rows="3"></el-input>
         </el-form-item>
       </el-col>
     </el-row>
@@ -31,19 +31,19 @@
 </template>
 
 <script setup lang="ts">
-import { propTypes } from "@/utils/propTypes";
+import { propTypes } from '@/utils/propTypes';
 
 const prop = defineProps({
   info: propTypes.any.def({})
 });
 
-const infoForm = computed(() => prop.info)
+const infoForm = computed(() => prop.info);
 
 // 表单校验
 const rules = ref({
-  tableName: [{ required: true, message: "请输入表名称", trigger: "blur" }],
-  tableComment: [{ required: true, message: "请输入表描述", trigger: "blur" }],
-  className: [{ required: true, message: "请输入实体类名称", trigger: "blur" }],
-  functionAuthor: [{ required: true, message: "请输入作者", trigger: "blur" }]
+  tableName: [{ required: true, message: '请输入表名称', trigger: 'blur' }],
+  tableComment: [{ required: true, message: '请输入表描述', trigger: 'blur' }],
+  className: [{ required: true, message: '请输入实体类名称', trigger: 'blur' }],
+  functionAuthor: [{ required: true, message: '请输入作者', trigger: 'blur' }]
 });
 </script>

+ 16 - 16
src/views/tool/gen/editTable.vue

@@ -35,22 +35,22 @@
 
           <el-table-column label="插入" min-width="5%">
             <template #default="scope">
-              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
+              <el-checkbox v-model="scope.row.isInsert" true-label="1" false-label="0"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="编辑" min-width="5%">
             <template #default="scope">
-              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
+              <el-checkbox v-model="scope.row.isEdit" true-label="1" false-label="0"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="列表" min-width="5%">
             <template #default="scope">
-              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
+              <el-checkbox v-model="scope.row.isList" true-label="1" false-label="0"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="查询" min-width="5%">
             <template #default="scope">
-              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
+              <el-checkbox v-model="scope.row.isQuery" true-label="1" false-label="0"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="查询方式" min-width="10%">
@@ -69,7 +69,7 @@
           </el-table-column>
           <el-table-column label="必填" min-width="5%">
             <template #default="scope">
-              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
+              <el-checkbox v-model="scope.row.isRequired" true-label="1" false-label="0"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="显示类型" min-width="12%">
@@ -104,7 +104,7 @@
       </el-tab-pane>
     </el-tabs>
     <el-form label-width="100px">
-      <div style="text-align: center;margin-left:-100px;margin-top:10px;">
+      <div style="text-align: center; margin-left: -100px; margin-top: 10px">
         <el-button type="primary" @click="submitForm()">提交</el-button>
         <el-button @click="close()">返回</el-button>
       </div>
@@ -118,7 +118,7 @@ import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
 import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
 import { DictTypeVO } from '@/api/system/dict/type/types';
 import BasicInfoForm from './basicInfoForm.vue';
-import GenInfoForm from "./genInfoForm.vue";
+import GenInfoForm from './genInfoForm.vue';
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -138,8 +138,8 @@ const submitForm = () => {
   const basicForm = basicInfo.value?.$refs.basicInfoForm;
   const genForm = genInfo.value?.$refs.genInfoForm;
 
-  Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
-    const validateResult = res.every(item => !!item);
+  Promise.all([basicForm, genForm].map(getFormPromise)).then(async (res) => {
+    const validateResult = res.every((item) => !!item);
     if (validateResult) {
       const genTable: any = Object.assign({}, info.value);
       genTable.columns = columns.value;
@@ -155,24 +155,24 @@ const submitForm = () => {
         close();
       }
     } else {
-      proxy?.$modal.msgError("表单校验未通过,请重新检查提交内容");
+      proxy?.$modal.msgError('表单校验未通过,请重新检查提交内容');
     }
   });
-}
+};
 const getFormPromise = (form: any) => {
-  return new Promise(resolve => {
+  return new Promise((resolve) => {
     form.validate((res: any) => {
       resolve(res);
     });
   });
-}
+};
 const close = () => {
-  const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: route.query.pageNum } };
+  const obj = { path: '/tool/gen', query: { t: Date.now(), pageNum: route.query.pageNum } };
   proxy?.$tab.closeOpenPage(obj);
-}
+};
 
 (async () => {
-  const tableId = route.params && route.params.tableId as string;
+  const tableId = route.params && (route.params.tableId as string);
   if (tableId) {
     // 获取表详细信息
     const res = await getGenTable(tableId);

+ 26 - 23
src/views/tool/gen/genInfoForm.vue

@@ -95,7 +95,7 @@
         </el-form-item>
       </el-col>
 
-      <el-col :span="24" v-if="infoForm.genType == '1'">
+      <el-col v-if="infoForm.genType == '1'" :span="24">
         <el-form-item prop="genPath">
           <template #label>
             自定义路径
@@ -223,7 +223,7 @@
 
 <script setup lang="ts">
 import { listMenu } from '@/api/system/menu';
-import { propTypes } from "@/utils/propTypes";
+import { propTypes } from '@/utils/propTypes';
 
 interface MenuOptionsType {
   menuId: number | string;
@@ -246,21 +246,21 @@ const table = computed(() => props.tables);
 
 // 表单校验
 const rules = ref({
-  tplCategory: [{ required: true, message: "请选择生成模板", trigger: "blur" }],
-  packageName: [{ required: true, message: "请输入生成包路径", trigger: "blur" }],
-  moduleName: [{ required: true, message: "请输入生成模块名", trigger: "blur" }],
-  businessName: [{ required: true, message: "请输入生成业务名", trigger: "blur" }],
-  functionName: [{ required: true, message: "请输入生成功能名", trigger: "blur" }]
+  tplCategory: [{ required: true, message: '请选择生成模板', trigger: 'blur' }],
+  packageName: [{ required: true, message: '请输入生成包路径', trigger: 'blur' }],
+  moduleName: [{ required: true, message: '请输入生成模块名', trigger: 'blur' }],
+  businessName: [{ required: true, message: '请输入生成业务名', trigger: 'blur' }],
+  functionName: [{ required: true, message: '请输入生成功能名', trigger: 'blur' }]
 });
 const subSelectChange = () => {
-  infoForm.value.subTableFkName = "";
-}
+  infoForm.value.subTableFkName = '';
+};
 const tplSelectChange = (value: string) => {
-  if (value !== "sub") {
-    infoForm.value.subTableName = "";
-    infoForm.value.subTableFkName = "";
+  if (value !== 'sub') {
+    infoForm.value.subTableName = '';
+    infoForm.value.subTableFkName = '';
   }
-}
+};
 const setSubTableColumns = (value: string) => {
   table.value.forEach((item: any) => {
     const name = item.tableName;
@@ -268,24 +268,27 @@ const setSubTableColumns = (value: string) => {
       subColumns.value = item.columns;
       return;
     }
-  })
-}
+  });
+};
 
 /** 查询菜单下拉树结构 */
 const getMenuTreeselect = async () => {
   const res = await listMenu();
-  res.data.forEach(m => m.menuId = m.menuId.toString());
-  const data = proxy?.handleTree<MenuOptionsType>(res.data, "menuId");
+  res.data.forEach((m) => (m.menuId = m.menuId.toString()));
+  const data = proxy?.handleTree<MenuOptionsType>(res.data, 'menuId');
   if (data) {
-    menuOptions.value = data
+    menuOptions.value = data;
   }
-}
+};
 
-watch(() => props.info.subTableName, val => {
-  setSubTableColumns(val);
-});
+watch(
+  () => props.info.subTableName,
+  (val) => {
+    setSubTableColumns(val);
+  }
+);
 
 onMounted(() => {
   getMenuTreeselect();
-})
+});
 </script>

+ 20 - 20
src/views/tool/gen/importTable.vue

@@ -1,7 +1,7 @@
 <template>
   <!-- 导入表 -->
-  <el-dialog title="导入表" v-model="visible" width="1100px" top="5vh" append-to-body>
-    <el-form :model="queryParams" ref="queryFormRef" :inline="true">
+  <el-dialog v-model="visible" title="导入表" width="1100px" top="5vh" append-to-body>
+    <el-form ref="queryFormRef" :model="queryParams" :inline="true">
       <el-form-item label="数据源" prop="dataName">
         <el-select v-model="queryParams.dataName" filterable placeholder="请选择/输入数据源名称" style="width: 200px">
           <el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
@@ -19,14 +19,14 @@
       </el-form-item>
     </el-form>
     <el-row>
-      <el-table @row-click="clickRow" ref="tableRef" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
+      <el-table ref="tableRef" :data="dbTableList" height="260px" @row-click="clickRow" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55"></el-table-column>
         <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
         <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
         <el-table-column prop="createTime" label="创建时间"></el-table-column>
         <el-table-column prop="updateTime" label="更新时间"></el-table-column>
       </el-table>
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-row>
     <template #footer>
       <div class="dialog-footer">
@@ -59,7 +59,7 @@ const queryParams = reactive<DbTableQuery>({
 });
 const dataNameList = ref<Array<string>>([]);
 
-const emit = defineEmits(["ok"]);
+const emit = defineEmits(['ok']);
 
 /** 查询参数列表 */
 const show = (dataName: string) => {
@@ -71,53 +71,53 @@ const show = (dataName: string) => {
   }
   getList();
   visible.value = true;
-}
+};
 /** 单击选择行 */
 const clickRow = (row: DbTableVO) => {
   // ele bug
   tableRef.value?.toggleRowSelection(row, false);
-}
+};
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DbTableVO[]) => {
-  tables.value = selection.map(item => item.tableName);
-}
+  tables.value = selection.map((item) => item.tableName);
+};
 /** 查询表数据 */
 const getList = async () => {
   const res = await listDbTable(queryParams);
   dbTableList.value = res.rows;
   total.value = res.total;
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNum = 1;
   getList();
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 导入按钮操作 */
 const handleImportTable = async () => {
-  const tableNames = tables.value.join(",");
-  if (tableNames == "") {
-    proxy?.$modal.msgError("请选择要导入的表");
+  const tableNames = tables.value.join(',');
+  if (tableNames == '') {
+    proxy?.$modal.msgError('请选择要导入的表');
     return;
   }
   const res = await importTable({ tables: tableNames, dataName: queryParams.dataName });
   proxy?.$modal.msgSuccess(res.msg);
   if (res.code === 200) {
     visible.value = false;
-    emit("ok");
+    emit('ok');
   }
-}
+};
 /** 查询多数据源名称 */
 const getDataNameList = async () => {
-  const res = await getDataNames()
+  const res = await getDataNames();
   dataNameList.value = res.data;
-}
+};
 
 defineExpose({
-  show,
+  show
 });
 </script>

+ 37 - 37
src/views/tool/gen/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-      <div class="mb-[10px]" v-show="showSearch">
+      <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
             <el-form-item label="数据源" prop="dataName">
               <el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
                 <el-option key="" label="全部" value="" />
@@ -39,20 +39,20 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button type="primary" plain icon="Download" @click="handleGenTable()" v-hasPermi="['tool:gen:code']">生成</el-button>
+            <el-button v-hasPermi="['tool:gen:code']" type="primary" plain icon="Download" @click="handleGenTable()">生成</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="info" plain icon="Upload" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
+            <el-button v-hasPermi="['tool:gen:import']" type="info" plain icon="Upload" @click="openImportTable">导入</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()" v-hasPermi="['tool:gen:edit']">修改</el-button>
+            <el-button v-hasPermi="['tool:gen:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleEditTable()">修改</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['tool:gen:remove']">
+            <el-button v-hasPermi="['tool:gen:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
               删除
             </el-button>
           </el-col>
-          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
       </template>
 
@@ -72,28 +72,28 @@
         <el-table-column label="操作" align="center" width="330" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-tooltip content="预览" placement="top">
-              <el-button link type="primary" icon="View" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']"></el-button>
+              <el-button v-hasPermi="['tool:gen:preview']" link type="primary" icon="View" @click="handlePreview(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="编辑" placement="top">
-              <el-button link type="primary" icon="Edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
+              <el-button v-hasPermi="['tool:gen:edit']" link type="primary" icon="Edit" @click="handleEditTable(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']"></el-button>
+              <el-button v-hasPermi="['tool:gen:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="同步" placement="top">
-              <el-button link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']"></el-button>
+              <el-button v-hasPermi="['tool:gen:edit']" link type="primary" icon="Refresh" @click="handleSynchDb(scope.row)"></el-button>
             </el-tooltip>
             <el-tooltip content="生成代码" placement="top">
-              <el-button link type="primary" icon="Download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']"></el-button>
+              <el-button v-hasPermi="['tool:gen:code']" link type="primary" icon="Download" @click="handleGenTable(scope.row)"></el-button>
             </el-tooltip>
           </template>
         </el-table-column>
       </el-table>
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
 
     <!-- 预览界面 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="80%" top="5vh" append-to-body class="scrollbar">
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="80%" top="5vh" append-to-body class="scrollbar">
       <el-tabs v-model="preview.activeName">
         <el-tab-pane
           v-for="(value, key) in preview.data"
@@ -101,7 +101,7 @@
           :name="key.substring(key.lastIndexOf('/') + 1, key.indexOf('.vm'))"
           :key="value"
         >
-          <el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">
+          <el-link v-copyText="value" v-copyText:callback="copyTextSuccess" :underline="false" icon="DocumentCopy" style="float: right">
             &nbsp;复制
           </el-link>
           <pre>{{ value }}</pre>
@@ -129,7 +129,7 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const uniqueId = ref("");
+const uniqueId = ref('');
 const dataNameList = ref<Array<string>>([]);
 
 const queryFormRef = ref<ElFormInstance>();
@@ -140,13 +140,13 @@ const queryParams = ref<TableQuery>({
   pageSize: 10,
   tableName: '',
   tableComment: '',
-  dataName: ""
-})
+  dataName: ''
+});
 
 const preview = ref<any>({
   data: {},
   activeName: 'domain.java'
-})
+});
 const dialog = reactive<DialogOption>({
   visible: false,
   title: '代码预览'
@@ -161,13 +161,13 @@ onActivated(() => {
     queryFormRef.value?.resetFields();
     getList();
   }
-})
+});
 
 /** 查询多数据源名称 */
 const getDataNameList = async () => {
-  const res = await getDataNames()
+  const res = await getDataNames();
   dataNameList.value = res.data;
-}
+};
 
 /** 查询表集合 */
 const getList = async () => {
@@ -176,65 +176,65 @@ const getList = async () => {
   tableList.value = res.rows;
   total.value = res.total;
   loading.value = false;
-}
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
   getList();
-}
+};
 /** 生成代码操作 */
 const handleGenTable = async (row?: TableVO) => {
   const tbIds = row?.tableId || ids.value;
-  if (tbIds == "") {
+  if (tbIds == '') {
     proxy?.$modal.msgError('请选择要生成的数据');
     return;
   }
-  if (row?.genType === "1") {
+  if (row?.genType === '1') {
     await genCode(row.tableId);
     proxy?.$modal.msgSuccess('成功生成到自定义路径:' + row.genPath);
   } else {
     proxy?.$download.zip('/tool/gen/batchGenCode?tableIdStr=' + tbIds, 'ruoyi.zip');
   }
-}
+};
 /** 同步数据库操作 */
 const handleSynchDb = async (row: TableVO) => {
   const tableId = row.tableId;
   await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
   await synchDb(tableId);
   proxy?.$modal.msgSuccess('同步成功');
-}
+};
 /** 打开导入表弹窗 */
 const openImportTable = () => {
   importRef.value?.show(queryParams.value.dataName);
-}
+};
 /** 重置按钮操作 */
 const resetQuery = () => {
   dateRange.value = ['', ''];
   queryFormRef.value?.resetFields();
   handleQuery();
-}
+};
 /** 预览按钮 */
 const handlePreview = async (row: TableVO) => {
   const res = await previewTable(row.tableId);
   preview.value.data = res.data;
   dialog.visible = true;
   preview.value.activeName = 'domain.java';
-}
+};
 /** 复制代码成功 */
 const copyTextSuccess = () => {
   proxy?.$modal.msgSuccess('复制成功');
-}
+};
 // 多选框选中数据
 const handleSelectionChange = (selection: TableVO[]) => {
-  ids.value = selection.map(item => item.tableId);
+  ids.value = selection.map((item) => item.tableId);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 /** 修改按钮操作 */
 const handleEditTable = (row?: TableVO) => {
   const tableId = row?.tableId || ids.value[0];
   router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: queryParams.value.pageNum } });
-}
+};
 /** 删除按钮操作 */
 const handleDelete = async (row?: TableVO) => {
   const tableIds = row?.tableId || ids.value;
@@ -242,10 +242,10 @@ const handleDelete = async (row?: TableVO) => {
   await delTable(tableIds);
   await getList();
   proxy?.$modal.msgSuccess('删除成功');
-}
+};
 
 onMounted(() => {
   getList();
   getDataNameList();
-})
+});
 </script>

+ 4 - 4
tsconfig.json

@@ -1,8 +1,8 @@
 {
   "compilerOptions": {
-    "target": "es2022",
-    "useDefineForClassFields": true,
+    "target": "esnext",
     "module": "esnext",
+    "useDefineForClassFields": true,
     "moduleResolution": "node",
     "strict": true,
     "jsx": "preserve",
@@ -21,6 +21,6 @@
     "allowSyntheticDefaultImports": true,
     "forceConsistentCasingInFileNames": true
   },
-  "include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts"],
-  "exclude": ["node_modules", "dist", "**/*.js"]
+  "include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts", "vite.config.ts"],
+  "exclude": ["node_modules", "dist", "**/*.js", "**/*.md", "src/**/*.md"]
 }