Browse Source

feat(油机详情页面):对接油机详情API
feat(油机更多详情页面):油机更多详情页面开发,对接油机更多详情页面API
feat(第三方权限应用管理页面):应用管理页面开发,对接应用管理页面API
feat(第三方应用权限管理页面):权限管理页面开发,对接权限管理页面API
feat(第三方应用角色管理页面):角色管理页面开发,对接角色管理页面API
feat(第三方应用视图管理页面):视图管理页面开发,对接视图管理页面API
feat(第三方应用操作日志页面):操作日志页面开发,对接操作日志页面API

xu 1 year ago
parent
commit
8d239dd23a
53 changed files with 6271 additions and 603 deletions
  1. 281 0
      admin.ui.plus-master/src/api/admin/Permission.ts
  2. 57 0
      admin.ui.plus-master/src/api/admin/Role.ts
  3. 334 3
      admin.ui.plus-master/src/api/admin/data-contracts.ts
  4. 26 0
      admin.ui.plus-master/src/api/admin/deviceAuthorization/fuelingftpApi.ts
  5. 0 0
      admin.ui.plus-master/src/api/admin/deviceAuthorization/fuelingftpDto.ts
  6. 23 1
      admin.ui.plus-master/src/api/admin/deviceAuthorization/oilSdkAuthor.ts
  7. 30 0
      admin.ui.plus-master/src/api/admin/deviceAuthorization/oilSdkAuthorDto.ts
  8. 14 4
      admin.ui.plus-master/src/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesApi.ts
  9. 104 0
      admin.ui.plus-master/src/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesDto.ts
  10. 165 177
      admin.ui.plus-master/src/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsApi.ts
  11. 34 65
      admin.ui.plus-master/src/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsDto.ts
  12. 138 94
      admin.ui.plus-master/src/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsApi.ts
  13. 203 0
      admin.ui.plus-master/src/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsDto.ts
  14. 7 0
      admin.ui.plus-master/src/i18n/lang/en.ts
  15. 7 0
      admin.ui.plus-master/src/i18n/lang/zh-cn.ts
  16. 7 0
      admin.ui.plus-master/src/i18n/lang/zh-tw.ts
  17. 125 15
      admin.ui.plus-master/src/router/route.ts
  18. 2 1
      admin.ui.plus-master/src/stores/globalCacheStore.ts
  19. 186 0
      admin.ui.plus-master/src/views/admin/authorize/fuelingFTP/index.vue
  20. 109 0
      admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/components/form-audit.vue
  21. 3 3
      admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/components/form-edit.vue
  22. 39 19
      admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/index.vue
  23. 11 1
      admin.ui.plus-master/src/views/admin/authorize/softwarePackageManagement/components/form-edit.vue
  24. 8 4
      admin.ui.plus-master/src/views/admin/authorize/softwarePackageManagement/index.vue
  25. 4 4
      admin.ui.plus-master/src/views/admin/login/component/account.vue
  26. 1 1
      admin.ui.plus-master/src/views/admin/login/component/mobile.vue
  27. 6 0
      admin.ui.plus-master/src/views/admin/login/index.vue
  28. 1 1
      admin.ui.plus-master/src/views/admin/product/record/index.vue
  29. 1 3
      admin.ui.plus-master/src/views/admin/product/type/index.vue
  30. 174 69
      admin.ui.plus-master/src/views/admin/statement/listOfOilEngines/index.vue
  31. 317 0
      admin.ui.plus-master/src/views/admin/statement/moreAlert/index.vue
  32. 124 36
      admin.ui.plus-master/src/views/admin/statement/moreOilEngineDetails/index.vue
  33. 169 80
      admin.ui.plus-master/src/views/admin/statement/oilEngineDetails/index.vue
  34. 18 13
      admin.ui.plus-master/src/views/admin/visualization/cityLevelMap/index.vue
  35. 10 8
      admin.ui.plus-master/src/views/admin/visualization/digitalMap/index.vue
  36. 0 1
      admin.ui.plus-master/src/views/admin/workbench/index.vue
  37. 127 0
      admin.ui.plus-master/src/views/example/application/applicationManage/components/org-form.vue
  38. 110 0
      admin.ui.plus-master/src/views/example/application/applicationManage/components/org-menu.vue
  39. 124 0
      admin.ui.plus-master/src/views/example/application/applicationManage/index.vue
  40. 115 0
      admin.ui.plus-master/src/views/example/application/operationLog/index.vue
  41. 243 0
      admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-dot-form.vue
  42. 233 0
      admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-group-form.vue
  43. 274 0
      admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-menu-form.vue
  44. 248 0
      admin.ui.plus-master/src/views/example/application/permissionManage/index.vue
  45. 110 0
      admin.ui.plus-master/src/views/example/application/roleManage/components/org-menu.vue
  46. 141 0
      admin.ui.plus-master/src/views/example/application/roleManage/components/role-form.vue
  47. 152 0
      admin.ui.plus-master/src/views/example/application/roleManage/components/set-app-menu.vue
  48. 163 0
      admin.ui.plus-master/src/views/example/application/roleManage/components/set-role-menu.vue
  49. 202 0
      admin.ui.plus-master/src/views/example/application/roleManage/components/user-select.vue
  50. 356 0
      admin.ui.plus-master/src/views/example/application/roleManage/index.vue
  51. 160 0
      admin.ui.plus-master/src/views/example/application/viewManage/components/view-form.vue
  52. 139 0
      admin.ui.plus-master/src/views/example/application/viewManage/index.vue
  53. 636 0
      admin.ui.plus-master/src/views/example/codeGeneration/index.vue

+ 281 - 0
admin.ui.plus-master/src/api/admin/Permission.ts

@@ -29,6 +29,10 @@ import {
   ResultOutputPermissionGetDotOutput,
   ResultOutputPermissionGetGroupOutput,
   ResultOutputPermissionGetMenuOutput,
+  oauthPermissionDto,
+  OauthApplyDto,
+  OauthViewDto,
+  OauthRoleDto
 } from './data-contracts'
 import { ContentType, HttpClient, RequestParams } from './http-client'
 
@@ -456,4 +460,281 @@ export class PermissionApi<SecurityDataType = unknown> extends HttpClient<Securi
       type: ContentType.Json,
       ...params,
     })
+  /**
+  * No description
+  *
+  * @tags permission
+  * @name addAppPermission
+  * @summary 应用权限-新增分组、菜单、权限点
+  * @request POST:/api/app/permission/upload-permission
+  * @secure
+  */
+  addAppPermission = (data: oauthPermissionDto, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/permission/upload-permission`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getPermissionInfo
+  * @summary  获取应用权限信息
+  * @request GET:/api/app/permission/get-permission
+  * @secure
+  */
+  getPermissionInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/permission/get-permission',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
+  /**
+  * No description
+  *
+  * @tags permission
+  * @name permissionDelete
+  * @summary 彻底删除应用权限
+  * @request POST:/api/app/permission/delete-permission
+  * @secure
+  */
+  permissionDelete = ( query:oauthPermissionDto,params: RequestParams = {}):any =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/permission/delete-permission`,
+      method: 'POST',
+      body: query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getApplyInfo
+  * @summary  获取应用信息
+  * @request GET:/api/app/apply/get-apply
+  * @secure
+  */
+  getApplyInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/apply/get-apply',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
+   /**
+   * No description
+   *
+   * @tags apply
+   * @name addApply
+   * @summary 新增、编辑应用
+   * @request POST:/api/app/permission/upload-permission
+   * @secure
+   */
+  addApply = (data: OauthApplyDto, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/apply/upload-apply`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+ /**
+  * No description
+  *
+  * @tags apply
+  * @name applyDelete
+  * @summary 删除应用
+  * @request POST:/api/app/permission/delete-permission
+  * @secure
+  */
+  applyDelete = ( query:any,params: RequestParams = {}):any =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/apply/delete-apply`,
+      method: 'POST',
+      body: query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getViewInfo
+  * @summary  获取视图信息
+  * @request GET:/api/app/view/get-permission
+  * @secure
+  */
+  getViewInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/view/get-permission',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
+  /**
+  * No description
+  *
+  * @tags view
+  * @name addView
+  * @summary 新增、编辑视图
+  * @request POST:/api/app/view/upload-view
+  * @secure
+  */
+  addView = (data: OauthViewDto, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/view/upload-view`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags view
+  * @name viewDelete
+  * @summary 删除视图
+  * @request POST:/api/app/view/delete-permission
+  * @secure
+  */
+  viewDelete = ( query:any,params: RequestParams = {}):any =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/view/delete-permission`,
+      method: 'POST',
+      body: query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getRoleInfo
+  * @summary  获取角色信息
+  * @request GET:/api/app/role/get-role
+  * @secure
+  */
+  getRoleInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/role/get-role',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
+  /**
+  * No description
+  *
+  * @tags role
+  * @name addRole
+  * @summary 新增、编辑角色
+  * @request POST:/api/app/role/upload-role
+  * @secure
+  */
+  addRole = (data: OauthRoleDto, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/role/upload-role`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags role
+  * @name roleDelete
+  * @summary 删除角色
+  * @request POST:/api/app/role/delete-role
+  * @secure
+  */
+  roleDelete = ( query:any,params: RequestParams = {}):any =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/role/delete-role`,
+      method: 'POST',
+      body: query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+  })
+  /**
+  * No description
+  *
+  * @tags role
+  * @name roleMenuAssign
+  * @summary 角色菜单权限
+  * @request POST:/api/app/role/assign
+  * @secure
+  */
+  roleMenuAssign = (data: any,query:any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/role/assign`,
+      method: 'POST',
+      body: data,
+      query:query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getOperationInfo
+  * @summary  获取操作日志信息
+  * @request POST:/api/app/operation-record/get-page
+  * @secure
+  */
+  getOperationInfo = (query:any ,params: RequestParams = {}) : any  =>
+  this.request<AxiosResponse,any>({
+    path:'/api/app/operation-record/get-page',
+    method: 'POST',
+    secure: true,
+    type: ContentType.Json,
+    format: 'json',
+    body:query,
+    ...params
+  })
+  /**
+  * No description
+  *
+  * @tags data
+  * @name getMenuInfo
+  * @summary  获取角色应用权限菜单信息
+  * @request GET:/api/app/role/get-role
+  * @secure
+  */
+  getMenuInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/role/get-permission',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
 }

+ 57 - 0
admin.ui.plus-master/src/api/admin/Role.ts

@@ -294,4 +294,61 @@ export class RoleApi<SecurityDataType = unknown> extends HttpClient<SecurityData
       type: ContentType.Json,
       ...params,
     })
+    /**
+  * No description
+  *
+  * @tags data
+  * @name getApplyInfo
+  * @summary  获取应用角色用户信息
+  * @request GET:/api/app/role/get-role-user-list
+  * @secure
+  */
+  getApplyRoseUserInfo = (query:any ,params: RequestParams = {}) : any  =>
+    this.request<AxiosResponse,any>({
+      path:'/api/app/role/get-role-user-list',
+      method: 'GET',
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      query:query,
+      ...params
+    })
+    /**
+  * No description
+  *
+  * @tags roleUser
+  * @name addApplyRoseUser
+  * @summary 添加应用角色用户信息
+  * @request POST:/api/app/role/add-role-user
+  * @secure
+  */
+  addApplyRoseUser = (data: any,query:any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/role/add-role-user`,
+      method: 'POST',
+      body: data,
+      query:query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
+    /**
+  * No description
+  *
+  * @tags roleUser
+  * @name deleteApplyRoseUser
+  * @summary 删除应用角色用户信息
+  * @request POST:/api/app/role/remove-role-user
+  * @secure
+  */
+  deleteApplyRoseUser = (data: any,query:any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/role/remove-role-user`,
+      method: 'POST',
+      body: data,
+      query:query,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
 }

+ 334 - 3
admin.ui.plus-master/src/api/admin/data-contracts.ts

@@ -4397,11 +4397,342 @@ export interface ViewUpdateInput {
    */
   id: number
 }
+/** 应用权限-新增分组、菜单、权限点 */
+export interface oauthPermissionDto {
+  id: number
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 权限名称 */
+  label?: string | null
+  /** 编码 */
+  code?: string | null
+  /** 权限类型 */
+  type?: number | null
+  /** 图标 */
+  icon?: string | null
+  /** 排序 */
+  sort?: string|null
+  /** 应用id */
+  appID?: number
+  /** 视图 */
+  viewId?: string|null
+  /** 说明 */
+  // description?: string | null
+}
+/** 应用权限 */
+export interface OauthPermission {
+  /** 主键id */
+  id: number
+  /** 创建者id */
+  createdUserId: number
+  /** 创建者 */
+  createdUserName: string | null
+  /** 创建时间 */
+  createdTime: string | null
+  /** 修改者id */
+  modifiedUserId: number
+  /** 修改者 */
+  modifiedUserName: string | null
+  /** 修改时间 */
+  modifiedTime: string | null
+  /** 是否删除 */
+  isDeleted: boolean
+  /** 版本 */
+  version: number
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 权限名称 */
+  label?: string | null
+  /** 编码 */
+  code?: string | null
+  /** 权限类型 */
+  type?: number | null
+  /** 图标 */
+  icon?: string | null
+  /** 排序 */
+  sort?: string|null
+  /** 应用id */
+  appID?: number
+  /** 视图 */
+  viewId?: string|null
+  /** 展开 */
+  opened?: boolean
+  /** 说明 */
+  // description?: string | null
+}
+/** 应用权限信息输出 */
+export interface ResultOutputListOauthPermission{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: OauthPermission[] | null
+}
+/** 应用请求参数 */
+export interface OauthApplyDto{
+  id: number
+  /** 应用id */
+  appid?: string
+  /** 应用名称 */
+  name?: string | null
+  /** 编码 */
+  code?: string | null
+  /** 排序 */
+  sort?: string|null
+}
+/** 应用 */
+export interface OauthApply{
+  /** 主键id */
+  id: number
+  /** 创建者id */
+  createdUserId: number
+  /** 创建者 */
+  createdUserName: string | null
+  /** 创建时间 */
+  createdTime: string | null
+  /** 修改者id */
+  modifiedUserId: number
+  /** 修改者 */
+  modifiedUserName: string | null
+  /** 修改时间 */
+  modifiedTime: string | null
+  /** 是否删除 */
+  isDeleted: boolean
+  /** 版本 */
+  version: number
+  /** 应用id */
+  appid?: string
+  /** 应用名称 */
+  name?: string | null
+  /** 编码 */
+  code?: string | null
+  /** 排序 */
+  sort?: string|null
+}
+/** 应用信息输出 */
+export interface ResultOutputListOauthApply{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: OauthApply[] | null
+}
+/** 应用视图 */
+export interface OauthView{
+  /** 主键id */
+  id: number
+  /** 创建者id */
+  createdUserId: number
+  /** 创建者 */
+  createdUserName: string | null
+  /** 创建时间 */
+  createdTime: string | null
+  /** 修改者id */
+  modifiedUserId: number
+  /** 修改者 */
+  modifiedUserName: string | null
+  /** 修改时间 */
+  modifiedTime: string | null
+  /** 是否删除 */
+  isDeleted: boolean
+  /** 版本 */
+  version: number
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 视图名称 */
+  label?: string
+  /** 视图地址 */
+  path?: string | null
+  /** 排序 */
+  sort?: string|null
+  /** 应用id */
+  appID?: number
+}
+/** 应用视图信息输出 */
+export interface ResultOutputListOauthView{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: OauthView[] | null
+}
+/** 视图请求参数 */
+export interface OauthViewDto{
+  id: number
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 视图名称 */
+  label?: string
+  /** 视图地址 */
+  path?: string | null
+  /** 排序 */
+  sort?: string|null
+  /** 应用id */
+  appID?: string
+}
+/** 角色请求参数 */
+export interface OauthRoleDto{
+  id:number,
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 角色名称 */
+  name?: string
+  /** 编码 */
+  code?: string | null
+  /** 类型 */
+  type?:RoleType
+  /** 说明 */
+  description?:string|null
+  /** 排序 */
+  sort?: string|null
+}
+/** 应用角色 */
+export interface OauthRole{
+  /** 主键id */
+  id: number
+  /** 创建者id */
+  createdUserId: number
+  /** 创建者 */
+  createdUserName: string | null
+  /** 创建时间 */
+  createdTime: string | null
+  /** 修改者id */
+  modifiedUserId: number
+  /** 修改者 */
+  modifiedUserName: string | null
+  /** 修改时间 */
+  modifiedTime: string | null
+  /** 是否删除 */
+  isDeleted: boolean
+  /** 版本 */
+  version: number
+  /** 上一级分组 */
+  parentId?: string | null
+  /** 角色名称 */
+  name?: string
+  /** 编码 */
+  code?: string | null
+  /** 类型 */
+  type?:RoleType
+  /** 说明 */
+  description?:string|null
+  /** 排序 */
+  sort?: string|null
+}
+/** 应用角色信息输出 */
+export interface ResultOutputListOauthRole{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: OauthRole[] | null
+}
+/** 操作日志信息 */
+export interface OauthOperationRecordGetPageOutPut{
+  /** 操作类型 */
+  operationType?: string |null
+  /** 模块名称 */
+  moduleName?: string | null
+  /** 描述 */
+  operationContent?: string | null
+  /** 操作前 */
+  beforeState?: string | null
+  /** 操作后 */
+  afterState?: string | null
+  /** 操作结果 */
+  result?: string | null
+  /** 操作人 */
+  createdUserName?: string | null
+  /** 操作时间 */
+  createdTime?: string | null
+}
+/** 操作日志输出信息 */
+export interface PageOutputOauthOperationRecordGetPageOutPut{
+  /** 数据总数 */
+  total?: number |null
+  /** 数据 */
+  list?: OauthOperationRecordGetPageOutPut[] | null
+}
+/** 操作日志信息输出 */
+export interface ResultOutputPageOutputOauthOperationRecordGetPageOutPut{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: PageOutputOauthOperationRecordGetPageOutPut | null
+}
 
+export interface Filter {
+  /** 操作类型 */
+  operationType?: string |null
+  /** 模块名称 */
+  moduleName?: string | null
+  /** 操作人 */
+  createdUserName?: string | null
+  /** 操作时间 */
+  createdTime?: string | null
+}
 
-
-
-
+/** 操作日志分页信息输入 */
+export interface PageInputOperationGetPageDto {
+  /**
+   * 当前页标
+   * @format int32
+   */
+  currentPage?: number
+  /**
+   * 每页大小
+   * @format int32
+   */
+  pageSize?: number
+  filter?: Filter
+}
+/** 角色应用权限菜单输出 */
+export interface ResultOutputList {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: [] | null
+}
+/** 角色应用用户信息 */
+export interface UserDto {
+  /** 用户id */
+  id?: number | null
+  /** 用户名 */
+  name?: string | null
+  /** 手机号 */
+  mobile?: string | null
+}
+/** 角色应用用户信息输出 */
+export interface ResultOutputListUserDto {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: UserDto[] | null
+}
 
 
 

+ 26 - 0
admin.ui.plus-master/src/api/admin/deviceAuthorization/fuelingftpApi.ts

@@ -0,0 +1,26 @@
+import {ContentType, HttpClient, RequestParams,} from "/@/api/admin/http-client";
+import {AxiosResponse} from "axios/index";
+
+export class FuelingFtpAPI<SecurityDataType = unknown> extends HttpClient<SecurityDataType>{
+
+  /**
+   * No description
+   *
+   * @tags
+   * @name getFtpPwd
+   * @summary 获取FTP密码
+   * @request POST:/api/app/fuel-ftp/get-fuel-ftp-key
+   * @secure
+   */
+  getFtpPwd = (data:any,params: RequestParams = {}) =>
+    this.request<AxiosResponse,any>({
+        path:'/api/app/fuel-ftp/get-fuel-ftp-key',
+        method: 'POST',
+        body:data,
+        secure: true,
+        type: ContentType.Json,
+        format: 'json',
+        ...params
+      }
+    )
+}

+ 0 - 0
admin.ui.plus-master/src/api/admin/deviceAuthorization/fuelingftpDto.ts


+ 23 - 1
admin.ui.plus-master/src/api/admin/deviceAuthorization/oilSdkAuthor.ts

@@ -2,7 +2,8 @@ import {ContentType, HttpClient, RequestParams,} from "/@/api/admin/http-client"
 import {
   oilSdkAuthorDtoResult,
   oilSdkAuthorPostPageDto,
-  oilSdkTableModel
+  oilSdkTableModel,
+  FueilingSdkAuthInput
 } from "/@/api/admin/deviceAuthorization/oilSdkAuthorDto";
 import {AxiosResponse} from "axios/index";
 
@@ -69,4 +70,25 @@ export class OilSdkAuthorAPI<SecurityDataType = unknown> extends HttpClient<Secu
         ...params
     }
     )
+
+    /**
+  * No description
+  *
+  * @tags
+  * @name updateForm
+  * @summary 批量审核
+  * @request PUT:
+  * @secure
+  */
+  updateForms = (data:FueilingSdkAuthInput, params: RequestParams = {}) =>
+  this.request<AxiosResponse,any>({
+      path:'/api/app/fueiling-sdk-auth/updates',
+      method: 'PUT',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      ...params
+  }
+  )
 }

+ 30 - 0
admin.ui.plus-master/src/api/admin/deviceAuthorization/oilSdkAuthorDto.ts

@@ -116,3 +116,33 @@ export interface oilSdkAuthorPostPageDto {
   PageSize?: number
   Filter?: oilSdkFilterModel
 }
+/** 审核数据输入 */
+export interface FueilingSdkAuthInput{
+  /**id*/
+  guid: number,
+  /**加油站*/
+  oilStation: string | null,
+  /**项目名称*/
+  project?: string | null,
+  /**设备SN号*/
+  sn: string | null,
+  /**授权码*/
+  key: string | null,
+  /**状态*/
+  state: string | null | number,
+  /**授权开始时间*/
+  expiedTime: string | null,
+  /**备注*/
+  remark: string | null
+}
+/**结果输出*/
+export interface ResultOutputBoolean {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 分页信息输出 */
+  data?: boolean
+}

+ 14 - 4
admin.ui.plus-master/src/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesApi.ts

@@ -1,4 +1,5 @@
-import {HttpClient} from "/@/api/admin/http-client";
+import {ContentType, HttpClient, RequestParams} from "/@/api/admin/http-client";
+import {PageInputFuelDispenserDto,ResultOutputPageOutputFuelDispenserDto} from "/@/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesDto";;
 
 export class ListOfOilEnginesApi <SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
 
@@ -8,13 +9,22 @@ export class ListOfOilEnginesApi <SecurityDataType = unknown> extends HttpClient
   * @tags List
   * @name GetPage
   * @summary 查询分页
-  * @request GET:
+  * @request POST:
   * @secure
   */
 
   timer = 200
-
-  getPage = () =>
+  getPage = (data: PageInputFuelDispenserDto, params: RequestParams = {}) =>
+    this.request<ResultOutputPageOutputFuelDispenserDto, any>({
+      path: `/api/app/fuel-dispenser/get-download-record`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      format: 'json',
+      ...params,
+    })
+  getPage2 = () =>
     new Promise(resolve => {
       setTimeout(() => {
         resolve({

+ 104 - 0
admin.ui.plus-master/src/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesDto.ts

@@ -0,0 +1,104 @@
+/**
+ * And=0,Or=1
+ * @format int32
+ */
+export type DynamicFilterLogic = 0 | 1
+
+/**
+ * Contains=0,StartsWith=1,EndsWith=2,NotContains=3,NotStartsWith=4,NotEndsWith=5,Equal=6,Equals=7,Eq=8,NotEqual=9,GreaterThan=10,GreaterThanOrEqual=11,LessThan=12,LessThanOrEqual=13,Range=14,DateRange=15,Any=16,NotAny=17,Custom=18
+ * @format int32
+ */
+export type DynamicFilterOperator = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18
+export interface DynamicFilterInfo {
+  field?: string | null
+  /** Contains=0,StartsWith=1,EndsWith=2,NotContains=3,NotStartsWith=4,NotEndsWith=5,Equal=6,Equals=7,Eq=8,NotEqual=9,GreaterThan=10,GreaterThanOrEqual=11,LessThan=12,LessThanOrEqual=13,Range=14,DateRange=15,Any=16,NotAny=17,Custom=18 */
+  operator?: DynamicFilterOperator
+  value?: string
+  /** And=0,Or=1 */
+  logic?: DynamicFilterLogic
+  filters?: DynamicFilterInfo[] | null
+}
+/**
+ * 油机列表查询信息
+ */
+export  interface FuelDispenserDto_SearchFilter{
+  /**加油号*/
+  name?: string,
+  /**加油站*/
+  gasStation?: string,
+  /**加油机机型*/
+  model?: string,
+  /**设备状态*/
+  deviceStatus?: string,
+  /**在线状态*/
+  onlineStatus?: string,
+}
+
+/**
+ * 油机列表信息
+ */
+export  interface FuelDispenserDto{
+  /**加油号*/
+  name?: string,
+  /**石油公司*/
+  oilCompany?: string,
+  /**加油站*/
+  gasStation?: string,
+  /**序列号*/
+  serialNumber?: string,
+  /**加油机机型*/
+  model?: string,
+  /**加油机枪数量*/
+  gunCount?: number,
+  /**加油机厂商*/
+  manufacturer?: string,
+  /**出厂时间*/
+  manufactureDate?: string,
+  /**启动时间*/
+  startupDate?: string,
+  /**安装时间*/
+  installationDate?: string,
+  /**设备状态*/
+  deviceStatus?: string,
+  /**在线状态*/
+  onlineStatus?: string
+}
+
+/** 分页信息输出*/
+export interface PageOutputFuelDispenserDto{
+  /**
+   * 数据总数
+   * @format int64
+   */
+  total?: number
+  /** 数据 */
+  list?: FuelDispenserDto[] | null
+}
+
+/**结果输出*/
+export interface ResultOutputPageOutputFuelDispenserDto{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 分页信息输出 */
+  data?: PageOutputFuelDispenserDto
+}
+
+/** 分页信息输入 */
+export interface PageInputFuelDispenserDto{
+  /**
+   * 当前页标
+   * @format int32
+   */
+  CurrentPage?: number
+  /**
+   * 每页大小
+   * @format int32
+   */
+  PageSize?: number
+  dynamicFilter?: DynamicFilterInfo
+  filter?: FuelDispenserDto_SearchFilter
+}

+ 165 - 177
admin.ui.plus-master/src/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsApi.ts

@@ -1,5 +1,5 @@
-import {HttpClient} from "/@/api/admin/http-client";
-
+import { ContentType, HttpClient, RequestParams } from "/@/api/admin/http-client";
+import { AxiosResponse } from 'axios'
 export class MoreOilEngineDetailsApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType>{
 
   timer = 400
@@ -9,112 +9,121 @@ export class MoreOilEngineDetailsApi<SecurityDataType = unknown> extends HttpCli
    * @tags data
    * @name getOilListData
    * @summary  获取油机列表详情数据
-   * @request GET:
+   * @request POST:/api/app/fuel-dispenser/get-nozzlecontrol
    * @secure
    */
-  getOilListData = () =>
-    new Promise(resolve => {
-      setTimeout(() => {
-        resolve(
-          {
-            success: true,
-            code: null,
-            msg: null,
-            data:
-              [
-                {
-                  oilEngineName: "17",
-                  oilEngineStatus: "离线",
-                  oilSpecifications: "1主板1枪",
-                  oils: "95号车用汽油",
-                  selfLockingState: "关闭",
-                  ECQSCode: "200023204009",
-                },
-                {
-                  oilEngineName: "18",
-                  oilEngineStatus: "离线",
-                  oilSpecifications: "1主板2枪",
-                  oils: "95号车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204015",
-                },
-                {
-                  oilEngineName: "19",
-                  oilEngineStatus: "离线",
-                  oilSpecifications: "1主板3枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204036",
-                },
-                {
-                  oilEngineName: "20",
-                  oilEngineStatus: "离线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "21",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "22",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "23",
-                  oilEngineStatus: "离线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "24",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "25",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "26",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                },
-                {
-                  oilEngineName: "27",
-                  oilEngineStatus: "在线",
-                  oilSpecifications: "1主板4枪",
-                  oils: "98车用汽油",
-                  selfLockingState: "已启动",
-                  ECQSCode: "200023204059",
-                }
-              ]
-          }
-        )
-      },this.timer)
+  getOilListData = (data: any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/fuel-dispenser/get-nozzlecontrol`,
+      method: 'POST',
+      query: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
     })
+  // getOilListData = () =>
+  //   new Promise(resolve => {
+  //     setTimeout(() => {
+  //       resolve(
+  //         {
+  //           success: true,
+  //           code: null,
+  //           msg: null,
+  //           data:
+  //             [
+  //               {
+  //                 oilEngineName: "17",
+  //                 oilEngineStatus: "离线",
+  //                 oilSpecifications: "1主板1枪",
+  //                 oils: "95号车用汽油",
+  //                 selfLockingState: "关闭",
+  //                 ECQSCode: "200023204009",
+  //               },
+  //               {
+  //                 oilEngineName: "18",
+  //                 oilEngineStatus: "离线",
+  //                 oilSpecifications: "1主板2枪",
+  //                 oils: "95号车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204015",
+  //               },
+  //               {
+  //                 oilEngineName: "19",
+  //                 oilEngineStatus: "离线",
+  //                 oilSpecifications: "1主板3枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204036",
+  //               },
+  //               {
+  //                 oilEngineName: "20",
+  //                 oilEngineStatus: "离线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "21",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "22",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "23",
+  //                 oilEngineStatus: "离线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "24",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "25",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "26",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               },
+  //               {
+  //                 oilEngineName: "27",
+  //                 oilEngineStatus: "在线",
+  //                 oilSpecifications: "1主板4枪",
+  //                 oils: "98车用汽油",
+  //                 selfLockingState: "已启动",
+  //                 ECQSCode: "200023204059",
+  //               }
+  //             ]
+  //         }
+  //       )
+  //     },this.timer)
+  //   })
 
   /**
    * No description
@@ -122,79 +131,58 @@ export class MoreOilEngineDetailsApi<SecurityDataType = unknown> extends HttpCli
    * @tags data
    * @name getTableData
    * @summary  获取表格数据对象
-   * @request GET:
-   * @secure
-   */
-  getTableData = () =>
-    new Promise(resolve => {
-      setTimeout(() => {
-        resolve({
-          success: true,
-          code: null,
-          msg: null,
-          data:[{
-            time: "string",
-            refuelingGun: "string",
-            alarmSource: "string",
-            alarmDescription: "string",
-            alarmType: "string"
-          },{
-            time: "string",
-            refuelingGun: "string",
-            alarmSource: "string",
-            alarmDescription: "string",
-            alarmType: "string"
-          },{
-            time: "string",
-            refuelingGun: "string",
-            alarmSource: "string",
-            alarmDescription: "string",
-            alarmType: "string"
-          },{
-            time: "string",
-            refuelingGun: "string",
-            alarmSource: "string",
-            alarmDescription: "string",
-            alarmType: "string"
-          }]
-        })
-      },this.timer)
-    })
-
-  /**
-   * No description
-   *
-   * @tags data
-   * @name getDetailsData
-   * @summary  获取油机详情数据对象
-   * @request GET:
+   * @request POST:/api/app/fuel-dispenser/get-last-five-alarm-history
    * @secure
    */
-  getDetailsData = () =>
-    new Promise(resolve => {
-      setTimeout(() => {
-        resolve({
-          success: true,
-          code: null,
-          msg: null,
-          data:{
-            oilEngineName: "4",
-            factoryNumber: "1904344P",
-            model: "4枪4显2油品潜油泵",
-            manufacture: "托肯恒山科技(广州)有限公司",
-            specifications: "THD2244B2",
-            dateOfManufacture: "2019-11-27 18:28",
-            measuringRange: "5L-50L",
-            installDate: "2019-11-27 18:28",
-            accuracyLevel: "0.3",
-            dateOfActivation: "2019-11-28 18:28",
-            equipmentStatus: "启动",
-            onlineStatus: "离线",
-            alarmStatus: "严重报警",
-            numberOfAlarms: "0",
-            accumulatedOnline: "945天"
-          }
-        })
-      },this.timer)
+  getTableData = (data: any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/fuel-dispenser/get-last-five-alarm-history`,
+      method: 'POST',
+      query: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
     })
+  // getTableData = () =>
+  //   new Promise(resolve => {
+  //     setTimeout(() => {
+  //       resolve({
+  //         success: true,
+  //         code: null,
+  //         msg: null,
+  //         data:[{
+  //           time: "string",
+  //           refuelingGun: "string",
+  //           alarmSource: "string",
+  //           alarmDescription: "string",
+  //           alarmType: "string"
+  //         },{
+  //           time: "string",
+  //           refuelingGun: "string",
+  //           alarmSource: "string",
+  //           alarmDescription: "string",
+  //           alarmType: "string"
+  //         },{
+  //           time: "string",
+  //           refuelingGun: "string",
+  //           alarmSource: "string",
+  //           alarmDescription: "string",
+  //           alarmType: "string"
+  //         },{
+  //           time: "string",
+  //           refuelingGun: "string",
+  //           alarmSource: "string",
+  //           alarmDescription: "string",
+  //           alarmType: "string"
+  //         },
+  //         {
+  //           time: "string",
+  //           refuelingGun: "string",
+  //           alarmSource: "string",
+  //           alarmDescription: "string",
+  //           alarmType: "string"
+  //         }]
+  //       })
+  //     },this.timer)
+  //   })
 }

+ 34 - 65
admin.ui.plus-master/src/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsDto.ts

@@ -1,76 +1,45 @@
+import { AlarmHistoryDto } from "/@/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsDto"
 /**
  * 报表管理 - 油机列表 - 查看更多
  * 数据对象的Dto
  * */
 
-/**
- * 表格数据对象
- */
-export interface moreOilEngineDetails_TableData {
-  /**时间*/
-  time: string
-  /**加油枪*/
-  refuelingGun: string
-  /**报警来源*/
-  alarmSource: string
-  /**报警描述*/
-  alarmDescription: string
-  /**报警类型*/
-  alarmType: string
-}
-
-
-/**
- * 油机详情数据对象
- */
-export interface moreOilEngineDetails_DetailsData {
-  /**油机名称*/
-  oilEngineName: string,
-  /**出厂编号*/
-  factoryNumber: string,
-  /**机型*/
-  model: string,
-  /**制造商*/
-  manufacture: string,
-  /**规格参数*/
-  specifications: string,
-  /**生产日期*/
-  dateOfManufacture: string,
-  /**测量范围*/
-  measuringRange: string,
-  /**安装日期*/
-  installDate: string,
-  /**准确度等级*/
-  accuracyLevel: string,
-  /**启用日期*/
-  dateOfActivation: string,
-  /**设备状态*/
-  equipmentStatus: string,
-  /**在线状态*/
-  onlineStatus: string,
-  /**报警状态*/
-  alarmStatus: string,
-  /**报警次数*/
-  numberOfAlarms: string,
-  /**累计在线时间*/
-  accumulatedOnline: string
+/** 表格数据输出信息 */
+export interface ResultOutputListAlarmHistoryDto {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: AlarmHistoryDto[] | null
 }
-
-
 /**
  * 油机列表详情数据对象
  */
-export interface moreOilEngineDetails_OilListData{
-  /**油机名称*/
-  oilEngineName: string
-  /**油机状态*/
-  oilEngineStatus: string
-  /**油机规格*/
-  oilSpecifications: string
+export interface NozzlecontrolDtl{
+  /**枪号*/
+  name: string
+  /**在线状态*/
+  onlineStatus: string
   /**油品*/
-  oils: string
-  /**自锁状态*/
-  selfLockingState: string
-  /**ECQS编码*/
-  ECQSCode: string
+  fuelName: string
+  /**编码*/
+  code: string
+  /***/
+  mainBoard_NozzleNo: string
+  /**自锁*/
+  alarming: string
+}
+/** 油机列表详情输出信息 */
+export interface ResultOutputListNozzlecontrolDtl {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: NozzlecontrolDtl[] | null
 }

+ 138 - 94
admin.ui.plus-master/src/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsApi.ts

@@ -1,111 +1,155 @@
-import {HttpClient} from "/@/api/admin/http-client";
+import { ContentType, HttpClient, RequestParams } from "/@/api/admin/http-client";
+import { AxiosResponse } from 'axios'
 
 export class OilEngineDetailsApi <SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
-
+  timer = 500
   /**
   * No description
   *
   * @tags
   * @name GetBasicInfo
   * @summary 获取油机详情基本信息
-  * @request GET:
+  * @request POST:/api/app/fuel-dispenser/get-dispensers
   * @secure
   */
-
-  timer = 500
-
-  getBasicInfoDto = () =>
-    new Promise(resolve => {
-      setTimeout(()=>{
-        resolve({
-          data:{
-            oilEngineNumber:"4",
-            serialNumber:"1904344P",
-            oilCompanies:"中石化安徽宣城石油分公司深爱的深爱的",
-            fuelDispenserManufacturer:"托肯恒山科技(广州)有限公司",
-            gasStation:"中石化安徽宣城金陵加油站",
-            specifications:"THD2244B2",
-            measuringRange:"2L-50L",
-            accuracyLevel:"0.3",
-            factoryCode:"1904344P",
-            onlineStatus:"离线",
-            alarmStatus:"严重报警",
-            imgUrl:"upload/2023/09/15/65048ee6-9b3f-2234-0097-734b351ca09d.png"
-          }
-        })
-      },this.timer)
+  getBasicInfoDto = (data: any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/fuel-dispenser/get-dispensers`,
+      method: 'POST',
+      query: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
     })
 
 
-  getAlarmHistoryDto = () =>
-    new Promise(resolve => {
-      setTimeout(() => {
-        resolve({
-          total:100,
-          list:[{
-            time:'2023-07-23 09:36',
-            gasStation:"中化安徽宣城金陵加油站",
-            fillingMachine:"4",
-            fuelDispenserSerialNumber:"1904344P",
-            alarmSource:"云平台",
-            alarmType:"加油机离线",
-            alarmDescription:"加油机(监督装置)长期离线"
-          },{
-            time:'2023-07-23 09:36',
-            gasStation:"中化安徽宣城金陵加油站",
-            fillingMachine:"4",
-            fuelDispenserSerialNumber:"1904344P",
-            alarmSource:"云平台",
-            alarmType:"加油机离线",
-            alarmDescription:"加油机(监督装置)长期离线"
-          },{
-            time:'2023-07-23 09:36',
-            gasStation:"中化安徽宣城金陵加油站",
-            fillingMachine:"4",
-            fuelDispenserSerialNumber:"1904344P",
-            alarmSource:"云平台",
-            alarmType:"加油机离线",
-            alarmDescription:"加油机(监督装置)长期离线"
-          },{
-            time:'2023-07-23 09:36',
-            gasStation:"中化安徽宣城金陵加油站",
-            fillingMachine:"4",
-            fuelDispenserSerialNumber:"1904344P",
-            alarmSource:"云平台",
-            alarmType:"加油机离线",
-            alarmDescription:"加油机(监督装置)长期离线"
-          }]
-        })
-      },this.timer)
+  // getBasicInfoDto = () =>
+  //   new Promise(resolve => {
+  //     setTimeout(()=>{
+  //       resolve({
+  //         data:{
+  //           oilEngineNumber:"4",
+  //           serialNumber:"1904344P",
+  //           oilCompanies:"中石化安徽宣城石油分公司深爱的深爱的",
+  //           fuelDispenserManufacturer:"托肯恒山科技(广州)有限公司",
+  //           gasStation:"中石化安徽宣城金陵加油站",
+  //           specifications:"THD2244B2",
+  //           measuringRange:"2L-50L",
+  //           accuracyLevel:"0.3",
+  //           factoryCode:"1904344P",
+  //           onlineStatus:"离线",
+  //           alarmStatus:"严重报警",
+  //           imgUrl:"upload/2023/09/15/65048ee6-9b3f-2234-0097-734b351ca09d.png"
+  //         }
+  //       })
+  //     },this.timer)
+  //   })
+
+  /**
+  * No description
+  *
+  * @tags
+  * @name GetAlarmHistoryDto
+  * @summary 获取油机详情报警历史列表信息
+  * @request POST:/api/app/fuel-dispenser/get-alarm-history
+  * @secure
+  */
+  getAlarmHistoryDto = (data: any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/fuel-dispenser/get-alarm-history`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
     })
+  // getAlarmHistoryDto = () =>
+  //   new Promise(resolve => {
+  //     setTimeout(() => {
+  //       resolve({
+  //         total:100,
+  //         list:[{
+  //           time:'2023-07-23 09:36',
+  //           gasStation:"中化安徽宣城金陵加油站",
+  //           fillingMachine:"4",
+  //           fuelDispenserSerialNumber:"1904344P",
+  //           alarmSource:"云平台",
+  //           alarmType:"加油机离线",
+  //           alarmDescription:"加油机(监督装置)长期离线"
+  //         },{
+  //           time:'2023-07-23 09:36',
+  //           gasStation:"中化安徽宣城金陵加油站",
+  //           fillingMachine:"4",
+  //           fuelDispenserSerialNumber:"1904344P",
+  //           alarmSource:"云平台",
+  //           alarmType:"加油机离线",
+  //           alarmDescription:"加油机(监督装置)长期离线"
+  //         },{
+  //           time:'2023-07-23 09:36',
+  //           gasStation:"中化安徽宣城金陵加油站",
+  //           fillingMachine:"4",
+  //           fuelDispenserSerialNumber:"1904344P",
+  //           alarmSource:"云平台",
+  //           alarmType:"加油机离线",
+  //           alarmDescription:"加油机(监督装置)长期离线"
+  //         },{
+  //           time:'2023-07-23 09:36',
+  //           gasStation:"中化安徽宣城金陵加油站",
+  //           fillingMachine:"4",
+  //           fuelDispenserSerialNumber:"1904344P",
+  //           alarmSource:"云平台",
+  //           alarmType:"加油机离线",
+  //           alarmDescription:"加油机(监督装置)长期离线"
+  //         }]
+  //       })
+  //     },this.timer)
+  //   })
 
-  getLifeCycleDto = () =>
-    new Promise(resolve => {
-      setTimeout(() => {
-        resolve({
-          total:100,
-          list:[{
-            time:"2023-07-23 09:36",
-            operator:"托肯",
-            operatorID:"123",
-            operation:"132",
-          },{
-            time:"2023-07-23 09:36",
-            operator:"托肯",
-            operatorID:"123",
-            operation:"132",
-          },{
-            time:"2023-07-23 09:36",
-            operator:"托肯",
-            operatorID:"123",
-            operation:"132",
-          },{
-            time:"2023-07-23 09:36",
-            operator:"托肯",
-            operatorID:"123",
-            operation:"132",
-          }]
-        })
-      },this.timer)
+  /**
+  * No description
+  *
+  * @tags
+  * @name GetLifeCycleDto
+  * @summary 获取油机详情生命周期列表信息
+  * @request POST:/api/app/fuel-dispenser/get-life-cycle
+  * @secure
+  */
+  getLifeCycleDto = (data: any, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/app/fuel-dispenser/get-life-cycle`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
     })
+  // getLifeCycleDto = () =>
+  //   new Promise(resolve => {
+  //     setTimeout(() => {
+  //       resolve({
+  //         total:100,
+  //         list:[{
+  //           time:"2023-07-23 09:36",
+  //           operator:"托肯",
+  //           operatorID:"123",
+  //           operation:"132",
+  //         },{
+  //           time:"2023-07-23 09:36",
+  //           operator:"托肯",
+  //           operatorID:"123",
+  //           operation:"132",
+  //         },{
+  //           time:"2023-07-23 09:36",
+  //           operator:"托肯",
+  //           operatorID:"123",
+  //           operation:"132",
+  //         },{
+  //           time:"2023-07-23 09:36",
+  //           operator:"托肯",
+  //           operatorID:"123",
+  //           operation:"132",
+  //         }]
+  //       })
+  //     },this.timer)
+  //   })
 }

+ 203 - 0
admin.ui.plus-master/src/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsDto.ts

@@ -0,0 +1,203 @@
+/**
+ * 油机列表详情输出数据
+ */
+export interface FuelDispenserEntity{
+  /**主键Id*/
+  id: number
+  /**创建者Id*/
+  createdUserId: number
+  /**创建者*/
+  createdUserName: string
+  /**创建时间*/
+  createdTime: string
+  /**修改者Id*/
+  modifiedUserId: number
+  /**修改者*/
+  modifiedUserName: string
+  /**修改时间*/
+  modifiedTime: string
+  /**加油机名称*/
+  name: string
+  /**石油公司*/
+  oilCompany: string
+  /**加油站*/
+  gasStation: string
+  /**序列号*/
+  serialNumber: string
+  /**加油机机型*/
+  model: string
+  /**加油机枪数量*/
+  gunCount: string
+  /**加油机厂商*/
+  manufacturer: string
+  /**出厂时间*/
+  manufactureDate: string
+  /**启动时间*/
+  startupDate: string
+  /**安装时间*/
+  installationDate: string
+  /**设备状态*/
+  deviceStatus: string
+  /**在线状态*/
+  onlineStatus: string
+  /**油机ID*/
+  fuelId: string
+  /**报警状态*/
+  alarmLevel: number
+  /**累计在线时间*/
+  onlineDesc: string
+  /**测量范围*/
+  measureRang: string
+  /**准确度等级*/
+  accuracyLevel: string
+  /**规格参数*/
+  modelSpec: string
+}
+/** 油机详情输出信息 */
+export interface ResultOutputList {
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */
+  data?: FuelDispenserEntity | null
+}
+/**
+ * And=0,Or=1
+ * @format int32
+ */
+export type DynamicFilterLogic = 0 | 1
+
+/**
+ * Contains=0,StartsWith=1,EndsWith=2,NotContains=3,NotStartsWith=4,NotEndsWith=5,Equal=6,Equals=7,Eq=8,NotEqual=9,GreaterThan=10,GreaterThanOrEqual=11,LessThan=12,LessThanOrEqual=13,Range=14,DateRange=15,Any=16,NotAny=17,Custom=18
+ * @format int32
+ */
+export type DynamicFilterOperator = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18
+export interface DynamicFilterInfo {
+  field?: string | null
+  /** Contains=0,StartsWith=1,EndsWith=2,NotContains=3,NotStartsWith=4,NotEndsWith=5,Equal=6,Equals=7,Eq=8,NotEqual=9,GreaterThan=10,GreaterThanOrEqual=11,LessThan=12,LessThanOrEqual=13,Range=14,DateRange=15,Any=16,NotAny=17,Custom=18 */
+  operator?: DynamicFilterOperator
+  value?: string
+  /** And=0,Or=1 */
+  logic?: DynamicFilterLogic
+  filters?: DynamicFilterInfo[] | null
+}
+/**
+ * 油机详情报警历史列表信息
+ */
+export  interface AlarmHistoryDto{
+  /**油机ID*/
+  fuelId: number,
+  /**创建时间*/
+  createdDate?: string,
+  /**加油站*/
+  gasStation?: string,
+  /**油机号*/
+  name?: string,
+  /**序列号*/
+  serialNumber?: string,
+  /*报警来源*/
+  alarmSource?: string,
+  /**报警类型*/
+  alarmType?: string,
+  /**报警描述*/
+  alarmDescription?: string,
+  /**id*/
+  alarmHistoryID: number,
+}
+/** 分页信息输入 */
+export interface PageInputAlarmHistoryDto{
+  /**
+   * 当前页标
+   * @format int32
+   */
+  currentPage?: number
+  /**
+   * 每页大小
+   * @format int32
+   */
+  pageSize?: number
+  dynamicFilter?: DynamicFilterInfo
+  filter?: AlarmHistoryDto
+}
+
+/** 分页信息输出*/
+export interface PageOutputAlarmHistoryDto{
+  /**
+   * 数据总数
+   * @format int64
+   */
+  total?: number
+  /** 数据 */
+  list?: AlarmHistoryDto[] | null
+}
+
+/**结果输出*/
+export interface ResultOutputPageOutputAlarmHistoryDto
+{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 分页信息输出 */
+  data?: PageOutputAlarmHistoryDto
+}
+/**
+ * 油机详情生命周期列表信息
+ */
+export  interface LifeCycleDto{
+  /**油机ID*/
+  fuelId: number,
+  /**创建时间*/
+  createdDate?: string,
+  /**操作人*/
+  operator?: string,
+  /**操作人ID*/
+  operatorID?: number,
+  /**操作*/
+  operation?: string,
+  /**id*/
+  lifeCycleID?: number,
+}
+/** 分页信息输入 */
+export interface PageInputLifeCycleDto{
+  /**
+   * 当前页标
+   * @format int32
+   */
+  currentPage?: number
+  /**
+   * 每页大小
+   * @format int32
+   */
+  pageSize?: number
+  dynamicFilter?: DynamicFilterInfo
+  filter?: LifeCycleDto
+}
+
+/** 分页信息输出*/
+export interface PageOutputLifeCycleDto{
+  /**
+   * 数据总数
+   * @format int64
+   */
+  total?: number
+  /** 数据 */
+  list?: LifeCycleDto[] | null
+}
+
+/**结果输出*/
+export interface ResultOutputPageOutputLifeCycleDto{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 分页信息输出 */
+  data?: PageOutputLifeCycleDto
+}

+ 7 - 0
admin.ui.plus-master/src/i18n/lang/en.ts

@@ -190,4 +190,11 @@ export default {
     btnTwo: 'Update now',
     btnTwoLoading: 'Updating',
   },
+  application:{
+    roleManage:'roleManage',
+    applicationManage:'applicationManage',
+    permissionManage:'permissionManage',
+    viewManage:'viewManage',
+    operationLog:'operationLog',
+  }
 }

+ 7 - 0
admin.ui.plus-master/src/i18n/lang/zh-cn.ts

@@ -190,4 +190,11 @@ export default {
     btnTwo: '马上更新',
     btnTwoLoading: '更新中',
   },
+  application:{
+    roleManage:'角色管理',
+    applicationManage:'应用管理',
+    permissionManage:'权限管理',
+    viewManage:'视图管理',
+    operationLog:'操作日志',
+  }
 }

+ 7 - 0
admin.ui.plus-master/src/i18n/lang/zh-tw.ts

@@ -190,4 +190,11 @@ export default {
     btnTwo: '馬上更新',
     btnTwoLoading: '更新中',
   },
+  application:{
+    roleManage:'角色管理',
+    applicationManage:'应用管理',
+    permissionManage:'权限管理',
+    viewManage:'视图管理',
+    operationLog:'操作日志',
+  }
 }

