Преглед изворни кода

Merge branch 'dev' of http://110.41.163.243:9980/kd-aiot/kd-aiot-frontend-mes into dev

liujt пре 2 месеци
родитељ
комит
ac67351785

+ 41 - 14
src/views/beEntrusted/index.vue

@@ -3,6 +3,17 @@
     <el-card shadow="never" v-loading="loading">
       <!-- <order-search @search="reload" ref="searchRef"> </order-search> -->
       <seek-page :seekList="seekList" @search="search"></seek-page>
+
+      <div class="btn_box">
+        <el-button type="primary" @click="salesToProductionOpen(2)"
+          >转生产订单</el-button
+        ></div
+      >
+
+      <el-tabs v-model="tabValue" type="card" @tab-click="handleTabClick">
+        <el-tab-pane label="受托任务" name="1"></el-tab-pane>
+        <el-tab-pane label="预处理任务" name="2"></el-tab-pane>
+      </el-tabs>
       <ele-pro-table
         ref="table"
         :columns="columns"
@@ -16,17 +27,6 @@
         :selection.sync="selection"
         @fullscreen-change="fullscreenChange"
       >
-        <template v-slot:toolbar>
-          <!-- <el-button type="primary" @click="salesToProductionOpen(1)"
-            >转生产计划</el-button
-          > -->
-          <el-button type="primary" @click="salesToProductionOpen(2)"
-            >转生产订单</el-button
-          >
-          <!-- <el-button type="primary" @click="salesToProductionOpen(3)"
-            >转生产工单</el-button
-          > -->
-        </template>
         <template v-slot:type="{ row }">
           <span> {{ getDictValue('请托类型', row.type + '') }}</span>
         </template>
@@ -209,7 +209,8 @@
         tableHeight: 'calc(100vh - 320px)',
         selection: [],
         factoryList: [],
-        typeList: []
+        typeList: [],
+        tabValue: '1'
       };
     },
     computed: {
@@ -461,6 +462,16 @@
             planList: this.factoryList
           },
           // {
+          //   label: '状态:',
+          //   value: 'preStatus',
+          //   type: 'select',
+          //   planList: [
+          //     { value: 0, label: '准备中' },
+          //     { value: 1, label: '准备完成' },
+          //     { value: 2, label: '取消' }
+          //   ]
+          // },
+          // {
           //   label: '受托工厂:',
           //   value: 'beEntrustedFactoriesId',
           //   type: 'select',
@@ -503,10 +514,16 @@
           endTime
         });
       },
+
       open(type, row) {
         this.$refs.create.open(type, row);
       },
 
+      handleTabClick(e) {
+        this.tabValue = e.name;
+        this.reload();
+      },
+
       async getTypeList() {
         let res = await getByCode('entrust_type');
         if (res?.code == 0) {
@@ -591,8 +608,14 @@
       },
       /* 刷新表格 */
       reload(where) {
+        const queryWhere = { ...(where || {}) };
+        if (this.tabValue === '2') {
+          queryWhere.preStatus = 1;
+        } else {
+          delete queryWhere.preStatus;
+        }
         this.$nextTick(() => {
-          this.$refs.table.reload({ page: 1, where });
+          this.$refs.table.reload({ page: 1, where: queryWhere });
         });
       },
 
@@ -619,4 +642,8 @@
   };
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+  .btn_box {
+    margin-bottom: 6px;
+  }
+</style>

+ 136 - 16
src/views/produce/components/feeding/index.vue

@@ -16,7 +16,6 @@
             value-format="yyyy-MM-dd HH:mm:ss"
             placeholder="选择日期"
             @change="handleCreate"
-            :picker-options="pickerOptions"
           >
           </el-date-picker>
         </div>
@@ -84,7 +83,7 @@
               value-format="yyyy-MM-dd HH:mm:ss"
               placeholder="选择日期"
               style="margin-right: 25px; width: 190px"
-              :picker-options="pickerOptions"
+              @change="onItemExecutorTimeChange(item, $event)"
             >
             </el-date-picker>
 
@@ -364,19 +363,7 @@
         teamName: '',
         isDefaultExecutor: false,
         checked: false,
-        useDefaultFeedDate: false,
-        pickerOptions: {
-          disabledDate(time) {
-            // 禁止选择大于当前时间的日期
-            return time.getTime() > Date.now();
-          }
-          // selectableRange: (() => {
-          //   const now = new Date();
-          //   const start = '00:00:00';
-          //   const end = now.toTimeString().split(' ')[0];
-          //   return `${start} - ${end}`;
-          // })()
-        }
+        useDefaultFeedDate: false
         // feedExistNum: '',
         // feedNeedAridRegion: '',
         // feedNeedAuxiliaryEquipment: '',
