Browse Source

代码生成

hyy 5 months ago
parent
commit
9502a7c980
78 changed files with 2748 additions and 107 deletions
  1. 47 0
      src/api/museums/museumsdocument/index.ts
  2. 44 0
      src/api/museums/photogroup/index.ts
  3. 42 0
      src/api/museums/photos/index.ts
  4. 68 0
      src/api/museums/specimeninfo/index.ts
  5. 56 0
      src/api/museums/specimenoutbound/index.ts
  6. 4 1
      src/utils/dict.ts
  7. 0 1
      src/views/bpm/category/index.vue
  8. 0 1
      src/views/bpm/definition/index.vue
  9. 0 1
      src/views/bpm/form/index.vue
  10. 0 1
      src/views/bpm/group/index.vue
  11. 0 7
      src/views/bpm/model/index.vue
  12. 0 1
      src/views/bpm/oa/leave/index.vue
  13. 0 2
      src/views/bpm/processExpression/index.vue
  14. 0 1
      src/views/bpm/processInstance/create/index.vue
  15. 0 1
      src/views/bpm/processInstance/index.vue
  16. 0 1
      src/views/bpm/processInstance/manager/index.vue
  17. 0 1
      src/views/bpm/processListener/index.vue
  18. 0 4
      src/views/bpm/task/copy/index.vue
  19. 0 7
      src/views/bpm/task/done/index.vue
  20. 0 1
      src/views/bpm/task/manager/index.vue
  21. 0 7
      src/views/bpm/task/todo/index.vue
  22. 0 1
      src/views/infra/apiAccessLog/index.vue
  23. 0 1
      src/views/infra/apiErrorLog/index.vue
  24. 0 4
      src/views/infra/codegen/index.vue
  25. 0 1
      src/views/infra/config/index.vue
  26. 0 1
      src/views/infra/demo/demo01/index.vue
  27. 0 1
      src/views/infra/demo/demo02/index.vue
  28. 0 1
      src/views/infra/demo/demo03/erp/index.vue
  29. 0 1
      src/views/infra/demo/demo03/inner/index.vue
  30. 0 1
      src/views/infra/demo/demo03/normal/index.vue
  31. 0 2
      src/views/infra/druid/index.vue
  32. 0 1
      src/views/infra/file/index.vue
  33. 0 1
      src/views/infra/fileConfig/index.vue
  34. 0 3
      src/views/infra/job/index.vue
  35. 0 3
      src/views/infra/job/logger/index.vue
  36. 0 2
      src/views/infra/redis/index.vue
  37. 0 1
      src/views/infra/server/index.vue
  38. 0 1
      src/views/infra/skywalking/index.vue
  39. 0 1
      src/views/infra/swagger/index.vue
  40. 0 2
      src/views/infra/webSocket/index.vue
  41. 138 0
      src/views/museums/museumsdocument/DocumentForm.vue
  42. 264 0
      src/views/museums/museumsdocument/index.vue
  43. 123 0
      src/views/museums/photogroup/PhotoGroupForm.vue
  44. 229 0
      src/views/museums/photogroup/index.vue
  45. 108 0
      src/views/museums/photos/PhotosForm.vue
  46. 217 0
      src/views/museums/photos/index.vue
  47. 283 0
      src/views/museums/specimeninfo/SpecimenInfoForm.vue
  48. 535 0
      src/views/museums/specimeninfo/index.vue
  49. 199 0
      src/views/museums/specimenoutbound/SpecimenOutboundForm.vue
  50. 389 0
      src/views/museums/specimenoutbound/index.vue
  51. 0 1
      src/views/pay/app/index.vue
  52. 0 4
      src/views/pay/demo/order/index.vue
  53. 0 1
      src/views/pay/notify/index.vue
  54. 0 3
      src/views/pay/order/index.vue
  55. 0 1
      src/views/pay/refund/index.vue
  56. 0 1
      src/views/report/goview/index.vue
  57. 0 1
      src/views/report/jmreport/index.vue
  58. 0 1
      src/views/system/area/index.vue
  59. 0 1
      src/views/system/loginlog/index.vue
  60. 0 1
      src/views/system/mail/account/index.vue
  61. 0 1
      src/views/system/mail/log/index.vue
  62. 0 1
      src/views/system/mail/template/index.vue
  63. 0 2
      src/views/system/menu/index.vue
  64. 0 2
      src/views/system/notify/message/index.vue
  65. 0 1
      src/views/system/notify/my/index.vue
  66. 0 1
      src/views/system/notify/template/index.vue
  67. 0 2
      src/views/system/oauth2/client/index.vue
  68. 0 1
      src/views/system/oauth2/token/index.vue
  69. 0 1
      src/views/system/operatelog/index.vue
  70. 0 2
      src/views/system/role/index.vue
  71. 0 1
      src/views/system/sms/channel/index.vue
  72. 0 1
      src/views/system/sms/log/index.vue
  73. 0 1
      src/views/system/sms/template/index.vue
  74. 0 1
      src/views/system/social/client/index.vue
  75. 0 2
      src/views/system/social/user/index.vue
  76. 1 1
      src/views/system/tenant/index.vue
  77. 1 1
      src/views/system/tenantPackage/index.vue
  78. 0 3
      src/views/system/user/index.vue

+ 47 - 0
src/api/museums/museumsdocument/index.ts

@@ -0,0 +1,47 @@
+import request from '@/config/axios'
+
+// 博物馆文件管理 VO
+export interface DocumentVO {
+  id: number // 主键
+  fileName: string // 文件名称
+  configId: number // 配置编号
+  path: string // 路径
+  url: string // 文件 URL
+  fileSize: number // 文件大小(字节)
+  fileType: string // 文件类型
+  uploadDate: Date // 上传时间
+  uploadedBy: string // 上传者
+}
+
+// 博物馆文件管理 API
+export const DocumentApi = {
+  // 查询博物馆文件管理分页
+  getDocumentPage: async (params: any) => {
+    return await request.get({ url: `/museums/document/page`, params })
+  },
+
+  // 查询博物馆文件管理详情
+  getDocument: async (id: number) => {
+    return await request.get({ url: `/museums/document/get?id=` + id })
+  },
+
+  // 新增博物馆文件管理
+  createDocument: async (data: DocumentVO) => {
+    return await request.post({ url: `/museums/document/create`, data })
+  },
+
+  // 修改博物馆文件管理
+  updateDocument: async (data: DocumentVO) => {
+    return await request.put({ url: `/museums/document/update`, data })
+  },
+
+  // 删除博物馆文件管理
+  deleteDocument: async (id: number) => {
+    return await request.delete({ url: `/museums/document/delete?id=` + id })
+  },
+
+  // 导出博物馆文件管理 Excel
+  exportDocument: async (params) => {
+    return await request.download({ url: `/museums/document/export-excel`, params })
+  }
+}

+ 44 - 0
src/api/museums/photogroup/index.ts

@@ -0,0 +1,44 @@
+import request from '@/config/axios'
+
+// 博物馆照片组 VO
+export interface PhotoGroupVO {
+  id: number // 主键
+  groupName: string // 照片组名称
+  groupDate: Date // 照片组时间
+  groupDescription: string // 照片组简介
+  createdAt: Date // 创建时间
+  uploadPhotos: string // 照片组上传
+}
+
+// 博物馆照片组 API
+export const PhotoGroupApi = {
+  // 查询博物馆照片组分页
+  getPhotoGroupPage: async (params: any) => {
+    return await request.get({ url: `/museums/photo-group/page`, params })
+  },
+
+  // 查询博物馆照片组详情
+  getPhotoGroup: async (id: number) => {
+    return await request.get({ url: `/museums/photo-group/get?id=` + id })
+  },
+
+  // 新增博物馆照片组
+  createPhotoGroup: async (data: PhotoGroupVO) => {
+    return await request.post({ url: `/museums/photo-group/create`, data })
+  },
+
+  // 修改博物馆照片组
+  updatePhotoGroup: async (data: PhotoGroupVO) => {
+    return await request.put({ url: `/museums/photo-group/update`, data })
+  },
+
+  // 删除博物馆照片组
+  deletePhotoGroup: async (id: number) => {
+    return await request.delete({ url: `/museums/photo-group/delete?id=` + id })
+  },
+
+  // 导出博物馆照片组 Excel
+  exportPhotoGroup: async (params) => {
+    return await request.download({ url: `/museums/photo-group/export-excel`, params })
+  }
+}