+ 125 - 15
admin.ui.plus-master/src/router/route.ts

@@ -1122,21 +1122,21 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
                   icon: 'iconfont icon-ico_shuju',
                 },
               },
-              {
-                path: '/example/personal',
-                name: 'example/personal',
-                component: () => import('/@/views/example/personal/index.vue'),
-                meta: {
-                  title: 'message.router.personal',
-                  isLink: '',
-                  isHide: false,
-                  isKeepAlive: true,
-                  isAffix: false,
-                  isIframe: false,
-                  roles: ['admin', 'common'],
-                  icon: 'iconfont icon-gerenzhongxin',
-                },
-              },
+              // {
+              //   path: '/example/personal',
+              //   name: 'example/personal',
+              //   component: () => import('/@/views/example/personal/index.vue'),
+              //   meta: {
+              //     title: 'message.router.personal',
+              //     isLink: '',
+              //     isHide: false,
+              //     isKeepAlive: true,
+              //     isAffix: false,
+              //     isIframe: false,
+              //     roles: ['admin', 'common'],
+              //     icon: 'iconfont icon-gerenzhongxin',
+              //   },
+              // },
               {
                 path: '/example/tools',
                 name: 'example/tools',
@@ -1197,8 +1197,118 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
                   icon: 'iconfont icon-neiqianshujuchucun',
                 },
               },
+              {
+                path: '/example/application',
+                name: 'example/application',
+                component: () => import('/@/layout/routerView/parent.vue'),
+                redirect: '/application/applicationManage',
+                meta: {
+                  title: 'message.application.applicationManage',
+                  isLink: '',
+                  isHide: false,
+                  isKeepAlive: true,
+                  isAffix: false,
+                  isIframe: false,
+                  roles: ['admin', 'common'],
+                  icon: 'iconfont icon-crew_feature',
+                },
+                children: [
+                  {
+                    path: '/example/application/roleManage',
+                    name: 'example/roleManage',
+                    component: () => import('/@/views/example/application/roleManage/index.vue'),
+                    meta: {
+                      title: 'message.application.roleManage',
+                      isLink: '',
+                      isHide: false,
+                      isKeepAlive: true,
+                      isAffix: false,
+                      isIframe: false,
+                      roles: ['admin', 'common'],
+                      icon: 'ele-ColdDrink',
+                    },
+                  },
+                  {
+                    path: '/example/application/permissionManage',
+                    name: 'example/permissionManage',
+                    component: () => import('/@/views/example/application/permissionManage/index.vue'),
+                    meta: {
+                      title: 'message.application.permissionManage',
+                      isLink: '',
+                      isHide: false,
+                      isKeepAlive: true,
+                      isAffix: false,
+                      isIframe: false,
+                      roles: ['admin'],
+                      icon: 'iconfont icon-quanxian',
+                    },
+                  },
+                  {
+                    path: '/example/application/applicationManage',
+                    name: 'example/applicationManage',
+                    component: () => import('/@/views/example/application/applicationManage/index.vue'),
+                    meta: {
+                      title: 'message.application.applicationManage',
+                      isLink: '',
+                      isHide: false,
+                      isKeepAlive: true,
+                      isAffix: false,
+                      isIframe: false,
+                      roles: ['admin'],
+                      icon: 'iconfont icon-crew_feature',
+                    },
+                  },
+                  {
+                    path: '/example/application/viewManage',
+                    name: 'example/viewManage',
+                    component: () => import('/@/views/example/application/viewManage/index.vue'),
+                    meta: {
+                      title: 'message.application.viewManage',
+                      isLink: '',
+                      isHide: false,
+                      isKeepAlive: true,
+                      isAffix: false,
+                      isIframe: false,
+                      roles: ['admin'],
+                      icon: 'iconfont icon-biaodan',
+                    },
+                  },
+                  {
+                    path: '/example/application/operationLog',
+                    name: 'example/operationLog',
+                    component: () => import('/@/views/example/application/operationLog/index.vue'),
+                    meta: {
+                      title: 'message.application.operationLog',
+                      isLink: '',
+                      isHide: false,
+                      isKeepAlive: true,
+                      isAffix: false,
+                      isIframe: false,
+                      roles: ['admin'],
+                      icon: 'ele-Document',
+                    },
+                  },
+                ],
+              },
+
             ],
           },
+          {
+            path: '/statement/:id/more/moreAlert',
+            name: '/statement/:id/more/moreAlert',
+            component: () => import('/@/views/admin/statement/moreAlert/index.vue'),
+            //redirect: '/application/applicationManage',
+            meta: {
+              title: '更多报警',
+              isLink: '',
+              isHide: true,
+              isKeepAlive: true,
+              isAffix: false,
+              isIframe: false,
+              roles: ['admin', 'common'],
+              icon: 'iconfont icon-crew_feature',
+            },
+          },
         ],
   },
 ]

+ 2 - 1
admin.ui.plus-master/src/stores/globalCacheStore.ts

@@ -17,7 +17,8 @@ const arr =
     'groupKeyGroupStatus',
     'softwareType',
     'equipmentType',
