Parcourir la source

!25 部分优化以及新增功能
Merge pull request !25 from ahaos/tspr

疯狂的狮子Li il y a 2 ans
Parent
commit
c13c622eac
73 fichiers modifiés avec 3434 ajouts et 3021 suppressions
  1. 31 0
      .eslintrc-auto-import.json
  2. 2 1
      .eslintrc.js
  3. 4 2
      package.json
  4. 45 28
      src/api/system/user/index.ts
  5. 6 1
      src/assets/styles/index.scss
  6. 2 2
      src/assets/styles/ruoyi.scss
  7. 2 2
      src/assets/styles/sidebar.scss
  8. 45 20
      src/assets/styles/variables.module.scss
  9. 19 19
      src/components/Breadcrumb/index.vue
  10. 64 0
      src/components/BuildCode/index.vue
  11. 62 0
      src/components/BuildCode/render.vue
  12. 2 5
      src/components/DictTag/index.vue
  13. 100 102
      src/components/Editor/index.vue
  14. 25 35
      src/components/FileUpload/index.vue
  15. 5 6
      src/components/Hamburger/index.vue
  16. 39 39
      src/components/HeaderSearch/index.vue
  17. 3 9
      src/components/IconSelect/index.vue
  18. 30 28
      src/components/ImagePreview/index.vue
  19. 13 20
      src/components/ImageUpload/index.vue
  20. 12 42
      src/components/Pagination/index.vue
  21. 4 14
      src/components/RightToolbar/index.vue
  22. 5 12
      src/components/SvgIcon/index.vue
  23. 38 38
      src/components/TreeSelect/index.vue
  24. 3 4
      src/components/iFrame/index.vue
  25. 1 1
      src/layout/components/IframeToggle/index.vue
  26. 41 29
      src/layout/components/Navbar.vue
  27. 18 5
      src/layout/components/Settings/index.vue
  28. 6 7
      src/layout/components/TagsView/ScrollPane.vue
  29. 11 6
      src/layout/components/TagsView/index.vue
  30. 158 0
      src/layout/components/topBar/search.vue
  31. 15 15
      src/plugins/modal.ts
  32. 33 16
      src/plugins/tab.ts
  33. 6 2
      src/store/modules/tagsView.ts
  34. 35 1
      src/types/element.d.ts
  35. 16 10
      src/types/global.d.ts
  36. 15 11
      src/types/module.d.ts
  37. 4 4
      src/types/router.d.ts
  38. 4 0
      src/types/vform3-builds.d.ts
  39. 25 0
      src/utils/propTypes.ts
  40. 38 42
      src/views/demo/demo/index.vue
  41. 21 21
      src/views/demo/tree/index.vue
  42. 0 1
      src/views/error/401.vue
  43. 6 7
      src/views/login.vue
  44. 3 4
      src/views/monitor/cache/index.vue
  45. 38 38
      src/views/monitor/logininfor/index.vue
  46. 36 35
      src/views/monitor/online/index.vue
  47. 107 107
      src/views/monitor/operlog/index.vue
  48. 62 63
      src/views/register.vue
  49. 104 104
      src/views/system/config/index.vue
  50. 114 109
      src/views/system/dept/index.vue
  51. 114 114
      src/views/system/dict/data.vue
  52. 106 106
      src/views/system/dict/index.vue
  53. 102 103
      src/views/system/menu/index.vue
  54. 89 89
      src/views/system/notice/index.vue
  55. 165 165
      src/views/system/oss/config.vue
  56. 148 148
      src/views/system/oss/index.vue
  57. 90 89
      src/views/system/post/index.vue
  58. 36 44
      src/views/system/role/authUser.vue
  59. 219 211
      src/views/system/role/index.vue
  60. 34 35
      src/views/system/role/selectUser.vue
  61. 142 142
      src/views/system/tenant/index.vue
  62. 179 168
      src/views/system/tenantPackage/index.vue
  63. 39 39
      src/views/system/user/authRole.vue
  64. 212 215
      src/views/system/user/index.vue
  65. 2 2
      src/views/system/user/profile/index.vue
  66. 30 26
      src/views/system/user/profile/resetPwd.vue
  67. 61 59
      src/views/system/user/profile/userAvatar.vue
  68. 24 22
      src/views/system/user/profile/userInfo.vue
  69. 6 11
      src/views/tool/gen/basicInfoForm.vue
  70. 7 8
      src/views/tool/gen/editTable.vue
  71. 9 15
      src/views/tool/gen/genInfoForm.vue
  72. 43 44
      src/views/tool/gen/importTable.vue
  73. 99 99
      src/views/tool/gen/index.vue

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

@@ -1,5 +1,36 @@
 {
   "globals": {
+    "ComponentInternalInstance": true,
+    "TransferKey": true,
+    "ElFormRules": true,
+    "CheckboxValueType": true,
+    "PropType": true,
+    "DateModelType": true,
+    "UploadFile": true,
+    "ElFormInstance": true,
+    "ElTableInstance": true,
+    "ElTreeInstance": true,
+    "ElTreeSelectInstance": true,
+    "ElSelectInstance": true,
+    "ElUploadInstance": true,
+    "ElCardInstance": true,
+    "ElDialogInstance": true,
+    "ElInputInstance": true,
+    "ElInputNumberInstance": true,
+    "ElRadioInstance": true,
+    "ElRadioGroupInstance": true,
+    "ElRadioButtonInstance": true,
+    "ElCheckboxInstance": true,
+    "ElCheckboxGroupInstance": true,
+    "ElSwitchInstance": true,
+    "ElDatePickerInstance": true,
+    "ElTimePickerInstance": true,
+    "ElTimeSelectInstance": true,
+    "ElScrollbarInstance": true,
+    "ElCascaderInstance": true,
+    "ElColorPickerInstance": true,
+    "ElRateInstance": true,
+    "ElSliderInstance": true,
     "useRouter": true,
     "useRoute": true,
     "EffectScope": true,

+ 2 - 1
.eslintrc.js

@@ -29,7 +29,8 @@ module.exports = {
         // 关闭空类型检查 {}
         extendDefaults: true,
         types: {
-          '{}': false
+          '{}': false,
+          'Function': false
         }
       }
     ]

+ 4 - 2
package.json

@@ -35,10 +35,12 @@
     "path-to-regexp": "6.2.0",
     "pinia": "2.0.22",
     "screenfull": "6.0.0",
+    "vform3-builds": "3.0.8",
     "vue": "3.2.45",
     "vue-cropper": "1.0.3",
     "vue-i18n": "9.2.2",
-    "vue-router": "4.1.4"
+    "vue-router": "4.1.4",
+    "vue-types": "^5.0.3"
   },
   "devDependencies": {
     "@iconify/json": "^2.2.40",
@@ -71,11 +73,11 @@
     "unplugin-auto-import": "0.13.0",
     "unplugin-icons": "0.15.1",
     "unplugin-vue-components": "0.23.0",
+    "vite": "4.3.1",
     "vite-plugin-compression": "0.5.1",
     "vite-plugin-svg-icons": "2.0.1",
     "vite-plugin-vue-setup-extend": "^0.4.0",
     "vitest": "^0.29.7",
-    "vite": "4.3.1",
     "vue-eslint-parser": "9.1.0",
     "vue-tsc": "0.35.0"
   }

+ 45 - 28
src/api/system/user/index.ts

@@ -9,64 +9,64 @@ import { parseStrEmpty } from '@/utils/ruoyi';
  * 查询用户列表
  * @param query
  */
-export function listUser(query: UserQuery): AxiosPromise<UserVO[]> {
+export const listUser = (query: UserQuery): AxiosPromise<UserVO[]> => {
   return request({
     url: '/system/user/list',
     method: 'get',
     params: query
   });
-}
+};
 
 /**
  * 获取用户详情
  * @param userId
  */
-export function getUser(userId?: string | number): AxiosPromise<UserInfoVO> {
+export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
   return request({
     url: '/system/user/' + parseStrEmpty(userId),
     method: 'get'
   });
-}
+};
 
 /**
  * 新增用户
  */
-export function addUser(data: UserForm) {
+export const addUser = (data: UserForm) => {
   return request({
     url: '/system/user',
     method: 'post',
     data: data
   });
-}
+};
 
 /**
  * 修改用户
  */
-export function updateUser(data: UserForm) {
+export const updateUser = (data: UserForm) => {
   return request({
     url: '/system/user',
     method: 'put',
     data: data
   });
-}
+};
 
 /**
  * 删除用户
  * @param userId 用户ID
  */
-export function delUser(userId: Array<string | number> | string | number) {
+export const delUser = (userId: Array<string | number> | string | number) => {
   return request({
     url: '/system/user/' + userId,
     method: 'delete'
   });
-}
+};
 
 /**
  * 用户密码重置
  * @param userId 用户ID
  * @param password 密码
  */
-export function resetUserPwd(userId: string | number, password: string) {
+export const resetUserPwd = (userId: string | number, password: string) => {
   const data = {
     userId,
     password
@@ -76,14 +76,14 @@ export function resetUserPwd(userId: string | number, password: string) {
     method: 'put',
     data: data
   });
-}
+};
 
 /**
  * 用户状态修改
  * @param userId 用户ID
  * @param status 用户状态
  */
-export function changeUserStatus(userId: number | string, status: string) {
+export const changeUserStatus = (userId: number | string, status: string) => {
   const data = {
     userId,
     status
@@ -93,36 +93,36 @@ export function changeUserStatus(userId: number | string, status: string) {
     method: 'put',
     data: data
   });
-}
+};
 
 /**
  * 查询用户个人信息
  */
-export function getUserProfile(): AxiosPromise<UserInfoVO> {
+export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
   return request({
     url: '/system/user/profile',
     method: 'get'
   });
-}
+};
 
 /**
  * 修改用户个人信息
  * @param data 用户信息
  */
-export function updateUserProfile(data: UserForm) {
+export const updateUserProfile = (data: UserForm) => {
   return request({
     url: '/system/user/profile',
     method: 'put',
     data: data
   });
-}
+};
 
 /**
  * 用户密码重置
  * @param oldPassword 旧密码
  * @param newPassword 新密码
  */
-export function updateUserPwd(oldPassword: string, newPassword: string) {
+export const updateUserPwd = (oldPassword: string, newPassword: string) => {
   const data = {
     oldPassword,
     newPassword
@@ -132,49 +132,66 @@ export function updateUserPwd(oldPassword: string, newPassword: string) {
     method: 'put',
     params: data
   });
-}
+};
 
 /**
  * 用户头像上传
  * @param data 头像文件
  */
-export function uploadAvatar(data: FormData) {
+export const uploadAvatar = (data: FormData) => {
   return request({
     url: '/system/user/profile/avatar',
     method: 'post',
     data: data
   });
-}
+};
 
 /**
  * 查询授权角色
  * @param userId 用户ID
  */
-export function getAuthRole(userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> {
+export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
   return request({
     url: '/system/user/authRole/' + userId,
     method: 'get'
   });
-}
+};
 
 /**
  * 保存授权角色
  * @param data 用户ID
  */
-export function updateAuthRole(data: { userId: string; roleIds: string }) {
+export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
   return request({
     url: '/system/user/authRole',
     method: 'put',
     params: data
   });
-}
+};
 
 /**
  * 查询部门下拉树结构
  */
-export function deptTreeSelect(): AxiosPromise<DeptVO[]> {
+export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
   return request({
     url: '/system/user/deptTree',
     method: 'get'
   });
-}
+};
+
+export default {
+  listUser,
+  getUser,
+  addUser,
+  updateUser,
+  delUser,
+  resetUserPwd,
+  changeUserStatus,
+  getUserProfile,
+  updateUserProfile,
+  updateUserPwd,
+  uploadAvatar,
+  getAuthRole,
+  updateAuthRole,
+  deptTreeSelect
+};

+ 6 - 1
src/assets/styles/index.scss

@@ -26,6 +26,10 @@ html {
   box-sizing: border-box;
 }
 
+html.dark .svg-icon, html.dark svg {
+  fill: var(--el-text-color-regular);
+}
+
 #app {
   height: 100%;
 }
@@ -137,6 +141,7 @@ aside {
   border: 1px solid var(--el-border-color-light);
   background-color: var(--el-bg-color-overlay);
   padding: 0.75rem;
+  transition: all ease 0.3s;
 
   &:hover {
     box-shadow: 0 2px 12px #0000001a;
@@ -199,4 +204,4 @@ aside {
     vertical-align: middle;
     margin-bottom: 10px;
   }
-}
+}

+ 2 - 2
src/assets/styles/ruoyi.scss

@@ -90,8 +90,8 @@ h6 {
   .el-table__fixed-header-wrapper {
     th {
       word-break: break-word;
-      background-color: #f8f8f9 !important;
-      color: #515a6e;
+      background-color: $table-header-bg !important;
+      color: $table-header-text-color;
       height: 40px !important;
       font-size: 13px;
     }

+ 2 - 2
src/assets/styles/sidebar.scss

@@ -84,7 +84,7 @@
     .sub-menu-title-noDropdown,
     .el-sub-menu__title {
       &:hover {
-        background-color: rgba(0, 0, 0, 0.06) !important;
+        background-color: $base-sub-menu-title-hover !important;
       }
     }
 
@@ -211,7 +211,7 @@
   .el-menu-item {
     &:hover {
       // you can use $sub-menuHover
-      background-color: rgba(0, 0, 0, 0.06) !important;
+      background-color: $base-menu-hover !important;
     }
   }
 

+ 45 - 20
src/assets/styles/variables.module.scss

@@ -1,3 +1,38 @@
+// 全局SCSS变量
+:root {
+  --menuBg: #304156;
+  --menuColor: #bfcbd9;
+  --menuActiveText: #f4f4f5;
+  --menuHover: #263445;
+
+  --subMenuBg: #1f2d3d;
+  --subMenuActiveText: #f4f4f5;
+  --subMenuHover: #001528;
+  --subMenuTitleHover: #293444;
+
+  --tableHeaderBg: #f8f8f9;
+  --tableHeaderTextColor: #515a6e;
+}
+html.dark {
+  --menuBg: #1d1e1f;
+  --menuColor: #bfcbd9;
+  --menuActiveText: #f4f4f5;
+  --menuHover: #171819;
+
+  --subMenuBg: #1d1e1f;
+  --subMenuActiveText: #1d1e1f;
+  --subMenuHover: #171819;
+  --subMenuTitleHover: #171819;
+
+  --tableHeaderBg: var(--el-bg-color);
+  --tableHeaderTextColor: var(--el-text-color);
+
+  // 覆盖ele 高亮当前行的标准暗色
+  .el-tree-node__content {
+    --el-color-primary-light-9: #262727;
+  }
+}
+
 // base color
 $blue: #324157;
 $light-blue: #3a71a8;
@@ -9,32 +44,22 @@ $yellow: #fec171;
 $panGreen: #30b08f;
 
 // 默认菜单主题风格
-$base-menu-color: #bfcbd9;
-$base-menu-color-active: #f4f4f5;
-$base-menu-background: #304156;
+$base-menu-color: var(--menuColor);
+$base-menu-hover: var(--menuHover);
+$base-menu-color-active: var(--menuActiveText);
+$base-menu-background: var(--menuBg);
 $base-logo-title-color: #ffffff;
 
 $base-menu-light-color: rgba(0, 0, 0, 0.7);
 $base-menu-light-background: #ffffff;
 $base-logo-light-title-color: #001529;
 
-$base-sub-menu-background: #1f2d3d;
-$base-sub-menu-hover: #001528;
-
-// 自定义暗色菜单风格
-/**
-$base-menu-color:hsla(0,0%,100%,.65);
-$base-menu-color-active:#fff;
-$base-menu-background:#001529;
-$base-logo-title-color: #ffffff;
-
-$base-menu-light-color:rgba(0,0,0,.70);
-$base-menu-light-background:#ffffff;
-$base-logo-light-title-color: #001529;
-
-$base-sub-menu-background:#000c17;
-$base-sub-menu-hover:#001528;
-*/
+$base-sub-menu-background: var(--subMenuBg);
+$base-sub-menu-hover: var(--subMenuHover);
+$base-sub-menu-title-hover: var(--subMenuTitleHover);
+// 表单头背景色和标题颜色
+$table-header-bg: var(--tableHeaderBg);
+$table-header-text-color: var(--tableHeaderTextColor);
 
 $--color-primary: #409eff;
 $--color-success: #67c23a;

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

@@ -18,34 +18,34 @@ const router = useRouter();
 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]
-    // 判断是否为首页
-    if (!isDashboard(first)) {
-        matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched)
-    }
-    levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+  // only show routes with meta.title
+  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)
+  }
+  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
-    if (!name) {
-        return false
-    }
-    return name.trim() === 'Index'
+  const name = route && route.name as string
+  if (!name) {
+    return false
+  }
+  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 you go to the redirect page, do not update the breadcrumbs
+  if (route.path.startsWith('/redirect/')) return
+  getBreadcrumb()
 })
 onMounted(() => {
-    getBreadcrumb();
+  getBreadcrumb();
 })
 </script>
 

+ 64 - 0
src/components/BuildCode/index.vue

@@ -0,0 +1,64 @@
+<!-- 代码构建 -->
+<script setup lang="ts">
+
+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())
+  let data = {
+    formJson, fieldJson
+  }
+  emits("saveDesign", data)
+}
+
+onMounted(() => {
+  if (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;
+  overflow-y: auto !important;
+
+  & header.main-header {
+    display: none;
+  }
+
+  & .right-toolbar-con {
+    text-align: right !important;
+  }
+}
+</style>

+ 62 - 0
src/components/BuildCode/render.vue

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

+ 2 - 5
src/components/DictTag/index.vue

@@ -24,7 +24,7 @@
 </template>
 
 <script setup lang="ts">
-import { PropType } from 'vue';
+import { propTypes } from '@/utils/propTypes';
 
 
 const props = defineProps({
@@ -36,10 +36,7 @@ const props = defineProps({
   // 当前的值
   value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
   // 当未找到匹配的数据时,显示value
-  showValue: {
-    type: Boolean as PropType<boolean>,
-    default: true,
-  },
+  showValue: propTypes.bool.def(true),
 });
 
 const values = computed(() => {

+ 100 - 102
src/components/Editor/index.vue

@@ -30,152 +30,139 @@
 import { QuillEditor, Quill } from '@vueup/vue-quill';
 import '@vueup/vue-quill/dist/vue-quill.snow.css';
 import { getToken } from "@/utils/auth";
-import { ComponentInternalInstance } from "vue";
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-    /* 编辑器的内容 */
-    modelValue: {
-        type: String,
-    },
-    /* 高度 */
-    height: {
-        type: Number,
-        default: null,
-    },
-    /* 最小高度 */
-    minHeight: {
-        type: Number,
-        default: null,
-    },
-    /* 只读 */
-    readOnly: {
-        type: Boolean,
-        default: false,
-    },
-    /* 上传文件大小限制(MB) */
-    fileSize: {
-        type: Number,
-        default: 5,
-    },
-    /* 类型(base64格式、url格式) */
-    type: {
-        type: String,
-        default: "url",
-    }
+  /* 编辑器的内容 */
+  modelValue: propTypes.string,
+  /* 高度 */
+  height: propTypes.number.def(400),
+  /* 最小高度 */
+  minHeight: propTypes.number.def(400),
+  /* 只读 */
+  readOnly: propTypes.bool.def(false),
+  /* 上传文件大小限制(MB) */
+  fileSize: propTypes.number.def(5),
+  /* 类型(base64格式、url格式) */
+  type: propTypes.string.def('url')
 });
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const upload = reactive<UploadOption>({
-    headers: { Authorization: "Bearer " + getToken() },
-    url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
+  headers: { Authorization: "Bearer " + getToken() },
+  url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
 })
 const myQuillEditor = ref();
 
 const options = ref({
-    theme: "snow",
-    bounds: document.body,
-    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"]                       // 链接、图片、视频
-            ],
-            handlers: {
-                image: function (value: any) {
-                    if (value) {
-                        // 调用element图片上传
-                        (document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
-                    } else {
-                        Quill.format("image", true);
-                    }
-                },
-            },
-        }
-    },
-    placeholder: '请输入内容',
-    readOnly: props.readOnly,
+  theme: "snow",
+  bounds: document.body,
+  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"]                       // 链接、图片、视频
+      ],
+      handlers: {
+        image: function (value: any) {
+          if (value) {
+            // 调用element图片上传
+            (document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click();
+          } else {
+            Quill.format("image", true);
+          }
+        },
+      },
+    }
+  },
+  placeholder: '请输入内容',
+  readOnly: props.readOnly,
 });
 
 const styles = computed(() => {
-    let style: any = {};
-    if (props.minHeight) {
-        style.minHeight = `${props.minHeight}px`;
-    }
-    if (props.height) {
-        style.height = `${props.height}px`;
-    }
-    return style;
+  let style: any = {};
+  if (props.minHeight) {
+    style.minHeight = `${props.minHeight}px`;
+  }
+  if (props.height) {
+    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;
-    }
+  if (v !== content.value) {
+    content.value = v === undefined ? "<p></p>" : v;
+  }
 }, { immediate: true });
 
 // 图片上传成功返回图片地址
 const handleUploadSuccess = (res: any) => {
-    // 获取富文本实例
-    let quill = toRaw(myQuillEditor.value).getQuill();
-    // 如果上传成功
-    if (res.code === 200) {
-        // 获取光标位置
-        let length = quill.selection.savedRange.index;
-        // 插入图片,res为服务器返回的图片链接地址
-        quill.insertEmbed(length, "image", res.data.url);
-        // 调整光标到最后
-        quill.setSelection(length + 1);
-        proxy?.$modal.closeLoading();
-    } else {
-        proxy?.$modal.loading(res.msg);
-        proxy?.$modal.closeLoading();
-    }
+  // 获取富文本实例
+  let quill = toRaw(myQuillEditor.value).getQuill();
+  // 如果上传成功
+  if (res.code === 200) {
+    // 获取光标位置
+    let length = quill.selection.savedRange.index;
+    // 插入图片,res为服务器返回的图片链接地址
+    quill.insertEmbed(length, "image", res.data.url);
+    // 调整光标到最后
+    quill.setSelection(length + 1);
+    proxy?.$modal.closeLoading();
+  } else {
+    proxy?.$modal.loading(res.msg);
+    proxy?.$modal.closeLoading();
+  }
 }
 
 // 图片上传前拦截
 const handleBeforeUpload = (file: any) => {
-    // 校检文件大小
-    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('正在上传文件,请稍候...');
-    return true;
+  }
+  proxy?.$modal.loading('正在上传文件,请稍候...');
+  return true;
 }
 
 // 图片失败拦截
 const handleUploadError = (err: any) => {
-    console.error(err);
-    proxy?.$modal.msgError('上传文件失败');
+  console.error(err);
+  proxy?.$modal.msgError('上传文件失败');
 }
 </script>
 
 <style>
