Browse Source

Merge remote-tracking branch 'origin/master'

lipenghui 3 weeks ago
parent
commit
c5651dba61
28 changed files with 3668 additions and 199 deletions
  1. 59 0
      src/api/pms/iotdailyreportattrs/index.ts
  2. 49 0
      src/api/pms/iotdailyreporttemplate/index.ts
  3. 55 0
      src/api/pms/iotprojectdailyreport/index.ts
  4. 8 0
      src/api/pms/iotprojecttaskattrs/index.ts
  5. 50 49
      src/api/pms/iotprojecttasktemplate/index.ts
  6. 66 0
      src/api/pms/iotrhdailyreport/index.ts
  7. 2 1
      src/locales/en.ts
  8. 2 1
      src/locales/ru.ts
  9. 2 1
      src/locales/zh-CN.ts
  10. 25 0
      src/router/modules/remaining.ts
  11. 192 0
      src/views/pms/iotdailyreportattrs/IotDailyReportAttrsForm.vue
  12. 399 0
      src/views/pms/iotdailyreportattrs/index.vue
  13. 140 0
      src/views/pms/iotdailyreporttemplate/IotDailyReportTemplateForm.vue
  14. 288 0
      src/views/pms/iotdailyreporttemplate/index.vue
  15. 184 0
      src/views/pms/iotprojectdailyreport/IotProjectDailyReportForm.vue
  16. 372 0
      src/views/pms/iotprojectdailyreport/index.vue
  17. 30 35
      src/views/pms/iotprojecttask/IotProjectTaskForm.vue
  18. 227 0
      src/views/pms/iotprojecttasktemplate/detail/TaskAttrModelForm.vue
  19. 108 0
      src/views/pms/iotprojecttasktemplate/detail/TaskAttrModelProperty.vue
  20. 112 0
      src/views/pms/iotprojecttasktemplate/detail/config.ts
  21. 172 0
      src/views/pms/iotprojecttasktemplate/detail/dataSpec/TaskAttrModelDropdownDataSpecs.vue
  22. 104 0
      src/views/pms/iotprojecttasktemplate/detail/dataSpec/TaskAttrModelNumberDataSpecs.vue
  23. 196 0
      src/views/pms/iotprojecttasktemplate/detail/index.vue
  24. 26 86
      src/views/pms/iotprojecttasktemplate/index.vue
  25. 259 0
      src/views/pms/iotrhdailyreport/IotRhDailyReportForm.vue
  26. 501 0
      src/views/pms/iotrhdailyreport/index.vue
  27. 20 13
      src/views/pms/maintenance/IotMaintenancePlan.vue
  28. 20 13
      src/views/pms/maintenance/IotMaintenancePlanEdit.vue

+ 59 - 0
src/api/pms/iotdailyreportattrs/index.ts

@@ -0,0 +1,59 @@
+import request from '@/config/axios'
+
+// 日报扩展模板属性 VO
+export interface IotDailyReportAttrsVO {
+  id: number // 主键id
+  templateId: number // 日报扩展模板id
+  deptId: number // 公司id
+  projectId: number // 项目id
+  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂 ...)
+  wellType: string // 井型
+  wellCategory: string // 井别
+  technique: string // 施工工艺
+  name: string // 属性名称
+  identifier: string // 属性标识符
+  dataType: string // 数据类型(double text textarea date dropdown)
+  required: number // 是否必填(0非必填 1必填)
+  unit: string // 单位(MPa)
+  accessMode: string // 访问模式(r读  w写)
+  defaultValue: string // 默认值
+  maxValue: string // 最大值
+  minValue: string // 最小值
+  extProperty: string // 不同专业公司的扩展属性
+  sort: number // 排序值
+  remark: string // 备注
+  status: number // 状态(0启用 1禁用)
+}
+
+// 日报扩展模板属性 API
+export const IotDailyReportAttrsApi = {
+  // 查询日报扩展模板属性分页
+  getIotDailyReportAttrsPage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-daily-report-attrs/page`, params })
+  },
+
+  // 查询日报扩展模板属性详情
+  getIotDailyReportAttrs: async (id: number) => {
+    return await request.get({ url: `/rq/iot-daily-report-attrs/get?id=` + id })
+  },
+
+  // 新增日报扩展模板属性
+  createIotDailyReportAttrs: async (data: IotDailyReportAttrsVO) => {
+    return await request.post({ url: `/rq/iot-daily-report-attrs/create`, data })
+  },
+
+  // 修改日报扩展模板属性
+  updateIotDailyReportAttrs: async (data: IotDailyReportAttrsVO) => {
+    return await request.put({ url: `/rq/iot-daily-report-attrs/update`, data })
+  },
+
+  // 删除日报扩展模板属性
+  deleteIotDailyReportAttrs: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-daily-report-attrs/delete?id=` + id })
+  },
+
+  // 导出日报扩展模板属性 Excel
+  exportIotDailyReportAttrs: async (params) => {
+    return await request.download({ url: `/rq/iot-daily-report-attrs/export-excel`, params })
+  },
+}

+ 49 - 0
src/api/pms/iotdailyreporttemplate/index.ts

@@ -0,0 +1,49 @@
+import request from '@/config/axios'
+
+// 生产日报属性模板 VO
+export interface IotDailyReportTemplateVO {
+  id: number // 主键id
+  deptId: number // 公司id
+  projectId: number // 项目id
+  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂...)
+  wellType: string // 井型
+  wellCategory: string // 井别
+  technique: string // 施工工艺
+  name: string // 模板名称
+  identifier: string // 模板标识符
+  remark: string // 备注
+  status: number // 状态(0启用 1禁用)
+}
+
+// 生产日报属性模板 API
+export const IotDailyReportTemplateApi = {
+  // 查询生产日报属性模板分页
+  getIotDailyReportTemplatePage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-daily-report-template/page`, params })
+  },
+
+  // 查询生产日报属性模板详情
+  getIotDailyReportTemplate: async (id: number) => {
+    return await request.get({ url: `/rq/iot-daily-report-template/get?id=` + id })
+  },
+
+  // 新增生产日报属性模板
+  createIotDailyReportTemplate: async (data: IotDailyReportTemplateVO) => {
+    return await request.post({ url: `/rq/iot-daily-report-template/create`, data })
+  },
+
+  // 修改生产日报属性模板
+  updateIotDailyReportTemplate: async (data: IotDailyReportTemplateVO) => {
+    return await request.put({ url: `/rq/iot-daily-report-template/update`, data })
+  },
+
+  // 删除生产日报属性模板
+  deleteIotDailyReportTemplate: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-daily-report-template/delete?id=` + id })
+  },
+
+  // 导出生产日报属性模板 Excel
+  exportIotDailyReportTemplate: async (params) => {
+    return await request.download({ url: `/rq/iot-daily-report-template/export-excel`, params })
+  },
+}

+ 55 - 0
src/api/pms/iotprojectdailyreport/index.ts

@@ -0,0 +1,55 @@
+import request from '@/config/axios'
+
+// 项目日报 VO
+export interface IotProjectDailyReportVO {
+  id: number // 主键id
+  deptId: number // 施工队伍id
+  projectId: number // 项目id
+  taskId: number // 任务id
+  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂... )
+  constructionStartDate: Date // 施工开始日期
+  constructionEndDate: Date // 施工结束日期
+  nextPlan: string // 下步工作计划
+  productionStatus: string // 当日生产情况生产动态
+  constructionStatus: number // 施工状态(数据字典)
+  personnel: string // 人员情况
+  extProperty: string // 不同专业公司的扩展属性值
+  sort: number // 排序值
+  remark: string // 备注
+  status: number // 状态(0启用 1禁用)
+  processInstanceId: string // 流程实例id
+  auditStatus: number // 审批状态 未提交、审批中、审批通过、审批不通过、已取消
+}
+
+// 项目日报 API
+export const IotProjectDailyReportApi = {
+  // 查询项目日报分页
+  getIotProjectDailyReportPage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-project-daily-report/page`, params })
+  },
+
+  // 查询项目日报详情
+  getIotProjectDailyReport: async (id: number) => {
+    return await request.get({ url: `/rq/iot-project-daily-report/get?id=` + id })
+  },
+
+  // 新增项目日报
+  createIotProjectDailyReport: async (data: IotProjectDailyReportVO) => {
+    return await request.post({ url: `/rq/iot-project-daily-report/create`, data })
+  },
+
+  // 修改项目日报
+  updateIotProjectDailyReport: async (data: IotProjectDailyReportVO) => {
+    return await request.put({ url: `/rq/iot-project-daily-report/update`, data })
+  },
+
+  // 删除项目日报
+  deleteIotProjectDailyReport: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-project-daily-report/delete?id=` + id })
+  },
+
+  // 导出项目日报 Excel
+  exportIotProjectDailyReport: async (params) => {
+    return await request.download({ url: `/rq/iot-project-daily-report/export-excel`, params })
+  },
+}

+ 8 - 0
src/api/pms/iotprojecttaskattrs/index.ts

@@ -12,11 +12,19 @@ export interface IotProjectTaskAttrsVO {
   technique: string // 施工工艺
   name: string // 属性名称
   identifier: string // 属性标识符
+  dataType: string  // 数据类型
   extProperty: string // 不同专业公司的扩展属性
   remark: string // 备注
   status: number // 施工状态(工作量开始/动迁/准备/施工)
 }
 
+/**
+ * 项目任务扩展属性 类型
+ */
+export interface TaskTemplateAttrs {
+  [key: string]: any
+}
+
 // 项目任务扩展属性 API
 export const IotProjectTaskAttrsApi = {
   // 查询项目任务扩展属性分页

+ 50 - 49
src/api/pms/iotprojecttasktemplate/index.ts

@@ -1,49 +1,50 @@
-import request from '@/config/axios'
-
-// 项目任务属性模板 VO
-export interface IotProjectTaskTemplateVO {
-  id: number // 主键id
-  deptId: number // 公司id
-  projectId: number // 项目id
-  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂 )
-  wellType: string // 井型
-  wellCategory: string // 井别
-  technique: string // 施工工艺
-  name: string // 模板名称
-  identifier: string // 模板标识符
-  remark: string // 备注
-  status: number // 施工状态(工作量开始/动迁/准备/施工)
-}
-
-// 项目任务属性模板 API
-export const IotProjectTaskTemplateApi = {
-  // 查询项目任务属性模板分页
-  getIotProjectTaskTemplatePage: async (params: any) => {
-    return await request.get({ url: `/rq/iot-project-task-template/page`, params })
-  },
-
-  // 查询项目任务属性模板详情
-  getIotProjectTaskTemplate: async (id: number) => {
-    return await request.get({ url: `/rq/iot-project-task-template/get?id=` + id })
-  },
-
-  // 新增项目任务属性模板
-  createIotProjectTaskTemplate: async (data: IotProjectTaskTemplateVO) => {
-    return await request.post({ url: `/rq/iot-project-task-template/create`, data })
-  },
-
-  // 修改项目任务属性模板
-  updateIotProjectTaskTemplate: async (data: IotProjectTaskTemplateVO) => {
-    return await request.put({ url: `/rq/iot-project-task-template/update`, data })
-  },
-
-  // 删除项目任务属性模板
-  deleteIotProjectTaskTemplate: async (id: number) => {
-    return await request.delete({ url: `/rq/iot-project-task-template/delete?id=` + id })
-  },
-
-  // 导出项目任务属性模板 Excel
-  exportIotProjectTaskTemplate: async (params) => {
-    return await request.download({ url: `/rq/iot-project-task-template/export-excel`, params })
-  },
-}
+import request from '@/config/axios'
+
+// 项目任务属性模板 VO
+export interface IotProjectTaskTemplateVO {
+  id: number // 主键id
+  deptId: number // 公司id
+  deptName: string  // 公司名称
+  projectId: number // 项目id
+  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂 )
+  wellType: string // 井型
+  wellCategory: string // 井别
+  technique: string // 施工工艺
+  name: string // 模板名称
+  identifier: string // 模板标识符
+  remark: string // 备注
+  status: number // 施工状态(工作量开始/动迁/准备/施工)
+}
+
+// 项目任务属性模板 API
+export const IotProjectTaskTemplateApi = {
+  // 查询项目任务属性模板分页
+  getIotProjectTaskTemplatePage: async (params: any) => {
+    return await request.get({ url: `/rq/iot-project-task-template/page`, params })
+  },
+
+  // 查询项目任务属性模板详情
+  getIotProjectTaskTemplate: async (id: number) => {
+    return await request.get({ url: `/rq/iot-project-task-template/get?id=` + id })
+  },
+
+  // 新增项目任务属性模板
+  createIotProjectTaskTemplate: async (data: IotProjectTaskTemplateVO) => {
+    return await request.post({ url: `/rq/iot-project-task-template/create`, data })
+  },
+
+  // 修改项目任务属性模板
+  updateIotProjectTaskTemplate: async (data: IotProjectTaskTemplateVO) => {
+    return await request.put({ url: `/rq/iot-project-task-template/update`, data })
+  },
+
+  // 删除项目任务属性模板
+  deleteIotProjectTaskTemplate: async (id: number) => {
+    return await request.delete({ url: `/rq/iot-project-task-template/delete?id=` + id })
+  },
+
+  // 导出项目任务属性模板 Excel
+  exportIotProjectTaskTemplate: async (params) => {
+    return await request.download({ url: `/rq/iot-project-task-template/export-excel`, params })
+  },
+}