-    'softwarePackageStatus'
+    'softwarePackageStatus',
+    'oilEngineStatus'
   ]
 
 export const useGlobalCacheStore = defineStore('globalCacheStore', {

+ 186 - 0
admin.ui.plus-master/src/views/admin/authorize/fuelingFTP/index.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="layout-pd" >
+    <el-row>
+      <!--操作-->
+      <el-col :xs="24" >
+        <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+          <div style="width: 100%;display: flex;justify-content: center;align-items: center;">
+            <h1 style="margin-bottom: 10px;font-size: 30px;">油机动态密钥生成</h1>
+          </div>
+          <div v-if="state.msgDisplay" style="width: 100%;display: flex;justify-content: center;align-items: center;">
+            <h1 style="margin-bottom: 10px;color: #81B337;font-size: 20px;">密码申请成功</h1>
+          </div>
+          <div style="width: 100%;display: flex;justify-content: center;align-items: center;">
+            <el-form :inline="true" @submit.stop.prevent style="width: 60%;">
+              <el-form-item label="申请备注" style="width: 100%;">
+                <el-input v-model="state.filter.remark" style="width: 100%;" placeholder="请输入申请备注" @keyup.enter="onQuery" />
+              </el-form-item>
+            </el-form>
+          </div>
+          <div v-if="state.pwdDisplay" style="width: 100%;display: flex;justify-content: center;align-items: center;">
+            <el-form :inline="true" @submit.stop.prevent style="width: 60%;">
+              <el-form-item label="FTP密码" style="width: 82%;">
+                <el-input disabled v-model="state.filter.pwd" style="width: 100%;" placeholder="FTP密码" @keyup.enter="onQuery" />
+              </el-form-item>
+              <el-form-item>
+                <el-button id="copyBtn" :data-clipboard-text="state.filter.pwd" type="primary" @click="onCopy()">复制</el-button>
+              </el-form-item>
+            </el-form>
+          </div>
+          <div v-if="state.timeDisplay" style="width: 100%;display: flex;justify-content: center;align-items: center;">
+            <el-form :inline="true" @submit.stop.prevent style="width: 60%;">
+              <el-form-item label="过期时间" style="width: 100%;">
+                {{ state.filter.expireTime }}
+              </el-form-item>
+            </el-form>
+          </div>
+          <div v-if="state.btnDisplay" style="display: flex;justify-content: center;align-items: center;">
+            <el-button style="margin-top: 10px;margin-bottom: 10px;width: 264px;height: 42px;" type="primary" @click="onQuery">申请油机FTP密码</el-button>
+        </div>
+        </el-card>
+      </el-col>
+      <!--表格-->
+      <el-col  :xs="24" >
+        <el-card style="height: 70vh" class="my-fill mt8" shadow="hover">
+          <el-table ref="multipleTableRef"
+            v-loading="state.loading"
+            stripe :data="state.tableModel"
+            row-key="id"
+            style="width: 100%" >
+            <el-table-column v-for="column in state.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label" />
+          </el-table>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+
+</template>
+
+<script setup lang="ts" name="authorize/fuelingsdk">
+import { onMounted, reactive, ref, watch, onBeforeMount } from "vue";
+import eventBus from "/@/utils/mitt";
+import { ElMessage, ElTable } from 'element-plus'
+import { FuelingFtpAPI } from '/@/api/admin/deviceAuthorization/fuelingFTPApi'
+import Clipboard from 'clipboard'
+
+const multipleTableRef=ref<InstanceType<typeof ElTable>>()
+/**FTP申请页面对象 */
+const state = reactive({
+  time:'',
+  /**加载显示 */
+  loading: false,
+  /**条件查询模块 */
+  filter: {
+    /**申请备注 */
+    remark: "",
+    /**FTP密码 */
+    pwd: "",
+    /**过期时间 */
+    expireTime: '',
+  },
+  /**表格信息 */
+  tableModel: [
+    {record:1,applyTime:'2024-04-15',applyUserName:'售后-陈*',remark:'现场维修诊断',expireTime:'2024-04-15 23:59:59'},
+    {record:2,applyTime:'2024-04-19',applyUserName:'售后-陈*',remark:'现场维修诊断',expireTime:'2024-04-19 23:59:59'}],
+  /**动态表头 */
+  dynamicColumns: [
+    { prop: 'record', label: '记录' },
+    { prop: 'applyTime', label: '申请时间' },
+    { prop: 'applyUserName', label: '申请人' },
+    { prop: 'remark', label: '备注' },
+    { prop: 'expireTime', label: '密钥过期时间' }
+  ],
+  pwdDisplay:false,
+  timeDisplay:false,
+  btnDisplay:true,
+  msgDisplay:false,
+})
+
+/**初始化 */
+const init = async () => {
+  state.filter.remark=''
+  state.filter.pwd=''
+  const time=new Date()
+  state.filter.expireTime=time.getFullYear()+'-'+(time.getMonth()+1)+'-'+time.getDate()+' 23:59:59'
+  state.btnDisplay=true
+  state.msgDisplay=false
+  state.pwdDisplay=false
+  state.timeDisplay=false
+}
+
+onMounted(() => {
+  init()
+  eventBus.off('refreshView')
+  eventBus.on('refreshView', async () => {
+    init()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshView')
+})
+
+/**
+ * 监听时间变换
+ */
+watch(() => state.time, (newVal ) => {
+  if(newVal.length === 0){
+    return
+  }
+  state.filter.expireTime = newVal?.[0].toString()
+})
+/**复制FTP密码 */
+const onCopy=()=>{
+  const clipboard=new Clipboard('#copyBtn')
+  clipboard.on('success',()=>{
+    ElMessage.success('复制成功')
+    clipboard.destroy()
+  })
+  clipboard.on('error',()=>{
+    ElMessage.error('复制失败')
+    clipboard.destroy()
+  })
+}
+/**申请FTP密码 */
+const onQuery =async () => {
+  if(state.filter.remark===''){
+    ElMessage.error('请输入申请备注')
+  }else{
+    const res=await new FuelingFtpAPI().getFtpPwd().catch()
+    state.filter.pwd=res.data
+    state.msgDisplay=true
+    state.pwdDisplay=true
+    state.timeDisplay=true
+    state.btnDisplay=false
+  }
+}
+/**将Filter对象成.的连接方式*/
+const flattenObject = (obj, parentKey = '') => {
+  const result = {};
+  for (const key in obj) {
+    if (obj.hasOwnProperty(key)) {
+      const newKey = parentKey ? `${parentKey}.${key}` : key;
+      if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
+        const flattened = flattenObject(obj[key], newKey);
+        Object.assign(result, flattened);
+      } else {
+        result[newKey] = obj[key];
+      }
+    }
+  }
+
+  return result;
+}
+</script>
+
+<style scoped lang="scss">
+.my-el-link {
+  font-size: 12px;
+}
+.el-form .el-col.mb20 {
+  margin: 0 !important;
+}
+.el-input, .el-select {
+  width: 240px;
+}
+</style>

+ 109 - 0
admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/components/form-audit.vue

@@ -0,0 +1,109 @@
+<template>
+  <div>
+    <el-dialog title="审核" v-model="isShowDialog" draggable width="400px">
+      <el-form ref="formRef" :model="formData.auditData" :rules="rules" >
+        <el-form-item label="失效时间" prop="expiedTime">
+          <el-date-picker
+                    v-model="formData.auditData.expiedTime"
+                    type="datetime"
+                    value-format="YYYY-MM-DD HH:mm:ss"
+                    placeholder="请选择失效时间" >
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" icon="ele-CircleClose" size="default">取 消</el-button>
+          <el-button type="primary" @click="confirmAudit">确定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {reactive, ref, watch} from "vue";
+import {oilSdkTableModel,FueilingSdkAuthInput} from "/src/api/admin/deviceAuthorization/oilSdkAuthorDto";
+import {OilSdkAuthorAPI} from "/src/api/admin/deviceAuthorization/oilSdkAuthor";
+import eventBus from "/src/utils/mitt";
+import {FormRules} from "element-plus";
+
+/**数据对象 */
+const formData = reactive({
+  loading: false,
+  //isShowDialog: false,
+  auditData:[] as FueilingSdkAuthInput
+})
+/**有效时间选择校验*/
+const validateDate = (rule: any, value: any, callback: any) => {
+  if(new Date(value).getTime() > Date.now()){
+    callback()
+  }else{
+    callback(new Error('选择的时间已失效'))
+  }
+}
+
+/**表单校验*/
+const rules = reactive<FormRules>({
+  expiedTime: [
+    { type: 'date', required: true, message: '请选择失效期', trigger: 'blur' },
+    { validator: validateDate, trigger: 'blur' }
+  ],
+})
+const isShowDialog = ref(false);
+const formRef = ref()
+
+const openDialog = (val:any[]) => {
+  //console.log(val)
+  formData.auditData = JSON.parse(JSON.stringify(val))
+  //console.log(formData.auditData)
+  //formData.isShowDialog = true
+  //formData.isShowDialog = true
+  isShowDialog.value = true;
+}
+
+const onCancel = () => {
+  isShowDialog.value=false
+}
+
+const confirmAudit =async () => {
+  formRef.value.validate(async (valid: boolean) =>{
+    if(!valid) return
+    formData.auditData=formData.auditData.map(item=>{
+      item.expiedTime=formData.auditData.expiedTime
+      item.state = '正常' ? 1 : 0 ?? 0
+      return item
+    })
+    formData.loading = true
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
+    let res = {} as any
+    res = await new OilSdkAuthorAPI().updateForms(formData.auditData,{ showSuccessMessage: true }).catch(() => {
+      formData.loading = false
+    })
+
+    if(res?.success){
+      //console.log('2')
+      //console.log(formData.auditData)
+      eventBus.emit('refreshView')
+      isShowDialog.value = false
+      formData.auditData = {} as oilSdkTableModel
+    }
+
+    formData.loading = false
+  })
+}
+
+/***监听弹窗关   闭表单验证*/
+watch(() => isShowDialog.value,(newVal) => {
+  if(newVal) formRef.value?.resetFields()
+})
+
+defineExpose({
+  openDialog,
+})
+
+
+</script>
+<style scoped lang="scss">
+
+</style>

+ 3 - 3
admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/components/form-edit.vue

@@ -29,12 +29,12 @@
             </el-form-item>
           </el-col> -->
           <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-            <el-form-item label="效时间" prop="expiedTime">
+            <el-form-item label="效时间" prop="expiedTime">
               <el-date-picker
                 v-model="formData.editData.expiedTime"
                 type="datetime"
                 value-format="YYYY-MM-DD HH:mm:ss"
-                placeholder="选择效时间"
+                placeholder="选择效时间"
               />
             </el-form-item>
           </el-col>
@@ -128,7 +128,7 @@ const rules = reactive<FormRules>({
     { required: true, message: '请输入设备授权码', trigger: 'blur' },
   ],
   expiedTime: [
-    { type: 'date', required: true, message: '请选择效期', trigger: 'blur' },
+    { type: 'date', required: true, message: '请选择效期', trigger: 'blur' },
     { validator: validateDate, trigger: 'blur' }
   ],
   state: [

+ 39 - 19
admin.ui.plus-master/src/views/admin/authorize/fuelingsdk/index.vue

@@ -27,7 +27,7 @@
                 </el-form-item>
               </el-col>
               <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
-                <el-form-item label="效时间">
+                <el-form-item label="效时间">
                   <el-date-picker
                     v-model="sdkData.time"
                     type="datetimerange"
@@ -50,10 +50,9 @@
               </el-col>
             </el-form-item>
           </el-form>
-          <div class="my-flex my-flex-start" >
-            <el-button  type="primary" icon="ele-CirclePlus" @click="onAdd"> 添加 </el-button>
-          </div>
           <div class="my-flex my-flex-end" >
+            <el-button  type="primary" icon="ele-CirclePlus" @click="onAdd"> 添加 </el-button>
+            <el-button type="primary" icon="ele-Tickets" @click="onAuditRecord()"> 审核 </el-button>
             <el-button type="primary" icon="ele-UploadFilled" @click="uploadFiles"> 批量导入 </el-button>
             <el-button type="primary" icon="ele-Document" @click="exportTable(sdkData.tableModel,sdkData.dynamicColumns)"> 导出表格 </el-button>
           </div>
@@ -62,8 +61,14 @@
       <!--表格-->
       <el-col  :xs="24" >
         <el-card style="height: 70vh" class="my-fill mt8" shadow="hover">
-          <el-table v-loading="sdkData.loading" stripe :data="sdkData.tableModel" row-key="id" style="width: 100%">
-            <el-table-column v-for="column in sdkData.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label"  />
+          <el-table ref="multipleTableRef"
+            v-loading="sdkData.loading"
+            stripe :data="sdkData.tableModel"
+            row-key="id"
+            style="width: 100%"
+            @row-click="onOilSdkRowClick" >
+            <el-table-column type="selection" width="50"></el-table-column>
+            <el-table-column v-for="column in sdkData.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label" />
             <el-table-column label="操作"  fixed="right" header-align="center" align="center" class="right-operation" width="100">
               <template #default="{ row }">
                 <el-link
@@ -75,7 +80,7 @@
                   :underline="false"
                   target="_blank"
                 >编辑</el-link>
-                <el-link
+                <!-- <el-link
                   class="my-el-link mr12 ml12"
                   v-if="showAudit(row)"
                   type="primary"
@@ -84,7 +89,7 @@
                   @click="onAuditRecord(row)"
                   :underline="false"
                   target="_blank"
-                >审核</el-link>
+                >审核</el-link> -->
               </template>
             </el-table-column>
           </el-table>
@@ -105,22 +110,29 @@
       </el-col>
     </el-row>
     <EditDialog ref="editDialogRef" />
+    <AuditDialog ref="auditDialogRef" />
   </div>
 
 </template>
 
 <script setup lang="ts" name="authorize/fuelingsdk">
-import {defineAsyncComponent, onMounted, reactive, ref, watch, onBeforeMount} from "vue";
-import {OilSdkAuthorDto, oilSdkFilterModel, oilSdkTableModel} from "/@/api/admin/deviceAuthorization/oilSdkAuthorDto";
+import {defineAsyncComponent, onMounted, reactive, ref, watch, onBeforeMount,getCurrentInstance} from "vue";
+import {OilSdkAuthorDto, oilSdkFilterModel, oilSdkTableModel,oilSdkAuthorPageOutput,FueilingSdkAuthInput} from "/@/api/admin/deviceAuthorization/oilSdkAuthorDto";
 import {OilSdkAuthorAPI} from "/@/api/admin/deviceAuthorization/oilSdkAuthor";
 import type {pageInput} from "/@/api/admin/shareDto/shareDto";
 import eventBus from "/@/utils/mitt";
 import * as ExcelJS from 'exceljs';
 import * as FileSaver from 'file-saver';
+import { ElTable } from 'element-plus'
 /**引入组件*/
 const EditDialog = defineAsyncComponent(() => import('/src/views/admin/authorize/fuelingsdk/components/form-edit.vue'))
+const AuditDialog = defineAsyncComponent(() => import('/src/views/admin/authorize/fuelingsdk/components/form-audit.vue'))
 
 const editDialogRef = ref()
+const auditDialogRef = ref()
+
+const multipleTableRef=ref<InstanceType<typeof ElTable>>()
+const { proxy } = getCurrentInstance() as any
 
 /**sdk授权页面对象 */
 const sdkData = reactive({
@@ -151,7 +163,7 @@ const sdkData = reactive({
     { prop: 'projectName', label: '项目名称' },
     { prop: 'sn', label: '设备SN号' },
     { prop: 'key', label: '授权码' },
-    { prop: 'expiedTime', label: '效时间' },
+    { prop: 'expiedTime', label: '效时间' },
     { prop: 'state', label: '状态' },
     { prop: 'remark', label: '备注' },
   ],
@@ -329,15 +341,23 @@ const editTableData = (row) => {
   editDialogRef.value.openDialog(row)
 }
 /**审核弹窗 */
-const onAuditRecord=(row)=>{
-  console.log(row.key)
-}
-/**授权码为空时显示审核按钮 */
-const showAudit=(row):boolean=>{
-  if(row.key){
-    return false
+const onAuditRecord=()=>{
+  const selectionRows = multipleTableRef.value!.getSelectionRows() as FueilingSdkAuthInput
+  //console.log(selectionRows)
+
+  if (!((selectionRows.length as number) > 0)) {
+    proxy.$modal.msgWarning('请选择要审核的数据')
+    return
+  }else{
+    auditDialogRef.value.openDialog(selectionRows)
   }
-  return true
+
+}
+const onOilSdkRowClick=(row: FueilingSdkAuthInput)=> {
+  // TODO: improvement typing when refactor table
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-expect-error
+  multipleTableRef.value!.toggleRowSelection(row, undefined)
 }
 </script>
 

+ 11 - 1
admin.ui.plus-master/src/views/admin/authorize/softwarePackageManagement/components/form-edit.vue

@@ -90,6 +90,15 @@ const formData = reactive({
   editData:{} as softwarePackageManagement_TableData,
   fileValue: null,
 })
+/**有效版本号选择校验*/
+const validateVersion = (rule: any, value: any, callback: any) => {
+  const versionPattern: RegExp = /^\d+\.\d+\.\d+$/; // 正则表达式,以数字开头和结尾,并且包含数字和点号(.)
+  if (!versionPattern.test(value)) {
+    callback(new Error('输入的版本号格式错误'))
+  } else {
+    callback()
+  }
+}
 
 
 /**表单校验*/
@@ -105,6 +114,7 @@ const rules = reactive<FormRules>({
   ],
   version: [
     { required: true, message: '请输入版本号', trigger: 'blur' },
+    { validator: validateVersion, trigger: 'blur' }
   ],
 })
 
@@ -154,7 +164,7 @@ const uploadFileRef = ref(null);
 const onSubmit =  () => {
 debugger
   formRef.value.validate(async (valid: boolean) =>{
-    //if(!valid) return
+    if(!valid) return
 
     formData.loading = true
     let res = {} as any

+ 8 - 4
admin.ui.plus-master/src/views/admin/authorize/softwarePackageManagement/index.vue

@@ -8,7 +8,7 @@
             <el-form-item prop="name" style="width: 100%">
               <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
                 <el-form-item label="软件类型">
-                  <el-select  v-model="softwareData.Filter.softwareType" placeholder="请选择软件类型" >
+                  <el-select  v-model="softwareData.Filter.softwareType" placeholder="请选择软件类型" style="width: 200px;" >
                     <el-option v-for="(value, key) in softwareType" :key="key" :label="value[1].name"  :value="Number(value[1].value)" />
                   </el-select>
                 </el-form-item>
@@ -25,7 +25,7 @@
               </el-col>
               <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
                 <el-form-item label="设备类型">
-                  <el-select  v-model="softwareData.Filter.equipmentType" placeholder="请选择设备类型" >
+                  <el-select  v-model="softwareData.Filter.equipmentType" placeholder="请选择设备类型" style="width: 200px;">
                     <el-option v-for="(value, key) in equipmentType" :key="key" :label="value[1].name"  :value="Number(value[1].value)" />
                   </el-select>
                 </el-form-item>
@@ -328,13 +328,13 @@ const onRelease = (row) => {
 /**下载*/
 const onDownload = (row) => {
   softwareData.loading = true;
-  var RowData =  JSON.parse(JSON.stringify(row))
+  var RowData = JSON.parse(JSON.stringify(row))
   const params = RowData as softwarePackageManagement_TableData
   //const link = downloadLink.value;
   //const url = `http://localhost:8000/api/app/software/download-file`;
   //link.href = url;
   //link.click();
-  const filename =  params.fileName?.toString();
+  const filename = params.fileName?.toString();
   const { userInfos } = storeToRefs(useUserInfo());
   const accessToken = userInfos.value.token
   const token = `Bearer ${accessToken}`
@@ -393,6 +393,10 @@ const onCurrentChange = () =>{
 
 /**过滤数字的属性*/
 const getProp = (val,row) => {
+ //debugger
+  // var sss = row[val];
+  // var fdsdfsd = String(row[val]);
+  //if(!row[val]) return null
   if(val === 'softwareType') return softwareType.value.get(String(row[val])).name
   if(val === 'equipmentType') return equipmentType.value.get(String(row[val])).name
   if(val === 'state') return softwarePackageStatus.value.get(String(row[val])).name

+ 4 - 4
admin.ui.plus-master/src/views/admin/login/component/account.vue

@@ -4,7 +4,7 @@
       <el-form-item class="login-animation1" prop="userName" :rules="[{ required: true, message: '请输入用户名', trigger: ['blur', 'change'] }]">
         <el-input
           text
-          :placeholder="$t('message.account.accountPlaceholder1')"
+          placeholder="请输入用户名"
           v-model="state.ruleForm.userName"
           clearable
           autocomplete="off"
@@ -18,7 +18,7 @@
       <el-form-item class="login-animation2" prop="password" :rules="[{ required: true, message: '请输入密码', trigger: ['blur', 'change'] }]">
         <el-input
           :type="state.isShowPassword ? 'text' : 'password'"
-          :placeholder="$t('message.account.accountPlaceholder2')"
+          placeholder="请输入密码"
           v-model="state.ruleForm.password"
           autocomplete="off"
           @keyup.enter="onSignIn"
@@ -106,8 +106,8 @@ const state = reactive({
   showDialog: false,
   isShowPassword: false,
   ruleForm: {
-    userName: 'admin',
-    password: '111111',
+    userName: '',
+    password: '',
     captchaId: '',
     captchaData: '',
   } as AuthLoginInput,

+ 1 - 1
admin.ui.plus-master/src/views/admin/login/component/mobile.vue

@@ -62,7 +62,7 @@ const phoneRef = ref()
 // 定义变量内容
 const state = reactive({
   ruleForm: {
-    mobile: '13122223333',
+    mobile: '',
     code: '',
     codeId: '',
   } as AuthMobileLoginInput,

+ 6 - 0
admin.ui.plus-master/src/views/admin/login/index.vue

@@ -13,6 +13,7 @@
           <img :src="loginMain" />
         </div>
         <img :src="loginBg" class="login-left-waves" />
+        <div class="floor">托肯恒山科技(广州)有限公司&nbsp;&nbsp;版本号:v2.00.1</div>
       </div>
       <div class="login-right flex">
         <div class="login-right-warp flex-margin">
@@ -136,6 +137,11 @@ onMounted(() => {
       left: 100%;
       height: 100%;
     }
+    .floor{
+      position: absolute;
+      bottom: 0;
+      right: 0;
+    }
   }
   .login-right {
     width: 700px;

+ 1 - 1
admin.ui.plus-master/src/views/admin/product/record/index.vue

@@ -225,7 +225,7 @@ const getComponentStatus = (val) => {
 
 //设置不同团标状态、油气回收字体颜色
 const getColor = (value: string): string => {
-  if (value === '备案') {
+  if (value === '备案') {
     return '#41b584';
   } else if (value === '灌注') {
       return '#409eff';

+ 1 - 3
admin.ui.plus-master/src/views/admin/product/type/index.vue

@@ -32,10 +32,8 @@
               </el-col>
             </el-form-item>
           </el-form>
-            <div class="my-flex my-flex-start">
-              <el-button  type="primary" icon="ele-CirclePlus" @click="onAdd"> 添加 </el-button>
-            </div>
             <div class="my-flex my-flex-end">
+              <el-button  type="primary" icon="ele-CirclePlus" @click="onAdd"> 添加 </el-button>
               <el-button type="primary" icon="ele-UploadFilled" @click="uploadFiles"> 批量导入 </el-button>
               <el-button type="primary" icon="ele-Document" @click="exportTable"> 导出表格 </el-button>
             </div>

+ 174 - 69
admin.ui.plus-master/src/views/admin/statement/listOfOilEngines/index.vue

@@ -4,11 +4,37 @@
       <!--操作-->
       <el-col :xs="24">
         <el-card class="mt8" shadow="hover">
-          <el-form :model="oilEngineOnQuery.filter" :inline="true" @submit.stop.prevent>
+          <el-form :model="oilEngineData.filterModel" :inline="true" @submit.stop.prevent>
             <el-form-item prop="name" style="width:100%">
               <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
-                <el-form-item label="GUID">
-                  <el-input v-model="oilEngineOnQuery.filter.guid" placeholder="请输入GUID" clearable></el-input>
+                <el-form-item label="油机号">
+                  <el-input v-model="oilEngineData.filterModel.name" placeholder="请输入油机号" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="加油站">
+                  <el-input v-model="oilEngineData.filterModel.gasStation" placeholder="请输入加油站" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="加油机机型">
+                  <el-input v-model="oilEngineData.filterModel.model" placeholder="请输入加油机机型" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="设备状态">
+                  <el-select  v-model="oilEngineData.filterModel.deviceStatus" placeholder="请输入设备状态" >
+                    <el-option v-for="(value, key) in FuelDispenserEnum" :key="key" :label="value"  :value="key" />
+                  </el-select>
+                  <!-- <el-input v-model="oilEngineData.filterModel.deviceStatus" placeholder="请输入设备状态" clearable></el-input> -->
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="在线状态">
+                  <el-select  v-model="oilEngineData.filterModel.onlineStatus" placeholder="请输入在线状态" >
+                    <el-option v-for="(value, key) in OnlineStatus" :key="key" :label="value"  :value="key" />
+                  </el-select>
+                  <!-- <el-input v-model="oilEngineData.filterModel.onlineStatus" placeholder="请输入在线状态" clearable></el-input> -->
                 </el-form-item>
               </el-col>
               <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
@@ -24,28 +50,31 @@
       <!--列表-->
       <el-col :xs="24">
         <el-card style="height: 70vh"  class="my-fill mt8" shadow="hover">
-          <el-table  v-loading="state.loading" stripe :data="state.list" row-key="id" style="width: 100%">
-            <el-table-column type="index" label="序号" width="60"/>
-            <el-table-column prop="id" label="GUID"  />
-            <el-table-column prop="name" label="名称"  >
+          <el-table v-loading="oilEngineData.loading" stripe :data="oilEngineData.tableModel" row-key="id" style="width: 100%">
+            <el-table-column prop="name" label="油机号"  />
+            <el-table-column prop="oilCompany" label="石油公司"  />
+            <el-table-column prop="gasStation" label="加油站"  />
+            <el-table-column prop="serialNumber" label="序列号"  />
+            <el-table-column prop="model" label="加油机机型"  />
+            <el-table-column prop="gunCount" label="加油机枪数量"  />
+            <!-- <el-table-column prop="manufacturer"  label="加油机厂商" /> -->
+            <el-table-column prop="manufactureDate"  label="出场时间" />
+            <el-table-column prop="startupDate"  label="启动时间" />
+            <el-table-column prop="installationDate"  label="安装时间" />
+            <el-table-column prop="deviceStatus" label="设备状态" >
               <template #default="{ row }">
-                {{ row.name}}
+                <div :style="{color:getColor(getOilEngineStatus(row.deviceStatus))}" class="bold-font">
+                  {{getOilEngineStatus(row.deviceStatus)}}
+                </div>
               </template>
             </el-table-column>
-            <el-table-column prop="oilCompanies" label="石油公司"  >
+            <el-table-column prop="onlineStatus" label="在线状态" >
               <template #default="{ row }">
-                {{ row.oilCompanies}}
+                <div :style="{color:getColor(getOilEngineStatus(row.onlineStatus))}" class="bold-font">
+                  {{getOilEngineStatus(row.onlineStatus)}}
+                </div>
               </template>
             </el-table-column>
-            <el-table-column prop="gasStation" label="加油站"  />
-            <el-table-column prop="serialNumber" label="序列号" />
-            <el-table-column prop="model" label="加油机机型" />
-            <el-table-column prop="quantity" label="加油机枪数量" />
-            <el-table-column prop="manufacturer" label="加油机厂商" />
-            <el-table-column prop="factoryTime" label="出厂时间" />
-            <el-table-column prop="startTime" label="启动时间" />
-            <el-table-column prop="equipmentStatus" label="设备状态" />
-            <el-table-column prop="onlineStatus" label="在线状态" />
             <el-table-column label="操作"  fixed="right" header-align="center" align="center" class="right-operation" width="100">
               <template #default="{ row }">
                 <el-link
@@ -62,9 +91,9 @@
           </el-table>
           <div class="my-flex my-flex-end" style="margin-top: 20px">
             <el-pagination
-              v-model:currentPage="state.pageInput.currentPage"
-              v-model:page-size="state.pageInput.pageSize"
-              :total="state.total"
+              v-model:currentPage="oilEngineData.pageInput.currentPage"
+              v-model:page-size="oilEngineData.pageInput.pageSize"
+              :total="oilEngineData.total"
               :default-page-size="5"
               :page-sizes="[5, 10, 20, 50, 100]"
               small
@@ -82,76 +111,152 @@
 
 <script setup lang="ts">
 
-import {onMounted, reactive} from "vue";
+import { onBeforeMount, onMounted, reactive,ref } from "vue";
 import {ListOfOilEnginesApi} from "/@/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesApi";
+import {FuelDispenserDto_SearchFilter,PageInputFuelDispenserDto,FuelDispenserDto} from "/@/api/admin/reportManagement/listOfOilEngines/listOfOilEnginesDto";
+import eventBus from "/@/utils/mitt";
+import {useGlobalCacheStore} from "/@/stores/globalCacheStore";
 import router from "/@/router";
 
-/**
- * 油机列表查询时的参数
- */
-const oilEngineOnQuery = reactive({
-  filter: {
-    guid:''
-  }
-})
-
+/**获取全局缓存*/
+const globalCacheStore = useGlobalCacheStore()
+// /**油机列表 - 列表状态 */
+// const oilEngineStatusType = ref(globalCacheStore.getGlobalStore().get('oilEngineStatusType'))
+/**油机列表 - 列表设备状态、在线状态 */
+const oilEngineStatus = ref(globalCacheStore.getGlobalStore().get('oilEngineStatus'))
 /**
  * 油机列表数据对象
  */
-const state = reactive({
+  const oilEngineData = reactive({
   loading: false,
-  list:  [] ,
-  pageInput:{
+  filterModel: {
+    /**油机号*/
+    name: "",
+     /**加油站*/
+    gasStation:"",
+    /**加油机机型*/
+    model: "",
+    /**设备状态*/
+    deviceStatus: "",
+    /**在线状态*/
+    onlineStatus: "",
+  }as FuelDispenserDto_SearchFilter,
+  total: 0,
+  pageInput: {
     currentPage: 1,
     pageSize: 10,
-  },
-  total: 0
+  } as PageInputFuelDispenserDto,
+  tableModel: [] as Array<FuelDispenserDto>
 })
-
-const resetForm = () => {
-  oilEngineOnQuery.filter = {
-    guid:''
+ /**设备状态*/
+enum FuelDispenserEnum {
+  enable = '启用',
+  register = '备案',
+  disable='维修',
+  factory='出产注册'
+}
+/**在线状态*/
+enum OnlineStatus {
+  online = '在线',
+  offline = '离线'
+}
+/**将filterModel对象成.的连接方式*/
+const flattenObject = (obj, parentKey = '') => {
+  const result = {};
+  for (const key in obj) {
+    if (obj.hasOwnProperty(key)) {
+      const newKey = parentKey ? `${parentKey}.${key}` : key;
+      if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
+        const flattened = flattenObject(obj[key], newKey);
+        Object.assign(result, flattened);
+      } else {
+        result[newKey] = obj[key];
+      }
+    }
   }
+
+  return result;
+}
+/**初始化 */
+const init = async () => {
+  oilEngineData.loading = true
+  const query = flattenObject({ filterModel: oilEngineData.filterModel})
+  const res:any = await new ListOfOilEnginesApi().getPage({...oilEngineData.pageInput, filter:oilEngineData.filterModel})
+  oilEngineData.tableModel = res?.data?.list ?? []
+  oilEngineData.total = res?.data?.total ?? 0
+  oilEngineData.loading = false
+}
+/**重置查询条件 */
+const resetQuery = () => {
+  oilEngineData.filterModel.name = ''
+  oilEngineData.filterModel.gasStation = ''
+  oilEngineData.filterModel.model = ''
+  oilEngineData.filterModel.deviceStatus = ''
+  oilEngineData.filterModel.onlineStatus = ''
 }
 
+/**重置 */
 const onReset = () => {
-  resetForm()
-  state.pageInput.currentPage = 1
-  onQuery()
+  resetQuery()
+  init()
 }
-
-/**
- * 页条变化
- * @param val
- */
-const onSizeChange = (val: number) => {
-  state.pageInput.pageSize = val
-  onQuery()
+/**条件查询 */
+const onQuery = () => {
+  init()
 }
-
-/**
- * 页数 变化
- * @param val
- */
-const onCurrentChange = (val: number) => {
-  state.pageInput.currentPage = val
-  onQuery()
+/**页条数变化*/
+const onSizeChange = () => {
+  init()
 }
 
-const onQuery =  async () => {
-  state.loading = true
-  const { total, list } = await new ListOfOilEnginesApi().getPage()
-  state.list = list
-  state.total = total
-  state.loading = false
+/**页数变化*/
+const onCurrentChange = () =>{
+  init()
 }
-
 const toPage = (row) => {
-  router.push({path:`/statement/${row.id}`})
+  router.push({path:`/statement/${row.fuelId}`})
+}
+// /**油机列表 - 列表状态 */
+// const getOilEngineStatusType = (val) => {
+//   val = String(val)
+//   if(oilEngineStatusType.value?.has(val)){
+//     return oilEngineStatusType.value.get(val)
+//   }else {
+//     return val
+//   }
+// }
+/**油机列表 - 列表设备状态、在线状态 */
+const getOilEngineStatus = (val) => {
+  val = String(val)
+  if(oilEngineStatus.value.has(val)){
+    return oilEngineStatus.value.get(val)
+  }else {
+    return val
+  }
+}
+
+//设置不同设备状态、在线状态字体颜色
+const getColor = (value: string): string => {
+  if (value === '在线'||value === '启用') {
+    return '#41b584';
+  } else if (value === '出厂注册') {
+      return '#409eff';
+  } else if(value === '备案') {
+    return '#E6A23C';
+  }else{
+    return '#F34D37'
+  }
 }
 
 onMounted(() => {
-  onQuery()
+  init()
+  eventBus.off('refreshView')
+  eventBus.on('refreshView', async () => {
+    await init()
+  })
+})
+onBeforeMount(() => {
+  eventBus.off('refreshView')
 })
 
 </script>

+ 317 - 0
admin.ui.plus-master/src/views/admin/statement/moreAlert/index.vue

@@ -0,0 +1,317 @@
+<template>
+  <div class="layout-pd" >
+    <el-row>
+      <!--操作-->
+      <el-col :xs="24" >
+        <el-card class="mt8"  shadow="hover" >
+          <el-form :model="sdkData.Filter" :inline="true" @submit.stop.prevent>
+            <el-form-item prop="name" style="width: 100%">
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="石油公司">
+                  <el-input v-model="sdkData.Filter.OilStation"  placeholder="请输入石油公司" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="加油站">
+                  <el-input v-model="sdkData.Filter.Project" placeholder="请输入加油站" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="报警类型">
+                  <el-input v-model="sdkData.Filter.SN" placeholder="请选择报警类型" clearable></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :xs="24" :sm="12" :md="8" :lg="9" :xl="4" class="mb20">
+                <el-form-item>
+                  <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+                  <el-button type="primary" icon="ele-Document" @click="onReset"> 导出 </el-button>
+                  <el-button type="primary" @click="onReset"> 展开搜索 </el-button>
+                </el-form-item>
+              </el-col>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </el-col>
+      <!--表格-->
+      <el-col  :xs="24" >
+        <el-card style="height: 70vh" class="my-fill mt8" shadow="hover">
+          <el-table ref="multipleTableRef"
+            v-loading="sdkData.loading"
+            stripe :data="sdkData.tableModel"
+            row-key="id"
+            style="width: 100%"
+            @row-click="onOilSdkRowClick" >
+            <el-table-column type="index" label="序号" width="60"></el-table-column>
+            <el-table-column type="selection" width="50"></el-table-column>
+            <el-table-column v-for="column in sdkData.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label" />
+          </el-table>
+        </el-card>
+      </el-col>
+    </el-row>
+    <EditDialog ref="editDialogRef" />
+    <AuditDialog ref="auditDialogRef" />
+  </div>
+
+</template>
+
+<script setup lang="ts" name="authorize/fuelingsdk">
+import {defineAsyncComponent, onMounted, reactive, ref, watch, onBeforeMount,getCurrentInstance} from "vue";
+import {OilSdkAuthorDto, oilSdkFilterModel, oilSdkTableModel,oilSdkAuthorPageOutput,FueilingSdkAuthInput} from "/@/api/admin/deviceAuthorization/oilSdkAuthorDto";
+import {OilSdkAuthorAPI} from "/@/api/admin/deviceAuthorization/oilSdkAuthor";
+import type {pageInput} from "/@/api/admin/shareDto/shareDto";
+import eventBus from "/@/utils/mitt";
+import * as ExcelJS from 'exceljs';
+import * as FileSaver from 'file-saver';
+import { ElTable } from 'element-plus'
+/**引入组件*/
+const EditDialog = defineAsyncComponent(() => import('/src/views/admin/authorize/fuelingsdk/components/form-edit.vue'))
+const AuditDialog = defineAsyncComponent(() => import('/src/views/admin/authorize/fuelingsdk/components/form-audit.vue'))
+
+const editDialogRef = ref()
+const auditDialogRef = ref()
+
+const multipleTableRef=ref<InstanceType<typeof ElTable>>()
+const { proxy } = getCurrentInstance() as any
+
+/**更多报警页面对象 */
+const sdkData = reactive({
+  time:'',
+  /**加载显示 */
+  loading: false,
+  /**条件查询模块 */
+  Filter: {
+    /**油站名称 */
+    OilStation: "",
+    /**项目名称 */
+    Project: "",
+    /**设备SN */
+    SN: "",
+    /**授权码*/
+    Key: "",
+    /**开始的时间 */
+    BeginTime: null,
+    /**开始的时间 */
+    EndTime: null,
+  },
+  /**表格信息 */
+  tableModel: [],
+  /**动态表头 */
+  dynamicColumns: [
+    { prop: '1', label: '石油公司' },
+    { prop: '2', label: '加油站名称' },
+    { prop: '3', label: '加油机厂商' },
+    { prop: '4', label: '加油机' },
+    { prop: '5', label: '加油机型号' },
+    { prop: '6', label: '加油机序列号' },
+    { prop: '7', label: '油枪' },
+    { prop: '8', label: '报警设备' },
+    { prop: '9', label: '报警类型' },
+    { prop: '10', label: '报警描述' },
+    { prop: '11', label: '报警来源' },
+    { prop: '12', label: '报警时间' }
+  ],
+  /**分页标识 */
+  pageInput:{
+    CurrentPage: 1,
+    PageSize: 10000,
+  },
+  /**分页总数 */
+  total: 0,
+})
+
+/**初始化 */
+const init = async () => {
+  sdkData.loading = true
+  const query = flattenObject({ Filter: sdkData.Filter})
+  const res:any = await new OilSdkAuthorAPI().getPageData({...sdkData.pageInput, ...query}).catch(() => {
+    sdkData.loading = false
+  })
+  sdkData.tableModel = res?.data?.list ?? []
+  sdkData.total = res?.data?.total ?? 0
+  sdkData.loading = false
+}
+
+onMounted(() => {
+  init()
+  eventBus.off('refreshView')
+  eventBus.on('refreshView', async () => {
+    init()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshView')
+})
+
+/**
+ * 监听时间变换
+ */
+watch(() => sdkData.time, (newVal ) => {
+  if(newVal.length === 0){
+    return
+  }
+  sdkData.Filter.BeginTime = newVal?.[0].toString()
+  sdkData.Filter.EndTime = newVal?.[1].toString()
+})
+
+/**条件查询 */
+const onQuery = () => {
+  init()
+}
+
+/**重置查询条件 */
+const resetQuery = () => {
+  sdkData.Filter.OilStation = ''
+  sdkData.Filter.Project = ''
+  sdkData.Filter.SN = ''
+  sdkData.Filter.Key = ''
+  sdkData.Filter.BeginTime =  ''
+  sdkData.Filter.EndTime = ''
+  sdkData.time = ''
+  sdkData.pageInput.CurrentPage = 1
+}
+
+/**重置 */
+const onReset = () => {
+  resetQuery()
+  init()
+}
+
+/**添加*/
+const onAdd = () => {
+  editDialogRef.value.openDialog()
+}
+
+/**页条数变化*/
+const onSizeChange = () => {
+  init()
+}
+
+/**页数变化*/
+const onCurrentChange = () =>{
+  init()
+}
+
+/**批量导入*/
+const uploadFiles = () =>{
+
+}
+
+/**导出表格*/
+const exportTable = async(data:any[],columns:{ prop: string, label: string }[]) =>{
+  // 创建一个新的工作簿
+  const workbook = new ExcelJS.Workbook();
+  const worksheet = workbook.addWorksheet('Sheet1');
+
+// 添加表头(不包括名为 "guid" 的表头列)
+  const headers = columns
+    .filter(column => column.prop !== 'guid')  // 过滤掉名为 "guid" 的表头列
+    .map(column => column.label);
+  const headerRow = worksheet.addRow(headers);
+
+  // 添加数据行(不包括 "guid" 的数据列)
+  data.forEach((item) => {
+    const row = columns
+      .filter(column => column.prop !== 'guid')  // 过滤掉名为 "guid" 的数据列
+      .map(column => item[column.prop]);
+    worksheet.addRow(row);
+  });
+
+// 设置数据行样式
+  worksheet.eachRow({ includeEmpty: true }, row => {
+    row.eachCell(cell => {
+      // 设置单元格样式
+      cell.font = { bold: false }; // 设置字体为普通样式
+      cell.border = { top: { style: 'thin' }, bottom: { style: 'thin' } }; // 设置上下边框为细线
+      cell.alignment = { vertical: 'middle', horizontal: 'center' }; // 将内容垂直居中、水平居中
+      // 设置单元格高度
+      row.height = 25; // 设置每一行的高度为 25
+    });
+  });
+
+  // 设置表头样式
+  headerRow.font = { bold: true }; // 设置字体为粗体
+
+  // 设置整个表格的边框样式
+  worksheet.eachRow({ includeEmpty: true }, row => {
+    row.eachCell(cell => {
+      if (cell.row === 1) {
+        // 设置表头单元格的边框为细线
+        cell.border = { left: { style: 'thin' }, right: { style: 'thin' }, top: { style: 'thin' }, bottom: { style: 'thin' } };
+        // 设置表头单元格背景颜色
+        cell.fill={type: 'pattern',pattern: 'solid',fgColor: { argb: '409eff' }}
+      } else {
+        // 设置数据行单元格的边框为细线
+        cell.border = { left: { style: 'thin' }, right: { style: 'thin' }, bottom: { style: 'thin' } };
+      }
+    });
+  });
+
+  // 调整单元格大小
+  worksheet.columns.forEach(column => {
+    column.width = 25; // 设置每列的宽度为 25
+  });
+
+
+  // 生成 Excel 文件
+  const buffer = await workbook.xlsx.writeBuffer();
+
+  // 将文件保存到本地
+  const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+  FileSaver.saveAs(blob, '油气SDK授权数据.xlsx');
+}
+
+/**将Filter对象成.的连接方式*/
+const flattenObject = (obj, parentKey = '') => {
+  const result = {};
+  for (const key in obj) {
+    if (obj.hasOwnProperty(key)) {
+      const newKey = parentKey ? `${parentKey}.${key}` : key;
+      if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
+        const flattened = flattenObject(obj[key], newKey);
+        Object.assign(result, flattened);
+      } else {
+        result[newKey] = obj[key];
+      }
+    }
+  }
+
+  return result;
+}
+
+/**编辑弹窗 */
+const editTableData = (row) => {
+  editDialogRef.value.openDialog(row)
+}
+/**审核弹窗 */
+const onAuditRecord=()=>{
+  const selectionRows = multipleTableRef.value!.getSelectionRows() as FueilingSdkAuthInput
+  //console.log(selectionRows)
+
+  if (!((selectionRows.length as number) > 0)) {
+    proxy.$modal.msgWarning('请选择要审核的数据')
+    return
+  }else{
+    auditDialogRef.value.openDialog(selectionRows)
+  }
+
+}
+const onOilSdkRowClick=(row: FueilingSdkAuthInput)=> {
+  // TODO: improvement typing when refactor table
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-expect-error
+  multipleTableRef.value!.toggleRowSelection(row, undefined)
+}
+</script>
+
+<style scoped lang="scss">
+.my-el-link {
+  font-size: 12px;
+}
+.el-form .el-col.mb20 {
+  margin: 0 !important;
+}
+.el-input, .el-select {
+  width: 240px;
+}
+</style>

+ 124 - 36
admin.ui.plus-master/src/views/admin/statement/moreOilEngineDetails/index.vue

@@ -5,13 +5,20 @@
         <el-card style="height: 86vh"   class="mt8 my-fill all-con" shadow="hover">
           <div class="tip-con">
             <el-alert
+              v-if="detailsData.list.onlineStatus==='离线'"
               title="加油机长时间离线"
               type="error"
               class="mb15"
             ></el-alert>
+            <el-alert
+              v-if="detailsData.list.onlineStatus==='在线'"
+              title="加油机长时间在线"
+              type="success"
+              class="mb15"
+            ></el-alert>
           </div>
           <div class="ma-con">
-            <div class="top-con" id="top-conId" v-loading="oilListData.loading">
+            <!-- <div class="top-con" id="top-conId" v-loading="oilListData.loading">
               <el-scrollbar>
                 <div class="scrollbar-flex-content" >
                   <div class="card"  :style="{backgroundColor: item.oilEngineStatus === '在线' ? '#67C23A': '#F56C6C'}" name="card"   v-for="(item,index) in oilListData.list" v-bind:key="index"  >
@@ -35,53 +42,83 @@
                   </div>
                 </div>
               </el-scrollbar>
-            </div>
+            </div> -->
             <div class="bom-con">
-              <div class="bomCon-lef">3D</div>
+              <div class="bomCon-lef">
+                <el-image style="top: 50%;translate: (-50%,-50%);" src="https://cma-fds.org.cn/static/img/dispenser.6960513.png"></el-image>
+              </div>
               <div class="bomCon-rig">
                 <div class="bomConR-lef">
-                  <el-card v-loading="detailsData.loading"  style="height:100%;" :header="detailsData.list.oilEngineName+'号机油机'">
+                  <el-card v-loading="detailsData.loading"  style="height:95%;margin-bottom: 10px;" :header="detailsData.list.name+'号机油机'">
                       <div class="oilInfo-con" >
-                        <div class="oilInfo-item">出厂编号:&nbsp;{{detailsData.list.factoryNumber}}</div>
+                        <div class="oilInfo-item">出厂编号:&nbsp;{{detailsData.list.serialNumber}}</div>
                         <div class="oilInfo-item">机型:&nbsp;{{detailsData.list.model}}</div>
-                        <div class="oilInfo-item">制造商:&nbsp;{{detailsData.list.manufacture}}</div>
+                        <div class="oilInfo-item">制造商:&nbsp;{{detailsData.list.manufacturer}}</div>
                         <div class="oilInfo-item oilInfo-item-two">
-                          <span>规格参数:&nbsp;{{detailsData.list.specifications}}</span>
-                          <span>生产日期:&nbsp;{{detailsData.list.dateOfManufacture}}</span>
+                          <span>规格参数:&nbsp;{{detailsData.list.modelSpec}}</span>
+                          <span>生产日期:&nbsp;{{detailsData.list.createdTime}}</span>
                         </div>
                         <div class="oilInfo-item oilInfo-item-two">
-                          <span>测量范围:&nbsp;{{detailsData.list.measuringRange}}</span>
-                          <span>安装日期:&nbsp;{{detailsData.list.installDate}}</span>
+                          <span>测量范围:&nbsp;{{detailsData.list.measureRang}}</span>
+                          <span>安装日期:&nbsp;{{detailsData.list.installationDate}}</span>
                         </div>
                         <div class="oilInfo-item oilInfo-item-two">
                           <span>准确度等级:&nbsp;{{detailsData.list.accuracyLevel}}</span>
-                          <span>启用日期:&nbsp;{{detailsData.list.dateOfActivation}}</span>
+                          <span>启用日期:&nbsp;{{detailsData.list.startupDate}}</span>
                         </div>
                         <div class="oilInfo-item oilInfo-item-two">
-                          <span>设备状态:&nbsp;{{detailsData.list.equipmentStatus}}</span>
+                          <span>设备状态:&nbsp;{{detailsData.list.deviceStatus}}</span>
                           <span>在线状态:&nbsp;{{detailsData.list.onlineStatus}}</span>
                         </div>
                         <div class="oilInfo-item oilInfo-item-two">
-                          <span>报警状态:&nbsp;{{detailsData.list.alarmStatus}}</span>
-                          <span>报警次数:&nbsp;{{detailsData.list.numberOfAlarms}}</span>
-                        </div>
-                        <div class="oilInfo-item oilInfo-item-two">
-                          <span>累计在线时间:&nbsp;{{detailsData.list.accumulatedOnline}}</span>
+                          <span>报警状态:&nbsp;{{detailsData.list.alarmLevel}}</span>
+                          <span>累计在线时间:&nbsp;{{detailsData.list.onlineDesc}}</span>
                         </div>
                       </div>
                   </el-card>
-                </div>
-                <div class="bomConR-rig">
-                  <el-card v-loading="tableData.loading"  style="height:100%" >
+                  <el-card v-loading="tableData.loading"  style="height:70%" >
+                    <div style="margin-bottom: 10px;color: #505050;">
+                      <span>最新5条报警</span>
+                      <span style="float: right;"><el-link type="primary" @click="toPage()">更多报警>></el-link></span>
+                    </div>
                     <el-table  :data="tableData.list" stripe  row-key="id" style="width: 100%">
-                      <el-table-column prop="time" label="时间"  />
-                      <el-table-column prop="refuelingGun" label="加油枪" />
+                      <el-table-column prop="createdDate" label="时间"  />
+                      <el-table-column prop="name" label="加油枪" />
                       <el-table-column prop="alarmSource" label="报警来源" />
                       <el-table-column prop="alarmDescription" label="报警描述" />
                       <el-table-column prop="alarmType" label="报警类型" />
                     </el-table>
                   </el-card>
                 </div>
+                <div class="bomConR-rig" style="padding-right: 0;">
+                  <el-row :gutter="12">
+                    <el-col :span="12" v-for="(item,index) in oilListData.list" v-bind:key="index" >
+                      <el-card v-loading="oilListData.loading" style="margin-bottom: 10px;width: 100%;">
+                        <div class="oilInfo-con" style="padding: 0;">
+                          <div class="oilInfo-item oilInfo-item-two">
+                          <span>{{item.name}}</span>
+                          <span style="float: right;">{{item.mainBoard_NozzleNo}}</span>
+                        </div>
+                          <div class="oilInfo-item oilInfo-item-two">
+                            <span>在线状态:&nbsp;{{item.onlineStatus}}</span>
+                          </div>
+                          <div class="oilInfo-item oilInfo-item-two">
+                            <span>油品:&nbsp;{{ item.fuelName }}</span>
+                          </div>
+                          <div class="oilInfo-item oilInfo-item-two">
+                            <span>自锁功能:&nbsp;{{ item.alarming }}</span>
+                          </div>
+                          <div class="oilInfo-item oilInfo-item-two">
+                            <span>ECQS编码:&nbsp;{{item.code}}</span>
+                          </div>
+                          <!-- <div class="oilInfo-item oilInfo-item-two" style="float: right;">
+                            <el-icon :size="20"><circle-plus-filled /></el-icon>
+                          </div> -->
+                        </div>
+                      </el-card>
+                    </el-col>
+                  </el-row>
+                </div>
               </div>
             </div>
           </div>
@@ -95,10 +132,11 @@
 <script setup lang="ts">
 
 import {onMounted, reactive, ref, watch} from "vue";
-import {
-  moreOilEngineDetails_DetailsData, moreOilEngineDetails_OilListData,
-  moreOilEngineDetails_TableData
-} from "/@/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsDto";
+//import { CirclePlusFilled } from '@element-plus/icons-vue'
+import { NozzlecontrolDtl } from "/@/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsDto";
+import {OilEngineDetailsApi} from "/@/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsApi";
+import { FuelDispenserEntity,AlarmHistoryDto } from "/@/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsDto"
+import router from "/@/router";
 import {MoreOilEngineDetailsApi} from "/@/api/admin/reportManagement/moreOilEngineDetails/moreOilEngineDetailsApi";
 
 /******************************数据对象***************************************/
@@ -108,7 +146,7 @@ import {MoreOilEngineDetailsApi} from "/@/api/admin/reportManagement/moreOilEngi
  */
 const tableData = reactive({
   loading: false,
-  list: [] as Array<moreOilEngineDetails_TableData>
+  list: [] as Array<AlarmHistoryDto>
 })
 
 /**
@@ -116,7 +154,7 @@ const tableData = reactive({
  */
 const detailsData = reactive({
   loading: false,
-  list: {} as moreOilEngineDetails_DetailsData
+  list: {} as FuelDispenserEntity
 })
 
 /**
@@ -124,13 +162,16 @@ const detailsData = reactive({
  */
 const oilListData = reactive({
   loading: false,
-  list: [] as Array<moreOilEngineDetails_OilListData>
+  list: [] as Array<NozzlecontrolDtl>
 })
-
 /**
  * 油机列表初始ID
  */
 const initID = ref()
+const toPage = () => {
+  const id = router.currentRoute.value.params.id
+  router.push({path:`/statement/${id}/more/moreAlert`})
+}
 /******************************数据对象***************************************/
 
 /*******************************方法**************************************/
@@ -171,15 +212,27 @@ watch(() => initID.value, ()=>{
 /*******************************方法**************************************/
 
 /**********************************初始化***********************************/
-
+/**
+ * 格式化日期
+ */
+const formatDate=(val)=>{
+  const date=new Date(val)
+  const year: number = date.getFullYear();
+  const month: string = (date.getMonth() + 1).toString().padStart(2, '0');
+  const day: string = date.getDate().toString().padStart(2, '0');
+  const hours: string = date.getHours().toString().padStart(2, '0');
+  const minutes: string = date.getMinutes().toString().padStart(2, '0');
+  const seconds: string = date.getSeconds().toString().padStart(2, '0');
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
 /**
  * 初始化油机列表详情数据对象
  */
 const initOilListData = async () => {
   oilListData.loading = true
-  const { data } = await new MoreOilEngineDetailsApi().getOilListData()
+  const fuelId=router.currentRoute.value.params.id
+  const { data } = await new MoreOilEngineDetailsApi().getOilListData({Fuelid:fuelId})
   oilListData.list = data
-  initID.value = data[0].oilEngineName
   oilListData.loading = false
 }
 
@@ -188,8 +241,15 @@ const initOilListData = async () => {
  */
 const initTableData = async () => {
   tableData.loading = true
-  const { data } = await new MoreOilEngineDetailsApi().getTableData()
+  const fuelId=router.currentRoute.value.params.id
+  const { data } = await new MoreOilEngineDetailsApi().getTableData({Fuelid:fuelId})
   tableData.list = data
+  tableData.list=tableData.list.map((item)=>{
+    if(item.createdDate!==null){
+      item.createdDate=formatDate(item.createdDate)
+    }
+    return item
+  })
   tableData.loading = false
 }
 
@@ -198,12 +258,40 @@ const initTableData = async () => {
  */
 const initDetailsData = async () => {
   detailsData.loading = true
-  const { data } = await new MoreOilEngineDetailsApi().getDetailsData()
+  const fuelId=router.currentRoute.value.params.id
+  const { data } = await new OilEngineDetailsApi().getBasicInfoDto({Fuelid:fuelId})
   detailsData.list = data
+  if(detailsData.list.createdTime!==null){
+    detailsData.list.createdTime=formatDate(detailsData.list.createdTime)
+  }
+  if(detailsData.list.installationDate!==null){
+    detailsData.list.installationDate=formatDate(detailsData.list.installationDate)
+  }
+  if(detailsData.list.startupDate!==null){
+    detailsData.list.startupDate=formatDate(detailsData.list.startupDate)
+  }
+  if(detailsData.list.onlineStatus!==null){
+    if(detailsData.list.onlineStatus==='offline'){
+      detailsData.list.onlineStatus='离线'
+    }else{
+      detailsData.list.onlineStatus='在线'
+    }
+  }
+  if(detailsData.list.deviceStatus!==null){
+    if(detailsData.list.deviceStatus==='enable'){
+      detailsData.list.deviceStatus='启用'
+    }else if(detailsData.list.deviceStatus==='factory'){
+      detailsData.list.deviceStatus='出厂注册'
+    }else{
+      detailsData.list.deviceStatus='备案'
+    }
+  }
   detailsData.loading = false
 }
 
 const init = () => {
+  initDetailsData()
+  initTableData()
   initOilListData()
 }
 
@@ -263,7 +351,7 @@ onMounted(() => {
 
         .bomCon-rig {
           display: flex;
-          width: 80%;
+          width: 100%;
 
           .bomConR-lef {
             width: 50%;

+ 169 - 80
admin.ui.plus-master/src/views/admin/statement/oilEngineDetails/index.vue

@@ -13,10 +13,10 @@
                   :width="200"
                   title="油机号"
                   trigger="hover"
-                  :content="basicInfo.info.oilEngineNumber"
+                  :content="basicInfo.info.name"
                 >
                   <template #reference>
-                    <span class="m-2"> 油机号: {{basicInfo.info.oilEngineNumber}}</span>
+                    <span class="m-2"> 油机号: {{basicInfo.info.name}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -39,10 +39,10 @@
                   :width="200"
                   title="石油公司"
                   trigger="hover"
-                  :content="basicInfo.info.oilCompanies"
+                  :content="basicInfo.info.oilCompany"
                 >
                   <template #reference>
-                    <span class="m-2"> 石油公司: {{basicInfo.info.oilCompanies}}</span>
+                    <span class="m-2"> 石油公司: {{basicInfo.info.oilCompany}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -52,10 +52,10 @@
                   :width="200"
                   title="加油机厂商"
                   trigger="hover"
-                  :content="basicInfo.info.fuelDispenserManufacturer"
+                  :content="basicInfo.info.manufacturer"
                 >
                   <template #reference>
-                    <span class="m-2"> 加油机厂商: {{basicInfo.info.fuelDispenserManufacturer}}</span>
+                    <span class="m-2"> 加油机厂商: {{basicInfo.info.manufacturer}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -79,14 +79,14 @@
                 <el-popover
                   placement="top-start"
                   :width="200"
-                  title="规格参数"
+                  title="加油机机型"
                   trigger="hover"
-                  :content="basicInfo.info.specifications"
+                  :content="basicInfo.info.model"
                 >
                   <template #reference>
                     <span class="m-2">
-                      密钥状态:
-                        {{ basicInfo.info.specifications }}
+                      加油机机型:
+                        {{ basicInfo.info.model }}
                     </span>
                   </template>
                 </el-popover>
@@ -95,15 +95,12 @@
                 <el-popover
                   placement="top-start"
                   :width="200"
-                  title="测量范围"
+                  title="加油机枪数量"
                   trigger="hover"
-                  :content="basicInfo.info.measuringRange"
+                  :content="basicInfo.info.gunCount"
                 >
                   <template #reference>
-                    <span class="m-2 ">
-                      测量范围:
-                        {{ basicInfo.info.measuringRange }}
-                    </span>
+                    <span class="m-2"> 加油机枪数量: {{basicInfo.info.gunCount}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -111,12 +108,12 @@
                 <el-popover
                   placement="top-start"
                   :width="200"
-                  title="准确度等级"
                   trigger="hover"
-                  :content="basicInfo.info.accuracyLevel"
+                  title="设备状态"
+                  :content="basicInfo.info.deviceStatus"
                 >
                   <template #reference>
-                    <span class="m-2"> 准确度等级: {{basicInfo.info.accuracyLevel}}</span>
+                    <span class="m-2"> 设备状态: {{basicInfo.info.deviceStatus}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -124,12 +121,12 @@
                 <el-popover
                   placement="top-start"
                   :width="200"
+                  title="在线状态"
                   trigger="hover"
-                  title="出厂编码"
-                  :content="basicInfo.info.factoryCode"
+                  :content="basicInfo.info.onlineStatus"
                 >
                   <template #reference>
-                    <span class="m-2"> 出厂编码: {{basicInfo.info.factoryCode}}</span>
+                    <span class="m-2"> 在线状态: {{basicInfo.info.onlineStatus}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -137,25 +134,90 @@
                 <el-popover
                   placement="top-start"
                   :width="200"
-                  title="在线状态"
+                  title="出厂时间"
                   trigger="hover"
-                  :content="basicInfo.info.onlineStatus"
+                  :content="basicInfo.info.manufactureDate"
                 >
                   <template #reference>
-                    <span class="m-2"> 在线状态: {{basicInfo.info.onlineStatus}}</span>
+                    <span class="m-2"> 出厂时间: {{basicInfo.info.manufactureDate}}</span>
                   </template>
                 </el-popover>
               </div>
-              <div class="item">
+              <div class="item ">
+                <el-popover
+                  placement="top-start"
+                  :width="200"
+                  title="启动时间"
+                  trigger="hover"
+                  :content="basicInfo.info.startupDate"
+                >
+                  <template #reference>
+                    <span class="m-2"> 启动时间: {{basicInfo.info.startupDate}}</span>
+                  </template>
+                </el-popover>
+              </div>
+              <div class="item ">
                 <el-popover
                   placement="top-start"
                   :width="200"
-                  title="报警状态"
+                  title="安装时间"
                   trigger="hover"
-                  :content="basicInfo.info.alarmStatus"
+                  :content="basicInfo.info.installationDate"
                 >
                   <template #reference>
-                    <span class="m-2"> 报警状态: {{basicInfo.info.alarmStatus}}</span>
+                    <span class="m-2"> 安装时间: {{basicInfo.info.installationDate}}</span>
+                  </template>
+                </el-popover>
+              </div>
+              <div class="item ">
+                <el-popover
+                  placement="top-start"
+                  :width="200"
+                  title="创建者"
+                  trigger="hover"
+                  :content="basicInfo.info.createdUserName"
+                >
+                  <template #reference>
+                    <span class="m-2"> 创建者: {{basicInfo.info.createdUserName}}</span>
+                  </template>
+                </el-popover>
+              </div>
+              <div class="item ">
+                <el-popover
+                  placement="top-start"
+                  :width="200"
+                  title="创建时间"
+                  trigger="hover"
+                  :content="basicInfo.info.createdTime"
+                >
+                  <template #reference>
+                    <span class="m-2"> 创建时间: {{basicInfo.info.createdTime}}</span>
+                  </template>
+                </el-popover>
+              </div>
+              <div class="item ">
+                <el-popover
+                  placement="top-start"
+                  :width="200"
+                  title="修改者"
+                  trigger="hover"
+                  :content="basicInfo.info.modifiedUserName"
+                >
+                  <template #reference>
+                    <span class="m-2"> 修改者: {{basicInfo.info.modifiedUserName}}</span>
+                  </template>
+                </el-popover>
+              </div>
+              <div class="item ">
+                <el-popover
+                  placement="top-start"
+                  :width="200"
+                  title="修改时间"
+                  trigger="hover"
+                  :content="basicInfo.info.modifiedTime"
+                >
+                  <template #reference>
+                    <span class="m-2"> 修改时间: {{basicInfo.info.modifiedTime}}</span>
                   </template>
                 </el-popover>
               </div>
@@ -171,12 +233,12 @@
               </div>
             </div>
             <div class="basicInformation-right" >
-              <div @click="showBigPic(basicInfo.info.imgUrl)">
+              <div @click="showBigPic(basicInfo.imgUrl)">
                 <el-image loading="lazy"
                           alt="fgg"
                           class="img"
                           fit="contain"
-                          :src="basicInfo.info.imgUrl ? baseUrl + '/' + basicInfo.info.imgUrl : ''" >
+                          :src="basicInfo.imgUrl" >
                   <template #error>
                     <div class="image-slot">
                       <el-icon><icon-picture /></el-icon>
@@ -193,16 +255,16 @@
       <el-col :xs="24">
         <el-card style="height: 40vh" class="mt8 my-fill" shadow="hover" header="报警历史">
           <el-table v-loading="alarmHistory.loading"  stripe :data="alarmHistory.list" row-key="id" style="width: 100%">
-            <el-table-column prop="time" label="时间"  />
+            <el-table-column prop="createdDate" label="时间"  />
             <el-table-column prop="gasStation" label="加油站"  />
-            <el-table-column prop="fillingMachine" label="加油机"  >
+            <el-table-column prop="name" label="加油机"  >
               <template #default="{ row }">
-                {{row.fillingMachine}}
+                {{row.name}}
               </template>
             </el-table-column>
-            <el-table-column prop="fuelDispenserSerialNumber" label="加油机序号"  >
+            <el-table-column prop="serialNumber" label="加油机序号"  >
               <template #default="{ row }">
-                {{row.fuelDispenserSerialNumber}}
+                {{row.serialNumber}}
               </template>
             </el-table-column>
             <el-table-column prop="alarmSource" label="报警来源"  >
@@ -234,7 +296,7 @@
       <el-col :xs="24">
         <el-card style="height: 40vh" class="mt8 my-fill" shadow="hover" header="生命周期">
           <el-table v-loading="lifeCycle.loading"  stripe :data="lifeCycle.list" row-key="id" style="width: 100%">
-            <el-table-column prop="time" label="时间"  />
+            <el-table-column prop="createdDate" label="时间"  />
             <el-table-column prop="operator" label="操作人"  />
             <el-table-column prop="operatorID" label="操作人ID"  />
             <el-table-column prop="operation" label="操作"  />
@@ -275,6 +337,7 @@ import { Picture as IconPicture } from '@element-plus/icons-vue'
 import {onMounted, reactive} from "vue";
 import {OilEngineDetailsApi} from "/@/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsApi";
 import router from "/@/router";
+import { FuelDispenserEntity,PageInputAlarmHistoryDto,AlarmHistoryDto,PageInputLifeCycleDto,LifeCycleDto } from "/@/api/admin/reportManagement/oilEngineDetails/oilEngineDetailsDto"
 
 /******************************数据对象***************************************/
 
@@ -296,21 +359,8 @@ const bigImgDto = reactive({
  */
 const basicInfo = reactive({
   loading:false,
-  info:{
-    id:'1',
-    oilEngineNumber:"",
-    serialNumber:"",
-    oilCompanies:"",
-    fuelDispenserManufacturer:"",
-    gasStation:"",
-    specifications:"",
-    measuringRange:"",
-    accuracyLevel:"",
-    factoryCode:"",
-    onlineStatus:"",
-    alarmStatus:"",
-    imgUrl:""
-  }
+  info:{} as FuelDispenserEntity,
+  imgUrl:'upload/2023/09/15/65048ee6-9b3f-2234-0097-734b351ca09d.png'
 })
 
 /**
@@ -318,20 +368,16 @@ const basicInfo = reactive({
  */
 const alarmHistory = reactive({
   loading:false,
-  list:[{
-    time:"",
-    gasStation:"",
-    fillingMachine:"",
-    fuelDispenserSerialNumber:"",
-    alarmSource:"",
-    alarmType:"",
-    alarmDescription:""
-  }],
+  list:[] as Array<AlarmHistoryDto>,
   pageInput:{
     currentPage: 1,
     pageSize: 5
-  },
-  total:0
+  } as PageInputAlarmHistoryDto,
+  total:0,
+  Filter: {
+    /**油机id */
+    fuelId: 0
+  }
 })
 
 /**
@@ -339,17 +385,16 @@ const alarmHistory = reactive({
  */
 const lifeCycle = reactive({
   loading:false,
-  list:[{
-    time:"",
-    operator:"",
-    operatorID:"",
-    operation:"",
-  }],
+  list:[] as Array<LifeCycleDto>,
   pageInput:{
     currentPage: 1,
     pageSize: 5
-  },
-  total:0
+  } as PageInputLifeCycleDto,
+  total:0,
+  Filter: {
+    /**油机id */
+    fuelId: 0
+  }
 })
 
 /***************************数据对象***************************************/
@@ -363,7 +408,7 @@ const lifeCycle = reactive({
  */
 const showBigPic = (val) => {
   if(val){
-    bigImgDto.imgUrl = baseUrl + '/' + val
+    bigImgDto.imgUrl = val
   }else {
     bigImgDto.imgUrl = ''
   }
@@ -377,7 +422,19 @@ const toPage = () => {
   const id = router.currentRoute.value.params.id
   router.push({path:`/statement/${id}/more`})
 }
-
+/**
+ * 格式化日期
+ */
+ const formatDate=(val)=>{
+  const date=new Date(val)
+  const year: number = date.getFullYear();
+  const month: string = (date.getMonth() + 1).toString().padStart(2, '0');
+  const day: string = date.getDate().toString().padStart(2, '0');
+  const hours: string = date.getHours().toString().padStart(2, '0');
+  const minutes: string = date.getMinutes().toString().padStart(2, '0');
+  const seconds: string = date.getSeconds().toString().padStart(2, '0');
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
 /**
  * 油机详情 - 报警历史 - 页条变化
  * @param val
@@ -424,8 +481,38 @@ const onLifeCycleCurrentChange = (val) => {
  */
 const getBasicInfo = async () => {
   basicInfo.loading = true
-  const { data } = await new OilEngineDetailsApi().getBasicInfoDto()
+  basicInfo.imgUrl=baseUrl + '/'+basicInfo.imgUrl
+  const fuelId=router.currentRoute.value.params.id
+  const { data } = await new OilEngineDetailsApi().getBasicInfoDto({Fuelid:fuelId})
   basicInfo.info = data
+  if(basicInfo.info.createdTime!==null){
+    basicInfo.info.createdTime=formatDate(basicInfo.info.createdTime)
+  }
+  if(basicInfo.info.installationDate!==null){
+    basicInfo.info.installationDate=formatDate(basicInfo.info.installationDate)
+  }
+  if(basicInfo.info.startupDate!==null){
+    basicInfo.info.startupDate=formatDate(basicInfo.info.startupDate)
+  }
+  if(basicInfo.info.modifiedTime!==null){
+    basicInfo.info.modifiedTime=formatDate(basicInfo.info.modifiedTime)
+  }
+  if(basicInfo.info.onlineStatus!==null){
+    if(basicInfo.info.onlineStatus==='offline'){
+      basicInfo.info.onlineStatus='离线'
+    }else{
+      basicInfo.info.onlineStatus='在线'
+    }
+  }
+  if(basicInfo.info.deviceStatus!==null){
+    if(basicInfo.info.deviceStatus==='enable'){
+      basicInfo.info.deviceStatus='启用'
+    }else if(basicInfo.info.deviceStatus==='factory'){
+      basicInfo.info.deviceStatus='出厂注册'
+    }else{
+      basicInfo.info.deviceStatus='备案'
+    }
+  }
   basicInfo.loading = false
 }
 
@@ -434,9 +521,10 @@ const getBasicInfo = async () => {
  */
 const getAlarmHistory = async () => {
   alarmHistory.loading = true
-  const {total, list} = await new OilEngineDetailsApi().getAlarmHistoryDto()
-  alarmHistory.total = total
-  alarmHistory.list = list
+  alarmHistory.Filter.fuelId=router.currentRoute.value.params.id
+  const {data} = await new OilEngineDetailsApi().getAlarmHistoryDto({...alarmHistory.pageInput,filter:alarmHistory.Filter})
+  alarmHistory.total = data.total
+  alarmHistory.list = data.list
   alarmHistory.loading = false
 }
 
@@ -445,9 +533,10 @@ const getAlarmHistory = async () => {
  */
 const getLifeCycle = async () => {
   lifeCycle.loading = true
-  const {total, list} = await new OilEngineDetailsApi().getLifeCycleDto()
-  lifeCycle.total = total
-  lifeCycle.list = list
+  lifeCycle.Filter.fuelId=router.currentRoute.value.params.id
+  const {data} = await new OilEngineDetailsApi().getLifeCycleDto({...lifeCycle.pageInput,filter:lifeCycle.Filter})
+  lifeCycle.total = data.total
+  lifeCycle.list = data.list
   lifeCycle.loading = false
 }
 

+ 18 - 13
admin.ui.plus-master/src/views/admin/visualization/cityLevelMap/index.vue

@@ -2,15 +2,14 @@
   <div class="layout-padding">
     <div class="layout-padding-auto layout-padding-view to-flex">
       <div ref="echartsMapRef" style="height: 100%;width: 80%;"></div>
-      <div class="to-right">
-        <h3>国内销售排名Top&nbsp;&nbsp;10</h3>
-      </div>
+      <!-- <div class="to-right">
+        <h3>国内销售排名Top&nbsp;&nbsp;5</h3>
+      </div> -->
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-
 import * as echarts from "echarts";
 import {onMounted, reactive, ref} from "vue";
 import router from "/@/router";
@@ -25,7 +24,7 @@ const echartsMapRef = ref<RefType>('')
 
 const getJson = async (path) => {
   try {
-    const module = await import('./mockData/'+path);
+    const module = await import(`./mockData/${path}.json`);
     // 注意:JSON 文件应导出为 default 属性
     return module.default
   } catch (error) {
@@ -61,7 +60,8 @@ const initEchartsMap = async () => {
       realtime: false,
       calculable: true,
       inRange: {
-        color: ['lightskyblue', 'yellow', 'orangered']
+        // color: ['lightskyblue', 'yellow', 'orangered']
+        color: ['#aacff9','#75c7f6', '#33a9d6']
       }
     },
     series: [
@@ -73,10 +73,14 @@ const initEchartsMap = async () => {
           show: true,
           fontSize: 12,
           formatter: (params) => {
+            let cityName=params.name
+            if(cityName.length>3){
+              cityName = cityName.substring(0, 3) + '...'
+            }
             if (params.value) {
-              return params.name + ':' + params.value
+              return cityName + ':' + params.value
             }
-            return params.name + ':0'
+            return cityName + ':0'
           },
         },
         // top: '30%',
@@ -115,19 +119,20 @@ onMounted(() => {
     display: flex;
     flex-direction: column;
     justify-content: space-around;
-    top: 0;
+    bottom: 0;
     right: 0;
-    width: 20%;
+    width: 10%;
     max-width: 300px;
-    height: 100%;
+    height: 25%;
     background-color: rgba(0, 234, 255, 0.5);
     color: #000; /* 文本颜色为黑色 */
     h3 {
       text-align: center;
-      font-size: 18px;
+      font-size: 14px;
     }
     .item {
-      margin-left: 50px;
+      text-align: center;
+      font-size: 12px;
     }
   }
 }

+ 10 - 8
admin.ui.plus-master/src/views/admin/visualization/digitalMap/index.vue

@@ -3,7 +3,7 @@
     <div class="layout-padding-auto layout-padding-view to-flex">
       <div ref="echartsMapRef" style="height: 100%;width: 100%;"></div>
       <div class="to-right">
-        <h3>国内销售排名Top&nbsp;&nbsp;10</h3>
+        <h3>国内销售排名Top&nbsp;&nbsp;5</h3>
         <div class="item" v-for="(item,index) in topData" :key="index">
           {{item.name}}:&nbsp;&nbsp;{{item.value}}
         </div>
@@ -28,7 +28,7 @@ const mapData = allCity.sort((a, b) => {
   return b.value - a.value
 })
 
-const topData= mapData.slice(0, 10)
+const topData= mapData.slice(0, 5)
 
 
 // 注册中国地图
@@ -66,7 +66,8 @@ const initEchartsMap = () => {
       realtime: false,
       calculable: true,
       inRange: {
-        color: ['lightskyblue', 'yellow', 'orangered']
+        // color: ['lightskyblue', 'yellow', 'orangered']
+        color: ['#aacff9','#75c7f6', '#33a9d6']
       }
     },
     series: [
@@ -136,19 +137,20 @@ onMounted(() => {
     flex-direction: column;
     justify-content: space-around;
     z-index: 999;
-    top: 0;
+    bottom: 0;
     right: 0;
-    width: 20%;
+    width: 10%;
     max-width: 300px;
-    height: 100%;
+    height: 25%;
     background-color: rgba(0, 234, 255, 0.5);
     color: #000; /* 文本颜色为黑色 */
     h3 {
       text-align: center;
-      font-size: 18px;
+      font-size: 14px;
     }
     .item {
-      margin-left: 50px;
+      text-align: center;
+      font-size: 12px;
     }
   }
 }

+ 0 - 1
admin.ui.plus-master/src/views/admin/workbench/index.vue

@@ -302,7 +302,6 @@ const initLineChart = () => {
 const initPieChart = () => {
   if (!state.global.dispose.some((b: any) => b === state.global.homeChartTwo)) state.global.homeChartTwo.dispose()
   state.global.homeChartTwo = markRaw(echarts.init(homePieRef.value, state.charts.theme))
-
   var data = []
   for (var i = 0; i < pieChart.getName.length; i++) {
     data.push({ name: pieChart.getName[i], value: pieChart.getValue[i] })

+ 127 - 0
admin.ui.plus-master/src/views/example/application/applicationManage/components/org-form.vue

@@ -0,0 +1,127 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用ID" prop="appid" :rules="[{ required: true, message: '请输入应用ID', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.appid" clearable />
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用名称" prop="name" :rules="[{ required: true, message: '请输入应用名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.name" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用编码" prop="code">
+              <el-input v-model="form.code" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/org/form">
+import { reactive, toRefs, ref, PropType } from 'vue'
+import { OauthApplyDto,OauthApply } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import eventBus from '/@/utils/mitt'
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  orgTreeData: {
+    type: Array as PropType<OauthApply[]>,
+    default: () => [],
+  },
+})
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {
+    id:0,
+    appid: '',
+    name: '',
+    code: '',
+    sort: ''
+  } as OauthApplyDto,
+})
+
+const { form } = toRefs(state)
+
+// 打开对话框
+const open = async (row: any = {}) => {
+  // if (row.id > 0) {
+  //   const res = await new PermissionApi().getApplyInfo({ id: row.id }, { loading: true })
+
+  //   if (res?.success) {
+  //     let formData = res.data as OauthApplyDto
+  //     state.form = formData
+  //   }
+  // } else {
+  //   state.form = {} as OauthApplyDto
+  // }
+  state.form=row
+  state.showDialog = true
+}
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addApply(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addApply(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshOrg')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>

+ 110 - 0
admin.ui.plus-master/src/views/example/application/applicationManage/components/org-menu.vue

@@ -0,0 +1,110 @@
+<template>
+  <el-card shadow="never" style="margin-top: 8px" body-style="padding:0px;" class="my-fill">
+    <template #header>
+      <el-input v-model="state.filterText" placeholder="筛选部门" clearable />
+    </template>
+    <el-scrollbar v-loading="state.loading" height="100%" max-height="100%" :always="false" wrap-style="padding:var(--el-card-padding)">
+      <el-tree
+        ref="orgMenuRef"
+        :data="state.orgTreeData"
+        node-key="id"
+        :props="{ children: 'children', label: 'name' }"
+        :filter-node-method="onFilterNode"
+        highlight-current
+        check-strictly
+        default-expand-all
+        render-after-expand
+        :expand-on-click-node="false"
+        v-bind="$attrs"
+        @node-click="onNodeClick"
+        @check-change="onCheckChange"
+      />
+    </el-scrollbar>
+  </el-card>
+</template>
+
+<script lang="ts" setup name="admin/org/menu">
+import { onMounted, reactive, ref, watch, nextTick } from 'vue'
+import { OrgListOutput } from '/@/api/admin/data-contracts'
+import { OrgApi } from '/@/api/admin/Org'
+import { listToTree } from '/@/utils/tree'
+import { ElTree } from 'element-plus'
+
+interface Props {
+  modelValue: number[] | null | undefined
+  selectFirstNode: boolean
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: () => [],
+  selectFirstNode: false,
+})
+
+const orgMenuRef = ref<InstanceType<typeof ElTree>>()
+const state = reactive({
+  loading: false,
+  filterText: '',
+  orgTreeData: [] as Array<OrgListOutput>,
+  lastKey: 0,
+})
+
+watch(
+  () => state.filterText,
+  (val) => {
+    orgMenuRef.value?.filter(val)
+  }
+)
+
+onMounted(() => {
+  initData()
+})
+
+const emits = defineEmits<{
+  (e: 'node-click', node: OrgListOutput | null): void
+  (e: 'update:modelValue', node: any[] | undefined | null): void
+}>()
+
+const onFilterNode = (value: string, data: OrgListOutput) => {
+  if (!value) return true
+  return data.name?.indexOf(value) !== -1
+}
+
+const onNodeClick = (node: OrgListOutput) => {
+  if (state.lastKey === node.id) {
+    state.lastKey = 0
+    orgMenuRef.value?.setCurrentKey(undefined)
+    emits('node-click', null)
+  } else {
+    state.lastKey = node.id as number
+    emits('node-click', node)
+  }
+}
+
+const onCheckChange = () => {
+  emits('update:modelValue', orgMenuRef.value?.getCheckedKeys())
+}
+
+const initData = async () => {
+  state.loading = true
+  const res = await new OrgApi().getList().catch(() => {
+    state.loading = false
+  })
+  state.loading = false
+  if (res?.success && res.data && res.data.length > 0) {
+    state.orgTreeData = listToTree(res.data)
+    if (state.orgTreeData.length > 0 && props.selectFirstNode) {
+      nextTick(() => {
+        const firstNode = state.orgTreeData[0]
+        orgMenuRef.value?.setCurrentKey(firstNode.id)
+        emits('node-click', firstNode)
+      })
+    }
+  } else {
+    state.orgTreeData = []
+  }
+}
+
+defineExpose({
+  orgMenuRef,
+})
+</script>

+ 124 - 0
admin.ui.plus-master/src/views/example/application/applicationManage/index.vue

@@ -0,0 +1,124 @@
+<template>
+  <div class="my-layout">
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <el-form :inline="true" @submit.stop.prevent>
+        <el-form-item label="应用名称">
+          <el-input v-model="state.filter.name" placeholder="应用名称" @keyup.enter="onQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+          <el-button v-auth="'api:admin:org:add'" type="primary" icon="ele-Plus" @click="onAdd"> 新增 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="my-fill mt8" shadow="never">
+      <el-table
+        :data="state.applyData"
+        style="width: 100%"
+        v-loading="state.loading"
+        default-expand-all
+      >
+        <el-table-column prop="appid" label="应用id" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="name" label="应用名称" min-width="120" show-overflow-tooltip />
+        <!-- <el-table-column prop="value" label="部门值" min-width="80" show-overflow-tooltip />
+        <el-table-column prop="sort" label="排序" width="80" align="center" show-overflow-tooltip />
+        <el-table-column label="状态" width="80" align="center" show-overflow-tooltip>
+          <template #default="{ row }">
+            <el-tag type="success" v-if="row.enabled">启用</el-tag>
+            <el-tag type="danger" v-else>禁用</el-tag>
+          </template>
+        </el-table-column> -->
+        <el-table-column label="操作" width="160" fixed="right" header-align="center" align="center">
+          <template #default="{ row }">
+            <el-button
+              icon="ele-EditPen"
+              size="small"
+              text
+              type="primary"
+              @click="onEdit(row)"
+              >编辑</el-button
+            >
+            <el-button
+              icon="ele-Delete"
+              size="small"
+              text
+              type="danger"
+              @click="onDelete(row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <org-form ref="orgFormRef" :title="state.orgFormTitle" :org-tree-data="state.orgTreeData"></org-form>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/org">
+import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, defineAsyncComponent } from 'vue'
+import { OauthApply,OauthApplyDto } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import eventBus from '/@/utils/mitt'
+import { auth } from '/@/utils/authFunction'
+
+// 引入组件
+const OrgForm = defineAsyncComponent(() => import('./components/org-form.vue'))
+
+const { proxy } = getCurrentInstance() as any
+
+const orgFormRef = ref()
+
+const state = reactive({
+  loading: false,
+  orgFormTitle: '',
+  filter: {
+    name: '',
+  }as OauthApplyDto,
+  applyData: [] as Array<OauthApply>,
+})
+
+onMounted(() => {
+  onQuery()
+  eventBus.off('refreshOrg')
+  eventBus.on('refreshOrg', () => {
+    onQuery()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshOrg')
+})
+
+const onQuery = async () => {
+  state.loading = true
+  const res = await new PermissionApi().getApplyInfo(state.filter).catch(() => {
+    state.loading = false
+  })
+  state.applyData=res.data
+  state.loading=false
+}
+
+const onAdd = () => {
+  state.orgFormTitle = '新增应用'
+  orgFormRef.value.open()
+}
+
+const onEdit = (row: OauthApply) => {
+  state.orgFormTitle = '编辑应用'
+  orgFormRef.value.open(row)
+}
+
+const onDelete = (row: OauthApply) => {
+  proxy.$modal
+    .confirmDelete(`确定要删除应用【${row.name}】?`)
+    .then(async () => {
+      await new PermissionApi().applyDelete({ id: row.id }, { loading: true })
+      onQuery()
+    })
+    .catch(() => {})
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 115 - 0
admin.ui.plus-master/src/views/example/application/operationLog/index.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="my-layout">
+    <el-card class="mt8" shadow="never" >
+      <el-form :model="state.filterModel" :inline="true" @submit.stop.prevent>
+        <el-form-item prop="name">
+          <el-input v-model="state.filterModel.createdUserName" placeholder="操作账号" @keyup.enter="onQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="my-fill mt8" shadow="never">
+      <el-table ref="tableRef" v-loading="state.loading" :data="state.oprationLogListData" row-key="id" style="width: 100%" stripe>
+        <el-table-column prop="createdUserName" label="操作账号" >
+          <template #default="{ row }"> {{ row.createdUserName }}</template>
+        </el-table-column>
+        <el-table-column prop="operationType" label="操作类型" >
+          <template #default="{ row }"> {{ row.operationType }}</template>
+        </el-table-column>
+        <el-table-column prop="moduleName" label="模块名称" >
+          <template #default="{ row }"> {{ row.moduleName }}</template>
+        </el-table-column>
+        <el-table-column prop="operationContent" label="描述" >
+          <template #default="{ row }"> {{ row.operationContent }}</template>
+        </el-table-column>
+        <el-table-column prop="beforeState" label="操作前" >
+          <template #default="{ row }"> {{ row.beforeState }}</template>
+        </el-table-column>
+        <el-table-column prop="afterState" label="操作后" >
+          <template #default="{ row }"> {{ row.afterState }}</template>
+        </el-table-column>
+        <el-table-column prop="result" label="操作结果" >
+          <template #default="{ row }"> {{ row.result }}</template>
+        </el-table-column>
+        <el-table-column prop="createdTime" label="操作时间" >
+          <template #default="{ row }"> {{ row.createdTime }}</template>
+        </el-table-column>
+      </el-table>
+      <div class="my-flex my-flex-end" style="margin-top: 20px">
+        <el-pagination
+          v-model:currentPage="state.pageInput.currentPage"
+          v-model:page-size="state.pageInput.pageSize"
+          :total="state.total"
+          :page-sizes="[10, 20, 50, 100]"
+          small
+          background
+          @size-change="onSizeChange"
+          @current-change="onCurrentChange"
+          layout="total, sizes, prev, pager, next, jumper"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/oprationLog">
+import { reactive, onMounted, ref } from 'vue'
+import { OprationLogListOutput, PageInputLogGetPageDto,PageInputOperationGetPageDto,OauthOperationRecordGetPageOutPut } from '/@/api/admin/data-contracts'
+import { OprationLogApi } from '/@/api/admin/OprationLog'
+import { PermissionApi } from '/@/api/admin/Permission'
+import dayjs from 'dayjs'
+import type { TableInstance } from 'element-plus'
+
+const tableRef = ref<TableInstance>()
+
+const state = reactive({
+  loading: false,
+  oprationLogFormTitle: '',
+  filterModel: {
+    createdUserName: '',
+  },
+  total: 0,
+  pageInput: {
+    currentPage: 1,
+    pageSize: 20,
+  } as PageInputOperationGetPageDto,
+  oprationLogListData: [] as Array<OauthOperationRecordGetPageOutPut>,
+  oprationLogLogsTitle: '',
+})
+
+onMounted(() => {
+  onQuery()
+})
+
+const formatterTime = (row: any, column: any, cellValue: any) => {
+  return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
+}
+
+const onQuery = async () => {
+  state.loading = true
+  state.pageInput.filter = state.filterModel
+  const res = await new PermissionApi().getOperationInfo(state.pageInput).catch(() => {
+    state.loading = false
+  })
+
+  state.oprationLogListData = res?.data?.list ?? []
+  state.total = res?.data?.total ?? 0
+  state.loading = false
+}
+
+const onSizeChange = (val: number) => {
+  state.pageInput.pageSize = val
+  onQuery()
+}
+
+const onCurrentChange = async (val: number) => {
+  state.pageInput.currentPage = val
+  await onQuery()
+  tableRef.value?.setScrollTop(0)
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 243 - 0
admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-dot-form.vue

@@ -0,0 +1,243 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用" prop="label">
+              <el-input v-model="state.app" clearable disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="上级菜单">
+              <el-tree-select
+                v-model="form.parentId"
+                :data="permissionTreeData"
+                node-key="id"
+                check-strictly
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                filterable
+                class="w100"
+              />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="API接口">
+              <el-tree-select
+                v-model="form.apiIds"
+                :data="state.apiTreeData"
+                node-key="id"
+                :props="{ label: 'path' }"
+                render-after-expand
+                fit-input-width
+                clearable
+                filterable
+                multiple
+                collapse-tags
+                collapse-tags-tooltip
+                :filter-node-method="onApiFilterNode"
+                class="w100"
+                :default-expanded-keys="state.expandRowKeys"
+                @current-change="onApiCurrentChange"
+              >
+                <template #default="{ data }">
+                  <span class="my-flex my-flex-between">
+                    <span>{{ data.label }}</span>
+                    <span class="my-line-1 my-mlr-12" :title="data.path">
+                      {{ data.path }}
+                    </span>
+                  </span>
+                </template>
+              </el-tree-select>
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="名称" prop="label" :rules="[{ required: true, message: '请输入名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.label" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="编码" prop="code" :rules="[{ required: true, message: '请输入编码', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.code" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="启用">
+              <el-switch v-model="form.enabled" />
+            </el-form-item>
+          </el-col> -->
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="说明">
+              <el-input v-model="form.description" clearable type="textarea" />
+            </el-form-item>
+          </el-col> -->
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/permission/permission-dot-form">
+import { reactive, toRefs, getCurrentInstance, ref, PropType } from 'vue'
+import { PermissionListOutput, PermissionUpdateDotInput, ApiListOutput,oauthPermissionDto,OauthPermission } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { ApiApi } from '/@/api/admin/Api'
+import { listToTree, treeToList } from '/@/utils/tree'
+import eventBus from '/@/utils/mitt'
+import { trimStart, replace, cloneDeep } from 'lodash-es'
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  permissionTreeData: {
+    type: Array as PropType<OauthPermission[]>,
+    default: () => [],
+  },
+})
+
+const { proxy } = getCurrentInstance() as any
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {} as oauthPermissionDto,
+  apiTreeData: [] as OauthPermission[],
+  expandRowKeys: [] as number[],
+  app:''
+})
+
+const { form } = toRefs(state)
+
+const getApis = async () => {
+  const res = await new PermissionApi().getPermissionInfo({appid:0})
+  res.data=res.data.map((item)=>{
+    if(item.parentId===''||item.parentId===null){
+      item.parentId=Number('0')
+      item.type=1
+    }
+    item.parentId=Number(item.parentId)
+    return item
+  })
+  if (res?.success && res.data && res.data.length > 0) {
+    state.apiTreeData = listToTree(res.data) as OauthPermission[]
+  } else {
+    state.apiTreeData = []
+  }
+}
+
+// 打开对话框
+const open = async (app:any,row: any = {}) => {
+  state.app=app
+  proxy.$modal.loading()
+
+  await getApis()
+
+  state.expandRowKeys = treeToList(cloneDeep(state.apiTreeData))
+    .filter((a: OauthPermission) => Number(a.parentId) === 0)
+    .map((a: OauthPermission) => a.id) as number[]
+
+  // if (row.id > 0) {
+  //   const res = await new PermissionApi().getPermissionInfo({appid:0,id: row.id}).catch(() => {
+  //     proxy.$modal.closeLoading()
+  //   })
+
+  //   if (res?.success) {
+  //     let formData = res.data as oauthPermissionDto
+  //     formData.parentId = formData.parentId && Number(formData.parentId) > 0 ? formData.parentId : undefined
+  //     state.form = formData
+  //   }
+  // } else {
+  //   state.form = {} as oauthPermissionDto
+  // }
+  state.form=row
+  proxy.$modal.closeLoading()
+  state.showDialog = true
+}
+
+const onApiFilterNode = (value: string, data: ApiListOutput) => {
+  if (!value) return true
+  return data.label?.indexOf(value) !== -1 || data.path?.indexOf(value) !== -1
+}
+
+const onApiCurrentChange = (data: ApiListOutput) => {
+  if (data) {
+    if (!state.form.label) {
+      state.form.label = data.label
+    }
+    if (!state.form.code) {
+      state.form.code = trimStart(replace(data.path || '', /\//g, ':'), ':')
+    }
+  }
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    state.form.parentId = state.form.parentId && Number(state.form.parentId) > 0 ? state.form.parentId : undefined
+    state.form.type=3
+    const appData=await new PermissionApi().getApplyInfo({name:state.app})
+    state.form.appID=appData.data[0].id
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshPermission')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>
+
+<style scoped lang="scss">
+.my-mlr-12 {
+  margin-left: 12px;
+  margin-right: 12px;
+}
+</style>

+ 233 - 0
admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-group-form.vue

@@ -0,0 +1,233 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用" prop="label">
+              <el-input v-model="state.app" clearable disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="上级分组">
+              <el-tree-select
+                v-model="form.parentId"
+                :data="permissionTreeData"
+                node-key="id"
+                check-strictly
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                class="w100"
+              />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图">
+              <el-tree-select
+                v-model="form.viewId"
+                :data="state.viewTreeData"
+                node-key="id"
+                :props="{ label: 'path' }"
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                filterable
+                :filter-node-method="onViewFilterNode"
+                class="w100"
+              >
+                <template #default="{ data }">
+                  <span class="my-flex my-flex-between">
+                    <span>{{ data.label }}</span>
+                    <span class="my-line-1 my-ml-12" :title="data.path">
+                      {{ data.path }}
+                    </span>
+                  </span>
+                </template>
+              </el-tree-select>
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="名称" prop="label" :rules="[{ required: true, message: '请输入名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.label" clearable />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="路由地址" prop="path" :rules="[{ required: true, message: '请输入路由地址', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.path" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="路由命名">
+              <el-input v-model="form.name" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="重定向">
+              <el-input v-model="form.redirect" clearable placeholder="重定向地址" />
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="图标" prop="icon">
+              <my-select-icon v-model="form.icon" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="启用">
+              <el-switch v-model="form.enabled" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="展开">
+              <el-switch v-model="form.opened" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="隐藏">
+              <el-switch v-model="form.hidden" />
+            </el-form-item>
+          </el-col> -->
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/permission/permission-group-form">
+import { reactive, toRefs, getCurrentInstance, ref, PropType, defineAsyncComponent } from 'vue'
+import { PermissionListOutput, PermissionUpdateGroupInput, ViewListOutput,OauthPermission,oauthPermissionDto } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { ViewApi } from '/@/api/admin/View'
+import { listToTree } from '/@/utils/tree'
+import eventBus from '/@/utils/mitt'
+
+// 引入组件
+const MySelectIcon = defineAsyncComponent(() => import('/@/components/my-select-icon/index.vue'))
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  permissionTreeData: {
+    type: Array as PropType<OauthPermission[]>,
+    default: () => [],
+  },
+})
+const { proxy } = getCurrentInstance() as any
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {} as oauthPermissionDto,
+  viewTreeData: [] as OauthPermission[],
+  app:''
+})
+const { form } = toRefs(state)
+
+const getViews = async () => {
+  const res = await new PermissionApi().getPermissionInfo({appid:0})
+  res.data=res.data.map((item)=>{
+    if(item.parentId===''||item.parentId===null){
+      item.parentId=Number('0')
+      item.type=1
+    }
+    item.parentId=Number(item.parentId)
+    return item
+  })
+  if (res?.success && res.data && res.data.length > 0) {
+    state.viewTreeData = listToTree(res.data) as OauthPermission[]
+  } else {
+    state.viewTreeData = []
+  }
+}
+
+// 打开对话框
+const open = async (app:any,row: any = {}) => {
+  state.app=app
+  proxy.$modal.loading()
+  await getViews()
+  // if (row.id > 0) {
+  //   const res = await new PermissionApi().getPermissionInfo({appid:0,id: row.id}).catch(() => {
+  //     proxy.$modal.closeLoading()
+  //   })
+
+  //   if (res?.success) {
+  //     let formData = res.data as oauthPermissionDto
+  //     formData.parentId = formData.parentId && Number(formData.parentId) > 0 ? formData.parentId : undefined
+  //     state.form = formData
+  //   }
+  // } else {
+  //   state.form = { icon: 'ele-Memo' } as oauthPermissionDto
+  // }
+  state.form=row
+  proxy.$modal.closeLoading()
+  state.showDialog = true
+}
+
+// const onViewFilterNode = (value: string, data: OauthPermission) => {
+//   if (!value) return true
+//   return data.label?.indexOf(value) !== -1 || data.path?.indexOf(value) !== -1
+// }
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    state.form.parentId = state.form.parentId && Number(state.form.parentId) > 0 ? state.form.parentId : undefined
+    state.form.type=1
+    const appData=await new PermissionApi().getApplyInfo({name:state.app})
+    state.form.appID=appData.data[0].id
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshPermission')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>

+ 274 - 0
admin.ui.plus-master/src/views/example/application/permissionManage/components/permission-menu-form.vue

@@ -0,0 +1,274 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用" prop="label">
+              <el-input v-model="state.app" clearable disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="上级分组">
+              <el-tree-select
+                v-model="form.parentId"
+                :data="permissionTreeData"
+                node-key="id"
+                check-strictly
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                class="w100"
+              />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图">
+              <el-tree-select
+                v-model="form.viewId"
+                :data="state.viewTreeData"
+                node-key="id"
+                :props="{ label: 'path' }"
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                filterable
+                :filter-node-method="onViewFilterNode"
+                class="w100"
+                @current-change="onViewCurrentChange"
+              >
+                <template #default="{ data }">
+                  <span class="my-flex my-flex-between">
+                    <span>{{ data.label }}</span>
+                    <span class="my-line-1 my-ml-12" :title="data.path">
+                      {{ data.path }}
+                    </span>
+                  </span>
+                </template>
+              </el-tree-select>
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="名称" prop="label" :rules="[{ required: true, message: '请输入名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.label" clearable />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="路由地址" prop="path" :rules="[{ required: true, message: '请输入路由地址', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.path" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="路由命名">
+              <el-input v-model="form.name" clearable />
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="图标" prop="icon">
+              <my-select-icon v-model="form.icon" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="启用">
+              <el-switch v-model="form.enabled" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="链接地址">
+              <el-input v-model="form.link" clearable placeholder="内嵌/外链链接地址" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="内嵌窗口">
+              <el-switch v-model="form.isIframe" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="缓存">
+              <el-switch v-model="form.isKeepAlive" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="固定">
+              <el-switch v-model="form.isAffix" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="隐藏">
+              <el-switch v-model="form.hidden" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="新窗口">
+              <el-switch v-model="form.newWindow" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="链接外显">
+              <el-switch v-model="form.external" />
+            </el-form-item>
+          </el-col> -->
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/permission/permission-menu-form">
+import { reactive, toRefs, getCurrentInstance, ref, PropType, defineAsyncComponent } from 'vue'
+import { PermissionListOutput, PermissionUpdateMenuInput, ViewListOutput,OauthPermission,oauthPermissionDto } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { ViewApi } from '/@/api/admin/View'
+import { listToTree } from '/@/utils/tree'
+import eventBus from '/@/utils/mitt'
+
+// 引入组件
+const MySelectIcon = defineAsyncComponent(() => import('/@/components/my-select-icon/index.vue'))
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  permissionTreeData: {
+    type: Array as PropType<OauthPermission[]>,
+    default: () => [],
+  },
+})
+
+const { proxy } = getCurrentInstance() as any
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {} as oauthPermissionDto,
+  viewTreeData: [] as OauthPermission[],
+  app:''
+})
+const { form } = toRefs(state)
+
+const getViews = async () => {
+  const res = await new PermissionApi().getPermissionInfo({appid:0})
+  res.data=res.data.map((item)=>{
+    if(item.parentId===''||item.parentId===null){
+      item.parentId=Number('0')
+      item.type=1
+    }
+    item.parentId=Number(item.parentId)
+    return item
+  })
+  if (res?.success && res.data && res.data.length > 0) {
+    state.viewTreeData = listToTree(res.data) as OauthPermission[]
+  } else {
+    state.viewTreeData = []
+  }
+}
+
+// 打开对话框
+const open = async (app:any,row: any = {}) => {
+  state.app=app
+  proxy.$modal.loading()
+
+  await getViews()
+
+  // if (row.id > 0) {
+  //   const res = await new PermissionApi().getPermissionInfo({appid:0,id: row.id}).catch(() => {
+  //     proxy.$modal.closeLoading()
+  //   })
+
+  //   if (res?.success) {
+  //     let formData = res.data as oauthPermissionDto
+  //     formData.parentId = formData.parentId && Number(formData.parentId) > 0 ? formData.parentId : undefined
+  //     state.form = formData
+  //   }
+  // } else {
+  //   state.form = { icon: 'ele-Memo' } as oauthPermissionDto
+  // }
+  state.form=row
+  proxy.$modal.closeLoading()
+  state.showDialog = true
+}
+
+// const onViewFilterNode = (value: string, data: OauthPermission) => {
+//   if (!value) return true
+//   return data.label?.indexOf(value) !== -1 || data.path?.indexOf(value) !== -1
+// }
+
+const onViewCurrentChange = (data: OauthPermission) => {
+  if (data) {
+    if (!state.form.label) {
+      state.form.label = data.label
+    }
+    // if (!state.form.path) {
+    //   state.form.path = '/' + data.path
+    // }
+  }
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    state.form.parentId = state.form.parentId && Number(state.form.parentId) > 0 ? state.form.parentId : undefined
+    state.form.type=2
+    const appData=await new PermissionApi().getApplyInfo({name:state.app})
+    state.form.appID=appData.data[0].id
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addAppPermission(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshPermission')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>
+
+<style scoped lang="scss">
+.my-ml-12 {
+  margin-left: 12px;
+}
+</style>

+ 248 - 0
admin.ui.plus-master/src/views/example/application/permissionManage/index.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="my-layout">
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <el-form :model="state.filter" :inline="true" @submit.stop.prevent>
+        <el-form-item label="应用">
+          <el-select v-model="state.filter.app"  placeholder="请选择应用" style="width: 200px;">
+            <el-option v-for="(value, key) in state.app" :key="key" :label="value.name"  :value="value.name" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="权限名称">
+          <el-input v-model="state.filter.name" placeholder="权限名称" @keyup.enter="onQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+          <el-dropdown
+            v-auths="['api:admin:permission:addgroup', 'api:admin:permission:addmenu', 'api:admin:permission:adddot']"
+            style="margin-left: 12px"
+          >
+            <el-button type="primary"
+              >新增<el-icon class="el-icon--right"><ele-ArrowDown /></el-icon
+            ></el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item v-if="auth('api:admin:permission:addgroup')" @click="onAdd(1)">新增分组</el-dropdown-item>
+                <el-dropdown-item v-if="auth('api:admin:permission:addmenu')" @click="onAdd(2)">新增菜单</el-dropdown-item>
+                <el-dropdown-item v-if="auth('api:admin:permission:adddot')" @click="onAdd(3)">新增权限点</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="my-fill mt8" shadow="never">
+      <el-table
+        :data="state.permissionTreeData"
+        style="width: 100%"
+        v-loading="state.loading"
+        row-key="id"
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+        :expand-row-keys="state.expandRowKeys"
+      >
+        <el-table-column prop="label" label="权限名称" width="240" show-overflow-tooltip>
+          <template #default="{ row }">
+            <SvgIcon :name="row.icon" />
+            {{ row.label }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="类型" width="80" show-overflow-tooltip>
+          <template #default="{ row }">
+            {{ row.type === 1 ? '分组' : row.type === 2 ? '菜单' : row.type === 3 ? '权限点' : '' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="path" label="权限地址" min-width="240" show-overflow-tooltip>
+          <template #default="{ row }">
+            <div v-if="row.type === 1 || row.type === 2">
+              {{ row.viewPath ? '视图地址:' + row.viewPath : '' }}
+            </div>
+            <div v-if="row.type === 3">接口地址:{{ row.viewPath }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="sort" label="排序" width="80" align="center" show-overflow-tooltip />
+        <!-- <el-table-column label="状态" width="80" align="center" show-overflow-tooltip>
+          <template #default="{ row }">
+            <el-tag type="success" v-if="row.enabled">启用</el-tag>
+            <el-tag type="danger" v-else>禁用</el-tag>
+          </template>
+        </el-table-column> -->
+        <el-table-column label="操作" width="160" fixed="right" header-align="center" align="center">
+          <template #default="{ row }">
+            <el-button
+              v-if="
+                (row.type === 1 && auth('api:admin:permission:updategroup')) ||
+                (row.type === 2 && auth('api:admin:permission:updatemenu')) ||
+                (row.type === 3 && auth('api:admin:permission:updatedot'))
+              "
+              icon="ele-EditPen"
+              size="small"
+              text
+              type="primary"
+              @click="onEdit(row)"
+              >编辑</el-button
+            >
+            <el-button v-auth="'api:admin:permission:delete'" icon="ele-Delete" size="small" text type="danger" @click="onDelete(row)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <permission-group-form
+      ref="permissionGroupFormRef"
+      :title="state.permissionFormTitle"
+      :permission-tree-data="state.formPermissionGroupTreeData"
+    ></permission-group-form>
+
+    <permission-menu-form
+      ref="permissionMenuFormRef"
+      :title="state.permissionFormTitle"
+      :permission-tree-data="state.formPermissionGroupTreeData"
+    ></permission-menu-form>
+
+    <permission-dot-form
+      ref="permissionDotFormRef"
+      :title="state.permissionFormTitle"
+      :permission-tree-data="state.formPermissionMenuTreeData"
+    ></permission-dot-form>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/permission">
+import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, defineAsyncComponent } from 'vue'
+import { OauthPermission,OauthApply } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { listToTree, treeToList, filterTree } from '/@/utils/tree'
+import { cloneDeep } from 'lodash-es'
+import eventBus from '/@/utils/mitt'
+import { auth } from '/@/utils/authFunction'
+import { it } from 'node:test'
+
+// 引入组件
+const PermissionGroupForm = defineAsyncComponent(() => import('./components/permission-group-form.vue'))
+const PermissionMenuForm = defineAsyncComponent(() => import('./components/permission-menu-form.vue'))
+const PermissionDotForm = defineAsyncComponent(() => import('./components/permission-dot-form.vue'))
+
+const { proxy } = getCurrentInstance() as any
+
+const permissionGroupFormRef = ref()
+const permissionMenuFormRef = ref()
+const permissionDotFormRef = ref()
+const state = reactive({
+  loading: false,
+  permissionFormTitle: '',
+  filter: {
+    name: '',
+    app:'1'
+  },
+  permissionTreeData: [] as Array<OauthPermission>,
+  formPermissionGroupTreeData: [] as Array<OauthPermission>,
+  formPermissionMenuTreeData: [] as Array<OauthPermission>,
+  expandRowKeys: [] as string[],
+  app:[] as Array<OauthApply>,
+})
+
+onMounted(async () => {
+  await onQuery()
+  //state.filter.app=state.app[0].name
+  state.expandRowKeys = treeToList(cloneDeep(state.permissionTreeData))
+    .filter((a: OauthPermission) => a.opened === true)
+    .map((a: OauthPermission) => a.id + '') as string[]
+  eventBus.off('refreshPermission')
+  eventBus.on('refreshPermission', async () => {
+    onQuery()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshPermission')
+})
+
+const onQuery = async () => {
+  state.loading = true
+  const appForm=await new PermissionApi().getApplyInfo({name:state.filter.app})
+  const appID=appForm.data[0].id
+  const appData=await new PermissionApi().getApplyInfo({id:0})
+  state.app=appData.data
+  const res = await new PermissionApi().getPermissionInfo({appid:appID,label:state.filter.name}).catch(() => {
+    state.loading = false
+  })
+  res.data=res.data.map((item)=>{
+    item.parentId=Number(item.parentId)
+    if(item.parentId===0||item.parentId===null){
+      //item.parentId=Number('0')
+      item.type=1
+    }
+    // if(item.parentId===0){
+    //   //item.parentId=Number(item.parentId)
+    //   item.type=2
+    // }
+    // if(item.parentId!==0){
+    //   //item.parentId=Number(item.parentId)
+    //   item.type=3
+    // }
+    return item
+  })
+  if (res && res.data && res.data.length > 0) {
+    state.permissionTreeData = filterTree(listToTree(cloneDeep(res.data)), state.filter.name, {
+      filterWhere: (item: any, keyword: string) => {
+        return item.label?.toLocaleLowerCase().indexOf(keyword) > -1
+      },
+    })
+    state.formPermissionGroupTreeData = listToTree(cloneDeep(res.data).filter((a) => a.type === 1))
+    state.formPermissionMenuTreeData = listToTree(cloneDeep(res.data).filter((a) => a.type === 1 || a.type === 2))
+  } else {
+    state.permissionTreeData = []
+    state.formPermissionGroupTreeData = []
+    state.formPermissionMenuTreeData = []
+  }
+  state.loading = false
+}
+
+const onAdd = (type: number) => {
+  switch (type) {
+    case 1:
+      state.permissionFormTitle = '新增分组'
+      permissionGroupFormRef.value.open(state.filter.app)
+      break
+    case 2:
+      state.permissionFormTitle = '新增菜单'
+      permissionMenuFormRef.value.open(state.filter.app)
+      break
+    case 3:
+      state.permissionFormTitle = '新增权限点'
+      permissionDotFormRef.value.open(state.filter.app)
+      break
+  }
+}
+
+const onEdit = (row: OauthPermission) => {
+  switch (row.type) {
+    case 1:
+      state.permissionFormTitle = '编辑分组'
+      permissionGroupFormRef.value.open(state.filter.app,row)
+      break
+    case 2:
+      state.permissionFormTitle = '编辑菜单'
+      permissionMenuFormRef.value.open(state.filter.app,row)
+      break
+    case 3:
+      state.permissionFormTitle = '编辑权限点'
+      permissionDotFormRef.value.open(state.filter.app,row)
+      break
+  }
+}
+
+const onDelete = (row: OauthPermission) => {
+  proxy.$modal
+    .confirmDelete(`确定要删除${row.type === 1 ? '分组' : row.type === 2 ? '菜单' : row.type === 3 ? '权限点' : ''}【${row.label}】?`)
+    .then(async () => {
+      await new PermissionApi().permissionDelete({id:row.id}, { loading: true })
+      onQuery()
+    })
+    .catch(() => {})
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 110 - 0
admin.ui.plus-master/src/views/example/application/roleManage/components/org-menu.vue

@@ -0,0 +1,110 @@
+<template>
+  <el-card shadow="never" style="margin-top: 8px" body-style="padding:0px;" class="my-fill">
+    <template #header>
+      <el-input v-model="state.filterText" placeholder="筛选部门" clearable />
+    </template>
+    <el-scrollbar v-loading="state.loading" height="100%" max-height="100%" :always="false" wrap-style="padding:var(--el-card-padding)">
+      <el-tree
+        ref="orgMenuRef"
+        :data="state.orgTreeData"
+        node-key="id"
+        :props="{ children: 'children', label: 'name' }"
+        :filter-node-method="onFilterNode"
+        highlight-current
+        check-strictly
+        default-expand-all
+        render-after-expand
+        :expand-on-click-node="false"
+        v-bind="$attrs"
+        @node-click="onNodeClick"
+        @check-change="onCheckChange"
+      />
+    </el-scrollbar>
+  </el-card>
+</template>
+
+<script lang="ts" setup name="admin/org/menu">
+import { onMounted, reactive, ref, watch, nextTick } from 'vue'
+import { OrgListOutput } from '/@/api/admin/data-contracts'
+import { OrgApi } from '/@/api/admin/Org'
+import { listToTree } from '/@/utils/tree'
+import { ElTree } from 'element-plus'
+
+interface Props {
+  modelValue: number[] | null | undefined
+  selectFirstNode: boolean
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: () => [],
+  selectFirstNode: false,
+})
+
+const orgMenuRef = ref<InstanceType<typeof ElTree>>()
+const state = reactive({
+  loading: false,
+  filterText: '',
+  orgTreeData: [] as Array<OrgListOutput>,
+  lastKey: 0,
+})
+
+watch(
+  () => state.filterText,
+  (val) => {
+    orgMenuRef.value?.filter(val)
+  }
+)
+
+onMounted(() => {
+  initData()
+})
+
+const emits = defineEmits<{
+  (e: 'node-click', node: OrgListOutput | null): void
+  (e: 'update:modelValue', node: any[] | undefined | null): void
+}>()
+
+const onFilterNode = (value: string, data: OrgListOutput) => {
+  if (!value) return true
+  return data.name?.indexOf(value) !== -1
+}
+
+const onNodeClick = (node: OrgListOutput) => {
+  if (state.lastKey === node.id) {
+    state.lastKey = 0
+    orgMenuRef.value?.setCurrentKey(undefined)
+    emits('node-click', null)
+  } else {
+    state.lastKey = node.id as number
+    emits('node-click', node)
+  }
+}
+
+const onCheckChange = () => {
+  emits('update:modelValue', orgMenuRef.value?.getCheckedKeys())
+}
+
+const initData = async () => {
+  state.loading = true
+  const res = await new OrgApi().getList().catch(() => {
+    state.loading = false
+  })
+  state.loading = false
+  if (res?.success && res.data && res.data.length > 0) {
+    state.orgTreeData = listToTree(res.data)
+    if (state.orgTreeData.length > 0 && props.selectFirstNode) {
+      nextTick(() => {
+        const firstNode = state.orgTreeData[0]
+        orgMenuRef.value?.setCurrentKey(firstNode.id)
+        emits('node-click', firstNode)
+      })
+    }
+  } else {
+    state.orgTreeData = []
+  }
+}
+
+defineExpose({
+  orgMenuRef,
+})
+</script>

+ 141 - 0
admin.ui.plus-master/src/views/example/application/roleManage/components/role-form.vue

@@ -0,0 +1,141 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <el-col v-if="form.type === 2" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="上级分组" prop="parentId" :rules="[{ required: true, message: '请选择上级分组', trigger: ['change'] }]">
+              <el-tree-select
+                v-model="form.parentId"
+                :data="roleTreeData"
+                node-key="id"
+                :props="{ label: 'name' }"
+                check-strictly
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                class="w100"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="名称" prop="name" :rules="[{ required: true, message: '请输入名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.name" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col v-if="form.type === 2" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="编码" prop="code">
+              <el-input v-model="form.code" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+          <el-col v-if="form.type === 2" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="说明">
+              <el-input v-model="form.description" clearable type="textarea" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/role/form">
+import { reactive, toRefs, ref, PropType } from 'vue'
+import { RoleGetListOutput, RoleUpdateInput,OauthRole } from '/@/api/admin/data-contracts'
+import { RoleApi } from '/@/api/admin/Role'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { cloneDeep } from 'lodash-es'
+import eventBus from '/@/utils/mitt'
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  roleTreeData: {
+    type: Array as PropType<OauthRole[]>,
+    default: () => [],
+  },
+})
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {} as OauthRole,
+})
+
+const { form } = toRefs(state)
+
+// 打开对话框
+const open = async (row: OauthRole) => {
+  let formData = cloneDeep(row) as OauthRole
+  // if (row.id > 0) {
+  //   const res = await new RoleApi().get({ id: row.id }, { loading: true })
+
+  //   if (res?.success) {
+  //     formData = res.data as OauthRole
+  //     formData.parentId = formData.parentId && formData.parentId > 0 ? formData.parentId : undefined
+  //   }
+  // }
+
+  state.form = formData
+  state.showDialog = true
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    state.form.parentId = state.form.parentId && Number(state.form.parentId) > 0 ? state.form.parentId : undefined
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addRole(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addRole(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshRole')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>

+ 152 - 0
admin.ui.plus-master/src/views/example/application/roleManage/components/set-app-menu.vue

@@ -0,0 +1,152 @@
+<template>
+  <div>
+    <el-dialog
+    v-model="state.showDialog"
+    destroy-on-close
+    :title="innerTitle"
+    append-to-body
+    draggable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    width="780px"
+  >
+    <div>
+      <el-radio-group v-model="selectedApp">
+        <el-radio v-for="(item,index) in state.permissionTreeData" :key="index" :label="item.id">{{ item.name }}</el-radio>
+      </el-radio-group>
+    </div>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="onCancel" size="default">取 消</el-button>
+        <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+      </span>
+    </template>
+  </el-dialog>
+  <set-role-menu ref="setRoleMenuRef"></set-role-menu>
+  </div>
+
+</template>
+
+<script lang="ts" setup name="admin/role/components/set-role-menu">
+import { ref, reactive, getCurrentInstance, computed,defineAsyncComponent } from 'vue'
+import { RoleGetListOutput, PermissionAssignInput,OauthApply } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { ElMessage, ElTree } from 'element-plus'
+import { listToTree } from '/@/utils/tree'
+import { cloneDeep } from 'lodash-es'
+const SetRoleMenu = defineAsyncComponent(() => import('../components/set-role-menu.vue'))
+const props = defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+})
+const setRoleMenuRef = ref()
+const innerTitle = computed(() => {
+  return props.title ? props.title : state.roleName ? `选择【${state.roleName}】应用权限` : '设置应用权限'
+})
+
+const state = reactive({
+  showDialog: false,
+  loading: false,
+  sureLoading: false,
+  permissionTreeData: [] as Array<OauthApply>,
+  roleId: 0 as number | undefined,
+  roleName: '' as string | undefined | null,
+  checkedKeys: [],
+})
+const selectedApp=ref('')
+
+const { proxy } = getCurrentInstance() as any
+
+// 打开对话框
+const open = async (role: RoleGetListOutput) => {
+  state.roleId = role.id
+  state.roleName = role.name
+  proxy.$modal.loading()
+  await onQuery()
+  //await getAppPermissionList()
+  proxy.$modal.closeLoading()
+  state.showDialog = true
+}
+
+// 关闭对话框
+const close = () => {
+  state.showDialog = false
+}
+
+const onQuery = async () => {
+  state.loading = true
+
+  const res = await new PermissionApi().getApplyInfo({ id:state.roleId }).catch(() => {
+    state.loading = false
+  })
+  if (res && res.data && res.data.length > 0) {
+    state.permissionTreeData = res.data
+  } else {
+    state.permissionTreeData = []
+  }
+  state.loading = false
+}
+
+const customNodeClass = (data: any) => {
+  return data.row ? 'is-penultimate' : ''
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = async () => {
+  state.sureLoading = true
+  if(selectedApp.value===''){
+    ElMessage.error('请选择应用')
+    state.sureLoading = false
+  }else{
+    const input = { id: state.roleId, name:state.roleName }
+    // const res = await new PermissionApi().roleMenu(input, { showSuccessMessage: true }).catch(() => {
+    //   state.sureLoading = false
+    // })
+
+    state.sureLoading = false
+    state.showDialog = false
+    // if (res?.success) {
+    //   state.showDialog = false
+    // }
+    setRoleMenuRef.value.open(input,selectedApp.value)
+  }
+}
+
+defineExpose({
+  open,
+  close,
+})
+</script>
+
+<style scoped lang="scss">
+:deep(.el-dialog__body) {
+  padding: 5px 10px;
+}
+:deep(.is-penultimate) {
+  .el-tree-node__children {
+    padding-left: 65px;
+    white-space: pre-wrap;
+    line-height: 100%;
+
+    .el-tree-node {
+      display: inline-block;
+    }
+
+    .el-tree-node__content {
+      padding-left: 12px !important;
+      padding-right: 12px;
+
+      .el-tree-node__expand-icon.is-leaf {
+        display: none;
+      }
+    }
+  }
+}
+</style>

+ 163 - 0
admin.ui.plus-master/src/views/example/application/roleManage/components/set-role-menu.vue

@@ -0,0 +1,163 @@
+<template>
+  <el-dialog
+    v-model="state.showDialog"
+    destroy-on-close
+    :title="innerTitle"
+    append-to-body
+    draggable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    width="780px"
+  >
+    <div>
+      <el-tree
+        ref="permissionTreeRef"
+        :data="state.permissionTreeData"
+        node-key="id"
+        show-checkbox
+        highlight-current
+        default-expand-all
+        check-on-click-node
+        :expand-on-click-node="false"
+        :props="{ class: customNodeClass }"
+        :default-checked-keys="state.checkedKeys"
+      />
+    </div>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="onCancel" size="default">取 消</el-button>
+        <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script lang="ts" setup name="admin/role/components/set-role-menu">
+import { ref, reactive, getCurrentInstance, computed } from 'vue'
+import { RoleGetListOutput, PermissionAssignInput } from '/@/api/admin/data-contracts'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { ElTree } from 'element-plus'
+import { listToTree } from '/@/utils/tree'
+import { cloneDeep } from 'lodash-es'
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+})
+
+const innerTitle = computed(() => {
+  return props.title ? props.title : state.roleName ? `设置【${state.roleName}】菜单权限` : '设置菜单权限'
+})
+
+const state = reactive({
+  showDialog: false,
+  loading: false,
+  sureLoading: false,
+  permissionTreeData: [],
+  roleId: 0 as number | undefined,
+  roleName: '' as string | undefined | null,
+  checkedKeys: [],
+  appid:0
+})
+
+const { proxy } = getCurrentInstance() as any
+const permissionTreeRef = ref<InstanceType<typeof ElTree>>()
+
+const getRolePermissionList = async () => {
+  const res = await new PermissionApi().getMenuInfo( {roleid:state.roleId,applyid:state.appid} )
+  state.checkedKeys = res?.success ? (res.data as never[]) : []
+}
+
+// 打开对话框
+const open = async (role: RoleGetListOutput,appId:any) => {
+  state.roleId = role.id
+  state.roleName = role.name
+  state.appid=appId
+  proxy.$modal.loading()
+  await onQuery()
+  await getRolePermissionList()
+  proxy.$modal.closeLoading()
+  state.showDialog = true
+}
+
+// 关闭对话框
+const close = () => {
+  state.showDialog = false
+}
+
+const onQuery = async () => {
+  state.loading = true
+
+  const res = await new PermissionApi().getPermissionInfo({appid:state.appid}).catch(() => {
+    state.loading = false
+  })
+  res.data=res.data.map((item)=>{
+    item.parentId=Number(item.parentId)
+    return item
+  })
+  if (res && res.data && res.data.length > 0) {
+    state.permissionTreeData = listToTree(cloneDeep(res.data))
+  } else {
+    state.permissionTreeData = []
+  }
+
+  state.loading = false
+}
+
+const customNodeClass = (data: any) => {
+  return data.row ? 'is-penultimate' : ''
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = async () => {
+  state.sureLoading = true
+  const permissionIds = permissionTreeRef.value?.getCheckedKeys(true)
+  const input = { strings: permissionIds }
+  const res = await new PermissionApi().roleMenuAssign(input,{applyid:String(state.appid),roleId: String(state.roleId)} ,{ showSuccessMessage: true }).catch(() => {
+    state.sureLoading = false
+  })
+  state.sureLoading = false
+
+  if (res?.success) {
+    state.showDialog = false
+  }
+}
+
+defineExpose({
+  open,
+  close,
+})
+</script>
+
+<style scoped lang="scss">
+:deep(.el-dialog__body) {
+  padding: 5px 10px;
+}
+:deep(.is-penultimate) {
+  .el-tree-node__children {
+    padding-left: 65px;
+    white-space: pre-wrap;
+    line-height: 100%;
+
+    .el-tree-node {
+      display: inline-block;
+    }
+
+    .el-tree-node__content {
+      padding-left: 12px !important;
+      padding-right: 12px;
+
+      .el-tree-node__expand-icon.is-leaf {
+        display: none;
+      }
+    }
+  }
+}
+</style>

+ 202 - 0
admin.ui.plus-master/src/views/example/application/roleManage/components/user-select.vue

@@ -0,0 +1,202 @@
+<template>
+  <el-dialog
+    v-model="state.showDialog"
+    destroy-on-close
+    :title="title"
+    append-to-body
+    draggable
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    width="780px"
+  >
+    <div style="padding: 0px 0px 8px 8px; background-color: var(--ba-bg-color)">
+      <el-row :gutter="8" style="width: 100%">
+        <el-col :xs="24" :sm="9">
+          <div class="my-flex-column h100">
+            <org-menu @node-click="onOrgNodeClick" class="my-flex-fill"></org-menu>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="15">
+          <el-card shadow="never" :body-style="{ paddingBottom: '0' }" style="margin-top: 8px">
+            <el-form :model="state.filter" :inline="true" @submit.stop.prevent>
+              <el-form-item label="姓名" prop="name">
+                <el-input v-model="state.filter.name" placeholder="姓名" @keyup.enter="onQuery" />
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+              </el-form-item>
+            </el-form>
+          </el-card>
+
+          <el-card shadow="never" style="margin-top: 8px">
+            <el-table
+              ref="userTableRef"
+              :data="state.userListData"
+              style="width: 100%"
+              v-loading="state.loading"
+              row-key="id"
+              default-expand-all
+              :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+              :highlight-current-row="!multiple"
+              @row-click="onRowClick"
+              @row-dblclick="onRowDbClick"
+            >
+              <el-table-column v-if="multiple" type="selection" width="55" />
+              <el-table-column prop="name" label="姓名" min-width="80" show-overflow-tooltip />
+              <el-table-column prop="mobile" label="手机号" min-width="120" show-overflow-tooltip />
+              <!-- <el-table-column prop="email" label="邮箱" min-width="120" show-overflow-tooltip /> -->
+            </el-table>
+            <div class="my-flex my-flex-end" style="margin-top: 20px">
+              <el-pagination
+                v-model:currentPage="state.pageInput.currentPage"
+                v-model:page-size="state.pageInput.pageSize"
+                :total="state.total"
+                :page-sizes="[10, 20, 50, 100]"
+                small
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                layout="total, sizes, prev, pager, next"
+              />
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="onCancel" size="default">取 消</el-button>
+        <el-button type="primary" @click="onSure" size="default" :loading="sureLoading">确 定</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script lang="ts" setup name="example/application/roleManage/components/user-select">
+import { ref, reactive, defineAsyncComponent } from 'vue'
+import { ElTable } from 'element-plus'
+import { UserDto, PageInputUserGetPageDto, OrgListOutput } from '/@/api/admin/data-contracts'
+import { UserApi } from '/@/api/admin/User'
+
+// 引入组件
+const OrgMenu = defineAsyncComponent(() => import('./org-menu.vue'))
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  multiple: {
+    type: Boolean,
+    default: false,
+  },
+  sureLoading: {
+    type: Boolean,
+    default: false,
+  },
+})
+
+const emits = defineEmits(['sure'])
+
+const userTableRef = ref<InstanceType<typeof ElTable>>()
+
+const state = reactive({
+  showDialog: false,
+  loading: false,
+  filter: {
+    name: '',
+  },
+  total: 0,
+  pageInput: {
+    currentPage: 1,
+    pageSize: 20,
+    filter: {
+      orgId: null,
+    },
+  } as PageInputUserGetPageDto,
+  userListData: [] as Array<UserDto>,
+})
+
+// 打开对话框
+const open = () => {
+  state.showDialog = true
+  if (state.pageInput.filter) {
+    state.pageInput.filter.orgId = null
+  }
+
+  onQuery()
+}
+
+// 关闭对话框
+const close = () => {
+  state.showDialog = false
+}
+
+const onQuery = async () => {
+  state.loading = true
+  state.pageInput.dynamicFilter = {
+    field: 'name',
+    operator: 0,
+    value: state.filter.name,
+  }
+  const res = await new UserApi().getPage(state.pageInput).catch(() => {
+    state.loading = false
+  })
+
+  state.userListData = res?.data?.list ?? []
+  state.total = res?.data?.total ?? 0
+  state.loading = false
+}
+
+const onSizeChange = (val: number) => {
+  state.pageInput.pageSize = val
+  onQuery()
+}
+
+const onCurrentChange = (val: number) => {
+  state.pageInput.currentPage = val
+  onQuery()
+}
+
+const onOrgNodeClick = (node: OrgListOutput | null) => {
+  if (state.pageInput.filter) {
+    state.pageInput.filter.orgId = node?.id
+  }
+  onQuery()
+}
+
+const onRowClick = (row:UserDto) => {
+  // TODO: improvement typing when refactor table
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-expect-error
+  userTableRef.value!.toggleRowSelection(row, props.multiple ? undefined : true)
+}
+
+const onRowDbClick = () => {
+  if (!props.multiple) {
+    onSure()
+  }
+}
+
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  const selectionRows = userTableRef.value!.getSelectionRows() as UserDto[]
+  emits('sure', props.multiple ? selectionRows : selectionRows.length > 0 ? selectionRows[0] : null)
+}
+
+defineExpose({
+  open,
+  close,
+})
+</script>
+
+<style scoped lang="scss">
+:deep(.el-dialog__body) {
+  padding: 5px 10px;
+}
+</style>

+ 356 - 0
admin.ui.plus-master/src/views/example/application/roleManage/index.vue

@@ -0,0 +1,356 @@
+<template>
+  <my-layout>
+    <pane size="50" min-size="30" max-size="70">
+      <div class="my-flex-column w100 h100">
+        <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+          <el-form :inline="true" @submit.stop.prevent>
+            <el-form-item label="角色名称">
+              <el-input v-model="state.filter.roleName" placeholder="角色名称" @keyup.enter="onQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+              <el-dropdown v-auth="'api:admin:role:add'" style="margin-left: 12px">
+                <el-button type="primary"
+                  >新增<el-icon class="el-icon--right"><ele-ArrowDown /></el-icon
+                ></el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item @click="onAdd(1)">新增分组</el-dropdown-item>
+                    <el-dropdown-item @click="onAdd(2)">新增角色</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <el-card class="my-fill mt8" shadow="never">
+          <el-table
+            ref="roleTableRef"
+            v-loading="state.loading"
+            :data="state.roleTreeData"
+            row-key="id"
+            default-expand-all
+            :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+            highlight-current-row
+            style="width: 100%"
+            @current-change="onCurrentChange"
+          >
+            <el-table-column prop="name" label="角色名称" min-width="120" show-overflow-tooltip />
+            <el-table-column prop="sort" label="排序" width="80" align="center" show-overflow-tooltip />
+            <el-table-column label="操作" width="100" fixed="right" header-align="center" align="right">
+              <template #default="{ row }">
+                <el-button
+                  v-if="row.type === 1"
+                  v-auth="'api:admin:role:add'"
+                  icon="ele-Plus"
+                  size="small"
+                  text
+                  type="primary"
+                  @click="onAdd(2, row)"
+                ></el-button>
+                <my-dropdown-more icon-only v-auths="['api:admin:permission:assign', 'api:admin:role:update', 'api:admin:role:delete']">
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item v-if="row.type === 2 && auth('api:admin:permission:assign')" @click="onSetAppMenu(row)"
+                        >菜单权限</el-dropdown-item
+                      >
+                      <!-- <el-dropdown-item v-if="row.type === 2" @click="onSetRoleDataScope(row)">数据权限</el-dropdown-item> -->
+                      <el-dropdown-item v-if="auth('api:admin:role:update')" @click="onEdit(row)"
+                        >编辑{{ row.type === 1 ? '分组' : '角色' }}</el-dropdown-item
+                      >
+                      <el-dropdown-item v-if="auth('api:admin:role:delete')" @click="onDelete(row)"
+                        >删除{{ row.type === 1 ? '分组' : '角色' }}</el-dropdown-item
+                      >
+                    </el-dropdown-menu>
+                  </template>
+                </my-dropdown-more>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+      </div>
+    </pane>
+    <pane>
+      <div class="my-flex-column w100 h100">
+        <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+          <el-form :inline="true" @submit.stop.prevent>
+            <el-form-item label="姓名">
+              <el-input v-model="state.filter.name" placeholder="姓名" @keyup.enter="onGetRoleUserList" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="ele-Search" @click="onGetRoleUserList"> 查询 </el-button>
+              <el-button v-auth="'api:admin:role:add-role-user'" type="primary" icon="ele-Plus" @click="onAddUser"> 添加用户 </el-button>
+              <el-button v-auth="'api:admin:role:remove-role-user'" type="danger" icon="ele-Delete" @click="onRemoveUser"> 移除用户 </el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <el-card class="my-fill mt8" shadow="never">
+          <el-table
+            ref="userTableRef"
+            v-loading="state.userListLoading"
+            :data="state.userListData"
+            row-key="id"
+            style="width: 100%"
+            @row-click="onUserRowClick"
+          >
+            <el-table-column type="selection" width="55" />
+            <el-table-column prop="name" label="姓名" min-width="120" show-overflow-tooltip />
+            <el-table-column prop="mobile" label="手机号" min-width="120" show-overflow-tooltip />
+            <!-- <el-table-column prop="email" label="邮箱" min-width="120" show-overflow-tooltip /> -->
+          </el-table>
+        </el-card>
+      </div>
+    </pane>
+
+    <role-form ref="roleFormRef" :title="state.roleFormTitle" :role-tree-data="state.roleFormTreeData"></role-form>
+    <user-select
+      ref="userSelectRef"
+      :title="`添加【${state.roleName}】用户`"
+      multiple
+      :sure-loading="state.sureLoading"
+      @sure="onSureUser"
+    ></user-select>
+    <set-app-menu ref="setAppMenuRef"></set-app-menu>
+    <set-role-data-scope ref="setRoleDataScopeRef"></set-role-data-scope>
+  </my-layout>
+</template>
+
+<script lang="ts" setup name="admin/role">
+import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, nextTick, defineAsyncComponent } from 'vue'
+import { OauthRole,RoleGetListOutput, RoleType,UserDto } from '/@/api/admin/data-contracts'
+import { RoleApi } from '/@/api/admin/Role'
+import { PermissionApi } from '/@/api/admin/Permission'
+import { listToTree, filterTree } from '/@/utils/tree'
+import { ElTable } from 'element-plus'
+import { cloneDeep } from 'lodash-es'
+import eventBus from '/@/utils/mitt'
+import { auth } from '/@/utils/authFunction'
+import { Pane } from 'splitpanes'
+
+// 引入组件
+const RoleForm = defineAsyncComponent(() => import('./components/role-form.vue'))
+const SetAppMenu = defineAsyncComponent(() => import('./components/set-app-menu.vue'))
+const UserSelect = defineAsyncComponent(() => import('./components/user-select.vue'))
+const MyDropdownMore = defineAsyncComponent(() => import('/@/components/my-dropdown-more/index.vue'))
+const MyLayout = defineAsyncComponent(() => import('/@/components/my-layout/index.vue'))
+
+const { proxy } = getCurrentInstance() as any
+
+const roleTableRef = ref()
+const roleFormRef = ref()
+const userTableRef = ref<InstanceType<typeof ElTable>>()
+const userSelectRef = ref()
+const setAppMenuRef = ref()
+const setRoleDataScopeRef = ref()
+
+const state = reactive({
+  loading: false,
+  userListLoading: false,
+  sureLoading: false,
+  roleFormTitle: '',
+  filter: {
+    name: '',
+    roleName: '',
+  },
+  roleTreeData: [] as any,
+  roleFormTreeData: [] as any,
+  userListData: [] as UserDto[],
+  roleId: undefined as number | undefined,
+  roleName: '' as string | null | undefined,
+})
+
+onMounted(() => {
+  onQuery()
+  eventBus.off('refreshRole')
+  eventBus.on('refreshRole', async () => {
+    onQuery()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshRole')
+})
+
+const onQuery = async () => {
+  state.loading = true
+  const res = await new PermissionApi().getRoleInfo({name:state.filter.roleName}).catch(() => {
+    state.loading = false
+  })
+  res.data=res.data.map((item)=>{
+    item.parentId=Number(item.parentId)
+    if(item.parentId===0||item.parentId===null){
+      //item.parentId=Number('0')
+      item.type=1
+    }
+    // if(item.parentId===0){
+    //   //item.parentId=Number(item.parentId)
+    //   item.type=2
+    // }
+    // if(item.parentId!==0){
+    //   //item.parentId=Number(item.parentId)
+    //   item.type=3
+    // }
+    return item
+  })
+  if (res && res.data && res.data.length > 0) {
+    state.roleTreeData = filterTree(listToTree(cloneDeep(res.data)), state.filter.roleName)
+    state.roleFormTreeData = listToTree(cloneDeep(res.data).filter((a) => a.parentId === 0))
+    if (state.roleTreeData.length > 0 && state.roleTreeData[0].children?.length > 0) {
+      nextTick(() => {
+        roleTableRef.value!.setCurrentRow(state.roleTreeData[0].children[0])
+      })
+    }
+  } else {
+    state.roleTreeData = []
+    state.roleFormTreeData = []
+  }
+
+  state.loading = false
+}
+
+const onAdd = (type: RoleType, row: OauthRole | undefined = undefined) => {
+  switch (type) {
+    case 1:
+      state.roleFormTitle = '新增分组'
+      roleFormRef.value.open({ type: 1 })
+      break
+    case 2:
+      state.roleFormTitle = '新增角色'
+      roleFormRef.value.open({ type: 2, parentId: row?.id, dataScope: 1 })
+      break
+  }
+}
+
+const onEdit = (row: OauthRole) => {
+  switch (row.type) {
+    case 1:
+      state.roleFormTitle = '编辑分组'
+      break
+    case 2:
+      state.roleFormTitle = '编辑角色'
+      break
+  }
+  roleFormRef.value.open(row)
+}
+
+const onDelete = (row: OauthRole) => {
+  proxy.$modal
+    .confirmDelete(`确定要删除角色【${row.name}】?`)
+    .then(async () => {
+      await new PermissionApi().roleDelete({ id: row.id }, { loading: true })
+      onQuery()
+    })
+    .catch(() => {})
+}
+
+const onGetRoleUserList = async () => {
+  state.userListLoading = true
+  const res = await new RoleApi().getApplyRoseUserInfo({ roleid: state.roleId, name: state.filter.name }).catch(() => {
+    state.userListLoading = false
+  })
+  state.userListLoading = false
+  if (res?.success) {
+    if (res.data && res.data.length > 0) {
+      state.userListData = res.data
+    } else {
+      state.userListData = []
+    }
+  }
+}
+
+const onCurrentChange = (currentRow: RoleGetListOutput, oldCurrentRow: RoleGetListOutput) => {
+  if (!currentRow) {
+    return
+  }
+
+  if (currentRow?.id !== oldCurrentRow?.id && (oldCurrentRow?.id as number) > 0) {
+    if ((currentRow?.parentId as number) === 0) {
+      roleTableRef.value!.setCurrentRow(oldCurrentRow)
+    }
+  } else {
+    if ((currentRow?.parentId as number) === 0) {
+      roleTableRef.value!.setCurrentRow()
+    }
+  }
+
+  if ((currentRow?.parentId as number) !== 0 && (oldCurrentRow?.parentId as number) !== 0 && (currentRow?.id as number) > 0) {
+    state.roleId = currentRow.id
+    state.roleName = currentRow.name
+    onGetRoleUserList()
+  }
+}
+
+const onUserRowClick = (row: UserDto) => {
+  // TODO: improvement typing when refactor table
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-expect-error
+  userTableRef.value!.toggleRowSelection(row, undefined)
+}
+
+const onAddUser = () => {
+  if (!((state.roleId as number) > 0)) {
+    proxy.$modal.msgWarning('请选择角色')
+    return
+  }
+  userSelectRef.value.open({ roleId: state.roleId })
+}
+
+const onRemoveUser = () => {
+  if (!((state.roleId as number) > 0)) {
+    proxy.$modal.msgWarning('请选择角色')
+    return
+  }
+
+  const selectionRows = userTableRef.value!.getSelectionRows() as UserDto[]
+
+  if (!((selectionRows.length as number) > 0)) {
+    proxy.$modal.msgWarning('请选择用户')
+    return
+  }
+
+  proxy.$modal
+    .confirm(`确定要移除吗?`)
+    .then(async () => {
+      const userIds = selectionRows?.map((a) => ({id:a.id,name:a.name,mobile:a.mobile}))
+      await new RoleApi().deleteApplyRoseUser(userIds,{roleid:state.roleId} ,{ showSuccessMessage: true })
+      onGetRoleUserList()
+    })
+    .catch(() => {})
+}
+
+const onSureUser = async (users: UserDto[]) => {
+  if (!(users?.length > 0)) {
+    userSelectRef.value.close()
+    return
+  }
+
+  state.sureLoading = true
+  const userIds = users?.map((a) => ({id:a.id,name:a.name,mobile:a.mobile}))
+  await new RoleApi().addApplyRoseUser(userIds,{roleid:state.roleId} ,{ showSuccessMessage: true }).catch(() => {
+    state.sureLoading = false
+  })
+  state.sureLoading = false
+  userSelectRef.value.close()
+  onGetRoleUserList()
+}
+
+const onSetAppMenu = (role: RoleGetListOutput) => {
+  if (!((role?.id as number) > 0)) {
+    proxy.$modal.msgWarning('请选择角色')
+    return
+  }
+  setAppMenuRef.value.open(role)
+}
+
+const onSetRoleDataScope = (role: RoleGetListOutput) => {
+  if (!((role?.id as number) > 0)) {
+    proxy.$modal.msgWarning('请选择角色')
+    return
+  }
+  setRoleDataScopeRef.value.open(role)
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 160 - 0
admin.ui.plus-master/src/views/example/application/viewManage/components/view-form.vue

@@ -0,0 +1,160 @@
+<template>
+  <div>
+    <el-dialog
+      v-model="state.showDialog"
+      destroy-on-close
+      :title="title"
+      draggable
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      width="600px"
+    >
+      <el-form :model="form" ref="formRef" size="default" label-width="80px">
+        <el-row :gutter="35">
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="应用" prop="label">
+              <el-input v-model="state.app" clearable disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="上级视图">
+              <el-tree-select
+                v-model="form.parentId"
+                :data="viewTreeData"
+                node-key="id"
+                check-strictly
+                default-expand-all
+                render-after-expand
+                fit-input-width
+                clearable
+                class="w100"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图名称" prop="label" :rules="[{ required: true, message: '请输入视图名称', trigger: ['blur', 'change'] }]">
+              <el-input v-model="form.label" clearable />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图命名" prop="path">
+              <el-input v-model="form.name" clearable />
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图地址" prop="path">
+              <el-input v-model="form.path" clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="10" :md="10" :lg="10" :xl="10">
+            <el-form-item label="排序">
+              <el-input-number v-model="form.sort" />
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :xs="24" :sm="7" :md="7" :lg="7" :xl="7">
+            <el-form-item label="缓存">
+              <el-switch v-model="form.cache" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="7" :md="7" :lg="7" :xl="7">
+            <el-form-item label="启用">
+              <el-switch v-model="form.enabled" />
+            </el-form-item>
+          </el-col> -->
+          <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="视图描述" prop="description">
+              <el-input v-model="form.description" clearable type="textarea" />
+            </el-form-item>
+          </el-col> -->
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="onCancel" size="default">取 消</el-button>
+          <el-button type="primary" @click="onSure" size="default" :loading="state.sureLoading">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/view/form">
+import { reactive, toRefs, ref, PropType } from 'vue'
+import { OauthView,OauthViewDto } from '/@/api/admin/data-contracts'
+import { ViewApi } from '/@/api/admin/View'
+import { PermissionApi } from '/@/api/admin/Permission'
+import eventBus from '/@/utils/mitt'
+
+defineProps({
+  title: {
+    type: String,
+    default: '',
+  },
+  viewTreeData: {
+    type: Array as PropType<OauthView[]>,
+    default: () => [],
+  },
+})
+
+const formRef = ref()
+const state = reactive({
+  showDialog: false,
+  sureLoading: false,
+  form: {} as OauthViewDto,
+  app:''
+})
+const { form } = toRefs(state)
+
+// 打开对话框
+const open = async (app:any,row: any = {}) => {
+  // if (row.id > 0) {
+  //   const res = await new PermissionApi().getViewInfo({ id: row.id }, { loading: true })
+
+  //   if (res?.success) {
+  //     let formData = res.data as OauthViewDto
+  //     state.form = formData
+  //   }
+  // } else {
+  //   state.form = {} as OauthViewDto
+  // }
+  state.app=app
+  state.form=row
+  state.showDialog = true
+}
+// 取消
+const onCancel = () => {
+  state.showDialog = false
+}
+
+// 确定
+const onSure = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return
+
+    state.sureLoading = true
+    let res = {} as any
+    const appData=await new PermissionApi().getApplyInfo({name:state.app})
+    state.form.appID=appData.data[0].id
+    if (state.form.id != undefined && state.form.id > 0) {
+      res = await new PermissionApi().addView(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    } else {
+      res = await new PermissionApi().addView(state.form, { showSuccessMessage: true }).catch(() => {
+        state.sureLoading = false
+      })
+    }
+
+    state.sureLoading = false
+
+    if (res?.success) {
+      eventBus.emit('refreshView')
+      state.showDialog = false
+    }
+  })
+}
+
+defineExpose({
+  open,
+})
+</script>

+ 139 - 0
admin.ui.plus-master/src/views/example/application/viewManage/index.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class="my-layout">
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <el-form :model="state.filter" :inline="true" @submit.stop.prevent>
+        <el-form-item label="应用">
+          <el-select v-model="state.filter.app" placeholder="请选择应用" style="width: 200px;">
+            <el-option v-for="(value, key) in state.app" :key="key" :label="value.name"  :value="value.name" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="视图名称">
+          <el-input v-model="state.filter.name" placeholder="视图名称" @keyup.enter="onQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+          <el-button v-auth="'api:admin:view:add'" type="primary" icon="ele-Plus" @click="onAdd"> 新增 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="my-fill mt8" shadow="never">
+      <el-table
+        :data="state.viewTreeData"
+        style="width: 100%"
+        v-loading="state.loading"
+        row-key="id"
+        default-expand-all
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+      >
+        <el-table-column prop="label" label="视图名称" min-width="120" show-overflow-tooltip />
+        <!-- <el-table-column prop="name" label="视图命名" min-width="120" show-overflow-tooltip /> -->
+        <el-table-column prop="path" label="视图地址" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="sort" label="排序" width="80" align="center" show-overflow-tooltip />
+        <!-- <el-table-column prop="description" label="视图描述" min-width="120" show-overflow-tooltip /> -->
+        <!-- <el-table-column label="状态" width="80" align="center" show-overflow-tooltip>
+          <template #default="{ row }">
+            <el-tag type="success" v-if="row.enabled">启用</el-tag>
+            <el-tag type="danger" v-else>禁用</el-tag>
+          </template>
+        </el-table-column> -->
+        <el-table-column label="操作" width="160" fixed="right" header-align="center" align="center">
+          <template #default="{ row }">
+            <el-button v-auth="'api:admin:view:update'" icon="ele-EditPen" size="small" text type="primary" @click="onEdit(row)">编辑</el-button>
+            <el-button v-auth="'api:admin:view:delete'" icon="ele-Delete" size="small" text type="danger" @click="onDelete(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <view-form ref="viewFormRef" :title="state.viewFormTitle" :view-tree-data="state.viewTreeData"></view-form>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/view">
+import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, defineAsyncComponent } from 'vue'
+import { OauthView,OauthApply } from '/@/api/admin/data-contracts'
+import { ViewApi } from '/@/api/admin/View'
+import { listToTree, filterTree } from '/@/utils/tree'
+import { cloneDeep } from 'lodash-es'
+import { PermissionApi } from '/@/api/admin/Permission'
+import eventBus from '/@/utils/mitt'
+
+// 引入组件
+const ViewForm = defineAsyncComponent(() => import('./components/view-form.vue'))
+
+const viewFormRef = ref()
+const { proxy } = getCurrentInstance() as any
+
+const state = reactive({
+  loading: false,
+  viewFormTitle: '',
+  filter: {
+    name: '',
+    app:'1'
+  },
+  viewTreeData: [] as Array<OauthView>,
+  formViewTreeData: [] as Array<OauthView>,
+  app:[] as Array<OauthApply>
+})
+
+onMounted(() => {
+  onQuery()
+  eventBus.off('refreshView')
+  eventBus.on('refreshView', async () => {
+    onQuery()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshView')
+})
+
+const onQuery = async () => {
+  state.loading = true
+  const appForm=await new PermissionApi().getApplyInfo({name:state.filter.app})
+  const appID=appForm.data[0].id
+  const appData=await new PermissionApi().getApplyInfo({id:0})
+  state.app=appData.data
+  const res = await new PermissionApi().getViewInfo({appID:appID,label:state.filter.name}).catch(() => {
+    state.loading = false
+  })
+  res.data=res.data.map((item)=>{
+    item.parentId=Number(item.parentId)
+    return item
+  })
+  if (res && res.data && res.data.length > 0) {
+    state.viewTreeData = filterTree(listToTree(cloneDeep(res.data)), state.filter.name, {
+      filterWhere: (item: any, keyword: string) => {
+        return item.label?.toLocaleLowerCase().indexOf(keyword) > -1 || item.path?.toLocaleLowerCase().indexOf(keyword) > -1
+      },
+    })
+  } else {
+    state.viewTreeData = []
+    state.formViewTreeData = []
+  }
+  state.loading = false
+}
+
+const onAdd = () => {
+  state.viewFormTitle = '新增视图'
+  viewFormRef.value.open(state.filter.app)
+}
+
+const onEdit = (row: OauthView) => {
+  state.viewFormTitle = '编辑视图'
+  viewFormRef.value.open(state.filter.app,row)
+}
+
+const onDelete = (row: OauthView) => {
+  proxy.$modal
+    .confirmDelete(`确定要删除视图【${row.label}】?`)
+    .then(async () => {
+      await new PermissionApi().viewDelete({ id: row.id }, { loading: true })
+      onQuery()
+    })
+    .catch(() => {})
+}
+</script>
+
+<style scoped lang="scss"></style>

+ 636 - 0
admin.ui.plus-master/src/views/example/codeGeneration/index.vue

@@ -0,0 +1,636 @@
+<template>
+  <div class="layout">
+    <h1 style="margin-top: 10px;margin-bottom: 10px;">页面配置</h1>
+    <div style="color: #505050;margin-bottom: 20px;">将表单内容进行分步可以提高用户处理的专注度,降低页面的复杂性</div>
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="接口地址" style="width: 60%;">
+            <el-input v-model="state.filter.name" placeholder="请输入接口地址" @keyup.enter="onQuery" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="查询页面接口来源" style="width: 70%;">
+            <el-select v-model="state.filter.api"  placeholder="请选择页面接口来源" @change="onChange(state.filter.api)">
+              <el-option v-for="(value, key) in state.api" :key="key" :label="value.api+' '+value.summary"  :value="value.api" />
+            </el-select>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="查询按钮" style="width: 100%;"></el-form-item>
+          <el-form-item label="">
+            <el-row :gutter="70">
+              <el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" v-for="(v, k) in state.selectBtn" :key="k">
+                <span style="margin-right: 10px;">{{ v.name }}</span>
+                <el-switch v-model="v.value" @change="change(k)"></el-switch>
+              </el-col>
+            </el-row>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="查询条件配置" style="width: 100%;"></el-form-item>
+          <el-form-item label="">
+            <el-row :gutter="100">
+              <el-col :span="100" :xl="4" v-for="(v, k) in state.selectVal" :key="k">
+                <span style="margin-right: 10px;">{{ v.description }}</span>
+                <el-switch v-model="v.value" @change="change(k)"></el-switch>
+              </el-col>
+            </el-row>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="列表操作栏" style="width: 100%;"></el-form-item>
+          <el-form-item label="">
+            <el-row :gutter="100">
+              <el-col :span="100" v-for="(v, k) in state.tableBtn" :key="k">
+                <span style="margin-right: 10px;">{{ v.name }}</span>
+                <el-switch v-model="v.value" @change="change(k)"></el-switch>
+              </el-col>
+            </el-row>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div>
+        <el-form :inline="true" @submit.stop.prevent>
+          <el-form-item label="列表元素配置" style="width: 100%;"></el-form-item>
+          <el-form-item label="">
+            <el-row :gutter="100">
+              <el-col :span="100" v-for="(v, k) in state.tableVal" :key="k">
+                <span style="margin-right: 10px;">{{ v.description }}</span>
+                <el-switch v-model="v.value" @change="change(k)"></el-switch>
+              </el-col>
+            </el-row>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <div style="display: flex;justify-content: center;align-items: center;">
+      <el-button style="margin-top: 20px;width: 264px;height: 42px;" type="primary" @click="onsubmit()">生成页面</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup name="admin/code">
+import { ref,reactive, onMounted, onBeforeMount } from 'vue'
+import eventBus from '/@/utils/mitt'
+import { ElMessage } from 'element-plus'
+
+const state = reactive({
+  loading: false,
+  orgFormTitle: '',
+  filter: {
+    name: 'http://dev.hsfuel.com:8070/app/swagger/app/swagger.json',
+    api:''
+  },
+  api:[],
+  selectBtn:[{value:false,name:'查询',method:'onQuery'},
+    {value:false,name:'添加',method:'onAdd'},
+    {value:false,name:'批量删除',method:'ondelete'},
+    {value:false,name:'重置',method:'onReset'},
+    {value:false,name:'上传',method:'onUpload'},
+    {value:false,name:'导出',method:'onExport'},
+    {value:false,name:'批量导入',method:'onBatImport'},
+    {value:false,name:'批量导出',method:'onBatExport'},
+    {value:false,name:'批量审核',method:'onBatReview'}],
+  selectVal:[],
+  tableBtn:[{value:false,name:'编辑',method:'onDateUpdate'},
+    {value:false,name:'详情',method:'onDataDetail'},
+    {value:false,name:'删除',method:'onDataDelete'}],
+  tableVal:[],
+  isPage:false
+})
+const dataJson=ref('')
+onMounted(() => {
+  onQuery()
+  eventBus.off('refreshOrg')
+  eventBus.on('refreshOrg', () => {
+    onQuery()
+  })
+})
+
+onBeforeMount(() => {
+  eventBus.off('refreshOrg')
+})
+const change=(k)=>{
+  // console.log(k)
+  // console.log(state.selectVal[k].value,state.selectVal[k].description)
+}
+//解析页面接口数据
+const onQuery = async () => {
+  fetch(state.filter.name)
+    .then(response=>response.json())
+    .then(swaggerJson=>{
+      //console.log(swaggerJson)
+      dataJson.value=swaggerJson
+      const {paths} =dataJson.value
+      //console.log(paths)
+      for(const path in paths){
+        if('get' in paths[path]){
+          let api:any=path
+          let summary:any=paths[path].get.summary?paths[path].get.summary:''
+          let methods:any='GET'
+          let isQuery:any=false
+          let isBody:any=false
+          if('parameters' in paths[path].get){
+            isQuery=true
+          }
+          if('requestBody' in paths[path].get){
+            isBody=true
+          }
+          state.api.push({api:api,summary:summary,methods:methods,isQuery:isQuery,isBody:isBody})
+          //console.log(path)
+          //console.log(paths[path].get.responses['200'].content['application/json'].schema['$ref'])
+        }
+        if('post' in paths[path]){
+          let summary:any=paths[path].post.summary?paths[path].post.summary:''
+          if(summary===''||summary.includes('查询')||summary.includes('获取')){
+            let api:any=path
+            let methods:any='POST'
+            let isQuery:any=false
+            let isBody:any=false
+            if('parameters' in paths[path].post){
+              isQuery=true
+            }
+            if('requestBody' in paths[path].post){
+              isBody=true
+            }
+            state.api.push({api:api,summary:summary,methods:methods,isQuery:isQuery,isBody:isBody})
+            //console.log(paths[path].post.responses['200'].content['application/json'].schema['$ref'])
+            //console.log(paths[path].post.requestBody)
+          }
+          //console.log(path)
+          //console.log(paths[path])
+        }
+      }
+      //console.log(state.api)
+    })
+    .catch(error=>{
+      console.log('Error fetch Swagger Json :',error)
+    })
+}
+//解析查询页面查询条件及列表元素
+const onChange=(api)=>{
+  state.selectVal=[]
+  state.tableVal=[]
+  let data=dataJson.value.paths[api]
+  const tableData=dataJson.value.components.schemas
+  //console.log(data)
+  if('get' in data){
+    data=data.get
+  }else{
+    data=data.post
+    //console.log(data)
+  }
+  if('parameters' in data){
+    const parameters=data['parameters']
+    //console.log(parameters)
+    for(const val in parameters){
+      if(!parameters[val].name.includes('Page')&&!parameters[val].name.includes('DynamicFilter')){
+        let value:any=false
+        let name:any=parameters[val].name
+        let description:any=(parameters[val].description&&!parameters[val].description.includes(1)&&!(parameters[val].description===''))?parameters[val].description:parameters[val].name
+        let type:any=parameters[val].schema.type
+        let isDate:any=parameters[val].schema.format==='date-time'?true:false
+        if(parameters[val].name.includes('.')){
+          let s=parameters[val].name.split('.')
+          let p=s[1].trim()
+          name=p
+          description=(parameters[val].description&&!parameters[val].description.includes(1)&&!(parameters[val].description===''))?parameters[val].description:p
+        }
+        state.selectVal.push({value:value,name:name,description:description,type:type,isDate:isDate})
+      }
+    }
+  }
+  if('requestBody' in data){
+    const requestBody=data['requestBody']['content']['application/json'].schema['$ref']
+    let s=requestBody.split('/')
+    let p=s[3].trim()
+    let properties=tableData[p]['properties']
+    if('dynamicFilter' in properties){
+      properties=properties.filter['$ref']
+      s=properties.split('/')
+      p=s[3].trim()
+      properties=tableData[p]['properties']
+    }
+    //console.log(properties)
+    for(const val in properties){
+      let value:any=false
+      let name:any=val
+      let description:any=(properties[val].description&&!properties[val].description.includes(1)&&!(properties[val].description===''))?properties[val].description:val
+      let type:any=properties[val].type
+      let isDate:any=false
+      if(properties[val].format==='date-time'||val.includes('Time')||val.includes('Date')){
+        isDate=true
+      }
+      //console.log(value,name,description,type,isDate)
+      state.selectVal.push({value:value,name:name,description:description,type:type,isDate:isDate})
+    }
+  }
+  let form=data.responses['200'].content['application/json'].schema['$ref']
+  let f=form.split('/')
+  let r=f[3].trim()
+  let formData=tableData[r].properties.data
+  let dataName:any=r
+  let list:any=''
+  if(!('type' in formData)||formData.type==='array'){
+    if(!('type' in formData)||'$ref' in formData.items){
+      if(!('type' in formData)){
+        formData=formData['$ref']
+      }else{
+        formData=formData.items['$ref']
+      }
+      f=formData.split('/')
+      r=f[3].trim()
+      list=r
+      formData=tableData[r]['properties']
+      let isList:any=false
+      let isArray:any=true
+      if('total' in formData){
+        formData=formData.list.items['$ref']
+        f=formData.split('/')
+        r=f[3].trim()
+        formData=tableData[r]['properties']
+        isList=true
+        state.isPage=true
+      }
+      for(const val in formData){
+        let value:any=false
+        let name:any=val
+        let description:any=(formData[val].description&&!formData[val].description.includes(1)&&!(formData[val].description===''))?formData[val].description:val
+        let type:any=formData[val].type
+        //console.log(value,name,description,type)
+        state.tableVal.push({value:value,name:name,description:description,type:type,belong:r,isList:isList,isArray:isArray,dataName:dataName,list:list})
+      }
+    }else{
+      let value:any=false
+      let isList:any=false
+      let isArray:any=true
+      let name:any=r
+      let description:any=(formData.description&&!formData.description.includes(1)&&!(formData.description===''))?formData.description:r
+      let type:any=formData.type
+      //console.log(value,name,description,type)
+      state.tableVal.push({value:value,name:name,description:description,type:type,belong:r,isList:isList,isArray:isArray,dataName:dataName,list:list})
+    }
+  }else{
+    let value:any=false
+    let name:any=r
+    let isList:any=false
+    let isArray:any=false
+    let description:any=(formData.description&&!formData.description.includes(1)&&!(formData.description===''))?formData.description:r
+    let type:any=formData.type
+    //console.log(value,name,description,type)
+    state.tableVal.push({value:value,name:name,description:description,type:type,belong:r,isList:isList,isArray:isArray,dataName:dataName,list:list})
+  }
+}
+//生成查询页面主要代码文件
+const onsubmit=()=>{
+  let api=''
+  if(state.filter.api===''){
+    ElMessage.error('请选择查询页面接口来源')
+  }else{
+    api=state.api.filter(item=>item.api===state.filter.api)
+  }
+  let selBtn=state.selectBtn.filter(item=>item.value===true)
+  let selVal=state.selectVal.filter(item=>item.value===true)
+  let tabBtn=state.tableBtn.filter(item=>item.value===true)
+  let tabVal=state.tableVal.filter(item=>item.value===true)
+  //console.log(tabVal)
+  let apiCode=`import { AxiosResponse } from 'axios'
+  import { ContentType, HttpClient, RequestParams } from './http-client'
+  export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
+    /**
+   * No description
+   *
+   * @tags
+   * @name GetList
+   * @summary 查询列表
+   * @request ${api[0].methods}:'${api[0].api}'
+   * @secure
+   */\n`
+  if(api[0].methods==='GET'){
+    apiCode=apiCode+`getList = (query:any ,params: RequestParams = {}) : any  =>
+      this.request<AxiosResponse,any>({
+        path:'${api[0].api}',
+        method: 'GET',
+        query:query,`
+  }else{
+    if(api[0].isQuery===true&&api[0].isBody===true){
+      apiCode=apiCode+`getList = (data:any ,query:any ,params: RequestParams = {}) : any  =>
+      this.request<AxiosResponse,any>({
+        path:'${api[0].api}',
+        method: 'POST',
+        body:data,
+        query:query,
+        type: ContentType.Json,`
+    }else if(api[0].isQuery===false&&api[0].isBody===true){
+      apiCode=apiCode+`getList = (data:any ,params: RequestParams = {}) : any  =>
+      this.request<AxiosResponse,any>({
+        path:'${api[0].api}',
+        method: 'POST',
+        body:data,
+        type: ContentType.Json,`
+    }else{
+      apiCode=apiCode+`getList = (query:any ,params: RequestParams = {}) : any  =>
+      this.request<AxiosResponse,any>({
+        path:'${api[0].api}',
+        method: 'POST',
+        query:query,
+        type: ContentType.Json,`
+    }
+  }
+  apiCode=apiCode+`
+        secure: true,
+        format: 'json',
+        ...params
+      })
+    }`
+  //console.log(apiCode)
+  let dataCode=`/** 查询信息输出 */
+  export interface ${state.tableVal[0].dataName}{
+  /** 是否成功标记 */
+  success?: boolean
+  /** 编码 */
+  code?: string | null
+  /** 消息 */
+  msg?: string | null
+  /** 数据 */\n`
+  if(state.tableVal[0].isArray===false&&state.tableVal[0].isList===false){
+    dataCode=dataCode+`  data?:${state.tableVal[0].type} | null\n}`
+    //console.log(dataCode)
+  }else if(state.tableVal[0].isArray===true&&state.tableVal[0].isList===false){
+    if(state.tableVal[0].list===''){
+      dataCode=dataCode+` data?:${state.tableVal[0].list}[] | null\n}`
+    }else{
+      dataCode=dataCode+` data?:${state.tableVal[0].list}[] | null\n}
+      export interface ${state.tableVal[0].list}{\n`
+      for(let i=0;i<state.tableVal.length;i++){
+        dataCode=dataCode+`   /** ${state.tableVal[i].description} */
+        ${state.tableVal[i].name}?: ${state.tableVal[i].type}\n`
+      }
+      dataCode=dataCode+`\n}`
+    }
+    //console.log(dataCode)
+  }else{
+    dataCode=dataCode+` data?:${state.tableVal[0].list}[] | null\n}
+    export interface ${state.tableVal[0].list}{
+      /**
+      * 数据总数
+      * @format int64
+      */
+      total?: number
+      /** 数据 */
+      list?: ${state.tableVal[0].belong}[] | null
+    }
+    export interface ${state.tableVal[0].belong}{\n`
+    for(let i=0;i<state.tableVal.length;i++){
+      dataCode=dataCode+`   /** ${state.tableVal[i].description} */
+      ${state.tableVal[i].name}?: ${state.tableVal[i].type}\n`
+    }
+    dataCode=dataCode+`\n}`
+    //console.log(dataCode)
+  }
+  if(state.isPage===true){
+    dataCode=dataCode+`\nexport interface pageInput {
+      /**当前页数 */
+      CurrentPage: number | any
+      /**展示页数 */
+      PageSize: number | any
+    }`
+  }
+  let selection=false
+  let indexCode=`\n<template>
+  <div class="layout-pd">
+    <el-row>`
+  if(selBtn.length>0||selVal.length>0){
+    indexCode=indexCode+`\n<!--操作-->
+      <el-col :xs="24" >
+        <el-card class="mt8"  shadow="hover" >`
+    if(selVal.length>0){
+      indexCode=indexCode+`\n<el-form :model="state.filter" :inline="true" @submit.stop.prevent>
+            <el-form-item prop="name" style="width: 100%">`
+      for(let i=0;i<selVal.length;i++){
+        if(selVal[i].type==='interger'){
+          indexCode=indexCode+`\n<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="${selVal[i].description}">
+                  <el-input-number v-model="state.filter.${selVal[i].name}" />
+                </el-form-item>
+              </el-col>`
+        }else if(selVal[i].isDate===true){
+          indexCode=indexCode+`\n<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+            <el-form-item label="选择时间">
+                  <el-date-picker
+                    v-model="state.filter.${selVal[i].name}"
+                    type="datetimerange"
+                    value-format="YYYY-MM-DD HH:mm:ss"
+                    range-separator="To"
+                    start-placeholder="Start date"
+                    end-placeholder="End date"
+                  />
+                </el-form-item>
+              </el-col>`
+        }else{
+          indexCode=indexCode+`\n<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
+                <el-form-item label="${selVal[i].description}">
+                  <el-input v-model="state.filter.${selVal[i].name}" placeholder="单行输入" clearable></el-input>
+                </el-form-item>
+              </el-col>`
+        }
+      }
+      indexCode=indexCode+`\n</el-form-item>
+          </el-form>`
+    }
+    if(selBtn.length>0){
+      indexCode=indexCode+`\n<div class="my-flex my-flex-start" >`
+      for(let i=0;i<selBtn.length;i++){
+        if(selBtn[i].name.includes('批量')){
+          selection=true
+        }
+        indexCode=indexCode+`\n<el-button  type="primary" icon="ele-CirclePlus" @click="${selBtn[i].method}"> ${selBtn[i].name} </el-button>`
+      }
+      indexCode=indexCode+`\n</div>`
+    }
+    indexCode=indexCode+`\n</el-card>
+      </el-col>`
+  }
+  if(tabVal.length>0){
+    indexCode=indexCode+`\n<!--表格-->
+      <el-col  :xs="24" >
+        <el-card style="height: 70vh" class="my-fill mt8" shadow="hover">`
+    if(selection){
+      indexCode=indexCode+`\n<el-table-column type="selection" width="50"></el-table-column>`
+    }
+    indexCode=indexCode+`\n<el-table v-loading="state.loading" stripe :data="state.tableModel" row-key="id" style="width: 100%">
+        <el-table-column v-for="column in state.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label"  >
+        </el-table-column>`
+    if(tabBtn.length>0){
+      indexCode=indexCode+` \n<el-table-column label="操作"  fixed="right" header-align="center" align="center" class="right-operation" width="140">
+        <template #default="{ row }" >`
+      for(let i=0;i<tabBtn.length;i++){
+        indexCode=indexCode+`\n<el-link
+                  class="my-el-link mr12 ml12"
+                  type="primary"
+                  icon="ele-Upload"
+                  size="small"
+                  @click="${tabBtn[i].method}(row)"
+                  :underline="false"
+                  target="_blank"
+                >${tabBtn[i].name}</el-link>`
+      }
+      indexCode=indexCode+`\n</template>
+            </el-table-column>`
+    }
+    indexCode=indexCode+`\n</el-table>`
+    if(state.isPage){
+      indexCode=indexCode+`\n<div class="my-flex my-flex-end" style="margin-top: 20px">
+            <el-pagination
+              v-model:currentPage="state.pageInput.CurrentPage"
+              v-model:page-size="state.pageInput.PageSize"
+              :total="state.total"
+              :page-sizes="[10, 20, 50, 100]"
+              small
+              background
+              @size-change="onSizeChange"
+              @current-change="onCurrentChange"
+              layout="total, sizes, prev, pager, next, jumper"
+            />
+          </div>`
+    }
+    indexCode=indexCode+`\n</el-card>
+      </el-col>`
+  }
+  indexCode=indexCode+`\n</el-row>
+    </div>
+  </template>
+  <script setup lang="ts">
+  import {onBeforeMount, onMounted, reactive, ref, watch} from "vue";
+  import eventBus from "/@/utils/mitt";
+  import {Api} from "/@/api/code/api";`
+  if(state.isPage&&tabVal.length>0){
+    indexCode=indexCode+`\nimport { pageInput,${tabVal[0].belong} } from "/@/api/code/dto";`
+  }else if(tabVal.length>0){
+    indexCode=indexCode+`\nimport { ${tabVal[0].belong} } from "/@/api/code/dto";`
+  }
+  indexCode=indexCode+`\n/**数据对象*/
+  const state = reactive({
+    /**加载显示 */
+    loading: false,
+    /**条件查询模块 */
+      filter: {`
+    if(selVal.length>0){
+      for(let i=0;i<selVal.length;i++){
+        indexCode=indexCode+`\n/**${selVal[i].description} */
+        ${selVal[i].name}: "",`
+      }
+    }
+  indexCode=indexCode+`},
+  /**表格信息 */`
+  if(tabVal.length>0){
+    indexCode=indexCode+`\ntableModel: [] as ${tabVal[0].belong},
+    /**动态表头 */
+    dynamicColumns: [`
+    for(let i=0;i<tabVal.length;i++){
+      indexCode=indexCode+`\n{ prop: '${tabVal[i].name}', label: '${tabVal[i].description}' },`
+    }
+    indexCode =indexCode+`],`
+  }else{
+    indexCode=indexCode+`\ntableModel: [],
+    /**动态表头 */
+    dynamicColumns: [],`
+  }
+  if(state.isPage){
+    indexCode=indexCode+`\n/**分页标识 */
+    pageInput:{
+      CurrentPage: 1,
+      PageSize: 10,
+    } as pageInput,
+    /**分页总数 */
+    total: 0,`
+  }
+  indexCode=indexCode+`\n})
+  onMounted(() => {
+    init()
+    eventBus.off('refreshView')
+    eventBus.on('refreshView', async () => {
+      await init()
+    })
+    console.log()
+  })
+  onBeforeMount(() => {
+    eventBus.off('refreshView')
+  })
+  /**
+  * 监听变换
+  */
+  watch(() => {})`
+  let isSel=false
+  if(selBtn.length>0){
+    for(let i=0;i<selBtn.length;i++){
+      if(selBtn[i].name==='查询'){
+        isSel=true
+        indexCode=indexCode+`\n/**条件查询 */
+          const onQuery = () => {
+          init()
+        }
+        /**初始化 */
+        const init = async () => {
+          state.loading = true`
+          if(state.isPage){
+            indexCode=indexCode+`\nconst res:any = await new Api().getList({...state.pageInput, Filter:state.filter})
+            state.total = res?.data?.total ?? 0`
+          }else{
+            indexCode=indexCode+`\nconst res:any = await new Api().getList({...state.filter})`
+          }
+          indexCode=indexCode+`\nstate.tableModel = res?.data?.list ?? []
+          state.loading = false
+        }`
+      }else{
+        indexCode=indexCode+`\n/**${selBtn[i].name} */
+        const ${selBtn[i].method}=()=>{}`
+      }
+    }
+  }
+  if(!isSel){
+    indexCode=indexCode+`\n/**初始化 */
+      const init = async () => {
+        state.loading = true
+        state.loading = false
+      }`
+  }
+  if(tabBtn.length>0){
+    for(let i=0;i<tabBtn.length;i++){
+      indexCode=indexCode+`\n/**${tabBtn[i].name} */
+      const ${tabBtn[i].method}=(row)=>{}`
+    }
+  }
+  indexCode=indexCode+`\n</`+`script>`+`\n<style scoped lang="scss">
+  </style>`
+  //console.log(indexCode)
+}
+</script>
+
+<style scoped lang="scss">
+.layout {
+  position: absolute;
+  left: 0;
+  top: 0;
+  overflow: hidden;
+  padding: 0px 8px 8px 8px;
+  display: flex;
+  flex-direction: column;
+}
+</style>