Просмотр исходного кода

调整瑞都日报填报,日期选择

Zimo 3 недель назад
Родитель
Сommit
1a4253e95f
1 измененных файлов с 141 добавлено и 90 удалено
  1. 141 90
      pages/ruiDu/compontents/report-form.vue

+ 141 - 90
pages/ruiDu/compontents/report-form.vue

@@ -22,7 +22,7 @@ import { getTenantId, getAccessToken } from "@/utils/auth.js";
 
 const istime = ref("false");
 
-onLoad(options => {
+onLoad((options) => {
   istime.value = options.istime;
 });
 
@@ -51,7 +51,7 @@ const rdStatusRange = ref([]);
 const techniqueRange = ref([]);
 
 const handleInitSelect = () => {
-  rdStatusRange.value = getStrDictOptions("rdStatus").map(item => {
+  rdStatusRange.value = getStrDictOptions("rdStatus").map((item) => {
     return {
       ...item,
       text: item.label,
@@ -59,7 +59,7 @@ const handleInitSelect = () => {
   });
   // 施工工艺
   techniqueRange.value = getIntDictOptions("rq_iot_project_technology_rd").map(
-    item => {
+    (item) => {
       return {
         ...item,
         text: item.label,
@@ -120,7 +120,7 @@ const startDefaultTime = ref("08:00");
 const endTime = ref("24:00");
 const endDefaultTime = ref("08:00");
 
-const timeRange = data => {
+const timeRange = (data) => {
   form.startTime = data[0];
   form.endTime = data[1];
 };
@@ -206,8 +206,8 @@ const validate = async () => {
   if (istime.value === "true") {
     return await reportFormRef.value.validateField([
       "constructionBrief",
-      ...form.platformIds.flatMap(pid => [
-        ...NON_PROD_FIELDS.map(item => `${pid}.${item.key}`),
+      ...form.platformIds.flatMap((pid) => [
+        ...NON_PROD_FIELDS.map((item) => `${pid}.${item.key}`),
         `${pid}.otherNptReason`,
       ]),
     ]);
@@ -216,16 +216,16 @@ const validate = async () => {
 
 const submitForm = async () => {
   const deleteId = wellOptions.value.filter(
-    o => !form.platformIds.includes(o.value)
+    (o) => !form.platformIds.includes(o.value)
   );
-  deleteId.forEach(o => {
+  deleteId.forEach((o) => {
     delete form[o.value];
   });
   await validate();
 
   let error = false;
 
-  form.platformIds.forEach(id => {
+  form.platformIds.forEach((id) => {
     const pair = form[id];
     // 计算所有时间字段的总和
     const totalTime =
@@ -242,7 +242,7 @@ const submitForm = async () => {
       (pair.winterBreakTime || 0) +
       (pair.otherNptTime || 0);
     const wellName =
-      wellOptions.value.find(item => item.value === id)?.text ??
+      wellOptions.value.find((item) => item.value === id)?.text ??
       props.reportData.wellName ??
       "";
     // 检查总和是否超过24小时
@@ -283,8 +283,8 @@ const submitForm = async () => {
 
   const responseData = [];
   // // 处理施工工艺
-  form.platformIds.forEach(id => {
-    formDataCopy[id].extProperty.forEach(attr => {
+  form.platformIds.forEach((id) => {
+    formDataCopy[id].extProperty.forEach((attr) => {
       if (attr.dataType === "double") {
         attr.actualValue = Number(attr.actualValue);
       }
@@ -292,7 +292,7 @@ const submitForm = async () => {
 
     const attachments = JSON.parse(
       JSON.stringify(formDataCopy.attachments)
-    ).map(item => {
+    ).map((item) => {
       item.bizId = id;
       return item;
     });
@@ -323,14 +323,15 @@ const submitForm = async () => {
       nextPlan: formDataCopy.nextPlan,
       ...(props.reportData.platformWell === 1
         ? {
-            platformId: props.reportData.platforms.find(v => v.reportId === id)
-              .id,
+            platformId: props.reportData.platforms.find(
+              (v) => v.reportId === id
+            ).id,
           }
         : {}),
       productionStatus: formDataCopy.productionStatus,
       rdStatus: formDataCopy[id].rdStatus,
-      techniqueIds: formDataCopy[id].techniqueIds.map(v => v.toString()),
-      reportFuels: formDataCopy.reportFuels.map(item => ({
+      techniqueIds: formDataCopy[id].techniqueIds.map((v) => v.toString()),
+      reportFuels: formDataCopy.reportFuels.map((item) => ({
         ...item,
         customFuel: Number(item.customFuel),
         reportId: id,
@@ -358,7 +359,7 @@ const submitForm = async () => {
   });
 
   // 提交表单
-  updateRuiDuReportBatch(responseData).then(res => {
+  updateRuiDuReportBatch(responseData).then((res) => {
     // 提交成功
     if (res.code === 0) {
       uni.showToast({ title: t("operation.success"), icon: "none" });
@@ -374,40 +375,59 @@ const handleClickSelectDevice = () => {
   deviceTransferRef.value.open();
 };
 
-const handleEquipmentNames = deviceIds => {
+const handleEquipmentNames = (deviceIds) => {
   form.deviceIds = deviceIds || []; //施工设备
   const { selectedDevices = [] } = props.reportData || {};
   const deviceIdSet = new Set(deviceIds);
   //   已选择的设备(名称)
   selectedEquipmentNames.value = selectedDevices
-    .filter(item => deviceIdSet.has(item.id))
-    .map(item => item.deviceName)
+    .filter((item) => deviceIdSet.has(item.id))
+    .map((item) => item.deviceName)
     .join(",");
 
   //   未选择的设备(名称)
   unselectedEquipmentNames.value =
     selectedDevices
-      .filter(item => !deviceIdSet.has(item.id))
-      .map(item => item.deviceName)
+      .filter((item) => !deviceIdSet.has(item.id))
+      .map((item) => item.deviceName)
       .join(",") || t("ruiDu.allEquipmentConstructed");
 };
 
 // 设备选择器回调
-const handleTransferChange = selectedIds => {
+const handleTransferChange = (selectedIds) => {
   // 更新已选择的设备及名称
   handleEquipmentNames(selectedIds);
 };
 
 const steps = ref([]);
 
-const formatT = arr =>
-  `${arr[0].toString().padStart(2, "0")}:${arr[1].toString().padStart(2, "0")}`;
+const formatT = (val) => {
+  if (typeof val === "string") {
+    return val;
+  }
+  if (Array.isArray(val)) {
+    return `${val[0].toString().padStart(2, "0")}:${val[1]
+      .toString()
+      .padStart(2, "0")}`;
+  }
+  return "08:00";
+};
+
+const formatDateTimestamp = (val) => {
+  const date = dayjs(val || props.reportData.createTime || new Date());
+  return date.isValid() ? date.startOf("day").valueOf() : "";
+};
+
+const getDefaultReportDate = () =>
+  formatDateTimestamp(props.reportData.createTime);
 
 const addReportDetailRow = () => {
   if (!form.reportDetails) {
     form.reportDetails = [];
   }
   form.reportDetails.push({
+    reportDate: getDefaultReportDate(),
+    endDateTime: getDefaultReportDate(),
     startTime: "08:00",
     endTime: "08:00",
     duration: 0,
@@ -415,7 +435,7 @@ const addReportDetailRow = () => {
   });
 };
 
-const removeReportDetailRow = index => {
+const removeReportDetailRow = (index) => {
   if (index === 0) {
     uni.showToast({ title: "至少填写一条生产动态", icon: "none" });
     return;
@@ -434,7 +454,7 @@ const formDataFormat = () => {
   }
 
   if (props.reportData.platformWell === 1) {
-    form.platformIds = props.reportData.platforms?.map(v => v.reportId) ?? [];
+    form.platformIds = props.reportData.platforms?.map((v) => v.reportId) ?? [];
   } else {
     form.platformIds = [props.reportData.id];
   }
@@ -446,7 +466,7 @@ const formDataFormat = () => {
   // }
 
   if (props.reportData.platformWell === 1) {
-    props.reportData.platforms.forEach(p => {
+    props.reportData.platforms.forEach((p) => {
       form[p.reportId] = {
         rdStatus: p.rdStatus,
         techniqueIds: p.techniqueIds,
@@ -489,12 +509,16 @@ const formDataFormat = () => {
 
   form.constructionBrief = props.reportData.constructionBrief || ""; // 施工简介
 
-  form.reportDetails = (props.reportData.reportDetails || []).map(item => ({
-    duration: item.duration || 0,
-    constructionDetail: item.constructionDetail || "",
-    startTime: formatT(item.startTime),
-    endTime: formatT(item.endTime),
-  }));
+  form.reportDetails = (props.reportData.reportDetails || []).map((item) => {
+    return {
+      duration: item.duration || 0,
+      constructionDetail: item.constructionDetail || "",
+      reportDate: formatDateTimestamp(item.reportDate),
+      endDateTime: formatDateTimestamp(item.endDateTime || item.reportDate),
+      startTime: formatT(item.startTime),
+      endTime: formatT(item.endTime),
+    };
+  });
 
   if (!form.reportDetails.length) {
     addReportDetailRow();
@@ -519,7 +543,7 @@ const formDataFormat = () => {
 
   const validList = list1?.length > 0 ? list1 : list2?.length > 0 ? list2 : [];
 
-  form.reportFuels = validList.map(v => ({
+  form.reportFuels = validList.map((v) => ({
     ...v,
     // 这里保持你原有的数值处理逻辑
     customFuel: Number(
@@ -531,7 +555,7 @@ const formDataFormat = () => {
     ),
   }));
 
-  steps.value = (props.reportData.taskProgresses ?? []).map(v => ({
+  steps.value = (props.reportData.taskProgresses ?? []).map((v) => ({
     title: v.rdStatusLabel,
     desc: v.createTime,
   }));
@@ -564,7 +588,7 @@ const timeRangeFormat = () => {
 
 watch(
   () => props.reportData,
-  val => {
+  (val) => {
     if (val.id) {
       formDataFormat();
     }
@@ -574,7 +598,7 @@ watch(
 
 const wellOptions = computed(() => {
   return (
-    props.reportData.platforms?.map(v => ({
+    props.reportData.platforms?.map((v) => ({
       text: v.wellName,
       value: v.reportId,
     })) ?? []
@@ -590,20 +614,21 @@ const reportDetailsTimeRangeRef = ref(null);
 
 const reportDetailIndex = ref(0);
 
-const handleClickTimeRangeItem = index => {
+const handleClickTimeRangeItem = (index) => {
   reportDetailIndex.value = index;
   reportDetailsTimeRangeRef.value.open();
 };
 
-const calculateDuration = row => {
-  if (!row.startTime || !row.endTime) {
+const calculateDuration = (row) => {
+  if (!row.reportDate || !row.endDateTime || !row.startTime || !row.endTime) {
     row.duration = 0;
     return;
   }
 
-  const todayStr = dayjs().format("YYYY-MM-DD");
-  const start = dayjs(`${todayStr} ${row.startTime}`);
-  const end = dayjs(`${todayStr} ${row.endTime}`);
+  const reportDate = dayjs(row.reportDate).format("YYYY-MM-DD");
+  const endDateTime = dayjs(row.endDateTime).format("YYYY-MM-DD");
+  const start = dayjs(`${reportDate} ${row.startTime}`);
+  const end = dayjs(`${endDateTime} ${row.endTime}`);
 
   let diffMinutes = end.diff(start, "minute");
 
@@ -614,7 +639,11 @@ const calculateDuration = row => {
   row.duration = Number((diffMinutes / 60).toFixed(2));
 };
 
-const reportDetailsTimeRange = data => {
+const handleReportDetailDateChange = (index) => {
+  calculateDuration(form.reportDetails[index]);
+};
+
+const reportDetailsTimeRange = (data) => {
   form.reportDetails[reportDetailIndex.value].startTime = data[0];
   form.reportDetails[reportDetailIndex.value].endTime = data[1];
 
@@ -629,9 +658,9 @@ const chooseFile = () => {
   uploadRef.value.chooseFile({
     count: 9,
     size: 50,
-    success: files => {
+    success: (files) => {
       attachmentList.value = attachmentList.value.concat(files);
-      attachmentList.value.forEach(file => {
+      attachmentList.value.forEach((file) => {
         // 将等待上传和上传失败的文件提交上传到服务器
         // 提示:::如果接口不支持跨域,改成调用this.getTempFilePath(file)
         if (file.status === "waiting" || file.status === "fail") {
@@ -642,7 +671,7 @@ const chooseFile = () => {
   });
 };
 
-const uploadHandle = file => {
+const uploadHandle = (file) => {
   uploadRef.value.upload({
     url:
       config.default.apiUrl + config.default.apiUrlSuffix + "/rq/file/upload",
@@ -654,7 +683,7 @@ const uploadHandle = file => {
       "Device-id": "undefined",
     },
     method: "post",
-    success: e => {
+    success: (e) => {
       file.status = "success";
       const result = JSON.parse(e.result);
 
@@ -677,7 +706,7 @@ const uploadHandle = file => {
         type: "attachment",
       });
     },
-    fail: e => {
+    fail: (e) => {
       file.status = "fail";
       console.error("上传异常:", err);
       uni.showToast({ title: t("operation.uploadFail"), icon: "none" });
@@ -734,7 +763,7 @@ const uploadHandle = file => {
 // };
 
 // 删除附件
-const deleteFiles = index => {
+const deleteFiles = (index) => {
   // 1. 从formData.attachments中移除选中项
   form.attachments.splice(index, 1);
 };
@@ -743,16 +772,16 @@ function copyToPublicAndOpen(sourcePath, fileName) {
   // 获取 _downloads/ (公共下载目录) 的目录对象
   plus.io.resolveLocalFileSystemURL(
     "_downloads/",
-    entryDir => {
+    (entryDir) => {
       // 获取源文件对象
       plus.io.resolveLocalFileSystemURL(
         sourcePath,
-        entryFile => {
+        (entryFile) => {
           // 执行复制操作:将 sourcePath 复制到 _downloads/ 下,并重命名
           entryFile.copyTo(
             entryDir,
             fileName,
-            newEntry => {
+            (newEntry) => {
               console.log("文件已复制到公共目录:", newEntry.fullPath);
 
               uni.showToast({
@@ -767,27 +796,27 @@ function copyToPublicAndOpen(sourcePath, fileName) {
               plus.runtime.openFile(
                 newEntry.fullPath,
                 {},
-                e => {
+                (e) => {
                   console.log("打开成功");
                 },
-                e => {
+                (e) => {
                   console.error("打开失败", e);
                   uni.showToast({ title: "无法打开文件", icon: "none" });
                 }
               );
             },
-            e => {
+            (e) => {
               console.error("复制文件失败:", e);
               uni.showToast({ title: "保存到公共目录失败", icon: "none" });
             }
           );
         },
-        e => {
+        (e) => {
           console.error("读取源文件失败:", e);
         }
       );
     },
-    e => {
+    (e) => {
       console.error("读取下载目录失败:", e);
     }
   );
@@ -798,16 +827,16 @@ function saveTempFileToDownloads(tempPath, fileName) {
   // "_downloads/" 是 H5+ API 对安卓公共下载目录的映射
   plus.io.resolveLocalFileSystemURL(
     "_downloads/",
-    entryDir => {
+    (entryDir) => {
       // 2. 获取临时文件对象
       plus.io.resolveLocalFileSystemURL(
         tempPath,
-        entryFile => {
+        (entryFile) => {
           // 3. 执行复制:将临时文件复制到 Downloads 目录
           entryFile.copyTo(
             entryDir,
             fileName,
-            newEntry => {
+            (newEntry) => {
               console.log("文件路径:" + newEntry.fullPath);
 
               uni.showToast({
@@ -818,18 +847,18 @@ function saveTempFileToDownloads(tempPath, fileName) {
               // 4. (可选) 打开预览
               plus.runtime.openFile(newEntry.fullPath);
             },
-            e => {
+            (e) => {
               console.error("复制失败", e);
               uni.showToast({ title: "保存失败", icon: "none" });
             }
           );
         },
-        e => {
+        (e) => {
           console.error("读取临时文件失败", e);
         }
       );
     },
-    e => {
+    (e) => {
       console.error("无法访问下载目录", e);
       // 这里如果报错,通常是权限没给或者 Android 11+ 读写受限
     }
@@ -837,7 +866,7 @@ function saveTempFileToDownloads(tempPath, fileName) {
 }
 
 // 下载文件
-const downloadFile = async file => {
+const downloadFile = async (file) => {
   console.log("🚀 ~ downloadFile ~ file:", file);
   const { filePath: fileUrl, name: fileName } = file;
 
@@ -852,7 +881,7 @@ const downloadFile = async file => {
   if (platform === "android") {
     uni.downloadFile({
       url: fileUrl,
-      success: res => {
+      success: (res) => {
         console.log("🚀 ~ downloadFile ~ res:", res);
         if (res.statusCode === 200) {
           saveTempFileToDownloads(res.tempFilePath, fileName);
@@ -876,7 +905,7 @@ const downloadFile = async file => {
           // });
         }
       },
-      fail: err => {
+      fail: (err) => {
         console.log("🚀 ~ downloadFile ~ err:", err);
         uni.showToast({
           title: t("operation.downloadFail"),
@@ -961,12 +990,12 @@ const downloadFileByBlob = async (fileUrl, fileName) => {
 
 const removeSelectedItem = (platformId, value) => {
   form[platformId].techniqueIds = form[platformId].techniqueIds.filter(
-    item => item !== value
+    (item) => item !== value
   );
   getWorkloadInfoByTechnique(platformId);
 };
 
-const getWorkloadInfoByTechnique = platformId => {
+const getWorkloadInfoByTechnique = (platformId) => {
   const ids = form[platformId].techniqueIds;
   if (!ids.length) {
     form[platformId].extProperty = [];
@@ -974,12 +1003,12 @@ const getWorkloadInfoByTechnique = platformId => {
   }
   getRuiDuReportAttrs({
     techniqueIds: ids.join(","),
-  }).then(res => {
+  }).then((res) => {
     const { data = [] } = res;
 
     // 1. 按 "identifier+unit" 去重:用Map保证唯一,key为拼接字段
     const uniqueMap = new Map();
-    data.forEach(item => {
+    data.forEach((item) => {
       // 生成去重key(identifier和unit都存在才拼接,避免异常)
       const key =
         item.identifier && item.unit
@@ -991,7 +1020,7 @@ const getWorkloadInfoByTechnique = platformId => {
     const uniqueData = Array.from(uniqueMap.values());
 
     // 2. 对比formData.extProperty,保留已有actualValue(避免覆盖用户输入)
-    const handledData = uniqueData.map(newItem => {
+    const handledData = uniqueData.map((newItem) => {
       // 生成当前新项的去重key
       const newKey =
         newItem.identifier && newItem.unit
@@ -999,7 +1028,7 @@ const getWorkloadInfoByTechnique = platformId => {
           : "";
 
       // 在原有extProperty中找匹配项
-      const oldItem = form[platformId].extProperty.find(old => {
+      const oldItem = form[platformId].extProperty.find((old) => {
         const oldKey =
           old.identifier && old.unit ? `${old.identifier}-${old.unit}` : "";
         return newKey && oldKey && newKey === oldKey;
@@ -1025,7 +1054,7 @@ defineExpose({
 // const props = defineProps({ reportData: Object });
 
 // --- 1. 公共工具函数 (保持不变) ---
-const parseNumber = val => {
+const parseNumber = (val) => {
   let num = parseFloat(val);
   if (isNaN(num)) num = 0;
   if (num < 0) num = 0;
@@ -1037,7 +1066,7 @@ const parseNumber = val => {
 // 列表变化 -> 算总和
 const handleListChange = useDebounceFn(() => {
   let total = 0;
-  form.reportFuels.forEach(item => {
+  form.reportFuels.forEach((item) => {
     const formattedVal = parseNumber(item.customFuel);
     if (item.customFuel !== formattedVal) {
       item.customFuel = formattedVal;
@@ -1082,7 +1111,7 @@ const initDailyFuel = () => {
     // 【情况B】Props 没值:根据列表计算初始值
     // 这里我们不使用防抖,直接立即计算一次,确保显示正确
     let total = 0;
-    form.reportFuels.forEach(item => {
+    form.reportFuels.forEach((item) => {
       // 初始化时顺便把列表里的脏数据格式化了
       const val = parseNumber(item.customFuel);
       item.customFuel = val;
@@ -1392,17 +1421,39 @@ watch(
 
         <template v-for="(item, index) in form.reportDetails" :key="index">
           <uv-divider v-if="index !== 0" class="divider"></uv-divider>
-          <uni-forms-item class="form-item" label="日期">
-            <uni-easyinput
-              class="digit-item"
-              :inputBorder="false"
-              :clearable="false"
+          <uni-forms-item
+            class="form-item"
+            label="开始日期"
+            required
+            :name="['reportDetails', index, 'reportDate']"
+            :rules="[{ required: true, errorMessage: '请选择开始日期' }]">
+            <uni-datetime-picker
+              type="date"
+              return-type="timestamp"
+              :clear-icon="false"
+              :border="false"
+              :placeholder="selectPlaceholder"
+              :disabled="formDisable"
               :styles="{ disableColor: '#fff' }"
-              :placeholder="inputPlaceholder"
-              :disabled="true"
-              :model-value="
-                dayjs(reportData.createTime).format('YYYY-MM-DD')
-              " />
+              v-model="item.reportDate"
+              @change="handleReportDetailDateChange(index)" />
+          </uni-forms-item>
+          <uni-forms-item
+            class="form-item"
+            label="结束日期"
+            required
+            :name="['reportDetails', index, 'endDateTime']"
+            :rules="[{ required: true, errorMessage: '请选择结束日期' }]">
+            <uni-datetime-picker
+              type="date"
+              return-type="timestamp"
+              :clear-icon="false"
+              :border="false"
+              :placeholder="selectPlaceholder"
+              :disabled="formDisable"
+              :styles="{ disableColor: '#fff' }"
+              v-model="item.endDateTime"
+              @change="handleReportDetailDateChange(index)" />
           </uni-forms-item>
           <uni-forms-item
             class="form-item"
@@ -1469,7 +1520,7 @@ watch(
         :key="platformId"
         class="content">
         <div class="content-title">{{
-          wellOptions.find(item => item.value === platformId)?.text ??
+          wellOptions.find((item) => item.value === platformId)?.text ??
           reportData.wellName ??
           ""
         }}</div>
@@ -1625,7 +1676,7 @@ watch(
             :styles="{ disableColor: '#fff' }"
             :disabled="istime !== 'true'"
             v-model.number="form[platformId][field.key]"
-            @input="val => onInputChange(val, platformId, field.key)" />
+            @input="(val) => onInputChange(val, platformId, field.key)" />
         </uni-forms-item>
 
         <uni-forms-item