+ 66 - 0
src/api/pms/iotrhdailyreport/index.ts

@@ -0,0 +1,66 @@
+import request from '@/config/axios'
+
+// 瑞恒日报 VO
+export interface IotRhDailyReportVO {
+  id: number // 主键id
+  deptId: number // 施工队伍id
+  projectId: number // 项目id
+  taskId: number // 任务id
+  projectClassification: string // 项目类别(钻井 修井 注氮 酸化压裂... )
+  relocationDays: number // 搬迁安装天数
+  transitTime: number // 运行时效
+  dailyGasInjection: number // 当日注气量(万方)
+  dailyWaterInjection: number // 当日注水量(方)
+  dailyInjectGasTime: number // 当日注气时间(H)
+  dailyInjectWaterTime: number // 当日注水时间(H)
+  nonProductionTime: number // 非生产时间(H)
+  nptReason: string // 非生产时间原因
+  constructionStartDate: Date // 施工开始日期
+  constructionEndDate: Date // 施工结束日期
+  productionStatus: string // 当日生产情况生产动态
+  nextPlan: string // 下步工作计划
+  constructionStatus: number // 施工状态(动迁 准备 施工 完工)
+  personnel: string // 人员情况
+  totalGasInjection: number // 累计注气量(万方)
+  totalWaterInjection: number // 累计注水量(方)
+  cumulativeCompletion: number // 累计完工井次
+  extProperty: string // 不同专业公司的扩展属性值
+  sort: number // 排序值
+  remark: string // 备注
+  status: number // 状态(0启用 1禁用)
+  processInstanceId: string // 流程实例id
+  auditStatus: number // 审批状态 未提交、审批中、审批通过、审批不通过、已取消
+}
+
+// 瑞恒日报 API
+export const IotRhDailyReportApi = {
+  // 查询瑞恒日报分页
+  getIotRhDailyReportPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-rh-daily-report/page`, params })
+  },
+
+  // 查询瑞恒日报详情
+  getIotRhDailyReport: async (id: number) => {
+    return await request.get({ url: `/pms/iot-rh-daily-report/get?id=` + id })
+  },
+
+  // 新增瑞恒日报
+  createIotRhDailyReport: async (data: IotRhDailyReportVO) => {
+    return await request.post({ url: `/pms/iot-rh-daily-report/create`, data })
+  },
+
+  // 修改瑞恒日报
+  updateIotRhDailyReport: async (data: IotRhDailyReportVO) => {
+    return await request.put({ url: `/pms/iot-rh-daily-report/update`, data })
+  },
+
+  // 删除瑞恒日报
+  deleteIotRhDailyReport: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-rh-daily-report/delete?id=` + id })
+  },
+
+  // 导出瑞恒日报 Excel
+  exportIotRhDailyReport: async (params) => {
+    return await request.download({ url: `/pms/iot-rh-daily-report/export-excel`, params })
+  },
+}

+ 2 - 1
src/locales/en.ts