@@ -407,8 +394,108 @@
     },
 
     methods: {
+      parseReportLastTimeMs(val) {
+        if (val == null || val === '') return null;
+        if (typeof val === 'number' && !isNaN(val)) {
+          const ms = val < 1e12 ? val * 1000 : val;
+          const t = new Date(ms).getTime();
+          return isNaN(t) ? null : t;
+        }
+        const s = String(val).trim();
+        const m = s.match(
+          /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})/
+        );
+        if (m) {
+          const d = new Date(
+            Number(m[1]),
+            Number(m[2]) - 1,
+            Number(m[3]),
+            Number(m[4]),
+            Number(m[5]),
+            Number(m[6])
+          );
+          const t = d.getTime();
+          return isNaN(t) ? null : t;
+        }
+        const d = new Date(s.replace(/-/g, '/'));
+        const t = d.getTime();
+        return isNaN(t) ? null : t;
+      },
+
+      formatMsToExecutorTime(ms) {
+        const date = new Date(ms);
+        const p = (n) => String(n).padStart(2, '0');
+        return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(
+          date.getDate()
+        )} ${p(date.getHours())}:${p(date.getMinutes())}:${p(
+          date.getSeconds()
+        )}`;
+      },
+
+      /** 提示文案中展示的上一工序报工时间 */
+      formatReportLastTimeDisplay(raw) {
+        const ms = this.parseReportLastTimeMs(raw);
+        if (ms != null) {
+          return this.formatMsToExecutorTime(ms);
+        }
+        const s = raw != null ? String(raw).trim() : '';
+        return s || '—';
+      },
+
+      getListMaxReportLastTimeMs() {
+        let max = null;
+        (this.List || []).forEach((item) => {
+          const ms = this.parseReportLastTimeMs(item.reportLastTime);
+          if (ms != null) {
+            max = max == null ? ms : Math.max(max, ms);
+          }
+        });
+        return max;
+      },
+
+      onItemExecutorTimeChange(item, val) {
+        if (!val || !item) return;
+        const minMs = this.parseReportLastTimeMs(item.reportLastTime);
+        if (minMs == null) return;
+        const t = this.parseReportLastTimeMs(val);
+        if (t == null) return;
+        if (t < minMs) {
+          const timeStr = this.formatReportLastTimeDisplay(item.reportLastTime);
+          this.$message.warning(
+            `投料时间不能早于上一工序报工时间(上一工序:${timeStr})`
+          );
+          this.$set(item, 'executorTime', '');
+        }
+      },
+
+      validateItemExecutorTime(item) {
+        if (!item || !item.executorTime) return;
+        const minMs = this.parseReportLastTimeMs(item.reportLastTime);
+        if (minMs == null) return;
+        const t = this.parseReportLastTimeMs(item.executorTime);
+        if (t != null && t < minMs) {
+          const timeStr = this.formatReportLastTimeDisplay(item.reportLastTime);
+          this.$message.warning(
+            `缓存的投料时间早于上一工序报工时间(上一工序:${timeStr}),已清空`
+          );
+          this.$set(item, 'executorTime', '');
+        }
+      },
+
       handleCreate(e) {
         if (e) {
+          const minMs = this.getListMaxReportLastTimeMs();
+          if (minMs != null) {
+            const t = this.parseReportLastTimeMs(e);
+            if (t != null && t < minMs) {
+              const timeStr = this.formatMsToExecutorTime(minMs);
+              this.$message.warning(
+                `批量投料时间不能早于各工单上一工序报工时间中最晚的一条(须≥ ${timeStr})`
+              );
+              this.executorTime = '';
+              return;
+            }
+          }
           const list = JSON.parse(JSON.stringify(this.List));
           console.log(list);
           list.map((item) => {
@@ -538,6 +625,15 @@
             });
             this.List = deepClone(arr);
             this.applyDefaultExecutorTime();
+            this.$nextTick(() => {
+              if (this.executorTime) {
+                const t = this.parseReportLastTimeMs(this.executorTime);
+                const minMs = this.getListMaxReportLastTimeMs();
+                if (minMs != null && t != null && t < minMs) {
+                  this.executorTime = '';
+                }
+              }
+            });
           })
           .finally(() => {
             this.isLoad = true;
@@ -565,8 +661,18 @@
         if (!this.useDefaultFeedDate || !this.List || this.List.length === 0) {
           return;
         }
-        const dateTime = this.getNowTime();
+        const nowMs = Date.now();
         this.List.forEach((item) => {
+          const minMs = this.parseReportLastTimeMs(item.reportLastTime);
+          if (minMs != null && nowMs < minMs) {
+            this.$set(item, 'executorTime', '');
+            return;
+          }
+          let dateTime = this.getNowTime();
+          const t = this.parseReportLastTimeMs(dateTime);
+          if (minMs != null && t != null && t < minMs) {
+            dateTime = this.formatMsToExecutorTime(minMs);
+          }
           this.$set(item, 'executorTime', dateTime);
         });
       },
@@ -773,6 +879,7 @@
                 f['revolvingDiskList'] = o.revolvingDiskList || [];
                 f['semiProductList'] = o.semiProductList || [];
                 this.$set(this.List[index], 'executorTime', o.executorTime);
+                this.validateItemExecutorTime(this.List[index]);
                 this.$forceUpdate();
               }
             });
@@ -786,6 +893,19 @@
           return this.$message.warning('请选择投料时间');
         }
 
+        for (const item of this.List) {
+          if (!item.executorTime) continue;
+          const minMs = this.parseReportLastTimeMs(item.reportLastTime);
+          if (minMs == null) continue;
+          const t = this.parseReportLastTimeMs(item.executorTime);
+          if (t != null && t < minMs) {
+            const timeStr = this.formatReportLastTimeDisplay(item.reportLastTime);
+            return this.$message.warning(
+              `工单${item.code}投料时间不能早于上一工序报工时间(上一工序:${timeStr})`
+            );
+          }
+        }
+
         if (this.executorIdList.length == 0) {
           return this.$message.warning('执行人不能为空!');
         }

+ 4 - 0
src/views/produce/components/picking/newWokePopup.vue

@@ -158,6 +158,8 @@
       // },
 
       open(req) {
+        this.rightMode = 'list';
+        this.currentRow = null;
         this.itemData = req;
         this.type = 1;
         this.workList = [];
@@ -176,6 +178,8 @@
       },
 
       openTwo(req) {
+        this.rightMode = 'list';
+        this.currentRow = null;
         this.itemData = req;
         this.type = 2;
         this.workList = [];

+ 12 - 6
src/views/produce/components/prenatalExamination/index.vue

@@ -4,6 +4,7 @@
     :visible.sync="dialogVisible"
     width="60%"
     :before-close="handleClose"
+    append-to-body
   >
     <div>
       <!-- <el-button type="primary" plain round @click="openMaintenancePlan">
@@ -260,7 +261,10 @@
         console.log('item~~~', item);
         // itemType 事项类型
         if (item.itemType == 1) {
-          if((!item.planOrders || item.planOrders.length == 0) && item.executeMethod == 1) {
+          if (
+            (!item.planOrders || item.planOrders.length == 0) &&
+            item.executeMethod == 1
+          ) {
             this.$message.error('未生成设备计划');
             return;
           }
@@ -268,23 +272,25 @@
           this.$refs.planRulesDialogRef.open(item);
         } else if (item.itemType == 2) {
           // 事件驱动
-          if(item.executeMethod == 1) {
+          if (item.executeMethod == 1) {
             // planRulesEventDialogRef
 
             // // 是否有计划
-            if(!item.plans || item.plans.length == 0) {
+            if (!item.plans || item.plans.length == 0) {
               this.$message.error('未生成记录计划');
               return;
             }
 
-            item.plans.forEach(plan => {
+            item.plans.forEach((plan) => {
               // 找到records数组中planid与当前plan.id匹配的记录
-              plan.matchedRecords = item.records.filter(record => record.planId == plan.id);
+              plan.matchedRecords = item.records.filter(
+                (record) => record.planId == plan.id
+              );
             });
             console.log('匹配后的plans数组:', item);
             this.$refs.planRulesEventDialogRef.open(item);
 
-            return
+            return;
 
             // // 有计划无工单  派单
             // if(item.plans && item.plans.length > 0 && (!item.records || item.records.length == 0)) {

+ 8 - 0
src/views/produce/components/qualityInspection/index.vue

@@ -242,6 +242,11 @@
     },
     methods: {
       async open(workOrder, produceTaskInfo, type, req) {
+        // 每次打开重置子界面,避免仍停留在上一次的报工/请托或残留行数据
+        this.leftMode = 'list';
+        this.currentRow = null;
+        this.reportType = null;
+
         this.workOrder = workOrder;
         this.produceTaskInfo = produceTaskInfo;
         this.type = type;
@@ -290,6 +295,9 @@
 
       handleClose() {
         this.dialogVisible = false;
+        this.leftMode = 'list';
+        this.currentRow = null;
+        this.reportType = null;
         this.$emit('close');
       },
       async handleUpdate() {

+ 3 - 1
src/views/produce/components/taskWorkList.vue

@@ -472,7 +472,9 @@
           productName: row.productName,
           specification: row.specification,
           newWeightUnit: row.newWeightUnit,
-          measuringUnit: row.measuringUnit
+          measuringUnit: row.measuringUnit,
+          reportQuantityReported: row.reportQuantity || 0,
+          lossQuantityReported: row.lossQuantity || 0
         };
         let form = {
           realEndTime: row.realEndTime,

+ 625 - 80
src/views/produce/components/warehousing/index.vue

@@ -7,25 +7,61 @@
         style="display: flex; align-items: center; margin-right: 10px"
         v-if="List.length > 1"
       >
-        <div class="rx-bc">
+        <div class="rx-bc" v-if="isReportTime">
           <div class="name">批量报工时间:</div>
+          <div>
+            <el-date-picker
+              v-model="reportTime[0]"
+              type="datetime"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder="开始时间"
+              style="margin-right: 5px; width: 190px"
+              @change="onBatchReportStartTimeChange"
+              :picker-options="pickerOptionsTwo"
+              @calendar-change="handleCalendarChange"
+            >
+            </el-date-picker
+            >至
+            <el-date-picker
+              v-model="reportTime[1]"
+              type="datetime"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder="结束时间"
+              style="margin-left: 5px; width: 190px"
+              @change="onBatchReportEndTimeChange"
+              :picker-options="pickerOptionsTwo"
+              @calendar-change="handleCalendarChange"
+            >
+            </el-date-picker>
+          </div>
+        </div>
+
+        <div class="rx-bc" v-if="!isReportTime">
+          <div class="name">批量报工时间:</div>
+          <el-date-picker
+            v-model="executorTime"
+            type="datetime"
+            format="yyyy-MM-dd HH:mm:ss"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="选择日期"
+            @change="handleCreate"
+            :picker-options="pickerOptions"
+          >
+          </el-date-picker>
         </div>
-        <el-date-picker
-          v-model="executorTime"
-          type="datetime"
-          format="yyyy-MM-dd HH:mm:ss"
-          value-format="yyyy-MM-dd HH:mm:ss"
-          placeholder="选择日期"
-          @change="handleCreate"
-          :picker-options="pickerOptions"
-        >
-        </el-date-picker>
       </div>
       <el-button type="primary" size="mini" @click="save">一键报工</el-button>
     </div>
 
     <div class="warehousing_box">
-      <div v-for="(item, index) in List" :key="index" class="card_box">
+      <div
+        v-for="(item, index) in List"
+        :key="index"
+        class="card_box"
+        v-if="isLoad"
+      >
         <div class="title_box rx-bc">
           <div class="name">工单信息</div>
         </div>
@@ -41,53 +77,136 @@
           <div class="title_box rx-bc">
             <div class="name">报工时间</div>
           </div>
-          报工时间:
-          <el-date-picker
-            v-model="item.workReportInfo.executorTime"
-            type="datetime"
-            format="yyyy-MM-dd HH:mm:ss"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            placeholder="选择日期"
-            style="margin-right: 25px; width: 190px"
-            :picker-options="pickerOptions"
-          >
-          </el-date-picker>
-          执行人:
-          <el-select
-            v-model="teamId"
-            placeholder="请选择班组"
-            filterable
-            style="width: 120px"
-            @change="checkTeamList(teamId)"
-          >
-            <el-option
-              v-for="item in teamList"
-              :label="item.name"
-              :value="item.id"
-              :key="item.id"
+
+          <div v-if="isReportTime">
+            报工时间
+            <el-date-picker
+              v-model="item.workReportInfo.executorStartTime"
+              type="datetime"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder="开始时间"
+              style="margin-right: 5px; width: 190px"
+              @change="onExecutorStartTimeChange(index)"
+              @calendar-change="handleCalendarChange"
+              :picker-options="pickerOptionsTwo"
             >
-            </el-option>
-          </el-select>
-          <el-select
-            v-model="executorIdList"
-            placeholder="请选择执行人"
-            filterable
-            multiple
-            @change="changeId"
-          >
-            <div class="checkboxWrapper">
-              <el-checkbox v-model="checked" @change="checkChange">
-                全选
-              </el-checkbox>
+            </el-date-picker
+            >至
+            <el-date-picker
+              v-model="item.workReportInfo.executorTime"
+              type="datetime"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder="结束时间"
+              style="margin-left: 5px; width: 190px"
+              @change="onExecutorEndTimeChange(index)"
+              @calendar-change="handleCalendarChange"
+              :picker-options="pickerOptionsTwo"
+            >
+            </el-date-picker>
+
+            工时
+            <el-input
+              v-model="item.workReportInfo.workTime"
+              placeholder="请输入工时"
+              style="width: 220px"
+            >
+              <template slot="append">小时</template>
+            </el-input>
+
+            <div style="margin-top: 10px">
+              执行人:
+              <el-select
+                v-model="teamId"
+                placeholder="请选择班组"
+                filterable
+                style="width: 120px"
+                @change="checkTeamList(teamId)"
+              >
+                <el-option
+                  v-for="item in teamList"
+                  :label="item.name"
+                  :value="item.id"
+                  :key="item.id"
+                >
+                </el-option>
+              </el-select>
+              <el-select
+                v-model="executorIdList"
+                placeholder="请选择执行人"
+                filterable
+                multiple
+                @change="changeId(index)"
+                style="width: 160px"
+              >
+                <div class="checkboxWrapper">
+                  <el-checkbox v-model="checked" @change="checkChange(index)">
+                    全选
+                  </el-checkbox>
+                </div>
+                <el-option
+                  v-for="item in teamUserList"
+                  :label="item.name"
+                  :value="item.id"
+                  :key="item.id"
+                >
+                </el-option>
+              </el-select>
             </div>
-            <el-option
-              v-for="item in teamUserList"
-              :label="item.name"
-              :value="item.id"
-              :key="item.id"
+          </div>
+
+          <div v-else>
+            报工时间:
+            <el-date-picker
+              v-model="item.workReportInfo.executorTime"
+              type="datetime"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder="选择日期"
+              style="margin-right: 25px; width: 190px"
+              :picker-options="pickerOptions"
+              @change="onSingleExecutorTimeChange(index)"
+            >
+            </el-date-picker>
+
+            执行人:
+            <el-select
+              v-model="teamId"
+              placeholder="请选择班组"
+              filterable
+              style="width: 120px"
+              @change="checkTeamList(teamId)"
+            >
+              <el-option
+                v-for="item in teamList"
+                :label="item.name"
+                :value="item.id"
+                :key="item.id"
+              >
+              </el-option>
+            </el-select>
+            <el-select
+              v-model="executorIdList"
+              placeholder="请选择执行人"
+              filterable
+              multiple
+              @change="changeId(index)"
             >
-            </el-option>
-          </el-select>
+              <div class="checkboxWrapper">
+                <el-checkbox v-model="checked" @change="checkChange(index)">
+                  全选
+                </el-checkbox>
+              </div>
+              <el-option
+                v-for="item in teamUserList"
+                :label="item.name"
+                :value="item.id"
+                :key="item.id"
+              >
+              </el-option>
+            </el-select>
+          </div>
         </div>
         <!--
         <div>
@@ -323,17 +442,19 @@
         teamId: '',
         teamName: '',
         checked: false,
+        isReportTime: false,
+        reportTime: [null, null],
+        isDefaultExecutor: false,
         pickerOptions: {
           disabledDate(time) {
             // 禁止选择大于当前时间的日期
             return time.getTime() > Date.now();
           }
-          // selectableRange: (() => {
-          //   const now = new Date();
-          //   const start = '00:00:00';
-          //   const end = now.toTimeString().split(' ')[0];
-          //   return `${start} - ${end}`;
-          // })()
+        },
+        pickerOptionsTwo: {
+          disabledDate: (time) => {
+            return time.getTime() > Date.now();
+          }
         }
       };
     },
@@ -398,8 +519,11 @@
                 formingWeight: null,
                 formedNum: null,
                 formedWeight: null,
-                taskId: '',
+                taskId: this.taskObj.id,
                 executorTime: null,
+                executorStartTime: null,
+                reportTime: '',
+                workTime: '',
                 lossQuantity: null,
                 lossWeight: null
               };
@@ -456,6 +580,13 @@
                 ...obj
               };
             });
+            if (
+              this.isReportTime &&
+              this.idsList.length == 1 &&
+              this.List.length > 0
+            ) {
+              this.applyDefaultReportTimeWhenSingle();
+            }
             this.List.forEach((item) => {
               if (item.semiProductList && item.semiProductList.length != 0) {
                 item.semiProductList.forEach((it) => {
@@ -499,20 +630,38 @@
 
       async getChooseEngrave() {
         await parameterGetByCode({
-          code: 'choose_engrave'
+          code: 'work_hour'
         }).then((res) => {
-          this.isChoose = res.value == '1' ? true : false;
+          this.isReportTime = res.value == '1' ? true : false;
+
+          if (this.isReportTime && this.idsList.length == 1) {
+            this.applyDefaultReportTimeWhenSingle();
+          }
         });
 
-        await parameterGetByCode({
+        const feedByDefaultRes = await parameterGetByCode({
           code: 'mes_order_feed_by_default_date'
-        }).then((res) => {
-          if (res.value == '1') {
-            const dateTime = this.getNowTime();
+        });
+
+        if (feedByDefaultRes.value == '1') {
+          const dateTime = this.getNowTime();
+
+          this.$nextTick(() => {
             this.List.forEach((item) => {
-              item.workReportInfo.executorTime = dateTime;
+              if (!item.workReportInfo) {
+                this.$set(item, 'workReportInfo', {});
+              }
+              if (!this.isReportTime) {
+                this.$set(item.workReportInfo, 'executorTime', dateTime);
+              }
             });
-          }
+          });
+        }
+
+        await parameterGetByCode({
+          code: 'choose_engrave'
+        }).then((res) => {
+          this.isChoose = res.value == '1' ? true : false;
         });
 
         await parameterGetByCode({
@@ -538,6 +687,307 @@
         });
       },
 
+      applyDefaultReportTimeWhenSingle() {
+        if (
+          !this.isReportTime ||
+          this.idsList.length !== 1 ||
+          !this.List ||
+          this.List.length === 0
+        ) {
+          return;
+        }
+        const dateTime = this.getNowTime();
+        this.List.forEach((item, index) => {
+          item.workReportInfo.executorStartTime = item.feedLastTime;
+          this.$set(item.workReportInfo, 'executorTime', dateTime);
+          this.calculateWorkTimeByStartEnd(index);
+        });
+      },
+
+      parseDateTime(val) {
+        if (!val) return null;
+        if (val instanceof Date) return val;
+        if (typeof val === 'string') {
+          return new Date(val.replace(/-/g, '/'));
+        }
+        return new Date(val);
+      },
+
+      formatDateTimeString(date) {
+        if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
+          return null;
+        }
+        const p = (n) => String(n).padStart(2, '0');
+        return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(
+          date.getDate()
+        )} ${p(date.getHours())}:${p(date.getMinutes())}:${p(
+          date.getSeconds()
+        )}`;
+      },
+
+      isTimeBeforeFeedLastTime(selected, feedLastTime) {
+        if (!feedLastTime || !selected) return false;
+        const t = this.parseDateTime(selected);
+        const f = this.parseDateTime(feedLastTime);
+        if (!t || !f || isNaN(t.getTime()) || isNaN(f.getTime())) return false;
+        return t.getTime() < f.getTime();
+      },
+
+      handleCalendarChange(val) {
+        if (!val) return;
+        const selected = Array.isArray(val) ? val[val.length - 1] : val;
+        if (!selected) return;
+        const now = new Date();
+        const todayStr = now.toDateString();
+        const selectedStr = new Date(selected).toDateString();
+
+        if (todayStr === selectedStr) {
+          const end = now.toTimeString().split(' ')[0];
+          this.pickerOptions.selectableRange = `00:00:00 - ${end}`;
+        } else {
+          this.pickerOptions.selectableRange = '00:00:00 - 23:59:59';
+        }
+      },
+
+      changeBatchReportTime(e) {
+        if (e) {
+          const list = JSON.parse(JSON.stringify(this.List));
+          list.map((item) => {
+            item.workReportInfo.reportTime = e;
+            item.workReportInfo.executorStartTime = e[0];
+            item.workReportInfo.executorTime = e[1];
+            const startTime = new Date(item.workReportInfo.reportTime[0]);
+            const endTime = new Date(item.workReportInfo.reportTime[1]);
+
+            const diffMs = endTime - startTime;
+            const diffHours = diffMs / (1000 * 60 * 60);
+
+            if (this.executorIdList.length != 0) {
+              item.workReportInfo.workTime = Number(
+                (
+                  Number(diffHours) * Number(this.executorIdList.length)
+                ).toFixed(2)
+              );
+            } else {
+              item.workReportInfo.workTime = Number(
+                Number(diffHours).toFixed(2)
+              );
+            }
+          });
+          this.$set(this, 'List', list);
+        }
+      },
+
+      onBatchReportStartTimeChange() {
+        if (!Array.isArray(this.reportTime)) {
+          this.$set(this, 'reportTime', [this.reportTime, null]);
+        }
+        this.tryApplyBatchReportTime();
+      },
+
+      onBatchReportEndTimeChange() {
+        if (!Array.isArray(this.reportTime)) {
+          this.$set(this, 'reportTime', [null, this.reportTime]);
+        }
+        this.tryApplyBatchReportTime();
+      },
+
+      tryApplyBatchReportTime() {
+        const [start, end] = Array.isArray(this.reportTime)
+          ? this.reportTime
+          : [null, null];
+        if (!start || !end) return;
+
+        const startDate = this.parseDateTime(start);
+        const endDate = this.parseDateTime(end);
+
+        if (startDate && startDate.getTime() > Date.now()) {
+          this.$set(this.reportTime, 0, null);
+          this.$message?.warning?.('开始时间不能超过当前时间');
+          return;
+        }
+        if (endDate && endDate.getTime() > Date.now()) {
+          this.$set(this.reportTime, 1, null);
+          this.$message?.warning?.('结束时间不能超过当前时间');
+          return;
+        }
+        if (startDate && endDate && startDate > endDate) {
+          this.$set(this.reportTime, 1, null);
+          this.$message?.warning?.('结束时间不能小于开始时间');
+          return;
+        }
+
+        let adjustedStart = start;
+        let maxFeedMs = null;
+        for (const item of this.List) {
+          if (item.feedLastTime) {
+            const f = this.parseDateTime(item.feedLastTime);
+            if (f && !isNaN(f.getTime())) {
+              maxFeedMs =
+                maxFeedMs == null
+                  ? f.getTime()
+                  : Math.max(maxFeedMs, f.getTime());
+            }
+          }
+        }
+
+        if (
+          maxFeedMs != null &&
+          startDate &&
+          startDate.getTime() < maxFeedMs
+        ) {
+          adjustedStart = this.formatDateTimeString(new Date(maxFeedMs));
+          this.$message?.warning?.(
+            '批量开始时间不能小于最后投料时间,已调整为最晚投料时间'
+          );
+        }
+
+        let adjustedEnd = end;
+        const adjStartD = this.parseDateTime(adjustedStart);
+        const endD = this.parseDateTime(adjustedEnd);
+        if (adjStartD && endD && adjStartD > endD) {
+          adjustedEnd = adjustedStart;
+          this.$set(this.reportTime, 1, adjustedEnd);
+        }
+        if (adjustedStart !== start) {
+          this.$set(this.reportTime, 0, adjustedStart);
+        }
+
+        this.changeBatchReportTime([adjustedStart, adjustedEnd]);
+      },
+
+      onSingleExecutorTimeChange(index) {
+        if (this.isReportTime) return;
+        const item = this.List?.[index];
+        const info = item?.workReportInfo;
+        if (!item || !info) return;
+        if (
+          item.feedLastTime &&
+          this.isTimeBeforeFeedLastTime(info.executorTime, item.feedLastTime)
+        ) {
+          this.$set(info, 'executorTime', item.feedLastTime);
+          this.$message?.warning?.(
+            '报工时间不能小于最后投料时间,已调整为最后投料时间'
+          );
+        }
+      },
+
+      onExecutorStartTimeChange(index) {
+        const info = this.List?.[index]?.workReportInfo;
+        if (!info) return;
+
+        const start = this.parseDateTime(info.executorStartTime);
+        const end = this.parseDateTime(info.executorTime);
+
+        if (start && start.getTime() > Date.now()) {
+          info.executorStartTime = null;
+          info.workTime = '';
+          this.$message?.warning?.('开始时间不能超过当前时间');
+          return;
+        }
+
+        const rowItem = this.List?.[index];
+        if (
+          rowItem?.feedLastTime &&
+          this.isTimeBeforeFeedLastTime(
+            info.executorStartTime,
+            rowItem.feedLastTime
+          )
+        ) {
+          this.$set(info, 'executorStartTime', rowItem.feedLastTime);
+          this.$message?.warning?.(
+            '开始时间不能小于最后投料时间,已调整为最后投料时间'
+          );
+          const start2 = this.parseDateTime(info.executorStartTime);
+          const end2 = this.parseDateTime(info.executorTime);
+          if (start2 && end2 && start2 > end2) {
+            this.$set(info, 'executorTime', info.executorStartTime);
+          }
+          this.calculateWorkTimeByStartEnd(index);
+          return;
+        }
+
+        if (start && end && start > end) {
+          info.executorStartTime = null;
+          info.workTime = '';
+          this.$message?.warning?.('开始时间不能大于结束时间');
+          return;
+        }
+
+        this.calculateWorkTimeByStartEnd(index);
+      },
+
+      onExecutorEndTimeChange(index) {
+        const info = this.List?.[index]?.workReportInfo;
+        if (!info) return;
+
+        const start = this.parseDateTime(info.executorStartTime);
+        const end = this.parseDateTime(info.executorTime);
+
+        if (end && end.getTime() > Date.now()) {
+          info.executorTime = null;
+          info.workTime = '';
+          this.$message?.warning?.('结束时间不能超过当前时间');
+          return;
+        }
+
+        if (start && end && end < start) {
+          info.executorTime = null;
+          info.workTime = '';
+          this.$message?.warning?.('结束时间不能小于开始时间');
+          return;
+        }
+
+        this.calculateWorkTimeByStartEnd(index);
+      },
+
+      calculateWorkTimeByStartEnd(index) {
+        const info = this.List?.[index]?.workReportInfo;
+        if (!info) return;
+
+        const start = this.parseDateTime(info.executorStartTime);
+        const end = this.parseDateTime(info.executorTime);
+
+        if (!start || !end) {
+          info.workTime = '';
+          return;
+        }
+
+        const diffMs = end - start;
+        if (!(diffMs >= 0)) {
+          info.workTime = '';
+          return;
+        }
+
+        const diffHours = diffMs / (1000 * 60 * 60);
+        const baseHours = Number.isFinite(diffHours) ? Number(diffHours) : 0;
+        const totalHours =
+          this.executorIdList.length != 0
+            ? baseHours * Number(this.executorIdList.length)
+            : baseHours;
+        info.workTime = Number(totalHours.toFixed(2));
+      },
+
+      calculateWorkingHours(index) {
+        const startTime = new Date(
+          this.List[index].workReportInfo.reportTime[0]
+        );
+        const endTime = new Date(this.List[index].workReportInfo.reportTime[1]);
+
+        const diffMs = endTime - startTime;
+        const diffHours = diffMs / (1000 * 60 * 60);
+
+        if (this.executorIdList.length != 0) {
+          this.List[index].workReportInfo.workTime = Number(
+            (Number(diffHours) * Number(this.executorIdList.length)).toFixed(2)
+          );
+        } else {
+          this.List[index].workReportInfo.workTime = Number(
+            Number(diffHours).toFixed(2)
+          );
+        }
+      },
+
       setDefaultIdList() {
         if (this.teamList.length != 0) {
           this.teamId = this.teamList[0].id;
@@ -581,7 +1031,15 @@
         });
       },
 
