Explorar o código

feat(risk-workReport): 作业上报新增工期字段及联动计算

- types.ts: RiskWorkReportBo/Vo 加 durationDays 字段类型
- index.vue:
  - 列表表格新增'工期(天)'列(放在项目名称之后,开始时间之前)
  - 查看详情弹窗新增'工期(天)'行(放在项目名称之后,开始时间之前)
  - 新增/编辑表单新增'工期'输入框(el-input-number),放在项目名称下方
  - 实现三个联动处理函数:
    - handleDurationChange: 工期变化 + 已有开始时间 → 自动算结束时间
    - handleStartTimeChange: 开始时间变化 → 结束时间已填则重算工期;否则若有工期则重算结束时间
    - handleEndTimeChange: 结束时间变化 + 已有开始时间 → 重算工期
  - 工期字段带提示'单位:天,录入工期+开始时间自动算结束时间'
yangjingjing hai 2 días
pai
achega
7b428f4c7b
Modificáronse 2 ficheiros con 128 adicións e 0 borrados
  1. 4 0
      src/api/risk/types.ts
  2. 124 0
      src/views/risk/workReport/index.vue

+ 4 - 0
src/api/risk/types.ts

@@ -113,6 +113,8 @@ export interface RiskWorkReportBo {
   workLocation?: string;
   workStartTime?: string;
   workEndTime?: string;
+  /** 工期(单位:天,与开始/结束时间联动计算) */
+  durationDays?: number;
   reporterId?: string | number;
   reporterName?: string;
   reportTime?: string;
@@ -143,6 +145,8 @@ export interface RiskWorkReportVo {
   workLocation: string;
   workStartTime: string;
   workEndTime: string;
+  /** 工期(单位:天) */
+  durationDays: number;
   reporterId: string | number;
   reporterName: string;
   reportTime: string;

+ 124 - 0
src/views/risk/workReport/index.vue

@@ -61,6 +61,12 @@
           :show-overflow-tooltip="true"
           min-width="180"
         />
+        <el-table-column
+          label="工期(天)"
+          align="center"
+          prop="durationDays"
+          width="90"
+        />
         <el-table-column
           label="施工开始时间"
           align="center"
@@ -136,6 +142,24 @@
           </el-col>
         </el-row>
 
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="工期" prop="durationDays">
+              <el-input-number
+                v-model="form.durationDays"
+                :min="1"
+                :max="3650"
+                :step="1"
+                placeholder="请输入工期,如:3天"
+                controls-position="right"
+                style="width: 100%"
+                @change="handleDurationChange"
+              />
+              <span class="form-tip">单位:天,录入工期+开始时间自动算结束时间</span>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="施工开始时间" prop="workStartTime">
@@ -146,6 +170,7 @@
                 value-format="YYYY-MM-DD HH:mm:ss"
                 format="YYYY-MM-DD HH:mm"
                 style="width: 100%"
+                @change="handleStartTimeChange"
               />
             </el-form-item>
           </el-col>
@@ -158,6 +183,7 @@
                 value-format="YYYY-MM-DD HH:mm:ss"
                 format="YYYY-MM-DD HH:mm"
                 style="width: 100%"
+                @change="handleEndTimeChange"
               />
             </el-form-item>
           </el-col>
@@ -266,6 +292,9 @@
         <el-descriptions-item label="项目名称">
           {{ viewForm.workTitle }}
         </el-descriptions-item>
+        <el-descriptions-item label="工期(天)">
+          {{ viewForm.durationDays ?? '-' }}
+        </el-descriptions-item>
         <el-descriptions-item label="施工开始时间">
           {{ viewForm.workStartTime }}
         </el-descriptions-item>
@@ -414,6 +443,7 @@ const data = reactive<any>({
     workContent: '',
     workStartTime: '',
     workEndTime: '',
+    durationDays: undefined,
     reporterName: '',
     contactPhone: '',
     photoList: [],
@@ -432,6 +462,21 @@ const data = reactive<any>({
   rules: {
     workType: [{ required: true, message: '请选择作业类型', trigger: 'change' }],
     workTitle: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
+    durationDays: [
+      { required: true, message: '请输入工期', trigger: 'blur' },
+      {
+        validator: (_rule: any, value: any, callback: any) => {
+          if (value === undefined || value === null || value === '') {
+            callback(new Error('请输入工期'));
+          } else if (Number(value) < 1) {
+            callback(new Error('工期必须大于等于1天'));
+          } else {
+            callback();
+          }
+        },
+        trigger: 'blur'
+      }
+    ],
     workStartTime: [{ required: true, message: '请选择施工开始时间', trigger: 'change' }],
     workEndTime: [
       { required: true, message: '请选择施工结束时间', trigger: 'change' },
@@ -651,6 +696,7 @@ const reset = () => {
     workContent: '',
     workStartTime: '',
     workEndTime: '',
+    durationDays: undefined,
     reporterName: '',
     contactPhone: '',
     photoList: [],
@@ -669,6 +715,78 @@ const closeDialog = () => {
   reset();
 };
 
+// ============ 工期 ↔ 时间 联动计算 ============
+
+/**
+ * 根据工期(天)和开始时间,计算结束时间字符串
+ */
+const computeEndTimeByDuration = (startTime: string, days: number): string => {
+  if (!startTime || !days || days <= 0) return '';
+  const start = new Date(startTime);
+  if (isNaN(start.getTime())) return '';
+  const end = new Date(start.getTime() + days * 24 * 60 * 60 * 1000);
+  // 格式化为 YYYY-MM-DD HH:mm:ss (与 value-format 一致)
+  const pad = (n: number) => String(n).padStart(2, '0');
+  return (
+    end.getFullYear() +
+    '-' +
+    pad(end.getMonth() + 1) +
+    '-' +
+    pad(end.getDate()) +
+    ' ' +
+    pad(end.getHours()) +
+    ':' +
+    pad(end.getMinutes()) +
+    ':' +
+    pad(end.getSeconds())
+  );
+};
+
+/**
+ * 根据开始时间和结束时间,向上取整计算工期(天)
+ * 1ms ~ 1天 都视为1天
+ */
+const computeDurationByRange = (startTime: string, endTime: string): number => {
+  if (!startTime || !endTime) return 0;
+  const start = new Date(startTime);
+  const end = new Date(endTime);
+  if (isNaN(start.getTime()) || isNaN(end.getTime())) return 0;
+  const diff = end.getTime() - start.getTime();
+  if (diff <= 0) return 0;
+  const oneDay = 24 * 60 * 60 * 1000;
+  return Math.ceil(diff / oneDay);
+};
+
+/** 工期变化 → 若有开始时间,自动算出结束时间 */
+const handleDurationChange = (val: number | undefined) => {
+  if (!val || val <= 0) return;
+  if (form.value.workStartTime) {
+    form.value.workEndTime = computeEndTimeByDuration(form.value.workStartTime, val);
+  }
+};
+
+/** 开始时间变化 → 若结束时间已填,重算工期;否则若工期已填,重算结束时间 */
+const handleStartTimeChange = (val: string | null) => {
+  if (!val) return;
+  if (form.value.workEndTime) {
+    // 结束时间已有 → 重算工期(用户期望改开始时间后工期随之变化)
+    const days = computeDurationByRange(val, form.value.workEndTime);
+    if (days > 0) form.value.durationDays = days;
+  } else if (form.value.durationDays && form.value.durationDays > 0) {
+    // 结束时间为空 + 工期有值 → 重算结束时间
+    form.value.workEndTime = computeEndTimeByDuration(val, form.value.durationDays);
+  }
+};
+
+/** 结束时间变化 → 若开始时间已填,重算工期 */
+const handleEndTimeChange = (val: string | null) => {
+  if (!val) return;
+  if (form.value.workStartTime) {
+    const days = computeDurationByRange(form.value.workStartTime, val);
+    if (days > 0) form.value.durationDays = days;
+  }
+};
+
 // ============ 上传相关 ============
 
 const handleUploadError = () => {
@@ -912,6 +1030,12 @@ onMounted(() => {
 .readonly-text {
   color: #303133;
 }
+.form-tip {
+  display: inline-block;
+  margin-left: 8px;
+  font-size: 12px;
+  color: #909399;
+}
 .audit-opinion.pass {
   color: #67c23a;
 }