@@ -265,7 +265,8 @@ export default {
     wellType: 'Well Type',
     wellCategory: 'Well Category',
     technology: 'Technology',
-    status: 'status'
+    status: 'status',
+    taskAttrDetail: 'Attr Detail',
   },
   form: {
     input: 'Input',

+ 2 - 1
src/locales/ru.ts

@@ -230,7 +230,8 @@ export default {
     wellType: '井型',
     wellCategory: '井别',
     technology: '施工工艺',
-    status: '施工状态'
+    status: '施工状态',
+    taskAttrDetail: '任务属性详情',
   },
   form: {
     input: '输入框',

+ 2 - 1
src/locales/zh-CN.ts

@@ -268,7 +268,8 @@ export default {
     wellCategory: '井别',
     technology: '施工工艺',
     unit: '工作量单位',
-    status: '施工状态'
+    status: '施工状态',
+    taskAttrDetail: '任务属性详情',
   },
   form: {
     input: '输入框',

+ 25 - 0
src/router/modules/remaining.ts

@@ -116,6 +116,31 @@ const remainingRouter: AppRouteRecordRaw[] = [
     ]
   },
 
+  {
+    path: '/projectTaskAttrsTemplate',
+    component: Layout,
+    name: 'TaskAttrsTemplateCenter',
+    meta: {
+      hidden: true,
+      keepAlive: true
+    },
+    children: [
+      {
+        path: 'template/attrs/:deptId/:templateName/:deptName',
+        component: () => import('@/views/pms/iotprojecttasktemplate/detail/index.vue'),
+        name: 'ProjectTaskTemplateAttrs',
+        meta: {
+          keepAlive: true,
+          title: t('project.taskAttrDetail'),
+          noCache: false,
+          hidden: true,
+          canTo: true,
+          activeMenu: '/template/info'
+        }
+      },
+    ]
+  },
+
   {
     path: '/devicecategoryboms',
     component: Layout,

+ 192 - 0
src/views/pms/iotdailyreportattrs/IotDailyReportAttrsForm.vue

@@ -0,0 +1,192 @@
+<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="templateId">
+        <el-input v-model="formData.templateId" placeholder="请输入日报扩展模板id" />
+      </el-form-item>
+      <el-form-item label="公司id" prop="deptId">
+        <el-input v-model="formData.deptId" placeholder="请输入公司id" />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input v-model="formData.projectId" placeholder="请输入项目id" />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂 ...)" prop="projectClassification">
+        <el-input v-model="formData.projectClassification" placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂 ...)" />
+      </el-form-item>
+      <el-form-item label="井型" prop="wellType">
+        <el-select v-model="formData.wellType" placeholder="请选择井型">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="井别" prop="wellCategory">
+        <el-input v-model="formData.wellCategory" placeholder="请输入井别" />
+      </el-form-item>
+      <el-form-item label="施工工艺" prop="technique">
+        <el-input v-model="formData.technique" placeholder="请输入施工工艺" />
+      </el-form-item>
+      <el-form-item label="属性名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入属性名称" />
+      </el-form-item>
+      <el-form-item label="属性标识符" prop="identifier">
+        <el-input v-model="formData.identifier" placeholder="请输入属性标识符" />
+      </el-form-item>
+      <el-form-item label="数据类型(double text textarea date dropdown)" prop="dataType">
+        <el-select v-model="formData.dataType" placeholder="请选择数据类型(double text textarea date dropdown)">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否必填(0非必填 1必填)" prop="required">
+        <el-input v-model="formData.required" placeholder="请输入是否必填(0非必填 1必填)" />
+      </el-form-item>
+      <el-form-item label="单位(MPa)" prop="unit">
+        <el-input v-model="formData.unit" placeholder="请输入单位(MPa)" />
+      </el-form-item>
+      <el-form-item label="访问模式(r读  w写)" prop="accessMode">
+        <el-input v-model="formData.accessMode" placeholder="请输入访问模式(r读  w写)" />
+      </el-form-item>
+      <el-form-item label="默认值" prop="defaultValue">
+        <el-input v-model="formData.defaultValue" placeholder="请输入默认值" />
+      </el-form-item>
+      <el-form-item label="最大值" prop="maxValue">
+        <el-input v-model="formData.maxValue" placeholder="请输入最大值" />
+      </el-form-item>
+      <el-form-item label="最小值" prop="minValue">
+        <el-input v-model="formData.minValue" placeholder="请输入最小值" />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性" prop="extProperty">
+        <el-input v-model="formData.extProperty" placeholder="请输入不同专业公司的扩展属性" />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input v-model="formData.sort" placeholder="请输入排序值" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </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 { IotDailyReportAttrsApi, IotDailyReportAttrsVO } from '@/api/pms/iotdailyreportattrs'
+
+/** 日报扩展模板属性 表单 */
+defineOptions({ name: 'IotDailyReportAttrsForm' })
+
+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,
+  templateId: undefined,
+  deptId: undefined,
+  projectId: undefined,
+  projectClassification: undefined,
+  wellType: undefined,
+  wellCategory: undefined,
+  technique: undefined,
+  name: undefined,
+  identifier: undefined,
+  dataType: undefined,
+  required: undefined,
+  unit: undefined,
+  accessMode: undefined,
+  defaultValue: undefined,
+  maxValue: undefined,
+  minValue: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+})
+const formRules = reactive({
+})
+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 IotDailyReportAttrsApi.getIotDailyReportAttrs(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 IotDailyReportAttrsVO
+    if (formType.value === 'create') {
+      await IotDailyReportAttrsApi.createIotDailyReportAttrs(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotDailyReportAttrsApi.updateIotDailyReportAttrs(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    templateId: undefined,
+    deptId: undefined,
+    projectId: undefined,
+    projectClassification: undefined,
+    wellType: undefined,
+    wellCategory: undefined,
+    technique: undefined,
+    name: undefined,
+    identifier: undefined,
+    dataType: undefined,
+    required: undefined,
+    unit: undefined,
+    accessMode: undefined,
+    defaultValue: undefined,
+    maxValue: undefined,
+    minValue: undefined,
+    extProperty: undefined,
+    sort: undefined,
+    remark: undefined,
+    status: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 399 - 0
src/views/pms/iotdailyreportattrs/index.vue

@@ -0,0 +1,399 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="日报扩展模板id" prop="templateId">
+        <el-input
+          v-model="queryParams.templateId"
+          placeholder="请输入日报扩展模板id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="公司id" prop="deptId">
+        <el-input
+          v-model="queryParams.deptId"
+          placeholder="请输入公司id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input
+          v-model="queryParams.projectId"
+          placeholder="请输入项目id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂 ...)" prop="projectClassification">
+        <el-input
+          v-model="queryParams.projectClassification"
+          placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂 ...)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="井型" prop="wellType">
+        <el-select
+          v-model="queryParams.wellType"
+          placeholder="请选择井型"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="井别" prop="wellCategory">
+        <el-input
+          v-model="queryParams.wellCategory"
+          placeholder="请输入井别"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="施工工艺" prop="technique">
+        <el-input
+          v-model="queryParams.technique"
+          placeholder="请输入施工工艺"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="属性名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入属性名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="属性标识符" prop="identifier">
+        <el-input
+          v-model="queryParams.identifier"
+          placeholder="请输入属性标识符"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="数据类型(double text textarea date dropdown)" prop="dataType">
+        <el-select
+          v-model="queryParams.dataType"
+          placeholder="请选择数据类型(double text textarea date dropdown)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否必填(0非必填 1必填)" prop="required">
+        <el-input
+          v-model="queryParams.required"
+          placeholder="请输入是否必填(0非必填 1必填)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="单位(MPa)" prop="unit">
+        <el-input
+          v-model="queryParams.unit"
+          placeholder="请输入单位(MPa)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="访问模式(r读  w写)" prop="accessMode">
+        <el-input
+          v-model="queryParams.accessMode"
+          placeholder="请输入访问模式(r读  w写)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="默认值" prop="defaultValue">
+        <el-input
+          v-model="queryParams.defaultValue"
+          placeholder="请输入默认值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="最大值" prop="maxValue">
+        <el-input
+          v-model="queryParams.maxValue"
+          placeholder="请输入最大值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="最小值" prop="minValue">
+        <el-input
+          v-model="queryParams.minValue"
+          placeholder="请输入最小值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性" prop="extProperty">
+        <el-input
+          v-model="queryParams.extProperty"
+          placeholder="请输入不同专业公司的扩展属性"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input
+          v-model="queryParams.sort"
+          placeholder="请输入排序值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态(0启用 1禁用)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </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="['rq:iot-daily-report-attrs:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['rq:iot-daily-report-attrs: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="主键id" align="center" prop="id" />
+      <el-table-column label="日报扩展模板id" align="center" prop="templateId" />
+      <el-table-column label="公司id" align="center" prop="deptId" />
+      <el-table-column label="项目id" align="center" prop="projectId" />
+      <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂 ...)" align="center" prop="projectClassification" />
+      <el-table-column label="井型" align="center" prop="wellType" />
+      <el-table-column label="井别" align="center" prop="wellCategory" />
+      <el-table-column label="施工工艺" align="center" prop="technique" />
+      <el-table-column label="属性名称" align="center" prop="name" />
+      <el-table-column label="属性标识符" align="center" prop="identifier" />
+      <el-table-column label="数据类型(double text textarea date dropdown)" align="center" prop="dataType" />
+      <el-table-column label="是否必填(0非必填 1必填)" align="center" prop="required" />
+      <el-table-column label="单位(MPa)" align="center" prop="unit" />
+      <el-table-column label="访问模式(r读  w写)" align="center" prop="accessMode" />
+      <el-table-column label="默认值" align="center" prop="defaultValue" />
+      <el-table-column label="最大值" align="center" prop="maxValue" />
+      <el-table-column label="最小值" align="center" prop="minValue" />
+      <el-table-column label="不同专业公司的扩展属性" align="center" prop="extProperty" />
+      <el-table-column label="排序值" align="center" prop="sort" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="状态(0启用 1禁用)" align="center" prop="status" />
+      <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="['rq:iot-daily-report-attrs:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['rq:iot-daily-report-attrs: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>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotDailyReportAttrsForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotDailyReportAttrsApi, IotDailyReportAttrsVO } from '@/api/pms/iotdailyreportattrs'
+import IotDailyReportAttrsForm from './IotDailyReportAttrsForm.vue'
+
+/** 日报扩展模板属性 列表 */
+defineOptions({ name: 'IotDailyReportAttrs' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotDailyReportAttrsVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  templateId: undefined,
+  deptId: undefined,
+  projectId: undefined,
+  projectClassification: undefined,
+  wellType: undefined,
+  wellCategory: undefined,
+  technique: undefined,
+  name: undefined,
+  identifier: undefined,
+  dataType: undefined,
+  required: undefined,
+  unit: undefined,
+  accessMode: undefined,
+  defaultValue: undefined,
+  maxValue: undefined,
+  minValue: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotDailyReportAttrsApi.getIotDailyReportAttrsPage(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 IotDailyReportAttrsApi.deleteIotDailyReportAttrs(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotDailyReportAttrsApi.exportIotDailyReportAttrs(queryParams)
+    download.excel(data, '日报扩展模板属性.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 140 - 0
src/views/pms/iotdailyreporttemplate/IotDailyReportTemplateForm.vue

@@ -0,0 +1,140 @@
+<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="deptId">
+        <el-input v-model="formData.deptId" placeholder="请输入公司id" />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input v-model="formData.projectId" placeholder="请输入项目id" />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂...)" prop="projectClassification">
+        <el-input v-model="formData.projectClassification" placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂...)" />
+      </el-form-item>
+      <el-form-item label="井型" prop="wellType">
+        <el-select v-model="formData.wellType" placeholder="请选择井型">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="井别" prop="wellCategory">
+        <el-input v-model="formData.wellCategory" placeholder="请输入井别" />
+      </el-form-item>
+      <el-form-item label="施工工艺" prop="technique">
+        <el-input v-model="formData.technique" placeholder="请输入施工工艺" />
+      </el-form-item>
+      <el-form-item label="模板名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入模板名称" />
+      </el-form-item>
+      <el-form-item label="模板标识符" prop="identifier">
+        <el-input v-model="formData.identifier" placeholder="请输入模板标识符" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </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 { IotDailyReportTemplateApi, IotDailyReportTemplateVO } from '@/api/pms/iotdailyreporttemplate'
+
+/** 生产日报属性模板 表单 */
+defineOptions({ name: 'IotDailyReportTemplateForm' })
+
+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,
+  deptId: undefined,
+  projectId: undefined,
+  projectClassification: undefined,
+  wellType: undefined,
+  wellCategory: undefined,
+  technique: undefined,
+  name: undefined,
+  identifier: undefined,
+  remark: undefined,
+  status: undefined,
+})
+const formRules = reactive({
+})
+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 IotDailyReportTemplateApi.getIotDailyReportTemplate(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 IotDailyReportTemplateVO
+    if (formType.value === 'create') {
+      await IotDailyReportTemplateApi.createIotDailyReportTemplate(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotDailyReportTemplateApi.updateIotDailyReportTemplate(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    projectId: undefined,
+    projectClassification: undefined,
+    wellType: undefined,
+    wellCategory: undefined,
+    technique: undefined,
+    name: undefined,
+    identifier: undefined,
+    remark: undefined,
+    status: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 288 - 0
src/views/pms/iotdailyreporttemplate/index.vue

@@ -0,0 +1,288 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="公司id" prop="deptId">
+        <el-input
+          v-model="queryParams.deptId"
+          placeholder="请输入公司id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input
+          v-model="queryParams.projectId"
+          placeholder="请输入项目id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂...)" prop="projectClassification">
+        <el-input
+          v-model="queryParams.projectClassification"
+          placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂...)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="井型" prop="wellType">
+        <el-select
+          v-model="queryParams.wellType"
+          placeholder="请选择井型"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="井别" prop="wellCategory">
+        <el-input
+          v-model="queryParams.wellCategory"
+          placeholder="请输入井别"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="施工工艺" prop="technique">
+        <el-input
+          v-model="queryParams.technique"
+          placeholder="请输入施工工艺"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="模板名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入模板名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="模板标识符" prop="identifier">
+        <el-input
+          v-model="queryParams.identifier"
+          placeholder="请输入模板标识符"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态(0启用 1禁用)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </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="['rq:iot-daily-report-template:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['rq:iot-daily-report-template: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="主键id" align="center" prop="id" />
+      <el-table-column label="公司id" align="center" prop="deptId" />
+      <el-table-column label="项目id" align="center" prop="projectId" />
+      <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂...)" align="center" prop="projectClassification" />
+      <el-table-column label="井型" align="center" prop="wellType" />
+      <el-table-column label="井别" align="center" prop="wellCategory" />
+      <el-table-column label="施工工艺" align="center" prop="technique" />
+      <el-table-column label="模板名称" align="center" prop="name" />
+      <el-table-column label="模板标识符" align="center" prop="identifier" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="状态(0启用 1禁用)" align="center" prop="status" />
+      <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="['rq:iot-daily-report-template:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['rq:iot-daily-report-template: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>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotDailyReportTemplateForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotDailyReportTemplateApi, IotDailyReportTemplateVO } from '@/api/pms/iotdailyreporttemplate'
+import IotDailyReportTemplateForm from './IotDailyReportTemplateForm.vue'
+
+/** 生产日报属性模板 列表 */
+defineOptions({ name: 'IotDailyReportTemplate' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotDailyReportTemplateVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  projectId: undefined,
+  projectClassification: undefined,
+  wellType: undefined,
+  wellCategory: undefined,
+  technique: undefined,
+  name: undefined,
+  identifier: undefined,
+  remark: undefined,
+  status: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotDailyReportTemplateApi.getIotDailyReportTemplatePage(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 IotDailyReportTemplateApi.deleteIotDailyReportTemplate(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotDailyReportTemplateApi.exportIotDailyReportTemplate(queryParams)
+    download.excel(data, '生产日报属性模板.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 184 - 0
src/views/pms/iotprojectdailyreport/IotProjectDailyReportForm.vue

@@ -0,0 +1,184 @@
+<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="deptId">
+        <el-input v-model="formData.deptId" placeholder="请输入施工队伍id" />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input v-model="formData.projectId" placeholder="请输入项目id" />
+      </el-form-item>
+      <el-form-item label="任务id" prop="taskId">
+        <el-input v-model="formData.taskId" placeholder="请输入任务id" />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂... )" prop="projectClassification">
+        <el-input v-model="formData.projectClassification" placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂... )" />
+      </el-form-item>
+      <el-form-item label="施工开始日期" prop="constructionStartDate">
+        <el-date-picker
+          v-model="formData.constructionStartDate"
+          type="date"
+          value-format="x"
+          placeholder="选择施工开始日期"
+        />
+      </el-form-item>
+      <el-form-item label="施工结束日期" prop="constructionEndDate">
+        <el-date-picker
+          v-model="formData.constructionEndDate"
+          type="date"
+          value-format="x"
+          placeholder="选择施工结束日期"
+        />
+      </el-form-item>
+      <el-form-item label="下步工作计划" prop="nextPlan">
+        <el-input v-model="formData.nextPlan" placeholder="请输入下步工作计划" />
+      </el-form-item>
+      <el-form-item label="当日生产情况生产动态" prop="productionStatus">
+        <el-radio-group v-model="formData.productionStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="施工状态(数据字典)" prop="constructionStatus">
+        <el-radio-group v-model="formData.constructionStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="人员情况" prop="personnel">
+        <el-input v-model="formData.personnel" placeholder="请输入人员情况" />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性值" prop="extProperty">
+        <el-input v-model="formData.extProperty" placeholder="请输入不同专业公司的扩展属性值" />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input v-model="formData.sort" placeholder="请输入排序值" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="流程实例id" prop="processInstanceId">
+        <el-input v-model="formData.processInstanceId" placeholder="请输入流程实例id" />
+      </el-form-item>
+      <el-form-item label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" prop="auditStatus">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </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 { IotProjectDailyReportApi, IotProjectDailyReportVO } from '@/api/pms/iotprojectdailyreport'
+
+/** 项目日报 表单 */
+defineOptions({ name: 'IotProjectDailyReportForm' })
+
+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,
+  deptId: undefined,
+  projectId: undefined,
+  taskId: undefined,
+  projectClassification: undefined,
+  constructionStartDate: undefined,
+  constructionEndDate: undefined,
+  nextPlan: undefined,
+  productionStatus: undefined,
+  constructionStatus: undefined,
+  personnel: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+})
+const formRules = reactive({
+})
+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 IotProjectDailyReportApi.getIotProjectDailyReport(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 IotProjectDailyReportVO
+    if (formType.value === 'create') {
+      await IotProjectDailyReportApi.createIotProjectDailyReport(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotProjectDailyReportApi.updateIotProjectDailyReport(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    projectId: undefined,
+    taskId: undefined,
+    projectClassification: undefined,
+    constructionStartDate: undefined,
+    constructionEndDate: undefined,
+    nextPlan: undefined,
+    productionStatus: undefined,
+    constructionStatus: undefined,
+    personnel: undefined,
+    extProperty: undefined,
+    sort: undefined,
+    remark: undefined,
+    status: undefined,
+    processInstanceId: undefined,
+    auditStatus: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 372 - 0
src/views/pms/iotprojectdailyreport/index.vue

@@ -0,0 +1,372 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="施工队伍id" prop="deptId">
+        <el-input
+          v-model="queryParams.deptId"
+          placeholder="请输入施工队伍id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input
+          v-model="queryParams.projectId"
+          placeholder="请输入项目id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="任务id" prop="taskId">
+        <el-input
+          v-model="queryParams.taskId"
+          placeholder="请输入任务id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂... )" prop="projectClassification">
+        <el-input
+          v-model="queryParams.projectClassification"
+          placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂... )"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="施工开始日期" prop="constructionStartDate">
+        <el-date-picker
+          v-model="queryParams.constructionStartDate"
+          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="constructionEndDate">
+        <el-date-picker
+          v-model="queryParams.constructionEndDate"
+          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="nextPlan">
+        <el-input
+          v-model="queryParams.nextPlan"
+          placeholder="请输入下步工作计划"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="当日生产情况生产动态" prop="productionStatus">
+        <el-select
+          v-model="queryParams.productionStatus"
+          placeholder="请选择当日生产情况生产动态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="施工状态(数据字典)" prop="constructionStatus">
+        <el-select
+          v-model="queryParams.constructionStatus"
+          placeholder="请选择施工状态(数据字典)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="人员情况" prop="personnel">
+        <el-input
+          v-model="queryParams.personnel"
+          placeholder="请输入人员情况"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性值" prop="extProperty">
+        <el-input
+          v-model="queryParams.extProperty"
+          placeholder="请输入不同专业公司的扩展属性值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input
+          v-model="queryParams.sort"
+          placeholder="请输入排序值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态(0启用 1禁用)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="流程实例id" prop="processInstanceId">
+        <el-input
+          v-model="queryParams.processInstanceId"
+          placeholder="请输入流程实例id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" prop="auditStatus">
+        <el-select
+          v-model="queryParams.auditStatus"
+          placeholder="请选择审批状态 未提交、审批中、审批通过、审批不通过、已取消"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </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="['rq:iot-project-daily-report:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['rq:iot-project-daily-report: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="主键id" align="center" prop="id" />
+      <el-table-column label="施工队伍id" align="center" prop="deptId" />
+      <el-table-column label="项目id" align="center" prop="projectId" />
+      <el-table-column label="任务id" align="center" prop="taskId" />
+      <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂... )" align="center" prop="projectClassification" />
+      <el-table-column
+        label="施工开始日期"
+        align="center"
+        prop="constructionStartDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="施工结束日期"
+        align="center"
+        prop="constructionEndDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="下步工作计划" align="center" prop="nextPlan" />
+      <el-table-column label="当日生产情况生产动态" align="center" prop="productionStatus" />
+      <el-table-column label="施工状态(数据字典)" align="center" prop="constructionStatus" />
+      <el-table-column label="人员情况" align="center" prop="personnel" />
+      <el-table-column label="不同专业公司的扩展属性值" align="center" prop="extProperty" />
+      <el-table-column label="排序值" align="center" prop="sort" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="状态(0启用 1禁用)" align="center" prop="status" />
+      <el-table-column label="流程实例id" align="center" prop="processInstanceId" />
+      <el-table-column label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" align="center" prop="auditStatus" />
+      <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="['rq:iot-project-daily-report:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['rq:iot-project-daily-report: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>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotProjectDailyReportForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotProjectDailyReportApi, IotProjectDailyReportVO } from '@/api/pms/iotprojectdailyreport'
+import IotProjectDailyReportForm from './IotProjectDailyReportForm.vue'
+
+/** 项目日报 列表 */
+defineOptions({ name: 'IotProjectDailyReport' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotProjectDailyReportVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  projectId: undefined,
+  taskId: undefined,
+  projectClassification: undefined,
+  constructionStartDate: [],
+  constructionEndDate: [],
+  nextPlan: undefined,
+  productionStatus: undefined,
+  constructionStatus: undefined,
+  personnel: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotProjectDailyReportApi.getIotProjectDailyReportPage(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 IotProjectDailyReportApi.deleteIotProjectDailyReport(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotProjectDailyReportApi.exportIotProjectDailyReport(queryParams)
+    download.excel(data, '项目日报.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 30 - 35
src/views/pms/iotprojecttask/IotProjectTaskForm.vue

@@ -202,36 +202,6 @@
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="井型" prop="wellType">
-            <el-select v-model="currentTask.wellType" placeholder="请选择井型" clearable>
-              <el-option
-                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_WELL_TYPE)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
-              />
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="井别" prop="wellCategory">
-            <el-select v-model="currentTask.wellCategory" placeholder="请选择井别" clearable>
-              <el-option
-                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_WELL_CATEGORY)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
-              />
-            </el-select>
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <el-row>
-        <el-col :span="8">
-          <!-- <el-form-item label="施工地点" prop="location">
-            <el-input v-model="currentTask.location" placeholder="请输入施工地点" />
-          </el-form-item> -->
           <el-form-item :label="t('project.workArea')" prop="location">
             <el-autocomplete
               ref="workAreaAutocomplete"
@@ -274,14 +244,39 @@
             </div>
           </el-form-item>
         </el-col>
+        <!--
         <el-col :span="8">
-          <el-form-item label="设计工作量" prop="workloadDesign">
-            <el-input v-model="currentTask.workloadDesign" placeholder="请输入设计工作量" />
+          <el-form-item label="井型" prop="wellType">
+            <el-select v-model="currentTask.wellType" placeholder="请选择井型" clearable>
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_WELL_TYPE)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
           </el-form-item>
         </el-col>
+        <el-col :span="8">
+          <el-form-item label="井别" prop="wellCategory">
+            <el-select v-model="currentTask.wellCategory" placeholder="请选择井别" clearable>
+              <el-option
+                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_WELL_CATEGORY)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col> -->
       </el-row>
 
       <el-row>
+        <el-col :span="8">
+          <el-form-item label="设计工作量" prop="workloadDesign">
+            <el-input v-model="currentTask.workloadDesign" placeholder="请输入设计工作量" />
+          </el-form-item>
+        </el-col>
         <el-col :span="8">
           <el-form-item :label="t('project.unit')" prop="workloadUnit">
             <el-select v-model="currentTask.workloadUnit" placeholder="请选择工作量单位" clearable>
@@ -294,6 +289,9 @@
             </el-select>
           </el-form-item>
         </el-col>
+      </el-row>
+
+      <el-row>
         <el-col :span="8">
           <el-form-item label="施工队伍" prop="deptIds">
             <el-tree-select
@@ -339,9 +337,6 @@
             </el-tooltip>
           </el-form-item>
         </el-col>
-      </el-row>
-
-      <el-row>
         <el-col :span="8">
           <el-form-item label="责任人" prop="responsiblePerson">
             <el-button

+ 227 - 0
src/views/pms/iotprojecttasktemplate/detail/TaskAttrModelForm.vue

@@ -0,0 +1,227 @@
+<!-- 日报项目任务属性表单 -->
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="TaskAttrModelFormRules"
+      label-width="100px"
+    >
+      <el-form-item label="属性名称" prop="name">
+        <lang-input v-model="formData.name" placeholder="请输入属性名称" />
+      </el-form-item>
+      <!-- 属性配置 -->
+      <TaskAttrModelProperty
+        v-model="formData.extProperty"
+      />
+      <el-form-item label="默认值" prop="defaultValue">
+        <el-input v-model="formData.defaultValue" placeholder="请输入默认值" />
+      </el-form-item>
+      <el-form-item label="描述" prop="description">
+        <el-input
+          v-model="formData.description"
+          :maxlength="200"
+          :rows="3"
+          placeholder="请输入属性描述"
+          type="textarea"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import TaskAttrModelProperty from './TaskAttrModelProperty.vue'
+import { IotProjectTaskAttrsApi, IotProjectTaskAttrsVO } from '@/api/pms/iotprojecttaskattrs'
+import { DataSpecsDataType, TaskAttrModelFormRules } from './config'
+import pinyin from 'pinyin'
+import { cloneDeep, debounce } from 'lodash-es'
+import { isEmpty } from '@/utils/is'
+import { defineProps } from 'vue'
+
+/** 项目 任务属性 模型数据表单 */
+defineOptions({ name: 'TaskAttrModelForm' })
+
+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 isComposing = ref(false)
+
+const formData = ref<IotProjectTaskAttrsVO>({
+  deptId: -1,
+  dataType: DataSpecsDataType.DOUBLE,
+  required: 0,
+  identifier: '',
+  description: '',
+  defaultValue: '',
+  extProperty: {
+    dataType: DataSpecsDataType.DOUBLE,
+    defaultValue: '',
+    required: '',
+    dropdownList: []
+  },
+})
+
+const props = defineProps({
+  deptId: [String, Number]
+})
+
+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 IotProjectTaskAttrsApi.getIotProjectTaskAttrs(id)
+      // 情况一:属性初始化
+      if (isEmpty(formData.value.extProperty)) {
+        formData.value.dataType = DataSpecsDataType.DOUBLE
+        formData.value.extProperty = {
+          dataType: DataSpecsDataType.DOUBLE,
+          dataSpecs: {
+          },
+          dropdownList: []
+        }
+      } else {
+        // 确保dropdownList是数组,处理可能的null或对象值
+        if (!Array.isArray(formData.value.extProperty.dropdownList)) {
+          formData.value.extProperty.dropdownList = []
+        }
+      }
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open, close: () => (dialogVisible.value = false) })
+
+/** 提交表单 */
+const emit = defineEmits(['success'])
+const submitForm = async () => {
+  await formRef.value.validate()
+  formLoading.value = true
+  try {
+    const data = cloneDeep(formData.value) as IotProjectTaskAttrsVO
+    data.deptId = props.deptId
+    data.requiredFlag = formData.value.extProperty.required
+    fillExtraAttributes(data)
+    if (formType.value === 'create') {
+      await IotProjectTaskAttrsApi.createDeviceAttrModel(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotProjectTaskAttrsApi.updateDeviceAttrModel(data)
+      message.success(t('common.updateSuccess'))
+    }
+  } finally {
+    dialogVisible.value = false // 确保关闭弹框
+    emit('success')
+    formLoading.value = false
+  }
+}
+
+/** 填写额外的属性 */
+const fillExtraAttributes = (data: any) => {
+  // 处理不同类型的情况
+  // 属性
+  removeDataSpecs(data.extProperty)
+  data.dataType = data.extProperty.dataType
+  data.extProperty.identifier = data.identifier
+  data.extProperty.name = data.name
+
+  // 如果不是下拉框类型,清除dropdownList
+  if (data.extProperty.dataType !== DataSpecsDataType.DROPDOWN) {
+    data.extProperty.dropdownList = null
+  }
+}
+/** 处理 dataSpecs 为空的情况 */
+const removeDataSpecs = (val: any) => {
+  if (isEmpty(val.dataSpecs)) {
+    delete val.dataSpecs
+  }
+  if (isEmpty(val.dataSpecsList)) {
+    delete val.dataSpecsList
+  }
+}
+
+// 处理属性名称生成标识符
+const processInputName = (name: string) => {
+  let result = ''
+  for (const char of name) {
+    // 汉字转拼音首字母
+    if (/[\u4e00-\u9fa5]/.test(char)) {
+      const pinyinArray = pinyin(char, {
+        style: pinyin.STYLE_FIRST_LETTER
+      })
+      if (pinyinArray[0]?.[0]) {
+        result += pinyinArray[0][0].toUpperCase()
+      }
+    }
+    // 非汉字字符原样保留
+    else {
+      result += char
+    }
+  }
+  return result
+}
+
+// 中文首字母提取方法
+const getChineseInitials = (name: string) => {
+  const chineseChars = name.match(/[\u4e00-\u9fa5]/g) || []
+  if (chineseChars.length === 0) return ''
+
+  const pinyinArray = pinyin(chineseChars.join(''), {
+    style: pinyin.STYLE_FIRST_LETTER,
+  })
+  return pinyinArray.map(arr => arr[0]?.charAt(0).toUpperCase()).join('')
+}
+
+// 生成标识符方法
+const generateIdentifier = debounce((name: string) => {
+  /* if (formData.value.code)  return */
+
+  const initials = processInputName(name)
+  if (initials) {
+    formData.value.code = `${initials}_${Date.now()}`
+  }
+}, 800)
+
+// 监听属性名称变化
+watchEffect(() => {
+  if (formData.value.name && !isComposing.value) {
+    generateIdentifier(formData.value.name)
+  }
+})
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    dataType: DataSpecsDataType.DOUBLE,
+    identifier: '',
+    extProperty: {
+      dataType: DataSpecsDataType.DOUBLE,
+      dropdownList: []
+    },
+  }
+  formRef.value?.resetFields()
+}
+
+onMounted(async () => {
+  // 如果不修改 属性名称 不要自动生成新标识符
+  isComposing.value = true
+})
+</script>

+ 108 - 0
src/views/pms/iotprojecttasktemplate/detail/TaskAttrModelProperty.vue

@@ -0,0 +1,108 @@
+<!-- 任务属性模型表单(property 项) -->
+<template>
+  <el-form-item
+    :rules="[{ required: true, message: '请选择数据类型', trigger: 'change' }]"
+    label="数据类型"
+    prop="extProperty.dataType"
+  >
+    <el-select v-model="extProperty.dataType" placeholder="请选择数据类型" @change="handleChange">
+      <!-- ARRAY 和 STRUCT 类型数据相互嵌套时,最多支持递归嵌套 2 层(父和子) ${option.value}(${option.label}) -->
+      <el-option
+        v-for="option in getDataTypeOptions"
+        :key="option.value"
+        :label="`${option.label}`"
+        :value="option.value"
+      />
+    </el-select>
+  </el-form-item>
+  <!-- 数值型配置 -->
+  <TaskAttrModelNumberDataSpecs
+    v-if="
+      [DataSpecsDataType.DOUBLE].includes(
+        extProperty.dataType || ''
+      )
+    "
+    v-model="extProperty.dataType"
+  />
+  <!-- 枚举型配置 -->
+  <TaskAttrModelDropdownDataSpecs
+    v-if="extProperty.dataType === DataSpecsDataType.DROPDOWN"
+    v-model="extProperty.dropdownList"
+  />
+  <!-- 时间型配置 -->
+  <el-form-item v-if="extProperty.dataType === DataSpecsDataType.DATE" label="时间格式" prop="date">
+    <el-input class="w-255px!" disabled placeholder="String 类型的 UTC 时间戳(毫秒)" />
+  </el-form-item>
+  <el-form-item v-if="!isStructDataSpecs && !isParams" label="是否必填" prop="extProperty.required">
+    <el-radio-group v-model="extProperty.required">
+      <el-radio :label="TaskAttrModelRequired.REQUIRED.value">
+        {{ TaskAttrModelRequired.REQUIRED.label }}
+      </el-radio>
+      <el-radio :label="TaskAttrModelRequired.NOT_REQUIRED.value">
+        {{ TaskAttrModelRequired.NOT_REQUIRED.label }}
+      </el-radio>
+    </el-radio-group>
+  </el-form-item>
+</template>
+
+<script lang="ts" setup>
+import { useVModel } from '@vueuse/core'
+import {
+  DataSpecsDataType,
+  dataTypeOptions,
+  TaskAttrModelRequired
+} from './config'
+import { isEmpty } from '@/utils/is'
+import { TaskTemplateAttrs } from "@/api/pms/iotprojecttaskattrs";
+
+/** 任务属性模板 属性 */
+defineOptions({ name: 'AttrTemplateModelProperty' })
+
+const props = defineProps<{ modelValue: any; isStructDataSpecs?: boolean; isParams?: boolean }>()
+const emits = defineEmits(['update:modelValue'])
+const extProperty = useVModel(props, 'modelValue', emits) as Ref<TaskTemplateAttrs>
+const getDataTypeOptions = computed(() => {
+  return dataTypeOptions
+}) // 获得数据类型列表
+
+/** 属性值的数据类型切换时初始化相关数据 */
+const handleChange = (dataType: any) => {
+  if (!Array.isArray(extProperty.value.dropdownList)) {
+    extProperty.value.dropdownList = []
+  }
+  // 不是列表型数据才设置 dataSpecs.dataType
+  /* ![DataSpecsDataType.DROPDOWN].includes(dataType) &&
+    (extProperty.value.dataSpecs.dataType = dataType) */
+  switch (dataType) {
+    case DataSpecsDataType.DROPDOWN:
+      if (extProperty.value.dropdownList.length === 0) {
+        extProperty.value.dropdownList.push({
+          name: '', // 枚举项的名称
+          value: undefined // 枚举值
+        })
+      }
+      break
+  }
+}
+
+// 默认选中 是否必填
+watch(
+  () => extProperty.value.required,
+  (val: string) => {
+    if (props.isStructDataSpecs || props.isParams) {
+      return
+    }
+    isEmpty(val) && (extProperty.value.required = TaskAttrModelRequired.REQUIRED.value)
+  },
+  { immediate: true }
+)
+
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-form-item) {
+  .el-form-item {
+    margin-bottom: 0;
+  }
+}
+</style>

+ 112 - 0
src/views/pms/iotprojecttasktemplate/detail/config.ts

@@ -0,0 +1,112 @@
+import { isEmpty } from '@/utils/is'
+
+/** dataSpecs 数值型数据结构 */
+export interface DataSpecsNumberDataVO {
+  dataType: 'int' | 'float' | 'double' // 数据类型,取值为 INT、FLOAT 或 DOUBLE
+  max: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
+  min: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
+  step: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
+  precise?: string // 精度,当 dataType 为 FLOAT 或 DOUBLE 时可选
+  defaultValue?: string // 默认值,可选
+  unit: string // 单位的符号
+  unitName: string // 单位的名称
+}
+
+/** dataSpecs 枚举型数据结构 */
+export interface DataSpecsEnumOrBoolDataVO {
+  // dataType: 'enum' | 'bool'
+  defaultValue?: string // 默认值,可选
+  name: string // 枚举项的名称
+  value: string // 枚举值
+}
+
+/** 属性值的数据类型 */
+export const DataSpecsDataType = {
+  DOUBLE: 'double',   //
+  DROPDOWN: 'dropdown',   //
+  TEXT: 'text',       //
+  TEXTAREA: 'textarea',
+  DATE: 'date',       //
+} as const
+
+/** 任务属性模型数据类型配置项 */
+export const dataTypeOptions = [
+  { value: DataSpecsDataType.DOUBLE, label: '数值' },
+  { value: DataSpecsDataType.DROPDOWN, label: '下拉框' },
+  { value: DataSpecsDataType.TEXT, label: '单行文本' },
+  { value: DataSpecsDataType.TEXTAREA, label: '多行文本' },
+  { value: DataSpecsDataType.DATE, label: '日期' },
+]
+
+/** 获得任务属性模型数据类型配置项名称 dataType && `${dataType.value}(${dataType.label})` */
+export const getDataTypeOptionsLabel = (value: string) => {
+  if (isEmpty(value)) {
+    return value
+  }
+  const dataType = dataTypeOptions.find((option) => option.value === value)
+  return dataType && `${dataType.label}`
+}
+
+// 设备属性模型访问模式枚举类
+export const DeviceAttrModelAccessMode = {
+  READ_WRITE: {
+    label: '读写',
+    value: 'rw'
+  },
+  READ_ONLY: {
+    label: '只读',
+    value: 'r'
+  }
+} as const
+
+// 设备属性模型 是否必填 枚举类
+export const TaskAttrModelRequired = {
+  REQUIRED: {
+    label: '必填',
+    value: 1
+  },
+  NOT_REQUIRED: {
+    label: '非必填',
+    value: 0
+  }
+} as const
+
+/** 公共校验规则 */
+export const TaskAttrModelFormRules = {
+  name: [
+    { required: true, message: '属性名称不能为空', trigger: 'blur' },
+    {
+      pattern: /^[\u4e00-\u9fa5a-zA-Z0-9][\u4e00-\u9fa5a-zA-Z0-9\-_/\.]{0,29}$/,
+      message:
+        '支持中文、大小写字母、日文、数字、短划线、下划线、斜杠和小数点,必须以中文、英文或数字开头,不超过 30 个字符',
+      trigger: 'blur'
+    }
+  ],
+  dataType: [{ required: true, message: '数据类型不能为空', trigger: 'blur' }],
+  'extProperty.accessMode': [{ required: true, message: '请选择读写类型', trigger: 'change' }]
+}
+
+/** 校验布尔值名称 */
+export const validateBoolName = (_: any, value: string, callback: any) => {
+  if (isEmpty(value)) {
+    callback(new Error('布尔值名称不能为空'))
+    return
+  }
+  // 检查开头字符
+  if (!/^[\u4e00-\u9fa5a-zA-Z0-9]/.test(value)) {
+    callback(new Error('布尔值名称必须以中文、英文字母或数字开头'))
+    return
+  }
+  // 检查整体格式
+  if (!/^[\u4e00-\u9fa5a-zA-Z0-9][a-zA-Z0-9\u4e00-\u9fa5_-]*$/.test(value)) {
+    callback(new Error('布尔值名称只能包含中文、英文字母、数字、下划线和短划线'))
+    return
+  }
+  // 检查长度(一个中文算一个字符)
+  if (value.length > 20) {
+    callback(new Error('布尔值名称长度不能超过 20 个字符'))
+    return
+  }
+
+  callback()
+}

+ 172 - 0
src/views/pms/iotprojecttasktemplate/detail/dataSpec/TaskAttrModelDropdownDataSpecs.vue

@@ -0,0 +1,172 @@
+<!-- dataType:dropdown 数组类型 -->
+<template>
+  <el-form-item
+    :rules="[{ required: true, validator: validateEnumList, trigger: 'change' }]"
+    label="下拉选项"
+  >
+    <div class="flex flex-col">
+      <div class="flex items-center">
+      </div>
+      <div
+        v-for="(item, index) in dropdownList"
+        :key="index"
+        class="flex items-center justify-between mb-5px"
+      >
+        <el-form-item
+          :prop="`extProperty.dropdownList[${index}].name`"
+          :rules="[
+            { required: true, message: '下拉选项不能为空' },
+            { validator: validateEnumName, trigger: 'blur' }
+          ]"
+          class="flex-1 mb-0"
+        >
+          <el-input v-model="item.name" placeholder="对该下拉选项的描述" />
+        </el-form-item>
+
+        <el-form-item
+          :prop="`extProperty.dropdownList[${index}].value`"
+          :rules="[
+            { required: true, validator: validateEnumValue, trigger: 'blur' }
+          ]"
+          class="flex-1 mb-0 ml-10px"
+        >
+          <el-input v-model="item.value" placeholder="下拉选项的值" />
+        </el-form-item>
+
+        <el-button class="ml-10px" link type="primary" @click="deleteEnum(index)">删除</el-button>
+      </div>
+      <el-button link type="primary" @click="addEnum">+添加下拉选项值</el-button>
+    </div>
+  </el-form-item>
+</template>
+
+<script lang="ts" setup>
+import { useVModel } from '@vueuse/core'
+import { DataSpecsDataType, DataSpecsEnumOrBoolDataVO } from '../config'
+import { isEmpty } from '@/utils/is'
+
+/** 枚举型的 dataSpecs 配置组件 */
+defineOptions({ name: 'TaskAttrModelDropdownDataSpecs' })
+
+const props = defineProps<{ modelValue: any }>()
+const emits = defineEmits(['update:modelValue'])
+// const dropdownList = useVModel(props, 'modelValue', emits) as Ref<DataSpecsEnumOrBoolDataVO[]>
+const message = useMessage()
+
+// 确保传入的值是数组
+const initialValue = Array.isArray(props.modelValue) ? props.modelValue : []
+const dropdownList = ref<DataSpecsEnumOrBoolDataVO[]>(initialValue)
+
+// 监听内部变化并通知父组件
+watch(dropdownList, (newValue) => {
+  emits('update:modelValue', newValue)
+}, { deep: true })
+
+// 监听父组件传入的值变化
+watch(() => props.modelValue, (newValue) => {
+  if (Array.isArray(newValue)) {
+    dropdownList.value = newValue
+  }
+})
+
+/** 添加枚举项 */
+const addEnum = () => {
+  dropdownList.value.push({
+    name: '', // 枚举项的名称
+    value: undefined // 枚举值
+  })
+}
+
+/** 删除枚举项 */
+const deleteEnum = (index: number) => {
+  if (dropdownList.value.length === 1) {
+    message.warning('至少需要一个枚举项')
+    return
+  }
+  dropdownList.value.splice(index, 1)
+}
+
+/** 校验枚举值 */
+const validateEnumValue = (_: any, value: any, callback: any) => {
+  if (isEmpty(value)) {
+    callback(new Error('枚举值不能为空'))
+    return
+  }
+  /* if (isNaN(Number(value))) {
+    callback(new Error('枚举值必须是数字'))
+    return
+  } */
+  // 检查枚举值是否重复
+  const values = dropdownList.value.map((item) => item.value)
+  if (values.filter((v) => v === value).length > 1) {
+    callback(new Error('枚举值不能重复'))
+    return
+  }
+  callback()
+}
+
+/** 校验枚举描述 */
+const validateEnumName = (_: any, value: string, callback: any) => {
+  if (isEmpty(value)) {
+    callback(new Error('枚举描述不能为空'))
+    return
+  }
+  // 检查开头字符
+  if (!/^[\u4e00-\u9fa5a-zA-Z0-9]/.test(value)) {
+    callback(new Error('枚举描述必须以中文、英文字母或数字开头'))
+    return
+  }
+  // 检查整体格式
+  if (!/^[\u4e00-\u9fa5a-zA-Z0-9][a-zA-Z0-9\u4e00-\u9fa5_-]*$/.test(value)) {
+    callback(new Error('枚举描述只能包含中文、英文字母、数字、下划线和短划线'))
+    return
+  }
+  // 检查长度(一个中文算一个字符)
+  if (value.length > 20) {
+    callback(new Error('枚举描述长度不能超过20个字符'))
+    return
+  }
+  callback()
+}
+
+/** 校验整个枚举列表 */
+const validateEnumList = (_: any, __: any, callback: any) => {
+  if (isEmpty(dropdownList.value)) {
+    callback(new Error('请至少添加一个枚举项'))
+    return
+  }
+
+  // 检查是否存在空值
+  const hasEmptyValue = dropdownList.value.some(
+    (item) => isEmpty(item.value) || isEmpty(item.name)
+  )
+  if (hasEmptyValue) {
+    callback(new Error('存在未填写的枚举值或描述'))
+    return
+  }
+
+  // 检查枚举值是否都是数字
+  /* const hasInvalidNumber = dropdownList.value.some((item) => isNaN(Number(item.value)))
+  if (hasInvalidNumber) {
+    callback(new Error('存在非数字的枚举值'))
+    return
+  } */
+
+  // 检查是否有重复的枚举值
+  const values = dropdownList.value.map((item) => item.value)
+  const uniqueValues = new Set(values)
+  if (values.length !== uniqueValues.size) {
+    callback(new Error('存在重复的枚举值'))
+    return
+  }
+  callback()
+}
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-form-item) {
+  .el-form-item {
+    margin-bottom: 0;
+  }
+}
+</style>

+ 104 - 0
src/views/pms/iotprojecttasktemplate/detail/dataSpec/TaskAttrModelNumberDataSpecs.vue

@@ -0,0 +1,104 @@
+<!-- dataType:number 数组类型 -->
+<template>
+  <el-form-item
+    :rules="[{ required: true, message: '请选择单位' }]"
+    label="单位"
+    prop="extProperty.unit"
+  >
+    <el-select
+      :model-value="extProperty.unit ? extProperty.unit : ''"
+      filterable
+      placeholder="请选择单位"
+      class="w-1/1"
+      @change="unitChange"
+    >
+      <el-option
+        v-for="(item, index) in getStrDictOptions(DICT_TYPE.PMS_THING_MODEL_UNIT)"
+        :key="index"
+        :label="item.label"
+        :value="item.label + '-' + item.value"
+      />
+    </el-select>
+  </el-form-item>
+</template>
+
+<script lang="ts" setup>
+import { useVModel } from '@vueuse/core'
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+import { DataSpecsNumberDataVO } from "@/views/pms/iotprojecttasktemplate/detail/config";
+
+/** 数值型的 dataSpecs 配置组件 */
+defineOptions({ name: 'TaskAttrModelNumberDataSpecs' })
+
+const props = defineProps<{ modelValue: any }>()
+const emits = defineEmits(['update:modelValue'])
+const dataSpecs = useVModel(props, 'modelValue', emits) as Ref<DataSpecsNumberDataVO>
+
+/** 单位发生变化时触发 */
+const unitChange = (UnitSpecs: string) => {
+  // const [unitName, unit] = UnitSpecs.split('-')
+  // dataSpecs.value.unitName = unitName
+  // dataSpecs.value.unit = unit
+}
+
+/** 校验最小值 */
+const validateMin = (_: any, __: any, callback: any) => {
+  const min = Number(dataSpecs.value.min)
+  const max = Number(dataSpecs.value.max)
+  if (isNaN(min)) {
+    callback(new Error('请输入有效的数值'))
+    return
+  }
+  if (max !== undefined && !isNaN(max) && min >= max) {
+    callback(new Error('最小值必须小于最大值'))
+    return
+  }
+
+  callback()
+}
+
+/** 校验最大值 */
+const validateMax = (_: any, __: any, callback: any) => {
+  const min = Number(dataSpecs.value.min)
+  const max = Number(dataSpecs.value.max)
+  if (isNaN(max)) {
+    callback(new Error('请输入有效的数值'))
+    return
+  }
+  if (min !== undefined && !isNaN(min) && max <= min) {
+    callback(new Error('最大值必须大于最小值'))
+    return
+  }
+
+  callback()
+}
+
+/** 校验步长 */
+const validateStep = (_: any, __: any, callback: any) => {
+  const step = Number(dataSpecs.value.step)
+  if (isNaN(step)) {
+    callback(new Error('请输入有效的数值'))
+    return
+  }
+  if (step <= 0) {
+    callback(new Error('步长必须大于0'))
+    return
+  }
+  const min = Number(dataSpecs.value.min)
+  const max = Number(dataSpecs.value.max)
+  if (!isNaN(min) && !isNaN(max) && step > max - min) {
+    callback(new Error('步长不能大于最大值和最小值的差值'))
+    return
+  }
+
+  callback()
+}
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-form-item) {
+  .el-form-item {
+    margin-bottom: 0;
+  }
+}
+</style>

+ 196 - 0
src/views/pms/iotprojecttasktemplate/detail/index.vue

@@ -0,0 +1,196 @@
+<!-- 项目任务扩展属性列表 -->
+<template>
+  <ContentWrap>
+    <el-form
+      ref="formRef"
+      :model="formData"
+      style="margin-right: 4em; margin-left: 0.5em; margin-top: 1em"
+      label-width="130px"
+    >
+      <div class="base-expandable-content">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="模板名称" prop="name">
+              <el-input type="text" v-model="formData.name" disabled/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="公司名称" prop="deptName">
+              <el-input
+                v-model="formData.deptName"
+                disabled
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </div>
+    </el-form>
+  </ContentWrap>
+
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item>
+        <el-button
+          v-hasPermi="[`pms:iot-device-category-template-attrs:create`]"
+          plain
+          type="primary"
+          @click="openForm('create')"
+        >
+          <Icon class="mr-5px" icon="ep:plus" />
+          添加属性
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-tabs>
+      <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
+        <el-table-column align="center" label="属性名称" prop="name" />
+        <el-table-column align="center" label="标识符" prop="identifier" />
+        <el-table-column align="center" label="数据类型" prop="type">
+          <template #default="{ row }">
+            {{ dataTypeOptionsLabel(row.extProperty?.dataType) ?? '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="操作">
+          <template #default="scope">
+            <el-button
+              v-hasPermi="[`pms:iot-device-category-template-attrs:update`]"
+              link
+              type="primary"
+              @click="openForm('update', scope.row.id)"
+            >
+              编辑
+            </el-button>
+            <el-button
+              v-hasPermi="['pms:iot-device-category-template-attrs:delete']"
+              link
+              type="danger"
+              @click="handleDelete(scope.row.id)"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <Pagination
+        v-model:limit="queryParams.pageSize"
+        v-model:page="queryParams.pageNo"
+        :total="total"
+        @pagination="getList"
+      />
+    </el-tabs>
+  </ContentWrap>
+  <!-- 表单弹窗:添加/修改-->
+  <TaskAttrModelForm ref="formRef" @success="getList" :deviceCategoryId="deviceCategoryId" />
+</template>
+<script lang="ts" setup>
+import { IotProjectTaskAttrsApi, IotProjectTaskAttrsVO } from '@/api/pms/iotprojecttaskattrs'
+import TaskAttrModelForm from './TaskAttrModelForm.vue'
+import { getDataTypeOptionsLabel } from './config'
+import { useTagsViewStore } from "@/store/modules/tagsView";
+
+const { delView } = useTagsViewStore() // 视图操作
+const route = useRoute()
+const { currentRoute } = useRouter()
+
+defineOptions({ name: 'ProjectTaskTemplateAttrs' })
+
+const deptId = route.params.deptId // 公司id
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotProjectTaskAttrsVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  type: undefined,
+  deptId: -1
+})
+
+// 定义表单数据
+const formData = reactive({
+  name: '',
+  deptName: ''
+})
+
+const queryFormRef = ref() // 搜索的表单
+const dataTypeOptionsLabel = computed(() => (value: string) => getDataTypeOptionsLabel(value)) // 解析数据类型
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    queryParams.deptId = deptId
+    const data = await IotProjectTaskAttrsApi.getIotProjectTaskAttrsPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  queryParams.type = undefined
+  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 DeviceAttrModelApi.deleteDeviceAttrModel(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 初始化 **/
+onMounted(() => {
+  if (!deptId) {
+    message.warning('参数错误,任务属性模板不能为空!')
+    delView(unref(currentRoute))
+    return
+  }
+  console.log(route.params.templateName + ' - ' + route.params.deptName)
+  // 从路由参数获取模板名称和公司名称
+  if (route.params.templateName) {
+    formData.name = route.params.templateName as string
+  }
+  if (route.params.deptName) {
+    formData.deptName = route.params.deptName as string
+  }
+
+  getList()
+})
+</script>

+ 26 - 86
src/views/pms/iotprojecttasktemplate/index.vue

@@ -8,56 +8,10 @@
       :inline="true"
       label-width="68px"
     >
-      <el-form-item label="公司id" prop="deptId">
-        <el-input
-          v-model="queryParams.deptId"
-          placeholder="请输入公司id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="项目id" prop="projectId">
-        <el-input
-          v-model="queryParams.projectId"
-          placeholder="请输入项目id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂 )" prop="projectClassification">
+      <el-form-item label="项目类别" prop="projectClassification">
         <el-input
           v-model="queryParams.projectClassification"
-          placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂 )"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="井型" prop="wellType">
-        <el-select
-          v-model="queryParams.wellType"
-          placeholder="请选择井型"
-          clearable
-          class="!w-240px"
-        >
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="井别" prop="wellCategory">
-        <el-input
-          v-model="queryParams.wellCategory"
-          placeholder="请输入井别"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="施工工艺" prop="technique">
-        <el-input
-          v-model="queryParams.technique"
-          placeholder="请输入施工工艺"
+          placeholder="请输入项目类别"
           clearable
           @keyup.enter="handleQuery"
           class="!w-240px"
@@ -72,34 +26,6 @@
           class="!w-240px"
         />
       </el-form-item>
-      <el-form-item label="模板标识符" prop="identifier">
-        <el-input
-          v-model="queryParams.identifier"
-          placeholder="请输入模板标识符"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="备注" prop="remark">
-        <el-input
-          v-model="queryParams.remark"
-          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="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
@@ -138,17 +64,10 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="主键id" align="center" prop="id" />
-      <el-table-column label="公司id" align="center" prop="deptId" />
-      <el-table-column label="项目id" align="center" prop="projectId" />
-      <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂 )" align="center" prop="projectClassification" />
-      <el-table-column label="井型" align="center" prop="wellType" />
-      <el-table-column label="井别" align="center" prop="wellCategory" />
-      <el-table-column label="施工工艺" align="center" prop="technique" />
+      <el-table-column label="公司" align="center" prop="deptName" />
+      <!-- <el-table-column label="项目类别" align="center" prop="projectClassification" /> -->
       <el-table-column label="模板名称" align="center" prop="name" />
       <el-table-column label="模板标识符" align="center" prop="identifier" />
-      <el-table-column label="备注" align="center" prop="remark" />
-      <el-table-column label="施工状态(工作量开始/动迁/准备/施工)" align="center" prop="status" />
       <el-table-column
         label="创建时间"
         align="center"
@@ -158,6 +77,13 @@
       />
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
+          <el-button
+            type="primary"
+            link
+            @click="openDetail(scope.row)"
+          >
+            <Icon icon="ep:edit" />查看
+          </el-button>
           <el-button
             link
             type="primary"
@@ -201,7 +127,7 @@ defineOptions({ name: 'IotProjectTaskTemplate' })
 
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
-
+const { push } = useRouter()
 const loading = ref(true) // 列表的加载中
 const list = ref<IotProjectTaskTemplateVO[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
@@ -266,6 +192,20 @@ const handleDelete = async (id: number) => {
   } catch {}
 }
 
+/** 模板详情 */
+const openDetail = (row) => {
+  push({
+    name: 'ProjectTaskTemplateAttrs',
+    params: {
+      deptId: row.deptId,
+      projectClassification: row.projectClassification,
+      // 添加额外参数
+      templateName: row.name,
+      deptName: row.deptName
+    }
+  })
+}
+
 /** 导出按钮操作 */
 const handleExport = async () => {
   try {

+ 259 - 0
src/views/pms/iotrhdailyreport/IotRhDailyReportForm.vue

@@ -0,0 +1,259 @@
+<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="deptId">
+        <el-input v-model="formData.deptId" placeholder="请输入施工队伍id" />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input v-model="formData.projectId" placeholder="请输入项目id" />
+      </el-form-item>
+      <el-form-item label="任务id" prop="taskId">
+        <el-input v-model="formData.taskId" placeholder="请输入任务id" />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂... )" prop="projectClassification">
+        <el-input v-model="formData.projectClassification" placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂... )" />
+      </el-form-item>
+      <el-form-item label="搬迁安装天数" prop="relocationDays">
+        <el-input v-model="formData.relocationDays" placeholder="请输入搬迁安装天数" />
+      </el-form-item>
+      <el-form-item label="运行时效" prop="transitTime">
+        <el-date-picker
+          v-model="formData.transitTime"
+          type="date"
+          value-format="x"
+          placeholder="选择运行时效"
+        />
+      </el-form-item>
+      <el-form-item label="当日注气量(万方)" prop="dailyGasInjection">
+        <el-input v-model="formData.dailyGasInjection" placeholder="请输入当日注气量(万方)" />
+      </el-form-item>
+      <el-form-item label="当日注水量(方)" prop="dailyWaterInjection">
+        <el-input v-model="formData.dailyWaterInjection" placeholder="请输入当日注水量(方)" />
+      </el-form-item>
+      <el-form-item label="当日注气时间(H)" prop="dailyInjectGasTime">
+        <el-date-picker
+          v-model="formData.dailyInjectGasTime"
+          type="date"
+          value-format="x"
+          placeholder="选择当日注气时间(H)"
+        />
+      </el-form-item>
+      <el-form-item label="当日注水时间(H)" prop="dailyInjectWaterTime">
+        <el-date-picker
+          v-model="formData.dailyInjectWaterTime"
+          type="date"
+          value-format="x"
+          placeholder="选择当日注水时间(H)"
+        />
+      </el-form-item>
+      <el-form-item label="非生产时间(H)" prop="nonProductionTime">
+        <el-date-picker
+          v-model="formData.nonProductionTime"
+          type="date"
+          value-format="x"
+          placeholder="选择非生产时间(H)"
+        />
+      </el-form-item>
+      <el-form-item label="非生产时间原因" prop="nptReason">
+        <el-input v-model="formData.nptReason" placeholder="请输入非生产时间原因" />
+      </el-form-item>
+      <el-form-item label="施工开始日期" prop="constructionStartDate">
+        <el-date-picker
+          v-model="formData.constructionStartDate"
+          type="date"
+          value-format="x"
+          placeholder="选择施工开始日期"
+        />
+      </el-form-item>
+      <el-form-item label="施工结束日期" prop="constructionEndDate">
+        <el-date-picker
+          v-model="formData.constructionEndDate"
+          type="date"
+          value-format="x"
+          placeholder="选择施工结束日期"
+        />
+      </el-form-item>
+      <el-form-item label="当日生产情况生产动态" prop="productionStatus">
+        <el-radio-group v-model="formData.productionStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="下步工作计划" prop="nextPlan">
+        <el-input v-model="formData.nextPlan" placeholder="请输入下步工作计划" />
+      </el-form-item>
+      <el-form-item label="施工状态(动迁 准备 施工 完工)" prop="constructionStatus">
+        <el-radio-group v-model="formData.constructionStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="人员情况" prop="personnel">
+        <el-input v-model="formData.personnel" placeholder="请输入人员情况" />
+      </el-form-item>
+      <el-form-item label="累计注气量(万方)" prop="totalGasInjection">
+        <el-input v-model="formData.totalGasInjection" placeholder="请输入累计注气量(万方)" />
+      </el-form-item>
+      <el-form-item label="累计注水量(方)" prop="totalWaterInjection">
+        <el-input v-model="formData.totalWaterInjection" placeholder="请输入累计注水量(方)" />
+      </el-form-item>
+      <el-form-item label="累计完工井次" prop="cumulativeCompletion">
+        <el-input v-model="formData.cumulativeCompletion" placeholder="请输入累计完工井次" />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性值" prop="extProperty">
+        <el-input v-model="formData.extProperty" placeholder="请输入不同专业公司的扩展属性值" />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input v-model="formData.sort" placeholder="请输入排序值" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="流程实例id" prop="processInstanceId">
+        <el-input v-model="formData.processInstanceId" placeholder="请输入流程实例id" />
+      </el-form-item>
+      <el-form-item label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" prop="auditStatus">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio value="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </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 { IotRhDailyReportApi, IotRhDailyReportVO } from '@/api/pms/iotrhdailyreport'
+
+/** 瑞恒日报 表单 */
+defineOptions({ name: 'IotRhDailyReportForm' })
+
+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,
+  deptId: undefined,
+  projectId: undefined,
+  taskId: undefined,
+  projectClassification: undefined,
+  relocationDays: undefined,
+  transitTime: undefined,
+  dailyGasInjection: undefined,
+  dailyWaterInjection: undefined,
+  dailyInjectGasTime: undefined,
+  dailyInjectWaterTime: undefined,
+  nonProductionTime: undefined,
+  nptReason: undefined,
+  constructionStartDate: undefined,
+  constructionEndDate: undefined,
+  productionStatus: undefined,
+  nextPlan: undefined,
+  constructionStatus: undefined,
+  personnel: undefined,
+  totalGasInjection: undefined,
+  totalWaterInjection: undefined,
+  cumulativeCompletion: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+})
+const formRules = reactive({
+})
+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 IotRhDailyReportApi.getIotRhDailyReport(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 IotRhDailyReportVO
+    if (formType.value === 'create') {
+      await IotRhDailyReportApi.createIotRhDailyReport(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotRhDailyReportApi.updateIotRhDailyReport(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    projectId: undefined,
+    taskId: undefined,
+    projectClassification: undefined,
+    relocationDays: undefined,
+    transitTime: undefined,
+    dailyGasInjection: undefined,
+    dailyWaterInjection: undefined,
+    dailyInjectGasTime: undefined,
+    dailyInjectWaterTime: undefined,
+    nonProductionTime: undefined,
+    nptReason: undefined,
+    constructionStartDate: undefined,
+    constructionEndDate: undefined,
+    productionStatus: undefined,
+    nextPlan: undefined,
+    constructionStatus: undefined,
+    personnel: undefined,
+    totalGasInjection: undefined,
+    totalWaterInjection: undefined,
+    cumulativeCompletion: undefined,
+    extProperty: undefined,
+    sort: undefined,
+    remark: undefined,
+    status: undefined,
+    processInstanceId: undefined,
+    auditStatus: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 501 - 0
src/views/pms/iotrhdailyreport/index.vue

@@ -0,0 +1,501 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="施工队伍id" prop="deptId">
+        <el-input
+          v-model="queryParams.deptId"
+          placeholder="请输入施工队伍id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目id" prop="projectId">
+        <el-input
+          v-model="queryParams.projectId"
+          placeholder="请输入项目id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="任务id" prop="taskId">
+        <el-input
+          v-model="queryParams.taskId"
+          placeholder="请输入任务id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="项目类别(钻井 修井 注氮 酸化压裂... )" prop="projectClassification">
+        <el-input
+          v-model="queryParams.projectClassification"
+          placeholder="请输入项目类别(钻井 修井 注氮 酸化压裂... )"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="搬迁安装天数" prop="relocationDays">
+        <el-input
+          v-model="queryParams.relocationDays"
+          placeholder="请输入搬迁安装天数"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="运行时效" prop="transitTime">
+        <el-date-picker
+          v-model="queryParams.transitTime"
+          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="dailyGasInjection">
+        <el-input
+          v-model="queryParams.dailyGasInjection"
+          placeholder="请输入当日注气量(万方)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="当日注水量(方)" prop="dailyWaterInjection">
+        <el-input
+          v-model="queryParams.dailyWaterInjection"
+          placeholder="请输入当日注水量(方)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="当日注气时间(H)" prop="dailyInjectGasTime">
+        <el-date-picker
+          v-model="queryParams.dailyInjectGasTime"
+          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="当日注水时间(H)" prop="dailyInjectWaterTime">
+        <el-date-picker
+          v-model="queryParams.dailyInjectWaterTime"
+          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="非生产时间(H)" prop="nonProductionTime">
+        <el-date-picker
+          v-model="queryParams.nonProductionTime"
+          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="nptReason">
+        <el-input
+          v-model="queryParams.nptReason"
+          placeholder="请输入非生产时间原因"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="施工开始日期" prop="constructionStartDate">
+        <el-date-picker
+          v-model="queryParams.constructionStartDate"
+          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="constructionEndDate">
+        <el-date-picker
+          v-model="queryParams.constructionEndDate"
+          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="productionStatus">
+        <el-select
+          v-model="queryParams.productionStatus"
+          placeholder="请选择当日生产情况生产动态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="下步工作计划" prop="nextPlan">
+        <el-input
+          v-model="queryParams.nextPlan"
+          placeholder="请输入下步工作计划"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="施工状态(动迁 准备 施工 完工)" prop="constructionStatus">
+        <el-select
+          v-model="queryParams.constructionStatus"
+          placeholder="请选择施工状态(动迁 准备 施工 完工)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="人员情况" prop="personnel">
+        <el-input
+          v-model="queryParams.personnel"
+          placeholder="请输入人员情况"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="累计注气量(万方)" prop="totalGasInjection">
+        <el-input
+          v-model="queryParams.totalGasInjection"
+          placeholder="请输入累计注气量(万方)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="累计注水量(方)" prop="totalWaterInjection">
+        <el-input
+          v-model="queryParams.totalWaterInjection"
+          placeholder="请输入累计注水量(方)"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="累计完工井次" prop="cumulativeCompletion">
+        <el-input
+          v-model="queryParams.cumulativeCompletion"
+          placeholder="请输入累计完工井次"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="不同专业公司的扩展属性值" prop="extProperty">
+        <el-input
+          v-model="queryParams.extProperty"
+          placeholder="请输入不同专业公司的扩展属性值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="排序值" prop="sort">
+        <el-input
+          v-model="queryParams.sort"
+          placeholder="请输入排序值"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态(0启用 1禁用)" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态(0启用 1禁用)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="流程实例id" prop="processInstanceId">
+        <el-input
+          v-model="queryParams.processInstanceId"
+          placeholder="请输入流程实例id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" prop="auditStatus">
+        <el-select
+          v-model="queryParams.auditStatus"
+          placeholder="请选择审批状态 未提交、审批中、审批通过、审批不通过、已取消"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </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="['pms:iot-rh-daily-report:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-rh-daily-report: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="主键id" align="center" prop="id" />
+      <el-table-column label="施工队伍id" align="center" prop="deptId" />
+      <el-table-column label="项目id" align="center" prop="projectId" />
+      <el-table-column label="任务id" align="center" prop="taskId" />
+      <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂... )" align="center" prop="projectClassification" />
+      <el-table-column label="搬迁安装天数" align="center" prop="relocationDays" />
+      <el-table-column label="运行时效" align="center" prop="transitTime" />
+      <el-table-column label="当日注气量(万方)" align="center" prop="dailyGasInjection" />
+      <el-table-column label="当日注水量(方)" align="center" prop="dailyWaterInjection" />
+      <el-table-column label="当日注气时间(H)" align="center" prop="dailyInjectGasTime" />
+      <el-table-column label="当日注水时间(H)" align="center" prop="dailyInjectWaterTime" />
+      <el-table-column label="非生产时间(H)" align="center" prop="nonProductionTime" />
+      <el-table-column label="非生产时间原因" align="center" prop="nptReason" />
+      <el-table-column
+        label="施工开始日期"
+        align="center"
+        prop="constructionStartDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="施工结束日期"
+        align="center"
+        prop="constructionEndDate"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="当日生产情况生产动态" align="center" prop="productionStatus" />
+      <el-table-column label="下步工作计划" align="center" prop="nextPlan" />
+      <el-table-column label="施工状态(动迁 准备 施工 完工)" align="center" prop="constructionStatus" />
+      <el-table-column label="人员情况" align="center" prop="personnel" />
+      <el-table-column label="累计注气量(万方)" align="center" prop="totalGasInjection" />
+      <el-table-column label="累计注水量(方)" align="center" prop="totalWaterInjection" />
+      <el-table-column label="累计完工井次" align="center" prop="cumulativeCompletion" />
+      <el-table-column label="不同专业公司的扩展属性值" align="center" prop="extProperty" />
+      <el-table-column label="排序值" align="center" prop="sort" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="状态(0启用 1禁用)" align="center" prop="status" />
+      <el-table-column label="流程实例id" align="center" prop="processInstanceId" />
+      <el-table-column label="审批状态 未提交、审批中、审批通过、审批不通过、已取消" align="center" prop="auditStatus" />
+      <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="['pms:iot-rh-daily-report:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['pms:iot-rh-daily-report: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>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotRhDailyReportForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotRhDailyReportApi, IotRhDailyReportVO } from '@/api/pms/iotrhdailyreport'
+import IotRhDailyReportForm from './IotRhDailyReportForm.vue'
+
+/** 瑞恒日报 列表 */
+defineOptions({ name: 'IotRhDailyReport' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotRhDailyReportVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  projectId: undefined,
+  taskId: undefined,
+  projectClassification: undefined,
+  relocationDays: undefined,
+  transitTime: [],
+  dailyGasInjection: undefined,
+  dailyWaterInjection: undefined,
+  dailyInjectGasTime: [],
+  dailyInjectWaterTime: [],
+  nonProductionTime: [],
+  nptReason: undefined,
+  constructionStartDate: [],
+  constructionEndDate: [],
+  productionStatus: undefined,
+  nextPlan: undefined,
+  constructionStatus: undefined,
+  personnel: undefined,
+  totalGasInjection: undefined,
+  totalWaterInjection: undefined,
+  cumulativeCompletion: undefined,
+  extProperty: undefined,
+  sort: undefined,
+  remark: undefined,
+  status: undefined,
+  processInstanceId: undefined,
+  auditStatus: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotRhDailyReportApi.getIotRhDailyReportPage(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 IotRhDailyReportApi.deleteIotRhDailyReport(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotRhDailyReportApi.exportIotRhDailyReport(queryParams)
+    download.excel(data, '瑞恒日报.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 20 - 13
src/views/pms/maintenance/IotMaintenancePlan.vue

@@ -313,16 +313,19 @@
       <div class="form-group"
            v-if="(configDialog.current?.runningTimeRule === 0 || configDialog.current?.mileageRule === 0)
             && (configDialog.current?.timeAccumulatedAttrs?.length || configDialog.current?.mileageAccumulatedAttrs?.length)
-            && !configDialog.current.totalRunTime && !configDialog.current.totalMileage" >
+            && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime))
+            && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage))" >
         <div class="group-title">{{ t('mainPlan.accumulatedParams') }}</div>
         <!-- 累计运行时长 -->
         <el-form-item
           v-if="configDialog.current?.runningTimeRule === 0
-          && configDialog.current?.timeAccumulatedAttrs?.length && !configDialog.current.totalRunTime"
+          && configDialog.current?.timeAccumulatedAttrs?.length
+          && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime))"
           :label="t('mainPlan.accumulatedRunTime')"
           prop="accumulatedTimeOption"
           :rules="[{
-            required: configDialog.current?.runningTimeRule === 0 && configDialog.current?.timeAccumulatedAttrs?.length,
+            required: configDialog.current?.runningTimeRule === 0 && configDialog.current?.timeAccumulatedAttrs?.length
+            && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime)),
             message: '请选择累计运行时长',
             trigger: 'change'
           }]"