-      changeId() {
+      changeId(index) {
+        if (this.isReportTime) {
+          if (this.List?.[index]?.workReportInfo?.reportTime) {
+            this.calculateWorkingHours(index);
+          } else {
+            this.calculateWorkTimeByStartEnd(index);
+          }
+        }
+
         if (this.executorIdList.length == this.teamUserList.length) {
           this.checked = true;
         } else {
@@ -596,12 +1054,23 @@
         this.teamUserList = this.teamAllList[index];
       },
 
-      checkChange() {
+      checkChange(index) {
         if (this.checked) {
           this.executorIdList = [];
           this.executorIdList = this.teamUserList.map((item) => item.id);
         } else {
           this.executorIdList = [];
+          if (this.List[index]?.workReportInfo) {
+            this.List[index].workReportInfo.workTime = '';
+          }
+        }
+
+        if (this.isReportTime) {
+          if (this.List?.[index]?.workReportInfo?.reportTime) {
+            this.calculateWorkingHours(index);
+          } else {
+            this.calculateWorkTimeByStartEnd(index);
+          }
         }
       },
 
@@ -708,20 +1177,96 @@
 
       handleCreate(e) {
         if (e) {
+          let anyAdjusted = false;
           const list = JSON.parse(JSON.stringify(this.List));
-          console.log(list);
-          list.map((item) => {
-            item.workReportInfo.executorTime = e;
+          list.forEach((item) => {
+            let t = e;
+            if (
+              item.feedLastTime &&
+              this.isTimeBeforeFeedLastTime(e, item.feedLastTime)
+            ) {
+              t = item.feedLastTime;
+              anyAdjusted = true;
+            }
+            item.workReportInfo.executorTime = t;
           });
+          if (anyAdjusted) {
+            this.$message?.warning?.(
+              '报工时间不能小于最后投料时间,已调整为对应工单的最后投料时间'
+            );
+          }
           this.$set(this, 'List', list);
         }
       },
 
       save() {
-        for (let i = 0; i < this.List.length; i++) {
-          if (!this.List[i].workReportInfo.executorTime) {
-            this.$message.warning('报工时间不能为空');
-            return;
+        if (this.isReportTime) {
+          let feedStartAdjusted = false;
+          for (let i = 0; i < this.List.length; i++) {
+            const item = this.List[i];
+            if (!item.workReportInfo.executorStartTime) {
+              return this.$message.warning('请选择开始时间');
+            }
+            if (!item.workReportInfo.executorTime) {
+              return this.$message.warning('请选择结束时间');
+            }
+            if (
+              item.feedLastTime &&
+              this.isTimeBeforeFeedLastTime(
+                item.workReportInfo.executorStartTime,
+                item.feedLastTime
+              )
+            ) {
+              this.$set(
+                item.workReportInfo,
+                'executorStartTime',
+                item.feedLastTime
+              );
+              const s2 = this.parseDateTime(
+                item.workReportInfo.executorStartTime
+              );
+              const e2 = this.parseDateTime(item.workReportInfo.executorTime);
+              if (s2 && e2 && s2 > e2) {
+                this.$set(
+                  item.workReportInfo,
+                  'executorTime',
+                  item.workReportInfo.executorStartTime
+                );
+              }
+              this.calculateWorkTimeByStartEnd(i);
+              feedStartAdjusted = true;
+            }
+          }
+          if (feedStartAdjusted) {
+            this.$message.warning(
+              '开始时间不能小于最后投料时间,已调整为最后投料时间'
+            );
+          }
+        } else {
+          for (let i = 0; i < this.List.length; i++) {
+            if (!this.List[i].workReportInfo.executorTime) {
+              this.$message.warning('报工时间不能为空');
+              return;
+            }
+          }
+          let execTimeAdjusted = false;
+          for (const item of this.List) {
+            if (!item.workReportInfo.executorTime) continue;
+            if (
+              item.feedLastTime &&
+              this.isTimeBeforeFeedLastTime(
+                item.workReportInfo.executorTime,
+                item.feedLastTime
+              )
+            ) {
+              this.$set(item.workReportInfo, 'executorTime', item.feedLastTime);
+              execTimeAdjusted = true;
+            }
+          }
+          if (execTimeAdjusted) {
+            this.$message.warning(
+              '报工时间不能小于最后投料时间,已调整为最后投料时间'
+            );
           }
         }
 

+ 7 - 1
src/views/produce/components/workOrderHandover/index.vue

@@ -651,7 +651,13 @@
           .catch(() => {});
       },
       allSelection(id, list) {
-        this.materialList = list;
+        // console.log(list, 'list');
+        this.materialList = list.map((item) => {
+          return {
+            ...item,
+            modelType: item.categoryModel
+          };
+        });
       },
       /* 删除 */
       remove(row) {

+ 91 - 6
src/views/produceOrder/components/details/dotLineDetail.vue

@@ -1,5 +1,20 @@
 <template>
   <div class="plan-dot-line">
+    <div class="plan-time-bar">
+      <span class="plan-time-item">
+        <span class="plan-time-label">计划开始时间:</span>
+        <span class="plan-time-value">{{ planStartDisplay }}</span>
+      </span>
+      <span class="plan-time-item">
+        <span class="plan-time-label">计划结束时间:</span>
+        <span class="plan-time-value">{{ planEndDisplay }}</span>
+      </span>
+
+      <span class="plan-time-item">
+        <span class="plan-time-label">计划数量:</span>
+        <span class="plan-time-value">{{ planNumDisplay }}</span>
+      </span>
+    </div>
     <div class="top-route">
       <div class="panel-title">工艺路线</div>
       <el-empty
@@ -42,8 +57,8 @@
             label="序号"
             width="60"
             align="center"
-            class-name="process-name-cell"
-            label-class-name="config-execution-team-header"
+            class-name="config-index-cell"
+            label-class-name="config-index-header"
           />
           <el-table-column
             label="工序名称"
@@ -106,6 +121,18 @@
 <script>
   import { getPlanDotLine } from '@/api/produceOrder/index';
   const EXEC_TYPE_MAP = { 0: '自制', 1: '请托', 2: '委外' };
+
+  function formatDateTime(val) {
+    if (val == null || val === '') return '';
+    const str = String(val).trim();
+    if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(str)) return str;
+    const d = new Date(val);
+    if (Number.isNaN(d.getTime())) return '';
+    const p = (n) => String(n).padStart(2, '0');
+    return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(
+      d.getHours()
+    )}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
+  }
   export default {
     props: {
       workOrderInfo: {
@@ -140,6 +167,18 @@
         if (!list.length) return -1;
         const a = this.dotLineRouteStepsActive;
         return a >= list.length ? list.length - 1 : a;
+      },
+      planStartDisplay() {
+        const t = this.workOrderInfo?.planStartTime;
+        return t ? formatDateTime(t) || String(t) : '—';
+      },
+      planEndDisplay() {
+        const t = this.workOrderInfo?.planCompleteTime;
+        return t ? formatDateTime(t) || String(t) : '—';
+      },
+      planNumDisplay() {
+        const t = this.workOrderInfo?.formingNum + this.workOrderInfo?.unit;
+        return t ? t : '—';
       }
     },
 
@@ -268,6 +307,35 @@
     min-height: 360px;
   }
 
+  .plan-time-bar {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 12px 28px;
+    margin-bottom: 12px;
+    padding: 10px 12px;
+    border: 1px solid #ebeef5;
+    border-radius: 4px;
+    background: #fafafa;
+    font-size: 14px;
+  }
+
+  .plan-time-item {
+    display: inline-flex;
+    align-items: baseline;
+    gap: 4px;
+  }
+
+  .plan-time-label {
+    color: #606266;
+    white-space: nowrap;
+  }
+
+  .plan-time-value {
+    color: #303133;
+    font-weight: 500;
+  }
+
   .top-route,
   .config-panel {
     border: 1px solid #ebeef5;
@@ -317,16 +385,29 @@
       word-break: break-all;
     }
     .el-step.active .el-step__title {
-      color: #409eff;
+      color: #157a2c;
       font-weight: 600;
     }
+    .el-step__head.is-process {
+      color: #157a2c;
+      border-color: #157a2c;
+    }
+    .el-step__title.is-process {
+      color: #157a2c;
+    }
     .el-step__head.is-success {
-      color: #0c7741;
-      border-color: #0c7741;
+      color: #157a2c;
+      border-color: #157a2c;
     }
     .el-step__title.is-success,
     .el-step__description.is-success {
-      color: #0c7741;
+      color: #157a2c;
+    }
+    .el-step__head.is-success .el-step__line {
+      background-color: #157a2c;
+    }
+    .el-step__head.is-success .el-step__line-inner {
+      border-color: #157a2c;
     }
     .el-step__line {
       top: 14px;
@@ -378,5 +459,9 @@
       font-weight: 500;
       line-height: 1.4;
     }
+    th.config-index-header > .cell,
+    td.config-index-cell > .cell {
+      font-size: 14px;
+    }
   }
 </style>

+ 63 - 2
src/views/produceOrder/workReport.vue

@@ -244,6 +244,11 @@
       <!-- <workes ref="jobRefs"> </workes> -->
 
       <!-- :workListIds="workListIds" :taskId="taskObj.id" -->
+      <!-- 产前准备 、 过程控制 、产后检测 -->
+      <prenatalExamination
+        ref="prenatalExaminationRef"
+        @close="closePrenatalExamination"
+      />
       <!-- 工步 -->
       <workStep ref="workStepRef" />
       <!--  任务  -->
@@ -264,6 +269,7 @@
   import TaskDialog from '@/views/produce/components/taskDialog/index.vue';
   import Search from '@/views/produce/components/search.vue';
   import footBtn from '@/views/produce/components/footBtn.vue';
+  import prenatalExamination from '@/views/produce/components/prenatalExamination/index.vue';
   import produceOrder from '@/views/produce/components/new_produceOrder.vue';
   import productionResource from '@/views/produce/components/productionResource/index.vue';
   import outsourcing from '@/views/produce/components/outsourcing/index.vue';
@@ -333,7 +339,8 @@
       outsourcingDetails,
       pleaseEntrust,
       addPlease,
-      qualityInspection
+      qualityInspection,
+      prenatalExamination
     },
     data() {
       return {
@@ -954,6 +961,48 @@
           );
         }
 
+        // this.$refs.prenatalExaminationRef.open(
+        //   this.workData.list[0],
+        //   this.produceTaskInfo,
+        //   type
+        // );
+
+        if (t == 'prenatalExamination') {
+          if (this.workListIds.length > 1) {
+            return this.$message.warning('产前准备只能选择一个工单!');
+          }
+
+          this.$refs.prenatalExaminationRef.open(
+            this.workOrderInfo,
+            this.taskObj,
+            1
+          );
+        }
+
+        if (t == 'postpartumExamination') {
+          if (this.workListIds.length > 1) {
+            return this.$message.warning('产后检查只能选择一个工单!');
+          }
+
+          this.$refs.prenatalExaminationRef.open(
+            this.workOrderInfo,
+            this.taskObj,
+            3
+          );
+        }
+
+        if (t == 'processDetection') {
+          if (this.workListIds.length > 1) {
+            return this.$message.warning('过程控制只能选择一个工单!');
+          }
+
+          this.$refs.prenatalExaminationRef.open(
+            this.workOrderInfo,
+            this.taskObj,
+            2
+          );
+        }
+
         if (t === 'error') {
           if (this.workListIds.length > 1) {
             return this.$message.warning('异常只能选择一个工单!');
@@ -996,9 +1045,17 @@
             return this.$message.warning('首件两检只能选择一个工单!');
           }
 
+          const req = {
+            taskId: this.taskObj.id,
+            workOrderId: this.workOrderInfo.id,
+            productCode: this.workOrderInfo.productCode
+          };
+
           this.$refs.qualityInspectionRef.open(
             this.workOrderInfo,
-            this.taskObj
+            this.taskObj,
+            '',
+            req
           );
         }
       },
@@ -1131,6 +1188,10 @@
         // this.pickingShow = true;
       },
 
+      closePrenatalExamination() {
+        // this.checkProductionResult();
+      },
+
       async checkPick() {
         await checkRepeatPick({
           workOrderId: this.workListIds[0]

+ 27 - 13
src/views/taskList/components/Ddtails.vue

@@ -328,14 +328,13 @@
     },
     methods: {
       open(type, row, form) {
+        console.log(type, row, form, 'type, row, form');
         this.title = type === 'report' ? '报工' : '详情';
         this.detailsVisible = true;
         this.current = { ...row };
         if (form.realEndTime) {
           this.$nextTick(() => {
             this.form = { ...form };
-            this.reportNum = form.reportQuantity ? form.reportQuantity : 0;
-            this.lossNum = form.lossQuantity ? form.lossQuantity : 0;
           });
           if (type !== 'report') {
             listUpdateRealTimeRecord(row.apsAssigneeId)
@@ -349,6 +348,9 @@
               });
           }
         }
+        // 累计已报工、已损耗(来自任务行,勿用表单预填的本次可报剩余)
+        this.reportNum = Number(this.current.reportQuantityReported) || 0;
+        this.lossNum = Number(this.current.lossQuantityReported) || 0;
         this.getData();
       },
       cancel() {
@@ -425,18 +427,19 @@
           this.$message.warning('合格重量加不合格重量不能大于任务重量');
         }
       },
-      // 计算数量
+      // 计算数量:本次报工+本次损耗 不能超过 要求完成数量 - 已报工 - 已损耗
       calculateQuantity(type) {
-        const actualQuantity = this.add(this.reportNum, this.lossNum);
-        const remainingQuantity = this.sub(
-          this.current.formingNum,
-          actualQuantity
-        );
-
-        let total = this.form.reportQuantity - 0 + (this.form.lossQuantity - 0);
-        if (total > remainingQuantity) {
-          this.form[type] = 0;
-          this.$message.warning('报工数量加损耗数量不能大于要求完成数量');
+        const req = Number(this.current.formingNum) || 0;
+        const done = this.add(this.reportNum, this.lossNum);
+        const remaining = this.sub(req, done);
+        const curRep = Number(this.form.reportQuantity) || 0;
+        const curLoss = Number(this.form.lossQuantity) || 0;
+        const curTotal = this.add(curRep, curLoss);
+        if (curTotal > remaining) {
+          this.form[type] = '';
+          this.$message.warning(
+            `本次报工数与损耗数之和不能超过剩余可报数量(剩余 ${remaining})`
+          );
         }
       },
 
@@ -502,6 +505,17 @@
       submitAdd() {
         this.$refs.form.validate((valid) => {
           if (!valid) return;
+          const req = Number(this.current.formingNum) || 0;
+          const done = this.add(this.reportNum, this.lossNum);
+          const remaining = this.sub(req, done);
+          const curRep = Number(this.form.reportQuantity) || 0;
+          const curLoss = Number(this.form.lossQuantity) || 0;
+          const curTotal = this.add(curRep, curLoss);
+          if (curTotal > remaining) {
+            return this.$message.warning(
+              `本次报工数与损耗数之和不能超过剩余数量(剩余 ${remaining})`
+            );
+          }
           // if (
           //   this.form.qualifiedQuantity -
           //     0 +

+ 4 - 1
src/views/taskList/index.vue

@@ -945,7 +945,10 @@
           productName: row.productName,
           specification: row.specification,
           newWeightUnit: row.newWeightUnit,
-          measuringUnit: row.measuringUnit
+          measuringUnit: row.measuringUnit,
+          // 累计已报工、已损耗(用于报工校验,与表单中本次填写区分)
+          reportQuantityReported: row.reportQuantity || 0,
+          lossQuantityReported: row.lossQuantity || 0
         };
         const actualQuantity = this.add(
           row.reportQuantity ? row.reportQuantity : 0,