+ 42 - 0
src/api/museums/photos/index.ts

@@ -0,0 +1,42 @@
+import request from '@/config/axios'
+
+// 博物馆照片 VO
+export interface PhotosVO {
+  id: number // 主键
+  groupId: number // 照片组表id
+  photoUrl: string // 照片存储路径
+  createdAt: Date // 上传时间
+}
+
+// 博物馆照片 API
+export const PhotosApi = {
+  // 查询博物馆照片分页
+  getPhotosPage: async (params: any) => {
+    return await request.get({ url: `/museums/photos/page`, params })
+  },
+
+  // 查询博物馆照片详情
+  getPhotos: async (id: number) => {
+    return await request.get({ url: `/museums/photos/get?id=` + id })
+  },
+
+  // 新增博物馆照片
+  createPhotos: async (data: PhotosVO) => {
+    return await request.post({ url: `/museums/photos/create`, data })
+  },
+
+  // 修改博物馆照片
+  updatePhotos: async (data: PhotosVO) => {
+    return await request.put({ url: `/museums/photos/update`, data })
+  },
+
+  // 删除博物馆照片
+  deletePhotos: async (id: number) => {
+    return await request.delete({ url: `/museums/photos/delete?id=` + id })
+  },
+
+  // 导出博物馆照片 Excel
+  exportPhotos: async (params) => {
+    return await request.download({ url: `/museums/photos/export-excel`, params })
+  }
+}

+ 68 - 0
src/api/museums/specimeninfo/index.ts

@@ -0,0 +1,68 @@
+import request from '@/config/axios'
+
+// 标本管理 VO
+export interface SpecimenInfoVO {
+  id: number // 主键
+  specimenType: number // 标本类型(矿物、岩石矿石、化石、陨石)
+  specimenNumber: string // 标本编号
+  assetNumber: string // 资产号
+  storageLocation: string // 存放位置
+  chineseName: string // 中文名称
+  englishName: string // 英文名称
+  composition: string // 成分
+  origin: string // 产地
+  era: string // 时代
+  preservedLayer: string // 保存地层
+  meteoriteType: string // 陨石类型
+  internationalName: string // 国际命名
+  discoveryTime: Date // 发现时间
+  fallTime: Date // 降落时间
+  preservationType: number // 保存类型(标本、光片、薄片模型及其他)
+  size: string // 尺寸
+  weight: number // 重量
+  source: number // 来源(采购、捐赠、采集)
+  provider: string // 标本提供者(供应商、捐赠人、采集人)
+  acquisitionTime: Date // 入藏时间(购买、捐赠、采集时间)
+  purpose: string // 用途
+  description: string // 描述
+  collectionStatus: number // 馆藏状态(在馆、借出)
+  notes: string // 备注
+  imageName: string // 图片名称
+  imagePath: string // 图片路径
+  deletedReason: string // 注销原因
+  operator: string // 入库操作员
+  entryDate: Date // 入库时间
+}
+
+// 标本管理 API
+export const SpecimenInfoApi = {
+  // 查询标本管理分页
+  getSpecimenInfoPage: async (params: any) => {
+    return await request.get({ url: `/museums/specimen-info/page`, params })
+  },
+
+  // 查询标本管理详情
+  getSpecimenInfo: async (id: number) => {
+    return await request.get({ url: `/museums/specimen-info/get?id=` + id })
+  },
+
+  // 新增标本管理
+  createSpecimenInfo: async (data: SpecimenInfoVO) => {
+    return await request.post({ url: `/museums/specimen-info/create`, data })
+  },
+
+  // 修改标本管理
+  updateSpecimenInfo: async (data: SpecimenInfoVO) => {
+    return await request.put({ url: `/museums/specimen-info/update`, data })
+  },
+
+  // 删除标本管理
+  deleteSpecimenInfo: async (id: number) => {
+    return await request.delete({ url: `/museums/specimen-info/delete?id=` + id })
+  },
+
+  // 导出标本管理 Excel
+  exportSpecimenInfo: async (params) => {
+    return await request.download({ url: `/museums/specimen-info/export-excel`, params })
+  }
+}

+ 56 - 0
src/api/museums/specimenoutbound/index.ts

@@ -0,0 +1,56 @@
+import request from '@/config/axios'
+
+// 标本出库回库信息 VO
+export interface SpecimenOutboundVO {
+  id: number // 主键
+  infoId: string // 关联到总表中的标本ID
+  chineseName: string // 中文名称
+  specimenNumber: string // 申请出库的标本编号
+  applicantName: string // 申请人或申请单位
+  applicationDate: Date // 申请日期
+  applicationUsage: string // 申请出库的用途
+  attachments: string // 附件上传
+  status: number // 审批状态
+  remarks: string // 备注信息
+  processInstanceId: string // 流程实例的编号
+  operator: string // 出库员
+  outgoingTime: Date // 出库时间
+  returner: string // 退还人
+  receiver: string // 点收人
+  returnDate: Date // 退还日期
+  specimenCondition: string // 标本情况
+  sampleStatus: number // 标本状态(已出库、已回库、出库审批中)
+}
+
+// 标本出库回库信息 API
+export const SpecimenOutboundApi = {
+  // 查询标本出库回库信息分页
+  getSpecimenOutboundPage: async (params: any) => {
+    return await request.get({ url: `/museums/specimen-outbound/page`, params })
+  },
+
+  // 查询标本出库回库信息详情
+  getSpecimenOutbound: async (id: number) => {
+    return await request.get({ url: `/museums/specimen-outbound/get?id=` + id })
+  },
+
+  // 新增标本出库回库信息
+  createSpecimenOutbound: async (data: SpecimenOutboundVO) => {
+    return await request.post({ url: `/museums/specimen-outbound/create`, data })
+  },
+
+  // 修改标本出库回库信息
+  updateSpecimenOutbound: async (data: SpecimenOutboundVO) => {
+    return await request.put({ url: `/museums/specimen-outbound/update`, data })
+  },
+
+  // 删除标本出库回库信息
+  deleteSpecimenOutbound: async (id: number) => {
+    return await request.delete({ url: `/museums/specimen-outbound/delete?id=` + id })
+  },
+
+  // 导出标本出库回库信息 Excel
+  exportSpecimenOutbound: async (params) => {
+    return await request.download({ url: `/museums/specimen-outbound/export-excel`, params })
+  }
+}

+ 4 - 1
src/utils/dict.ts

@@ -226,5 +226,8 @@ export enum DICT_TYPE {
   AI_WRITE_LENGTH = 'ai_write_length', // AI 写作长度
   AI_WRITE_FORMAT = 'ai_write_format', // AI 写作格式
   AI_WRITE_TONE = 'ai_write_tone', // AI 写作语气
-  AI_WRITE_LANGUAGE = 'ai_write_language' // AI 写作语言
+  AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言
+
+  // ========== MUSEUMS - 地质博物馆模块  ==========
+  MUSEUMS_SPECIMEN_INFO='museums_specimen_info'
 }

+ 0 - 1
src/views/bpm/category/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="工作流手册" url="https://doc.iocoder.cn/bpm/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/definition/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="工作流手册" url="https://doc.iocoder.cn/bpm/" />
 
   <ContentWrap>
     <el-table v-loading="loading" :data="list">

+ 0 - 1
src/views/bpm/form/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="审批接入(流程表单)" url="https://doc.iocoder.cn/bpm/use-bpm-form/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/group/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="工作流手册" url="https://doc.iocoder.cn/bpm/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 7
src/views/bpm/model/index.vue

@@ -1,11 +1,4 @@
 <template>