@@ -345,11 +348,13 @@
         <!-- 累计运行公里数 -->
         <el-form-item
           v-if="configDialog.current?.mileageRule === 0
-          && configDialog.current?.mileageAccumulatedAttrs?.length && !configDialog.current.totalMileage"
+          && configDialog.current?.mileageAccumulatedAttrs?.length
+          && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage))"
           :label="t('mainPlan.accumulatedMileage')"
           prop="accumulatedMileageOption"
           :rules="[{
-            required: configDialog.current?.mileageRule === 0 && configDialog.current?.mileageAccumulatedAttrs?.length,
+            required: configDialog.current?.mileageRule === 0 && configDialog.current?.mileageAccumulatedAttrs?.length
+            && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage)),
             message: '请选择累计运行公里数',
             trigger: 'change'
           }]"
@@ -507,8 +512,8 @@ const checkRowFilled = (row: IotMaintenanceBomVO) => {
       row.nextRunningKilometers > 0 &&
       row.kiloCycleLead > 0 &&
     // 检查累计里程参数是否已选择(当条件满足时)
-    (!(row.mileageAccumulatedAttrs?.length && !row.totalMileage) ||
-      (row.mileageAccumulatedAttrs?.length && !row.totalMileage && row.type)));
+    (!(row.mileageAccumulatedAttrs?.length && (row.totalMileage==null || isNaN(row.totalMileage))) ||
+      (row.mileageAccumulatedAttrs?.length && (row.totalMileage==null || isNaN(row.totalMileage)) && row.type)));
 
   // 检查运行时间规则
   const runningTimeFilled = row.runningTimeRule !== 0