-.editor, .ql-toolbar {
+.editor,
+.ql-toolbar {
   white-space: pre-wrap !important;
   line-height: normal !important;
 }
+
 .quill-img {
   display: none;
 }
+
 .ql-snow .ql-tooltip[data-mode="link"]::before {
   content: "请输入链接地址:";
 }
+
 .ql-snow .ql-tooltip.ql-editing a.ql-action::after {
   border-right: 0;
   content: "保存";
@@ -190,14 +177,17 @@ const handleUploadError = (err: any) => {
 .ql-snow .ql-picker.ql-size .ql-picker-item::before {
   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="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";
@@ -207,26 +197,32 @@ const handleUploadError = (err: any) => {
 .ql-snow .ql-picker.ql-header .ql-picker-item::before {
   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="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="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="6"]::before,
 .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
   content: "标题6";
@@ -236,10 +232,12 @@ const handleUploadError = (err: any) => {
 .ql-snow .ql-picker.ql-font .ql-picker-item::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: "等宽字体";

+ 25 - 35
src/components/FileUpload/index.vue

@@ -45,31 +45,18 @@
 <script setup lang="ts">
 import { getToken } from "@/utils/auth";
 import { listByIds, delOss } from "@/api/system/oss";
-import { ComponentInternalInstance } from "vue";
-import { ElUpload, UploadFile } from "element-plus";
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
     modelValue: [String, Object, Array],
     // 数量限制
-    limit: {
-        type: Number,
-        default: 5,
-    },
+    limit: propTypes.number.def(5),
     // 大小限制(MB)
-    fileSize: {
-        type: Number,
-        default: 5,
-    },
+    fileSize: propTypes.number.def(5),
     // 文件类型, 例如['png', 'jpg', 'jpeg']
-    fileType: {
-        type: Array,
-        default: () => ["doc", "xls", "ppt", "txt", "pdf"],
-    },
+    fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
     // 是否显示提示
-    isShowTip: {
-        type: Boolean,
-        default: true
-    }
+    isShowTip: propTypes.bool.def(true),
 });
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -86,7 +73,7 @@ const showTip = computed(
     () => props.isShowTip && (props.fileType || props.fileSize)
 );
 
-const fileUploadRef = ref(ElUpload);
+const fileUploadRef = ref<ElUploadInstance>();
 
 watch(() => props.modelValue, async val => {
     if (val) {
@@ -96,7 +83,7 @@ watch(() => props.modelValue, async val => {
         if (Array.isArray(val)) {
             list = val;
         } else {
-            const res =  await listByIds(val as string)
+            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;
@@ -104,7 +91,7 @@ watch(() => props.modelValue, async val => {
         }
         // 然后将数组转为对象数组
         fileList.value = list.map(item => {
-            item = {name: item.name, url: item.url, ossId: item.ossId};
+            item = { name: item.name, url: item.url, ossId: item.ossId };
             item.uid = item.uid || new Date().getTime() + temp++;
             return item;
         });
@@ -112,7 +99,7 @@ watch(() => props.modelValue, async val => {
         fileList.value = [];
         return [];
     }
-},{ deep: true, immediate: true });
+}, { deep: true, immediate: true });
 
 // 上传前校检格式和大小
 const handleBeforeUpload = (file: any) => {
@@ -150,7 +137,7 @@ const handleUploadError = () => {
 }
 
 // 上传成功回调
-const handleUploadSuccess = (res:any, file: UploadFile) => {
+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();
@@ -158,7 +145,7 @@ const handleUploadSuccess = (res:any, file: UploadFile) => {
         number.value--;
         proxy?.$modal.closeLoading();
         proxy?.$modal.msgError(res.msg);
-        fileUploadRef.value.handleRemove(file);
+        fileUploadRef.value?.handleRemove(file);
         uploadedSuccessfully();
     }
 }
@@ -172,7 +159,7 @@ const handleDelete = (index: number) => {
 }
 
 // 上传结束处理
-const uploadedSuccessfully =() => {
+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 = [];
@@ -207,21 +194,24 @@ const listToString = (list: any[], separator?: string) => {
 
 <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>

+ 5 - 6
src/components/Hamburger/index.vue

@@ -1,6 +1,6 @@
 <template>
   <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">
+    <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"
       />
@@ -9,16 +9,15 @@
 </template>
 
 <script setup lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
 defineProps({
-    isActive: {
-        type: Boolean,
-        default: false
-    }
+  isActive: propTypes.bool.def(false)
 })
 
 const emit = defineEmits(['toggleClick'])
 const toggleClick = () => {
-    emit('toggleClick');
+  emit('toggleClick');
 }
 </script>
 

+ 39 - 39
src/components/HeaderSearch/index.vue

@@ -17,12 +17,12 @@
   </div>
 </template>
 
-<script setup lang="ts">
-import Fuse from 'fuse.js'
-import { getNormalPath } from '@/utils/ruoyi'
-import { isHttp } from '@/utils/validate'
-import usePermissionStore from '@/store/modules/permission'
-import { RouteOption } from 'vue-router'
+<script setup lang="ts" name="HeaderSearch">
+import Fuse from 'fuse.js';
+import { getNormalPath } from '@/utils/ruoyi';
+import { isHttp } from '@/utils/validate';
+import usePermissionStore from '@/store/modules/permission';
+import { RouteOption } from 'vue-router';
 
 type Router = Array<{
     path: string;
@@ -34,7 +34,7 @@ const options = ref<any>([]);
 const searchPool = ref<Router>([]);
 const show = ref(false);
 const fuse = ref();
-const headerSearchSelectRef = ref(ElSelect);
+const headerSearchSelectRef = ref<ElSelectInstance>();
 const router = useRouter();
 const routes = computed(() => usePermissionStore().routes);
 
@@ -123,9 +123,9 @@ onMounted(() => {
     searchPool.value = generateRoutes(routes.value);
 })
 
-watchEffect(() => {
-    searchPool.value = generateRoutes(routes.value)
-})
+// watchEffect(() => {
+//     searchPool.value = generateRoutes(routes.value)
+// })
 
 watch(show, (value) => {
     if (value) {
@@ -142,40 +142,40 @@ watch(searchPool, (list) => {
 
 <style lang="scss" scoped>
 .header-search {
-  font-size: 0 !important;
+    font-size: 0 !important;
 
-  .search-icon {
-    cursor: pointer;
-    font-size: 18px;
-    vertical-align: middle;
-  }
+    .search-icon {
+        cursor: pointer;
+        font-size: 18px;
+        vertical-align: middle;
+    }
 
-  .header-search-select {
-    font-size: 18px;
-    transition: width 0.2s;
-    width: 0;
-    overflow: hidden;
-    background: transparent;
-    border-radius: 0;
-    display: inline-block;
-    vertical-align: middle;
+    .header-search-select {
+        font-size: 18px;
+        transition: width 0.2s;
+        width: 0;
+        overflow: hidden;
+        background: transparent;
+        border-radius: 0;
+        display: inline-block;
+        vertical-align: middle;
 
-    :deep(.el-input__inner) {
-      border-radius: 0;
-      border: 0;
-      padding-left: 0;
-      padding-right: 0;
-      box-shadow: none !important;
-      border-bottom: 1px solid #d9d9d9;
-      vertical-align: middle;
+        :deep(.el-input__inner) {
+            border-radius: 0;
+            border: 0;
+            padding-left: 0;
+            padding-right: 0;
+            box-shadow: none !important;
+            border-bottom: 1px solid #d9d9d9;
+            vertical-align: middle;
+        }
     }
-  }
 
-  &.show {
-    .header-search-select {
-      width: 210px;
-      margin-left: 10px;
+    &.show {
+        .header-search-select {
+            width: 210px;
+            margin-left: 10px;
+        }
     }
-  }
 }
 </style>

+ 3 - 9
src/components/IconSelect/index.vue

@@ -31,17 +31,11 @@
 
 <script setup lang="ts">
 import icons from '@/components/IconSelect/requireIcons';
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-  modelValue: {
-    type: String,
-    require: true
-  },
-  width: {
-    type: String,
-    require: false,
-    default: '400px'
-  }
+  modelValue: propTypes.string.isRequired,
+  width: propTypes.string.def('400px')
 });
 
 const emit = defineEmits(['update:modelValue']);

+ 30 - 28
src/components/ImagePreview/index.vue

@@ -9,47 +9,46 @@
 </template>
 
 <script setup lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
 const props = defineProps({
-    src: {
-        type: String,
-        default: ""
-    },
-    width: {
-        type: [Number, String],
-        default: ""
-    },
-    height: {
-        type: [Number, String],
-        default: ""
-    }
+  src: propTypes.string.def(''),
+  width: {
+    type: [Number, String],
+    default: ""
+  },
+  height: {
+    type: [Number, String],
+    default: ""
+  }
 });
 
 const realSrc = computed(() => {
-    if (!props.src) {
-        return;
-    }
-    let real_src = props.src.split(",")[0];
-    return real_src;
+  if (!props.src) {
+    return;
+  }
+  let real_src = props.src.split(",")[0];
+  return real_src;
 });
 
 const realSrcList = computed(() => {
-    if (!props.src) {
-        return;
-    }
-    let real_src_list = props.src.split(",");
-    let srcList:string[] = [];
-    real_src_list.forEach(item => {
-        return srcList.push(item);
-    });
-    return srcList;
+  if (!props.src) {
+    return;
+  }
+  let real_src_list = props.src.split(",");
+  let srcList: string[] = [];
+  real_src_list.forEach(item => {
+    return srcList.push(item);
+  });
+  return srcList;
 });
 
 const realWidth = computed(() =>
-    typeof props.width == "string" ? props.width : `${props.width}px`
+  typeof props.width == "string" ? props.width : `${props.width}px`
 );
 
 const realHeight = computed(() =>
-    typeof props.height == "string" ? props.height : `${props.height}px`
+  typeof props.height == "string" ? props.height : `${props.height}px`
 );
 </script>
 
@@ -58,13 +57,16 @@ const realHeight = computed(() =>
   border-radius: 5px;
   background-color: #ebeef5;
   box-shadow: 0 0 5px 1px #ccc;
+
   :deep(.el-image__inner) {
     transition: all 0.3s;
     cursor: pointer;
+
     &:hover {
       transform: scale(1.2);
     }
   }
+
   :deep(.image-slot) {
     display: flex;
     justify-content: center;

+ 13 - 20
src/components/ImageUpload/index.vue

@@ -17,7 +17,9 @@
       :on-preview="handlePictureCardPreview"
       :class="{ hide: fileList.length >= limit }"
     >
-      <el-icon class="avatar-uploader-icon"><plus /></el-icon>
+      <el-icon class="avatar-uploader-icon">
+        <plus />
+      </el-icon>
     </el-upload>
     <!-- 上传提示 -->
     <div class="el-upload__tip" v-if="showTip">
@@ -42,25 +44,16 @@ import { getToken } from "@/utils/auth";
 import { listByIds, delOss } from "@/api/system/oss";
 import { ComponentInternalInstance, PropType } from "vue";
 import { OssVO } from "@/api/system/oss/types";
-import { ElUpload, UploadFile } from "element-plus";
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
     modelValue: [String, Object, Array],
     // 图片数量限制
-    limit: {
-        type: Number,
-        default: 5,
-    },
+    limit: propTypes.number.def(5),
     // 大小限制(MB)
-    fileSize: {
-        type: Number,
-        default: 5,
-    },
+    fileSize: propTypes.number.def(5),
     // 文件类型, 例如['png', 'jpg', 'jpeg']
-    fileType: {
-        type: Array as PropType<string[]>,
-        default: () => ["png", "jpg", "jpeg"],
-    },
+    fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
     // 是否显示提示
     isShowTip: {
         type: Boolean,
@@ -84,12 +77,12 @@ const showTip = computed(
     () => props.isShowTip && (props.fileType || props.fileSize)
 );
 
-const imageUploadRef = ref(ElUpload);
+const imageUploadRef = ref<ElUploadInstance>();
 
 watch(() => props.modelValue, async val => {
     if (val) {
         // 首先将值转为数组
-        let list:OssVO[] = [];
+        let list: OssVO[] = [];
         if (Array.isArray(val)) {
             list = val as OssVO[];
         } else {
@@ -112,7 +105,7 @@ watch(() => props.modelValue, async val => {
         fileList.value = [];
         return [];
     }
-},{ deep: true, immediate: true });
+}, { deep: true, immediate: true });
 
 /** 上传前loading加载 */
 const handleBeforeUpload = (file: any) => {
@@ -122,7 +115,7 @@ const handleBeforeUpload = (file: any) => {
         if (file.name.lastIndexOf(".") > -1) {
             fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
         }
-        isImg = props.fileType.some((type) => {
+        isImg = props.fileType.some((type: any) => {
             if (file.type.indexOf(type) > -1) return true;
             if (fileExtension && fileExtension.indexOf(type) > -1) return true;
             return false;
@@ -161,7 +154,7 @@ const handleUploadSuccess = (res: any, file: UploadFile) => {
         number.value--;
         proxy?.$modal.closeLoading();
         proxy?.$modal.msgError(res.msg);
-        imageUploadRef.value.handleRemove(file);
+        imageUploadRef.value?.handleRemove(file);
         uploadedSuccessfully();
     }
 }
@@ -207,7 +200,7 @@ 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) {
+        if (undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) {
             strs += list[i].ossId + separator;
         }
     }

+ 12 - 42
src/components/Pagination/index.vue

@@ -22,52 +22,23 @@ export default {
 
 <script setup lang="ts">
 import { scrollTo } from '@/utils/scroll-to'
-import { PropType } from "vue";
+import { propTypes } from "@/utils/propTypes";
 
 const props = defineProps({
-    total: {
-        required: true,
-        type: Number
-    },
-    page: {
-        type: Number,
-        default: 1
-    },
-    limit: {
-        type: Number,
-        default: 20
-    },
+    total: propTypes.number,
+    page: propTypes.number.def(1),
+    limit: propTypes.number.def(20),
     pageSizes: {
-        type: Array as PropType<number[]>,
-        default() {
-            return [10, 20, 30, 50]
-        }
+      type: Array as PropType<number[]>,
+      default: () => [10, 20, 30, 50]
     },
     // 移动端页码按钮的数量端默认值5
-    pagerCount: {
-        type: Number,
-        default: document.body.clientWidth < 992 ? 5 : 7
-    },
-    layout: {
-        type: String,
-        default: 'total, sizes, prev, pager, next, jumper'
-    },
-    background: {
-        type: Boolean,
-        default: true
-    },
-    autoScroll: {
-        type: Boolean,
-        default: true
-    },
-    hidden: {
-        type: Boolean,
-        default: false
-    },
-    float: {
-        type: String,
-        default: 'right'
-    }
+    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']);
@@ -106,7 +77,6 @@ function handleCurrentChange(val: number) {
 
 <style lang="scss" scoped>
 .pagination-container {
-  background: #fff;
   padding: 32px 16px;
   .el-pagination{
     float: v-bind(float);

+ 4 - 14
src/components/RightToolbar/index.vue

@@ -18,25 +18,15 @@
 </template>
 
 <script setup lang="ts">
-import { TransferKey } from "element-plus";
-import { PropType } from "vue";
+import { propTypes } from '@/utils/propTypes';
 
 const props = defineProps({
-    showSearch: {
-        type: Boolean,
-        default: true,
-    },
+    showSearch: propTypes.bool.def(true),
     columns: {
         type: Array as PropType<FieldOption[]>,
     },
-    search: {
-        type: Boolean,
-        default: true,
-    },
-    gutter: {
-        type: Number,
-        default: 10,
-    },
+    search: propTypes.bool.def(true),
+    gutter: propTypes.number.def(10),
 })
 
 const emits = defineEmits(['update:showSearch', 'queryTable']);

+ 5 - 12
src/components/SvgIcon/index.vue

@@ -5,19 +5,12 @@
 </template>
 
 <script setup lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
 const props = defineProps({
-    iconClass: {
-        type: String,
-        required: true
-    },
-    className: {
-        type: String,
-        default: ''
-    },
-    color: {
-        type: String,
-        default: ''
-    },
+    iconClass: propTypes.string.isRequired,
+    className: propTypes.string.def(''),
+    color: propTypes.string.def(''),
 })
 const iconName =  computed(() => `#icon-${props.iconClass}`);
 const svgClass = computed(() => {

+ 38 - 38
src/components/TreeSelect/index.vue

@@ -29,94 +29,93 @@
 </template>
 
 <script setup lang="ts">
-import { ElTreeSelect } from 'element-plus'
 
 const props = defineProps({
   /* 配置项 */
   objMap: {
-  type: Object,
-  default: () => {
-    return {
-    value: 'id', // ID字段名
-    label: 'label', // 显示名称
-    children: 'children' // 子级字段名
+    type: Object,
+    default: () => {
+      return {
+        value: 'id', // ID字段名
+        label: 'label', // 显示名称
+        children: 'children' // 子级字段名
+      }
     }
-  }
   },
   /* 自动收起 */
   accordion: {
-  type: Boolean,
-  default: () => {
-    return false
-  }
+    type: Boolean,
+    default: () => {
+      return false
+    }
   },
   /**当前双向数据绑定的值 */
   value: {
-  type: [String, Number],
-  default: ''
+    type: [String, Number],
+    default: ''
   },
   /**当前的数据 */
   options: {
-  type: Array,
-  default: () => []
+    type: Array,
+    default: () => []
   },
   /**输入框内部的文字 */
   placeholder: {
-  type: String,
-  default: ''
+    type: String,
+    default: ''
   }
 })
 
 
-const selectTree = ref(ElTreeSelect);
+const selectTree = ref<ElTreeSelectInstance>();
 
 const emit = defineEmits(['update:value']);
 
 const valueId = computed({
   get: () => props.value,
   set: (val) => {
-  emit('update:value', val)
+    emit('update:value', val)
   }
 });
 const valueTitle = ref('');
 const defaultExpandedKey = ref<any[]>([]);
 
-function initHandle() {
+const initHandle = () => {
   nextTick(() => {
-  const selectedValue = valueId.value;
-  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] // 设置默认展开
+    const selectedValue = valueId.value;
+    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] // 设置默认展开
+      }
+    } else {
+      clearHandle()
     }
-  } else {
-    clearHandle()
-  }
   })
 }
-function handleNodeClick(node: any) {
+const handleNodeClick = (node: any) => {
   valueTitle.value = node[props.objMap.label]
   valueId.value = node[props.objMap.value];
   defaultExpandedKey.value = [];
-  selectTree.value.blur()
+  selectTree.value?.blur()
   selectFilterData('')
 }
-function selectFilterData(val: any) {
-  selectTree.value.filter(val)
+const selectFilterData = (val: any) => {
+  selectTree.value?.filter(val)
 }
-function filterNode(value: any, data: any) {
+const filterNode = (value: any, data: any) => {
   if (!value) return true
   return data[props.objMap['label']].indexOf(value) !== -1
 }
-function clearHandle() {
+const clearHandle = () => {
   valueTitle.value = ''
   valueId.value = ''
   defaultExpandedKey.value = [];
   clearSelected()
 }
-function clearSelected() {
+const clearSelected = () => {
   const allNode = document.querySelectorAll('#tree-option .el-tree-node')
   allNode.forEach((element) => element.classList.remove('is-current'))
 }
@@ -132,6 +131,7 @@ watch(valueId, () => {
 
 <style lang="scss" scoped>
 @import "@/assets/styles/variables.module.scss";
+
 .el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
   padding: 0;
   background-color: #fff;

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

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

+ 1 - 1
src/layout/components/IframeToggle/index.vue

@@ -16,4 +16,4 @@ import useTagsViewStore from '@/store/modules/tagsView';
 
 const route = useRoute();
 const tagsViewStore = useTagsViewStore()
-</script>
+</script>

+ 41 - 29
src/layout/components/Navbar.vue

@@ -20,8 +20,13 @@
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
         </el-select>
 
-        <header-search id="header-search" class="right-menu-item" />
-
+        <!-- <header-search id="header-search" class="right-menu-item" /> -->
+        <search-menu ref="searchMenuRef" />
+        <el-tooltip content="搜索" effect="dark" placement="bottom">
+          <div class="right-menu-item hover-effect" @click="openSearchMenu">
+            <svg-icon class-name="search-icon" icon-class="search" />
+          </div>
+        </el-tooltip>
         <el-tooltip content="Github" effect="dark" placement="bottom">
           <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
         </el-tooltip>
@@ -68,17 +73,18 @@
 </template>
 
 <script setup lang="ts">
-import useAppStore from '@/store/modules/app'
-import useUserStore from '@/store/modules/user'
-import useSettingsStore from '@/store/modules/settings'
+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";
 
-const appStore = useAppStore()
-const userStore = useUserStore()
-const settingsStore = useSettingsStore()
+const appStore = useAppStore();
+const userStore = useUserStore();
+const settingsStore = useSettingsStore();
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -89,46 +95,52 @@ const tenantList = ref<TenantVO[]>([]);
 const dynamic = ref(false);
 // 租户开关
 const tenantEnabled = ref(true);
+// 搜索菜单
+const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
+
+const openSearchMenu = () => {
+  searchMenuRef.value?.openSearch();
+}
 
 // 动态切换
 const dynamicTenantEvent = async (tenantId: string) => {
-    if (companyName.value != null && companyName.value !== '') {
-        await dynamicTenant(tenantId);
-        dynamic.value = true;
-        proxy?.$tab.closeAllPage();
-        proxy?.$router.push('/');
-    }
+  if (companyName.value != null && companyName.value !== '') {
+    await dynamicTenant(tenantId);
+    dynamic.value = true;
+    proxy?.$tab.closeAllPage();
+    proxy?.$router.push('/');
+  }
 }
 
 const dynamicClearEvent = async () => {
-    await dynamicClear();
-    dynamic.value = false;
-    proxy?.$tab.closeAllPage();
-    proxy?.$router.push('/')
+  await dynamicClear();
+  dynamic.value = false;
+  proxy?.$tab.closeAllPage();
+  proxy?.$router.push('/');
 }
 
 /** 租户列表 */
 const initTenantList = async () => {
-    const { data } = await getTenantList();
-    tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
-    if (tenantEnabled.value) {
-        tenantList.value = data.voList;
-    }
+  const { data } = await getTenantList();
+  tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
+  if (tenantEnabled.value) {
+    tenantList.value = data.voList;
+  }
 }
 
 defineExpose({
-    initTenantList,
+  initTenantList,
 })
 
 const toggleSideBar = () => {
-    appStore.toggleSideBar(false)
+  appStore.toggleSideBar(false);
 }
 
 const logout = async () => {
     await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
     })
     await userStore.logout()
     location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
@@ -169,7 +181,7 @@ const handleCommand = (command: string) => {
   height: 50px;
   overflow: hidden;
   position: relative;
-  background: #fff;
+  //background: #fff;
   box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
 
   .hamburger-container {

+ 18 - 5
src/layout/components/Settings/index.vue

@@ -1,8 +1,7 @@
 <template>
   <el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
-    <div class="setting-drawer-title">
-      <h3 class="drawer-title">主题风格设置</h3>
-    </div>
+    <h3 class="drawer-title">主题风格设置</h3>
+
     <div class="setting-drawer-block-checbox">
       <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
         <img src="@/assets/images/dark.svg" alt="dark" />
@@ -35,6 +34,13 @@
         <el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange" />
       </span>
     </div>
+    <div class="drawer-item">
+      <span>深色模式</span>
+      <span class="comp-style">
+        <el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" />
+      </span>
+    </div>
+
     <el-divider />
 
     <h3 class="drawer-title">系统布局配置</h3>
@@ -102,7 +108,15 @@ const sideTheme = ref(settingsStore.sideTheme);
 const storeSettings = computed(() => settingsStore);
 const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
 
-/** 是否需要topnav */
+// 是否暗黑模式
+const isDark = useDark({
+  storageKey: 'useDarkKey',
+  valueDark: 'dark',
+  valueLight: 'light',
+});
+const toggleDark = () => useToggle(isDark);
+
+/** 是否需要topNav */
 const topNav = computed({
     get: () => storeSettings.value.topNav,
     set: (val) => {
@@ -234,7 +248,6 @@ defineExpose({
 }
 
 .drawer-item {
-  color: rgba(0, 0, 0, 0.65);
   padding: 12px 0;
   font-size: 14px;
 

+ 6 - 7
src/layout/components/TagsView/ScrollPane.vue

@@ -6,22 +6,21 @@
 
 <script setup lang="ts">
 import useTagsViewStore from '@/store/modules/tagsView'
-import { ElScrollbar } from 'element-plus';
 import { TagView } from 'vue-router'
 const tagAndTagSpacing = ref(4);
 
-const scrollContainerRef = ref(ElScrollbar)
-const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
+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 eventDelta = (e as any).wheelDelta || - e.deltaY * 40
     const $scrollWrapper = scrollWrapper.value;
     $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
 }
@@ -34,7 +33,7 @@ const tagsViewStore = useTagsViewStore()
 const visitedViews = computed(() => tagsViewStore.visitedViews);
 
 const moveToTarget = (currentTag: TagView) => {
-    const $container = scrollContainerRef.value.$el
+    const $container = scrollContainerRef.value?.$el
     const $containerWidth = $container.offsetWidth
     const $scrollWrapper = scrollWrapper.value;
 

+ 11 - 6
src/layout/components/TagsView/index.vue

@@ -125,6 +125,9 @@ const initTags = () => {
 }
 const addTags = () => {
     const { name } = route;
+    if(route.query.title) {
+        route.meta.title = route.query.title;
+    }
     if (name) {
         useTagsViewStore().addView(route);
         if (route.meta.link) {
@@ -237,8 +240,8 @@ onMounted(() => {
 .tags-view-container {
   height: 34px;
   width: 100%;
-  background: #fff;
-  border-bottom: 1px solid #d8dce5;
+  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);
   .tags-view-wrapper {
     .tags-view-item {
@@ -247,13 +250,16 @@ onMounted(() => {
       cursor: pointer;
       height: 26px;
       line-height: 23px;
-      border: 1px solid #d8dce5;
+      background-color: var(--el-bg-color);
+      border: 1px solid var(--el-border-color-light);
       color: #495060;
-      background: #fff;
       padding: 0 8px;
       font-size: 12px;
       margin-left: 5px;
       margin-top: 4px;
+      &:hover {
+        color: var(--el-color-primary);
+      }
       &:first-of-type {
         margin-left: 15px;
       }
@@ -279,7 +285,7 @@ onMounted(() => {
   }
   .contextmenu {
     margin: 0;
-    background: #fff;
+    background: var(--el-bg-color);
     z-index: 3000;
     position: absolute;
     list-style-type: none;
@@ -287,7 +293,6 @@ onMounted(() => {
     border-radius: 4px;
     font-size: 12px;
     font-weight: 400;
-    color: #333;
     box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
     li {
       margin: 0;

+ 158 - 0
src/layout/components/topBar/search.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="layout-search-dialog">
+    <el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
+      <template #footer>
+        <el-autocomplete
+          v-model="state.menuQuery"
+          :fetch-suggestions="menuSearch"
+          placeholder="搜索"
+          ref="layoutMenuAutocompleteRef"
+          @select="onHandleSelect"
+          :fit-input-width="true"
+        >
+          <template #prefix>
+            <svg-icon class-name="search-icon" icon-class="search" />
+          </template>
+          <template #default="{ item }">
+            <div>
+              <svg-icon :icon-class="item.icon" class="mr5" />
+              {{ item.title }}
+            </div>
+          </template>
+        </el-autocomplete>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts" name="layoutBreadcrumbSearch">
+import { getNormalPath } from '@/utils/ruoyi';
+import { isHttp } from '@/utils/validate';
+import usePermissionStore from '@/store/modules/permission';
+import { RouteOption } from 'vue-router';
+type Router = Array<{
+	path: string;
+	icon: string;
+	title: string[];
+}>
+type SearchState<T = any> = {
+	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: [],
+});
+
+// 搜索弹窗打开
+const openSearch = () => {
+	state.menuQuery = '';
+	state.isShowSearch = true;
+	state.menuList = generateRoutes(routes.value);
+	nextTick(() => {
+		setTimeout(() => {
+			layoutMenuAutocompleteRef.value.focus();
+		});
+	});
+};
+// 搜索弹窗关闭
+const closeSearch = () => {
+	state.isShowSearch = false;
+};
+// 菜单搜索数据过滤
+const menuSearch = (queryString: string, cb: Function) => {
+	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 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();
+
+};
+
+// 暴露变量
+defineExpose({
+	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%);
+	}
+}
+</style>

+ 15 - 15
src/plugins/modal.ts

@@ -1,57 +1,57 @@
-import { ElMessage, ElMessageBox, ElNotification, ElLoading, MessageBoxData } from 'element-plus';
+import { MessageBoxData } from 'element-plus';
 import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
 let loadingInstance: LoadingInstance;
 export default {
   // 消息提示
-  msg(content: string) {
+  msg(content: any) {
     ElMessage.info(content);
   },
   // 错误消息
-  msgError(content: string) {
+  msgError(content: any) {
     ElMessage.error(content);
   },
   // 成功消息
-  msgSuccess(content: string) {
+  msgSuccess(content: any) {
     ElMessage.success(content);
   },
   // 警告消息
-  msgWarning(content: string) {
+  msgWarning(content: any) {
     ElMessage.warning(content);
   },
   // 弹出提示
-  alert(content: string) {
+  alert(content: any) {
     ElMessageBox.alert(content, '系统提示');
   },
   // 错误提示
-  alertError(content: string) {
+  alertError(content: any) {
     ElMessageBox.alert(content, '系统提示', { type: 'error' });
   },
   // 成功提示
-  alertSuccess(content: string, s: string, p: { dangerouslyUseHTMLString: boolean }) {
+  alertSuccess(content: any) {
     ElMessageBox.alert(content, '系统提示', { type: 'success' });
   },
   // 警告提示
-  alertWarning(content: string) {
+  alertWarning(content: any) {
     ElMessageBox.alert(content, '系统提示', { type: 'warning' });
   },
   // 通知提示
-  notify(content: string) {
+  notify(content: any) {
     ElNotification.info(content);
   },
   // 错误通知
-  notifyError(content: string) {
+  notifyError(content: any) {
     ElNotification.error(content);
   },
   // 成功通知
-  notifySuccess(content: string) {
+  notifySuccess(content: any) {
     ElNotification.success(content);
   },
   // 警告通知
-  notifyWarning(content: string) {
+  notifyWarning(content: any) {
     ElNotification.warning(content);
   },
   // 确认窗体
-  confirm(content: string): Promise<MessageBoxData> {
+  confirm(content: any): Promise<MessageBoxData> {
     return ElMessageBox.confirm(content, '系统提示', {
       confirmButtonText: '确定',
       cancelButtonText: '取消',
@@ -59,7 +59,7 @@ export default {
     });
   },
   // 提交内容
-  prompt(content: string) {
+  prompt(content: any) {
     return ElMessageBox.prompt(content, '系统提示', {
       confirmButtonText: '确定',
       cancelButtonText: '取消',

+ 33 - 16
src/plugins/tab.ts

@@ -3,8 +3,11 @@ import router from '@/router';
 import { TagView, RouteLocationRaw } from 'vue-router';
 
 export default {
-  // 刷新当前tab页签
-  async refreshPage(obj: TagView): Promise<void> {
+  /**
+   * 刷新当前tab页签
+   * @param obj 标签对象
+   */
+  async refreshPage(obj?: TagView): Promise<void> {
     const { path, query, matched } = router.currentRoute.value;
     if (obj === undefined) {
       matched.forEach((m) => {
@@ -15,11 +18,16 @@ export default {
         }
       });
     }
-    // prettier-ignore
-    await useTagsViewStore().delCachedView(obj)
-    router.replace({
-      path: '/redirect' + obj.path,
-      query: obj.query
+    let query1: undefined | {} = {};
+    let path1: undefined | string = '';
+    if (obj) {
+      query1 = obj.query;
+      path1 = obj.path;
+    }
+    await useTagsViewStore().delCachedView(obj);
+    await router.replace({
+      path: '/redirect' + path1,
+      query: query1
     });
   },
   // 关闭当前tab页签,打开新页签
@@ -34,9 +42,9 @@ export default {
     if (obj === undefined) {
       // prettier-ignore
       const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any
-      const latestView = visitedViews.slice(-1)[0]
+      const latestView = visitedViews.slice(-1)[0];
       if (latestView) {
-        return router.push(latestView.fullPath)
+        return router.push(latestView.fullPath);
       }
       return router.push('/');
     }
@@ -47,22 +55,31 @@ export default {
     return useTagsViewStore().delAllViews();
   },
   // 关闭左侧tab页签
-  closeLeftPage(obj: TagView) {
+  closeLeftPage(obj?: TagView) {
     return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
   },
   // 关闭右侧tab页签
-  closeRightPage(obj: TagView) {
+  closeRightPage(obj?: TagView) {
     return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
   },
   // 关闭其他tab页签
-  closeOtherPage(obj: TagView) {
+  closeOtherPage(obj?: TagView) {
     return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
   },
-  // 打开tab页签
-  openPage(url: RouteLocationRaw) {
-    return router.push(url);
+  /**
+   * 打开tab页签
+   * @param url 路由地址
+   * @param title 标题
+   * @param query 参数
+   */
+  openPage(url: string, title?: string, query?: any) {
+    const obj = { path: url, query: { ...query, title } };
+    return router.push(obj);
   },
-  // 修改tab页签
+  /**
+   * 修改tab页签
+   * @param obj 标签对象
+   */
   updatePage(obj: TagView) {
     return useTagsViewStore().updateVisitedView(obj);
   }

+ 6 - 2
src/store/modules/tagsView.ts

@@ -54,8 +54,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
       resolve([...visitedViews.value]);
     });
   };
-  const delCachedView = (view: TagView): Promise<string[]> => {
-    const viewName = view.name as string;
+  const delCachedView = (view?: TagView): Promise<string[]> => {
+    let viewName = '';
+    if (view) {
+      viewName = view.name as string;
+    }
     return new Promise((resolve) => {
       const index = cachedViews.value.indexOf(viewName);
       index > -1 && cachedViews.value.splice(index, 1);
@@ -167,6 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
 
   const addCachedView = (view: TagView): void => {
     const viewName = view.name as string;
+    if (!viewName) return;
     if (cachedViews.value.includes(viewName)) return;
     if (!view.meta?.noCache) {
       cachedViews.value.push(viewName);

+ 35 - 1
src/types/element.d.ts

@@ -1 +1,35 @@
-declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
+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 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>;
+  declare type ElInputNumberInstance = InstanceType<typeof ep.ElInputNumber>;
+  declare type ElRadioInstance = InstanceType<typeof ep.ElRadio>;
+  declare type ElRadioGroupInstance = InstanceType<typeof ep.ElRadioGroup>;
+  declare type ElRadioButtonInstance = InstanceType<typeof ep.ElRadioButton>;
+  declare type ElCheckboxInstance = InstanceType<typeof ep.ElCheckbox>;
+  declare type ElCheckboxGroupInstance = InstanceType<typeof ep.ElCheckboxGroup>;
+  declare type ElSwitchInstance = InstanceType<typeof ep.ElSwitch>;
+  declare type ElDatePickerInstance = InstanceType<typeof ep.ElDatePicker>;
+  declare type ElTimePickerInstance = InstanceType<typeof ep.ElTimePicker>;
+  declare type ElTimeSelectInstance = InstanceType<typeof ep.ElTimeSelect>;
+  declare type ElCascaderInstance = InstanceType<typeof ep.ElCascader>;
+  declare type ElColorPickerInstance = InstanceType<typeof ep.ElColorPicker>;
+  declare type ElRateInstance = InstanceType<typeof ep.ElRate>;
+  declare type ElSliderInstance = InstanceType<typeof ep.ElSlider>;
+  declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
+  declare type ElScrollbarInstance = InstanceType<typeof ep.ElScrollbar>;
+
+  declare type TransferKey = ep.TransferKey;
+  declare type CheckboxValueType = ep.CheckboxValueType;
+  declare type ElFormRules = ep.FormRules;
+  declare type DateModelType = ep.DateModelType;
+  declare type UploadFile = typeof ep.UploadFile;
+}

+ 16 - 10
src/types/global.d.ts

@@ -1,9 +1,15 @@
-import { FormRules } from 'element-plus';
+import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue';
+
 declare global {
+  /** vue Instance */
+  declare type ComponentInternalInstance = ComponentInstance;
+  /**vue */
+  declare type PropType<T> = VuePropType<T>;
+
   /**
    * 界面字段隐藏属性
    */
-  interface FieldOption {
+  declare interface FieldOption {
     key: number;
     label: string;
     visible: boolean;
@@ -12,7 +18,7 @@ declare global {
   /**
    * 弹窗属性
    */
-  interface DialogOption {
+  declare interface DialogOption {
     /**
      * 弹窗标题
      */
@@ -23,7 +29,7 @@ declare global {
     visible: boolean;
   }
 
-  interface UploadOption {
+  declare interface UploadOption {
     /** 设置上传的请求头部 */
     headers: { [key: string]: any };
 
@@ -34,7 +40,7 @@ declare global {
   /**
    * 导入属性
    */
-  interface ImportOption extends UploadOption {
+  declare interface ImportOption extends UploadOption {
     /** 是否显示弹出层 */
     open: boolean;
     /** 弹出层标题 */
@@ -48,14 +54,14 @@ declare global {
   /**
    * 字典数据  数据配置
    */
-  interface DictDataOption {
+  declare interface DictDataOption {
     label: string;
     value: string;
     elTagType?: ElTagType;
     elTagClass?: string;
   }
 
-  interface BaseEntity {
+  declare interface BaseEntity {
     createBy?: any;
     createDept?: any;
     createTime?: string;
@@ -68,15 +74,15 @@ declare global {
    * T : 表单数据
    * D : 查询参数
    */
-  interface PageData<T, D> {
+  declare interface PageData<T, D> {
     form: T;
     queryParams: D;
-    rules: FormRules;
+    rules: ElFormRules;
   }
   /**
    * 分页查询参数
    */
-  interface PageQuery {
+  declare interface PageQuery {
     pageNum: number;
     pageSize: number;
   }

+ 15 - 11
src/types/module.d.ts

@@ -1,23 +1,27 @@
-import modal from '@/plugins/modal';
-import tab from '@/plugins/tab';
-import { useDict } from '@/utils/dict';
-import { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
-import { getConfigKey, updateConfigByKey } from '@/api/system/config';
-import { download as download1 } from '@/utils/request';
-import download from '@/plugins/download';
-import animate from '@/animate';
+import type modal from '@/plugins/modal';
+import type tab from '@/plugins/tab';
+import type download from '@/plugins/download';
+import type auth from '@/plugins/auth';
+import type cache from '@/plugins/cache';
+import type animate from '@/animate';
+import type { useDict } from '@/utils/dict';
+import type { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
+import type { getConfigKey, updateConfigByKey } from '@/api/system/config';
+import type { download as rd } from '@/utils/request';
 
-declare module 'vue' {
-  export interface ComponentCustomProperties {
+declare module '@vue/runtime-core' {
+  interface ComponentCustomProperties {
     // 全局方法声明
     $modal: typeof modal;
     $tab: typeof tab;
     $download: typeof download;
+    $auth: typeof auth;
+    $cache: typeof cache;
     animate: typeof animate;
 
     useDict: typeof useDict;
     addDateRange: typeof addDateRange;
-    download: typeof download1;
+    download: typeof rd;
     handleTree: typeof handleTree;
     getConfigKey: typeof getConfigKey;
     updateConfigByKey: typeof updateConfigByKey;

+ 4 - 4
src/types/router.d.ts

@@ -1,7 +1,7 @@
 import { RouteRecordRaw } from 'vue-router';
 
 declare module 'vue-router' {
-  type RouteOption = {
+  declare type RouteOption = {
     hidden?: boolean;
     permissions?: string[];
     roles?: string[];
@@ -16,15 +16,15 @@ declare module 'vue-router' {
     query?: string;
   } & RouteRecordRaw;
 
-  interface _RouteLocationBase {
+  declare interface _RouteLocationBase {
     children?: RouteOption[];
   }
 
-  interface RouteLocationOptions {
+  declare interface RouteLocationOptions {
     fullPath?: string;
   }
 
-  interface TagView extends Partial<_RouteLocationBase> {
+  declare interface TagView extends Partial<_RouteLocationBase> {
     title?: string;
     meta?: {
       link?: string;

+ 4 - 0
src/types/vform3-builds.d.ts

@@ -0,0 +1,4 @@
+declare module 'vform3-builds' {
+  const content: any;
+  export = content;
+}

+ 25 - 0
src/utils/propTypes.ts

@@ -0,0 +1,25 @@
+import { CSSProperties } from 'vue';
+import { createTypes, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
+
+type PropTypes = VueTypesInterface & {
+  readonly style: VueTypeValidableDef<CSSProperties>;
+};
+
+const propTypes = createTypes({
+  func: undefined,
+  bool: undefined,
+  string: undefined,
+  number: undefined,
+  object: undefined,
+  integer: undefined
+}) as PropTypes;
+
+propTypes.extend([
+  {
+    name: 'style',
+    getter: true,
+    type: [String, Object],
+    default: undefined
+  }
+]);
+export { propTypes };

+ 38 - 42
src/views/demo/demo/index.vue

@@ -1,32 +1,34 @@
 <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="68px">
-          <el-form-item label="部门id" prop="deptId">
-            <el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="用户id" prop="userId">
-            <el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="排序号" prop="orderNum">
-            <el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="key键" prop="testKey">
-            <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="值" prop="value">
-            <el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+            <el-form-item label="部门id" prop="deptId">
+              <el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="用户id" prop="userId">
+              <el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="排序号" prop="orderNum">
+              <el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="key键" prop="testKey">
+              <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="值" prop="value">
+              <el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -36,7 +38,9 @@
             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</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>
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']"
+              >删除</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>
@@ -65,13 +69,7 @@
         </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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改测试单对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@@ -105,8 +103,6 @@
 <script setup name="Demo" lang="ts">
 import { listDemo, getDemo, delDemo, addDemo, updateDemo } from '@/api/demo/demo';
 import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types';
-import { ComponentInternalInstance } from 'vue';
-import { ElForm } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -119,8 +115,8 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
-const queryFormRef = ref(ElForm);
-const demoFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const demoFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -136,7 +132,7 @@ const initFormData: DemoForm = {
   value: undefined,
 }
 const data = reactive<PageData<DemoForm, DemoQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
@@ -187,8 +183,8 @@ const cancel = () => {
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
-  demoFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  demoFormRef.value?.resetFields();
 }
 
 /** 搜索按钮操作 */
@@ -199,7 +195,7 @@ const handleQuery = () => {
 
 /** 重置按钮操作 */
 const resetQuery = () => {
-  queryFormRef.value.resetFields();
+  queryFormRef.value?.resetFields();
   handleQuery();
 }
 
@@ -235,13 +231,13 @@ const handleUpdate = (row?: DemoVO) => {
 
 /** 提交按钮 */
 const submitForm = () => {
-  demoFormRef.value.validate(async (valid: boolean) => {
+  demoFormRef.value?.validate(async (valid: boolean) => {
     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("修改成功");
       dialog.visible = false;

+ 21 - 21
src/views/demo/tree/index.vue

@@ -1,20 +1,22 @@
 <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="68px">
-          <el-form-item label="树节点名" prop="treeName">
-            <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+            <el-form-item label="树节点名" prop="treeName">
+              <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -89,8 +91,6 @@
 <script setup name="Tree" lang="ts">
 import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
 import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
-import { ComponentInternalInstance } from 'vue';
-import { ElForm, ElTable } from 'element-plus';
 
 
 type TreeOption = {
@@ -109,9 +109,9 @@ const showSearch = ref(true);
 const isExpandAll = ref(true);
 const loading = ref(false);
 
-const queryFormRef = ref(ElForm);
-const treeFormRef = ref(ElForm);
-const treeTableRef = ref(ElTable)
+const queryFormRef = ref<ElFormInstance>();
+const treeFormRef = ref<ElFormInstance>();
+const treeTableRef = ref<ElTableInstance>()
 
 const dialog = reactive<DialogOption>({
     visible: false,
@@ -185,7 +185,7 @@ const cancel = () => {
 // 表单重置
 const reset = () => {
   form.value = {...initFormData}
-  treeFormRef.value.resetFields();
+  treeFormRef.value?.resetFields();
 }
 
 /** 搜索按钮操作 */
@@ -195,7 +195,7 @@ const handleQuery = () => {
 
 /** 重置按钮操作 */
 const resetQuery = () => {
-  queryFormRef.value.resetFields();
+  queryFormRef.value?.resetFields();
   handleQuery();
 }
 
@@ -223,7 +223,7 @@ const handleToggleExpandAll = () => {
 /** 展开/折叠操作 */
 const toggleExpandAll = (data: TreeVO[], status: boolean) => {
   data.forEach((item) => {
-    treeTableRef.value.toggleRowExpansion(item, status)
+    treeTableRef.value?.toggleRowExpansion(item, status)
     if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
   })
 }
@@ -247,7 +247,7 @@ const handleUpdate = (row: TreeVO) => {
 
 /** 提交按钮 */
 const submitForm = () => {
-  treeFormRef.value.validate(async (valid: boolean) => {
+  treeFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       buttonLoading.value = true;
       if (form.value.id) {
@@ -257,7 +257,7 @@ const submitForm = () => {
       }
       proxy?.$modal.msgSuccess("操作成功");
       dialog.visible = false;
-      getList();
+      await getList();
     }
   });
 }

+ 0 - 1
src/views/error/401.vue

@@ -21,7 +21,6 @@
 
 <script setup lang="ts">
 import errImage from '@/assets/401_images/401.gif';
-import { ComponentInternalInstance } from "vue";
 
 let { proxy } = getCurrentInstance() as ComponentInternalInstance;
 

+ 6 - 7
src/views/login.vue

@@ -65,14 +65,14 @@ import Cookies from 'js-cookie';
 import { encrypt, decrypt } from '@/utils/jsencrypt';
 import { useUserStore } from '@/store/modules/user';
 import { LoginData, TenantVO } from '@/api/types';
-import { ElForm, FormRules } from 'element-plus';
 import { to } from 'await-to-js';
+import { HttpStatus } from "@/enums/RespEnum";
 
 const userStore = useUserStore();
 const router = useRouter();
 
 const loginForm = ref<LoginData>({
-  tenantId: "000000",
+  tenantId: '000000',
   username: 'admin',
   password: 'admin123',
   rememberMe: false,
@@ -80,7 +80,7 @@ const loginForm = ref<LoginData>({
   uuid: ''
 });
 
-const loginRules: FormRules = {
+const loginRules: ElFormRules = {
   tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
   username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
   password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
@@ -98,12 +98,12 @@ const tenantEnabled = ref(true);
 // 注册开关
 const register = ref(false);
 const redirect = ref(undefined);
-const loginRef = ref(ElForm);
+const loginRef = ref<ElFormInstance>();
 // 租户列表
 const tenantList = ref<TenantVO[]>([]);
 
 const handleLogin = () => {
-  loginRef.value.validate(async (valid: boolean, fields: any) => {
+  loginRef.value?.validate(async (valid: boolean, fields: any) => {
     if (valid) {
       loading.value = true;
       // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
@@ -120,7 +120,6 @@ const handleLogin = () => {
         Cookies.remove('rememberMe');
       }
       // 调用action的登录方法
-      // prittier-ignore
       const [err] = await to(userStore.login(loginForm.value));
       if (!err) {
         await router.push({ path: redirect.value || '/' });
@@ -189,7 +188,7 @@ watch(() => loginForm.value.tenantId, (val: string) => {
  */
 const doSocialLogin = (type: string) => {
   authBinding(type).then((res: any) => {
-    if (res.code === 200) {
+    if (res.code === HttpStatus.SUCCESS) {
       // 获取授权地址跳转
       window.location.href = res.data;
     } else {

+ 3 - 4
src/views/monitor/cache/index.vue

@@ -2,7 +2,7 @@
   <div class="p-2">
     <el-row>
       <el-col :span="24" class="card-box">
-        <el-card>
+        <el-card shadow="hover">
           <template #header>
             <Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
             <span style="vertical-align: middle;">基本信息</span>
@@ -98,7 +98,7 @@
       </el-col>
 
       <el-col :span="12" class="card-box">
-        <el-card>
+        <el-card shadow="hover">
           <template #header>
             <PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
             <span style="vertical-align: middle;">命令统计</span>
@@ -110,7 +110,7 @@
       </el-col>
 
       <el-col :span="12" class="card-box">
-        <el-card>
+        <el-card shadow="hover">
           <template #header>
             <Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
           </template>
@@ -126,7 +126,6 @@
 <script setup name="Cache" lang="ts">
 import { getCache } from '@/api/monitor/cache';
 import * as echarts from 'echarts';
-import { ComponentInternalInstance } from "vue";
 
 const cache = ref<any>({});
 const commandstats = ref();

+ 38 - 38
src/views/monitor/logininfor/index.vue

@@ -1,39 +1,41 @@
 <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="68px">
-          <el-form-item label="登录地址" prop="ipaddr">
-            <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-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="登录状态" clearable style="width: 240px">
-              <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="登录时间" style="width: 308px">
-            <el-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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-form-item>
+            <el-form-item label="用户名称" prop="userName">
+              <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">
+                <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="登录时间" style="width: 308px">
+              <el-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -98,9 +100,7 @@
 
 <script setup name="Logininfor" lang="ts">
 import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
-import { ComponentInternalInstance } from "vue";
 import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
-import { DateModelType } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
@@ -116,8 +116,8 @@ const total = ref(0);
 const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
 const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
 
-const queryFormRef = ref(ElForm);
-const loginInfoTableRef = ref(ElTable);
+const queryFormRef = ref<ElFormInstance>();
+const loginInfoTableRef = ref<ElTableInstance>();
 // 查询参数
 const queryParams = ref<LoginInfoQuery>({
     pageNum: 1,
@@ -145,9 +145,9 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 const resetQuery = () => {
     dateRange.value = ['', ''];
-    queryFormRef.value.resetFields();
+    queryFormRef.value?.resetFields();
     queryParams.value.pageNum = 1;
-    loginInfoTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
+    loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: LoginInfoVO[]) => {
@@ -167,14 +167,14 @@ const handleDelete = async (row?: LoginInfoVO) => {
     const infoIds = row?.infoId || ids.value;
     await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
     await delLoginInfo(infoIds);
-    getList();
+    await getList();
     proxy?.$modal.msgSuccess("删除成功");
 }
 /** 清空按钮操作 */
 const handleClean = async () => {
     await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
     await cleanLoginInfo();
-    getList();
+    await getList();
     proxy?.$modal.msgSuccess("清空成功");
 }
 /** 解锁按钮操作 */

+ 36 - 35
src/views/monitor/online/index.vue

@@ -1,20 +1,22 @@
 <template>
   <div class="p-2">
-    <div class="search">
-      <el-form :model="queryParams" ref="queryFormRef" :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>
-        <el-form-item label="用户名称" prop="userName">
-          <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-        </el-form-item>
-      </el-form>
+    <div class="mb-[10px]">
+      <el-card shadow="hover">
+        <el-form :model="queryParams" ref="queryFormRef" :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>
+          <el-form-item label="用户名称" prop="userName">
+            <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item>
+            <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>
     </div>
-    <div class="panel">
+    <el-card shadow="hover">
       <el-table
         v-loading="loading"
         :data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
@@ -48,13 +50,12 @@
       </el-table>
 
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
-    </div>
+    </el-card>
   </div>
 </template>
 
 <script setup name="Online" lang="ts">
 import { forceLogout, list as initData } from "@/api/monitor/online";
-import { ComponentInternalInstance } from "vue";
 import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -63,42 +64,42 @@ const onlineList = ref<OnlineVO[]>([]);
 const loading = ref(true);
 const total = ref(0);
 
-const queryFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
 
 const queryParams = ref<OnlineQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    ipaddr: '',
-    userName: ''
+  pageNum: 1,
+  pageSize: 10,
+  ipaddr: '',
+  userName: ''
 });
 
 /** 查询登录日志列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await initData(queryParams.value);
-    onlineList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await initData(queryParams.value);
+  onlineList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 强退按钮操作 */
 const handleForceLogout = async (row: OnlineVO) => {
-    await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
-    await forceLogout(row.tokenId);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
+  await forceLogout(row.tokenId);
+  getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 })
 </script>

+ 107 - 107
src/views/monitor/operlog/index.vue

@@ -1,44 +1,46 @@
 <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="68px">
-          <el-form-item label="系统模块" prop="title">
-            <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-form-item>
-          <el-form-item label="类型" prop="businessType">
-            <el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
-              <el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="操作状态" clearable style="width: 240px">
-              <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="操作时间" style="width: 308px">
-            <el-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+            <el-form-item label="系统模块" prop="title">
+              <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-form-item>
+            <el-form-item label="类型" prop="businessType">
+              <el-select v-model="queryParams.businessType" placeholder="操作类型" clearable style="width: 240px">
+                <el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="操作状态" clearable style="width: 240px">
+                <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="操作时间" style="width: 308px">
+              <el-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -132,7 +134,7 @@
             <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
           </el-col>
           <el-col :span="24">
-            <el-form-item label="请求参数:">{{form.operParam}}</el-form-item>
+            <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
           </el-col>
           <el-col :span="24">
             <el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
@@ -165,12 +167,10 @@
 
 <script setup name="Operlog" lang="ts">
 import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
-import { ComponentInternalInstance } from 'vue';
 import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
-import { DateModelType } from 'element-plus';
 
 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);
@@ -181,116 +181,116 @@ const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
 
-const operLogTableRef = ref(ElTable);
-const queryFormRef = ref(ElForm);
+const operLogTableRef = ref<ElTableInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 
 const data = reactive<PageData<OperLogForm, OperLogQuery>>({
-    form: {
-        operId: undefined,
-        tenantId: undefined,
-        title: '',
-        businessType: 0,
-        businessTypes: undefined,
-        method: '',
-        requestMethod: '',
-        operatorType: 0,
-        operName: '',
-        deptName: '',
-        operUrl: '',
-        operIp: '',
-        operLocation: '',
-        operParam: '',
-        jsonResult: '',
-        status: 0,
-        errorMsg: '',
-        operTime: '',
-        costTime: 0
-    },
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        title: '',
-        operName: '',
-        businessType: '',
-        status: '',
-        orderByColumn: defaultSort.value.prop,
-        isAsc: defaultSort.value.order
-    },
-    rules: {}
+  form: {
+    operId: undefined,
+    tenantId: undefined,
+    title: '',
+    businessType: 0,
+    businessTypes: undefined,
+    method: '',
+    requestMethod: '',
+    operatorType: 0,
+    operName: '',
+    deptName: '',
+    operUrl: '',
+    operIp: '',
+    operLocation: '',
+    operParam: '',
+    jsonResult: '',
+    status: 0,
+    errorMsg: '',
+    operTime: '',
+    costTime: 0
+  },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    title: '',
+    operName: '',
+    businessType: '',
+    status: '',
+    orderByColumn: defaultSort.value.prop,
+    isAsc: defaultSort.value.order
+  },
+  rules: {}
 });
 
 const { queryParams, form } = toRefs(data);
 
 /** 查询登录日志 */
 const getList = async () => {
-    loading.value = true;
-    const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
-    operlogList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value));
+  operlogList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 操作日志类型字典翻译 */
 const typeFormat = (row: OperLogForm) => {
-    return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
+  return proxy?.selectDictLabel(sys_oper_type.value, row.businessType);
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  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);
+  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);
-    multiple.value = !selection.length;
+  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();
+  queryParams.value.orderByColumn = column.prop;
+  queryParams.value.isAsc = column.order;
+  getList();
 }
 /** 详细按钮操作 */
 const handleView = (row: OperLogVO) => {
-    dialog.visible = true;
-    form.value = row;
+  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);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const operIds = row?.operId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
+  await delOperlog(operIds);
+  await getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 /** 清空按钮操作 */
 const handleClean = async () => {
-    await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
-    await cleanOperlog();
-    getList();
-    proxy?.$modal.msgSuccess("清空成功");
+  await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
+  await cleanOperlog();
+  await getList();
+  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();
+  getList();
 })
 </script>

+ 62 - 63
src/views/register.vue

@@ -58,19 +58,18 @@
 <script setup lang="ts">
 import { getCodeImg, register, getTenantList } from '@/api/login';
 import { RegisterForm, TenantVO } from '@/api/types';
-import { FormRules } from 'element-plus';
 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"
 });
 
 // 租户开关
@@ -78,30 +77,30 @@ const tenantEnabled = ref(true);
 
 
 const equalToPassword = (rule: any, value: string, callback: any) => {
-    if (registerForm.value.password !== value) {
-        callback(new Error("两次输入的密码不一致"));
-    } else {
-        callback();
-    }
+  if (registerForm.value.password !== value) {
+    callback(new Error("两次输入的密码不一致"));
+  } else {
+    callback();
+  }
 };
 
-const registerRules: FormRules = {
-    tenantId: [
-        { required: true, trigger: "blur", message: "请输入您的租户编号" }
-    ],
-    username: [
-        { 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" }
-    ],
-    confirmPassword: [
-        { required: true, trigger: "blur", message: "请再次输入您的密码" },
-        { required: true, validator: equalToPassword, trigger: "blur" }
-    ],
-    code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+const registerRules: ElFormRules = {
+  tenantId: [
+    { required: true, trigger: "blur", message: "请输入您的租户编号" }
+  ],
+  username: [
+    { 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" }
+  ],
+  confirmPassword: [
+    { required: true, trigger: "blur", message: "请再次输入您的密码" },
+    { required: true, validator: equalToPassword, trigger: "blur" }
+  ],
+  code: [{ required: true, trigger: "change", message: "请输入验证码" }]
 };
 const codeUrl = ref("");
 const loading = ref(false);
@@ -111,50 +110,50 @@ const registerRef = ref(ElForm);
 const tenantList = ref<TenantVO[]>([]);
 
 const handleRegister = () => {
-    registerRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            loading.value = true;
-            const [err] = await to(register(registerForm.value));
-            if (!err) {
-                const username = registerForm.value.username;
-                await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
-                    dangerouslyUseHTMLString: true,
-                    type: "success",
-                });
-                await router.push("/login");
-            } else {
-                loading.value = false;
-                if (captchaEnabled) {
-                    getCode();
-                }
-            }
+  registerRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      loading.value = true;
+      const [err] = await to(register(registerForm.value));
+      if (!err) {
+        const username = registerForm.value.username;
+        await ElMessageBox.alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
+          dangerouslyUseHTMLString: true,
+          type: "success",
+        });
+        await router.push("/login");
+      } else {
+        loading.value = false;
+        if (captchaEnabled) {
+          getCode();
         }
-    });
+      }
+    }
+  });
 }
 
 const getCode = async () => {
-    const { data } = await getCodeImg();
-    captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
-    if (captchaEnabled.value) {
-        codeUrl.value = "data:image/gif;base64," + data.img;
-        registerForm.value.uuid = data.uuid;
-    }
+  const { data } = await getCodeImg();
+  captchaEnabled.value = data.captchaEnabled === undefined ? true : data.captchaEnabled;
+  if (captchaEnabled.value) {
+    codeUrl.value = "data:image/gif;base64," + data.img;
+    registerForm.value.uuid = data.uuid;
+  }
 }
 
 const initTenantList = async () => {
-    const { data } = await getTenantList();
-    tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
-    if (tenantEnabled.value) {
-        tenantList.value = data.voList;
-        if (tenantList.value != null && tenantList.value.length !== 0) {
-            registerForm.value.tenantId = tenantList.value[0].tenantId;
-        }
+  const { data } = await getTenantList();
+  tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
+  if (tenantEnabled.value) {
+    tenantList.value = data.voList;
+    if (tenantList.value != null && tenantList.value.length !== 0) {
+      registerForm.value.tenantId = tenantList.value[0].tenantId;
     }
+  }
 }
 
 onMounted(() => {
-    getCode();
-    initTenantList();
+  getCode();
+  initTenantList();
 })
 </script>
 

+ 104 - 104
src/views/system/config/index.vue

@@ -1,38 +1,40 @@
 <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="68px">
-          <el-form-item label="参数名称" prop="configName">
-            <el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="参数键名" prop="configKey">
-            <el-input v-model="queryParams.configKey" placeholder="请输入参数键名" clearable style="width: 240px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="系统内置" prop="configType">
-            <el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
-              <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-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="参数键名" prop="configKey">
+              <el-input v-model="queryParams.configKey" placeholder="请输入参数键名" clearable style="width: 240px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="系统内置" prop="configType">
+              <el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
+                <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-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -123,8 +125,6 @@
 <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 { ComponentInternalInstance } from "vue";
-import { DateModelType } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
@@ -138,124 +138,124 @@ const multiple = ref(true);
 const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 
-const queryFormRef = ref(ElForm);
-const configFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const configFormRef = ref<ElFormInstance>();
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 const initFormData: ConfigForm = {
-    configId: undefined,
-    configName: '',
-    configKey: '',
-    configValue: '',
-    configType: "Y",
-    remark: ''
+  configId: undefined,
+  configName: '',
+  configKey: '',
+  configValue: '',
+  configType: "Y",
+  remark: ''
 }
 const data = reactive<PageData<ConfigForm, ConfigQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        configName: '',
-        configKey: '',
-        configType: '',
-    },
-    rules: {
-        configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
-        configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
-        configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    configName: '',
+    configKey: '',
+    configType: '',
+  },
+  rules: {
+    configName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
+    configKey: [{ required: true, message: "参数键名不能为空", trigger: "blur" }],
+    configValue: [{ required: true, message: "参数键值不能为空", trigger: "blur" }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询参数列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
-    configList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listConfig(proxy?.addDateRange(queryParams.value, dateRange.value));
+  configList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset();
-    dialog.visible = false;
+  reset();
+  dialog.visible = false;
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = {...initFormData};
-    configFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  configFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    dateRange.value = ['', ''];
-    queryFormRef.value.resetFields();
-    handleQuery();
+  dateRange.value = ['', ''];
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: ConfigVO[]) => {
-    ids.value = selection.map(item => item.configId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.configId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加参数";
-    nextTick(() => {
-        reset();
-    })
+  dialog.visible = true;
+  dialog.title = "添加参数";
+  nextTick(() => {
+    reset();
+  })
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: ConfigVO) => {
-    dialog.visible = true;
-    dialog.title = "修改参数";
-    const configId = row?.configId || ids.value[0];
-    nextTick(async () => {
-        reset();
-        const res = await getConfig(configId);
-        form.value = res.data;
-    })
+  dialog.visible = true;
+  dialog.title = "修改参数";
+  const configId = row?.configId || ids.value[0];
+  nextTick(async () => {
+    reset();
+    const res = await getConfig(configId);
+    form.value = res.data;
+  })
 }
 /** 提交按钮 */
 const submitForm = () => {
-    configFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  configFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
+      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);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const configIds = row?.configId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
+  await delConfig(configIds);
+  await getList();
+  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("刷新缓存成功");
+  await refreshCache();
+  proxy?.$modal.msgSuccess("刷新缓存成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 })
 </script>

+ 114 - 109
src/views/system/dept/index.vue

@@ -1,25 +1,27 @@
 <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 ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
-          <el-form-item label="菜单名称" prop="menuName">
-            <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
-              <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>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
+            <el-form-item label="菜单名称" prop="menuName">
+              <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
+                <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>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
@@ -130,13 +132,12 @@
 
 <script setup name="Dept" lang="ts">
 import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
-import { ComponentInternalInstance } from 'vue';
 import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
 
 interface DeptOptionsType {
-    deptId: number | string;
-    deptName: string;
-    children: DeptOptionsType[];
+  deptId: number | string;
+  deptName: string;
+  children: DeptOptionsType[];
 
 }
 
@@ -151,142 +152,146 @@ const isExpandAll = ref(true)
 
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
-const deptTableRef = ref(ElTable);
-const queryFormRef = ref(ElForm);
-const deptFormRef = ref(ElForm);
+const deptTableRef = ref<ElTableInstance>();
+const queryFormRef = ref<ElFormInstance>();
+const deptFormRef = ref<ElFormInstance>();
 
 const initFormData: DeptForm = {
-    deptId: undefined,
-    parentId: undefined,
-    deptName: undefined,
-    orderNum: 0,
-    leader: undefined,
-    phone: undefined,
-    email: undefined,
-    status: "0"
+  deptId: undefined,
+  parentId: undefined,
+  deptName: undefined,
+  orderNum: 0,
+  leader: undefined,
+  phone: undefined,
+  email: undefined,
+  status: "0"
 }
 const data = reactive<PageData<DeptForm, DeptQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        deptName: undefined,
-        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" }]
-    },
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    deptName: undefined,
+    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" }]
+  },
 })
 
 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")
-    if (data) {
-        deptList.value = data
-    }
-    loading.value = false
+  loading.value = true;
+  const res = await listDept(queryParams.value);
+  const data = proxy?.handleTree<DeptVO>(res.data, "deptId")
+  if (data) {
+    deptList.value = data
+  }
+  loading.value = false
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset()
-    dialog.visible = false
+  reset()
+  dialog.visible = false
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = {...initFormData};
-    deptFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  deptFormRef.value?.resetFields();
 }
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    getList();
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery()
+  queryFormRef.value?.resetFields();
+  handleQuery()
 }
 /** 新增按钮操作 */
 const handleAdd = (row?: DeptVO) => {
-    listDept().then(res => {
-        const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
-        if (data) {
-            deptOptions.value = data
-            dialog.visible = true;
-            dialog.title = "添加部门";
-            nextTick(() => {
-                reset();
-                if (row && row.deptId) {
-                    form.value.parentId = row?.deptId;
-                }
-            })
+  listDept().then(res => {
+    const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
+    if (data) {
+      deptOptions.value = data
+      dialog.visible = true;
+      dialog.title = "添加部门";
+      nextTick(() => {
+        reset();
+        if (row && row.deptId) {
+          form.value.parentId = row?.deptId;
         }
-    })
+      })
+    }
+  })
 }
 /** 展开/折叠操作 */
 const handleToggleExpandAll = () => {
-    isExpandAll.value = !isExpandAll.value;
-    toggleExpandAll(deptList.value, isExpandAll.value)
+  isExpandAll.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)
-    })
+  data.forEach((item) => {
+    deptTableRef.value?.toggleRowExpansion(item, status)
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
+  })
 }
 
 /** 修改按钮操作 */
 const handleUpdate = async (row: DeptVO) => {
-    const res = await getDept(row.deptId);
-    dialog.visible = true;
-    dialog.title = "修改部门";
-    nextTick(async () => {
-        reset();
-        form.value = res.data
-        const response = await listDeptExcludeChild(row.deptId);
-        const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
-        if (data) {
-            deptOptions.value = data;
-            if (data.length === 0) {
-                const noResultsOptions: DeptOptionsType = { deptId: res.data.parentId, deptName: res.data.parentName, children: [] };
-                deptOptions.value.push(noResultsOptions);
-            }
-        }
-    })
+  const res = await getDept(row.deptId);
+  dialog.visible = true;
+  dialog.title = "修改部门";
+  await nextTick(async () => {
+    reset();
+    form.value = res.data
+    const response = await listDeptExcludeChild(row.deptId);
+    const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
+    if (data) {
+      deptOptions.value = data;
+      if (data.length === 0) {
+        const noResultsOptions: DeptOptionsType = {
+          deptId: res.data.parentId,
+          deptName: res.data.parentName,
+          children: []
+        };
+        deptOptions.value.push(noResultsOptions);
+      }
+    }
+  })
 }
 /** 提交按钮 */
 const submitForm = () => {
-    deptFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    })
+  deptFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  })
 }
 /** 删除按钮操作 */
 const handleDelete = async (row: DeptVO) => {
-    await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
-    await delDept(row.deptId);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
+  await delDept(row.deptId);
+  await getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 });
 </script>

+ 114 - 114
src/views/system/dict/data.vue

@@ -1,29 +1,31 @@
 <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="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" />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="字典标签" prop="dictLabel">
-            <el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
-              <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>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="字典标签" prop="dictLabel">
+              <el-input v-model="queryParams.dictLabel" placeholder="请输入字典标签" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="数据状态" clearable style="width: 200px">
+                <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>
+              <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>
       </div>
     </transition>
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -136,9 +138,7 @@ 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 { ComponentInternalInstance } from "vue";
 import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
-import { ElForm } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
@@ -154,159 +154,159 @@ const total = ref(0);
 const defaultDictType = ref("");
 const typeOptions = ref<DictTypeVO[]>([]);
 
-const dataFormRef = ref(ElForm);
-const queryFormRef = ref(ElForm);
+const dataFormRef = ref<ElFormInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  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: "危险" }
+  { value: "default", label: "默认" },
+  { value: "primary", label: "主要" },
+  { value: "success", label: "成功" },
+  { value: "info", label: "信息" },
+  { value: "warning", label: "警告" },
+  { value: "danger", label: "危险" }
 ]);
 
 const initFormData: DictDataForm = {
-    dictCode: undefined,
-    dictLabel: '',
-    dictValue: '',
-    cssClass: '',
-    listClass: "default",
-    dictSort: 0,
-    status: "0",
-    remark: ''
+  dictCode: undefined,
+  dictLabel: '',
+  dictValue: '',
+  cssClass: '',
+  listClass: "default",
+  dictSort: 0,
+  status: "0",
+  remark: ''
 }
 const data = reactive<PageData<DictDataForm, DictDataQuery>>({
-    form: { ...initFormData },
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        dictName: '',
-        dictType: '',
-        status: '',
-        dictLabel: ''
-    },
-    rules: {
-        dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
-        dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
-        dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    dictName: '',
+    dictType: '',
+    status: '',
+    dictLabel: ''
+  },
+  rules: {
+    dictLabel: [{ required: true, message: "数据标签不能为空", trigger: "blur" }],
+    dictValue: [{ required: true, message: "数据键值不能为空", trigger: "blur" }],
+    dictSort: [{ required: true, message: "数据顺序不能为空", trigger: "blur" }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询字典类型详细 */
 const getTypes = async (dictId: string | number) => {
-    const { data } = await getType(dictId);
-    queryParams.value.dictType = data.dictType;
-    defaultDictType.value = data.dictType;
-    getList();
+  const { data } = await getType(dictId);
+  queryParams.value.dictType = data.dictType;
+  defaultDictType.value = data.dictType;
+  getList();
 }
 
 /** 查询字典类型列表 */
 const getTypeList = async () => {
-    const res = await getDictOptionselect()
-    typeOptions.value = res.data;
+  const res = await getDictOptionselect()
+  typeOptions.value = res.data;
 }
 /** 查询字典数据列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listData(queryParams.value);
-    dataList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listData(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 取消按钮 */
 const cancel = () => {
-    dialog.visible = false;
-    reset();
+  dialog.visible = false;
+  reset();
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = { ...initFormData };
-    dataFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  dataFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 返回按钮操作 */
 const handleClose = () => {
-    const obj = { path: "/system/dict" };
-    proxy?.$tab.closeOpenPage(obj);
+  const obj = { path: "/system/dict" };
+  proxy?.$tab.closeOpenPage(obj);
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    queryParams.value.dictType = defaultDictType.value;
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  queryParams.value.dictType = defaultDictType.value;
+  handleQuery();
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加字典数据";
-    nextTick(() => {
-        reset();
-        form.value.dictType = queryParams.value.dictType;
-    })
+  dialog.visible = true;
+  dialog.title = "添加字典数据";
+  nextTick(() => {
+    reset();
+    form.value.dictType = queryParams.value.dictType;
+  })
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: DictDataVO[]) => {
-    ids.value = selection.map(item => item.dictCode);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.dictCode);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: DictDataVO) => {
-    const dictCode = row?.dictCode || ids.value[0];
-    dialog.visible = true;
-    dialog.title = "修改字典数据";
-    nextTick(async () => {
-        const res =  await getData(dictCode);
-        reset();
-        form.value = res.data;
-    })
+  const dictCode = row?.dictCode || ids.value[0];
+  dialog.visible = true;
+  dialog.title = "修改字典数据";
+  nextTick(async () => {
+    const res = await getData(dictCode);
+    reset();
+    form.value = res.data;
+  })
 }
 /** 提交按钮 */
 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("操作成功");
-            dialog.visible = false;
-            getList();
+  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("操作成功");
+      dialog.visible = false;
+      await getList();
 
-        }
-    });
+    }
+  });
 }
 /** 删除按钮操作 */
 const handleDelete = async (row?: DictDataVO) => {
-    const dictCodes = row?.dictCode || ids.value;
-    await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
-    await delData(dictCodes);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
-    useDictStore().removeDict(queryParams.value.dictType);
+  const dictCodes = row?.dictCode || ids.value;
+  await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
+  await delData(dictCodes);
+  await getList();
+  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);
-    getTypeList();
+  getTypes(route.params && route.params.dictId as string);
+  getTypeList();
 })
 </script>

+ 106 - 106
src/views/system/dict/index.vue

@@ -1,38 +1,40 @@
 <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="68px">
-          <el-form-item label="字典名称" prop="dictName">
-            <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="字典类型" prop="dictType">
-            <el-input v-model="queryParams.dictType" 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">
-              <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-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="字典类型" prop="dictType">
+              <el-input v-model="queryParams.dictType" 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">
+                <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-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -123,9 +125,7 @@
 <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 { ComponentInternalInstance } from "vue";
 import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
-import { DateModelType } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"))
@@ -139,128 +139,128 @@ const multiple = ref(true);
 const total = ref(0);
 const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 
-const dictFormRef = ref(ElForm);
-const queryFormRef = ref(ElForm);
+const dictFormRef = ref<ElFormInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 const initFormData: DictTypeForm = {
-    dictId: undefined,
-    dictName: '',
-    dictType: '',
-    status: "0",
-    remark: ''
+  dictId: undefined,
+  dictName: '',
+  dictType: '',
+  status: "0",
+  remark: ''
 }
 const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        dictName: '',
-        dictType: '',
-        status: ''
-    },
-    rules: {
-        dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
-        dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
-    },
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    dictName: '',
+    dictType: '',
+    status: ''
+  },
+  rules: {
+    dictName: [{ required: true, message: "字典名称不能为空", trigger: "blur" }],
+    dictType: [{ required: true, message: "字典类型不能为空", trigger: "blur" }]
+  },
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询字典类型列表 */
 const getList = () => {
-    loading.value = true;
-    listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => {
-        typeList.value = res.rows;
-        total.value = res.total;
-        loading.value = false;
-    });
+  loading.value = true;
+  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;
+  reset();
+  dialog.visible = false;
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = {...initFormData};
-    dictFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  dictFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    dateRange.value = ['', ''];
-    queryFormRef.value.resetFields();
-    handleQuery();
+  dateRange.value = ['', ''];
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加字典类型";
-    nextTick(() => {
-        reset();
-    })
+  dialog.visible = true;
+  dialog.title = "添加字典类型";
+  nextTick(() => {
+    reset();
+  })
 }
 /** 多选框选中数据 */
-const handleSelectionChange = (selection: DictTypeVO[]) =>  {
-    ids.value = selection.map(item => item.dictId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+const handleSelectionChange = (selection: DictTypeVO[]) => {
+  ids.value = selection.map(item => item.dictId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: DictTypeVO) => {
-    dialog.visible = true;
-    dialog.title = "修改字典类型";
-    const dictId = row?.dictId || ids.value[0];
-    nextTick(async () => {
-        reset();
-        const res = await getType(dictId);
-        form.value = res.data;
-    })
+  dialog.visible = true;
+  dialog.title = "修改字典类型";
+  const dictId = row?.dictId || ids.value[0];
+  nextTick(async () => {
+    reset();
+    const res = await getType(dictId);
+    form.value = res.data;
+  })
 
 }
 /** 提交按钮 */
 const submitForm = () => {
-    dictFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.dictId ? await updateType(form.value) : await addType(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  dictFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.dictId ? await updateType(form.value) : await addType(form.value);
+      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("删除成功");
+  const dictIds = row?.dictId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?');
+  await delType(dictIds);
+  getList();
+  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("刷新成功");
-    useDictStore().cleanDict();
+  await refreshCache();
+  proxy?.$modal.msgSuccess("刷新成功");
+  useDictStore().cleanDict();
 }
 
-onMounted(()=>{
-    getList();
+onMounted(() => {
+  getList();
 })
 </script>

+ 102 - 103
src/views/system/menu/index.vue

@@ -1,25 +1,27 @@
 <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 ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
-          <el-form-item label="菜单名称" prop="menuName">
-            <el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
-              <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>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
+            <el-form-item label="菜单名称" prop="menuName">
+              <el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
+                <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>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
@@ -37,7 +39,6 @@
         :data="menuList"
         row-key="menuId"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
-        border
         ref="menuTableRef"
         :default-expand-all="isExpandAll"
       >
@@ -262,14 +263,12 @@
 <script setup name="Menu" lang="ts">
 import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
 import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
-import { ComponentInternalInstance } from 'vue';
 import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
-import { ElTable, ElForm } from 'element-plus';
 
 interface MenuOptionsType {
-    menuId: number;
-    menuName: string;
-    children: MenuOptionsType[] | undefined;
+  menuId: number;
+  menuName: string;
+  children: MenuOptionsType[] | undefined;
 }
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance
@@ -282,136 +281,136 @@ const menuOptions = ref<MenuOptionsType[]>([])
 const isExpandAll = ref(false)
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
-const queryFormRef = ref(ElForm);
-const menuFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const menuFormRef = ref<ElFormInstance>();
 const initFormData = {
-    path: '',
-    menuId: undefined,
-    parentId: 0,
-    menuName: '',
-    icon: '',
-    menuType: MenuTypeEnum.M,
-    orderNum: 1,
-    isFrame: "1",
-    isCache: "0",
-    visible: "0",
-    status: "0"
+  path: '',
+  menuId: undefined,
+  parentId: 0,
+  menuName: '',
+  icon: '',
+  menuType: MenuTypeEnum.M,
+  orderNum: 1,
+  isFrame: "1",
+  isCache: "0",
+  visible: "0",
+  status: "0"
 }
 const data = reactive<PageData<MenuForm, MenuQuery>>({
-    form: { ...initFormData },
-    queryParams: {
-        menuName: undefined,
-        status: undefined
-    },
-    rules: {
-        menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
-        orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
-        path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
-    },
+  form: { ...initFormData },
+  queryParams: {
+    menuName: undefined,
+    status: undefined
+  },
+  rules: {
+    menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
+    orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
+    path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
+  },
 })
 
-const menuTableRef = ref(ElTable);
+const menuTableRef = ref<ElTableInstance>();
 
 const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
 /** 查询菜单列表 */
 const getList = async () => {
-    loading.value = true
-    const res = await listMenu(queryParams.value);
-    const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
-    if (data) {
-        menuList.value = data
-    }
-    loading.value = false
+  loading.value = true
+  const res = await listMenu(queryParams.value);
+  const data = proxy?.handleTree<MenuVO>(res.data, "menuId")
+  if (data) {
+    menuList.value = data
+  }
+  loading.value = false
 }
 /** 查询菜单下拉树结构 */
 const getTreeselect = async () => {
-    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)
+  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 cancel = () => {
-    reset()
-    dialog.visible = false
+  reset()
+  dialog.visible = false
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = { ...initFormData };
-    menuFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  menuFormRef.value?.resetFields();
 }
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    getList();
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 新增按钮操作 */
 const handleAdd = (row?: MenuVO) => {
-    dialog.visible = true;
-    dialog.title = "添加菜单";
-    getTreeselect();
-    nextTick(() => {
-        reset();
-        row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
-    })
+  dialog.visible = true;
+  dialog.title = "添加菜单";
+  getTreeselect();
+  nextTick(() => {
+    reset();
+    row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
+  })
 
 }
 /** 展开/折叠操作 */
 const handleToggleExpandAll = () => {
-    isExpandAll.value = !isExpandAll.value;
-    toggleExpandAll(menuList.value, isExpandAll.value)
+  isExpandAll.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)
-    })
+  data.forEach((item: MenuVO) => {
+    menuTableRef.value?.toggleRowExpansion(item, status)
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
+  })
 }
 /** 修改按钮操作 */
 const handleUpdate = async (row: MenuVO) => {
-    await getTreeselect();
-    dialog.visible = true;
-    dialog.title = "修改菜单";
-    await nextTick(async () => {
-        if (row.menuId) {
-            const { data } = await getMenu(row.menuId);
-            reset();
-            form.value = data;
-        }
-    })
+  await getTreeselect();
+  dialog.visible = true;
+  dialog.title = "修改菜单";
+  await nextTick(async () => {
+    if (row.menuId) {
+      const { data } = await getMenu(row.menuId);
+      reset();
+      form.value = data;
+    }
+  })
 
 }
 /** 提交按钮 */
 const submitForm = () => {
-    menuFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    })
+  menuFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  })
 }
 /** 删除按钮操作 */
 const handleDelete = async (row: MenuVO) => {
-    await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
-    await delMenu(row.menuId);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
+  await delMenu(row.menuId);
+  await getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 });
 </script>

+ 89 - 89
src/views/system/notice/index.vue

@@ -1,28 +1,30 @@
 <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="68px">
-          <el-form-item label="公告标题" prop="noticeTitle">
-            <el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="操作人员" prop="createByName">
-            <el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="类型" prop="noticeType">
-            <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
-              <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-            </el-select>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="操作人员" prop="createByName">
+              <el-input v-model="queryParams.createByName" placeholder="请输入操作人员" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="类型" prop="noticeType">
+              <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable style="width: 200px">
+                <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -119,9 +121,7 @@
 
 <script setup name="Notice" lang="ts">
 import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
-import { ComponentInternalInstance } from "vue";
 import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
-import { ElForm } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
@@ -134,116 +134,116 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
-const queryFormRef = ref(ElForm);
-const noticeFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const noticeFormRef = ref<ElFormInstance>();
 
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 const initFormData: NoticeForm = {
-    noticeId: undefined,
-    noticeTitle: '',
-    noticeType: '',
-    noticeContent: '',
-    status: "0",
-    remark: '',
-    createByName: ''
+  noticeId: undefined,
+  noticeTitle: '',
+  noticeType: '',
+  noticeContent: '',
+  status: "0",
+  remark: '',
+  createByName: ''
 }
 const data = reactive<PageData<NoticeForm, NoticeQuery>>({
-    form: { ...initFormData },
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        noticeTitle: '',
-        createByName: '',
-        status: '',
-        noticeType: ''
-    },
-    rules: {
-        noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
-        noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
-    },
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    noticeTitle: '',
+    createByName: '',
+    status: '',
+    noticeType: ''
+  },
+  rules: {
+    noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
+    noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
+  },
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询公告列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listNotice(queryParams.value);
-    noticeList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listNotice(queryParams.value);
+  noticeList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset();
-    dialog.visible = false;
+  reset();
+  dialog.visible = false;
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = { ...initFormData };
-    noticeFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  noticeFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: NoticeVO[]) => {
-    ids.value = selection.map(item => item.noticeId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.noticeId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加公告";
-    nextTick(() => {
-        reset();
-    })
+  dialog.visible = true;
+  dialog.title = "添加公告";
+  nextTick(() => {
+    reset();
+  })
 }
 /**修改按钮操作 */
 const handleUpdate = (row?: NoticeVO) => {
-    dialog.visible = true;
-    dialog.title = "修改公告";
-    nextTick(async () => {
-        const noticeId = row?.noticeId || ids.value[0];
-        reset();
-        const { data } = await getNotice(noticeId);
-        form.value = data;
-    })
+  dialog.visible = true;
+  dialog.title = "修改公告";
+  nextTick(async () => {
+    const noticeId = row?.noticeId || ids.value[0];
+    reset();
+    const { data } = await getNotice(noticeId);
+    form.value = data;
+  })
 }
 /** 提交按钮 */
 const submitForm = () => {
-    noticeFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
-            proxy?.$modal.msgSuccess("修改成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  noticeFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
+      proxy?.$modal.msgSuccess("修改成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
 }
 /** 删除按钮操作 */
 const handleDelete = async (row?: NoticeVO) => {
-    const noticeIds = row?.noticeId || ids.value
-    await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
-    await delNotice(noticeIds);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const noticeIds = row?.noticeId || ids.value
+  await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
+  await delNotice(noticeIds);
+  await getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 })
-</script>
+</script>

+ 165 - 165
src/views/system/oss/config.vue

@@ -1,29 +1,31 @@
 <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="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>
-          <el-form-item label="桶名称" prop="bucketName">
-            <el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="是否默认" prop="status">
-            <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
-              <el-option key="0" label="是" value="0" />
-              <el-option key="1" label="否" value="1" />
-            </el-select>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="桶名称" prop="bucketName">
+              <el-input v-model="queryParams.bucketName" placeholder="请输入桶名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否默认" prop="status">
+              <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px">
+                <el-option key="0" label="是" value="0" />
+                <el-option key="1" label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -131,16 +133,14 @@
 
 <script setup name="OssConfig" lang="ts">
 import {
-    listOssConfig,
-    getOssConfig,
-    delOssConfig,
-    addOssConfig,
-    updateOssConfig,
-    changeOssConfigStatus
+  listOssConfig,
+  getOssConfig,
+  delOssConfig,
+  addOssConfig,
+  updateOssConfig,
+  changeOssConfigStatus
 } from "@/api/system/ossConfig";
-import { ComponentInternalInstance } from "vue";
 import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
-import { ElForm } from 'element-plus';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance
@@ -155,193 +155,193 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
-const queryFormRef = ref(ElForm);
-const ossConfigFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const ossConfigFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 // 列显隐信息
 const columns = ref<FieldOption[]>([
-    { key: 0, label: `主建`, visible: true },
-    { key: 1, label: `配置key`, visible: false },
-    { key: 2, label: `访问站点`, visible: true },
-    { key: 3, label: `自定义域名`, visible: true },
-    { key: 4, label: `桶名称`, visible: true },
-    { key: 5, label: `前缀`, visible: true },
-    { key: 6, label: `域`, visible: true },
-    { key: 7, label: `桶权限类型`, visible: true },
-    { key: 8, label: `状态`, visible: true }
+  { key: 0, label: `主建`, visible: true },
+  { key: 1, label: `配置key`, visible: false },
+  { key: 2, label: `访问站点`, visible: true },
+  { key: 3, label: `自定义域名`, visible: true },
+  { key: 4, label: `桶名称`, visible: true },
+  { key: 5, label: `前缀`, visible: true },
+  { key: 6, label: `域`, visible: true },
+  { key: 7, label: `桶权限类型`, visible: true },
+  { key: 8, label: `状态`, visible: true }
 ]);
 
 
 const initFormData: OssConfigForm = {
-    ossConfigId: undefined,
-    configKey: '',
-    accessKey: '',
-    secretKey: '',
-    bucketName: '',
-    prefix: '',
-    endpoint: '',
-    domain: '',
-    isHttps: "N",
-    accessPolicy: "1",
-    region: '',
-    status: "1",
-    remark: '',
+  ossConfigId: undefined,
+  configKey: '',
+  accessKey: '',
+  secretKey: '',
+  bucketName: '',
+  prefix: '',
+  endpoint: '',
+  domain: '',
+  isHttps: "N",
+  accessPolicy: "1",
+  region: '',
+  status: "1",
+  remark: '',
 }
 const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({
-    form: { ...initFormData },
-    // 查询参数
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        configKey: '',
-        bucketName: '',
-        status: '',
-    },
-    rules: {
-        configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
-        accessKey: [
-            { required: true, message: "accessKey不能为空", trigger: "blur" },
-            {
-                min: 2,
-                max: 200,
-                message: "accessKey长度必须介于 2 和 100 之间",
-                trigger: "blur",
-            },
-        ],
-        secretKey: [
-            { required: true, message: "secretKey不能为空", trigger: "blur" },
-            {
-                min: 2,
-                max: 100,
-                message: "secretKey长度必须介于 2 和 100 之间",
-                trigger: "blur",
-            },
-        ],
-        bucketName: [
-            { required: true, message: "bucketName不能为空", trigger: "blur" },
-            {
-                min: 2,
-                max: 100,
-                message: "bucketName长度必须介于 2 和 100 之间",
-                trigger: "blur",
-            },
-        ],
-        endpoint: [
-            { required: true, message: "endpoint不能为空", trigger: "blur" },
-            {
-                min: 2,
-                max: 100,
-                message: "endpoint名称长度必须介于 2 和 100 之间",
-                trigger: "blur",
-            },
-        ],
-        accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
-    }
+  form: { ...initFormData },
+  // 查询参数
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    configKey: '',
+    bucketName: '',
+    status: '',
+  },
+  rules: {
+    configKey: [{ required: true, message: "configKey不能为空", trigger: "blur" },],
+    accessKey: [
+      { required: true, message: "accessKey不能为空", trigger: "blur" },
+      {
+        min: 2,
+        max: 200,
+        message: "accessKey长度必须介于 2 和 100 之间",
+        trigger: "blur",
+      },
+    ],
+    secretKey: [
+      { required: true, message: "secretKey不能为空", trigger: "blur" },
+      {
+        min: 2,
+        max: 100,
+        message: "secretKey长度必须介于 2 和 100 之间",
+        trigger: "blur",
+      },
+    ],
+    bucketName: [
+      { required: true, message: "bucketName不能为空", trigger: "blur" },
+      {
+        min: 2,
+        max: 100,
+        message: "bucketName长度必须介于 2 和 100 之间",
+        trigger: "blur",
+      },
+    ],
+    endpoint: [
+      { required: true, message: "endpoint不能为空", trigger: "blur" },
+      {
+        min: 2,
+        max: 100,
+        message: "endpoint名称长度必须介于 2 和 100 之间",
+        trigger: "blur",
+      },
+    ],
+    accessPolicy: [{ required: true, message: "accessPolicy不能为空", trigger: "blur" }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询对象存储配置列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listOssConfig(queryParams.value);
-    ossConfigList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listOssConfig(queryParams.value);
+  ossConfigList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 取消按钮 */
 const cancel = () => {
-    dialog.visible = false;
-    reset();
+  dialog.visible = false;
+  reset();
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = { ...initFormData };
-    ossConfigFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  ossConfigFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 选择条数  */
 const handleSelectionChange = (selection: OssConfigVO[]) => {
-    ids.value = selection.map(item => item.ossConfigId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.ossConfigId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加对象存储配置";
-    nextTick(() => {
-        reset();
-    })
+  dialog.visible = true;
+  dialog.title = "添加对象存储配置";
+  nextTick(() => {
+    reset();
+  })
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: OssConfigVO) => {
-    loading.value = true;
-    dialog.visible = true;
-    dialog.title = "修改对象存储配置";
-    const ossConfigId = row?.ossConfigId || ids.value[0];
-    nextTick(async () => {
-        reset();
-        const res = await getOssConfig(ossConfigId);
-        loading.value = false;
-        form.value = res.data;
-    })
+  loading.value = true;
+  dialog.visible = true;
+  dialog.title = "修改对象存储配置";
+  const ossConfigId = row?.ossConfigId || ids.value[0];
+  nextTick(async () => {
+    reset();
+    const res = await getOssConfig(ossConfigId);
+    loading.value = false;
+    form.value = res.data;
+  })
 }
 /** 提交按钮 */
 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);
-            } else {
-                await addOssConfig(form.value).finally(() => buttonLoading.value = false);
-            }
-            proxy?.$modal.msgSuccess("新增成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  ossConfigFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.ossConfigId) {
+        await updateOssConfig(form.value).finally(() => buttonLoading.value = false);
+      } else {
+        await addOssConfig(form.value).finally(() => buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("新增成功");
+      dialog.visible = false;
+      getList();
+    }
+  });
 }
 /** 状态修改  */
-const  handleStatusChange = async (row: OssConfigVO) => {
-    let text = row.status === "0" ? "启用" : "停用";
-    try {
-        await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
-        await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
-        getList()
-        proxy?.$modal.msgSuccess(text + "成功");
-    } catch { return } finally {
-        row.status = row.status === "0" ? "1" : "0";
-    }
+const handleStatusChange = async (row: OssConfigVO) => {
+  let text = row.status === "0" ? "启用" : "停用";
+  try {
+    await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
+    await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
+    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);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const ossConfigIds = row?.ossConfigId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
+  loading.value = true;
+  await delOssConfig(ossConfigIds).finally(() => loading.value = false);
+  getList();
+  proxy?.$modal.msgSuccess("删除成功");
 
 }
 
 onMounted(() => {
-    getList();
+  getList();
 })
-</script>
+</script>

+ 148 - 148
src/views/system/oss/index.vue

@@ -1,40 +1,42 @@
 <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="68px">
-          <el-form-item label="文件名" prop="fileName">
-            <el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="原名" prop="originalName">
-            <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="文件后缀" prop="fileSuffix">
-            <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="创建时间">
-            <el-date-picker
-              v-model="daterangeCreateTime"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item label="服务商" prop="service">
-            <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="原名" prop="originalName">
+              <el-input v-model="queryParams.originalName" placeholder="请输入原名" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="文件后缀" prop="fileSuffix">
+              <el-input v-model="queryParams.fileSuffix" placeholder="请输入文件后缀" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="创建时间">
+              <el-date-picker
+                v-model="daterangeCreateTime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item label="服务商" prop="service">
+              <el-input v-model="queryParams.service" placeholder="请输入服务商" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -133,9 +135,7 @@
 <script setup name="Oss" lang="ts">
 import { listOss, delOss } from "@/api/system/oss";
 import ImagePreview from "@/components/ImagePreview/index.vue";
-import { ComponentInternalInstance } from "vue";
 import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
-import { DateModelType } from 'element-plus';
 
 const router = useRouter();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -154,186 +154,186 @@ const previewListResource = ref(true);
 const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 // 默认排序
 const defaultSort = ref({ prop: 'createTime', order: 'ascending' });
 
-const ossFormRef = ref(ElForm);
-const queryFormRef = ref(ElForm);
+const ossFormRef = ref<ElFormInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 const initFormData = {
-    file: undefined,
+  file: undefined,
 }
 const data = reactive<PageData<OssForm, OssQuery>>({
-    form: { ...initFormData },
-    // 查询参数
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        fileName: '',
-        originalName: '',
-        fileSuffix: '',
-        createTime: '',
-        service: '',
-        orderByColumn: defaultSort.value.prop,
-        isAsc: defaultSort.value.order
-    },
-    rules: {
-        file: [
-            { required: true, message: "文件不能为空", trigger: "blur" }
-        ]
-    }
+  form: { ...initFormData },
+  // 查询参数
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    fileName: '',
+    originalName: '',
+    fileSuffix: '',
+    createTime: '',
+    service: '',
+    orderByColumn: defaultSort.value.prop,
+    isAsc: defaultSort.value.order
+  },
+  rules: {
+    file: [
+      { required: true, message: "文件不能为空", trigger: "blur" }
+    ]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询OSS对象存储列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await proxy?.getConfigKey("sys.oss.previewListResource");
-    previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
-    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;
+  loading.value = true;
+  const res = await proxy?.getConfigKey("sys.oss.previewListResource");
+  previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
+  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 => {
-        return fileSuffix.indexOf(type) > -1;
-    });
+  let arr = ["png", "jpg", "jpeg"];
+  return arr.some(type => {
+    return fileSuffix.indexOf(type) > -1;
+  });
 }
 /** 取消按钮 */
 function cancel() {
-    dialog.visible = false;
-    reset();
+  dialog.visible = false;
+  reset();
 }
 /** 表单重置 */
 function reset() {
-    form.value = { ...initFormData };
-    ossFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  ossFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 function handleQuery() {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 function resetQuery() {
-    showTable.value = false;
-    daterangeCreateTime.value = ['', ''];
-    queryFormRef.value.resetFields();
-    queryParams.value.orderByColumn = defaultSort.value.prop;
-    queryParams.value.isAsc = defaultSort.value.order;
-    handleQuery();
+  showTable.value = false;
+  daterangeCreateTime.value = ['', ''];
+  queryFormRef.value?.resetFields();
+  queryParams.value.orderByColumn = defaultSort.value.prop;
+  queryParams.value.isAsc = defaultSort.value.order;
+  handleQuery();
 }
 /** 选择条数  */
 function handleSelectionChange(selection: OssVO[]) {
-    ids.value = selection.map(item => item.ossId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  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
-    }
-    switch (column.multiOrder) {
-        case 'descending':
-            column.multiOrder = 'ascending';
-            break;
-        case 'ascending':
-            column.multiOrder = '';
-            break;
-        default:
-            column.multiOrder = 'descending';
-            break;
-    }
-    handleOrderChange(column.property, column.multiOrder)
+  if (column.sortable !== 'custom') {
+    return
+  }
+  switch (column.multiOrder) {
+    case 'descending':
+      column.multiOrder = 'ascending';
+      break;
+    case 'ascending':
+      column.multiOrder = '';
+      break;
+    default:
+      column.multiOrder = 'descending';
+      break;
+  }
+  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)
-    if (propIndex !== -1) {
-        if (order) {
-            //排序里已存在 只修改排序
-            isAscArr[propIndex] = order;
-        } else {
-            //如果order为null 则删除排序字段和属性
-            isAscArr.splice(propIndex, 1);//删除排序
-            orderByArr.splice(propIndex, 1);//删除属性
-        }
+  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 {
-        //排序里不存在则新增排序
-        orderByArr.push(prop);
-        isAscArr.push(order);
+      //如果order为null 则删除排序字段和属性
+      isAscArr.splice(propIndex, 1);//删除排序
+      orderByArr.splice(propIndex, 1);//删除属性
     }
-    //合并排序
-    queryParams.value.orderByColumn = orderByArr.join(",");
-    queryParams.value.isAsc = isAscArr.join(",");
-    getList();
+  } else {
+    //排序里不存在则新增排序
+    orderByArr.push(prop);
+    isAscArr.push(order);
+  }
+  //合并排序
+  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 = () => {
-    dialog.visible = true;
-    dialog.title = "上传文件";
-    nextTick(() => {
-        reset();
-        type.value = 0;
-    })
+  dialog.visible = true;
+  dialog.title = "上传文件";
+  nextTick(() => {
+    reset();
+    type.value = 0;
+  })
 }
 /** 图片按钮操作 */
 const handleImage = () => {
-    dialog.visible = true;
-    dialog.title = "上传图片";
-    nextTick(() => {
-        reset();
-        type.value = 1;
-    })
+  dialog.visible = true;
+  dialog.title = "上传图片";
+  nextTick(() => {
+    reset();
+    type.value = 1;
+  })
 }
 /** 提交按钮 */
 const submitForm = () => {
-    dialog.visible = false;
-    getList();
+  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 ? "启用" : "停用";
-    try {
-      await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
-      await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
-      getList()
-      proxy?.$modal.msgSuccess(text + "成功");
-    } catch { return }
+  let text = preview ? "启用" : "停用";
+  try {
+    await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
+    await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
+    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);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const ossIds = row?.ossId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
+  loading.value = true;
+  await delOss(ossIds).finally(() => loading.value = false);
+  getList();
+  proxy?.$modal.msgSuccess("删除成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 })
 </script>

+ 90 - 89
src/views/system/post/index.vue

@@ -1,27 +1,29 @@
 <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="70">
-          <el-form-item label="岗位编码" prop="postCode">
-            <el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="岗位名称" prop="postName">
-            <el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
-              <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>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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>
+            <el-form-item label="岗位名称" prop="postName">
+              <el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="岗位状态" clearable style="width: 200px">
+                <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>
+              <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>
       </div>
     </transition>
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -107,7 +109,6 @@
 <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 { ComponentInternalInstance } from "vue";
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
@@ -120,121 +121,121 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
-const postFormRef = ref(ElForm);
-const queryFormRef = ref(ElForm);
+const postFormRef = ref<ElFormInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 const initFormData: PostForm = {
-    postId: undefined,
-    postCode: '',
-    postName: '',
-    postSort: 0,
-    status: "0",
-    remark: ''
+  postId: undefined,
+  postCode: '',
+  postName: '',
+  postSort: 0,
+  status: "0",
+  remark: ''
 }
 
 const data = reactive<PageData<PostForm, PostQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        postCode: '',
-        postName: '',
-        status: ''
-    },
-    rules: {
-        postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
-        postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
-        postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    postCode: '',
+    postName: '',
+    status: ''
+  },
+  rules: {
+    postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
+    postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
+    postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
+  }
 });
 
 const { queryParams, form, rules } = toRefs<PageData<PostForm, PostQuery>>(data);
 
 /** 查询岗位列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listPost(queryParams.value);
-    postList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listPost(queryParams.value);
+  postList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset();
-    dialog.visible = false;
+  reset();
+  dialog.visible = false;
 }
 /** 表单重置 */
 const reset = () => {
-    form.value = {...initFormData};
-    postFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  postFormRef.value?.resetFields();
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: PostVO[]) => {
-    ids.value = selection.map(item => item.postId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.postId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加岗位";
-    nextTick(() => {
-        reset();
-    })
+  dialog.visible = true;
+  dialog.title = "添加岗位";
+  nextTick(() => {
+    reset();
+  })
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: PostVO) => {
-    dialog.visible = true;
-    dialog.title = "修改岗位";
-    nextTick(async () => {
-        reset();
-        const postId = row?.postId || ids.value[0];
-        const res = await getPost(postId);
-        form.value = res.data;
-    })
+  dialog.visible = true;
+  dialog.title = "修改岗位";
+  nextTick(async () => {
+    reset();
+    const postId = row?.postId || ids.value[0];
+    const res = await getPost(postId);
+    form.value = res.data;
+  })
 }
 /** 提交按钮 */
 const submitForm = () => {
-    postFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.postId ? await updatePost(form.value) : await addPost(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  postFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.postId ? await updatePost(form.value) : await addPost(form.value);
+      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);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const postIds = row?.postId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
+  await delPost(postIds);
+  await getList();
+  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();
+  getList();
 });
 </script>

+ 36 - 44
src/views/system/role/authUser.vue

@@ -58,13 +58,7 @@
         </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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
       <select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
     </el-card>
   </div>
@@ -73,10 +67,8 @@
 <script setup name="AuthUser" lang="ts">
 import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
 import { UserQuery } from "@/api/system/user/types";
-import { ComponentInternalInstance } from "vue";
 import { UserVO } from "@/api/system/user/types";
 import SelectUser from "./selectUser.vue";
-// import { ElForm, ElSelect} from 'element-plus';
 
 
 const route = useRoute();
@@ -90,68 +82,68 @@ const multiple = ref(true);
 const total = ref(0);
 const userIds = ref<Array<string | number>>([]);
 
-const queryFormRef = ref(ElForm);
-const selectRef = ref(SelectUser);
+const queryFormRef = ref<ElFormInstance>();
+const selectRef = ref<InstanceType<typeof SelectUser>>();
 
 const queryParams = reactive<UserQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    roleId: route.params.roleId as string,
-    userName: undefined,
-    phonenumber: undefined,
+  pageNum: 1,
+  pageSize: 10,
+  roleId: route.params.roleId as string,
+  userName: undefined,
+  phonenumber: undefined,
 });
 
 /** 查询授权用户列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await allocatedUserList(queryParams);
-    userList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await allocatedUserList(queryParams);
+  userList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 // 返回按钮
 const handleClose = () => {
-    const obj = { path: "/system/role" };
-    proxy?.$tab.closeOpenPage(obj);
+  const obj = { path: "/system/role" };
+  proxy?.$tab.closeOpenPage(obj);
 }
 /** 搜索按钮操作 */
-const handleQuery=() => {
-    queryParams.pageNum = 1;
-    getList();
+const handleQuery = () => {
+  queryParams.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
-const resetQuery=() =>{
-    queryFormRef.value.resetFields();
-    handleQuery();
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 // 多选框选中数据
-const handleSelectionChange = (selection: UserVO[]) =>{
-    userIds.value = selection.map(item => item.userId);
-    multiple.value = !selection.length;
+const handleSelectionChange = (selection: UserVO[]) => {
+  userIds.value = selection.map(item => item.userId);
+  multiple.value = !selection.length;
 }
 /** 打开授权用户表弹窗 */
 const openSelectUser = () => {
-    selectRef.value.show();
+  selectRef.value?.show();
 }
 /** 取消授权按钮操作 */
 const cancelAuthUser = async (row: UserVO) => {
-    await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
-    await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
-    getList();
-    proxy?.$modal.msgSuccess("取消授权成功");
+  await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
+  await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
+  await getList();
+  proxy?.$modal.msgSuccess("取消授权成功");
 }
 /** 批量取消授权按钮操作 */
 const cancelAuthUserAll = async () => {
-    const roleId = queryParams.roleId;
-    const uIds = userIds.value.join(",");
-    await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
-    await authUserCancelAll({ roleId: roleId, userIds: uIds });
-    getList();
-    proxy?.$modal.msgSuccess("取消授权成功");
+  const roleId = queryParams.roleId;
+  const uIds = userIds.value.join(",");
+  await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
+  await authUserCancelAll({ roleId: roleId, userIds: uIds });
+  await getList();
+  proxy?.$modal.msgSuccess("取消授权成功");
 }
 
 onMounted(() => {
-    getList();
+  getList();
 });
 </script>
 

+ 219 - 211
src/views/system/role/index.vue

@@ -1,40 +1,42 @@
 <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 ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
-          <el-form-item label="角色名称" prop="roleName">
-            <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="权限字符" prop="roleKey">
-            <el-input v-model="queryParams.roleKey" 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">
-              <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-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-            ></el-date-picker>
-          </el-form-item>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
+            <el-form-item label="角色名称" prop="roleName">
+              <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="权限字符" prop="roleKey">
+              <el-input v-model="queryParams.roleKey" 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">
+                <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-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              ></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-form-item>
-        </el-form>
+            <el-form-item>
+              <el-button type="primary" @click="handleQuery" icon="Search">搜索</el-button>
+              <el-button @click="resetQuery" icon="Refresh">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
@@ -119,7 +121,7 @@
         <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
+              dict.label
             }}</el-radio>
           </el-radio-group>
         </el-form-item>
@@ -196,8 +198,6 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
 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';
-import { ComponentInternalInstance } from 'vue';
-import { ElTree, ElForm, DateModelType } from 'element-plus';
 
 const router = useRouter();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -221,54 +221,54 @@ 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(ElForm);
-const roleFormRef = ref(ElForm);
-const dataScopeRef = ref(ElForm);
-const menuRef = ref(ElTree);
-const deptRef = ref(ElTree);
+const queryFormRef = ref<ElFormInstance>();
+const roleFormRef = ref<ElFormInstance>();
+const dataScopeRef = ref<ElFormInstance>();
+const menuRef = ref<ElTreeInstance>();
+const deptRef = ref<ElTreeInstance>();
 
 const initForm: RoleForm = {
-    roleId: undefined,
-    roleSort: 1,
-    status: '0',
-    roleName: '',
-    roleKey: '',
-    menuCheckStrictly: true,
-    deptCheckStrictly: true,
-    remark: '',
-    dataScope: '1',
-    menuIds: [],
-    deptIds: [],
+  roleId: undefined,
+  roleSort: 1,
+  status: '0',
+  roleName: '',
+  roleKey: '',
+  menuCheckStrictly: true,
+  deptCheckStrictly: true,
+  remark: '',
+  dataScope: '1',
+  menuIds: [],
+  deptIds: [],
 }
 
 const data = reactive<PageData<RoleForm, RoleQuery>>({
-    form: {...initForm},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        roleName: '',
-        roleKey: '',
-        status: '',
-    },
-    rules: {
-        roleName: [{ required: true, message: "角色名称不能为空", trigger: "blur" }],
-        roleKey: [{ required: true, message: "权限字符不能为空", trigger: "blur" }],
-        roleSort: [{ required: true, message: "角色顺序不能为空", trigger: "blur" }]
-    }
+  form: { ...initForm },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    roleName: '',
+    roleKey: '',
+    status: '',
+  },
+  rules: {
+    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 dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 
@@ -276,233 +276,241 @@ 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
+  })
 }
 
 /**
  * 搜索按钮操作
  */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 
 /** 重置 */
 const resetQuery = () => {
-    dateRange.value = ['', '']
-    queryFormRef.value.resetFields();
-    handleQuery();
+  dateRange.value = ['', '']
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /**删除按钮操作 */
 const handleDelete = async (row?: RoleVO) => {
-    const roleids = row?.roleId || ids.value;
-    await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
-    await delRole(roleids);
-    getList();
-    proxy?.$modal.msgSuccess('删除成功');
+  const roleids = row?.roleId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
+  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;
+  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" ? "启用" : "停用";
-    try {
-        await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
-        await changeRoleStatus(row.roleId, row.status);
-        proxy?.$modal.msgSuccess(text + "成功");
-    } catch {
-        row.status = row.status === "0" ? "1" : "0";
-    }
+  let text = row.status === "0" ? "启用" : "停用";
+  try {
+    await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
+    await changeRoleStatus(row.roleId, row.status);
+    proxy?.$modal.msgSuccess(text + "成功");
+  } catch {
+    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 res = await menuTreeselect();
+  menuOptions.value = res.data;
 }
 /** 所有部门节点数据 */
-const getDeptAllCheckedKeys = () => {
-    // 目前被选中的部门节点
-    let checkedKeys = deptRef.value.getCheckedKeys();
-    // 半选中的部门节点
-    let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
-    checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
-    return checkedKeys
+const getDeptAllCheckedKeys = (): any => {
+  // 目前被选中的部门节点
+  let checkedKeys = deptRef.value?.getCheckedKeys();
+  // 半选中的部门节点
+  let halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
+  if (halfCheckedKeys) {
+    checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
+  }
+  return checkedKeys
 }
 /** 重置新增的表单以及其他数据  */
 const reset = () => {
-    menuRef.value.setCheckedKeys([]);
-    menuExpand.value = false
-    menuNodeAll.value = false
-    deptExpand.value = true
-    deptNodeAll.value = false
-    form.value = { ...initForm };
-    roleFormRef.value.resetFields();
+  menuRef.value?.setCheckedKeys([]);
+  menuExpand.value = false
+  menuNodeAll.value = false
+  deptExpand.value = true
+  deptNodeAll.value = false
+  form.value = { ...initForm };
+  roleFormRef.value?.resetFields();
 
 }
 
 /** 添加角色 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加角色";
-    nextTick(() => {
-        reset();
-        getMenuTreeselect();
-    })
+  dialog.visible = true;
+  dialog.title = "添加角色";
+  nextTick(() => {
+    reset();
+    getMenuTreeselect();
+  })
 }
 /** 修改角色 */
 const handleUpdate = async (row?: RoleVO) => {
-    const roleId = row?.roleId || ids.value[0]
-    const roleMenu = getRoleMenuTreeselect(roleId)
-    const { data } = await getRole(roleId);
-    dialog.visible = true;
-    dialog.title = "修改角色";
-    nextTick(() => {
-        reset();
-        Object.assign(form.value, data);
-        form.value.roleSort = Number(form.value.roleSort);
-        nextTick(async () => {
-            const res = await roleMenu;
-            let checkedKeys = res.checkedKeys;
-            checkedKeys.forEach((v) => {
-                nextTick(() => {
-                    menuRef.value.setChecked(v, true, false);
-                })
-            })
+  const roleId = row?.roleId || ids.value[0]
+  const roleMenu = getRoleMenuTreeselect(roleId)
+  const { data } = await getRole(roleId);
+  dialog.visible = true;
+  dialog.title = "修改角色";
+  await nextTick(() => {
+    reset();
+    Object.assign(form.value, data);
+    form.value.roleSort = Number(form.value.roleSort);
+    nextTick(async () => {
+      const res = await roleMenu;
+      let checkedKeys = res.checkedKeys;
+      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;
-    })
+  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 res = await deptTreeSelect(roleId);
+  deptOptions.value = res.data.depts;
+  return res.data;
 }
 /** 树权限(展开/折叠)*/
-const handleCheckedTreeExpand = (value: any, type: string) => {
-    if (type == "menu") {
-        let treeList = menuOptions.value;
-        for (let i = 0; i < treeList.length; i++) {
-            menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
-        }
-    } else if (type == "dept") {
-        let treeList = deptOptions.value;
-        for (let i = 0; i < treeList.length; i++) {
-            deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
-        }
+const handleCheckedTreeExpand = (value: boolean, type: string) => {
+  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") {
+    let treeList = deptOptions.value;
+    for (let i = 0; i < treeList.length; i++) {
+      if (deptRef.value) {
+        deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
+      }
+    }
+  }
 }
 /** 树权限(全选/全不选) */
 const handleCheckedTreeNodeAll = (value: any, type: string) => {
-    if (type == "menu") {
-        menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
-    } else if (type == "dept") {
-        deptRef.value.setCheckedNodes(value ? deptOptions.value : []);
-    }
+  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") {
-        form.value.menuCheckStrictly = value;
-    } else if (type == "dept") {
-        form.value.deptCheckStrictly = value;
-    }
+  if (type == "menu") {
+    form.value.menuCheckStrictly = value;
+  } else if (type == "dept") {
+    form.value.deptCheckStrictly = value;
+  }
 }
 /** 所有菜单节点数据 */
-const getMenuAllCheckedKeys = () => {
-    // 目前被选中的菜单节点
-    let checkedKeys = menuRef.value.getCheckedKeys();
-    // 半选中的菜单节点
-    let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
-    checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
-    return checkedKeys;
+const getMenuAllCheckedKeys = (): any => {
+  // 目前被选中的菜单节点
+  let checkedKeys = menuRef.value?.getCheckedKeys();
+  // 半选中的菜单节点
+  let halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
+  if (halfCheckedKeys) {
+    checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
+  }
+  return checkedKeys;
 }
 /** 提交按钮 */
 const submitForm = () => {
-    roleFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.menuIds = getMenuAllCheckedKeys()
-            form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
-            proxy?.$modal.msgSuccess("操作成功")
-            dialog.visible = false
-            getList()
-        }
-    })
+  roleFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.menuIds = getMenuAllCheckedKeys()
+      form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
+      proxy?.$modal.msgSuccess("操作成功")
+      dialog.visible = false
+      getList()
+    }
+  })
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset()
-    dialog.visible = false;
+  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 roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
-    const response = await getRole(row.roleId);
-    Object.assign(form.value, response.data);
-    openDataScope.value = true;
-    dialog.title = "分配数据权限";
-    nextTick(async () => {
-        const res = await roleDeptTreeselect;
-        nextTick(() => {
-            if (deptRef.value) {
-                deptRef.value.setCheckedKeys(res.checkedKeys);
-            }
-        })
+  const roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
+  const response = await getRole(row.roleId);
+  Object.assign(form.value, response.data);
+  openDataScope.value = true;
+  dialog.title = "分配数据权限";
+  await nextTick(async () => {
+    const res = await roleDeptTreeselect;
+    await nextTick(() => {
+      if (deptRef.value) {
+        deptRef.value.setCheckedKeys(res.checkedKeys);
+      }
     })
+  })
 }
 /** 提交按钮(数据权限) */
 const submitDataScope = async () => {
-    if (form.value.roleId) {
-        form.value.deptIds = getDeptAllCheckedKeys();
-        await dataScope(form.value);
-        proxy?.$modal.msgSuccess("修改成功");
-        openDataScope.value = false;
-        getList();
-    }
+  if (form.value.roleId) {
+    form.value.deptIds = getDeptAllCheckedKeys();
+    await dataScope(form.value);
+    proxy?.$modal.msgSuccess("修改成功");
+    openDataScope.value = false;
+    getList();
+  }
 }
 /** 取消按钮(数据权限)*/
 const cancelDataScope = () => {
-    dataScopeRef.value.resetFields();
-    form.value = {...initForm};
-    openDataScope.value = false;
+  dataScopeRef.value?.resetFields();
+  form.value = { ...initForm };
+  openDataScope.value = false;
 }
 
 onMounted(() => {
-    getList();
+  getList();
 });
 </script>

+ 34 - 35
src/views/system/role/selectUser.vue

@@ -47,14 +47,12 @@
 import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
 import { UserVO } from '@/api/system/user/types';
 import { UserQuery } from '@/api/system/user/types';
-import { ComponentInternalInstance } from 'vue';
-import { ElForm, ElTable } from 'element-plus';
 
 
 const props = defineProps({
-    roleId: {
-        type: [Number, String]
-    }
+  roleId: {
+    type: [Number, String]
+  }
 })
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -66,67 +64,68 @@ const total = ref(0);
 const userIds = ref<Array<string | number>>([]);
 
 const queryParams = reactive<UserQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    roleId: undefined,
-    userName: undefined,
-    phonenumber: undefined
+  pageNum: 1,
+  pageSize: 10,
+  roleId: undefined,
+  userName: undefined,
+  phonenumber: undefined
 })
 
-const tableRef = ref(ElTable);
-const queryFormRef = ref(ElForm);
+const tableRef = ref<ElTableInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 const show = () => {
-    queryParams.roleId = props.roleId;
-    getList();
-    visible.value = true;
+  queryParams.roleId = props.roleId;
+  getList();
+  visible.value = true;
 }
 
 /**
  * 选择行
  */
 const clickRow = (row: any) => {
-    tableRef.value.toggleRowSelection(row);
+  // ele的bug
+  tableRef.value?.toggleRowSelection(row);
 }
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: UserVO[]) => {
-    userIds.value = selection.map((item: UserVO) => item.userId);
+  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 res = await unallocatedUserList(queryParams);
+  userList.value = res.rows;
+  total.value = res.total;
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.pageNum = 1;
-    getList();
+  queryParams.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    getList();
+  queryFormRef.value?.resetFields();
+  getList();
 }
 
 const emit = defineEmits(["ok"]);
 /**选择授权用户操作 */
 const handleSelectUser = async () => {
-    const roleId = queryParams.roleId;
-    const ids = userIds.value.join(',');
-    if (ids == "") {
-        proxy?.$modal.msgError('请选择要分配的用户');
-        return;
-    }
-    await authUserSelectAll({ roleId, userIds: ids });
-    proxy?.$modal.msgSuccess('分配成功');
-    emit('ok');
-    visible.value = false;
+  const roleId = queryParams.roleId;
+  const ids = userIds.value.join(',');
+  if (ids == "") {
+    proxy?.$modal.msgError('请选择要分配的用户');
+    return;
+  }
+  await authUserSelectAll({ roleId, userIds: ids });
+  proxy?.$modal.msgSuccess('分配成功');
+  emit('ok');
+  visible.value = false;
 }
 // 暴露
 defineExpose({
-    show,
+  show,
 });
 </script>
 

+ 142 - 142
src/views/system/tenant/index.vue

@@ -1,29 +1,31 @@
 <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="68px">
-          <el-form-item label="租户编号" prop="tenantId">
-            <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="联系人" prop="contactUserName">
-            <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="联系电话" prop="contactPhone">
-            <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="企业名称" prop="companyName">
-            <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+            <el-form-item label="租户编号" prop="tenantId">
+              <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="联系人" prop="contactUserName">
+              <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="联系电话" prop="contactPhone">
+              <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="企业名称" prop="companyName">
+              <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -80,7 +82,7 @@
         </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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改租户对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@@ -143,8 +145,6 @@ import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenant
 import { selectTenantPackage } from '@/api/system/tenantPackage';
 import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
 import { TenantPkgVO } from '@/api/system/tenantPackage/types';
-import { ComponentInternalInstance } from 'vue';
-import { ElForm } from 'element-plus';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -158,196 +158,196 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
-const queryFormRef = ref(ElForm);
-const tenantFormRef = ref(ElForm);
+const queryFormRef = ref<ElFormInstance>();
+const tenantFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 const initFormData: TenantForm = {
-    id: undefined,
-    tenantId: undefined,
-    contactUserName: '',
-    contactPhone: '',
-    username: '',
-    password: '',
-    companyName: '',
-    licenseNumber: '',
-    domain: '',
-    address: '',
-    intro: '',
-    remark: '',
-    packageId: '',
-    expireTime: '',
-    accountCount: 0,
-    status: '0',
+  id: undefined,
+  tenantId: undefined,
+  contactUserName: '',
+  contactPhone: '',
+  username: '',
+  password: '',
+  companyName: '',
+  licenseNumber: '',
+  domain: '',
+  address: '',
+  intro: '',
+  remark: '',
+  packageId: '',
+  expireTime: '',
+  accountCount: 0,
+  status: '0',
 }
 const data = reactive<PageData<TenantForm, TenantQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        tenantId: '',
-        contactUserName: '',
-        contactPhone: '',
-        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" }],
-        username: [
-            { required: true, message: "用户名不能为空", trigger: "blur" },
-            { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
-        ],
-        password: [
-            { required: true, message: "密码不能为空", trigger: "blur" },
-            { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
-        ]
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    tenantId: '',
+    contactUserName: '',
+    contactPhone: '',
+    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" }],
+    username: [
+      { required: true, message: "用户名不能为空", trigger: "blur" },
+      { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
+    ],
+    password: [
+      { required: true, message: "密码不能为空", trigger: "blur" },
+      { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
+    ]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询所有租户套餐 */
 const getTenantPackage = async () => {
-    const res = await selectTenantPackage()
-    packageList.value = res.data;
+  const res = await selectTenantPackage()
+  packageList.value = res.data;
 }
 
 /** 查询租户列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listTenant(queryParams.value);
-    tenantList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listTenant(queryParams.value);
+  tenantList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 
 // 租户套餐状态修改
 const handleStatusChange = async (row: TenantVO) => {
-    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 + "成功");
-    } catch {
-        row.status = row.status === "0" ? "1" : "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 + "成功");
+  } catch {
+    row.status = row.status === "0" ? "1" : "0";
+  }
 
 
 }
 
 // 取消按钮
 const cancel = () => {
-    reset();
-    dialog.visible = false;
+  reset();
+  dialog.visible = false;
 }
 
 // 表单重置
 const reset = () => {
-    form.value = {...initFormData};
-    tenantFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  tenantFormRef.value?.resetFields();
 }
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 
 // 多选框选中数据
 const handleSelectionChange = (selection: TenantVO[]) => {
-    ids.value = selection.map(item => item.id);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加租户";
-    nextTick(() => {
-        reset();
-        getTenantPackage();
-    })
+  dialog.visible = true;
+  dialog.title = "添加租户";
+  nextTick(() => {
+    reset();
+    getTenantPackage();
+  })
 }
 
 /** 修改按钮操作 */
 const handleUpdate = (row?: TenantVO) => {
-    loading.value = true;
-    dialog.visible = true;
-    dialog.title = "修改租户";
-    nextTick(async () => {
-        reset();
-        getTenantPackage();
-        const _id = row?.id || ids.value[0];
-        const res = await getTenant(_id);
-        loading.value = false;
-        Object.assign(form.value, res.data)
-    })
+  loading.value = true;
+  dialog.visible = true;
+  dialog.title = "修改租户";
+  nextTick(async () => {
+    reset();
+    await getTenantPackage();
+    const _id = row?.id || ids.value[0];
+    const res = await getTenant(_id);
+    loading.value = false;
+    Object.assign(form.value, res.data)
+  })
 }
 
 /** 提交按钮 */
 const submitForm = () => {
-    tenantFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            buttonLoading.value = true;
-            if (form.value.id) {
-                await updateTenant(form.value).finally(() => buttonLoading.value = false);
-            } else {
-                await addTenant(form.value).finally(() => buttonLoading.value = false);
-            }
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
+  tenantFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateTenant(form.value).finally(() => buttonLoading.value = false);
+      } else {
+        await addTenant(form.value).finally(() => buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      getList();
+    }
+  });
 }
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantVO) => {
-    const _ids = row?.id || ids.value;
-    await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
-    loading.value = true;
-    await delTenant(_ids).finally(() => loading.value = false);
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
+  loading.value = true;
+  await delTenant(_ids).finally(() => loading.value = false);
+  await getList();
+  proxy?.$modal.msgSuccess("删除成功");
 
 
 }
 
 /** 同步租户套餐按钮操作 */
 const handleSyncTenantPackage = async (row: TenantVO) => {
-    try {
-        await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
-        loading.value = true;
-        await syncTenantPackage(row.tenantId, row.packageId);
-        getList();
-        proxy?.$modal.msgSuccess("同步成功");
-    } catch {return} finally {
-        loading.value = false;
-    }
+  try {
+    await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
+    loading.value = true;
+    await syncTenantPackage(row.tenantId, row.packageId);
+    await getList();
+    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();
+  getList();
 })
 </script>

+ 179 - 168
src/views/system/tenantPackage/index.vue

@@ -1,37 +1,39 @@
 <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="68px">
-          <el-form-item label="套餐名称" prop="packageName">
-            <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+            <el-form-item label="套餐名称" prop="packageName">
+              <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <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 type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']"> 新增 </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
-            >
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']">
+              修改
+            </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
-            >
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']">
+              删除
+            </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 type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出 </el-button>
           </el-col>
           <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
         </el-row>
@@ -53,13 +55,13 @@
               <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenantPackage:edit']"></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 link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:tenantPackage:remove']"></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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
 
     <!-- 添加或修改租户套餐对话框 -->
@@ -70,8 +72,8 @@
         </el-form-item>
         <el-form-item label="关联菜单">
           <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
-          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
-          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
+          <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
             class="tree-border"
             :data="menuOptions"
@@ -98,12 +100,17 @@
 </template>
 
 <script setup name="TenantPackage" lang="ts">
-import { listTenantPackage, getTenantPackage, delTenantPackage, addTenantPackage, updateTenantPackage, changePackageStatus } from "@/api/system/tenantPackage";
+import {
+  listTenantPackage,
+  getTenantPackage,
+  delTenantPackage,
+  addTenantPackage,
+  updateTenantPackage,
+  changePackageStatus
+} from "@/api/system/tenantPackage";
 import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
-import { ComponentInternalInstance } from "vue";
 import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
 import { MenuTreeOption } from "@/api/system/menu/types";
-import { CheckboxValueType, ElTree, ElForm } from 'element-plus';
 import to from "await-to-js";
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -120,212 +127,216 @@ const menuExpand = ref(false);
 const menuNodeAll = ref(false);
 const menuOptions = ref<MenuTreeOption[]>([]);
 
-const menuTreeRef = ref(ElTree);
-const queryFormRef = ref(ElForm);
-const tenantPackageFormRef = ref(ElForm);
+const menuTreeRef = ref<ElTreeInstance>();
+const queryFormRef = ref<ElFormInstance>();
+const tenantPackageFormRef = ref<ElFormInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ""
 });
 
 
 const initFormData: TenantPkgForm = {
-    packageId: undefined,
-    packageName: '',
-    menuIds: '',
-    remark: '',
-    menuCheckStrictly: true
+  packageId: undefined,
+  packageName: "",
+  menuIds: "",
+  remark: "",
+  menuCheckStrictly: true
 };
 const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
-    form: {...initFormData},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        packageName: ''
-    },
-    rules: {
-        packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
-        packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    packageName: ""
+  },
+  rules: {
+    packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
+    packageName: [{ required: true, message: "套餐名称不能为空", trigger: "blur" }]
+  }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
 /** 查询菜单树结构 */
-const getMenuTreeselect = async() => {
-    const { data } = await menuTreeselect();
-    menuOptions.value = data;
-}
+const getMenuTreeselect = async () => {
+  const { data } = await menuTreeselect();
+  menuOptions.value = data;
+};
 
 // 所有菜单节点数据
-const getMenuAllCheckedKeys = () => {
-    // 目前被选中的菜单节点
-    let checkedKeys = menuTreeRef.value.getCheckedKeys();
-    // 半选中的菜单节点
-    let halfCheckedKeys = menuTreeRef.value.getHalfCheckedKeys();
-    checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
-    return checkedKeys;
-}
+const getMenuAllCheckedKeys = (): any => {
+  // 目前被选中的菜单节点
+  let checkedKeys = menuTreeRef.value?.getCheckedKeys();
+  // 半选中的菜单节点
+  let halfCheckedKeys = menuTreeRef.value?.getHalfCheckedKeys();
+  if (halfCheckedKeys) {
+    checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
+  }
+  return checkedKeys;
+};
 
 /** 根据租户套餐ID查询菜单树结构 */
-const getPackageMenuTreeselect = async(packageId: string | number) => {
-    const res = await tenantPackageMenuTreeselect(packageId);
-    menuOptions.value = res.data.menus;
-    return Promise.resolve(res);
-}
+const getPackageMenuTreeselect = async (packageId: string | number) => {
+  const res = await tenantPackageMenuTreeselect(packageId);
+  menuOptions.value = res.data.menus;
+  return Promise.resolve(res);
+};
 
 /** 查询租户套餐列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listTenantPackage(queryParams.value);
-    tenantPackageList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
-}
+  loading.value = true;
+  const res = await listTenantPackage(queryParams.value);
+  tenantPackageList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
 
 // 租户套餐状态修改
 const handleStatusChange = async (row: TenantPkgVO) => {
-    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";
-    } else {
-        await changePackageStatus(row.packageId, row.status);
-        proxy?.$modal.msgSuccess(text + "成功");
-    }
-}
+  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";
+  } else {
+    await changePackageStatus(row.packageId, row.status);
+    proxy?.$modal.msgSuccess(text + "成功");
+  }
+};
 
 // 取消按钮
 const cancel = () => {
-    reset();
-    dialog.visible = false;
-}
+  reset();
+  dialog.visible = false;
+};
 
 // 表单重置
 const reset = () => {
-    menuTreeRef.value.setCheckedKeys([]);
-    menuExpand.value = false;
-    menuNodeAll.value = false;
-    form.value = {...initFormData};
-    tenantPackageFormRef.value.resetFields();
-}
+  menuTreeRef.value?.setCheckedKeys([]);
+  menuExpand.value = false;
+  menuNodeAll.value = false;
+  form.value = { ...initFormData };
+  tenantPackageFormRef.value?.resetFields();
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
-}
+  queryParams.value.pageNum = 1;
+  getList();
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
-}
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
 
 // 多选框选中数据
 const handleSelectionChange = (selection: TenantPkgVO[]) => {
-    ids.value = selection.map(item => item.packageId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
-}
+  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') {
-        let treeList = menuOptions.value;
-        for (let i = 0; i < treeList.length; i++) {
-            menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value;
-        }
+  if (type == "menu") {
+    let treeList = menuOptions.value;
+    for (let i = 0; i < treeList.length; i++) {
+      if (menuTreeRef.value) {
+        menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value as boolean;
+      }
     }
-}
+  }
+};
 
 // 树权限(全选/全不选)
 const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
-    if (type == 'menu') {
-        menuTreeRef.value.setCheckedNodes(value ? menuOptions.value: []);
-    }
-}
+  if (type == "menu") {
+    menuTreeRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
+  }
+};
 
 // 树权限(父子联动)
 const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
-    if (type == 'menu') {
-        form.value.menuCheckStrictly = value as boolean;
-    }
-}
+  if (type == "menu") {
+    form.value.menuCheckStrictly = value as boolean;
+  }
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "添加租户套餐";
-    nextTick(() => {
-        reset();
-        getMenuTreeselect();
-    })
-}
+  dialog.visible = true;
+  dialog.title = "添加租户套餐";
+  nextTick(() => {
+    reset();
+    getMenuTreeselect();
+  });
+};
 
 /** 修改按钮操作 */
 const handleUpdate = (row?: TenantPkgVO) => {
-    loading.value = true
-    dialog.visible = true;
-    dialog.title = "修改租户套餐";
-    nextTick(async () => {
-        reset();
-        const _packageId = row?.packageId || ids.value[0];
-        const packageMenu = getPackageMenuTreeselect(_packageId);
-        const response = await getTenantPackage(_packageId);
-        loading.value = false;
-        form.value = response.data;
-        nextTick(async () => {
-            const res = await packageMenu;
-            let checkedKeys = res.data.checkedKeys
-            checkedKeys.forEach((v) => {
-                nextTick(() => {
-                    menuTreeRef.value.setChecked(v, true ,false);
-                })
-            })
+  loading.value = true;
+  dialog.visible = true;
+  dialog.title = "修改租户套餐";
+  nextTick(async () => {
+    reset();
+    const _packageId = row?.packageId || ids.value[0];
+    const packageMenu = getPackageMenuTreeselect(_packageId);
+    const response = await getTenantPackage(_packageId);
+    loading.value = false;
+    form.value = response.data;
+    await nextTick(async () => {
+      const res = await packageMenu;
+      let checkedKeys = res.data.checkedKeys;
+      checkedKeys.forEach((v) => {
+        nextTick(() => {
+          menuTreeRef.value?.setChecked(v, true, false);
         });
-    })
-}
+      });
+    });
+  });
+};
 
 /** 提交按钮 */
 const submitForm = () => {
-    tenantPackageFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            buttonLoading.value = true;
-            form.value.menuIds = getMenuAllCheckedKeys();
-            if (form.value.packageId != null) {
-                await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
-            } else {
-                await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
-            }
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            getList();
-        }
-    });
-}
+  tenantPackageFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      form.value.menuIds = getMenuAllCheckedKeys();
+      if (form.value.packageId != null) {
+        await updateTenantPackage(form.value).finally(() => buttonLoading.value = false);
+      } else {
+        await addTenantPackage(form.value).finally(() => buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantPkgVO) => {
-    const _packageIds = row?.packageId || ids.value;
-    await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
-        loading.value = false;
-    });
-    await delTenantPackage(_packageIds);
-    loading.value = true;
-    getList();
-    proxy?.$modal.msgSuccess("删除成功");
-}
+  const _packageIds = row?.packageId || ids.value;
+  await proxy?.$modal.confirm("是否确认删除租户套餐编号为\"" + _packageIds + "\"的数据项?").finally(() => {
+    loading.value = false;
+  });
+  await delTenantPackage(_packageIds);
+  loading.value = true;
+  await getList();
+  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(() => {
-    getList();
-})
+  getList();
+});
 </script>

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

@@ -55,11 +55,10 @@
 </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 { ElTable } from "element-plus";
-import { ComponentInternalInstance } from 'vue';
+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,58 +69,59 @@ const pageSize = ref(10);
 const roleIds = ref<Array<string | number>>([]);
 const roles = ref<RoleVO[]>([]);
 const form = ref<Partial<UserForm>>({
-    nickName: undefined,
-    userName: '',
-    userId: undefined
+  nickName: undefined,
+  userName: "",
+  userId: undefined
 });
 
-const tableRef = ref(ElTable)
+const tableRef = ref<ElTableInstance>();
 
 /** 单击选中行数据 */
 const clickRow = (row: RoleVO) => {
-    tableRef.value.toggleRowSelection(row);
+  // ele的方法有问题,selected应该为可选参数
+  tableRef.value?.toggleRowSelection(row);
 };
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: RoleVO[]) => {
-    roleIds.value = selection.map(item => item.roleId);
+  roleIds.value = selection.map(item => item.roleId);
 };
 /** 保存选中的数据编号 */
 const getRowKey = (row: RoleVO): string => {
-    return String(row.roleId);
+  return String(row.roleId);
 };
 /** 关闭按钮 */
 const close = () => {
-    const obj = { path: "/system/user" };
-    proxy?.$tab.closeOpenPage(obj);
+  const obj = { path: "/system/user" };
+  proxy?.$tab.closeOpenPage(obj);
 };
 /** 提交按钮 */
 const submitForm = async () => {
-    const userId = form.value.userId;
-    const rIds = roleIds.value.join(",");
-    await updateAuthRole({ userId: userId as string, roleIds: rIds })
-    proxy?.$modal.msgSuccess("授权成功");
-    close();
+  const userId = form.value.userId;
+  const rIds = roleIds.value.join(",");
+  await updateAuthRole({ userId: userId as string, roleIds: rIds });
+  proxy?.$modal.msgSuccess("授权成功");
+  close();
 };
 
-const getList = async() => {
-    const userId = route.params && route.params.userId;
-    if (userId) {
-        loading.value = true;
-        const res = await getAuthRole(userId as string);
-        Object.assign(form.value, res.data.user)
-        Object.assign(roles.value, res.data.roles)
-        total.value = roles.value.length;
-        await nextTick(() => {
-            roles.value.forEach(row => {
-                if (row?.flag) {
-                    tableRef.value.toggleRowSelection(row);
-                }
-            });
-        });
-        loading.value = false;
-    }
-}
+const getList = async () => {
+  const userId = route.params && route.params.userId;
+  if (userId) {
+    loading.value = true;
+    const res = await getAuthRole(userId as string);
+    Object.assign(form.value, res.data.user);
+    Object.assign(roles.value, res.data.roles);
+    total.value = roles.value.length;
+    await nextTick(() => {
+      roles.value.forEach(row => {
+        if (row?.flag) {
+          tableRef.value?.toggleRowSelection(row, true);
+        }
+      });
+    });
+    loading.value = false;
+  }
+};
 onMounted(() => {
-    getList();
-})
+  getList();
+});
 </script>

+ 212 - 215
src/views/system/user/index.vue

@@ -16,40 +16,48 @@
             highlight-current
             default-expand-all
             @node-click="handleNodeClick"
-          ></el-tree>
+          />
         </el-card>
       </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="search" v-show="showSearch">
-            <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
-              <el-form-item label="用户名称" prop="userName">
-                <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
-              </el-form-item>
-              <el-form-item label="手机号码" prop="phonenumber">
-                <el-input v-model="queryParams.phonenumber" 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">
-                  <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-date-picker
-                  v-model="dateRange"
-                  value-format="YYYY-MM-DD"
-                  type="daterange"
-                  range-separator="-"
-                  start-placeholder="开始日期"
-                  end-placeholder="结束日期"
-                ></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-form-item>
-            </el-form>
+          <div class="mb-[10px]" v-show="showSearch">
+            <el-card shadow="hover">
+              <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
+                <el-form-item label="用户名称" prop="userName">
+                  <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
+                </el-form-item>
+                <el-form-item label="手机号码" prop="phonenumber">
+                  <el-input
+                    v-model="queryParams.phonenumber"
+                    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">
+                    <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-date-picker
+                    v-model="dateRange"
+                    value-format="YYYY-MM-DD"
+                    type="daterange"
+                    range-separator="-"
+                    start-placeholder="开始日期"
+                    end-placeholder="结束日期"
+                  ></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-form-item>
+              </el-form>
+            </el-card>
           </div>
         </transition>
 
@@ -203,7 +211,7 @@
             <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>
+                  dict.label }}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -289,30 +297,19 @@
 </template>
 
 <script setup name="User" lang="ts">
-import {
-    changeUserStatus,
-    listUser,
-    resetUserPwd,
-    delUser,
-    getUser,
-    updateUser,
-    addUser,
-    deptTreeSelect
-} from "@/api/system/user"
+import api from "@/api/system/user"
 import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
-import { ComponentInternalInstance } from "vue";
 import { getToken } from "@/utils/auth";
 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 { DateModelType, ElTree, ElUpload, UploadFile, ElForm } from 'element-plus';
 import { to } from "await-to-js";
+
 const router = useRouter();
 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)
@@ -320,7 +317,7 @@ const ids = ref<Array<number | string>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
-const dateRange = ref<[DateModelType, DateModelType]>(['','']);
+const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const deptName = ref('');
 const deptOptions = ref<DeptVO[]>([]);
 const initPassword = ref('123456');
@@ -328,274 +325,274 @@ const postOptions = ref<PostVO[]>([]);
 const roleOptions = ref<RoleVO[]>([]);
 /*** 用户导入参数 */
 const upload = reactive<ImportOption>({
-    // 是否显示弹出层(用户导入)
-    open: false,
-    // 弹出层标题(用户导入)
-    title: "",
-    // 是否禁用上传
-    isUploading: false,
-    // 是否更新已经存在的用户数据
-    updateSupport: 0,
-    // 设置上传的请求头部
-    headers: { Authorization: "Bearer " + getToken() },
-    // 上传的地址
-    url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
+  // 是否显示弹出层(用户导入)
+  open: false,
+  // 弹出层标题(用户导入)
+  title: "",
+  // 是否禁用上传
+  isUploading: false,
+  // 是否更新已经存在的用户数据
+  updateSupport: 0,
+  // 设置上传的请求头部
+  headers: { Authorization: "Bearer " + getToken() },
+  // 上传的地址
+  url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
 })
 // 列显隐信息
 const columns = ref<FieldOption[]>([
-    { key: 0, label: `用户编号`, visible: false },
-    { key: 1, label: `用户名称`, visible: true },
-    { key: 2, label: `用户昵称`, visible: true },
-    { key: 3, label: `部门`, visible: true },
-    { key: 4, label: `手机号码`, visible: true },
-    { key: 5, label: `状态`, visible: true },
-    { key: 6, label: `创建时间`, visible: true }
+  { key: 0, label: `用户编号`, visible: false },
+  { key: 1, label: `用户名称`, visible: true },
+  { key: 2, label: `用户昵称`, visible: true },
+  { key: 3, label: `部门`, visible: true },
+  { key: 4, label: `手机号码`, visible: true },
+  { key: 5, label: `状态`, visible: true },
+  { key: 6, label: `创建时间`, visible: true }
 ])
 
 
-const deptTreeRef = ref(ElTree);
-const queryFormRef = ref(ElForm);
-const userFormRef = ref(ElForm);
-const uploadRef = ref(ElUpload);
+const deptTreeRef = ref<ElTreeInstance>();
+const queryFormRef = ref<ElFormInstance>();
+const userFormRef = ref<ElFormInstance>();
+const uploadRef = ref<ElUploadInstance>();
 
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: ''
+  visible: false,
+  title: ''
 });
 
 const initFormData: UserForm = {
-    userId: undefined,
-    deptId: undefined,
-    userName: '',
-    nickName: undefined,
-    password: '',
-    phonenumber: undefined,
-    email: undefined,
-    sex: undefined,
-    status: "0",
-    remark: '',
-    postIds: [],
-    roleIds: []
+  userId: undefined,
+  deptId: undefined,
+  userName: '',
+  nickName: undefined,
+  password: '',
+  phonenumber: undefined,
+  email: undefined,
+  sex: undefined,
+  status: "0",
+  remark: '',
+  postIds: [],
+  roleIds: []
 }
 const data = reactive<PageData<UserForm, UserQuery>>({
-    form: { ...initFormData },
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        userName: '',
-        phonenumber: '',
-        status: '',
-        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" }]
-    }
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    userName: '',
+    phonenumber: '',
+    status: '',
+    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" }]
+  }
 })
 
 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);},
-    {
-        flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
-    }
+  () => { deptTreeRef.value?.filter(deptName.value); },
+  {
+    flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
+  }
 );
 
 /** 查询部门下拉树结构 */
 const getTreeSelect = async () => {
-    const res = await deptTreeSelect();
-    deptOptions.value = res.data;
+  const res = await api.deptTreeSelect();
+  deptOptions.value = res.data;
 };
 
 /** 查询用户列表 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
-    loading.value = false;
-    userList.value = res.rows;
-    total.value = res.total;
+  loading.value = true;
+  const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
+  loading.value = false;
+  userList.value = res.rows;
+  total.value = res.total;
 }
 
 /** 节点单击事件 */
 const handleNodeClick = (data: DeptVO) => {
-    queryParams.value.deptId = data.id;
-    handleQuery()
+  queryParams.value.deptId = data.id;
+  handleQuery()
 }
 
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1
-    getList()
+  queryParams.value.pageNum = 1
+  getList()
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    dateRange.value = ['','']
-    queryFormRef.value.resetFields();
-    queryParams.value.pageNum = 1;
-    queryParams.value.deptId = undefined;
-    deptTreeRef.value.setCurrentKey(null);
-    handleQuery();
+  dateRange.value = ['', '']
+  queryFormRef.value?.resetFields();
+  queryParams.value.pageNum = 1;
+  queryParams.value.deptId = undefined;
+  deptTreeRef.value?.setCurrentKey(undefined);
+  handleQuery();
 }
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: UserVO) => {
-    const userIds = row?.userId || ids.value;
-    const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
-    if (!err) {
-        await delUser(userIds);
-        await getList();
-        proxy?.$modal.msgSuccess("删除成功");
-    }
+  const userIds = row?.userId || ids.value;
+  const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
+  if (!err) {
+    await api.delUser(userIds);
+    await getList();
+    proxy?.$modal.msgSuccess("删除成功");
+  }
 }
 
 /** 用户状态修改  */
 const handleStatusChange = async (row: UserVO) => {
-    let text = row.status === "0" ? "启用" : "停用"
-    try {
-        await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
-        await changeUserStatus(row.userId, row.status);
-        proxy?.$modal.msgSuccess(text + "成功");
-    } catch (err) {
-        row.status = row.status === "0" ? "1" : "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 + "成功");
+  } catch (err) {
+    row.status = row.status === "0" ? "1" : "0";
+  }
 }
 /** 跳转角色分配 */
 const handleAuthRole = (row: UserVO) => {
-    const userId = row.userId;
-    router.push("/system/user-auth/role/" + userId);
+  const userId = row.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 之间",
-    }))
-    if (!err) {
-        await resetUserPwd(row.userId, res.value);
-        proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
-    }
+  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);
+  }
 }
 
 /** 选择条数  */
 const handleSelectionChange = (selection: UserVO[]) => {
-    ids.value = selection.map((item) => item.userId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  ids.value = selection.map((item) => item.userId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
 }
 
 /** 导入按钮操作 */
 const handleImport = () => {
-    upload.title = "用户导入";
-    upload.open = true;
+  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;
+  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 });
-    getList();
+  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 });
+  getList();
 }
 
 /** 提交上传文件 */
 function submitFileForm() {
-    uploadRef.value.submit();
+  uploadRef.value?.submit();
 }
 
 /** 初始化部门数据 */
 const initTreeData = async () => {
-    // 判断部门的数据是否存在,存在不获取,不存在则获取
-    if (deptOptions.value === undefined) {
-        const { data } = await treeselect();
-        deptOptions.value = data;
-    }
+  // 判断部门的数据是否存在,存在不获取,不存在则获取
+  if (deptOptions.value === undefined) {
+    const { data } = await treeselect();
+    deptOptions.value = data;
+  }
 }
 
 
 /** 重置操作表单 */
 const reset = () => {
-    form.value = { ...initFormData };
-    userFormRef.value.resetFields();
+  form.value = { ...initFormData };
+  userFormRef.value?.resetFields();
 }
 /** 取消按钮 */
 const cancel = () => {
-    reset();
-    dialog.visible = false;
+  reset();
+  dialog.visible = false;
 }
 
 /** 新增按钮操作 */
 const handleAdd = () => {
-    dialog.visible = true;
-    dialog.title = "新增用户";
-    nextTick(async () => {
-        reset();
-        await initTreeData();
-        const { data } = await getUser();
-        postOptions.value = data.posts;
-        roleOptions.value = data.roles;
-        form.value.password = initPassword.value;
-    })
+  dialog.visible = true;
+  dialog.title = "新增用户";
+  nextTick(async () => {
+    reset();
+    await initTreeData();
+    const { data } = await api.getUser();
+    postOptions.value = data.posts;
+    roleOptions.value = data.roles;
+    form.value.password = initPassword.value;
+  })
 }
 /** 修改按钮操作 */
 const handleUpdate = (row?: UserForm) => {
-    dialog.visible = true;
-    dialog.title = "修改用户";
-    nextTick(async () => {
-        reset();
-        await initTreeData();
-        const userId = row?.userId || ids.value[0]
-        const { data } = await getUser(userId)
-        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 = "";
-    })
+  dialog.visible = true;
+  dialog.title = "修改用户";
+  nextTick(async () => {
+    reset();
+    await initTreeData();
+    const userId = row?.userId || ids.value[0]
+    const { data } = await api.getUser(userId)
+    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 = "";
+  })
 
 }
 
 /** 提交按钮 */
 const submitForm = () => {
-    userFormRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            form.value.userId ? await updateUser(form.value) : await addUser(form.value);
-            proxy?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            await getList();
-        }
-    })
+  userFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  })
 }
 
 
@@ -603,23 +600,23 @@ const submitForm = () => {
  * 关闭用户弹窗
  */
 const closeDialog = () => {
-    dialog.visible = false;
-    resetForm();
+  dialog.visible = false;
+  resetForm();
 }
 
 /**
  * 重置表单
  */
 const resetForm = () => {
-    userFormRef.value.resetFields();
-    userFormRef.value.clearValidate();
+  userFormRef.value?.resetFields();
+  userFormRef.value?.clearValidate();
 
-    form.value.id = undefined;
-    form.value.status = '1';
+  form.value.id = undefined;
+  form.value.status = '1';
 }
 onMounted(() => {
-    getTreeSelect() // 初始化部门数据
-    getList() // 初始化列表数据
+  getTreeSelect() // 初始化部门数据
+  getList() // 初始化列表数据
 });
 </script>
 

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

@@ -74,11 +74,11 @@ import { getAuthList } from "@/api/system/social/auth";
 import { getUserProfile } from "@/api/system/user";
 
 const activeTab = ref("userinfo");
-const state = ref<{ user: any; roleGroup: string;  postGroup: string; auths:any[]}>({
+const state = ref<Record<string, any>>({
     user: {},
     roleGroup: '',
     postGroup: '',
-    auths: [],
+    auths: []
 });
 
 const userForm = ref({});

+ 30 - 26
src/views/system/user/profile/resetPwd.vue

@@ -17,46 +17,50 @@
 </template>
 
 <script setup lang="ts">
-import { updateUserPwd } from '@/api/system/user';
-import { ComponentInternalInstance } from 'vue';
-import { ResetPwdForm } from '@/api/system/user/types'
-import { ElForm } from 'element-plus';
+import { updateUserPwd } from "@/api/system/user";
+import type { ResetPwdForm } from "@/api/system/user/types";
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-
-
-const pwdRef = ref(ElForm);
-
+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("两次输入的密码不一致"));
-    } else {
-        callback();
-    }
+  if (user.value.newPassword !== value) {
+    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"
+  }]
 });
 
 /** 提交按钮 */
 const submit = () => {
-    pwdRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            await updateUserPwd(user.value.oldPassword, user.value.newPassword)
-            proxy?.$modal.msgSuccess("修改成功");
-        }
-    });
+  pwdRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      await updateUserPwd(user.value.oldPassword, user.value.newPassword);
+      proxy?.$modal.msgSuccess("修改成功");
+    }
+  });
 };
 /** 关闭按钮 */
 const close = () => {
-    proxy?.$tab.closePage();
+  proxy?.$tab.closePage();
 };
 </script>

+ 61 - 59
src/views/system/user/profile/userAvatar.vue

@@ -29,7 +29,9 @@
           <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
             <el-button>
               选择
-              <el-icon class="el-icon--right"><Upload /></el-icon>
+              <el-icon class="el-icon--right">
+                <Upload />
+              </el-icon>
             </el-button>
           </el-upload>
         </el-col>
@@ -58,18 +60,17 @@ import "vue-cropper/dist/index.css";
 import { VueCropper } from "vue-cropper";
 import { uploadAvatar } from "@/api/system/user";
 import useUserStore from "@/store/modules/user";
-import { ComponentInternalInstance } from "vue";
 
 interface Options {
-    img: string | ArrayBuffer | null // 裁剪图片的地址
-    autoCrop: boolean // 是否默认生成截图框
-    autoCropWidth: number // 默认生成截图框宽度
-    autoCropHeight: number // 默认生成截图框高度
-    fixedBox: boolean // 固定截图框大小 不允许改变
-    fileName: string
-    previews: any // 预览数据
-    outputType: string
-    visible: boolean
+  img: string | ArrayBuffer | null; // 裁剪图片的地址
+  autoCrop: boolean; // 是否默认生成截图框
+  autoCropWidth: number; // 默认生成截图框宽度
+  autoCropHeight: number; // 默认生成截图框高度
+  fixedBox: boolean; // 固定截图框大小 不允许改变
+  fileName: string;
+  previews: any; // 预览数据
+  outputType: string;
+  visible: boolean;
 }
 
 
@@ -83,75 +84,76 @@ const title = ref("修改头像");
 const cropper = ref<any>({});
 //图片裁剪数据
 const options = reactive<Options>({
-    img: userStore.avatar,
-    autoCrop: true,
-    autoCropWidth: 200,
-    autoCropHeight: 200,
-    fixedBox: true,
-    outputType: "png",
-    fileName: '',
-    previews: {},
-    visible: false
+  img: userStore.avatar,
+  autoCrop: true,
+  autoCropWidth: 200,
+  autoCropHeight: 200,
+  fixedBox: true,
+  outputType: "png",
+  fileName: "",
+  previews: {},
+  visible: false
 });
 
 /** 编辑头像 */
 const editCropper = () => {
-    open.value = true;
-}
+  open.value = true;
+};
 /** 打开弹出层结束时的回调 */
 const modalOpened = () => {
-    visible.value = true;
-}
+  visible.value = true;
+};
 /** 覆盖默认上传行为 */
-const requestUpload = (): any => {}
+const requestUpload = (): any => {
+};
 /** 向左旋转 */
 const rotateLeft = () => {
-    cropper.value.rotateLeft();
-}
+  cropper.value.rotateLeft();
+};
 /** 向右旋转 */
 const rotateRight = () => {
-    cropper.value.rotateRight();
-}
+  cropper.value.rotateRight();
+};
 /** 图片缩放 */
 const changeScale = (num: number) => {
-    num = num || 1;
-    cropper.value.changeScale(num);
-}
+  num = num || 1;
+  cropper.value.changeScale(num);
+};
 /** 上传预处理 */
 const beforeUpload = (file: any) => {
-    if (file.type.indexOf("image/") == -1) {
-        proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
-    } else {
-        const reader = new FileReader();
-        reader.readAsDataURL(file);
-        reader.onload = () => {
-            options.img = reader.result;
-            options.fileName = file.name;
-        };
-    }
-}
+  if (file.type.indexOf("image/") == -1) {
+    proxy?.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
+  } else {
+    const reader = new FileReader();
+    reader.readAsDataURL(file);
+    reader.onload = () => {
+      options.img = reader.result;
+      options.fileName = file.name;
+    };
+  }
+};
 /** 上传图片 */
 const uploadImg = async () => {
-    cropper.value.getCropBlob(async (data: any) => {
-        let formData = new FormData();
-        formData.append("avatarfile", data, options.fileName);
-        const res = await uploadAvatar(formData);
-        open.value = false;
-        options.img = res.data.imgUrl;
-        userStore.avatar = options.img as string;
-        proxy?.$modal.msgSuccess("修改成功");
-        visible.value = false;
-    });
-}
+  cropper.value.getCropBlob(async (data: any) => {
+    let formData = new FormData();
+    formData.append("avatarfile", data, options.fileName);
+    const res = await uploadAvatar(formData);
+    open.value = false;
+    options.img = res.data.imgUrl;
+    userStore.avatar = options.img as string
+    proxy?.$modal.msgSuccess("修改成功");
+    visible.value = false;
+  });
+};
 /** 实时预览 */
 const realTime = (data: any) => {
-    options.previews = data;
-}
+  options.previews = data;
+};
 /** 关闭窗口 */
 const closeDialog = () => {
-    options.img = userStore.avatar;
-    options.visible = false;
-}
+  options.img = userStore.avatar;
+  options.visible = false;
+};
 </script>
 
 <style lang="scss" scoped>

+ 24 - 22
src/views/system/user/profile/userInfo.vue

@@ -24,40 +24,42 @@
 
 <script setup lang="ts">
 import { updateUserProfile } from "@/api/system/user";
-import { FormRules } from "element-plus";
-import { ComponentInternalInstance } from "vue";
-import { PropType } from "vue";
-import { ElForm } from "element-plus";
 
 const props = defineProps({
-    user: {
-        type: Object as PropType<any>,
-    }
+  user: {
+    type: Object as PropType<any>,
+    required: true
+  }
 });
 const userForm = computed(() => props.user);
-
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-
-const userRef = ref(ElForm);
-
-const rules = ref<FormRules>({
-    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 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" }]
 });
 
 
 /** 提交按钮 */
 const submit = () => {
-    userRef.value.validate(async (valid: boolean) => {
-        if (valid) {
-            await updateUserProfile(props.user)
-            proxy?.$modal.msgSuccess("修改成功");
-        }
-    });
+  userRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      await updateUserProfile(props.user);
+      proxy?.$modal.msgSuccess("修改成功");
+    }
+  });
 };
 /** 关闭按钮 */
 const close = () => {
-    proxy?.$tab.closePage();
+  proxy?.$tab.closePage();
 };
 </script>

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

@@ -31,24 +31,19 @@
 </template>
 
 <script setup lang="ts">
-import { PropType } from 'vue';
+import { propTypes } from "@/utils/propTypes";
 
 const prop = defineProps({
-    info: {
-        type: Object as PropType<any>,
-        default: () => {
-            return {};
-        }
-    }
+  info: propTypes.any.def({})
 });
 
 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>

+ 7 - 8
src/views/tool/gen/editTable.vue

@@ -117,9 +117,8 @@ import { getGenTable, updateGenTable } from '@/api/tool/gen';
 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 { ComponentInternalInstance } from "vue";
+import BasicInfoForm from './basicInfoForm.vue';
+import GenInfoForm from "./genInfoForm.vue";
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -131,13 +130,13 @@ const columns = ref<DbColumnVO[]>([]);
 const dictOptions = ref<DictTypeVO[]>([]);
 const info = ref<Partial<DbTableVO>>({});
 
-const basicInfo = ref(basicInfoForm);
-const genInfo = ref(genInfoForm);
+const basicInfo = ref<InstanceType<typeof BasicInfoForm>>();
+const genInfo = ref<InstanceType<typeof GenInfoForm>>();
 
 /** 提交按钮 */
 const submitForm = () => {
-  const basicForm = basicInfo.value.$refs.basicInfoForm;
-  const genForm = genInfo.value.$refs.genInfoForm;
+  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);
@@ -168,7 +167,7 @@ const getFormPromise = (form: any) => {
   });
 }
 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);
 }
 

+ 9 - 15
src/views/tool/gen/genInfoForm.vue

@@ -223,7 +223,7 @@
 
 <script setup lang="ts">
 import { listMenu } from '@/api/system/menu';
-import { ComponentInternalInstance, PropType } from 'vue';
+import { propTypes } from "@/utils/propTypes";
 
 interface MenuOptionsType {
   menuId: number | string;
@@ -236,14 +236,8 @@ const menuOptions = ref<Array<MenuOptionsType>>([]);
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const props = defineProps({
-  info: {
-    type: Object as PropType<any>,
-    default: null
-  },
-  tables: {
-    type: Array as PropType<any[]>,
-    default: null
-  }
+  info: propTypes.any.def(null),
+  tables: propTypes.any.def(null)
 });
 
 const infoForm = computed(() => props.info);
@@ -252,11 +246,11 @@ 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 = "";
@@ -268,7 +262,7 @@ const tplSelectChange = (value: string) => {
   }
 }
 const setSubTableColumns = (value: string) => {
-  table.value.forEach(item => {
+  table.value.forEach((item: any) => {
     const name = item.tableName;
     if (value === name) {
       subColumns.value = item.columns;

+ 43 - 44
src/views/tool/gen/importTable.vue

@@ -3,11 +3,11 @@
   <el-dialog title="导入表" v-model="visible" width="1100px" top="5vh" append-to-body>
     <el-form :model="queryParams" ref="queryFormRef" :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>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="表名称" prop="tableName">
+        <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>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="表名称" prop="tableName">
         <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable @keyup.enter="handleQuery" />
       </el-form-item>
       <el-form-item label="表描述" prop="tableComment">
@@ -26,7 +26,7 @@
         <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" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-row>
     <template #footer>
       <div class="dialog-footer">
@@ -40,8 +40,6 @@
 <script setup lang="ts">
 import { listDbTable, importTable, getDataNames } from '@/api/tool/gen';
 import { DbTableQuery, DbTableVO } from '@/api/tool/gen/types';
-import { ComponentInternalInstance } from 'vue';
-import { ElTable, ElForm } from 'element-plus';
 
 const total = ref(0);
 const visible = ref(false);
@@ -49,15 +47,15 @@ const tables = ref<Array<string>>([]);
 const dbTableList = ref<Array<DbTableVO>>([]);
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
-const tableRef = ref(ElTable);
-const queryFormRef = ref(ElForm);
+const tableRef = ref<ElTableInstance>();
+const queryFormRef = ref<ElFormInstance>();
 
 const queryParams = reactive<DbTableQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    dataName: '',
-    tableName: '',
-    tableComment: ''
+  pageNum: 1,
+  pageSize: 10,
+  dataName: '',
+  tableName: '',
+  tableComment: ''
 });
 const dataNameList = ref<Array<string>>([]);
 
@@ -65,52 +63,53 @@ const emit = defineEmits(["ok"]);
 
 /** 查询参数列表 */
 const show = (dataName: string) => {
-    getDataNameList();
-    if(dataName){
-      queryParams.dataName = dataName;
-    } else {
-      queryParams.dataName = 'master';
-    }
-    getList();
-    visible.value = true;
+  getDataNameList();
+  if (dataName) {
+    queryParams.dataName = dataName;
+  } else {
+    queryParams.dataName = 'master';
+  }
+  getList();
+  visible.value = true;
 }
 /** 单击选择行 */
 const clickRow = (row: DbTableVO) => {
-    tableRef.value.toggleRowSelection(row);
+  // ele bug
+  tableRef.value?.toggleRowSelection(row);
 }
 /** 多选框选中数据 */
 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 res = await listDbTable(queryParams);
+  dbTableList.value = res.rows;
+  total.value = res.total;
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.pageNum = 1;
-    getList();
+  queryParams.pageNum = 1;
+  getList();
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    queryFormRef.value.resetFields();
-    handleQuery();
+  queryFormRef.value?.resetFields();
+  handleQuery();
 }
 /** 导入按钮操作 */
 const handleImportTable = async () => {
-    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");
-    }
+  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");
+  }
 }
 /** 查询多数据源名称 */
 const getDataNameList = async () => {
@@ -119,6 +118,6 @@ const getDataNameList = async () => {
 }
 
 defineExpose({
-    show,
+  show,
 });
 </script>

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

@@ -1,39 +1,41 @@
 <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="68px">
-          <el-form-item label="数据源" prop="dataName">
-            <el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
-              <el-option key="" label="全部" value="" />
-              <el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="表名称" prop="tableName">
-            <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="表描述" prop="tableComment">
-            <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
-          </el-form-item>
-          <el-form-item label="创建时间" style="width: 308px">
-            <el-date-picker
-              v-model="dateRange"
-              value-format="YYYY-MM-DD"
-              type="daterange"
-              range-separator="-"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-            ></el-date-picker>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-          </el-form-item>
-        </el-form>
+      <div class="mb-[10px]" v-show="showSearch">
+        <el-card shadow="hover">
+          <el-form :model="queryParams" ref="queryFormRef" :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="" />
+                <el-option v-for="item in dataNameList" :key="item" :label="item" :value="item"> </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="表名称" prop="tableName">
+              <el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="表描述" prop="tableComment">
+              <el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable style="width: 200px" @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="创建时间" style="width: 308px">
+              <el-date-picker
+                v-model="dateRange"
+                value-format="YYYY-MM-DD"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <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>
       </div>
     </transition>
 
-    <el-card shadow="never">
+    <el-card shadow="hover">
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
@@ -99,9 +101,9 @@
           :name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
           :key="value"
         >
-          <el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
-            >&nbsp;复制</el-link
-          >
+          <el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">
+            &nbsp;复制
+          </el-link>
           <pre>{{ value }}</pre>
         </el-tab-pane>
       </el-tabs>
@@ -114,9 +116,7 @@
 import { listTable, previewTable, delTable, genCode, synchDb, getDataNames } from '@/api/tool/gen';
 import { TableQuery, TableVO } from '@/api/tool/gen/types';
 import router from '@/router';
-import importTable from './importTable.vue';
-import { ComponentInternalInstance } from 'vue';
-import { ElForm, DateModelType } from 'element-plus';
+import ImportTable from './importTable.vue';
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -132,35 +132,35 @@ const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
 const uniqueId = ref("");
 const dataNameList = ref<Array<string>>([]);
 
-const queryFormRef = ref(ElForm);
-const importRef = ref(importTable);
+const queryFormRef = ref<ElFormInstance>();
+const importRef = ref<InstanceType<typeof ImportTable>>();
 
 const queryParams = ref<TableQuery>({
-    pageNum: 1,
-    pageSize: 10,
-    tableName: '',
-    tableComment: '',
-    dataName: ""
+  pageNum: 1,
+  pageSize: 10,
+  tableName: '',
+  tableComment: '',
+  dataName: ""
 })
 
-const preview = ref <any>({
-    data: {},
-    activeName: 'domain.java'
+const preview = ref<any>({
+  data: {},
+  activeName: 'domain.java'
 })
 const dialog = reactive<DialogOption>({
-    visible: false,
-    title: '代码预览'
+  visible: false,
+  title: '代码预览'
 });
 
 onActivated(() => {
-    const time = route.query.t;
-    if (time != null && time != uniqueId.value) {
-        uniqueId.value = time as string;
-        queryParams.value.pageNum = Number(route.query.pageNum);
-        dateRange.value = ['', ''];
-        queryFormRef.value.resetFields();
-        getList();
-    }
+  const time = route.query.t;
+  if (time != null && time != uniqueId.value) {
+    uniqueId.value = time as string;
+    queryParams.value.pageNum = Number(route.query.pageNum);
+    dateRange.value = ['', ''];
+    queryFormRef.value?.resetFields();
+    getList();
+  }
 })
 
 /** 查询多数据源名称 */
@@ -171,81 +171,81 @@ const getDataNameList = async () => {
 
 /** 查询表集合 */
 const getList = async () => {
-    loading.value = true;
-    const res = await listTable(proxy?.addDateRange(queryParams.value, dateRange.value));
-    tableList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
+  loading.value = true;
+  const res = await listTable(proxy?.addDateRange(queryParams.value, dateRange.value));
+  tableList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 /** 搜索按钮操作 */
 const handleQuery = () => {
-    queryParams.value.pageNum = 1;
-    getList();
+  queryParams.value.pageNum = 1;
+  getList();
 }
 /** 生成代码操作 */
 const handleGenTable = async (row?: TableVO) => {
-    const tbIds = row?.tableId || ids.value;
-    if (tbIds == "") {
-        proxy?.$modal.msgError('请选择要生成的数据');
-        return;
-    }
-    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 tbIds = row?.tableId || ids.value;
+  if (tbIds == "") {
+    proxy?.$modal.msgError('请选择要生成的数据');
+    return;
+  }
+  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 tableId = row.tableId;
+  await proxy?.$modal.confirm('确认要强制同步"' + row.tableName + '"表结构吗?');
+  await synchDb(tableId);
+  proxy?.$modal.msgSuccess('同步成功');
 }
 /** 打开导入表弹窗 */
 const openImportTable = () => {
-    importRef.value.show(queryParams.value.dataName);
+  importRef.value?.show(queryParams.value.dataName);
 }
 /** 重置按钮操作 */
 const resetQuery = () => {
-    dateRange.value = ['', ''];
-    queryFormRef.value.resetFields();
-    handleQuery();
+  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 res = await previewTable(row.tableId);
+  preview.value.data = res.data;
+  dialog.visible = true;
+  preview.value.activeName = 'domain.java';
 }
 /** 复制代码成功 */
 const copyTextSuccess = () => {
-    proxy?.$modal.msgSuccess('复制成功');
+  proxy?.$modal.msgSuccess('复制成功');
 }
 // 多选框选中数据
 const handleSelectionChange = (selection: TableVO[]) => {
-    ids.value = selection.map(item => item.tableId);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
+  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 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;
-    await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
-    await delTable(tableIds);
-    getList();
-    proxy?.$modal.msgSuccess('删除成功');
+  const tableIds = row?.tableId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
+  await delTable(tableIds);
+  getList();
+  proxy?.$modal.msgSuccess('删除成功');
 }
 
 onMounted(() => {
-    getList();
-    getDataNameList();
+  getList();
+  getDataNameList();
 })
 </script>