-  <doc-alert title="流程设计器(BPMN)" url="https://doc.iocoder.cn/bpm/model-designer-dingding/" />
-  <doc-alert
-    title="流程设计器(钉钉、飞书)"
-    url="https://doc.iocoder.cn/bpm/model-designer-bpmn/"
-  />
-  <doc-alert title="选择审批人、发起人自选" url="https://doc.iocoder.cn/bpm/assignee/" />
-  <doc-alert title="会签、或签、依次审批" url="https://doc.iocoder.cn/bpm/multi-instance/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/oa/leave/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="审批接入(业务表单)" url="https://doc.iocoder.cn/bpm/use-business-form/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 2
src/views/bpm/processExpression/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="流程表达式" url="https://doc.iocoder.cn/bpm/expression/" />
-
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form

+ 0 - 1
src/views/bpm/processInstance/create/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="流程发起、取消、重新发起" url="https://doc.iocoder.cn/bpm/process-instance/" />
 
   <!-- 第一步,通过流程定义的列表,选择对应的流程 -->
   <ContentWrap v-if="!selectProcessDefinition" v-loading="loading">

+ 0 - 1
src/views/bpm/processInstance/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="流程发起、取消、重新发起" url="https://doc.iocoder.cn/bpm/process-instance/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/processInstance/manager/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="工作流手册" url="https://doc.iocoder.cn/bpm/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/processListener/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="执行监听器、任务监听器" url="https://doc.iocoder.cn/bpm/listener/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 4
src/views/bpm/task/copy/index.vue

@@ -1,9 +1,5 @@
 <!-- 工作流 - 抄送我的流程 -->
 <template>
-  <doc-alert
-    title="审批转办、委派、抄送"
-    url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/"
-  />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 7
src/views/bpm/task/done/index.vue

@@ -1,11 +1,4 @@
 <template>
-  <doc-alert title="审批通过、不通过、驳回" url="https://doc.iocoder.cn/bpm/task-todo-done/" />
-  <doc-alert title="审批加签、减签" url="https://doc.iocoder.cn/bpm/sign/" />
-  <doc-alert
-    title="审批转办、委派、抄送"
-    url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/"
-  />
-  <doc-alert title="审批加签、减签" url="https://doc.iocoder.cn/bpm/sign/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/bpm/task/manager/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="工作流手册" url="https://doc.iocoder.cn/bpm/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 7
src/views/bpm/task/todo/index.vue

@@ -1,11 +1,4 @@
 <template>
-  <doc-alert title="审批通过、不通过、驳回" url="https://doc.iocoder.cn/bpm/task-todo-done/" />
-  <doc-alert title="审批加签、减签" url="https://doc.iocoder.cn/bpm/sign/" />
-  <doc-alert
-    title="审批转办、委派、抄送"
-    url="https://doc.iocoder.cn/bpm/task-delegation-and-cc/"
-  />
-  <doc-alert title="审批加签、减签" url="https://doc.iocoder.cn/bpm/sign/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/apiAccessLog/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="系统日志" url="https://doc.iocoder.cn/system-log/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/apiErrorLog/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="系统日志" url="https://doc.iocoder.cn/system-log/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 4
src/views/infra/codegen/index.vue

@@ -1,8 +1,4 @@
 <template>
-  <doc-alert title="代码生成(单表)" url="https://doc.iocoder.cn/new-feature/" />
-  <doc-alert title="代码生成(树表)" url="https://doc.iocoder.cn/new-feature/tree/" />
-  <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" />
-  <doc-alert title="单元测试" url="https://doc.iocoder.cn/unit-test/" />
 
   <!-- 搜索 -->
   <ContentWrap>

+ 0 - 1
src/views/infra/config/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="配置中心" url="https://doc.iocoder.cn/config-center/" />
 
   <!-- 搜索 -->
   <ContentWrap>

+ 0 - 1
src/views/infra/demo/demo01/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="代码生成(单表)" url="https://doc.iocoder.cn/new-feature/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/demo/demo02/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="代码生成(树表)" url="https://doc.iocoder.cn/new-feature/tree/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/demo/demo03/erp/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/demo/demo03/inner/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/infra/demo/demo03/normal/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 2
src/views/infra/druid/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="数据库 MyBatis" url="https://doc.iocoder.cn/mybatis/" />
-  <doc-alert title="多数据源(读写分离)" url="https://doc.iocoder.cn/dynamic-datasource/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame v-if="!loading" v-loading="loading" :src="url" />

+ 0 - 1
src/views/infra/file/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="上传下载" url="https://doc.iocoder.cn/file/" />
   <!-- 搜索 -->
   <ContentWrap>
     <el-form

+ 0 - 1
src/views/infra/fileConfig/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="上传下载" url="https://doc.iocoder.cn/file/" />
 
   <!-- 搜索 -->
   <ContentWrap>

+ 0 - 3
src/views/infra/job/index.vue

@@ -1,7 +1,4 @@
 <template>
-  <doc-alert title="定时任务" url="https://doc.iocoder.cn/job/" />
-  <doc-alert title="异步任务" url="https://doc.iocoder.cn/async-task/" />
-  <doc-alert title="消息队列" url="https://doc.iocoder.cn/message-queue/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 3
src/views/infra/job/logger/index.vue

@@ -1,7 +1,4 @@
 <template>
-  <doc-alert title="定时任务" url="https://doc.iocoder.cn/job/" />
-  <doc-alert title="异步任务" url="https://doc.iocoder.cn/async-task/" />
-  <doc-alert title="消息队列" url="https://doc.iocoder.cn/message-queue/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 2
src/views/infra/redis/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="Redis 缓存" url="https://doc.iocoder.cn/redis-cache/" />
-  <doc-alert title="本地缓存" url="https://doc.iocoder.cn/local-cache/" />
   <el-scrollbar height="calc(100vh - 88px - 40px - 50px)">
     <el-row>
       <!-- 基本信息 -->

+ 0 - 1
src/views/infra/server/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="服务监控" url="https://doc.iocoder.cn/server-monitor/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame v-if="!loading" v-loading="loading" :src="src" />

+ 0 - 1
src/views/infra/skywalking/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="服务监控" url="https://doc.iocoder.cn/server-monitor/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame v-if="!loading" v-loading="loading" :src="src" />

+ 0 - 1
src/views/infra/swagger/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="接口文档" url="https://doc.iocoder.cn/api-doc/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame v-if="!loading" v-loading="loading" :src="src" />

+ 0 - 2
src/views/infra/webSocket/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="WebSocket 实时通信" url="https://doc.iocoder.cn/websocket/" />
-
   <div class="flex">
     <!-- 左侧:建立连接、发送消息 -->
     <el-card :gutter="12" class="w-1/2" shadow="always">

+ 138 - 0
src/views/museums/museumsdocument/DocumentForm.vue

