Jelajahi Sumber

Merge branch 'qhse_person' of shuzhihua/pms-iot-vue into master

yanghao 1 Minggu lalu
induk
melakukan
51dbaec4de

+ 7 - 0
src/api/pms/iotprojecttaskschedule/index.ts

@@ -53,4 +53,11 @@ export const IotProjectTaskScheduleApi = {
   exportIotProjectTaskSchedule: async (params) => {
     return await request.download({ url: `/rq/iot-project-task-schedule/export-excel`, params })
   },
+
+  // 查询每个任务相关公司的 工作量字段
+  getWorkload: async (id: number | string) => {
+    return await request.get({
+      url: `/rq/iot-project-task-schedule/scheduleExtProperties?taskId=${id}`
+    })
+  }
 }

+ 129 - 76
src/views/pms/iotprojecttask/index.vue

@@ -44,6 +44,17 @@ interface PlanRow {
   startTime: string
   endTime: string
   showEndTime: boolean
+  [key: string]: any
+}
+
+interface PlanExtColumn {
+  name: string
+  identifier: string
+  dataType?: string
+  required?: number
+  unit?: string
+  defaultValue?: string | number | null
+  sort?: number
 }
 
 const message = useMessage()
@@ -107,9 +118,53 @@ const timestampToDateTime = (timestamp: number | string | null | undefined): str
   return dayjs(value).format('YYYY-MM-DD HH:mm')
 }
 