@@ -517,8 +522,8 @@ const checkRowFilled = (row: IotMaintenanceBomVO) => {
       row.nextRunningTime > 0 &&
       row.timePeriodLead > 0  &&
       // 检查累计时间参数是否已选择(当条件满足时)
-      (!(row.timeAccumulatedAttrs?.length && !row.totalRunTime) ||
-        (row.timeAccumulatedAttrs?.length && !row.totalRunTime && row.code)));
+      (!(row.timeAccumulatedAttrs?.length && (row.totalRunTime==null || isNaN(row.totalRunTime))) ||
+        (row.timeAccumulatedAttrs?.length && (row.totalRunTime==null || isNaN(row.totalRunTime)) && row.code)));
 
   // 检查自然日期规则
   const naturalDateFilled = row.naturalDateRule !== 0
@@ -591,14 +596,16 @@ const saveConfig = () => {
     // 累计运行时长配置 校验逻辑
     if (configDialog.current.runningTimeRule === 0 &&
       configDialog.current.timeAccumulatedAttrs?.length &&
-      !configDialog.form.accumulatedTimeOption) {
+      !configDialog.form.accumulatedTimeOption &&
+      (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime)) ) {
       message.error('请选择累计运行时长');
       return;
     }
     // 累计运行公里数配置 校验逻辑
     if (configDialog.current.mileageRule === 0 &&
       configDialog.current.mileageAccumulatedAttrs?.length &&
-      !configDialog.form.accumulatedMileageOption) {
+      !configDialog.form.accumulatedMileageOption &&
+      (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage)) ) {
       message.error('请选择累计运行公里数');
       return;
     }