@@ -0,0 +1,138 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="文件名称" prop="fileName">
+        <el-input v-model="formData.fileName" placeholder="请输入文件名称" />
+      </el-form-item>
+      <el-form-item label="配置编号" prop="configId">
+        <el-input v-model="formData.configId" placeholder="请输入配置编号" />
+      </el-form-item>
+      <el-form-item label="路径" prop="path">
+        <el-input v-model="formData.path" placeholder="请输入路径" />
+      </el-form-item>
+      <el-form-item label="文件 URL" prop="url">
+        <UploadFile v-model="formData.url" />
+      </el-form-item>
+      <el-form-item label="文件大小(字节)" prop="fileSize">
+        <el-input v-model="formData.fileSize" placeholder="请输入文件大小(字节)" />
+      </el-form-item>
+      <el-form-item label="文件类型" prop="fileType">
+        <el-select v-model="formData.fileType" placeholder="请选择文件类型">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="上传时间" prop="uploadDate">
+        <el-date-picker
+          v-model="formData.uploadDate"
+          type="date"
+          value-format="x"
+          placeholder="选择上传时间"
+        />
+      </el-form-item>
+      <el-form-item label="上传者" prop="uploadedBy">
+        <el-input v-model="formData.uploadedBy" placeholder="请输入上传者" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { DocumentApi, DocumentVO } from '@/api/museums/museumsdocument'
+
+/** 博物馆文件管理 表单 */
+defineOptions({ name: 'DocumentForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  fileName: undefined,
+  configId: undefined,
+  path: undefined,
+  url: undefined,
+  fileSize: undefined,
+  fileType: undefined,
+  uploadDate: undefined,
+  uploadedBy: undefined
+})
+const formRules = reactive({
+  fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
+  path: [{ required: true, message: '路径不能为空', trigger: 'blur' }],
+  url: [{ required: true, message: '文件 URL不能为空', trigger: 'blur' }],
+  fileSize: [{ required: true, message: '文件大小(字节)不能为空', trigger: 'blur' }],
+  uploadedBy: [{ required: true, message: '上传者不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await DocumentApi.getDocument(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as DocumentVO
+    if (formType.value === 'create') {
+      await DocumentApi.createDocument(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await DocumentApi.updateDocument(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    fileName: undefined,
+    configId: undefined,
+    path: undefined,
+    url: undefined,
+    fileSize: undefined,
+    fileType: undefined,
+    uploadDate: undefined,
+    uploadedBy: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 264 - 0
src/views/museums/museumsdocument/index.vue

@@ -0,0 +1,264 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="文件名称" prop="fileName">
+        <el-input
+          v-model="queryParams.fileName"
+          placeholder="请输入文件名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="配置编号" prop="configId">
+        <el-input
+          v-model="queryParams.configId"
+          placeholder="请输入配置编号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="路径" prop="path">
+        <el-input
+          v-model="queryParams.path"
+          placeholder="请输入路径"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="文件大小(字节)" prop="fileSize">
+        <el-input
+          v-model="queryParams.fileSize"
+          placeholder="请输入文件大小(字节)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="文件类型" prop="fileType">
+        <el-select
+          v-model="queryParams.fileType"
+          placeholder="请选择文件类型"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="上传时间" prop="uploadDate">
+        <el-date-picker
+          v-model="queryParams.uploadDate"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="上传者" prop="uploadedBy">
+        <el-input
+          v-model="queryParams.uploadedBy"
+          placeholder="请输入上传者"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['museums:document:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['museums:document:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="主键" align="center" prop="id" />
+      <el-table-column label="文件名称" align="center" prop="fileName" />
+      <el-table-column label="配置编号" align="center" prop="configId" />
+      <el-table-column label="路径" align="center" prop="path" />
+      <el-table-column label="文件 URL" align="center" prop="url" />
+      <el-table-column label="文件大小(字节)" align="center" prop="fileSize" />
+      <el-table-column label="文件类型" align="center" prop="fileType" />
+      <el-table-column
+        label="上传时间"
+        align="center"
+        prop="uploadDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="上传者" align="center" prop="uploadedBy" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['museums:document:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['museums:document:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <DocumentForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { DocumentApi, DocumentVO } from '@/api/museums/museumsdocument'
+import DocumentForm from './DocumentForm.vue'
+
+/** 博物馆文件管理 列表 */
+defineOptions({ name: 'MuseumsDocument' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<DocumentVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  fileName: undefined,
+  configId: undefined,
+  path: undefined,
+  url: undefined,
+  fileSize: undefined,
+  fileType: undefined,
+  uploadDate: [],
+  uploadedBy: undefined,
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await DocumentApi.getDocumentPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await DocumentApi.deleteDocument(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await DocumentApi.exportDocument(queryParams)
+    download.excel(data, '博物馆文件管理.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 123 - 0
src/views/museums/photogroup/PhotoGroupForm.vue

@@ -0,0 +1,123 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="照片组名称" prop="groupName">
+        <el-input v-model="formData.groupName" placeholder="请输入照片组名称" />
+      </el-form-item>
+      <el-form-item label="照片组时间" prop="groupDate">
+        <el-date-picker
+          v-model="formData.groupDate"
+          type="date"
+          value-format="x"
+          placeholder="选择照片组时间"
+        />
+      </el-form-item>
+      <el-form-item label="照片组简介" prop="groupDescription">
+        <Editor v-model="formData.groupDescription" height="150px" />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createdAt">
+        <el-date-picker
+          v-model="formData.createdAt"
+          type="date"
+          value-format="x"
+          placeholder="选择创建时间"
+        />
+      </el-form-item>
+      <el-form-item label="照片组上传" prop="uploadPhotos">
+        <UploadFile v-model="formData.uploadPhotos" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { PhotoGroupApi, PhotoGroupVO } from '@/api/museums/photogroup'
+
+/** 博物馆照片组 表单 */
+defineOptions({ name: 'PhotoGroupForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  groupName: undefined,
+  groupDate: undefined,
+  groupDescription: undefined,
+  createdAt: undefined,
+  uploadPhotos: undefined
+})
+const formRules = reactive({
+  groupName: [{ required: true, message: '照片组名称不能为空', trigger: 'blur' }],
+  groupDate: [{ required: true, message: '照片组时间不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await PhotoGroupApi.getPhotoGroup(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as PhotoGroupVO
+    if (formType.value === 'create') {
+      await PhotoGroupApi.createPhotoGroup(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await PhotoGroupApi.updatePhotoGroup(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    groupName: undefined,
+    groupDate: undefined,
+    groupDescription: undefined,
+    createdAt: undefined,
+    uploadPhotos: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 229 - 0
src/views/museums/photogroup/index.vue

@@ -0,0 +1,229 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="照片组名称" prop="groupName">
+        <el-input
+          v-model="queryParams.groupName"
+          placeholder="请输入照片组名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="照片组时间" prop="groupDate">
+        <el-date-picker
+          v-model="queryParams.groupDate"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createdAt">
+        <el-date-picker
+          v-model="queryParams.createdAt"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="选择创建时间"
+          clearable
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['museums:photo-group:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['museums:photo-group:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="主键" align="center" prop="id" />
+      <el-table-column label="照片组名称" align="center" prop="groupName" />
+      <el-table-column
+        label="照片组时间"
+        align="center"
+        prop="groupDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="照片组简介" align="center" prop="groupDescription" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createdAt"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="照片组上传" align="center" prop="uploadPhotos" />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['museums:photo-group:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['museums:photo-group:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <PhotoGroupForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { PhotoGroupApi, PhotoGroupVO } from '@/api/museums/photogroup'
+import PhotoGroupForm from './PhotoGroupForm.vue'
+
+/** 博物馆照片组 列表 */
+defineOptions({ name: 'PhotoGroup' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<PhotoGroupVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  groupName: undefined,
+  groupDate: [],
+  groupDescription: undefined,
+  createdAt: undefined,
+  createdAt: [],
+  createTime: [],
+  uploadPhotos: undefined
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PhotoGroupApi.getPhotoGroupPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await PhotoGroupApi.deletePhotoGroup(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await PhotoGroupApi.exportPhotoGroup(queryParams)
+    download.excel(data, '博物馆照片组.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 108 - 0
src/views/museums/photos/PhotosForm.vue

@@ -0,0 +1,108 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="照片组表id" prop="groupId">
+        <el-input v-model="formData.groupId" placeholder="请输入照片组表id" />
+      </el-form-item>
+      <el-form-item label="照片存储路径" prop="photoUrl">
+        <el-input v-model="formData.photoUrl" placeholder="请输入照片存储路径" />
+      </el-form-item>
+      <el-form-item label="上传时间" prop="createdAt">
+        <el-date-picker
+          v-model="formData.createdAt"
+          type="date"
+          value-format="x"
+          placeholder="选择上传时间"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { PhotosApi, PhotosVO } from '@/api/museums/photos'
+
+/** 博物馆照片 表单 */
+defineOptions({ name: 'PhotosForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  groupId: undefined,
+  photoUrl: undefined,
+  createdAt: undefined
+})
+const formRules = reactive({
+  groupId: [{ required: true, message: '照片组表id不能为空', trigger: 'blur' }],
+  photoUrl: [{ required: true, message: '照片存储路径不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await PhotosApi.getPhotos(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as PhotosVO
+    if (formType.value === 'create') {
+      await PhotosApi.createPhotos(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await PhotosApi.updatePhotos(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    groupId: undefined,
+    photoUrl: undefined,
+    createdAt: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 217 - 0
src/views/museums/photos/index.vue

@@ -0,0 +1,217 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="照片组表id" prop="groupId">
+        <el-input
+          v-model="queryParams.groupId"
+          placeholder="请输入照片组表id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="照片存储路径" prop="photoUrl">
+        <el-input
+          v-model="queryParams.photoUrl"
+          placeholder="请输入照片存储路径"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="上传时间" prop="createdAt">
+        <el-date-picker
+          v-model="queryParams.createdAt"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="选择上传时间"
+          clearable
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['museums:photos:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['museums:photos:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="主键" align="center" prop="id" />
+      <el-table-column label="照片组表id" align="center" prop="groupId" />
+      <el-table-column label="照片存储路径" align="center" prop="photoUrl" />
+      <el-table-column
+        label="上传时间"
+        align="center"
+        prop="createdAt"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['museums:photos:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['museums:photos:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <PhotosForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { PhotosApi, PhotosVO } from '@/api/museums/photos'
+import PhotosForm from './PhotosForm.vue'
+
+/** 博物馆照片 列表 */
+defineOptions({ name: 'Photos' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<PhotosVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  groupId: undefined,
+  photoUrl: undefined,
+  createdAt: undefined,
+  createdAt: [],
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PhotosApi.getPhotosPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await PhotosApi.deletePhotos(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await PhotosApi.exportPhotos(queryParams)
+    download.excel(data, '博物馆照片.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 283 - 0
src/views/museums/specimeninfo/SpecimenInfoForm.vue

@@ -0,0 +1,283 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="标本类型(矿物、岩石矿石、化石、陨石)" prop="specimenType">
+        <el-select v-model="formData.specimenType" placeholder="请选择标本类型(矿物、岩石矿石、化石、陨石)">
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标本编号" prop="specimenNumber">
+        <el-input v-model="formData.specimenNumber" placeholder="请输入标本编号" />
+      </el-form-item>
+      <el-form-item label="资产号" prop="assetNumber">
+        <el-input v-model="formData.assetNumber" placeholder="请输入资产号" />
+      </el-form-item>
+      <el-form-item label="存放位置" prop="storageLocation">
+        <el-input v-model="formData.storageLocation" placeholder="请输入存放位置" />
+      </el-form-item>
+      <el-form-item label="中文名称" prop="chineseName">
+        <el-input v-model="formData.chineseName" placeholder="请输入中文名称" />
+      </el-form-item>
+      <el-form-item label="英文名称" prop="englishName">
+        <el-input v-model="formData.englishName" placeholder="请输入英文名称" />
+      </el-form-item>
+      <el-form-item label="成分" prop="composition">
+        <el-input v-model="formData.composition" placeholder="请输入成分" />
+      </el-form-item>
+      <el-form-item label="产地" prop="origin">
+        <el-input v-model="formData.origin" placeholder="请输入产地" />
+      </el-form-item>
+      <el-form-item label="时代" prop="era">
+        <el-input v-model="formData.era" placeholder="请输入时代" />
+      </el-form-item>
+      <el-form-item label="保存地层" prop="preservedLayer">
+        <el-input v-model="formData.preservedLayer" placeholder="请输入保存地层" />
+      </el-form-item>
+      <el-form-item label="陨石类型" prop="meteoriteType">
+        <el-input v-model="formData.meteoriteType" placeholder="请输入陨石类型" />
+      </el-form-item>
+      <el-form-item label="国际命名" prop="internationalName">
+        <el-input v-model="formData.internationalName" placeholder="请输入国际命名" />
+      </el-form-item>
+      <el-form-item label="发现时间" prop="discoveryTime">
+        <el-date-picker
+          v-model="formData.discoveryTime"
+          type="date"
+          value-format="x"
+          placeholder="选择发现时间"
+        />
+      </el-form-item>
+      <el-form-item label="降落时间" prop="fallTime">
+        <el-date-picker
+          v-model="formData.fallTime"
+          type="date"
+          value-format="x"
+          placeholder="选择降落时间"
+        />
+      </el-form-item>
+      <el-form-item label="保存类型(标本、光片、薄片模型及其他)" prop="preservationType">
+        <el-select v-model="formData.preservationType" placeholder="请选择保存类型(标本、光片、薄片模型及其他)">
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="尺寸" prop="size">
+        <el-input v-model="formData.size" placeholder="请输入尺寸" />
+      </el-form-item>
+      <el-form-item label="重量" prop="weight">
+        <el-input v-model="formData.weight" placeholder="请输入重量" />
+      </el-form-item>
+      <el-form-item label="来源(采购、捐赠、采集)" prop="source">
+        <el-select v-model="formData.source" placeholder="请选择来源(采购、捐赠、采集)">
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标本提供者(供应商、捐赠人、采集人)" prop="provider">
+        <el-input v-model="formData.provider" placeholder="请输入标本提供者(供应商、捐赠人、采集人)" />
+      </el-form-item>
+      <el-form-item label="入藏时间(购买、捐赠、采集时间)" prop="acquisitionTime">
+        <el-date-picker
+          v-model="formData.acquisitionTime"
+          type="date"
+          value-format="x"
+          placeholder="选择入藏时间(购买、捐赠、采集时间)"
+        />
+      </el-form-item>
+      <el-form-item label="用途" prop="purpose">
+        <el-input v-model="formData.purpose" placeholder="请输入用途" />
+      </el-form-item>
+      <el-form-item label="描述" prop="description">
+        <Editor v-model="formData.description" height="150px" />
+      </el-form-item>
+      <el-form-item label="馆藏状态(在馆、借出)" prop="collectionStatus">
+        <el-radio-group v-model="formData.collectionStatus">
+          <el-radio
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.value"
+          >
+            {{ dict.label }}
+          </el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="备注" prop="notes">
+        <el-input v-model="formData.notes" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="图片名称" prop="imageName">
+        <el-input v-model="formData.imageName" placeholder="请输入图片名称" />
+      </el-form-item>
+      <el-form-item label="图片路径" prop="imagePath">
+        <el-input v-model="formData.imagePath" placeholder="请输入图片路径" />
+      </el-form-item>
+      <el-form-item label="注销原因" prop="deletedReason">
+        <el-input v-model="formData.deletedReason" placeholder="请输入注销原因" />
+      </el-form-item>
+      <el-form-item label="入库操作员" prop="operator">
+        <el-input v-model="formData.operator" placeholder="请输入入库操作员" />
+      </el-form-item>
+      <el-form-item label="入库时间" prop="entryDate">
+        <el-date-picker
+          v-model="formData.entryDate"
+          type="date"
+          value-format="x"
+          placeholder="选择入库时间"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
+import { SpecimenInfoApi, SpecimenInfoVO } from '@/api/museums/specimeninfo'
+
+/** 标本管理 表单 */
+defineOptions({ name: 'SpecimenInfoForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  specimenType: undefined,
+  specimenNumber: undefined,
+  assetNumber: undefined,
+  storageLocation: undefined,
+  chineseName: undefined,
+  englishName: undefined,
+  composition: undefined,
+  origin: undefined,
+  era: undefined,
+  preservedLayer: undefined,
+  meteoriteType: undefined,
+  internationalName: undefined,
+  discoveryTime: undefined,
+  fallTime: undefined,
+  preservationType: undefined,
+  size: undefined,
+  weight: undefined,
+  source: undefined,
+  provider: undefined,
+  acquisitionTime: undefined,
+  purpose: undefined,
+  description: undefined,
+  collectionStatus: undefined,
+  notes: undefined,
+  imageName: undefined,
+  imagePath: undefined,
+  deletedReason: undefined,
+  operator: undefined,
+  entryDate: undefined
+})
+const formRules = reactive({
+  specimenType: [{ required: true, message: '标本类型(矿物、岩石矿石、化石、陨石)不能为空', trigger: 'change' }],
+  specimenNumber: [{ required: true, message: '标本编号不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await SpecimenInfoApi.getSpecimenInfo(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as SpecimenInfoVO
+    if (formType.value === 'create') {
+      await SpecimenInfoApi.createSpecimenInfo(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await SpecimenInfoApi.updateSpecimenInfo(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    specimenType: undefined,
+    specimenNumber: undefined,
+    assetNumber: undefined,
+    storageLocation: undefined,
+    chineseName: undefined,
+    englishName: undefined,
+    composition: undefined,
+    origin: undefined,
+    era: undefined,
+    preservedLayer: undefined,
+    meteoriteType: undefined,
+    internationalName: undefined,
+    discoveryTime: undefined,
+    fallTime: undefined,
+    preservationType: undefined,
+    size: undefined,
+    weight: undefined,
+    source: undefined,
+    provider: undefined,
+    acquisitionTime: undefined,
+    purpose: undefined,
+    description: undefined,
+    collectionStatus: undefined,
+    notes: undefined,
+    imageName: undefined,
+    imagePath: undefined,
+    deletedReason: undefined,
+    operator: undefined,
+    entryDate: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 535 - 0
src/views/museums/specimeninfo/index.vue

@@ -0,0 +1,535 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="标本类型(矿物、岩石矿石、化石、陨石)" prop="specimenType">
+        <el-select
+          v-model="queryParams.specimenType"
+          placeholder="请选择标本类型(矿物、岩石矿石、化石、陨石)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标本编号" prop="specimenNumber">
+        <el-input
+          v-model="queryParams.specimenNumber"
+          placeholder="请输入标本编号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="资产号" prop="assetNumber">
+        <el-input
+          v-model="queryParams.assetNumber"
+          placeholder="请输入资产号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="存放位置" prop="storageLocation">
+        <el-input
+          v-model="queryParams.storageLocation"
+          placeholder="请输入存放位置"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="中文名称" prop="chineseName">
+        <el-input
+          v-model="queryParams.chineseName"
+          placeholder="请输入中文名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="英文名称" prop="englishName">
+        <el-input
+          v-model="queryParams.englishName"
+          placeholder="请输入英文名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="成分" prop="composition">
+        <el-input
+          v-model="queryParams.composition"
+          placeholder="请输入成分"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="产地" prop="origin">
+        <el-input
+          v-model="queryParams.origin"
+          placeholder="请输入产地"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="时代" prop="era">
+        <el-input
+          v-model="queryParams.era"
+          placeholder="请输入时代"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="保存地层" prop="preservedLayer">
+        <el-input
+          v-model="queryParams.preservedLayer"
+          placeholder="请输入保存地层"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="陨石类型" prop="meteoriteType">
+        <el-input
+          v-model="queryParams.meteoriteType"
+          placeholder="请输入陨石类型"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="国际命名" prop="internationalName">
+        <el-input
+          v-model="queryParams.internationalName"
+          placeholder="请输入国际命名"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="发现时间" prop="discoveryTime">
+        <el-date-picker
+          v-model="queryParams.discoveryTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="降落时间" prop="fallTime">
+        <el-date-picker
+          v-model="queryParams.fallTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="保存类型(标本、光片、薄片模型及其他)" prop="preservationType">
+        <el-select
+          v-model="queryParams.preservationType"
+          placeholder="请选择保存类型(标本、光片、薄片模型及其他)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="尺寸" prop="size">
+        <el-input
+          v-model="queryParams.size"
+          placeholder="请输入尺寸"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="重量" prop="weight">
+        <el-input
+          v-model="queryParams.weight"
+          placeholder="请输入重量"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="来源(采购、捐赠、采集)" prop="source">
+        <el-select
+          v-model="queryParams.source"
+          placeholder="请选择来源(采购、捐赠、采集)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标本提供者(供应商、捐赠人、采集人)" prop="provider">
+        <el-input
+          v-model="queryParams.provider"
+          placeholder="请输入标本提供者(供应商、捐赠人、采集人)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="入藏时间(购买、捐赠、采集时间)" prop="acquisitionTime">
+        <el-date-picker
+          v-model="queryParams.acquisitionTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="用途" prop="purpose">
+        <el-input
+          v-model="queryParams.purpose"
+          placeholder="请输入用途"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="馆藏状态(在馆、借出)" prop="collectionStatus">
+        <el-select
+          v-model="queryParams.collectionStatus"
+          placeholder="请选择馆藏状态(在馆、借出)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MUSEUMS_SPECIMEN_INFO)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="notes">
+        <el-input
+          v-model="queryParams.notes"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="图片名称" prop="imageName">
+        <el-input
+          v-model="queryParams.imageName"
+          placeholder="请输入图片名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="图片路径" prop="imagePath">
+        <el-input
+          v-model="queryParams.imagePath"
+          placeholder="请输入图片路径"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="注销原因" prop="deletedReason">
+        <el-input
+          v-model="queryParams.deletedReason"
+          placeholder="请输入注销原因"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="入库操作员" prop="operator">
+        <el-input
+          v-model="queryParams.operator"
+          placeholder="请输入入库操作员"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="入库时间" prop="entryDate">
+        <el-date-picker
+          v-model="queryParams.entryDate"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['museums:specimen-info:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['museums:specimen-info:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="主键" align="center" prop="id" />
+      <el-table-column label="标本类型(矿物、岩石矿石、化石、陨石)" align="center" prop="specimenType">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MUSEUMS_SPECIMEN_INFO" :value="scope.row.specimenType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="标本编号" align="center" prop="specimenNumber" />
+      <el-table-column label="资产号" align="center" prop="assetNumber" />
+      <el-table-column label="存放位置" align="center" prop="storageLocation" />
+      <el-table-column label="中文名称" align="center" prop="chineseName" />
+      <el-table-column label="英文名称" align="center" prop="englishName" />
+      <el-table-column label="成分" align="center" prop="composition" />
+      <el-table-column label="产地" align="center" prop="origin" />
+      <el-table-column label="时代" align="center" prop="era" />
+      <el-table-column label="保存地层" align="center" prop="preservedLayer" />
+      <el-table-column label="陨石类型" align="center" prop="meteoriteType" />
+      <el-table-column label="国际命名" align="center" prop="internationalName" />
+      <el-table-column label="发现时间" align="center" prop="discoveryTime" />
+      <el-table-column label="降落时间" align="center" prop="fallTime" />
+      <el-table-column label="保存类型(标本、光片、薄片模型及其他)" align="center" prop="preservationType">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MUSEUMS_SPECIMEN_INFO" :value="scope.row.preservationType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="尺寸" align="center" prop="size" />
+      <el-table-column label="重量" align="center" prop="weight" />
+      <el-table-column label="来源(采购、捐赠、采集)" align="center" prop="source">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MUSEUMS_SPECIMEN_INFO" :value="scope.row.source" />
+        </template>
+      </el-table-column>
+      <el-table-column label="标本提供者(供应商、捐赠人、采集人)" align="center" prop="provider" />
+      <el-table-column label="入藏时间(购买、捐赠、采集时间)" align="center" prop="acquisitionTime" />
+      <el-table-column label="用途" align="center" prop="purpose" />
+      <el-table-column label="描述" align="center" prop="description" />
+      <el-table-column label="馆藏状态(在馆、借出)" align="center" prop="collectionStatus">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MUSEUMS_SPECIMEN_INFO" :value="scope.row.collectionStatus" />
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="notes" />
+      <el-table-column label="图片名称" align="center" prop="imageName" />
+      <el-table-column label="图片路径" align="center" prop="imagePath" />
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="注销原因" align="center" prop="deletedReason" />
+      <el-table-column label="入库操作员" align="center" prop="operator" />
+      <el-table-column
+        label="入库时间"
+        align="center"
+        prop="entryDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['museums:specimen-info:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['museums:specimen-info:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <SpecimenInfoForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { SpecimenInfoApi, SpecimenInfoVO } from '@/api/museums/specimeninfo'
+import SpecimenInfoForm from './SpecimenInfoForm.vue'
+
+/** 标本管理 列表 */
+defineOptions({ name: 'SpecimenInfo' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<SpecimenInfoVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  specimenType: undefined,
+  specimenNumber: undefined,
+  assetNumber: undefined,
+  storageLocation: undefined,
+  chineseName: undefined,
+  englishName: undefined,
+  composition: undefined,
+  origin: undefined,
+  era: undefined,
+  preservedLayer: undefined,
+  meteoriteType: undefined,
+  internationalName: undefined,
+  discoveryTime: [],
+  fallTime: [],
+  preservationType: undefined,
+  size: undefined,
+  weight: undefined,
+  source: undefined,
+  provider: undefined,
+  acquisitionTime: [],
+  purpose: undefined,
+  description: undefined,
+  collectionStatus: undefined,
+  notes: undefined,
+  imageName: undefined,
+  imagePath: undefined,
+  createTime: [],
+  deletedReason: undefined,
+  operator: undefined,
+  entryDate: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await SpecimenInfoApi.getSpecimenInfoPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await SpecimenInfoApi.deleteSpecimenInfo(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await SpecimenInfoApi.exportSpecimenInfo(queryParams)
+    download.excel(data, '标本管理.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 199 - 0
src/views/museums/specimenoutbound/SpecimenOutboundForm.vue

@@ -0,0 +1,199 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="关联到总表中的标本ID" prop="infoId">
+        <el-input v-model="formData.infoId" placeholder="请输入关联到总表中的标本ID" />
+      </el-form-item>
+      <el-form-item label="中文名称" prop="chineseName">
+        <el-input v-model="formData.chineseName" placeholder="请输入中文名称" />
+      </el-form-item>
+      <el-form-item label="申请出库的标本编号" prop="specimenNumber">
+        <el-input v-model="formData.specimenNumber" placeholder="请输入申请出库的标本编号" />
+      </el-form-item>
+      <el-form-item label="申请人或申请单位" prop="applicantName">
+        <el-input v-model="formData.applicantName" placeholder="请输入申请人或申请单位" />
+      </el-form-item>
+      <el-form-item label="申请日期" prop="applicationDate">
+        <el-date-picker
+          v-model="formData.applicationDate"
+          type="date"
+          value-format="x"
+          placeholder="选择申请日期"
+        />
+      </el-form-item>
+      <el-form-item label="申请出库的用途" prop="applicationUsage">
+        <el-input v-model="formData.applicationUsage" placeholder="请输入申请出库的用途" />
+      </el-form-item>
+      <el-form-item label="附件上传" prop="attachments">
+        <el-input v-model="formData.attachments" placeholder="请输入附件上传" />
+      </el-form-item>
+      <el-form-item label="审批状态" prop="status">
+        <el-select v-model="formData.status" placeholder="请选择审批状态">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注信息" prop="remarks">
+        <el-input v-model="formData.remarks" placeholder="请输入备注信息" />
+      </el-form-item>
+      <el-form-item label="流程实例的编号" prop="processInstanceId">
+        <el-input v-model="formData.processInstanceId" placeholder="请输入流程实例的编号" />
+      </el-form-item>
+      <el-form-item label="出库员" prop="operator">
+        <el-input v-model="formData.operator" placeholder="请输入出库员" />
+      </el-form-item>
+      <el-form-item label="出库时间" prop="outgoingTime">
+        <el-date-picker
+          v-model="formData.outgoingTime"
+          type="date"
+          value-format="x"
+          placeholder="选择出库时间"
+        />
+      </el-form-item>
+      <el-form-item label="退还人" prop="returner">
+        <el-input v-model="formData.returner" placeholder="请输入退还人" />
+      </el-form-item>
+      <el-form-item label="点收人" prop="receiver">
+        <el-input v-model="formData.receiver" placeholder="请输入点收人" />
+      </el-form-item>
+      <el-form-item label="退还日期" prop="returnDate">
+        <el-date-picker
+          v-model="formData.returnDate"
+          type="date"
+          value-format="x"
+          placeholder="选择退还日期"
+        />
+      </el-form-item>
+      <el-form-item label="标本情况" prop="specimenCondition">
+        <el-input v-model="formData.specimenCondition" placeholder="请输入标本情况" />
+      </el-form-item>
+      <el-form-item label="标本状态(已出库、已回库、出库审批中)" prop="sampleStatus">
+        <el-select v-model="formData.sampleStatus" placeholder="请选择标本状态(已出库、已回库、出库审批中)">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { SpecimenOutboundApi, SpecimenOutboundVO } from '@/api/museums/specimenoutbound'
+
+/** 标本出库回库信息 表单 */
+defineOptions({ name: 'SpecimenOutboundForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  infoId: undefined,
+  chineseName: undefined,
+  specimenNumber: undefined,
+  applicantName: undefined,
+  applicationDate: undefined,
+  applicationUsage: undefined,
+  attachments: undefined,
+  status: undefined,
+  remarks: undefined,
+  processInstanceId: undefined,
+  operator: undefined,
+  outgoingTime: undefined,
+  returner: undefined,
+  receiver: undefined,
+  returnDate: undefined,
+  specimenCondition: undefined,
+  sampleStatus: undefined
+})
+const formRules = reactive({
+  infoId: [{ required: true, message: '关联到总表中的标本ID不能为空', trigger: 'blur' }],
+  chineseName: [{ required: true, message: '中文名称不能为空', trigger: 'blur' }],
+  specimenNumber: [{ required: true, message: '申请出库的标本编号不能为空', trigger: 'blur' }],
+  applicantName: [{ required: true, message: '申请人或申请单位不能为空', trigger: 'blur' }],
+  applicationUsage: [{ required: true, message: '申请出库的用途不能为空', trigger: 'blur' }],
+  operator: [{ required: true, message: '出库员不能为空', trigger: 'blur' }],
+  returner: [{ required: true, message: '退还人不能为空', trigger: 'blur' }],
+  receiver: [{ required: true, message: '点收人不能为空', trigger: 'blur' }],
+  returnDate: [{ required: true, message: '退还日期不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await SpecimenOutboundApi.getSpecimenOutbound(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as SpecimenOutboundVO
+    if (formType.value === 'create') {
+      await SpecimenOutboundApi.createSpecimenOutbound(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await SpecimenOutboundApi.updateSpecimenOutbound(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    infoId: undefined,
+    chineseName: undefined,
+    specimenNumber: undefined,
+    applicantName: undefined,
+    applicationDate: undefined,
+    applicationUsage: undefined,
+    attachments: undefined,
+    status: undefined,
+    remarks: undefined,
+    processInstanceId: undefined,
+    operator: undefined,
+    outgoingTime: undefined,
+    returner: undefined,
+    receiver: undefined,
+    returnDate: undefined,
+    specimenCondition: undefined,
+    sampleStatus: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 389 - 0
src/views/museums/specimenoutbound/index.vue

@@ -0,0 +1,389 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="关联到总表中的标本ID" prop="infoId">
+        <el-input
+          v-model="queryParams.infoId"
+          placeholder="请输入关联到总表中的标本ID"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="中文名称" prop="chineseName">
+        <el-input
+          v-model="queryParams.chineseName"
+          placeholder="请输入中文名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="申请出库的标本编号" prop="specimenNumber">
+        <el-input
+          v-model="queryParams.specimenNumber"
+          placeholder="请输入申请出库的标本编号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="申请人或申请单位" prop="applicantName">
+        <el-input
+          v-model="queryParams.applicantName"
+          placeholder="请输入申请人或申请单位"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="申请日期" prop="applicationDate">
+        <el-date-picker
+          v-model="queryParams.applicationDate"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="申请出库的用途" prop="applicationUsage">
+        <el-input
+          v-model="queryParams.applicationUsage"
+          placeholder="请输入申请出库的用途"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="附件上传" prop="attachments">
+        <el-input
+          v-model="queryParams.attachments"
+          placeholder="请输入附件上传"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="审批状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择审批状态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注信息" prop="remarks">
+        <el-input
+          v-model="queryParams.remarks"
+          placeholder="请输入备注信息"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="流程实例的编号" prop="processInstanceId">
+        <el-input
+          v-model="queryParams.processInstanceId"
+          placeholder="请输入流程实例的编号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="出库员" prop="operator">
+        <el-input
+          v-model="queryParams.operator"
+          placeholder="请输入出库员"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="出库时间" prop="outgoingTime">
+        <el-date-picker
+          v-model="queryParams.outgoingTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="退还人" prop="returner">
+        <el-input
+          v-model="queryParams.returner"
+          placeholder="请输入退还人"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="点收人" prop="receiver">
+        <el-input
+          v-model="queryParams.receiver"
+          placeholder="请输入点收人"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="退还日期" prop="returnDate">
+        <el-date-picker
+          v-model="queryParams.returnDate"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="标本情况" prop="specimenCondition">
+        <el-input
+          v-model="queryParams.specimenCondition"
+          placeholder="请输入标本情况"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="标本状态(已出库、已回库、出库审批中)" prop="sampleStatus">
+        <el-select
+          v-model="queryParams.sampleStatus"
+          placeholder="请选择标本状态(已出库、已回库、出库审批中)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['museums:specimen-outbound:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['museums:specimen-outbound:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="主键" align="center" prop="id" />
+      <el-table-column label="关联到总表中的标本ID" align="center" prop="infoId" />
+      <el-table-column label="中文名称" align="center" prop="chineseName" />
+      <el-table-column label="申请出库的标本编号" align="center" prop="specimenNumber" />
+      <el-table-column label="申请人或申请单位" align="center" prop="applicantName" />
+      <el-table-column
+        label="申请日期"
+        align="center"
+        prop="applicationDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="申请出库的用途" align="center" prop="applicationUsage" />
+      <el-table-column label="附件上传" align="center" prop="attachments" />
+      <el-table-column label="审批状态" align="center" prop="status" />
+      <el-table-column label="备注信息" align="center" prop="remarks" />
+      <el-table-column label="流程实例的编号" align="center" prop="processInstanceId" />
+      <el-table-column label="出库员" align="center" prop="operator" />
+      <el-table-column
+        label="出库时间"
+        align="center"
+        prop="outgoingTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="退还人" align="center" prop="returner" />
+      <el-table-column label="点收人" align="center" prop="receiver" />
+      <el-table-column
+        label="退还日期"
+        align="center"
+        prop="returnDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="标本情况" align="center" prop="specimenCondition" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="标本状态(已出库、已回库、出库审批中)" align="center" prop="sampleStatus" />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['museums:specimen-outbound:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['museums:specimen-outbound:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <SpecimenOutboundForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { SpecimenOutboundApi, SpecimenOutboundVO } from '@/api/museums/specimenoutbound'
+import SpecimenOutboundForm from './SpecimenOutboundForm.vue'
+
+/** 标本出库回库信息 列表 */
+defineOptions({ name: 'SpecimenOutbound' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<SpecimenOutboundVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  infoId: undefined,
+  chineseName: undefined,
+  specimenNumber: undefined,
+  applicantName: undefined,
+  applicationDate: [],
+  applicationUsage: undefined,
+  attachments: undefined,
+  status: undefined,
+  remarks: undefined,
+  processInstanceId: undefined,
+  operator: undefined,
+  outgoingTime: [],
+  returner: undefined,
+  receiver: undefined,
+  returnDate: [],
+  specimenCondition: undefined,
+  createTime: [],
+  sampleStatus: undefined
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await SpecimenOutboundApi.getSpecimenOutboundPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await SpecimenOutboundApi.deleteSpecimenOutbound(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await SpecimenOutboundApi.exportSpecimenOutbound(queryParams)
+    download.excel(data, '标本出库回库信息.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 0 - 1
src/views/pay/app/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="支付功能开启" url="https://doc.iocoder.cn/pay/build/" />
   <!-- 搜索 -->
   <ContentWrap>
     <el-form

+ 0 - 4
src/views/pay/demo/order/index.vue

@@ -1,8 +1,4 @@
 <template>
-  <doc-alert title="支付宝支付接入" url="https://doc.iocoder.cn/pay/alipay-pay-demo/" />
-  <doc-alert title="支付宝、微信退款接入" url="https://doc.iocoder.cn/pay/refund-demo/" />
-  <doc-alert title="微信公众号支付接入" url="https://doc.iocoder.cn/pay/wx-pub-pay-demo/" />
-  <doc-alert title="微信小程序支付接入" url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/" />
 
   <!-- 操作工具栏 -->
   <el-row :gutter="10" class="mb8">

+ 0 - 1
src/views/pay/notify/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="支付功能开启" url="https://doc.iocoder.cn/pay/build/" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 3
src/views/pay/order/index.vue

@@ -1,7 +1,4 @@
 <template>
-  <doc-alert title="支付宝支付接入" url="https://doc.iocoder.cn/pay/alipay-pay-demo/" />
-  <doc-alert title="微信公众号支付接入" url="https://doc.iocoder.cn/pay/wx-pub-pay-demo/" />
-  <doc-alert title="微信小程序支付接入" url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/" />
 
   <ContentWrap>
     <el-form

+ 0 - 1
src/views/pay/refund/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="支付宝、微信退款接入" url="https://doc.iocoder.cn/pay/refund-demo/" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 1
src/views/report/goview/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="大屏设计器" url="https://doc.iocoder.cn/report/screen/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame :src="src" />

+ 0 - 1
src/views/report/jmreport/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="报表设计器" url="https://doc.iocoder.cn/report/" />
 
   <ContentWrap :bodyStyle="{ padding: '0px' }" class="!mb-0">
     <IFrame :src="src" />

+ 0 - 1
src/views/system/area/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="地区 & IP" url="https://doc.iocoder.cn/area-and-ip/" />
 
   <!-- 操作栏 -->
   <ContentWrap>

+ 0 - 1
src/views/system/loginlog/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="系统日志" url="https://doc.iocoder.cn/system-log/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/mail/account/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="邮件配置" url="https://doc.iocoder.cn/mail" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 1
src/views/system/mail/log/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="邮件配置" url="https://doc.iocoder.cn/mail" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 1
src/views/system/mail/template/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="邮件配置" url="https://doc.iocoder.cn/mail" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 2
src/views/system/menu/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
-  <doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue3/route/" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 2
src/views/system/notify/message/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" />
-
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form

+ 0 - 1
src/views/system/notify/my/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/notify/template/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" />
 
   <!-- 搜索工作栏 -->
   <ContentWrap>

+ 0 - 2
src/views/system/oauth2/client/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="OAuth 2.0(SSO 单点登录)" url="https://doc.iocoder.cn/oauth2/" />
-
   <!-- 搜索 -->
   <ContentWrap>
     <el-form

+ 0 - 1
src/views/system/oauth2/token/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="OAuth 2.0(SSO 单点登录)" url="https://doc.iocoder.cn/oauth2/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/operatelog/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="系统日志" url="https://doc.iocoder.cn/system-log/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 2
src/views/system/role/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
-  <doc-alert title="数据权限" url="https://doc.iocoder.cn/data-permission" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/sms/channel/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="短信配置" url="https://doc.iocoder.cn/sms/" />
 
   <ContentWrap>
     <el-form

+ 0 - 1
src/views/system/sms/log/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="短信配置" url="https://doc.iocoder.cn/sms/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/sms/template/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="短信配置" url="https://doc.iocoder.cn/sms/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 1
src/views/system/social/client/index.vue

@@ -1,5 +1,4 @@
 <template>
-  <doc-alert title="三方登录" url="https://doc.iocoder.cn/social-user/" />
 
   <ContentWrap>
     <!-- 搜索工作栏 -->

+ 0 - 2
src/views/system/social/user/index.vue

@@ -1,6 +1,4 @@
 <template>
-  <doc-alert title="三方登录" url="https://doc.iocoder.cn/social-user/" />
-
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form

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

@@ -1,5 +1,5 @@
 <template>
-  <doc-alert title="SaaS 多租户" url="https://doc.iocoder.cn/saas-tenant/" />
+<!--  <doc-alert title="SaaS 多租户" url="https://doc.iocoder.cn/saas-tenant/" />-->
 
   <!-- 搜索 -->
   <ContentWrap>

+ 1 - 1
src/views/system/tenantPackage/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <doc-alert title="SaaS 多租户" url="https://doc.iocoder.cn/saas-tenant/" />
+<!--  <doc-alert title="SaaS 多租户" url="https://doc.iocoder.cn/saas-tenant/" />-->
 
   <!-- 搜索 -->
   <ContentWrap>

+ 0 - 3
src/views/system/user/index.vue

@@ -1,7 +1,4 @@
 <template>
-  <doc-alert title="用户体系" url="https://doc.iocoder.cn/user-center/" />
-  <doc-alert title="三方登陆" url="https://doc.iocoder.cn/social-user/" />
-  <doc-alert title="Excel 导入导出" url="https://doc.iocoder.cn/excel-import-and-export/" />
 
   <el-row :gutter="20">
     <!-- 左侧部门树 -->