+const currentTableColumns = ref<PlanExtColumn[]>([])
+
+const normalizeWorkloadColumns = (res: any): PlanExtColumn[] => {
+  const columns = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
+  return columns
+    .filter((item: PlanExtColumn) => item?.identifier)
+    .sort((a: PlanExtColumn, b: PlanExtColumn) => (a?.sort ?? 0) - (b?.sort ?? 0))
+}
+
+const isRequiredColumn = (column: PlanExtColumn) => Number(column.required) === 1
+
+const isEmptyValue = (value: unknown) =>
+  value === undefined || value === null || (typeof value === 'string' && value.trim() === '')
+
+const getPlanDynamicValues = (row: PlanRow) =>
+  currentTableColumns.value.reduce<Record<string, any>>((values, column) => {
+    values[column.identifier] = row[column.identifier] ?? ''
+    return values
+  }, {})
+
+const createPlanRow = (plan?: any): PlanRow => {
+  const row: PlanRow = {
+    id: plan?.id,
+    status: plan?.status || '',
+    startTime: timestampToDateTime(plan?.startTime),
+    endTime: timestampToDateTime(plan?.endTime),
+    showEndTime: plan?.status !== COMPLETED_STATUS
+  }
+
+  currentTableColumns.value.forEach((column) => {
+    row[column.identifier] = plan?.[column.identifier] ?? column.defaultValue ?? ''
+  })
+
+  return row
+}
+
 const openPlanDialog = async (row: ProjectTaskRow) => {
   currentRow.value = row
   planList.value = []
+  currentTableColumns.value = []
+
+  try {
+    const res = await IotProjectTaskScheduleApi.getWorkload(row.id)
+    currentTableColumns.value = normalizeWorkloadColumns(res)
+  } catch {
+    message.error('获取部门数据失败')
+  }
 
   try {
     getWorkProgressDictOptions()
@@ -118,16 +173,7 @@ const openPlanDialog = async (row: ProjectTaskRow) => {
     })
 
     if (taskSchedules?.length) {
-      planList.value = taskSchedules.map((plan: any) => {
-        const status = plan.status
-        return {
-          id: plan.id,
-          status,
-          startTime: timestampToDateTime(plan.startTime),
-          endTime: timestampToDateTime(plan.endTime),
-          showEndTime: status !== COMPLETED_STATUS
-        }
-      })
+      planList.value = taskSchedules.map((plan: any) => createPlanRow(plan))
     }
 
     planDialogVisible.value = true
@@ -149,12 +195,7 @@ const onStatusChange = (row: PlanRow) => {
 }
 
 const addNewRow = () => {
-  planList.value.push({
-    status: '',
-    startTime: '',
-    endTime: '',
-    showEndTime: true
-  })
+  planList.value.push(createPlanRow())
 }
 
 const removeRow = (index: number) => {
@@ -166,8 +207,18 @@ const savePlan = async () => {
     saveLoading.value = true
 
     for (let index = 0; index < planList.value.length; index++) {
-      if (!planList.value[index].status) {
-        message.error(`第${index + 1}行请选择施工状态`)
+      const row = planList.value[index]
+
+      if (!row.startTime) {
+        message.error(`第${index + 1}行请选择开始时间`)
+        return
+      }
+
+      const emptyRequiredColumn = currentTableColumns.value.find(
+        (column) => isRequiredColumn(column) && isEmptyValue(row[column.identifier])
+      )
+      if (emptyRequiredColumn) {
+        message.error(`第${index + 1}行请填写${emptyRequiredColumn.name}`)
         return
       }
     }
@@ -178,14 +229,16 @@ const savePlan = async () => {
       status: item.status,
       startTime: item.startTime ? new Date(item.startTime).getTime() : null,
       endTime:
-        item.status !== COMPLETED_STATUS && item.endTime ? new Date(item.endTime).getTime() : null
+        item.status !== COMPLETED_STATUS && item.endTime ? new Date(item.endTime).getTime() : null,
+      ...getPlanDynamicValues(item)
     }))
 
     await IotProjectTaskScheduleApi.saveTaskSchedule(submitData)
     message.success('保存成功')
     planDialogVisible.value = false
     getList()
-  } catch {
+  } catch (error) {
+    console.log(error)
     message.error('保存失败')
   } finally {
     saveLoading.value = false
@@ -292,15 +345,13 @@ onMounted(async () => {
 
 <template>
   <div
-    class="iot-project-task-page grid grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
-  >
+    class="iot-project-task-page grid grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
     <el-form
       ref="queryFormRef"
       :model="queryParams"
       size="default"
       label-width="72px"
-      class="iot-project-task-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0"
-    >
+      class="iot-project-task-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0">
       <div class="query-row">
         <el-form-item label="公司" prop="companyId">
           <el-select
@@ -308,14 +359,12 @@ onMounted(async () => {
             placeholder="请选择公司"
             clearable
             filterable
-            class="w-full"
-          >
+            class="w-full">
             <el-option
               v-for="item in companyDeptList"
               :key="item.id"
               :label="item.name"
-              :value="item.id"
-            />
+              :value="item.id" />
           </el-select>
         </el-form-item>
         <el-form-item label="客户名称" prop="manufactureName">
@@ -324,8 +373,7 @@ onMounted(async () => {
             placeholder="请输入客户名称"
             clearable
             class="w-full"
-            @keyup.enter="handleQuery"
-          />
+            @keyup.enter="handleQuery" />
         </el-form-item>
         <el-form-item label="合同名称" prop="contractName">
           <el-input
@@ -333,8 +381,7 @@ onMounted(async () => {
             placeholder="请输入合同名称"
             clearable
             class="w-full"
-            @keyup.enter="handleQuery"
-          />
+            @keyup.enter="handleQuery" />
         </el-form-item>
         <el-form-item label="合同编号" prop="contractCode">
           <el-input
@@ -342,8 +389,7 @@ onMounted(async () => {
             placeholder="请输入合同编号"
             clearable
             class="w-full"
-            @keyup.enter="handleQuery"
-          />
+            @keyup.enter="handleQuery" />
         </el-form-item>
         <el-form-item label="施工队伍" prop="deptName">
           <el-input
@@ -351,8 +397,7 @@ onMounted(async () => {
             placeholder="请输入施工队伍"
             clearable
             class="w-full"
-            @keyup.enter="handleQuery"
-          />
+            @keyup.enter="handleQuery" />
         </el-form-item>
         <el-form-item label="井号" prop="wellName">
           <el-input
@@ -360,8 +405,7 @@ onMounted(async () => {
             placeholder="请输入井号"
             clearable
             class="w-full"
-            @keyup.enter="handleQuery"
-          />
+            @keyup.enter="handleQuery" />
         </el-form-item>
         <el-form-item label="平台井" prop="platformFlag">
           <el-select
@@ -369,8 +413,7 @@ onMounted(async () => {
             placeholder="请选择平台井"
             clearable
             class="w-full"
-            @change="handleQuery"
-          >
+            @change="handleQuery">
             <el-option label="全部" value="A" />
             <el-option label="是" value="Y" />
             <el-option label="否" value="N" />
@@ -384,8 +427,7 @@ onMounted(async () => {
             start-placeholder="开始日期"
             end-placeholder="结束日期"
             :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-            class="w-full"
-          />
+            class="w-full" />
         </el-form-item>
 
         <el-form-item class="query-actions">
@@ -410,15 +452,13 @@ onMounted(async () => {
               :width="width"
               :height="height"
               :max-height="height"
-              show-border
-            >
+              show-border>
               <ZmTableColumn
                 type="index"
                 :label="t('monitor.serial')"
                 :width="70"
                 fixed="left"
-                hide-in-column-settings
-              />
+                hide-in-column-settings />
               <ZmTableColumn prop="manufactureName" label="客户名称" min-width="180" fixed="left" />
               <ZmTableColumn prop="contractName" label="合同名称" min-width="220" />
               <ZmTableColumn prop="contractCode" label="合同编号" min-width="150" />
@@ -437,32 +477,28 @@ onMounted(async () => {
                     link
                     type="primary"
                     @click="openPlanDialog(row)"
-                    v-hasPermi="['rq:iot-project-task:update']"
-                  >
+                    v-hasPermi="['rq:iot-project-task:update']">
                     计划
                   </el-button>
                   <el-button
                     v-if="Number(row.deptId) === REPORT_DEPT_ID"
                     link
                     type="primary"
-                    @click="openGenerateReportDialog(row)"
-                  >
+                    @click="openGenerateReportDialog(row)">
                     生成日报
                   </el-button>
                   <el-button
                     link
                     type="primary"
                     @click="openForm('update', row.id, row.projectId)"
-                    v-hasPermi="['rq:iot-project-task:update']"
-                  >
+                    v-hasPermi="['rq:iot-project-task:update']">
                     编辑
                   </el-button>
                   <el-button
                     link
                     type="danger"
                     @click="handleDelete(row.id)"
-                    v-hasPermi="['rq:iot-project-task:delete']"
-                  >
+                    v-hasPermi="['rq:iot-project-task:delete']">
                     删除
                   </el-button>
                 </template>
@@ -483,8 +519,7 @@ onMounted(async () => {
           :total="total"
           layout="total, sizes, prev, pager, next, jumper"
           @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
+          @current-change="handleCurrentChange" />
       </div>
     </div>
   </div>
@@ -492,8 +527,7 @@ onMounted(async () => {
   <el-dialog
     v-model="planDialogVisible"
     :title="`${currentRow?.contractName || ''} - ${currentRow?.wellName || ''} - 任务计划`"
-    width="80%"
-  >
+    width="80%">
     <div class="mb-15px">
       <el-button type="primary" @click="addNewRow">
         <Icon icon="ep:plus" class="mr-5px" />新增行
@@ -506,24 +540,22 @@ onMounted(async () => {
           {{ scope.$index + 1 }}
         </template>
       </el-table-column>
-      <el-table-column label="施工状态" min-width="200">
+      <!-- <el-table-column label="施工状态" min-width="200">
         <template #default="scope">
           <el-select
             v-model="scope.row.status"
             placeholder="请选择施工状态"
             clearable
             class="w-full"
-            @change="onStatusChange(scope.row)"
-          >
+            @change="onStatusChange(scope.row)">
             <el-option
               v-for="dict in workProgressDictOptions"
               :key="dict.value"
               :label="dict.label"
-              :value="dict.value"
-            />
+              :value="dict.value" />
           </el-select>
         </template>
-      </el-table-column>
+      </el-table-column> -->
       <el-table-column label="开始时间" min-width="200">
         <template #default="scope">
           <el-date-picker
@@ -532,8 +564,7 @@ onMounted(async () => {
             placeholder="选择开始时间"
             value-format="YYYY-MM-DD HH:mm"
             format="YYYY-MM-DD HH:mm"
-            class="w-full"
-          />
+            class="w-full" />
         </template>
       </el-table-column>
       <el-table-column label="结束时间" min-width="200">
@@ -545,10 +576,31 @@ onMounted(async () => {
             placeholder="选择结束时间"
             value-format="YYYY-MM-DD HH:mm"
             format="YYYY-MM-DD HH:mm"
-            class="w-full"
-          />
+            class="w-full" />
         </template>
       </el-table-column>
+
+      <el-table-column
+        min-width="100"
+        v-for="item in currentTableColumns"
+        :key="item.identifier"
+        :prop="item.identifier">
+        <template #header>
+          <span>
+            <span v-if="isRequiredColumn(item)" class="required-mark">*</span>
+            {{ item.unit ? `${item.name}(${item.unit})` : item.name }}
+          </span>
+        </template>
+        <template #default="scope">
+          <!-- <el-input type="number" v-model="scope.row[item.identifier]" placeholder="请输入" /> -->
+          <el-input-number
+            style="width: 150px"
+            v-model="scope.row[item.identifier]"
+            :min="0"
+            placeholder="请输入" />
+        </template>
+      </el-table-column>
+
       <el-table-column label="操作" width="100" align="center">
         <template #default="scope">
           <el-button link type="danger" @click="removeRow(scope.$index)">删除</el-button>
@@ -573,8 +625,7 @@ onMounted(async () => {
           placeholder="请选择日期"
           value-format="YYYY-MM-DD"
           format="YYYY-MM-DD"
-          class="w-full!"
-        />
+          class="w-full!" />
       </el-form-item>
     </el-form>
 
@@ -585,8 +636,7 @@ onMounted(async () => {
           size="default"
           type="primary"
           :loading="generateReportLoading"
-          @click="submitGenerateReport"
-        >
+          @click="submitGenerateReport">
           确定
         </el-button>
       </span>
@@ -603,8 +653,7 @@ onMounted(async () => {
           placeholder="请选择日期"
           value-format="YYYY-MM-DD"
           format="YYYY-MM-DD"
-          class="w-full!"
-        />
+          class="w-full!" />
       </el-form-item>
     </el-form>
 
@@ -615,8 +664,7 @@ onMounted(async () => {
           size="default"
           type="primary"
           @click="submitGenerateReport"
-          :loading="generateReportLoading"
-        >
+          :loading="generateReportLoading">
           确定
         </el-button>
       </span>
@@ -656,6 +704,11 @@ onMounted(async () => {
   margin-bottom: 0;
 }
 
+.required-mark {
+  margin-right: 2px;
+  color: var(--el-color-danger);
+}
+
 @media (width >= 2200px) {
   .query-actions {
     grid-column: 4;