Эх сурвалжийг харах

Merge branch 'develop_Allen' of www/taais-web into master

allen 10 сар өмнө
parent
commit
66ce634457
100 өөрчлөгдсөн 4837 нэмэгдсэн , 836 устгасан
  1. 1 1
      .env
  2. 2 1
      .env.development
  3. 1 1
      .prettierrc.cjs
  4. 0 1
      .vscode/extensions.json
  5. 9 2
      README.md
  6. 1 1
      index.html
  7. 206 349
      package-lock.json
  8. 9 12
      package.json
  9. 0 0
      public/logo.svg
  10. 12 10
      src/api/index.ts
  11. 86 0
      src/api/interface/ag/config.ts
  12. 101 0
      src/api/interface/ag/model.ts
  13. 14 3
      src/api/interface/index.ts
  14. 59 0
      src/api/interface/login.ts
  15. 2 2
      src/api/interface/menu.ts
  16. 25 0
      src/api/interface/system/config.ts
  17. 28 0
      src/api/interface/system/data.ts
  18. 47 0
      src/api/interface/system/dept.ts
  19. 71 0
      src/api/interface/system/menu.ts
  20. 24 0
      src/api/interface/system/oss.ts
  21. 41 0
      src/api/interface/system/ossConfig.ts
  22. 25 0
      src/api/interface/system/post.ts
  23. 54 0
      src/api/interface/system/role.ts
  24. 20 0
      src/api/interface/system/type.ts
  25. 87 0
      src/api/interface/system/user.ts
  26. 181 0
      src/api/interface/task/bizProcess.ts
  27. 171 0
      src/api/interface/task/dataProcess.ts
  28. 151 0
      src/api/interface/task/dataSet.ts
  29. 125 0
      src/api/interface/task/subtask.ts
  30. 96 0
      src/api/interface/task/subtaskDetail.ts
  31. 101 0
      src/api/interface/task/task.ts
  32. 175 0
      src/api/interface/tool/gen.ts
  33. 70 0
      src/api/modules/ag/config.ts
  34. 70 0
      src/api/modules/ag/model.ts
  35. 69 0
      src/api/modules/demo/data.ts
  36. 11 9
      src/api/modules/login.ts
  37. 86 0
      src/api/modules/system/config.ts
  38. 7 31
      src/api/modules/system/dept.ts
  39. 13 22
      src/api/modules/system/dict.ts
  40. 9 9
      src/api/modules/system/dictData.ts
  41. 14 37
      src/api/modules/system/menu.ts
  42. 28 0
      src/api/modules/system/oss.ts
  43. 62 0
      src/api/modules/system/ossConfig.ts
  44. 7 6
      src/api/modules/system/post.ts
  45. 89 6
      src/api/modules/system/role.ts
  46. 54 10
      src/api/modules/system/user.ts
  47. 36 0
      src/api/modules/taais/task.ts
  48. 94 0
      src/api/modules/task/bizProcess.ts
  49. 70 0
      src/api/modules/task/dataProcess.ts
  50. 70 0
      src/api/modules/task/dataSet.ts
  51. 70 0
      src/api/modules/task/subtask.ts
  52. 70 0
      src/api/modules/task/subtaskDetail.ts
  53. 78 0
      src/api/modules/task/task.ts
  54. 19 19
      src/api/modules/tool/gen.ts
  55. 6 4
      src/api/modules/upload.ts
  56. 0 1
      src/assets/images/logo.svg
  57. 4 18
      src/components/CustomDialog/index.vue
  58. 1 6
      src/components/DictTag/index.vue
  59. 1 6
      src/components/ECharts/config/index.ts
  60. 1 3
      src/components/ECharts/index.vue
  61. 16 2
      src/components/FormDialog/index.vue
  62. 1 3
      src/components/Grid/components/GridItem.vue
  63. 1 3
      src/components/Highlight/index.vue
  64. 1 2
      src/components/HighlightDialog/index.vue
  65. 73 0
      src/components/ImagePreview/index.vue
  66. 2 14
      src/components/ImportExcel/index.vue
  67. 3 0
      src/components/ImportPicDataset/index.scss
  68. 261 0
      src/components/ImportPicDataset/index.vue
  69. 4 4
      src/components/Loading/fullScreen.ts
  70. 4 14
      src/components/ProForm/components/Item.vue
  71. 53 16
      src/components/ProForm/index.vue
  72. 2 2
      src/components/ProFormOld/index.vue
  73. 1 5
      src/components/ProTable/components/TableColumn.vue
  74. 15 41
      src/components/ProTable/index.vue
  75. 1 2
      src/components/ProTable/interface/index.ts
  76. 3 3
      src/components/SearchForm/index.vue
  77. 1 3
      src/components/SelectFilter/index.vue
  78. 1 1
      src/components/SelectIcon/index.vue
  79. 121 0
      src/components/TableDialog/index.vue
  80. 234 0
      src/components/Upload/File.vue
  81. 234 0
      src/components/Upload/FileS3.vue
  82. 5 4
      src/components/Upload/Img.vue
  83. 122 77
      src/components/Upload/Imgs.vue
  84. 361 0
      src/components/Upload/ImgsS3.vue
  85. 98 0
      src/components/UploadDialog/index.vue
  86. 30 0
      src/components/iFrame/index.vue
  87. 1 1
      src/directives/modules/role.ts
  88. 15 0
      src/enums/MenuTypeEnum.ts
  89. 99 2
      src/hooks/useDownload.ts
  90. 1 4
      src/hooks/useTheme.ts
  91. 3 7
      src/hooks/useTime.ts
  92. 1 1
      src/languages/modules/en.ts
  93. 1 1
      src/languages/modules/zh.ts
  94. 1 7
      src/layouts/LayoutClassic/index.vue
  95. 1 7
      src/layouts/LayoutColumns/index.vue
  96. 1 7
      src/layouts/LayoutVertical/index.vue
  97. 1 1
      src/layouts/components/Footer/index.vue
  98. 8 8
      src/layouts/components/Header/ToolBarRight.vue
  99. 1 6
      src/layouts/components/Header/components/AssemblySize.vue
  100. 21 18
      src/layouts/components/Header/components/Avatar.vue

+ 1 - 1
.env

@@ -1,5 +1,5 @@
 # title
-VITE_GLOB_APP_TITLE = 目标精确捕获系统
+VITE_GLOB_APP_TITLE = 算法任务系统
 
 # 本地运行端口号
 VITE_PORT = 8848

+ 2 - 1
.env.development

@@ -25,7 +25,8 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C
 VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
 
 # 开发环境跨域代理,支持配置多个
-VITE_PROXY = [["/api","http://localhost:9090"]]
+# VITE_PROXY = [["/api","http://localhost:9090"]]
+VITE_PROXY = [["/api","http://192.168.101.34/prod-api"]]
 # VITE_PROXY = [["/api","https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e"]]
 # VITE_PROXY = [["/api","https://www.fastmock.site/mock/f81e8333c1a9276214bcdbc170d9e0a0"]]
 # VITE_PROXY = [["/api-easymock","https://mock.mengxuegu.com"],["/api-fastmock","https://www.fastmock.site"]]

+ 1 - 1
.prettierrc.cjs