@@ -953,7 +960,7 @@ const validateTableData = (): boolean => {
     // 累计参数校验逻辑
     if (row.mileageRule === 0 &&
       row.mileageAccumulatedAttrs?.length &&
-      !row.totalMileage &&
+      (row.totalMileage==null || isNaN(row.totalMileage)) &&
       !row.type) {
       errorMessages.push(`第 ${rowNumber} 行(${deviceIdentifier}):请选择累计运行公里数参数`)
       isValid = false
@@ -961,7 +968,7 @@ const validateTableData = (): boolean => {
 
     if (row.runningTimeRule === 0 &&
       row.timeAccumulatedAttrs?.length &&
-      !row.totalRunTime &&
+      (row.totalRunTime==null || isNaN(row.totalRunTime)) &&
       !row.code) {
       errorMessages.push(`第 ${rowNumber} 行(${deviceIdentifier}):请选择累计运行时长参数`)
       isValid = false

+ 20 - 13
src/views/pms/maintenance/IotMaintenancePlanEdit.vue

@@ -399,16 +399,19 @@
       <div class="form-group"
            v-if="(configDialog.current?.runningTimeRule === 0 || configDialog.current?.mileageRule === 0)
             && (configDialog.current?.timeAccumulatedAttrs?.length || configDialog.current?.mileageAccumulatedAttrs?.length)
-            && !configDialog.current.totalRunTime && !configDialog.current.totalMileage" >
+            && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime))
+            && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage))" >
         <div class="group-title">{{ t('mainPlan.accumulatedParams') }}</div>
         <!-- 累计运行时长 -->
         <el-form-item
           v-if="configDialog.current?.runningTimeRule === 0
-          && configDialog.current?.timeAccumulatedAttrs?.length && !configDialog.current.totalRunTime"
+          && configDialog.current?.timeAccumulatedAttrs?.length
+          && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime))"
           :label="t('mainPlan.accumulatedRunTime')"
           prop="accumulatedTimeOption"
           :rules="[{
-            required: configDialog.current?.runningTimeRule === 0 && configDialog.current?.timeAccumulatedAttrs?.length,
+            required: configDialog.current?.runningTimeRule === 0 && configDialog.current?.timeAccumulatedAttrs?.length
+            && (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime)),
             message: '请选择累计运行时长',
             trigger: 'change'
           }]"
@@ -431,11 +434,13 @@
         <!-- 累计运行公里数 -->
         <el-form-item
           v-if="configDialog.current?.mileageRule === 0
-          && configDialog.current?.mileageAccumulatedAttrs?.length && !configDialog.current.totalMileage"
+          && configDialog.current?.mileageAccumulatedAttrs?.length
+          && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage))"
           :label="t('mainPlan.accumulatedMileage')"
           prop="accumulatedMileageOption"
           :rules="[{
-            required: configDialog.current?.mileageRule === 0 && configDialog.current?.mileageAccumulatedAttrs?.length,
+            required: configDialog.current?.mileageRule === 0 && configDialog.current?.mileageAccumulatedAttrs?.length
+            && (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage)),
             message: '请选择累计运行公里数',
             trigger: 'change'
           }]"
@@ -640,14 +645,16 @@ const saveConfig = () => {
     // 累计运行时长配置 校验逻辑
     if (configDialog.current.runningTimeRule === 0 &&
       configDialog.current.timeAccumulatedAttrs?.length &&
-      !configDialog.form.accumulatedTimeOption) {
+      !configDialog.form.accumulatedTimeOption &&
+      (configDialog.current.totalRunTime == null || isNaN(configDialog.current.totalRunTime)) ) {
       message.error('请选择累计运行时长');
       return;
     }
     // 累计运行公里数配置 校验逻辑
     if (configDialog.current.mileageRule === 0 &&
       configDialog.current.mileageAccumulatedAttrs?.length &&
-      !configDialog.form.accumulatedMileageOption) {
+      !configDialog.form.accumulatedMileageOption &&
+      (configDialog.current.totalMileage == null || isNaN(configDialog.current.totalMileage)) ) {
       message.error('请选择累计运行公里数');
       return;
     }
@@ -1070,8 +1077,8 @@ const checkRowFilled = (row: IotMaintenanceBomVO) => {
       row.nextRunningKilometers > 0 &&
       row.kiloCycleLead > 0 &&
       // 检查累计里程参数是否已选择(当条件满足时)
-      (!(row.mileageAccumulatedAttrs?.length && !row.totalMileage) ||
-        (row.mileageAccumulatedAttrs?.length && !row.totalMileage && row.type)));
+      (!(row.mileageAccumulatedAttrs?.length && (row.totalMileage==null || isNaN(row.totalMileage))) ||
+        (row.mileageAccumulatedAttrs?.length && (row.totalMileage==null || isNaN(row.totalMileage)) && row.type)));
 
   // 检查运行时间规则
   const runningTimeFilled = row.runningTimeRule !== 0
@@ -1080,8 +1087,8 @@ const checkRowFilled = (row: IotMaintenanceBomVO) => {
       row.nextRunningTime > 0 &&
       row.timePeriodLead > 0  &&
       // 检查累计时间参数是否已选择(当条件满足时)
-      (!(row.timeAccumulatedAttrs?.length && !row.totalRunTime) ||
-        (row.timeAccumulatedAttrs?.length && !row.totalRunTime && row.code)));
+      (!(row.timeAccumulatedAttrs?.length && (row.totalRunTime==null || isNaN(row.totalRunTime))) ||
+        (row.timeAccumulatedAttrs?.length && (row.totalRunTime==null || isNaN(row.totalRunTime)) && row.code)));
 
   // 检查自然日期规则
   const naturalDateFilled = row.naturalDateRule !== 0
@@ -1351,7 +1358,7 @@ const validateTableData = (): boolean => {
     // 累计参数校验逻辑
     if (row.mileageRule === 0 &&
       row.mileageAccumulatedAttrs?.length &&
-      !row.totalMileage &&
+      (row.totalMileage==null || isNaN(row.totalMileage)) &&
       !row.type) {
       errorMessages.push(`第 ${rowNumber} 行(${deviceIdentifier}):请选择累计运行公里数参数`)
       isValid = false
@@ -1359,7 +1366,7 @@ const validateTableData = (): boolean => {
 
     if (row.runningTimeRule === 0 &&
       row.timeAccumulatedAttrs?.length &&
-      !row.totalRunTime &&
+      (row.totalRunTime==null || isNaN(row.totalRunTime)) &&
       !row.code) {
       errorMessages.push(`第 ${rowNumber} 行(${deviceIdentifier}):请选择累计运行时长参数`)
       isValid = false