@@ -2,7 +2,7 @@
 
 module.exports = {
   // 指定最大换行长度
-  printWidth: 130,
+  printWidth: 150,
   // 缩进制表符宽度 | 空格数
   tabWidth: 2,
   // 使用制表符而不是空格缩进行 (true:制表符,false:空格)

+ 0 - 1
.vscode/extensions.json

@@ -3,7 +3,6 @@
     "vue.volar",
     "vue.vscode-typescript-vue-plugin",
     "hollowtree.vue-snippets",
-    "dbaeumer.vscode-eslint",
     "stylelint.vscode-stylelint",
     "esbenp.prettier-vscode",
     "editorconfig.editorconfig",

+ 9 - 2
README.md

@@ -1,3 +1,10 @@
-# km-web
+# taais-web
 
-前端脚手架
+```
+yarn install
+
+## 启动
+yarn serve
+```
+
+前端脚手架

+ 1 - 1
index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vue.svg" />
+    <link rel="icon" type="image/svg+xml" href="/logo.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title><%= title %></title>
   </head>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 206 - 349
package-lock.json


+ 9 - 12
package.json

@@ -1,22 +1,14 @@
 {
-  "name": "km-admin",
+  "name": "taais-admin",
   "private": true,
   "version": "1.2.0",
   "type": "module",
-  "description": "km-admin open source management system",
+  "description": "taais-admin open source management system",
   "author": {
     "name": "gaokunw",
     "email": "wanggaokun@wo.cn"
   },
   "license": "MIT",
-  "homepage": "https://gitee.com/gaokunw/kimi-web",
-  "repository": {
-    "type": "git",
-    "url": "git@gitee.com:gaokunw/kimi-web.git"
-  },
-  "bugs": {
-    "url": "https://gitee.com/gaokunw/kimi-web/issues"
-  },
   "scripts": {
     "dev": "vite",
     "serve": "vite",
@@ -47,8 +39,10 @@
     "driver.js": "^1.3.1",
     "echarts": "^5.4.3",
     "echarts-liquidfill": "^3.1.0",
-    "element-plus": "^2.4.3",
+    "element-plus": "2.6.0",
+    "fabric": "^5.3.0",
     "file-saver": "^2.0.5",
+    "image-conversion": "^2.1.1",
     "js-cookie": "^3.0.5",
     "jsencrypt": "^3.3.2",
     "md5": "^2.3.0",
@@ -61,9 +55,12 @@
     "qs": "^6.11.2",
     "screenfull": "^6.0.2",
     "sortablejs": "^1.15.1",
-    "vue": "^3.3.11",
+    "vue": "3.3.13",
+    "vue-cropper": "^1.1.2",
     "vue-i18n": "^9.6.4",
+    "vue-konva": "^3.0.2",
     "vue-router": "^4.2.5",
+    "vue-types": "^5.1.1",
     "vuedraggable": "^4.1.0"
   },
   "devDependencies": {

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
public/logo.svg


+ 12 - 10
src/api/index.ts

@@ -31,12 +31,13 @@ const config = {
 const encryptHeader = 'encrypt-key'
 // 是否显示重新登录
 export let isReLogin = { show: false }
-// export const globalHeaders = () => {
-//   return {
-//     Authorization: 'Bearer ' + getToken(),
-//     clientid: import.meta.env.VITE_APP_CLIENT_ID
-//   }
-// }
+
+export const globalHeaders = () => {
+  return {
+    Authorization: 'Bearer ' + getToken(),
+    clientid: import.meta.env.VITE_APP_CLIENT_ID
+  }
+}
 axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
 axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID
 const axiosCanceler = new AxiosCanceler()
@@ -110,10 +111,11 @@ class RequestHttp {
           // 生成一个 AES 密钥
           const aesKey = generateAesKey()
           config.headers[encryptHeader] = encrypt(encryptBase64(aesKey))
-          config.data =
-            typeof config.data === 'object'
-              ? encryptWithAes(JSON.stringify(config.data), aesKey)
-              : encryptWithAes(config.data, aesKey)
+          config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey)
+        }
+        // FormData数据去请求头Content-Type
+        if (config.data instanceof FormData) {
+          delete config.headers['Content-Type']
         }
         return config
       },

+ 86 - 0
src/api/interface/ag/config.ts

@@ -0,0 +1,86 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface ConfigVO extends BaseEntity {
+  /**
+   * 类型
+   */
+  type: string
+
+  /**
+   * 分系统
+   */
+  subsystem: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress: string
+}
+
+export interface ConfigForm {
+  /**
+   * 类型
+   */
+  type?: string
+
+  /**
+   * 父id
+   */
+  parentId?: string | number
+
+  /**
+   * 分系统
+   */
+  subsystem?: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName?: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress?: string
+
+  /**
+   * 参数配置
+   */
+  parameterConfig?: string
+
+  /**
+   * 备注
+   */
+  remarks?: string
+}
+
+export interface ConfigQuery extends PageQuery {
+  /**
+   * 类型
+   */
+  type?: string
+
+  /**
+   * 分系统
+   */
+  subsystem?: string
+
+  /**
+   * 算法名称
+   */
+  algorithmName?: string
+
+  /**
+   * 算法地址
+   */
+  algorithmAddress?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 101 - 0
src/api/interface/ag/model.ts

@@ -0,0 +1,101 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface ModelVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch: number
+
+  /**
+   * 备注
+   */
+  remarks: string
+}
+
+export interface ModelForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName?: string
+
+  /**
+   * 模型
+   */
+  modelAddress?: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber?: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+}
+
+export interface ModelQuery extends PageQuery {
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型名称
+   */
+  modelName?: string
+
+  /**
+   * 训练样本数
+   */
+  sampleNumber?: number
+
+  /**
+   * 训练循环次数
+   */
+  cycleEpoch?: number
+
+  /**
+   * 备注
+   */
+  remarks?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 14 - 3
src/api/interface/index.ts

@@ -18,11 +18,22 @@ export interface ResPage<T> {
 }
 
 // 分页请求参数
-export interface ReqPage {
+export interface PageQuery {
   pageNum: number
   pageSize: number
 }
 
+// 分页请求参数
+export interface BaseEntity {
+  /** 乐观锁 */
+  version?: number
+  createBy?: any
+  createDept?: any
+  createTime?: string
+  updateBy?: any
+  updateTime?: any
+}
+
 // 文件上传模块
 export namespace Upload {
   export interface ResFileUrl {
@@ -40,7 +51,7 @@ export namespace Login {
     uuid: string
     clientId: string
     grantType: string
-    tenantId: string
+    tenantId: string | number
   }
   export interface ResLogin {
     access_token: string
@@ -52,7 +63,7 @@ export namespace Login {
 
 // 用户管理模块
 export namespace User {
-  export interface ReqUserParams extends ReqPage {
+  export interface ReqUserParams extends PageQuery {
     username: string
     gender: number
     idCard: string

+ 59 - 0
src/api/interface/login.ts

@@ -0,0 +1,59 @@
+/**
+ * 注册
+ */
+export type RegisterForm = {
+  tenantId: number
+  username: string
+  password: string
+  confirmPassword?: string
+  code?: string
+  uuid?: string
+  userType?: string
+}
+
+/**
+ * 登录请求
+ */
+export interface LoginData {
+  tenantId?: number | string
+  username?: string
+  password?: string
+  rememberMe?: boolean
+  socialCode?: string
+  socialState?: string
+  source?: string
+  code?: string
+  uuid?: string
+  clientId: string
+  grantType: string
+}
+
+/**
+ * 登录响应
+ */
+export interface LoginResult {
+  access_token: string
+}
+
+/**
+ * 验证码返回
+ */
+export interface VerifyCodeResult {
+  captchaEnabled: boolean
+  uuid?: string
+  img?: string
+}
+
+/**
+ * 租户
+ */
+export interface TenantVO {
+  companyName: string
+  domain: any
+  tenantId: string
+}
+
+export interface TenantInfo {
+  tenantEnabled: boolean
+  voList: TenantVO[]
+}

+ 2 - 2
src/api/interface/menu.ts

@@ -1,7 +1,7 @@
-import { ReqPage } from '@/api/interface/index'
+import { PageQuery } from '@/api/interface/index'
 // 用户管理模块
 export namespace Menu {
-  export interface ReqMenuParams extends ReqPage {
+  export interface ReqMenuParams extends PageQuery {
     username: string
     gender: number
     idCard: string

+ 25 - 0
src/api/interface/system/config.ts

@@ -0,0 +1,25 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface ConfigVO extends BaseEntity {
+  configId: number | string
+  configName: string
+  configKey: string
+  configValue: string
+  configType: string
+  remark: string
+}
+
+export interface ConfigForm {
+  configId: number | string | undefined
+  configName: string
+  configKey: string
+  configValue: string
+  configType: string
+  version: number
+  remark: string
+}
+
+export interface ConfigQuery extends PageQuery {
+  configName: string
+  configKey: string
+  configType: string
+}

+ 28 - 0
src/api/interface/system/data.ts

@@ -0,0 +1,28 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DictDataQuery extends PageQuery {
+  dictName: string
+  dictType: string
+  dictLabel: string
+}
+
+export interface DictDataVO extends BaseEntity {
+  dictCode: string
+  dictLabel: string
+  dictValue: string
+  cssClass: string
+  listClass: ElTagType
+  dictSort: number
+  remark: string
+}
+
+export interface DictDataForm {
+  dictType?: string
+  dictCode: string | undefined
+  dictLabel: string
+  dictValue: string
+  cssClass: string
+  listClass: ElTagType
+  dictSort: number
+  version: number
+  remark: string
+}

+ 47 - 0
src/api/interface/system/dept.ts

@@ -0,0 +1,47 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+/**
+ * 部门查询参数
+ */
+export interface DeptQuery extends PageQuery {
+  deptName?: string
+  status?: number
+}
+
+/**
+ * 部门类型
+ */
+export interface DeptVO extends BaseEntity {
+  id: number | string
+  parentName: string
+  parentId: number | string
+  children: DeptVO[]
+  deptId: number | string
+  deptName: string
+  orderNum: number
+  leader: string
+  phone: string
+  email: string
+  status: string
+  delFlag: string
+  ancestors: string
+  menuId: string | number
+}
+
+/**
+ * 部门表单类型
+ */
+export interface DeptForm {
+  parentName?: string
+  parentId?: number | string
+  children?: DeptForm[]
+  deptId?: number | string
+  deptName?: string
+  orderNum?: number
+  leader?: string
+  phone?: string
+  email?: string
+  status?: string
+  version?: number
+  delFlag?: string
+  ancestors?: string
+}

+ 71 - 0
src/api/interface/system/menu.ts

@@ -0,0 +1,71 @@
+import { MenuTypeEnum } from '@/enums/MenuTypeEnum'
+import { BaseEntity } from '@/api/interface/index'
+
+/**
+ * 菜单树形结构类型
+ */
+export interface MenuTreeOption {
+  id: string | number
+  label: string
+  parentId: string | number
+  weight: number
+  children?: MenuTreeOption[]
+}
+
+export interface RoleMenuTree {
+  menus: MenuTreeOption[]
+  checkedKeys: string[]
+}
+
+/**
+ * 菜单查询参数类型
+ */
+export interface MenuQuery {
+  keywords?: string
+  menuName?: string
+  status?: string
+}
+
+/**
+ * 菜单视图对象类型
+ */
+export interface MenuVO extends BaseEntity {
+  parentName: string
+  parentId: string | number
+  children: MenuVO[]
+  menuId: string | number
+  menuName: string
+  orderNum: number
+  path: string
+  component: string
+  queryParam: string
+  isFrame: string
+  isCache: string
+  menuType: MenuTypeEnum
+  visible: string
+  status: string
+  icon: string
+  remark: string
+}
+
+export interface MenuForm {
+  parentName?: string
+  parentId?: string | number
+  children?: MenuForm[]
+  menuId?: string | number
+  menuName: string
+  orderNum: number
+  path: string
+  component?: string
+  queryParam?: string
+  isFrame?: string
+  isCache?: string
+  menuType?: MenuTypeEnum
+  visible?: string
+  status?: string
+  icon?: string
+  remark?: string
+  query?: string
+  perms?: string
+  version?: number
+}

+ 24 - 0
src/api/interface/system/oss.ts

@@ -0,0 +1,24 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+
+export interface OssVO extends BaseEntity {
+  ossId: string | number
+  fileName: string
+  originalName: string
+  fileSuffix: string
+  url: string
+  createByName: string
+  service: string
+}
+
+export interface OssQuery extends PageQuery {
+  fileName: string
+  originalName: string
+  fileSuffix: string
+  createTime: string
+  service: string
+  orderByColumn: string
+  isAsc: string
+}
+export interface OssForm {
+  file: undefined | string
+}

+ 41 - 0
src/api/interface/system/ossConfig.ts

@@ -0,0 +1,41 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+
+export interface OssConfigVO extends BaseEntity {
+  ossConfigId: number | string
+  configKey: string
+  accessKey: string
+  secretKey: string
+  bucketName: string
+  prefix: string
+  endpoint: string
+  domain: string
+  isHttps: string
+  region: string
+  status: string
+  ext1: string
+  remark: string
+  accessPolicy: string
+}
+
+export interface OssConfigQuery extends PageQuery {
+  configKey: string
+  bucketName: string
+  status: string
+}
+
+export interface OssConfigForm {
+  ossConfigId: string | number | undefined
+  configKey: string
+  accessKey: string
+  secretKey: string
+  bucketName: string
+  prefix: string
+  endpoint: string
+  domain: string
+  isHttps: string
+  accessPolicy: string
+  region: string
+  status: string
+  version: number
+  remark: string
+}

+ 25 - 0
src/api/interface/system/post.ts

@@ -0,0 +1,25 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface PostVO extends BaseEntity {
+  postId: number | string
+  postCode: string
+  postName: string
+  postSort: number
+  status: string
+  remark: string
+}
+
+export interface PostForm {
+  postId: number | string | undefined
+  postCode: string
+  postName: string
+  postSort: number
+  status: string
+  version: number
+  remark: string
+}
+
+export interface PostQuery extends PageQuery {
+  postCode: string
+  postName: string
+  status: string
+}

+ 54 - 0
src/api/interface/system/role.ts

@@ -0,0 +1,54 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+/**
+ * 菜单树形结构类型
+ */
+export interface DeptTreeOption {
+  id: string
+  label: string
+  parentId: string
+  weight: number
+  children?: DeptTreeOption[]
+}
+
+export interface RoleDeptTree {
+  checkedKeys: string[]
+  depts: DeptTreeOption[]
+}
+
+export interface RoleVO extends BaseEntity {
+  roleId: string | number
+  roleName: string
+  roleKey: string
+  roleSort: number
+  dataScope: string
+  menuCheckStrictly: boolean
+  deptCheckStrictly: boolean
+  status: string
+  delFlag: string
+  remark?: any
+  flag: boolean
+  menuIds?: Array<string | number>
+  deptIds?: Array<string | number>
+  admin: boolean
+}
+
+export interface RoleQuery extends PageQuery {
+  roleName: string
+  roleKey: string
+  status: string
+}
+
+export interface RoleForm {
+  roleName: string
+  roleKey: string
+  roleSort: number
+  status: string
+  menuCheckStrictly: boolean
+  deptCheckStrictly: boolean
+  remark: string
+  dataScope?: string
+  roleId: string | undefined
+  menuIds: Array<string | number>
+  deptIds: Array<string | number>
+  version?: number
+}

+ 20 - 0
src/api/interface/system/type.ts

@@ -0,0 +1,20 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DictTypeVO extends BaseEntity {
+  dictId: number | string
+  dictName: string
+  dictType: string
+  remark: string
+}
+
+export interface DictTypeForm {
+  dictId: number | string | undefined
+  dictName: string
+  dictType: string
+  version: number
+  remark: string
+}
+
+export interface DictTypeQuery extends PageQuery {
+  dictName: string
+  dictType: string
+}

+ 87 - 0
src/api/interface/system/user.ts

@@ -0,0 +1,87 @@
+import { RoleVO } from '@/api/interface/system/role'
+import { PostVO } from '@/api/interface/system/post'
+import { DeptVO } from '@/api/interface/system/dept'
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+/**
+ * 用户信息
+ */
+export interface UserInfo {
+  user: UserVO
+  roles: string[]
+  permissions: string[]
+}
+
+/**
+ * 用户查询对象类型
+ */
+export interface UserQuery extends PageQuery {
+  userName?: string
+  phonenumber?: string
+  status?: string
+  deptId?: string | number
+  roleId?: string | number
+}
+
+/**
+ * 用户返回对象
+ */
+export interface UserVO extends BaseEntity {
+  userId: string | number
+  deptId: number
+  userName: string
+  nickName: string
+  userType: string
+  email: string
+  phonenumber: string
+  dept: DeptVO
+  gender: string
+  avatar: string
+  url: string
+  status: string
+  delFlag: string
+  loginIp: string
+  loginDate: string
+  remark: string
+  deptName: string
+  roles: RoleVO[]
+  roleIds: any
+  postIds: any
+  roleId: any
+  admin: boolean
+}
+
+/**
+ * 用户表单类型
+ */
+export interface UserForm {
+  id?: string
+  userId?: string
+  deptId?: number
+  userName: string
+  nickName?: string
+  password: string
+  phonenumber?: string
+  email?: string
+  gender?: string
+  status: string
+  remark?: string
+  postIds: string[]
+  roleIds: string[]
+  version?: number
+}
+
+export interface UserInfoVO {
+  user: UserVO
+  roles: RoleVO[]
+  roleIds: string[]
+  posts: PostVO[]
+  postIds: string[]
+  roleGroup: string
+  postGroup: string
+}
+
+export interface ResetPwdForm {
+  oldPassword: string
+  newPassword: string
+  confirmPassword: string
+}

+ 181 - 0
src/api/interface/task/bizProcess.ts

@@ -0,0 +1,181 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface BizProcessVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 模型
+   */
+  modelId: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface BizProcessForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 模型
+   */
+  modelId?: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface BizProcessQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 171 - 0
src/api/interface/task/dataProcess.ts

@@ -0,0 +1,171 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DataProcessVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 算法
+   */
+  algorithmId: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface DataProcessForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 算法
+   */
+  algorithmId?: string | number
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 预处理数据路径
+   */
+  preprocessPath?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface DataProcessQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 151 - 0
src/api/interface/task/dataSet.ts

@@ -0,0 +1,151 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface DataSetVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 序号
+   */
+  index: number
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+
+  /**
+   * 日志
+   */
+  log: string
+}
+
+export interface DataSetForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 结果数据路径
+   */
+  resultPath?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface DataSetQuery extends PageQuery {
+  /**
+   * 子任务id
+   */
+  subTaskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 125 - 0
src/api/interface/task/subtask.ts

@@ -0,0 +1,125 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface SubtaskVO extends BaseEntity {
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 任务类型
+   */
+  type: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+}
+
+export interface SubtaskForm {
+  /**
+   * 任务ID
+   */
+  taskId?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+
+  /**
+   * 序号
+   */
+  index?: number
+}
+
+export interface SubtaskQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  taskId?: string
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 任务类型
+   */
+  type?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 96 - 0
src/api/interface/task/subtaskDetail.ts

@@ -0,0 +1,96 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface SubtaskDetailVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+}
+
+export interface SubtaskDetailForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 调用算法时所用的参数
+   */
+  parameters?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface SubtaskDetailQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 101 - 0
src/api/interface/task/task.ts

@@ -0,0 +1,101 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface TaskVO extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id: string | number
+
+  /**
+   * 任务名称
+   */
+  name: string
+
+  /**
+   * 任务状态
+   */
+  status: string
+
+  /**
+   * 开始时间
+   */
+  startTime: string
+
+  /**
+   * 结束时间
+   */
+  endTime: string
+
+  /**
+   * 耗时
+   */
+  costSecond: number
+}
+
+export interface TaskForm {
+  /**
+   * 主键ID
+   */
+  id?: string | number
+
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日志
+   */
+  log?: string
+}
+
+export interface TaskQuery extends PageQuery {
+  /**
+   * 任务名称
+   */
+  name?: string
+
+  /**
+   * 任务状态
+   */
+  status?: string
+
+  /**
+   * 开始时间
+   */
+  startTime?: string
+
+  /**
+   * 结束时间
+   */
+  endTime?: string
+
+  /**
+   * 耗时
+   */
+  costSecond?: number
+
+  /**
+   * 日期范围参数
+   */
+  params?: any
+}

+ 175 - 0
src/api/interface/tool/gen.ts

@@ -0,0 +1,175 @@
+import { PageQuery, BaseEntity } from '@/api/interface/index'
+export interface TableVO extends BaseEntity {
+  tableId: string | number
+  tableName: string
+  tableComment: string
+  subTableName?: any
+  subTableFkName?: any
+  className: string
+  tplCategory: string
+  packageName: string
+  moduleName: string
+  businessName: string
+  functionName: string
+  functionAuthor: string
+  genType: string
+  genPath: string
+  pkColumn?: any
+  columns?: any
+  options?: any
+  remark?: any
+  treeCode?: any
+  treeParentCode?: any
+  treeName?: any
+  menuIds?: any
+  parentMenuId?: any
+  parentMenuName?: any
+  tree: boolean
+  crud: boolean
+  editColumns: number
+}
+
+export interface TableQuery extends PageQuery {
+  tableName: string
+  tableComment: string
+}
+
+export interface DbColumnVO extends BaseEntity {
+  columnId?: any
+  tableId?: any
+  columnName?: any
+  columnComment?: any
+  columnType?: any
+  javaType?: any
+  javaField?: any
+  isPk?: any
+  isIncrement?: any
+  isRequired?: any
+  isInsert?: any
+  isEdit?: any
+  isList?: any
+  isQuery?: any
+  queryType?: any
+  htmlType?: any
+  dictType?: any
+  sort?: any
+  increment: boolean
+  capJavaField?: any
+  usableColumn: boolean
+  superColumn: boolean
+  list: boolean
+  pk: boolean
+  insert: boolean
+  edit: boolean
+  query: boolean
+  required: boolean
+}
+
+export interface DbTableVO {
+  tableId?: any
+  tableName: string
+  tableComment: string
+  subTableName?: any
+  subTableFkName?: any
+  className?: any
+  tplCategory?: any
+  packageName?: any
+  moduleName?: any
+  businessName?: any
+  functionName?: any
+  functionAuthor?: any
+  genType?: any
+  genPath?: any
+  pkColumn?: any
+  columns: DbColumnVO[]
+  options?: any
+  remark?: any
+  treeCode?: any
+  treeParentCode?: any
+  treeName?: any
+  menuIds?: any
+  parentMenuId?: any
+  parentMenuName?: any
+  tree: boolean
+  crud: boolean
+  version?: number
+}
+
+export interface DbTableQuery extends PageQuery {
+  tableName: string
+  tableComment: string
+}
+
+export interface GenTableVO {
+  info: DbTableVO
+  rows: DbColumnVO[]
+  tables: DbTableVO[]
+}
+
+export interface DbColumnForm extends BaseEntity {
+  columnId: string
+  tableId: string
+  columnName: string
+  columnComment: string
+  columnType: string
+  javaType: string
+  javaField: string
+  isPk: string
+  isIncrement: string
+  isRequired: string
+  isInsert?: any
+  isEdit: string
+  isList: string
+  isQuery?: any
+  queryType: string
+  htmlType: string
+  dictType: string
+  sort: number
+  increment: boolean
+  capJavaField: string
+  usableColumn: boolean
+  superColumn: boolean
+  list: boolean
+  pk: boolean
+  insert: boolean
+  edit: boolean
+  query: boolean
+  required: boolean
+}
+
+export interface DbParamForm {
+  treeCode?: any
+  treeName?: any
+  treeParentCode?: any
+  parentMenuId: string
+}
+
+export interface DbTableForm extends BaseEntity {
+  tableId: string | string
+  tableName: string
+  tableComment: string
+  subTableName?: any
+  subTableFkName?: any
+  className: string
+  tplCategory: string
+  packageName: string
+  moduleName: string
+  businessName: string
+  functionName: string
+  functionAuthor: string
+  genType: string
+  genPath: string
+  pkColumn?: any
+  columns: DbColumnForm[]
+  options: string
+  remark?: any
+  treeCode?: any
+  treeParentCode?: any
+  treeName?: any
+  menuIds?: any
+  parentMenuId: string
+  parentMenuName?: any
+  tree: boolean
+  crud: boolean
+  params: DbParamForm
+}

+ 70 - 0
src/api/modules/ag/config.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { ConfigVO, ConfigForm, ConfigQuery } from '@/api/interface/ag/config'
+/**
+ * @name 查询算法配置列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listConfigApi = (query: ConfigQuery) => {
+  return http.get<ConfigVO[]>('/ag/config/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法配置详细
+ * @param id id
+ * @returns returns
+ */
+export const getConfigApi = (id: string | number) => {
+  return http.get<ConfigVO>(`/ag/config/${id}`)
+}
+
+/**
+ * @name 新增算法配置
+ * @param data data
+ * @returns returns
+ */
+export const addConfigApi = (data: ConfigForm) => {
+  return http.post<any>('/ag/config', data, { loading: false })
+}
+
+/**
+ * @name 修改算法配置
+ * @param data data
+ * @returns returns
+ */
+export const updateConfigApi = (data: ConfigForm) => {
+  return http.put<any>('/ag/config', data, { loading: false })
+}
+
+/**
+ * @name 删除算法配置
+ * @param id id
+ * @returns returns
+ */
+export const delConfigApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/ag/config/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/ag/config/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importConfigDataApi = (data: any) => {
+  return http.post('/ag/config/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportConfigApi = (data: any) => {
+  return http.downloadPost('/ag/config/export', data)
+}

+ 70 - 0
src/api/modules/ag/model.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { ModelVO, ModelForm, ModelQuery } from '@/api/interface/ag/model'
+/**
+ * @name 查询算法模型配置列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listModelApi = (query: ModelQuery) => {
+  return http.get<ModelVO[]>('/ag/model/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法模型配置详细
+ * @param id id
+ * @returns returns
+ */
+export const getModelApi = (id: string | number) => {
+  return http.get<ModelVO>(`/ag/model/${id}`)
+}
+
+/**
+ * @name 新增算法模型配置
+ * @param data data
+ * @returns returns
+ */
+export const addModelApi = (data: ModelForm) => {
+  return http.post<any>('/ag/model', data, { loading: false })
+}
+
+/**
+ * @name 修改算法模型配置
+ * @param data data
+ * @returns returns
+ */
+export const updateModelApi = (data: ModelForm) => {
+  return http.put<any>('/ag/model', data, { loading: false })
+}
+
+/**
+ * @name 删除算法模型配置
+ * @param id id
+ * @returns returns
+ */
+export const delModelApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/ag/model/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/ag/model/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importModelDataApi = (data: any) => {
+  return http.post('/ag/model/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportModelApi = (data: any) => {
+  return http.downloadPost('/ag/model/export', data)
+}

+ 69 - 0
src/api/modules/demo/data.ts

@@ -0,0 +1,69 @@
+import http from '@/api'
+/**
+ * @name 查询数据管理列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataApi = (query: any) => {
+  return http.get<any[]>('/demo/data/list', query, { loading: true })
+}
+
+/**
+ * @name 查询数据管理详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataApi = (id: string | number) => {
+  return http.get<any>(`/demo/data/${id}`)
+}
+
+/**
+ * @name 新增数据管理
+ * @param data data
+ * @returns returns
+ */
+export const addDataApi = (data: any) => {
+  return http.post<any>('/demo/data', data, { loading: false })
+}
+
+/**
+ * @name 修改数据管理
+ * @param data data
+ * @returns returns
+ */
+export const updateDataApi = (data: any) => {
+  return http.put<any>('/demo/data', data, { loading: false })
+}
+
+/**
+ * @name 删除数据管理
+ * @param id id
+ * @returns returns
+ */
+export const delDataApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/demo/data/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/demo/data/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataDataApi = (data: any) => {
+  return http.post('/demo/data/zip/upload', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataApi = (data: any) => {
+  return http.downloadPost('/demo/data/export', data)
+}

+ 11 - 9
src/api/modules/login.ts

@@ -1,12 +1,14 @@
-import { Login } from '@/api/interface/index'
+import { UserInfo } from '@/api/interface/system/user'
+import { LoginData, LoginResult, VerifyCodeResult } from '@/api/interface/login'
 import http from '@/api'
 
 /**
- * @name 登录模块
+ *
+ * 用户登录
+ * @param data {LoginData}
  */
-// 用户登录
-export const loginApi = (params: Login.ReqLoginForm) => {
-  return http.post<Login.ResLogin>('/auth/login', params, { loading: true, isEncrypt: true }) // 正常 post json 请求  ==>  application/json
+export const loginApi = (data: LoginData) => {
+  return http.post<LoginResult>('/auth/login', data, { loading: true, isEncrypt: true }) // 正常 post json 请求  ==>  application/json
 }
 
 // 用户退出登录
@@ -14,11 +16,11 @@ export const logoutApi = () => {
   return http.post('/auth/logout', {}, { loading: false })
 }
 
-// 用户退出登录
+// 获取用户详细信息
 export const getInfoApi = () => {
-  return http.get('/system/user/getInfo', {}, { loading: false })
+  return http.get<UserInfo>('/system/user/getInfo', {}, { loading: false })
 }
-// 用户退出登录
+// 获取验证码
 export const getCodeImg = () => {
-  return http.get('/captchaImage', {}, { loading: false })
+  return http.get<VerifyCodeResult>('/captchaImage', {}, { loading: false })
 }

+ 86 - 0
src/api/modules/system/config.ts

@@ -0,0 +1,86 @@
+import { ConfigVO } from '@/api/interface/system/config'
+import http from '@/api'
+/**
+ * @name 根据参数键名查询参数值
+ * @param ossConfigId ossConfigId
+ * @returns returns
+ */
+export const getConfigKeyApi = (configKey: string) => {
+  return http.get<ConfigVO>(`/system/config/configKey/${configKey}`)
+}
+/**
+ * @name 查询参数配置列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listConfigApi = (query: any) => {
+  return http.get<any>('/system/config/list', query, { loading: true })
+}
+
+/**
+ * @name 查询参数配置详细
+ * @param configId configId
+ * @returns returns
+ */
+export const getConfigApi = (configId: any) => {
+  return http.get<any>(`/system/config/${configId}`)
+}
+
+/**
+ * @name 新增参数配置
+ * @param data data
+ * @returns returns
+ */
+export const addConfigApi = (data: any) => {
+  return http.post<any>('/system/config', data, { loading: false })
+}
+
+/**
+ * @name 修改参数配置
+ * @param data data
+ * @returns returns
+ */
+export const updateConfigApi = (data: any) => {
+  return http.put<any>('/system/config', data, { loading: false })
+}
+/**
+ * @name 修改参数配置
+ * @param data data
+ * @returns returns
+ */
+export const updateConfigByKeyApi = (data: any) => {
+  return http.put<any>('/system/config/updateByKey', data, { loading: false })
+}
+
+/**
+ * @name 删除参数配置
+ * @param configId configId
+ * @returns returns
+ */
+export const delConfigApi = (configId: any) => {
+  return http.delete<any>(`/system/config/${configId}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/system/config/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importConfigDataApi = (data: any) => {
+  return http.post('/system/config/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportConfigApi = (data: any) => {
+  return http.downloadPost('/system/config/export', data)
+}

+ 7 - 31
src/api/modules/system/dept.ts

@@ -1,11 +1,11 @@
 import http from '@/api'
-
+import { DeptForm, DeptQuery, DeptVO } from '@/api/interface/system/dept'
 /**
  * @name 查询部门列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listDeptApi = (query: any) => {
+export const listDeptApi = (query: DeptQuery) => {
   return http.get<any>('/system/dept/list', query, { loading: true })
 }
 
@@ -14,8 +14,8 @@ export const listDeptApi = (query: any) => {
  * @param deptId deptId
  * @returns returns
  */
-export const getDeptApi = (deptId: any) => {
-  return http.get<any>(`/system/dept/${deptId}`)
+export const getDeptApi = (deptId: string | number) => {
+  return http.get<DeptVO>(`/system/dept/${deptId}`)
 }
 
 /**
@@ -23,7 +23,7 @@ export const getDeptApi = (deptId: any) => {
  * @param data data
  * @returns returns
  */
-export const addDeptApi = (data: any) => {
+export const addDeptApi = (data: DeptForm) => {
   return http.post<any>('/system/dept', data, { loading: false })
 }
 
@@ -32,7 +32,7 @@ export const addDeptApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const updateDeptApi = (data: any) => {
+export const updateDeptApi = (data: DeptForm) => {
   return http.put<any>('/system/dept', data, { loading: false })
 }
 
@@ -41,30 +41,6 @@ export const updateDeptApi = (data: any) => {
  * @param deptId deptId
  * @returns returns
  */
-export const delDeptApi = (deptId: any) => {
+export const delDeptApi = (deptId: number | string) => {
   return http.delete<any>(`/system/dept/${deptId}`)
 }
-
-/**
- * @name 下载模板
- * @returns returns
- */
-export const importTemplateApi = () => {
-  return http.downloadPost('/system/dept/importTemplate', {})
-}
-
-/**
- * @name 导入数据
- * @returns returns
- */
-export const importDataApi = (data: any) => {
-  return http.post('/system/dept/importData', data)
-}
-
-/**
- * @name 导出数据
- * @returns returns
- */
-export const exportApi = (data: any) => {
-  return http.downloadPost('/system/dept/export', data)
-}

+ 13 - 22
src/api/modules/system/dict.ts

@@ -1,12 +1,12 @@
 import http from '@/api'
-
+import { DictTypeForm, DictTypeVO, DictTypeQuery } from '@/api/interface/system/type'
 /**
  * @name 查询字典类型列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listDictApi = (query: any) => {
-  return http.get<any>('/system/dict/type/list', query, { loading: false })
+export const listDictApi = (query: DictTypeQuery) => {
+  return http.get<DictTypeVO[]>('/system/dict/type/list', query, { loading: false })
 }
 
 /**
@@ -14,7 +14,7 @@ export const listDictApi = (query: any) => {
  * @param dictId dictId
  * @returns returns
  */
-export const getDictApi = (dictId: any) => {
+export const getDictApi = (dictId: string | number) => {
   return http.get<any>(`/system/dict/type/${dictId}`)
 }
 
@@ -23,7 +23,7 @@ export const getDictApi = (dictId: any) => {
  * @param data data
  * @returns returns
  */
-export const addDictApi = (data: any) => {
+export const addDictApi = (data: DictTypeForm) => {
   return http.post<any>('/system/dict/type', data, { loading: false })
 }
 
@@ -32,7 +32,7 @@ export const addDictApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const updateDictApi = (data: any) => {
+export const updateDictApi = (data: DictTypeForm) => {
   return http.put<any>('/system/dict/type', data, { loading: false })
 }
 
@@ -41,32 +41,23 @@ export const updateDictApi = (data: any) => {
  * @param dictId dictId
  * @returns returns
  */
-export const delDictApi = (id: any) => {
+export const delDictApi = (id: string | number | Array<string | number>) => {
   return http.delete<any>(`/system/dict/type/${id}`)
 }
 
 /**
- * @name 下载模板
- * @returns returns
- */
-export const importTemplateApi = () => {
-  return http.downloadPost('/system/dict/type/importTemplate', {})
-}
-
-/**
- * @name 导入数据
+ * @name 导出数据
  * @returns returns
  */
-export const importDataApi = (data: any) => {
-  return http.post('/system/dict/type/importData', data)
+export const exportApi = (data: any) => {
+  return http.downloadPost('/system/dict/type/export', data)
 }
-
 /**
- * @name 导出数据
+ * @name 刷新字典缓存
  * @returns returns
  */
-export const exportApi = (data: any) => {
-  return http.downloadPost('/system/dict/type/export', data)
+export const refreshCacheApi = () => {
+  return http.delete<any>(`system/dict/type/refreshCache`)
 }
 
 /**

+ 9 - 9
src/api/modules/system/dictData.ts

@@ -1,12 +1,12 @@
 import http from '@/api'
-
+import { DictDataForm, DictDataQuery, DictDataVO } from '@/api/interface/system/data'
 /**
  * @name 查询字典数据列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listDataApi = (query: any) => {
-  return http.get<any>('/system/dict/data/list', query, { loading: true })
+export const listDataApi = (query: DictDataQuery) => {
+  return http.get<DictDataVO[]>('/system/dict/data/list', query, { loading: true })
 }
 
 /**
@@ -14,8 +14,8 @@ export const listDataApi = (query: any) => {
  * @param dictCode dictCode
  * @returns returns
  */
-export const getDataApi = (dictCode: any) => {
-  return http.get<any>(`/system/dict/data/${dictCode}`)
+export const getDataApi = (dictCode: string | number) => {
+  return http.get<DictDataVO>(`/system/dict/data/${dictCode}`)
 }
 
 /**
@@ -24,7 +24,7 @@ export const getDataApi = (dictCode: any) => {
  * @returns returns
  */
 export const getDictsApi = (dictType: string) => {
-  return http.get<any>(`/system/dict/data/type/${dictType}`)
+  return http.get<DictDataVO[]>(`/system/dict/data/type/${dictType}`)
 }
 
 /**
@@ -32,7 +32,7 @@ export const getDictsApi = (dictType: string) => {
  * @param data data
  * @returns returns
  */
-export const addDataApi = (data: any) => {
+export const addDataApi = (data: DictDataForm) => {
   return http.post<any>('/system/dict/data', data, { loading: false })
 }
 
@@ -41,7 +41,7 @@ export const addDataApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const updateDataApi = (data: any) => {
+export const updateDataApi = (data: DictDataForm) => {
   return http.put<any>('/system/dict/data', data, { loading: false })
 }
 
@@ -50,7 +50,7 @@ export const updateDataApi = (data: any) => {
  * @param dictCode dictCode
  * @returns returns
  */
-export const delDataApi = (id: any) => {
+export const delDataApi = (id: string | number | Array<string | number>) => {
   return http.delete<any>(`/system/dict/data/${id}`)
 }
 

+ 14 - 37
src/api/modules/system/menu.ts

@@ -1,8 +1,9 @@
 import http from '@/api'
-
+import { MenuQuery, MenuVO, MenuForm, MenuTreeOption, RoleMenuTree } from '@/api/interface/system/menu'
+import { RouteRecordRaw } from 'vue-router'
 // 获取路由
 export const getRoutersApi = () => {
-  return http.get<Menu.MenuOptions[]>('/system/menu/getRouters', {}, { loading: false })
+  return http.get<RouteRecordRaw[]>('/system/menu/getRouters', {}, { loading: false })
 }
 
 /**
@@ -10,8 +11,8 @@ export const getRoutersApi = () => {
  * @param query 参数
  * @returns 返回列表
  */
-export const listMenuApi = (query?: any) => {
-  return http.get<any>('/system/menu/list', query, { loading: true })
+export const listMenuApi = (query?: MenuQuery) => {
+  return http.get<MenuVO[]>('/system/menu/list', query, { loading: true })
 }
 
 /**
@@ -19,8 +20,8 @@ export const listMenuApi = (query?: any) => {
  * @param menuId menuId
  * @returns returns
  */
-export const getMenuApi = (menuId: any) => {
-  return http.get<any>(`/system/menu/${menuId}`)
+export const getMenuApi = (menuId: string | number) => {
+  return http.get<MenuVO>(`/system/menu/${menuId}`)
 }
 
 /**
@@ -28,7 +29,7 @@ export const getMenuApi = (menuId: any) => {
  * @param data data
  * @returns returns
  */
-export const addMenuApi = (data: any) => {
+export const addMenuApi = (data: MenuForm) => {
   return http.post<any>('/system/menu', data, { loading: false })
 }
 
@@ -37,7 +38,7 @@ export const addMenuApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const updateMenuApi = (data: any) => {
+export const updateMenuApi = (data: MenuForm) => {
   return http.put<any>('/system/menu', data, { loading: false })
 }
 
@@ -46,40 +47,16 @@ export const updateMenuApi = (data: any) => {
  * @param menuId menuId
  * @returns returns
  */
-export const delMenuApi = (menuId: any) => {
+export const delMenuApi = (menuId: string | number) => {
   return http.delete<any>(`/system/menu/${menuId}`)
 }
 
-/**
- * @name 下载模板
- * @returns returns
- */
-export const importTemplateApi = () => {
-  return http.downloadPost('/system/menu/importTemplate', {})
-}
-
-/**
- * @name 导入数据
- * @returns returns
- */
-export const importDataApi = (data: any) => {
-  return http.post('/system/menu/importData', data)
-}
-
-/**
- * @name 导出数据
- * @returns returns
- */
-export const exportApi = (data: any) => {
-  return http.downloadPost('/system/menu/export', data)
-}
-
 /**
  * @name 查询菜单下拉树结构
  * @returns returns
  */
-export const treeselectApi = () => {
-  return http.get<any>(`/system/menu/treeselect`)
+export const treeSelectApi = () => {
+  return http.get<MenuTreeOption[]>(`/system/menu/treeselect`)
 }
 
 /**
@@ -87,6 +64,6 @@ export const treeselectApi = () => {
  * @param roleId roleId
  * @returns returns
  */
-export const roleMenuTreeselectApi = (roleId: any) => {
-  return http.get<any>(`/system/menu/roleMenuTreeselect/${roleId}`)
+export const roleMenuTreeselectApi = (roleId: string | number) => {
+  return http.get<RoleMenuTree>(`/system/menu/roleMenuTreeselect/${roleId}`)
 }

+ 28 - 0
src/api/modules/system/oss.ts

@@ -0,0 +1,28 @@
+import http from '@/api'
+import { OssQuery, OssVO } from '@/api/interface/system/oss'
+/**
+ * @name 查询OSS对象存储列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listOssApi = (query: OssQuery) => {
+  return http.get<OssVO[]>('/resource/oss/list', query, { loading: true })
+}
+
+/**
+ * @name 查询OSS对象基于id串
+ * @param ossId ossId
+ * @returns returns
+ */
+export const getListByIdsApi = (ossIds: string | number) => {
+  return http.get<OssVO[]>(`/resource/oss/listByIds/${ossIds}`)
+}
+
+/**
+ * @name 删除OSS对象存储
+ * @param ossId ossId
+ * @returns returns
+ */
+export const delOssApi = (ossId: string | number | Array<string | number>) => {
+  return http.delete<any>(`/resource/oss/${ossId}`)
+}

+ 62 - 0
src/api/modules/system/ossConfig.ts

@@ -0,0 +1,62 @@
+import http from '@/api'
+import { OssConfigForm, OssConfigQuery, OssConfigVO } from '@/api/interface/system/ossConfig'
+/**
+ * @name 查询对象存储配置列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listOssConfigApi = (query: OssConfigQuery) => {
+  return http.get<OssConfigVO[]>('/resource/oss/config/list', query, { loading: true })
+}
+
+/**
+ * @name 查询对象存储配置详细
+ * @param ossConfigId ossConfigId
+ * @returns returns
+ */
+export const getOssConfigApi = (ossConfigId: string | number) => {
+  return http.get<OssConfigVO>(`/resource/oss/config/${ossConfigId}`)
+}
+
+/**
+ * @name 新增对象存储配置
+ * @param data data
+ * @returns returns
+ */
+export const addOssConfigApi = (data: OssConfigForm) => {
+  return http.post<any>('/resource/oss/config', data, { loading: false })
+}
+
+/**
+ * @name 修改对象存储配置
+ * @param data data
+ * @returns returns
+ */
+export const updateOssConfigApi = (data: OssConfigForm) => {
+  return http.put<any>('/resource/oss/config', data, { loading: false })
+}
+/**
+ * @name 对象存储状态修改
+ * @param data data
+ * @returns returns
+ */
+export const changeOssConfigStatusApi = (data: { ossConfigId: string | number; version: number; status: string; configKey: string }) => {
+  return http.put<any>('/resource/oss/config/changeStatus', data, { loading: false })
+}
+
+/**
+ * @name 删除对象存储配置
+ * @param ossConfigId ossConfigId
+ * @returns returns
+ */
+export const delOssConfigApi = (ossConfigId: string | number | Array<string | number>) => {
+  return http.delete<any>(`/resource/oss/config/${ossConfigId}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/resource/oss/config/importTemplate', {})
+}

+ 7 - 6
src/api/modules/system/post.ts

@@ -1,12 +1,13 @@
 import http from '@/api'
+import { PostForm, PostQuery, PostVO } from '@/api/interface/system/post'
 
 /**
  * @name 查询岗位信息列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listPostApi = (query: any) => {
-  return http.get<any>('/system/post/list', query, { loading: true })
+export const listPostApi = (query: PostQuery) => {
+  return http.get<PostVO[]>('/system/post/list', query, { loading: true })
 }
 
 /**
@@ -14,7 +15,7 @@ export const listPostApi = (query: any) => {
  * @param postId postId
  * @returns returns
  */
-export const getPostApi = (postId: any) => {
+export const getPostApi = (postId: string | number) => {
   return http.get<any>(`/system/post/${postId}`)
 }
 
@@ -23,7 +24,7 @@ export const getPostApi = (postId: any) => {
  * @param data data
  * @returns returns
  */
-export const addPostApi = (data: any) => {
+export const addPostApi = (data: PostForm) => {
   return http.post<any>('/system/post', data, { loading: false })
 }
 
@@ -32,7 +33,7 @@ export const addPostApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const updatePostApi = (data: any) => {
+export const updatePostApi = (data: PostForm) => {
   return http.put<any>('/system/post', data, { loading: false })
 }
 
@@ -41,7 +42,7 @@ export const updatePostApi = (data: any) => {
  * @param postId postId
  * @returns returns
  */
-export const delPostApi = (postId: any) => {
+export const delPostApi = (postId: string | number | (string | number)[]) => {
   return http.delete<any>(`/system/post/${postId}`)
 }
 

+ 89 - 6
src/api/modules/system/role.ts

@@ -1,12 +1,32 @@
 import http from '@/api'
-
+import { RoleQuery, RoleVO, RoleDeptTree } from '@/api/interface/system/role'
+import { UserVO, UserQuery } from '@/api/interface/system/user'
+import { RoleMenuTree } from '@/api/interface/system/menu'
 /**
  * @name 查询角色信息列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listRoleApi = (query: any) => {
-  return http.get<any>('/system/role/list', query, { loading: true })
+export const listRoleApi = (query: RoleQuery) => {
+  return http.get<RoleVO[]>('/system/role/list', query, { loading: true })
+}
+
+/**
+ * @name 根据角色ID查询部门树结构
+ * @param roleId 角色Id
+ * @returns 返回列表
+ */
+export const deptTreeSelectApi = (roleId: string | number) => {
+  return http.get<RoleDeptTree>(`/system/role/deptTree/${roleId}`)
+}
+
+/**
+ * @name 根据角色ID查询菜单下拉树结构
+ * @param roleId 角色Id
+ * @returns 返回列表
+ */
+export const roleMenuTreeSelectApi = (roleId: any) => {
+  return http.get<RoleMenuTree>(`/system/menu/roleMenuTreeselect/${roleId}`)
 }
 
 /**
@@ -14,8 +34,8 @@ export const listRoleApi = (query: any) => {
  * @param roleId roleId
  * @returns returns
  */
-export const getRoleApi = (roleId: any) => {
-  return http.get<any>(`/system/role/${roleId}`)
+export const getRoleApi = (roleId: string | number) => {
+  return http.get<RoleVO>(`/system/role/${roleId}`)
 }
 
 /**
@@ -36,12 +56,30 @@ export const updateRoleApi = (data: any) => {
   return http.put<any>('/system/role', data, { loading: false })
 }
 
+/**
+ * @name 角色数据权限
+ * @param data data
+ * @returns returns
+ */
+export const dataScopeApi = (data: any) => {
+  return http.put<any>('/system/role/dataScope', data, { loading: false })
+}
+
+/**
+ * @name 修改角色状态
+ * @param data data
+ * @returns returns
+ */
+export const changeStatusApi = (data: { roleId: string | number; version: number; status: string }) => {
+  return http.put<any>('/system/role/changeStatus', data, { loading: false })
+}
+
 /**
  * @name 删除角色信息
  * @param roleId roleId
  * @returns returns
  */
-export const delRoleApi = (roleId: any) => {
+export const delRoleApi = (roleId: Array<string | number> | string | number) => {
   return http.delete<any>(`/system/role/${roleId}`)
 }
 
@@ -68,3 +106,48 @@ export const importDataApi = (data: any) => {
 export const exportApi = (data: any) => {
   return http.downloadPost('/system/role/export', data)
 }
+
+/**
+ * @name 查询角色已授权用户列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const allocatedUserListApi = (query: UserQuery) => {
+  return http.get<UserVO[]>(`/system/role/authUser/allocatedList`, query, { loading: true })
+}
+
+/**
+ * @name 查询角色未授权用户列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const unallocatedUserListApi = (query: UserQuery) => {
+  return http.get<UserVO[]>(`/system/role/authUser/unallocatedList`, query, { loading: true })
+}
+
+/**
+ * @name 取消用户授权角色
+ * @param data data
+ * @returns returns
+ */
+export const authUserCancelApi = (data: any) => {
+  return http.put<any>('/system/role/authUser/cancel', data, { loading: false })
+}
+
+/**
+ * @name 批量取消用户授权角色
+ * @param data data
+ * @returns returns
+ */
+export const authUserCancelAllApi = (data: any) => {
+  return http.put<any>('/system/role/authUser/cancelAll', data, { loading: false })
+}
+
+/**
+ * @name 授权用户选择
+ * @param data data
+ * @returns returns
+ */
+export const authUserSelectAllApi = (data: any) => {
+  return http.put<any>('/system/role/authUser/selectAll', data, { loading: false })
+}

+ 54 - 10
src/api/modules/system/user.ts

@@ -1,13 +1,14 @@
 import http from '@/api'
 import { parseStrEmpty } from '@/utils/common'
-
+import { UserForm, UserQuery, UserVO, UserInfoVO } from '@/api/interface/system/user'
+import { DeptVO } from '@/api/interface/system/dept'
 /**
  * @name 查询用户列表
  * @param query 参数
  * @returns 返回列表
  */
-export const listUserApi = (query: any) => {
-  return http.get<any>('/system/user/list', query, { loading: true })
+export const listUserApi = (query: UserQuery) => {
+  return http.get<UserVO[]>('/system/user/list', query, { loading: true })
 }
 
 /**
@@ -15,8 +16,8 @@ export const listUserApi = (query: any) => {
  * @param userId userId
  * @returns returns
  */
-export const getUserApi = (userId?: string) => {
-  return http.get<any>(`/system/user/` + parseStrEmpty(userId))
+export const getUserApi = (userId?: string | number) => {
+  return http.get<UserInfoVO>(`/system/user/` + parseStrEmpty(userId))
 }
 
 /**
@@ -24,14 +25,14 @@ export const getUserApi = (userId?: string) => {
  * @returns returns
  */
 export const deptTreeSelectApi = () => {
-  return http.get<any>(`/system/user/deptTree`)
+  return http.get<DeptVO[]>(`/system/user/deptTree`)
 }
 
 /**
  * @name 新增用户
  * @returns returns
  */
-export const addUserApi = (data: any) => {
+export const addUserApi = (data: UserForm) => {
   return http.post<any>('/system/user', data, { loading: false })
 }
 
@@ -39,7 +40,7 @@ export const addUserApi = (data: any) => {
  * @name 修改用户
  * @returns returns
  */
-export const updateUserApi = (data: any) => {
+export const updateUserApi = (data: UserForm) => {
   return http.put<any>('/system/user', data, { loading: false })
 }
 
@@ -47,7 +48,7 @@ export const updateUserApi = (data: any) => {
  * @name 删除用户
  * @returns returns
  */
-export const delUserApi = (userId: any) => {
+export const delUserApi = (userId: Array<string | number> | string | number) => {
   return http.delete<any>(`/system/user/${userId}`)
 }
 
@@ -57,10 +58,19 @@ export const delUserApi = (userId: any) => {
  * @param status status
  * @returns returns
  */
-export const changeUserStatus = (data: any) => {
+export const changeUserStatus = (data: { userId: number | string; version: number; status: string }) => {
   return http.put<any>('/system/user/changeStatus', data, { loading: false })
 }
 
+/**
+ * @name 用户密码重置
+ * @param data data
+ * @returns returns
+ */
+export const resetUserPwdApi = (data: any) => {
+  return http.put<any>('/system/user/resetPwd', data, { loading: false })
+}
+
 /**
  * @name 下载模板
  * @returns returns
@@ -84,3 +94,37 @@ export const importDataApi = (params: FormData) => {
 export const exportApi = (data: any) => {
   return http.downloadPost('/system/user/export', data)
 }
+
+/**
+ * @name 用户头像上传
+ * @param params params
+ * @returns returns
+ */
+export const uploadAvatarApi = (params: FormData) => {
+  return http.post<any>('/system/user/profile/avatar', params)
+}
+
+/**
+ * @name 查询用户个人信息
+ * @returns returns
+ */
+export const getUserProfileApi = () => {
+  return http.get<UserInfoVO>(`/system/user/profile`)
+}
+
+/**
+ * @name 修改用户个人信息
+ * @param data data
+ * @returns returns
+ */
+export const updateUserProfileApi = (data: UserForm) => {
+  return http.put<any>('/system/user/profile', data, { loading: false })
+}
+/**
+ * @name 修改用户密码
+ * @param data data
+ * @returns returns
+ */
+export const updateUserPwdApi = (data: { oldPassword: string; newPassword: string }) => {
+  return http.put<any>('system/user/profile/updatePwd', data, { loading: false })
+}

+ 36 - 0
src/api/modules/taais/task.ts

@@ -1,3 +1,4 @@
+import http from '@/api'
 import taskDataList from '@/assets/mock/taskData.json'
 import tableData from '@/assets/mock/tableData.json'
 
@@ -21,3 +22,38 @@ export const getTransferImgList1 = () => {
 export const getTransferImgList2 = () => {
   return tableData.transferImgList2
 }
+// /task/task/create
+/**
+ * @name 得到图像数据
+ * @param type type
+ * @returns returns
+ */
+export const getImageApi = (type: any) => {
+  return http.post<any>(`/task/task/getImage`, type)
+}
+/**
+ * @name 创建算法任务
+ * @param data data
+ * @returns returns
+ */
+export const createTaskApi = (data: any) => {
+  return http.post<any>(`/task/task/create`, data)
+}
+/**
+ * @name 算法查询
+ * @param data data
+ * @returns returns
+ */
+export const getAlgorithmApi = (type: any, subsystem: any) => {
+  return http.post<any>(`/task/task/getAlgorithm/${type}/${subsystem}`)
+  // return http.post<any>(`/task/task/getModel`, data)
+}
+/**
+ * @name 模型查询
+ * @param data data
+ * @returns returns
+ */
+export const getModelApi = (data: any) => {
+  return http.post<any>(`/task/task/getModel/${data}`)
+  // return http.post<any>(`/task/task/getModel`, data)
+}

+ 94 - 0
src/api/modules/task/bizProcess.ts

@@ -0,0 +1,94 @@
+import http from '@/api'
+import { BizProcessVO, BizProcessForm, BizProcessQuery } from '@/api/interface/task/bizProcess'
+/**
+ * @name 查询算法业务处理列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listBizProcessApi = (query: BizProcessQuery) => {
+  return http.get<BizProcessVO[]>('/task/bizProcess/list', query, { loading: false })
+}
+
+/**
+ * @name 查询算法业务处理详细
+ * @param id id
+ * @returns returns
+ */
+export const getBizProcessApi = (id: string | number) => {
+  return http.get<BizProcessVO>(`/task/bizProcess/${id}`)
+}
+
+/**
+ * @name 新增算法业务处理
+ * @param data data
+ * @returns returns
+ */
+export const addBizProcessApi = (data: BizProcessForm) => {
+  return http.post<any>('/task/bizProcess', data, { loading: false })
+}
+
+/**
+ * @name 修改算法业务处理
+ * @param data data
+ * @returns returns
+ */
+export const updateBizProcessApi = (data: BizProcessForm) => {
+  return http.put<any>('/task/bizProcess', data, { loading: false })
+}
+
+/**
+ * @name 删除算法业务处理
+ * @param id id
+ * @returns returns
+ */
+export const delBizProcessApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/bizProcess/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/bizProcess/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importBizProcessDataApi = (data: any) => {
+  return http.post('/task/bizProcess/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportBizProcessApi = (data: any) => {
+  return http.downloadPost('/task/bizProcess/export', data)
+}
+
+/**
+ * @name 查看训练结果
+ * @returns returns
+ */
+export const getTrainResultApi = (subtaskId: string | number) => {
+  return http.get(`/task/bizProcess/getTrainResult/${subtaskId}`)
+}
+
+/**
+ * @name 查看验证结果
+ * @returns returns
+ */
+export const getVerifyResultApi = (subtaskId: string | number) => {
+  return http.get(`/task/bizProcess/getVerifyResult/${subtaskId}`)
+}
+
+/**
+ * @name 查看测试结果
+ * @returns returns
+ */
+export const getTestResultApi = (subtaskId: string | number) => {
+  return http.get(`/task/bizProcess/getTestResult/${subtaskId}`)
+}

+ 70 - 0
src/api/modules/task/dataProcess.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { DataProcessVO, DataProcessForm, DataProcessQuery } from '@/api/interface/task/dataProcess'
+/**
+ * @name 查询算法数据处理列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataProcessApi = (query: DataProcessQuery) => {
+  return http.get<DataProcessVO[]>('/task/dataProcess/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法数据处理详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataProcessApi = (id: string | number) => {
+  return http.get<DataProcessVO>(`/task/dataProcess/${id}`)
+}
+
+/**
+ * @name 新增算法数据处理
+ * @param data data
+ * @returns returns
+ */
+export const addDataProcessApi = (data: DataProcessForm) => {
+  return http.post<any>('/task/dataProcess', data, { loading: false })
+}
+
+/**
+ * @name 修改算法数据处理
+ * @param data data
+ * @returns returns
+ */
+export const updateDataProcessApi = (data: DataProcessForm) => {
+  return http.put<any>('/task/dataProcess', data, { loading: false })
+}
+
+/**
+ * @name 删除算法数据处理
+ * @param id id
+ * @returns returns
+ */
+export const delDataProcessApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/dataProcess/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/dataProcess/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataProcessDataApi = (data: any) => {
+  return http.post('/task/dataProcess/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataProcessApi = (data: any) => {
+  return http.downloadPost('/task/dataProcess/export', data)
+}

+ 70 - 0
src/api/modules/task/dataSet.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { DataSetVO, DataSetForm, DataSetQuery } from '@/api/interface/task/dataSet'
+/**
+ * @name 查询算法数据集合列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listDataSetApi = (query: DataSetQuery) => {
+  return http.get<DataSetVO[]>('/task/dataSet/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法数据集合详细
+ * @param id id
+ * @returns returns
+ */
+export const getDataSetApi = (id: string | number) => {
+  return http.get<DataSetVO>(`/task/dataSet/${id}`)
+}
+
+/**
+ * @name 新增算法数据集合
+ * @param data data
+ * @returns returns
+ */
+export const addDataSetApi = (data: DataSetForm) => {
+  return http.post<any>('/task/dataSet', data, { loading: false })
+}
+
+/**
+ * @name 修改算法数据集合
+ * @param data data
+ * @returns returns
+ */
+export const updateDataSetApi = (data: DataSetForm) => {
+  return http.put<any>('/task/dataSet', data, { loading: false })
+}
+
+/**
+ * @name 删除算法数据集合
+ * @param id id
+ * @returns returns
+ */
+export const delDataSetApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/dataSet/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/dataSet/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importDataSetDataApi = (data: any) => {
+  return http.post('/task/dataSet/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportDataSetApi = (data: any) => {
+  return http.downloadPost('/task/dataSet/export', data)
+}

+ 70 - 0
src/api/modules/task/subtask.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { SubtaskVO, SubtaskForm, SubtaskQuery } from '@/api/interface/task/subtask'
+/**
+ * @name 查询算法子任务列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listSubtaskApi = (query: SubtaskQuery) => {
+  return http.get<SubtaskVO[]>('/task/subtask/list', query, { loading: false })
+}
+
+/**
+ * @name 查询算法子任务详细
+ * @param id id
+ * @returns returns
+ */
+export const getSubtaskApi = (id: string | number) => {
+  return http.get<SubtaskVO>(`/task/subtask/${id}`)
+}
+
+/**
+ * @name 新增算法子任务
+ * @param data data
+ * @returns returns
+ */
+export const addSubtaskApi = (data: SubtaskForm) => {
+  return http.post<any>('/task/subtask', data, { loading: false })
+}
+
+/**
+ * @name 修改算法子任务
+ * @param data data
+ * @returns returns
+ */
+export const updateSubtaskApi = (data: SubtaskForm) => {
+  return http.put<any>('/task/subtask', data, { loading: false })
+}
+
+/**
+ * @name 删除算法子任务
+ * @param id id
+ * @returns returns
+ */
+export const delSubtaskApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/subtask/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/subtask/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importSubtaskDataApi = (data: any) => {
+  return http.post('/task/subtask/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportSubtaskApi = (data: any) => {
+  return http.downloadPost('/task/subtask/export', data)
+}

+ 70 - 0
src/api/modules/task/subtaskDetail.ts

@@ -0,0 +1,70 @@
+import http from '@/api'
+import { SubtaskDetailVO, SubtaskDetailForm, SubtaskDetailQuery } from '@/api/interface/task/subtaskDetail'
+/**
+ * @name 查询算法子任务详情列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listSubtaskDetailApi = (query: SubtaskDetailQuery) => {
+  return http.get<SubtaskDetailVO[]>('/task/subtaskDetail/list', query, { loading: true })
+}
+
+/**
+ * @name 查询算法子任务详情详细
+ * @param id id
+ * @returns returns
+ */
+export const getSubtaskDetailApi = (id: string | number) => {
+  return http.get<SubtaskDetailVO>(`/task/subtaskDetail/${id}`)
+}
+
+/**
+ * @name 新增算法子任务详情
+ * @param data data
+ * @returns returns
+ */
+export const addSubtaskDetailApi = (data: SubtaskDetailForm) => {
+  return http.post<any>('/task/subtaskDetail', data, { loading: false })
+}
+
+/**
+ * @name 修改算法子任务详情
+ * @param data data
+ * @returns returns
+ */
+export const updateSubtaskDetailApi = (data: SubtaskDetailForm) => {
+  return http.put<any>('/task/subtaskDetail', data, { loading: false })
+}
+
+/**
+ * @name 删除算法子任务详情
+ * @param id id
+ * @returns returns
+ */
+export const delSubtaskDetailApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/subtaskDetail/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/subtaskDetail/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importSubtaskDetailDataApi = (data: any) => {
+  return http.post('/task/subtaskDetail/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportSubtaskDetailApi = (data: any) => {
+  return http.downloadPost('/task/subtaskDetail/export', data)
+}

+ 78 - 0
src/api/modules/task/task.ts

@@ -0,0 +1,78 @@
+import http from '@/api'
+import { TaskVO, TaskForm, TaskQuery } from '@/api/interface/task/task'
+/**
+ * @name 查询算法任务列表
+ * @param query 参数
+ * @returns 返回列表
+ */
+export const listTaskApi = (query: TaskQuery) => {
+  return http.get<TaskVO[]>('/task/task/list', query, { loading: true })
+}
+
+/**
+ * @name 查询所有算法
+ * @returns 返回列表
+ */
+export const getAlgorithmOptionApi = () => {
+  return http.get<TaskVO[]>('/task/task/getAlgorithmOption')
+}
+
+/**
+ * @name 查询算法任务详细
+ * @param id id
+ * @returns returns
+ */
+export const getTaskApi = (id: string | number) => {
+  return http.get<TaskVO>(`/task/task/${id}`)
+}
+
+/**
+ * @name 新增算法任务
+ * @param data data
+ * @returns returns
+ */
+export const addTaskApi = (data: TaskForm) => {
+  return http.post<any>('/task/task', data, { loading: false })
+}
+
+/**
+ * @name 修改算法任务
+ * @param data data
+ * @returns returns
+ */
+export const updateTaskApi = (data: TaskForm) => {
+  return http.put<any>('/task/task', data, { loading: false })
+}
+
+/**
+ * @name 删除算法任务
+ * @param id id
+ * @returns returns
+ */
+export const delTaskApi = (id: string | number | Array<string | number>) => {
+  return http.delete<any>(`/task/task/${id}`)
+}
+
+/**
+ * @name 下载模板
+ * @returns returns
+ */
+export const importTemplateApi = () => {
+  return http.downloadPost('/task/task/importTemplate', {})
+}
+
+/**
+ * @name 导入数据
+ * @returns returns
+ */
+export const importTaskDataApi = (data: any) => {
+  return http.post('/task/task/importData', data)
+}
+
+/**
+ * @name 导出数据
+ * @returns returns
+ */
+export const exportTaskApi = (data: any) => {
+  return http.downloadPost('/task/task/export', data)
+}

+ 19 - 19
src/api/modules/tool/gen.ts

@@ -1,12 +1,12 @@
 import http from '@/api'
-
+import { DbTableQuery, DbTableVO, TableQuery, TableVO, GenTableVO, DbTableForm } from '@/api/interface/tool/gen'
 /**
  * @name 查询生成表数据
- * @param query 参数
+ * @param query {TableQuery} 参数
  * @returns 返回列表
  */
-export const listTableApi = (query: any) => {
-  return http.get<any>('/tool/gen/list', query, { loading: true })
+export const listTableApi = (query: TableQuery) => {
+  return http.get<TableVO[]>('/tool/gen/list', query, { loading: true })
 }
 
 /**
@@ -14,8 +14,8 @@ export const listTableApi = (query: any) => {
  * @param query 参数
  * @returns 返回列表
  */
-export const listDbTableApi = (query: any) => {
-  return http.get<any>('/tool/gen/db/list', query, { loading: true })
+export const listDbTableApi = (query: DbTableQuery) => {
+  return http.get<DbTableVO[]>('/tool/gen/db/list', query, { loading: true })
 }
 
 /**
@@ -23,8 +23,8 @@ export const listDbTableApi = (query: any) => {
  * @param tableId tableId
  * @returns returns
  */
-export const getTableApi = (tableId: any) => {
-  return http.get<any>(`/tool/gen/${tableId}`)
+export const getTableApi = (tableId: string | number) => {
+  return http.get<GenTableVO>(`/tool/gen/${tableId}`)
 }
 
 /**
@@ -32,8 +32,8 @@ export const getTableApi = (tableId: any) => {
  * @param data data
  * @returns returns
  */
-export const updateGenTableApi = (data: any) => {
-  return http.put<any>('/tool/gen', data, { loading: false })
+export const updateGenTableApi = (data: DbTableForm) => {
+  return http.put<GenTableVO>('/tool/gen', data, { loading: false })
 }
 
 /**
@@ -41,8 +41,8 @@ export const updateGenTableApi = (data: any) => {
  * @param data data
  * @returns returns
  */
-export const importTableApi = (data: any) => {
-  return http.post<any>('/tool/gen/importTable', data, { loading: false })
+export const importTableApi = (data: { tables: string }) => {
+  return http.post<GenTableVO>('/tool/gen/importTable', data, { loading: false })
 }
 
 /**
@@ -50,7 +50,7 @@ export const importTableApi = (data: any) => {
  * @param tableId tableId
  * @returns returns
  */
-export const previewTableApi = (tableId: any) => {
+export const previewTableApi = (tableId: string | number) => {
   return http.get<any>(`/tool/gen/preview/${tableId}`)
 }
 
@@ -59,7 +59,7 @@ export const previewTableApi = (tableId: any) => {
  * @param tableId tableId
  * @returns returns
  */
-export const delTableApi = (tableId: any) => {
+export const delTableApi = (tableId: string | number | Array<string | number>) => {
   return http.delete<any>(`/tool/gen/${tableId}`)
 }
 
@@ -68,17 +68,17 @@ export const delTableApi = (tableId: any) => {
  * @param tableId tableId
  * @returns returns
  */
-export const genCodeApi = (tableId: any) => {
+export const genCodeApi = (tableId: string | number) => {
   return http.get<any>(`/tool/gen/genCode/${tableId}`)
 }
 
 /**
  * @name 同步数据库
- * @param tableName tableName
+ * @param tableId tableName
  * @returns returns
  */
-export const synchDbApi = (tableName: any) => {
-  return http.get<any>(`/tool/gen/syncDb/${tableName}`)
+export const synchDbApi = (tableId: string | number) => {
+  return http.get<any>(`/tool/gen/syncDb/${tableId}`)
 }
 
 /**
@@ -86,6 +86,6 @@ export const synchDbApi = (tableName: any) => {
  * @param tableId tableId
  * @returns returns
  */
-export const batchGenCodeApi = (tableId: any) => {
+export const batchGenCodeApi = (tableId: string | number) => {
   return http.downloadGet(`/tool/gen/batchGenCode?tables=${tableId}`)
 }

+ 6 - 4
src/api/modules/upload.ts

@@ -1,5 +1,5 @@
-import { Upload } from '@/api/interface/index'
-import { PORT1 } from '@/api/config/servicePort'
+// import { Upload } from '@/api/interface/index'
+// import { PORT1 } from '@/api/config/servicePort'
 import http from '@/api'
 
 /**
@@ -7,10 +7,12 @@ import http from '@/api'
  */
 // 图片上传
 export const uploadImg = (params: FormData) => {
-  return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/img`, params, { cancel: false })
+  // return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/img`, params, { cancel: false })
+  return http.post<any>('/common/upload', params, { cancel: false })
 }
 
 // 视频上传
 export const uploadVideo = (params: FormData) => {
-  return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/video`, params, { cancel: false })
+  // return http.post<any>(PORT1 + `/file/upload/video`, params, { cancel: false })
+  return http.post<any>('/common/uploads', params, { cancel: false })
 }

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 1
src/assets/images/logo.svg


+ 4 - 18
src/components/CustomDialog/index.vue

@@ -8,11 +8,10 @@
     :top="parameter.top"
     draggable
   >
-    <slot name="default" :model="parameter.model"></slot>
+    <slot name="default" :parameter="parameter"></slot>
     <template #footer>
       <span class="dialog-footer">
-        <el-button type="primary" v-if="parameter.isEdit" :loading="butLoading" @click="handleSubmit">确认</el-button>
-        <el-button @click="handleCancel">取消</el-button>
+        <slot name="footer" :parameter="parameter"></slot>
       </span>
     </template>
   </el-dialog>
@@ -20,7 +19,6 @@
 
 <script setup lang="ts" name="FormDialog">
 import { ref } from 'vue'
-import { ElMessage } from 'element-plus'
 
 export interface FormParameterProps {
   title: string // 标题
@@ -42,19 +40,6 @@ const parameter = ref<FormParameterProps>({
   model: {},
   api: undefined
 })
-// 提交
-const handleSubmit = () => {
-  butLoading.value = true
-  parameter.value.api!(parameter.value.model).then(res => {
-    if (res.code == 200) {
-      ElMessage.success('操作成功')
-      dialogVisible.value = false
-    } else {
-      console.log('message', res.message)
-    }
-  })
-  butLoading.value = false
-}
 
 // 取消按钮,重置表单,关闭弹框
 const handleCancel = () => {
@@ -70,6 +55,7 @@ const openDialog = (params: FormParameterProps) => {
 }
 
 defineExpose({
-  openDialog
+  openDialog,
+  handleCancel
 })
 </script>

+ 1 - 6
src/components/DictTag/index.vue

@@ -2,12 +2,7 @@
   <div>
     <template v-for="(item, index) in options">
       <template v-if="values.includes(item.value)">
-        <span
-          v-if="item.elTagType == 'default' || item.elTagType == ''"
-          :key="item.value"
-          :index="index"
-          :class="item.elTagClass"
-        >
+        <span v-if="item.elTagType == 'default' || item.elTagType == ''" :key="item.value" :index="index" :class="item.elTagClass">
           {{ item.label }}
         </span>
         <el-tag

+ 1 - 6
src/components/ECharts/config/index.ts

@@ -23,12 +23,7 @@ import type {
   RadarSeriesOption,
   GaugeSeriesOption
 } from 'echarts/charts'
-import type {
-  TitleComponentOption,
-  TooltipComponentOption,
-  GridComponentOption,
-  DatasetComponentOption
-} from 'echarts/components'
+import type { TitleComponentOption, TooltipComponentOption, GridComponentOption, DatasetComponentOption } from 'echarts/components'
 import type { ComposeOption } from 'echarts/core'
 import 'echarts-liquidfill'
 

+ 1 - 3
src/components/ECharts/index.vue

@@ -26,9 +26,7 @@ const props = withDefaults(defineProps<Props>(), {
 })
 
 const echartsStyle = computed(() => {
-  return props.width || props.height
-    ? { height: props.height + 'px', width: props.width + 'px' }
-    : { height: '100%', width: '100%' }
+  return props.width || props.height ? { height: props.height + 'px', width: props.width + 'px' } : { height: '100%', width: '100%' }
 })
 
 const chartRef = ref<HTMLDivElement | HTMLCanvasElement>()

+ 16 - 2
src/components/FormDialog/index.vue

@@ -5,9 +5,14 @@
     :title="parameter.title"
     :destroy-on-close="true"
     :width="parameter.width"
+    :top="parameter.top"
     draggable
   >
-    <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model" />
+    <ProFrom ref="proFormRef" :items-options="parameter.itemsOptions" :form-options="_options" :model="parameter.model">
+      <template #modelAddress="{}">
+        <FileUpload :file-size="4096" :file-type="['pt']" />
+      </template>
+    </ProFrom>
     <template #footer>
       <span class="dialog-footer">
         <el-button type="primary" v-if="parameter.isEdit" :loading="butLoading" @click="handleSubmit">确认</el-button>
@@ -21,6 +26,7 @@
 import { ref, ComputedRef, computed } from 'vue'
 import ProFrom from '@/components/ProForm/index.vue'
 import { ElMessage } from 'element-plus'
+import FileUpload from '@/components/Upload/File.vue'
 
 export interface FormParameterProps {
   title: string // 标题
@@ -28,6 +34,7 @@ export interface FormParameterProps {
   labelWidth?: number // label宽度
   api?: (params: any) => Promise<any> // 表单提交api
   isEdit?: boolean // 是否编辑
+  top?: string // 离顶部距离
   formOptions?: ProForm.FormOptions // 表单配置
   itemsOptions: ProForm.ItemsOptions[] // 动态表单字段配置
   model?: Record<ProForm.FormItem['prop'], ProForm.FormItem['value']> // 表单数据对象
@@ -40,6 +47,7 @@ const butLoading = ref(false)
 const parameter = ref<FormParameterProps>({
   title: '',
   width: 500,
+  top: '10vh',
   itemsOptions: [],
   formOptions: {},
   isEdit: true
@@ -56,11 +64,12 @@ const proFormRef = ref<InstanceType<typeof ProFrom> | null>(null)
 // 表单提交校验
 const handleSubmit = () => {
   const formEl = proFormRef.value?.proFormRef
+  const formModel = proFormRef.value?.formModel
   butLoading.value = true
   if (!formEl) return
   formEl.validate(valid => {
     if (valid) {
-      parameter.value.api!(parameter.value.model).then(res => {
+      parameter.value.api!({ ...formModel, ...parameter.value.model }).then(res => {
         if (res.code == 200) {
           proFormRef.value?.resetForm(formEl)
           ElMessage.success('操作成功')
@@ -78,8 +87,13 @@ const handleSubmit = () => {
 
 // 取消按钮,重置表单,关闭弹框
 const handleCancel = () => {
+  console.log(parameter.value.model)
   const formEl = proFormRef.value?.proFormRef
   if (!formEl) return
+  if (parameter.value.model?.url) {
+    ElMessage.info('请先删除已经上传的图片')
+    return
+  }
   proFormRef.value?.resetForm(formEl)
   butLoading.value = false
   dialogVisible.value = false

+ 1 - 3
src/components/Grid/components/GridItem.vue

@@ -58,9 +58,7 @@ const style = computed(() => {
     }
   } else {
     return {
-      gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset}/span ${
-        span + offset > cols.value ? cols.value : span + offset
-      }`,
+      gridColumn: `span ${span + offset > cols.value ? cols.value : span + offset}/span ${span + offset > cols.value ? cols.value : span + offset}`,
       marginLeft: offset !== 0 ? `calc(((100% + ${gap}px) / ${span + offset}) * ${offset})` : 'unset'
     }
   }

+ 1 - 3
src/components/Highlight/index.vue

@@ -1,7 +1,5 @@
 <template>
-  <pre
-    :class="'hx-scroll ' + lineNumbers"
-  ><code :class="'language-'+ type" v-html="Prism.highlight(code, Prism.languages[type], type)"></code></pre>
+  <pre :class="'hx-scroll ' + lineNumbers"><code :class="'language-'+ type" v-html="Prism.highlight(code, Prism.languages[type], type)"></code></pre>
 </template>
 <script setup lang="ts">
 import { onMounted, computed } from 'vue'

+ 1 - 2
src/components/HighlightDialog/index.vue

@@ -7,8 +7,7 @@
     :width="parameter.width"
     draggable
   >
-    <preview-code v-if="flag" :code="parameter.code" :type="parameter.type" :is-show-line-numbers="parameter.isShowLineNumbers">
-    </preview-code>
+    <preview-code v-if="flag" :code="parameter.code" :type="parameter.type" :is-show-line-numbers="parameter.isShowLineNumbers"> </preview-code>
     <template #footer>
       <span class="dialog-footer">
         <el-button type="primary" v-if="parameter.isEdit" :loading="butLoading">导出</el-button>

+ 73 - 0
src/components/ImagePreview/index.vue

@@ -0,0 +1,73 @@
+<template>
+  <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
+    <template #error>
+      <div class="image-slot">
+        <el-icon><picture-filled /></el-icon>
+      </div>
+    </template>
+  </el-image>
+</template>
+
+<script setup lang="ts" name="ImgPreview">
+import { computed } from 'vue'
+
+interface ImgPreviewProps {
+  src: string
+  height?: string | number // 组件高度 ==> 非必传(默认为 150px)
+  width?: string | number // 组件宽度 ==> 非必传(默认为 150px)
+}
+
+const props = withDefaults(defineProps<ImgPreviewProps>(), {
+  src: '',
+  height: '150px',
+  width: '150px'
+})
+
+const realSrc = computed(() => {
+  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: string) => {
+    return srcList.push(item)
+  })
+  return srcList
+})
+
+const realWidth = computed(() => (typeof props.width == 'string' ? props.width : `${props.width}px`))
+
+const realHeight = computed(() => (typeof props.height == 'string' ? props.height : `${props.height}px`))
+</script>
+
+<style lang="scss" scoped>
+.el-image {
+  background-color: #ebeef5;
+  border-radius: 5px;
+  box-shadow: 0 0 5px 1px #cccccc;
+  :deep(.el-image__inner) {
+    cursor: pointer;
+    transition: all 0.3s;
+    &:hover {
+      transform: scale(1.2);
+    }
+  }
+  :deep(.image-slot) {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    font-size: 30px;
+    color: #909399;
+  }
+}
+</style>

+ 2 - 14
src/components/ImportExcel/index.vue

@@ -1,12 +1,5 @@
 <template>
-  <el-dialog
-    v-model="dialogVisible"
-    :width="parameter.width"
-    :top="parameter.top"
-    :title="`${parameter.title}`"
-    :destroy-on-close="true"
-    draggable
-  >
+  <el-dialog v-model="dialogVisible" :width="parameter.width" :top="parameter.top" :title="`${parameter.title}`" :destroy-on-close="true" draggable>
     <el-form class="drawer-multiColumn-form" label-width="100px">
       <el-form-item label="文件上传">
         <el-upload
@@ -38,12 +31,7 @@
               </div>
               <div class="el-upload__tip text-center">
                 请上传 .xls , .xlsx 标准格式文件,文件最大为 {{ parameter.fileSize }}M。
-                <el-link
-                  type="primary"
-                  :underline="false"
-                  style="font-size: 12px; vertical-align: baseline"
-                  @click="downloadTemp"
-                >
+                <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="downloadTemp">
                   模板下载
                 </el-link>
               </div>

+ 3 - 0
src/components/ImportPicDataset/index.scss

@@ -0,0 +1,3 @@
+.upload {
+  width: 80%;
+}

+ 261 - 0
src/components/ImportPicDataset/index.vue

@@ -0,0 +1,261 @@
+<template>
+  <el-dialog v-model="dialogVisible" :width="parameter.width" :top="parameter.top" :title="`${parameter.title}`" :destroy-on-close="true" draggable>
+    <el-form class="drawer-multiColumn-form" label-width="100px">
+      <el-form-item label="图片数据集压缩文件上传">
+        <el-upload
+          action="#"
+          class="upload"
+          :drag="true"
+          :show-file-list="true"
+          :http-request="uploadZip"
+          :before-upload="beforeZipUpload"
+          :on-exceed="handleExceed"
+          :accept="parameter.ZipFileType!.join(',')"
+        >
+          <slot name="empty">
+            <el-icon class="el-icon--upload">
+              <upload-filled />
+            </el-icon>
+            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+          </slot>
+          <template #tip>
+            <slot name="tip">
+              <!-- <div class="el-upload__tip text-center">
+                <el-checkbox v-model="isCover">是否更新已存在的数据</el-checkbox>
+              </div> -->
+              <div class="el-upload__tip text-center">
+                请上传 .zip 标准格式文件,文件最大为 {{ parameter.fileSize }}M。
+                <!-- <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="downloadTemp">
+                  模板下载
+                </el-link> -->
+              </div>
+            </slot>
+          </template>
+        </el-upload>
+      </el-form-item>
+
+      <el-form-item label="文件上传">
+        <el-upload
+          action="#"
+          class="upload"
+          :drag="true"
+          :limit="parameter.limit"
+          :multiple="parameter.multiple"
+          :show-file-list="true"
+          :http-request="uploadExcel"
+          :before-upload="beforeExcelUpload"
+          :on-exceed="handleExceed"
+          :accept="parameter.fileType!.join(',')"
+        >
+          <slot name="empty">
+            <el-icon class="el-icon--upload">
+              <upload-filled />
+            </el-icon>
+            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+          </slot>
+          <template #tip>
+            <slot name="tip">
+              <!-- <div class="el-upload__tip text-center">
+                <el-checkbox v-model="isCover">是否更新已存在的数据</el-checkbox>
+              </div> -->
+              <div class="el-upload__tip text-center">
+                请上传 .xls , .xlsx 标准格式文件,文件最大为 {{ parameter.fileSize }}M。
+                <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="downloadTemp">
+                  模板下载
+                </el-link>
+              </div>
+            </slot>
+          </template>
+        </el-upload>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button type="primary" @click="handleSubmit">确认</el-button>
+        <el-button @click="dialogVisible = false">取消</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="ImportPicDataset">
+import { ref } from 'vue'
+import { useDownload } from '@/hooks/useDownload'
+import { ElNotification, UploadRequestOptions, UploadRawFile } from 'element-plus'
+
+export interface ParameterProps {
+  title: string // 标题
+  fileSize?: number // 上传文件的大小
+  limit?: number // 上传文件个数
+  top?: string // 离顶部距离
+  width?: number // 弹框宽度
+  multiple?: boolean // 是否支持多选文件
+  fileType?: File.ExcelMimeType[] // 上传文件的类型
+  ZipFileType?: File.ZipMimeType[] //上传zip文件的类型
+  tempApi?: (params: any) => Promise<any> // 下载模板的Api
+  importApi?: (params: any) => Promise<any> // 批量导入的Api
+  getTableList?: () => void // 获取表格数据的Api
+}
+
+// 是否覆盖数据
+// const isCover = ref(false)
+// dialog状态
+const dialogVisible = ref(false)
+// 父组件传过来的参数
+const parameter = ref<ParameterProps>({
+  title: '',
+  limit: 1,
+  width: 500,
+  top: '20vh',
+  multiple: false,
+  fileSize: 4096,
+  fileType: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
+  ZipFileType: ['application/zip', 'application/x-zip-compressed', 'application/x-rar-compressed']
+})
+
+// 接收父组件参数
+const acceptParams = (params: ParameterProps) => {
+  parameter.value = { ...parameter.value, ...params }
+  dialogVisible.value = true
+}
+
+// Excel 导入模板下载
+const downloadTemp = () => {
+  if (!parameter.value.tempApi) return
+  useDownload(parameter.value.tempApi, `${parameter.value.title}_template_${new Date().getTime()}`)
+}
+// const uploadRef = ref<UploadInstance>()
+
+const formData = new FormData()
+const handleSubmit = async () => {
+  const zipFile = formData.get('file')
+  const excelFile = formData.get('excelFile')
+  console.log(zipFile)
+  console.log(excelFile)
+  // 检查是否同时上传了压缩文件和 Excel 文件
+  if (!zipFile || !excelFile) {
+    ElNotification({
+      title: '温馨提示',
+      message: '请同时上传一个压缩文件和一个Excel文件!',
+      type: 'warning'
+    })
+    return
+  }
+
+  try {
+    // 同时上传了两个文件,可以进行提交处理
+    await parameter.value.importApi!(formData)
+
+    ElNotification({
+      title: '温馨提示',
+      message: `文件上传成功`,
+      type: 'success'
+    })
+
+    parameter.value.getTableList && parameter.value.getTableList()
+    dialogVisible.value = false
+  } catch (error) {
+    ElNotification({
+      title: '温馨提示',
+      message: `文件上传失败,请重新上传`,
+      type: 'error'
+    })
+  }
+}
+
+// 压缩文件上传
+const uploadZip = (param: UploadRequestOptions) => {
+  formData.append('file', param.file)
+
+  // parameter.value.getTableList && parameter.value.getTableList()
+  // dialogVisible.value = false
+}
+
+// 文件上传
+const uploadExcel = (param: UploadRequestOptions) => {
+  formData.append('excelFile', param.file)
+
+  // parameter.value.getTableList && parameter.value.getTableList()
+  // dialogVisible.value = false
+}
+
+/**
+ * @description 文件上传之前判断
+ * @param file 上传的文件
+ * */
+const beforeExcelUpload = (file: UploadRawFile) => {
+  const isExcel = parameter.value.fileType!.includes(file.type as File.ExcelMimeType)
+
+  const fileSize = file.size / 1024 / 1024 < parameter.value.fileSize!
+  if (!isExcel)
+    ElNotification({
+      title: '温馨提示',
+      message: '上传文件只能是 xls / xlsx 格式!',
+      type: 'warning'
+    })
+  if (!fileSize)
+    setTimeout(() => {
+      ElNotification({
+        title: '温馨提示',
+        message: `上传文件大小不能超过 ${parameter.value.fileSize}MB!`,
+        type: 'warning'
+      })
+    }, 0)
+  return isExcel && fileSize
+}
+
+const beforeZipUpload = (file: UploadRawFile) => {
+  const isZip = parameter.value.ZipFileType!.includes(file.type as File.ZipMimeType)
+
+  const fileSize = file.size / 1024 / 1024 < parameter.value.fileSize!
+  if (!isZip)
+    ElNotification({
+      title: '温馨提示',
+      message: '上传文件只能是 zip 格式!',
+      type: 'warning'
+    })
+  if (!fileSize)
+    setTimeout(() => {
+      ElNotification({
+        title: '温馨提示',
+        message: `上传文件大小不能超过 ${parameter.value.fileSize}MB!`,
+        type: 'warning'
+      })
+    }, 0)
+  return isZip && fileSize
+}
+
+// 文件数超出提示
+const handleExceed = () => {
+  ElNotification({
+    title: '温馨提示',
+    message: '最多只能上传一个文件!',
+    type: 'warning'
+  })
+}
+
+// 上传错误提示
+// const excelUploadError = () => {
+//   ElNotification({
+//     title: '温馨提示',
+//     message: `批量添加${parameter.value.title}失败,请您重新上传!`,
+//     type: 'error'
+//   })
+// }
+
+// 上传成功提示
+// const excelUploadSuccess = () => {
+//   ElNotification({
+//     title: '温馨提示',
+//     message: `批量添加${parameter.value.title}成功!`,
+//     type: 'success'
+//   })
+// }
+
+defineExpose({
+  acceptParams
+})
+</script>
+<style lang="scss" scoped>
+@import './index.scss';
+</style>

+ 4 - 4
src/components/Loading/fullScreen.ts

@@ -6,11 +6,11 @@ let loadingInstance: ReturnType<typeof ElLoading.service>
 /**
  * @description 开启 Loading
  * */
-const startLoading = () => {
+const startLoading = (content: string) => {
   loadingInstance = ElLoading.service({
     fullscreen: true,
     lock: true,
-    text: 'Loading',
+    text: content,
     background: 'rgba(0, 0, 0, 0.7)'
   })
 }
@@ -26,9 +26,9 @@ const endLoading = () => {
  * @description 显示全屏加载
  * */
 let needLoadingRequestCount = 0
-export const showFullScreenLoading = () => {
+export const showFullScreenLoading = (content: string = 'Loading') => {
   if (needLoadingRequestCount === 0) {
-    startLoading()
+    startLoading(content)
   }
   needLoadingRequestCount++
 }

+ 4 - 14
src/components/ProForm/components/Item.vue

@@ -3,7 +3,7 @@
     :is="elTagNameValue"
     v-bind="item.compOptions"
     v-model.trim="_formModel[handleProp(item.prop)]"
-    :data="['tree-select', 'tree'].includes(item.compOptions.elTagName!) ? itemEnum : []"
+    :data="['tree-select'].includes(item.compOptions.elTagName!) ? itemEnum : []"
     :options="['cascader', 'select-v2'].includes(item.compOptions.elTagName!) ? itemEnum : []"
   >
     <template v-if="item.compOptions.elTagName === 'cascader'" #default="{ data }">
@@ -19,22 +19,12 @@
       ></component>
     </template>
     <template v-if="item.compOptions.elTagName === 'radio-group'">
-      <component
-        :is="`el-radio`"
-        v-for="(col, index) in itemEnum"
-        :key="index"
-        :label="col[item.compOptions.valueKey || 'value']"
-      >
+      <component :is="`el-radio`" v-for="(col, index) in itemEnum" :key="index" :value="col[item.compOptions.valueKey || 'value']">
         {{ col[item.compOptions.labelKey || 'label'] }}
       </component>
     </template>
     <template v-if="item.compOptions.elTagName === 'radio-button'">
-      <component
-        :is="`el-radio-button`"
-        v-for="(col, index) in itemEnum"
-        :key="index"
-        :label="col[item.compOptions.valueKey || 'value']"
-      >
+      <component :is="`el-radio-button`" v-for="(col, index) in itemEnum" :key="index" :value="col[item.compOptions.valueKey || 'value']">
         {{ col[item.compOptions.labelKey || 'label'] }}
       </component>
     </template>
@@ -43,7 +33,7 @@
         :is="`el-checkbox`"
         v-for="col in itemEnum"
         :key="col[item.compOptions.valueKey || 'value']"
-        :label="col[item.compOptions.valueKey || 'value']"
+        :value="col[item.compOptions.valueKey || 'value']"
       >
         {{ col[item.compOptions.labelKey || 'label'] }}
       </component>

+ 53 - 16
src/components/ProForm/index.vue

@@ -2,8 +2,8 @@
   <component :is="'el-form'" v-bind="_formOptions" ref="proFormRef" :model="formModel">
     <el-row :gutter="5">
       <template v-for="item in itemsOptions" :key="item.prop">
-        <el-col :span="item.span || 24" g>
-          <component :is="'el-form-item'" v-bind="item" v-if="show(item.show)">
+        <el-col :span="item.span || 24" g v-if="show(item.show)">
+          <component :is="'el-form-item'" v-bind="item">
             <template #label>
               <el-space :size="4">
                 <span class="label-span">{{ `${item.label}` }}</span>
@@ -14,14 +14,32 @@
                   <i :class="'iconfont icon-yiwen'"></i>
                 </el-tooltip>
               </el-space>
-              <span>{{ `${_formOptions.labelSuffix}` }}</span>
-            </template>
-            <template v-if="item.compOptions.elTagName === 'slot'">
-              <slot :name="item.prop" :form-model="formModel"></slot>
+              <span v-if="item.hideLabelSuffix">{{ `${item.hideLabelSuffix ? '' : ':'}` }}</span>
+              <span v-else>{{ `${_formOptions.labelSuffix}` }}</span>
             </template>
+            <!-- <template v-if="item.compOptions.elTagName === 'slot'"> -->
+            <slot :name="item.prop" :form-model="formModel"></slot>
+            <slot name="default" :form-model="formModel"></slot>
+            <!-- </template> -->
             <template v-if="item.compOptions.elTagName === 'icon'">
               <SelectIcon v-model:icon-value="formModel[item.prop]" />
             </template>
+            <template v-else-if="item.compOptions.elTagName === 'file-upload'">
+              <FileUpload v-model:model-value="formModel[item.prop]" v-bind="$attrs" />
+            </template>
+            <template v-else-if="item.compOptions.elTagName === 'img-upload'">
+              <uploadImg v-model:image-url="formModel[item.prop]" />
+            </template>
+
+            <template v-else-if="item.compOptions.elTagName === 'imgs-upload'">
+              <Imgs v-model="formModel[item.prop]" v-bind="$attrs" />
+            </template>
+            <template v-else-if="item.compOptions.elTagName === 'file-upload-s3'">
+              <FileUploadS3 v-model:model-value="formModel[item.prop]" />
+            </template>
+            <template v-else-if="item.compOptions.elTagName === 'imgs-upload-s3'">
+              <ImgsS3 v-model="formModel[item.prop]" v-bind="$attrs" />
+            </template>
             <Item v-else :item="item" :form-model="formModel" />
           </component>
         </el-col>
@@ -29,9 +47,7 @@
     </el-row>
     <el-form-item v-if="_formOptions.hasFooter">
       <slot name="operation" :form-model="formModel" :model="formModel" :pro-form-ref="proFormRef">
-        <el-button type="primary" v-if="_formOptions.showSubmitButton" @click="onSubmit(proFormRef)">{{
-          _formOptions.submitButtonText
-        }}</el-button>
+        <el-button type="primary" v-if="_formOptions.showSubmitButton" @click="onSubmit(proFormRef)">{{ _formOptions.submitButtonText }}</el-button>
         <el-button v-if="_formOptions.showResetButton" type="info" @click="resetForm(proFormRef)">
           {{ _formOptions.resetButtonText }}
         </el-button>
@@ -45,15 +61,21 @@
 
 <script setup lang="ts" name="ProForm">
 import { ref, computed, ComputedRef, watch, unref, provide } from 'vue'
-import type { FormInstance } from 'element-plus'
+import { ElMessage, type FormInstance } from 'element-plus'
 import Item from '@/components/ProForm/components/Item.vue'
 import SelectIcon from '@/components/SelectIcon/index.vue'
+import FileUpload from '@/components/Upload/File.vue'
+import uploadImg from '@/components/Upload/Img.vue'
+import Imgs from '@/components/Upload/Imgs.vue'
+import FileUploadS3 from '@/components/Upload/FileS3.vue'
+import ImgsS3 from '@/components/Upload/ImgsS3.vue'
 // import { handleProp } from '@/utils'
 // 表单整体配置项
 export interface ProFormProps {
   formOptions?: ProForm.FormOptions
   itemsOptions: ProForm.ItemsOptions[]
   model?: Record<ProForm.FormItem['prop'], ProForm.FormItem['value']>
+  api?: (params: any) => Promise<any> // 表单提交api
 }
 
 // 表单的数据
@@ -82,8 +104,7 @@ const _formOptions: ComputedRef<ProForm.FormOptions> = computed(() => {
     labelWidth: 120,
     disabled: false,
     hasFooter: true,
-    labelSuffix: ': ',
-    showSubmitButton: true,
+    labelSuffix: ':',
     submitButtonText: '提交',
     resetButtonText: '重置',
     cancelButtonText: '取消'
@@ -125,27 +146,42 @@ props.itemsOptions.forEach(async item => {
   await setEnumMap(item)
 })
 const emits = defineEmits<EmitEvent>()
+// 监听itemsOptions变化
+watch(props, () => {
+  // 处理表单项需要的参数
+  props.itemsOptions.forEach(async item => {
+    await setEnumMap(item)
+  })
+})
 // 根据items初始化model, 如果items有传值就用传递的model数据模型,否则就给上面声明的formModel设置相应的(key,value) [item.prop], item.value是表单的默认值(选填)
 watch(
   () => props.model,
   () => {
     props.itemsOptions.map((item: ProForm.ItemsOptions) => {
       // 如果类型为checkbox,默认值需要设置一个空数组
-      const value = ['checkbox', 'transfer'].includes(item.compOptions.elTagName!) ? [] : ''
-      props.model ? (formModel.value = props.model) : (formModel.value[item.prop] = item.value || value)
+      let value = ['checkbox', 'transfer'].includes(item.compOptions.elTagName!) ? [] : props.model[item.prop]
+      props.model[item.prop] ? (formModel.value = props.model) : (formModel.value[item.prop] = item.compOptions.value || value)
     })
   },
   { immediate: true }
 )
-
 // 提交按钮
 const onSubmit = (formEl: FormInstance | undefined) => {
   console.log('表单提交数据', formModel.value)
   if (!formEl) return
   formEl.validate(valid => {
     if (valid) {
-      emits('submit', formModel.value)
+      if (props.api) emits('submit', formModel.value)
+      props.api!({ ...formModel }).then(res => {
+        if (res.code == 200) {
+          resetForm(formEl)
+          ElMessage.success('操作成功')
+        } else {
+          console.log('message', res.message)
+        }
+      })
     } else {
+      console.log('校验失败')
     }
   })
 }
@@ -165,6 +201,7 @@ const resetForm = (formEl: FormInstance | undefined) => {
 // 暴露方法给父组件使用
 defineExpose({
   proFormRef,
+  formModel,
   resetForm,
   onSubmit
 })

+ 2 - 2
src/components/ProFormOld/index.vue

@@ -16,7 +16,7 @@
               <!-- 单选框 -->
               <el-radio-group v-if="item.type === 'radio'" v-model="formModel[item.field]" :disabled="item.disabled">
                 <el-radio
-                  :label="val[item.options?.valueKey || 'value']"
+                  :value="val[item.options?.valueKey || 'value']"
                   v-for="val in item.options?.data"
                   :key="val[item.options?.valueKey || 'value']"
                 >
@@ -28,7 +28,7 @@
                 <el-checkbox
                   v-for="val in item.options?.data"
                   :key="val[item.options?.valueKey || 'value']"
-                  :label="val[item.options?.valueKey || 'value']"
+                  :value="val[item.options?.valueKey || 'value']"
                   >{{ val[item.options?.labelKey || 'label'] }}
                 </el-checkbox>
               </el-checkbox-group>

+ 1 - 5
src/components/ProTable/components/TableColumn.vue

@@ -29,11 +29,7 @@ const RenderTableColumn = (item: ColumnProps) => {
   return (
     <>
       {item.isShow && (
-        <el-table-column
-          {...item}
-          align={item.align ?? 'center'}
-          showOverflowTooltip={item.showOverflowTooltip ?? item.prop !== 'operation'}
-        >
+        <el-table-column {...item} align={item.align ?? 'center'} showOverflowTooltip={item.showOverflowTooltip ?? item.prop !== 'operation'}>
           {{
             default: (scope: RenderScope<any>) => {
               if (item._children) return item._children.map(child => RenderTableColumn(child))

+ 15 - 41
src/components/ProTable/index.vue

@@ -1,13 +1,6 @@
 <template>
   <!-- 查询表单 -->
-  <SearchForm
-    v-show="isShowSearch"
-    :search="_search"
-    :reset="_reset"
-    :columns="searchColumns"
-    :search-param="searchParam"
-    :search-col="searchCol"
-  />
+  <SearchForm v-show="isShowSearch" :search="_search" :reset="_reset" :columns="searchColumns" :search-param="searchParam" :search-col="searchCol" />
 
   <!-- 表格主体 -->
   <div class="card table-main">
@@ -18,26 +11,14 @@
       </div>
       <div v-if="toolButton" class="header-button-ri">
         <slot name="toolButton">
-          <el-button v-if="showToolButton('refresh')" :icon="Refresh" circle @click="getTableList" />
-          <el-button v-if="showToolButton('setting') && columns.length" :icon="Operation" circle @click="openColSetting" />
-          <el-button
-            v-if="showToolButton('search') && searchColumns?.length"
-            :icon="Search"
-            circle
-            @click="isShowSearch = !isShowSearch"
-          />
+          <el-button v-if="showToolButton('refresh')" icon="Refresh" circle @click="getTableList" />
+          <el-button v-if="showToolButton('setting') && columns.length" icon="Operation" circle @click="openColSetting" />
+          <el-button v-if="showToolButton('search') && searchColumns?.length" icon="Search" circle @click="isShowSearch = !isShowSearch" />
         </slot>
       </div>
     </div>
     <!-- 表格主体 -->
-    <el-table
-      ref="tableRef"
-      v-bind="$attrs"
-      :data="processTableData"
-      :border="border"
-      :row-key="rowKey"
-      @selection-change="selectionChange"
-    >
+    <el-table ref="tableRef" v-bind="$attrs" :data="processTableData" :border="border" :row-key="rowKey" @selection-change="selectionChange">
       <!-- 默认插槽 -->
       <slot />
       <template v-for="item in tableColumns" :key="item">
@@ -87,12 +68,7 @@
     </el-table>
     <!-- 分页组件 -->
     <slot name="pagination">
-      <Pagination
-        v-if="pagination"
-        :pageable="pageable"
-        :handle-size-change="handleSizeChange"
-        :handle-current-change="handleCurrentChange"
-      />
+      <Pagination v-if="pagination" :pageable="pageable" :handle-size-change="handleSizeChange" :handle-current-change="handleCurrentChange" />
     </slot>
   </div>
   <!-- 列设置 -->
@@ -106,7 +82,6 @@ import { useTable } from '@/hooks/useTable'
 import { useSelection } from '@/hooks/useSelection'
 import { BreakPoint } from '@/components/Grid/interface'
 import { ColumnProps, TypeProps } from '@/components/ProTable/interface'
-import { Refresh, Operation, Search } from '@element-plus/icons-vue'
 import { handleProp } from '@/utils'
 import SearchForm from '@/components/SearchForm/index.vue'
 import Pagination from './components/Pagination.vue'
@@ -163,10 +138,14 @@ const radio = ref('')
 
 // 表格多选 Hooks
 const { selectionChange, selectedList, selectedListIds, isSelected } = useSelection(props.rowKey)
-
 // 表格操作 Hooks
-const { tableData, pageable, searchParam, searchInitParam, getTableList, search, reset, handleSizeChange, handleCurrentChange } =
-  useTable(props.requestApi, props.initParam, props.pagination, props.dataCallback, props.requestError)
+const { tableData, pageable, searchParam, searchInitParam, getTableList, search, reset, handleSizeChange, handleCurrentChange } = useTable(
+  props.requestApi,
+  props.initParam,
+  props.pagination,
+  props.dataCallback,
+  props.requestError
+)
 
 // 清空选中数据列表
 const clearSelection = () => tableRef.value!.clearSelection()
@@ -182,10 +161,7 @@ onMounted(() => {
 const processTableData = computed(() => {
   if (!props.data) return tableData.value
   if (!props.pagination) return props.data
-  return props.data.slice(
-    (pageable.value.pageNum - 1) * pageable.value.pageSize,
-    pageable.value.pageSize * pageable.value.pageNum
-  )
+  return props.data.slice((pageable.value.pageNum - 1) * pageable.value.pageSize, pageable.value.pageSize * pageable.value.pageNum)
 })
 
 // 监听页面 initParam 改化,重新获取表格数据
@@ -237,9 +213,7 @@ const flatColumnsFunc = (columns: ColumnProps[], flatArr: ColumnProps[] = []) =>
 
 // 过滤需要搜索的配置项 && 排序
 const searchColumns = computed(() => {
-  return flatColumns.value
-    ?.filter(item => item.search?.el || item.search?.render)
-    .sort((a, b) => a.search!.order! - b.search!.order!)
+  return flatColumns.value?.filter(item => item.search?.el || item.search?.render).sort((a, b) => a.search!.order! - b.search!.order!)
 })
 
 // 设置 搜索表单默认排序 && 搜索表单项的默认值

+ 1 - 2
src/components/ProTable/interface/index.ts

@@ -68,8 +68,7 @@ export type HeaderRenderScope<T> = {
   [key: string]: any
 }
 
-export interface ColumnProps<T = any>
-  extends Partial<Omit<TableColumnCtx<T>, 'type' | 'children' | 'renderCell' | 'renderHeader'>> {
+export interface ColumnProps<T = any> extends Partial<Omit<TableColumnCtx<T>, 'type' | 'children' | 'renderCell' | 'renderHeader'>> {
   type?: TypeProps // 列类型
   tag?: boolean | Ref<boolean> // 是否是标签展示
   isShow?: boolean | Ref<boolean> // 是否显示在表格当中

+ 3 - 3
src/components/SearchForm/index.vue

@@ -18,8 +18,8 @@
         </GridItem>
         <GridItem suffix>
           <div class="operation">
-            <el-button type="primary" :icon="Search" @click="search"> 搜索 </el-button>
-            <el-button :icon="Delete" @click="reset"> 重置 </el-button>
+            <el-button type="primary" icon="Search" @click="search"> 搜索 </el-button>
+            <el-button icon="Delete" @click="reset"> 重置 </el-button>
             <el-button v-if="showCollapse" type="primary" link class="search-isOpen" @click="collapsed = !collapsed">
               {{ collapsed ? '展开' : '合并' }}
               <el-icon class="el-icon--right">
@@ -36,7 +36,7 @@
 import { computed, ref } from 'vue'
 import { ColumnProps } from '@/components/ProTable/interface'
 import { BreakPoint } from '@/components/Grid/interface'
-import { Delete, Search, ArrowDown, ArrowUp } from '@element-plus/icons-vue'
+import { ArrowDown, ArrowUp } from '@element-plus/icons-vue'
 import SearchFormItem from './components/SearchFormItem.vue'
 import Grid from '@/components/Grid/index.vue'
 import GridItem from '@/components/Grid/components/GridItem.vue'

+ 1 - 3
src/components/SelectFilter/index.vue

@@ -11,9 +11,7 @@
             v-for="option in item.options"
             :key="option.value"
             :class="{
-              active:
-                option.value === selected[item.key] ||
-                (Array.isArray(selected[item.key]) && selected[item.key].includes(option.value))
+              active: option.value === selected[item.key] || (Array.isArray(selected[item.key]) && selected[item.key].includes(option.value))
             }"
             @click="select(item, option)"
           >

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

@@ -10,7 +10,7 @@
       @click="openDialog"
     >
       <template #append>
-        <el-button :icon="customIcons[iconValue]" />
+        <el-button :icon="customIcons[iconValue] || ''" />
       </template>
     </el-input>
     <el-dialog v-model="dialogVisible" :title="placeholder" top="10%" width="40%">

+ 121 - 0
src/components/TableDialog/index.vue

@@ -0,0 +1,121 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    :close-on-click-modal="false"
+    :title="parameter.title"
+    :destroy-on-close="true"
+    :append-to-body="true"
+    :width="parameter.width"
+    :top="parameter.top"
+    draggable
+  >
+    <ProTable
+      ref="proTable"
+      height="50vh"
+      :tool-button="parameter.toolButton"
+      :columns="parameter.columns"
+      :row-key="parameter.rowKey"
+      :request-api="parameter.getTableList"
+      :init-param="parameter.initParam"
+    />
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button type="primary" :loading="butLoading" @click="handleSubmit">确认</el-button>
+        <el-button @click="handleCancel">取消</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="FormDialog">
+import { ref } from 'vue'
+import ProTable from '@/components/ProTable/index.vue'
+import { ElMessage } from 'element-plus'
+import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
+
+export interface TableParameterProps {
+  title?: string // 标题
+  width?: number // 弹框宽度
+  top?: string // 离顶部距离
+  toolButton?: boolean
+  initParam?: any // 初始化参数
+  apiParam?: (params?: any) => any
+  rowKey?: string
+  api?: (params: any) => Promise<any> // 表单提交api
+  columns?: ColumnProps[] // 动态表单字段
+  getTableList?: (params: any) => Promise<any> // 获取表格数据的Api
+  backTableList?: (params: any) => Promise<any> // 返回主表表格数据的Api
+}
+// dialog状态
+const dialogVisible = ref(false)
+const butLoading = ref(false)
+// 接受父组件参数,配置默认值
+// const parameter = ref<TableParameterProps>({
+//   title: '',
+//   width: 600,
+//   top: '5vh',
+//   toolButton: false,
+//   columns: [] as ColumnProps[]
+// })
+let parameter = withDefaults(defineProps<TableParameterProps>(), {
+  title: '',
+  width: 600,
+  top: '10vh',
+  rowKey: 'id',
+  toolButton: false,
+  initParam: {},
+  columns: () => []
+})
+// ProTable 实例
+const proTable = ref<ProTableInstance>()
+// 定义 emit 事件
+const emit = defineEmits<{
+  submitForm: []
+}>()
+// 表单提交校验
+const handleSubmit = () => {
+  butLoading.value = true
+  if (!proTable.value?.selectedList.length) {
+    ElMessage.warning('请选择数据')
+    butLoading.value = false
+    return
+  }
+  let paramObj: any = undefined
+  let params: any[] | undefined = []
+  if (parameter.apiParam) {
+    paramObj = parameter.apiParam(proTable.value?.selectedList)
+  } else {
+    params = proTable.value?.selectedList.map(item => item[parameter.rowKey])
+  }
+  parameter.api!(paramObj || params).then(res => {
+    if (res.code == 200) {
+      ElMessage.success('操作成功')
+      dialogVisible.value = false
+      emit('submitForm')
+    } else {
+      console.log('message', res.message)
+    }
+  })
+  butLoading.value = false
+}
+
+// 取消按钮,重置表单,关闭弹框
+const handleCancel = () => {
+  butLoading.value = false
+  dialogVisible.value = false
+}
+
+// 接收父组件参数
+const openDialog = (params: TableParameterProps) => {
+  parameter = { ...parameter, ...params }
+  butLoading.value = false
+  dialogVisible.value = true
+}
+
+defineExpose({
+  openDialog,
+  proTable,
+  handleCancel
+})
+</script>
+<style scoped lang="scss"></style>

+ 234 - 0
src/components/Upload/File.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="upload-file">
+    <el-upload
+      ref="uploadRef"
+      :action="uploadFileUrl"
+      :file-list="_fileList"
+      class="upload-file-uploader"
+      :show-file-list="false"
+      :multiple="true"
+      :disabled="self_disabled"
+      :limit="limit"
+      :before-upload="beforeUpload"
+      :on-exceed="handleExceed"
+      :on-success="uploadSuccess"
+      :on-error="uploadError"
+      :accept="fileType.join(',')"
+      :headers="headers"
+    >
+      <el-button icon="icon" type="primary">{{ text }}</el-button>
+    </el-upload>
+    <!-- 上传提示 -->
+    <div class="el-upload__tip" v-if="showTip">
+      请上传
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
+      </template>
+      的文件
+    </div>
+    <!-- 文件列表 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in _fileList">
+        <el-link :href="`${file.url}`" :underline="false" target="_blank">
+          <span class="document">
+            {{ file.name }}
+          </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" @click="handleRemove(index)" type="danger">删除</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script setup lang="ts" name="UploadImgs">
+import { ref, computed, inject, watch } from 'vue'
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { globalHeaders } from '@/api'
+import { OssVO } from '@/api/interface/system/oss'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { listToString } from '@/utils/common'
+interface UploadFileProps {
+  modelValue?: string | number
+  disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
+  drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
+  limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
+  fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
+  isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
+  text?: string // 按钮文字
+  icon?: string
+  fileType?: Array<string>
+}
+// 默认值
+const props = withDefaults(defineProps<UploadFileProps>(), {
+  modelValue: () => '',
+  drag: true,
+  disabled: false,
+  limit: 1,
+  fileSize: 5,
+  fileType: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
+  text: '文件上传',
+  isShowTip: true
+})
+
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadFileUrl = ref(baseUrl + '/common/upload') // 上传文件服务器地址
+const headers = ref(globalHeaders())
+const uploadRef = ref<UploadInstance>()
+const number = ref(0)
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const uploadList = ref<any[]>([])
+const emit = defineEmits<{
+  'update:modelValue': [value: any]
+}>()
+
+// 获取 el-form 组件上下文
+const formContext = inject(formContextKey, void 0)
+// 获取 el-form-item 组件上下文
+const formItemContext = inject(formItemContextKey, void 0)
+// 判断是否禁用上传和删除
+const self_disabled = computed(() => {
+  return props.disabled || formContext?.disabled
+})
+
+const _fileList = ref<any[]>([])
+
+// 监听 props.modelValue 列表默认值改变
+watch(
+  () => props.modelValue,
+  async (val: string | number) => {
+    if (val) {
+      let temp = 1
+      // 首先将值转为数组
+      let list: any[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data.map(oss => {
+          return {
+            name: oss.originalName,
+            url: oss.url,
+            ossId: oss.ossId
+          }
+        })
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        item = { name: item.name, url: item.url, ossId: item.ossId }
+        item.uid = item.uid || new Date().getTime() + temp++
+        return item
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
+)
+/**
+ * @description 文件上传之前判断
+ * @param rawFile 选择的文件
+ * */
+const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
+  // 校验文件格式
+  const fileName = rawFile.name.split('.')
+  const fileExt = fileName[fileName.length - 1]
+  const isTypeOk = props.fileType.indexOf(fileExt) >= 0
+  // 校检文件大小
+  const isLt = rawFile.size / 1024 / 1024 < props.fileSize
+  if (!isTypeOk) {
+    ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
+    return false
+  }
+  if (!isLt) {
+    ElMessage.error(`文件大小不能超过 ${props.fileSize}M!`)
+    return false
+  }
+  number.value++
+  showFullScreenLoading('正在上传文件,请稍候...')
+  return isTypeOk && isLt
+}
+
+/**
+ * @description 文件上传成功
+ * @param response 上传响应结果
+ * @param uploadFile 上传的文件
+ * */
+const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
+  if (response.code !== 200) {
+    number.value--
+    ElMessage.error(response.msg)
+    uploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  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 = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
+  }
+  // 监听表单验证
+  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+}
+
+/**
+ * @description 删除图片
+ * @param file 删除的文件
+ * */
+const handleRemove = (index: number) => {
+  let ossId = _fileList.value[index].ossId
+  delOssApi(ossId)
+  _fileList.value.splice(index, 1)
+  emit('update:modelValue', listToString(_fileList.value))
+}
+
+/**
+ * @description 文件上传错误
+ * */
+const uploadError = () => {
+  ElMessage.error('文件上传失败,请您重新上传!')
+}
+
+/**
+ * @description 文件数超出
+ * */
+const handleExceed = () => {
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
+}
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  position: relative;
+  margin-bottom: 10px;
+  line-height: 2;
+  border: 1px solid #e4e7ed;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
+</style>

+ 234 - 0
src/components/Upload/FileS3.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="upload-file">
+    <el-upload
+      ref="uploadRef"
+      :action="uploadFileUrl"
+      :file-list="_fileList"
+      class="upload-file-uploader"
+      :show-file-list="false"
+      :multiple="true"
+      :disabled="self_disabled"
+      :limit="limit"
+      :before-upload="beforeUpload"
+      :on-exceed="handleExceed"
+      :on-success="uploadSuccess"
+      :on-error="uploadError"
+      :accept="fileType.join(',')"
+      :headers="headers"
+    >
+      <el-button icon="icon" type="primary">{{ text }}</el-button>
+    </el-upload>
+    <!-- 上传提示 -->
+    <div class="el-upload__tip" v-if="showTip">
+      请上传
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
+      </template>
+      的文件
+    </div>
+    <!-- 文件列表 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in _fileList">
+        <el-link :href="`${file.url}`" :underline="false" target="_blank">
+          <span class="document">
+            {{ file.name }}
+          </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" @click="handleRemove(index)" type="danger">删除</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script setup lang="ts" name="UploadImgs">
+import { ref, computed, inject, watch } from 'vue'
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { globalHeaders } from '@/api'
+import { OssVO } from '@/api/interface/system/oss'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { listToString } from '@/utils/common'
+interface UploadFileProps {
+  modelValue?: string | number
+  disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
+  drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
+  limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
+  fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
+  isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
+  text?: string // 按钮文字
+  icon?: string
+  fileType?: Array<string>
+}
+// 默认值
+const props = withDefaults(defineProps<UploadFileProps>(), {
+  modelValue: () => '',
+  drag: true,
+  disabled: false,
+  limit: 1,
+  fileSize: 5,
+  fileType: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
+  text: '文件上传',
+  isShowTip: true
+})
+
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadFileUrl = ref(baseUrl + '/resource/oss/upload') // 上传文件服务器地址
+const headers = ref(globalHeaders())
+const uploadRef = ref<UploadInstance>()
+const number = ref(0)
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const uploadList = ref<any[]>([])
+const emit = defineEmits<{
+  'update:modelValue': [value: any]
+}>()
+
+// 获取 el-form 组件上下文
+const formContext = inject(formContextKey, void 0)
+// 获取 el-form-item 组件上下文
+const formItemContext = inject(formItemContextKey, void 0)
+// 判断是否禁用上传和删除
+const self_disabled = computed(() => {
+  return props.disabled || formContext?.disabled
+})
+
+const _fileList = ref<any[]>([])
+
+// 监听 props.modelValue 列表默认值改变
+watch(
+  () => props.modelValue,
+  async (val: string | number) => {
+    if (val) {
+      let temp = 1
+      // 首先将值转为数组
+      let list: any[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data.map(oss => {
+          return {
+            name: oss.originalName,
+            url: oss.url,
+            ossId: oss.ossId
+          }
+        })
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        item = { name: item.name, url: item.url, ossId: item.ossId }
+        item.uid = item.uid || new Date().getTime() + temp++
+        return item
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
+)
+/**
+ * @description 文件上传之前判断
+ * @param rawFile 选择的文件
+ * */
+const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
+  // 校验文件格式
+  const fileName = rawFile.name.split('.')
+  const fileExt = fileName[fileName.length - 1]
+  const isTypeOk = props.fileType.indexOf(fileExt) >= 0
+  // 校检文件大小
+  const isLt = rawFile.size / 1024 / 1024 < props.fileSize
+  if (!isTypeOk) {
+    ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
+    return false
+  }
+  if (!isLt) {
+    ElMessage.error(`文件大小不能超过 ${props.fileSize}M!`)
+    return false
+  }
+  number.value++
+  showFullScreenLoading('正在上传文件,请稍候...')
+  return isTypeOk && isLt
+}
+
+/**
+ * @description 文件上传成功
+ * @param response 上传响应结果
+ * @param uploadFile 上传的文件
+ * */
+const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
+  if (response.code !== 200) {
+    number.value--
+    ElMessage.error(response.msg)
+    uploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  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 = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
+  }
+  // 监听表单验证
+  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+}
+
+/**
+ * @description 删除图片
+ * @param file 删除的文件
+ * */
+const handleRemove = (index: number) => {
+  let ossId = _fileList.value[index].ossId
+  delOssApi(ossId)
+  _fileList.value.splice(index, 1)
+  emit('update:modelValue', listToString(_fileList.value))
+}
+
+/**
+ * @description 文件上传错误
+ * */
+const uploadError = () => {
+  ElMessage.error('文件上传失败,请您重新上传!')
+}
+
+/**
+ * @description 文件数超出
+ * */
+const handleExceed = () => {
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
+}
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  position: relative;
+  margin-bottom: 10px;
+  line-height: 2;
+  border: 1px solid #e4e7ed;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
+</style>

+ 5 - 4
src/components/Upload/Img.vue

@@ -15,7 +15,7 @@
       :accept="fileType.join(',')"
     >
       <template v-if="imageUrl">
-        <img :src="imageUrl" class="upload-image" />
+        <img :src="'/api' + imageUrl" class="upload-image" />
         <div class="upload-handle" @click.stop>
           <div v-if="!self_disabled" class="handle-icon" @click="editImg">
             <el-icon><Edit /></el-icon>
@@ -43,7 +43,7 @@
     <div class="el-upload__tip">
       <slot name="tip"></slot>
     </div>
-    <el-image-viewer v-if="imgViewVisible" :url-list="[imageUrl]" @close="imgViewVisible = false" />
+    <el-image-viewer v-if="imgViewVisible" :url-list="['/api' + imageUrl]" @close="imgViewVisible = false" />
   </div>
 </template>
 
@@ -104,8 +104,9 @@ const handleHttpUpload = async (options: UploadRequestOptions) => {
   formData.append('file', options.file)
   try {
     const api = props.api ?? uploadImg
-    const { data } = await api(formData)
-    emit('update:imageUrl', data.fileUrl)
+    const res = await api(formData)
+
+    emit('update:imageUrl', res.data.url)
     // 调用 el-form 内部的校验方法(可自动校验)
     formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
   } catch (error) {

+ 122 - 77
src/components/Upload/Imgs.vue

@@ -1,18 +1,18 @@
 <template>
   <div class="upload-box">
     <el-upload
-      v-model:file-list="_fileList"
-      action="#"
+      :file-list="_fileList"
+      :action="uploadImgUrl"
       list-type="picture-card"
-      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '']"
-      :multiple="true"
-      :disabled="self_disabled"
-      :limit="limit"
-      :http-request="handleHttpUpload"
       :before-upload="beforeUpload"
-      :on-exceed="handleExceed"
       :on-success="uploadSuccess"
+      :on-exceed="handleExceed"
       :on-error="uploadError"
+      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '', { hide: _fileList.length >= limit }]"
+      :multiple="true"
+      :headers="headers"
+      :disabled="self_disabled"
+      :limit="limit"
       :drag="drag"
       :accept="fileType.join(',')"
     >
@@ -36,6 +36,16 @@
         </div>
       </template>
     </el-upload>
+    <div v-if="showTip" class="el-upload__tip">
+      请上传
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
+      </template>
+      的文件
+    </div>
     <div class="el-upload__tip">
       <slot name="tip"></slot>
     </div>
@@ -46,13 +56,17 @@
 <script setup lang="ts" name="UploadImgs">
 import { ref, computed, inject, watch } from 'vue'
 import { Plus } from '@element-plus/icons-vue'
-import { uploadImg } from '@/api/modules/upload'
-import type { UploadProps, UploadFile, UploadUserFile, UploadRequestOptions } from 'element-plus'
-import { ElNotification, formContextKey, formItemContextKey } from 'element-plus'
-
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey } from 'element-plus'
+import { listToString } from '@/utils/common'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { compressAccurately } from 'image-conversion'
+import { OssVO } from '@/api/interface/system/oss'
+import { globalHeaders } from '@/api'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { ResultData } from '@/api/interface'
 interface UploadFileProps {
-  fileList: UploadUserFile[]
-  api?: (params: any) => Promise<any> // 上传图片的 api 方法,一般项目上传都是同一个 api 方法,在组件里直接引入即可 ==> 非必传
+  modelValue: string | number
   drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
   disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
   limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
@@ -60,21 +74,30 @@ interface UploadFileProps {
   fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
   height?: string // 组件高度 ==> 非必传(默认为 150px)
   width?: string // 组件宽度 ==> 非必传(默认为 150px)
+  isShowTip?: boolean
   borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
+  compressSupport?: boolean // 是否支持图片压缩 ==> 非必传(默认为 false)
+  compressTargetSize?: number // 图片压缩目标大小 ==> 非必传(默认为 300kb)
 }
 
 const props = withDefaults(defineProps<UploadFileProps>(), {
-  fileList: () => [],
+  modelValue: () => '',
   drag: true,
   disabled: false,
   limit: 5,
   fileSize: 5,
+  isShowTip: true,
+  compressSupport: false,
+  compressTargetSize: 300,
   fileType: () => ['image/jpeg', 'image/png', 'image/gif'],
   height: '150px',
   width: '150px',
   borderRadius: '8px'
 })
 
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadImgUrl = ref(baseUrl + '/common/upload') // 上传的图片服务器地址
+const headers = ref(globalHeaders())
 // 获取 el-form 组件上下文
 const formContext = inject(formContextKey, void 0)
 // 获取 el-form-item 组件上下文
@@ -83,15 +106,42 @@ const formItemContext = inject(formItemContextKey, void 0)
 const self_disabled = computed(() => {
   return props.disabled || formContext?.disabled
 })
-
-const _fileList = ref<UploadUserFile[]>(props.fileList)
-
-// 监听 props.fileList 列表默认值改变
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const _fileList = ref<any[]>([])
+const uploadList = ref<any[]>([])
+const number = ref(0)
+const imageUploadRef = ref<ElUploadInstance>()
+// 监听 props.modelValue 列表默认值改变
 watch(
-  () => props.fileList,
-  (n: UploadUserFile[]) => {
-    _fileList.value = n
-  }
+  () => props.modelValue,
+  async (val: string | number) => {
+    if (val) {
+      // 首先将值转为数组
+      let list: OssVO[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
+        let itemData
+        if (typeof item === 'string') {
+          itemData = { name: item, url: item }
+        } else {
+          // 此处name使用ossId 防止删除出现重名
+          itemData = { name: item.ossId, url: item.url, ossId: item.ossId }
+        }
+        return itemData
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
 )
 
 /**
@@ -101,37 +151,21 @@ watch(
 const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
   const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
   const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType)
-  if (!imgType)
-    ElNotification({
-      title: '温馨提示',
-      message: '上传图片不符合所需的格式!',
-      type: 'warning'
-    })
-  if (!imgSize)
-    setTimeout(() => {
-      ElNotification({
-        title: '温馨提示',
-        message: `上传图片大小不能超过 ${props.fileSize}M!`,
-        type: 'warning'
-      })
-    }, 0)
-  return imgType && imgSize
-}
-
-/**
- * @description 图片上传
- * @param options upload 所有配置项
- * */
-const handleHttpUpload = async (options: UploadRequestOptions) => {
-  let formData = new FormData()
-  formData.append('file', options.file)
-  try {
-    const api = props.api ?? uploadImg
-    const { data } = await api(formData)
-    options.onSuccess(data)
-  } catch (error) {
-    options.onError(error as any)
+  if (!imgType) {
+    ElMessage.error(`上传图片不符合所需的格式,  请上传${props.fileType.join('/')}图片格式文件!`)
+    return false
   }
+  if (!imgSize) {
+    ElMessage.error('图片大小不能超过 ' + props.fileSize + 'M!')
+    return false
+  }
+  if (props.compressSupport && rawFile.size / 1024 > props.compressTargetSize) {
+    return compressAccurately(rawFile, props.compressTargetSize)
+  }
+  showFullScreenLoading('正在上传图片,请稍候...')
+  number.value++
+  console.log('number', number.value)
+  return imgType && imgSize
 }
 
 /**
@@ -140,19 +174,31 @@ const handleHttpUpload = async (options: UploadRequestOptions) => {
  * @param uploadFile 上传的文件
  * */
 const emit = defineEmits<{
-  'update:fileList': [value: UploadUserFile[]]
+  'update:modelValue': [value: string]
 }>()
-const uploadSuccess = (response: { fileUrl: string } | undefined, uploadFile: UploadFile) => {
-  if (!response) return
-  uploadFile.url = response.fileUrl
-  emit('update:fileList', _fileList.value)
-  // 调用 el-form 内部的校验方法(可自动校验)
+const uploadSuccess = (response: ResultData, uploadFile: UploadFile) => {
+  if (response.code !== 200) {
+    number.value--
+    ElMessage.error(response.msg)
+    imageUploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  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 = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
+  }
+  // 监听表单验证
   formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
-  ElNotification({
-    title: '温馨提示',
-    message: '图片上传成功!',
-    type: 'success'
-  })
 }
 
 /**
@@ -160,30 +206,30 @@ const uploadSuccess = (response: { fileUrl: string } | undefined, uploadFile: Up
  * @param file 删除的文件
  * */
 const handleRemove = (file: UploadFile) => {
-  _fileList.value = _fileList.value.filter(item => item.url !== file.url || item.name !== file.name)
-  emit('update:fileList', _fileList.value)
+  const fIndex = _fileList.value.map(f => f.name).indexOf(file.name)
+  if (fIndex > -1 && uploadList.value.length === number.value) {
+    let ossId = _fileList.value[fIndex].ossId
+    delOssApi(ossId)
+    _fileList.value.splice(fIndex, 1)
+    emit('update:modelValue', listToString(_fileList.value))
+    formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+    return false
+  }
+  return true
 }
 
 /**
  * @description 图片上传错误
  * */
 const uploadError = () => {
-  ElNotification({
-    title: '温馨提示',
-    message: '图片上传失败,请您重新上传!',
-    type: 'error'
-  })
+  ElMessage.error('图片上传失败,请您重新上传!')
 }
 
 /**
  * @description 文件数超出
  * */
 const handleExceed = () => {
-  ElNotification({
-    title: '温馨提示',
-    message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
-    type: 'warning'
-  })
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 张图片,请移除后上传!`)
 }
 
 /**
@@ -310,7 +356,6 @@ const handlePictureCardPreview: UploadProps['onPreview'] = file => {
   }
   .el-upload__tip {
     line-height: 15px;
-    text-align: center;
   }
 }
 </style>

+ 361 - 0
src/components/Upload/ImgsS3.vue

@@ -0,0 +1,361 @@
+<template>
+  <div class="upload-box">
+    <el-upload
+      :file-list="_fileList"
+      :action="uploadImgUrl"
+      list-type="picture-card"
+      :before-upload="beforeUpload"
+      :on-success="uploadSuccess"
+      :on-exceed="handleExceed"
+      :on-error="uploadError"
+      :class="['upload', self_disabled ? 'disabled' : '', drag ? 'no-border' : '', { hide: _fileList.length >= limit }]"
+      :multiple="true"
+      :headers="headers"
+      :disabled="self_disabled"
+      :limit="limit"
+      :drag="drag"
+      :accept="fileType.join(',')"
+    >
+      <div class="upload-empty">
+        <slot name="empty">
+          <el-icon><Plus /></el-icon>
+          <!-- <span>请上传图片</span> -->
+        </slot>
+      </div>
+      <template #file="{ file }">
+        <img :src="file.url" class="upload-image" />
+        <div class="upload-handle" @click.stop>
+          <div class="handle-icon" @click="handlePictureCardPreview(file)">
+            <el-icon><ZoomIn /></el-icon>
+            <span>查看</span>
+          </div>
+          <div v-if="!self_disabled" class="handle-icon" @click="handleRemove(file)">
+            <el-icon><Delete /></el-icon>
+            <span>删除</span>
+          </div>
+        </div>
+      </template>
+    </el-upload>
+    <div v-if="showTip" class="el-upload__tip">
+      请上传
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
+      </template>
+      的文件
+    </div>
+    <div class="el-upload__tip">
+      <slot name="tip"></slot>
+    </div>
+    <el-image-viewer v-if="imgViewVisible" :url-list="[viewImageUrl]" @close="imgViewVisible = false" />
+  </div>
+</template>
+
+<script setup lang="ts" name="UploadImgs">
+import { ref, computed, inject, watch } from 'vue'
+import { Plus } from '@element-plus/icons-vue'
+import type { UploadProps, UploadFile } from 'element-plus'
+import { ElMessage, formContextKey, formItemContextKey } from 'element-plus'
+import { listToString } from '@/utils/common'
+import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
+import { compressAccurately } from 'image-conversion'
+import { OssVO } from '@/api/interface/system/oss'
+import { globalHeaders } from '@/api'
+import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
+import { ResultData } from '@/api/interface'
+interface UploadFileProps {
+  modelValue: string | number
+  drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
+  disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
+  limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
+  fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
+  fileType?: File.ImageMimeType[] // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
+  height?: string // 组件高度 ==> 非必传(默认为 150px)
+  width?: string // 组件宽度 ==> 非必传(默认为 150px)
+  isShowTip?: boolean
+  borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
+  compressSupport?: boolean // 是否支持图片压缩 ==> 非必传(默认为 false)
+  compressTargetSize?: number // 图片压缩目标大小 ==> 非必传(默认为 300kb)
+}
+
+const props = withDefaults(defineProps<UploadFileProps>(), {
+  modelValue: () => '',
+  drag: true,
+  disabled: false,
+  limit: 5,
+  fileSize: 5,
+  isShowTip: true,
+  compressSupport: false,
+  compressTargetSize: 300,
+  fileType: () => ['image/jpeg', 'image/png', 'image/gif'],
+  height: '150px',
+  width: '150px',
+  borderRadius: '8px'
+})
+
+const baseUrl = import.meta.env.VITE_API_URL
+const uploadImgUrl = ref(baseUrl + '/resource/oss/upload') // 上传的图片服务器地址
+const headers = ref(globalHeaders())
+// 获取 el-form 组件上下文
+const formContext = inject(formContextKey, void 0)
+// 获取 el-form-item 组件上下文
+const formItemContext = inject(formItemContextKey, void 0)
+// 判断是否禁用上传和删除
+const self_disabled = computed(() => {
+  return props.disabled || formContext?.disabled
+})
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
+const _fileList = ref<any[]>([])
+const uploadList = ref<any[]>([])
+const number = ref(0)
+const imageUploadRef = ref<ElUploadInstance>()
+// 监听 props.modelValue 列表默认值改变
+watch(
+  () => props.modelValue,
+  async (val: string | number) => {
+    if (val) {
+      // 首先将值转为数组
+      let list: OssVO[] = []
+      if (Array.isArray(val)) {
+        list = val as OssVO[]
+      } else {
+        const res = await getListByIdsApi(val)
+        list = res.data
+      }
+      // 然后将数组转为对象数组
+      _fileList.value = list.map(item => {
+        // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
+        let itemData
+        if (typeof item === 'string') {
+          itemData = { name: item, url: item }
+        } else {
+          // 此处name使用ossId 防止删除出现重名
+          itemData = { name: item.ossId, url: item.url, ossId: item.ossId }
+        }
+        return itemData
+      })
+    } else {
+      _fileList.value = []
+      return []
+    }
+  },
+  { deep: true, immediate: true }
+)
+
+/**
+ * @description 文件上传之前判断
+ * @param rawFile 选择的文件
+ * */
+const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
+  const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
+  const imgType = props.fileType.includes(rawFile.type as File.ImageMimeType)
+  if (!imgType) {
+    ElMessage.error(`上传图片不符合所需的格式,  请上传${props.fileType.join('/')}图片格式文件!`)
+    return false
+  }
+  if (!imgSize) {
+    ElMessage.error('图片大小不能超过 ' + props.fileSize + 'M!')
+    return false
+  }
+  if (props.compressSupport && rawFile.size / 1024 > props.compressTargetSize) {
+    return compressAccurately(rawFile, props.compressTargetSize)
+  }
+  showFullScreenLoading('正在上传图片,请稍候...')
+  number.value++
+  console.log('number', number.value)
+  return imgType && imgSize
+}
+
+/**
+ * @description 图片上传成功
+ * @param response 上传响应结果
+ * @param uploadFile 上传的文件
+ * */
+const emit = defineEmits<{
+  'update:modelValue': [value: string]
+}>()
+const uploadSuccess = (response: ResultData, uploadFile: UploadFile) => {
+  if (response.code !== 200) {
+    number.value--
+    ElMessage.error(response.msg)
+    imageUploadRef.value?.handleRemove(uploadFile)
+    uploadedSuccessfully()
+    return
+  }
+  uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
+  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 = []
+    number.value = 0
+    emit('update:modelValue', listToString(_fileList.value))
+    tryHideFullScreenLoading()
+  }
+  // 监听表单验证
+  formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+}
+
+/**
+ * @description 删除图片
+ * @param file 删除的文件
+ * */
+const handleRemove = (file: UploadFile) => {
+  const fIndex = _fileList.value.map(f => f.name).indexOf(file.name)
+  if (fIndex > -1 && uploadList.value.length === number.value) {
+    let ossId = _fileList.value[fIndex].ossId
+    delOssApi(ossId)
+    _fileList.value.splice(fIndex, 1)
+    emit('update:modelValue', listToString(_fileList.value))
+    formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
+    return false
+  }
+  return true
+}
+
+/**
+ * @description 图片上传错误
+ * */
+const uploadError = () => {
+  ElMessage.error('图片上传失败,请您重新上传!')
+}
+
+/**
+ * @description 文件数超出
+ * */
+const handleExceed = () => {
+  ElMessage.warning(`当前最多只能上传 ${props.limit} 张图片,请移除后上传!`)
+}
+
+/**
+ * @description 图片预览
+ * @param file 预览的文件
+ * */
+const viewImageUrl = ref('')
+const imgViewVisible = ref(false)
+const handlePictureCardPreview: UploadProps['onPreview'] = file => {
+  viewImageUrl.value = file.url!
+  imgViewVisible.value = true
+}
+</script>
+
+<style scoped lang="scss">
+.is-error {
+  .upload {
+    :deep(.el-upload--picture-card),
+    :deep(.el-upload-dragger) {
+      border: 1px dashed var(--el-color-danger) !important;
+      &:hover {
+        border-color: var(--el-color-primary) !important;
+      }
+    }
+  }
+}
+:deep(.disabled) {
+  .el-upload--picture-card,
+  .el-upload-dragger {
+    cursor: not-allowed;
+    background: var(--el-disabled-bg-color) !important;
+    border: 1px dashed var(--el-border-color-darker);
+    &:hover {
+      border-color: var(--el-border-color-darker) !important;
+    }
+  }
+}
+.upload-box {
+  .no-border {
+    :deep(.el-upload--picture-card) {
+      border: none !important;
+    }
+  }
+  :deep(.upload) {
+    .el-upload-dragger {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      padding: 0;
+      overflow: hidden;
+      border: 1px dashed var(--el-border-color-darker);
+      border-radius: v-bind(borderRadius);
+      &:hover {
+        border: 1px dashed var(--el-color-primary);
+      }
+    }
+    .el-upload-dragger.is-dragover {
+      background-color: var(--el-color-primary-light-9);
+      border: 2px dashed var(--el-color-primary) !important;
+    }
+    .el-upload-list__item,
+    .el-upload--picture-card {
+      width: v-bind(width);
+      height: v-bind(height);
+      background-color: transparent;
+      border-radius: v-bind(borderRadius);
+    }
+    .upload-image {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+    }
+    .upload-handle {
+      position: absolute;
+      top: 0;
+      right: 0;
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      cursor: pointer;
+      background: rgb(0 0 0 / 60%);
+      opacity: 0;
+      transition: var(--el-transition-duration-fast);
+      .handle-icon {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding: 0 6%;
+        color: aliceblue;
+        .el-icon {
+          margin-bottom: 15%;
+          font-size: 140%;
+        }
+        span {
+          font-size: 100%;
+        }
+      }
+    }
+    .el-upload-list__item {
+      &:hover {
+        .upload-handle {
+          opacity: 1;
+        }
+      }
+    }
+    .upload-empty {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      font-size: 12px;
+      line-height: 30px;
+      color: var(--el-color-info);
+      .el-icon {
+        font-size: 28px;
+        color: var(--el-text-color-secondary);
+      }
+    }
+  }
+  .el-upload__tip {
+    line-height: 15px;
+  }
+}
+</style>

+ 98 - 0
src/components/UploadDialog/index.vue

@@ -0,0 +1,98 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    :close-on-click-modal="false"
+    :title="parameter.title"
+    :destroy-on-close="true"
+    :width="parameter.width"
+    :top="parameter.top"
+    draggable
+  >
+    <ProFrom ref="proFormRef" :items-options="itemsOptions" :form-options="_options" :model="model" />
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button type="primary" :loading="butLoading" @click="handleSubmit">确认</el-button>
+        <el-button @click="handleCancel">取消</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="ImageUploadDialog">
+import { ref, computed, ComputedRef } from 'vue'
+import ProFrom from '@/components/ProForm/index.vue'
+export interface DialogProps {
+  title: string // 标题
+  width?: number // 弹框宽度
+  top?: string // 离顶部距离
+  type?: File.FileUploadType // 弹框类型 默认file-upload-s3:s3服务器上传文件
+  getTableList?: () => void // 获取表格数据的Api
+}
+// 表单的数据
+const model = ref<Record<string, any>>({ file: undefined })
+// dialog状态
+const dialogVisible = ref(false)
+const butLoading = ref(false)
+// 父组件传过来的参数
+const parameter = ref<DialogProps>({
+  title: '',
+  width: 500,
+  top: '10vh',
+  type: 'file-upload-s3'
+})
+const _options: ComputedRef<ProForm.FormOptions> = computed(() => {
+  return {
+    labelWidth: 120,
+    hasFooter: false,
+    disabled: false
+  }
+})
+let itemsOptions: ProForm.ItemsOptions[] = []
+const setItemsOptions = () => {
+  itemsOptions = [
+    {
+      label: '上传',
+      prop: 'file',
+      rules: [{ required: true, message: '文件不能为空', trigger: 'change' }],
+      compOptions: {
+        elTagName: parameter.value.type
+      }
+    }
+  ]
+}
+
+const proFormRef = ref<InstanceType<typeof ProFrom> | null>(null)
+
+// 表单提交校验
+const handleSubmit = () => {
+  const formEl = proFormRef.value?.proFormRef
+  console.log(proFormRef.value?.formModel)
+  butLoading.value = true
+  if (!formEl) return
+  formEl.validate(valid => {
+    if (valid) {
+      parameter.value.getTableList && parameter.value.getTableList()
+      dialogVisible.value = false
+    }
+    butLoading.value = false
+  })
+}
+
+// 取消按钮,重置表单,关闭弹框
+const handleCancel = () => {
+  butLoading.value = false
+  dialogVisible.value = false
+}
+
+// 接收父组件参数
+const openDialog = (params: DialogProps) => {
+  parameter.value = { ...parameter.value, ...params }
+  butLoading.value = false
+  setItemsOptions()
+  dialogVisible.value = true
+}
+
+defineExpose({
+  openDialog
+})
+</script>

+ 30 - 0
src/components/iFrame/index.vue

@@ -0,0 +1,30 @@
+<template>
+  <div v-loading="loading" :style="'height:' + height">
+    <iframe :src="url" frameborder="no" style="width: 100%; height: 100%" scrolling="auto" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted } from 'vue'
+
+interface IFrameProps {
+  src: string
+}
+
+const props = withDefaults(defineProps<IFrameProps>(), {
+  src: ''
+})
+
+const height = ref(document.documentElement.clientHeight - 94.5 + 'px;')
+const loading = ref(true)
+const url = computed(() => props.src)
+
+onMounted(() => {
+  setTimeout(() => {
+    loading.value = false
+  }, 300)
+  window.onresize = function temp() {
+    height.value = document.documentElement.clientHeight - 94.5 + 'px;'
+  }
+})
+</script>

+ 1 - 1
src/directives/modules/role.ts

@@ -8,7 +8,7 @@ import type { Directive, DirectiveBinding } from 'vue'
 const role: Directive = {
   mounted(el: HTMLElement, binding: DirectiveBinding) {
     const { value } = binding
-    const super_admin = 'admin'
+    const super_admin = 'superadmin'
     const roles = useUserStore().roles
 
     if (value && value instanceof Array && value.length > 0) {

+ 15 - 0
src/enums/MenuTypeEnum.ts

@@ -0,0 +1,15 @@
+export enum MenuTypeEnum {
+  /**
+   * 目录
+   */
+  M = 'M',
+  /**
+   * 菜单
+   */
+  C = 'C',
+
+  /**
+   * 按钮
+   */
+  F = 'F'
+}

+ 99 - 2
src/hooks/useDownload.ts

@@ -1,6 +1,10 @@
-import { ElNotification, ElMessage } from 'element-plus'
-import { saveAs } from 'file-saver'
+import { ElNotification, ElMessage, ElLoading } from 'element-plus'
+import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
 import { blobValidate } from '@/utils/common'
+import axios from 'axios'
+import { globalHeaders } from '@/api'
+let downloadLoadingInstance: LoadingInstance
+import { saveAs } from 'file-saver'
 import errorCode from '@/utils/errorCode'
 /**
  * @description 接收数据流生成 blob,创建链接,下载文件
@@ -51,3 +55,96 @@ export const useDownload = async (
     ElMessage.error('下载文件出现错误,请联系管理员!')
   }
 }
+
+const baseURL = import.meta.env.VITE_API_URL
+
+export default {
+  async oss(ossId: string | number) {
+    const url = baseURL + '/resource/oss/download/' + ossId
+    downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' })
+    try {
+      const res = await axios({
+        method: 'get',
+        url: url,
+        responseType: 'blob',
+        headers: globalHeaders()
+      })
+      const isBlob = blobValidate(res.data)
+      if (isBlob) {
+        const blob = new Blob([res.data], { type: 'application/octet-stream' })
+        saveAs(blob, decodeURIComponent(res.headers['download-filename'] as string))
+      } else {
+        this.printErrMsg(res.data)
+      }
+      downloadLoadingInstance.close()
+    } catch (r) {
+      console.error(r)
+      ElMessage.error('下载文件出现错误,请联系管理员!')
+      downloadLoadingInstance.close()
+    }
+  },
+  async localResource(resource: string) {
+    let url = baseURL + '/common/download/resource?resource=' + encodeURI(resource)
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: globalHeaders()
+    }).then(async res => {
+      const isLogin = await blobValidate(res.data)
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data)
+      }
+    })
+  },
+  async localName(name: string, isDelete = true) {
+    let url = baseURL + '/common/download?fileName=' + encodeURI(name) + '&delete=' + isDelete
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: globalHeaders()
+    }).then(async res => {
+      const isLogin = await blobValidate(res.data)
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data)
+      }
+    })
+  },
+  async printErrMsg(data: any) {
+    const resText = await data.text()
+    const rspObj = JSON.parse(resText)
+    const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+    ElMessage.error(errMsg)
+  },
+  async zip(url: string, name: string) {
+    url = baseURL + url
+    downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' })
+    try {
+      const res = await axios({
+        method: 'get',
+        url: url,
+        responseType: 'blob',
+        headers: globalHeaders()
+      })
+      const isBlob = blobValidate(res.data)
+      if (isBlob) {
+        const blob = new Blob([res.data], { type: 'application/zip' })
+        saveAs(blob, name)
+      } else {
+        this.printErrMsg(res.data)
+      }
+      downloadLoadingInstance.close()
+    } catch (r) {
+      console.error(r)
+      ElMessage.error('下载文件出现错误,请联系管理员!')
+      downloadLoadingInstance.close()
+    }
+  }
+}

+ 1 - 4
src/hooks/useTheme.ts

@@ -33,10 +33,7 @@ export const useTheme = () => {
     }
     // 计算主题颜色变化
     document.documentElement.style.setProperty('--el-color-primary', val)
-    document.documentElement.style.setProperty(
-      '--el-color-primary-dark-2',
-      isDark.value ? `${getLightColor(val, 0.2)}` : `${getDarkColor(val, 0.3)}`
-    )
+    document.documentElement.style.setProperty('--el-color-primary-dark-2', isDark.value ? `${getLightColor(val, 0.2)}` : `${getDarkColor(val, 0.3)}`)
     for (let i = 1; i <= 9; i++) {
       const primaryColor = isDark.value ? `${getDarkColor(val, i / 10)}` : `${getLightColor(val, i / 10)}`
       document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, primaryColor)

+ 3 - 7
src/hooks/useTime.ts

@@ -20,15 +20,11 @@ export const useTime = () => {
     month.value = date.getMonth() + 1
     week.value = '日一二三四五六'.charAt(date.getDay())
     day.value = date.getDate()
-    hour.value =
-      (date.getHours() + '')?.padStart(2, '0') ||
-      new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getHours())
+    hour.value = (date.getHours() + '')?.padStart(2, '0') || new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getHours())
     minute.value =
-      (date.getMinutes() + '')?.padStart(2, '0') ||
-      new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getMinutes())
+      (date.getMinutes() + '')?.padStart(2, '0') || new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getMinutes())
     second.value =
-      (date.getSeconds() + '')?.padStart(2, '0') ||
-      new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getSeconds())
+      (date.getSeconds() + '')?.padStart(2, '0') || new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getSeconds())
     nowTime.value = `${year.value}年${month.value}月${day.value} ${hour.value}:${minute.value}:${second.value}`
   }
 

+ 1 - 1
src/languages/modules/en.ts

@@ -22,7 +22,7 @@ export default {
     weakMode: 'Weak mode',
     fullScreen: 'Full Screen',
     exitFullScreen: 'Exit Full Screen',
-    personalData: 'Personal Data',
+    personalCenter: 'Personal Center',
     changePassword: 'Change Password',
     logout: 'Logout'
   }

+ 1 - 1
src/languages/modules/zh.ts

@@ -22,7 +22,7 @@ export default {
     weakMode: '色弱模式',
     fullScreen: '全屏',
     exitFullScreen: '退出全屏',
-    personalData: '个人信息',
+    personalCenter: '个人中心',
     changePassword: '修改密码',
     logout: '退出登录'
   }

+ 1 - 7
src/layouts/LayoutClassic/index.vue

@@ -17,13 +17,7 @@
       <el-aside>
         <div class="aside-box" :style="{ width: isCollapse ? '65px' : '210px' }">
           <el-scrollbar>
-            <el-menu
-              :router="false"
-              :default-active="activeMenu"
-              :collapse="isCollapse"
-              :unique-opened="accordion"
-              :collapse-transition="false"
-            >
+            <el-menu :router="false" :default-active="activeMenu" :collapse="isCollapse" :unique-opened="accordion" :collapse-transition="false">
               <SubMenu :menu-list="menuList" />
             </el-menu>
           </el-scrollbar>

+ 1 - 7
src/layouts/LayoutColumns/index.vue

@@ -27,13 +27,7 @@
         <span v-show="subMenuList.length" class="logo-text">{{ isCollapse ? 'G' : title }}</span>
       </div>
       <el-scrollbar>
-        <el-menu
-          :router="false"
-          :default-active="activeMenu"
-          :collapse="isCollapse"
-          :unique-opened="accordion"
-          :collapse-transition="false"
-        >
+        <el-menu :router="false" :default-active="activeMenu" :collapse="isCollapse" :unique-opened="accordion" :collapse-transition="false">
           <SubMenu :menu-list="subMenuList" />
         </el-menu>
       </el-scrollbar>

+ 1 - 7
src/layouts/LayoutVertical/index.vue

@@ -8,13 +8,7 @@
           <span v-show="!isCollapse" class="logo-text">{{ title }}</span>
         </div>
         <el-scrollbar>
-          <el-menu
-            :router="false"
-            :default-active="activeMenu"
-            :collapse="isCollapse"
-            :unique-opened="accordion"
-            :collapse-transition="false"
-          >
+          <el-menu :router="false" :default-active="activeMenu" :collapse="isCollapse" :unique-opened="accordion" :collapse-transition="false">
             <SubMenu :menu-list="menuList" />
           </el-menu>
         </el-scrollbar>

+ 1 - 1
src/layouts/components/Footer/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="footer flx-center">
-    <a href="https://gitee.com/gaokunw/kimi-web" target="_blank"> 2023 © km-Admin By gaokunw Technology. </a>
+    <a href="https://gitee.com/gaokunw/kimi-web" target="_blank"> 2023 © taais-Admin By gaokunw Technology. </a>
   </div>
 </template>
 

+ 8 - 8
src/layouts/components/Header/ToolBarRight.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="tool-bar-ri">
     <div class="header-icon">
-      <SwitchDark />
-      <AssemblySize id="assemblySize" />
+      <!-- <SwitchDark /> -->
+      <!-- <AssemblySize id="assemblySize" /> -->
       <!-- <Language id="language" /> -->
-      <SearchMenu id="searchMenu" />
-      <ThemeSetting id="themeSetting" />
+      <!-- <SearchMenu id="searchMenu" /> -->
+      <!-- <ThemeSetting id="themeSetting" /> -->
       <!-- <Message id="message" /> -->
       <Fullscreen id="fullscreen" />
     </div>
@@ -17,14 +17,14 @@
 <script setup lang="ts">
 // import { computed } from 'vue'
 // import { useUserStore } from '@/stores/modules/user'
-import AssemblySize from './components/AssemblySize.vue'
+// import AssemblySize from './components/AssemblySize.vue'
 // import Language from './components/Language.vue'
-import SearchMenu from './components/SearchMenu.vue'
-import ThemeSetting from './components/ThemeSetting.vue'
+// import SearchMenu from './components/SearchMenu.vue'
+// import ThemeSetting from './components/ThemeSetting.vue'
 // import Message from './components/Message.vue'
 import Fullscreen from './components/Fullscreen.vue'
 import Avatar from './components/Avatar.vue'
-import SwitchDark from '@/components/SwitchDark/index.vue'
+// import SwitchDark from '@/components/SwitchDark/index.vue'
 
 // const userStore = useUserStore()
 // const username = computed(() => userStore.name || 'KM')

+ 1 - 6
src/layouts/components/Header/components/AssemblySize.vue

@@ -3,12 +3,7 @@
     <i :class="'iconfont icon-contentright'" class="toolBar-icon"></i>
     <template #dropdown>
       <el-dropdown-menu>
-        <el-dropdown-item
-          v-for="item in assemblySizeList"
-          :key="item.value"
-          :command="item.value"
-          :disabled="assemblySize === item.value"
-        >
+        <el-dropdown-item v-for="item in assemblySizeList" :key="item.value" :command="item.value" :disabled="assemblySize === item.value">
           {{ item.label }}
         </el-dropdown-item>
       </el-dropdown-menu>

+ 21 - 18
src/layouts/components/Header/components/Avatar.vue

@@ -1,15 +1,15 @@
 <template>
   <el-dropdown trigger="click">
-    <div class="avatar">
+    <div class="avatar" v-if="userStore.avatar.indexOf('undefined') === -1">
+      <img :src="userStore.avatar" />
+    </div>
+    <div class="avatar-dft" v-else>
       <img src="@/assets/icons/avatar-user.svg" alt="avatar" />
     </div>
     <template #dropdown>
       <el-dropdown-menu>
-        <el-dropdown-item @click="openDialog('infoRef')">
-          <el-icon><User /></el-icon>{{ $t('header.personalData') }}
-        </el-dropdown-item>
-        <el-dropdown-item @click="openDialog('passwordRef')">
-          <el-icon><Edit /></el-icon>{{ $t('header.changePassword') }}
+        <el-dropdown-item @click="toProfile()">
+          <el-icon><User /></el-icon>{{ $t('header.personalCenter') }}
         </el-dropdown-item>
         <el-dropdown-item divided @click="logout">
           <el-icon><SwitchButton /></el-icon>{{ $t('header.logout') }}
@@ -17,17 +17,13 @@
       </el-dropdown-menu>
     </template>
   </el-dropdown>
-  <!-- infoDialog -->
   <InfoDialog ref="infoRef"></InfoDialog>
-  <!-- passwordDialog -->
   <PasswordDialog ref="passwordRef"></PasswordDialog>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue'
 import { LOGIN_URL } from '@/config'
 import { useRouter } from 'vue-router'
-// import { logoutApi } from '@/api/modules/login'
 import { useUserStore } from '@/stores/modules/user'
 import { ElMessageBox, ElMessage } from 'element-plus'
 import InfoDialog from './InfoDialog.vue'
@@ -35,7 +31,11 @@ import PasswordDialog from './PasswordDialog.vue'
 
 const router = useRouter()
 const userStore = useUserStore()
+console.log('userStore.avatar', userStore.avatar.indexOf('undefined') !== -1)
 
+const toProfile = () => {
+  router.push('/system/user/profile')
+}
 // 退出登录
 const logout = () => {
   ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
@@ -51,18 +51,21 @@ const logout = () => {
     ElMessage.success('退出登录成功!')
   })
 }
-
-// 打开修改密码和个人信息弹窗
-const infoRef = ref<InstanceType<typeof InfoDialog> | null>(null)
-const passwordRef = ref<InstanceType<typeof PasswordDialog> | null>(null)
-const openDialog = (ref: string) => {
-  if (ref == 'infoRef') infoRef.value?.openDialog()
-  if (ref == 'passwordRef') passwordRef.value?.openDialog()
-}
 </script>
 
 <style scoped lang="scss">
 .avatar {
+  width: 40px;
+  height: 40px;
+  overflow: hidden;
+  cursor: pointer;
+  border-radius: 50%;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+.avatar-dft {
   width: 40px;
   height: 40px;
   overflow: hidden;

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно