lucw il y a 7 mois
Parent
commit
ab9e8e5b9c

+ 13 - 10
src/views/batchRecord/components/editModal.vue

@@ -396,10 +396,7 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="牌号">
-              <el-input
-                v-model="form.brandNo"
-                placeholder="请输入牌号"
-              ></el-input>
+              <el-input v-model="form.brandNo" placeholder="牌号"></el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -452,7 +449,7 @@
             <el-form-item label="批次号" prop="batchNo">
               <el-input
                 v-model="form.batchNo"
-                placeholder="请输入"
+                placeholder="批次号"
                 :disabled="Boolean(form.workOrderId)"
               ></el-input>
             </el-form-item>
@@ -463,7 +460,7 @@
             <el-form-item label="规格" prop="specification">
               <el-input
                 v-model="form.specification"
-                placeholder="请输入"
+                placeholder="规格"
                 :disabled="Boolean(form.workOrderId)"
               ></el-input>
             </el-form-item>
@@ -472,7 +469,7 @@
             <el-form-item label="型号" prop="productModel">
               <el-input
                 v-model="form.productModel"
-                placeholder="请输入"
+                placeholder="型号"
                 :disabled="Boolean(form.workOrderId)"
               ></el-input>
             </el-form-item>
@@ -488,9 +485,13 @@
             >
               <el-input
                 v-model.number="form.formingNum"
-                placeholder="请输入"
+                placeholder="要求生产数量"
                 :disabled="Boolean(form.workOrderId)"
-              ></el-input>
+              >
+                <template slot="append" v-if="workOrderInfo">
+                  {{ workOrderInfo.unit }}
+                </template>
+              </el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -543,6 +544,8 @@
             :bomCategoryId="workOrderInfo ? workOrderInfo.bomCategoryId : ''"
             :ruleId="form.ruleId"
             :rulesDetailList="rulesDetailList"
+            :unit="workOrderInfo ? workOrderInfo.unit : ''"
+            :formingNum="workOrderInfo ? workOrderInfo.formingNum : 0"
           ></statistics>
         </template>
 
@@ -1484,7 +1487,7 @@
           }
         }
 
-        if (this.$refs.statisticsRef && type != 'cache') {
+        if (this.$refs.statisticsRef && type != 'cache' && type != 'submit-reset') {
           // 验证统计项目
           const valid = this.$refs.statisticsRef.validateStatisticsFilled();
           if (!valid) {

+ 374 - 112
src/views/batchRecord/components/statistics.vue

@@ -29,31 +29,72 @@
         v-slot:[`column_${index}`]="{ row }"
       >
         <div :key="`column_${index}`" class="column_content">
-          <div v-if="row[index].isOnlyShow">
+          <!-- 文本 -->
+          <div v-if="row[index].paramType == 7 || row[index].isOnlyShow">
             {{ row[index].value }}
           </div>
-          <el-input
-            v-else
-            v-model.number="row[index].value"
-            :placeholder="
-              row[index].formula
-                ? row[index].formula.replace(/[\[\]]/g, '')
-                : `请输入${row[index].title}`
-            "
-            :disabled="Boolean(row[index].formula)"
-            @input="handleDataChange(row[index], row)"
-          >
-            <template v-if="!row[index].isOnlyShow" slot="append">
-              <div style="width: 80px; height: 100%">
+          <!-- 数值 -->
+          <template v-else-if="row[index].paramType == 1">
+            <div style="display: flex">
+              <el-input-number
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                :disabled="Boolean(row[index].formula)"
+                :controls="false"
+                @input="handleDataChange(row)"
+              ></el-input-number>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
                 <DictSelection
                   v-model="row[index].unit"
                   dictName="工艺参数单位"
                   placeholder="单位"
                 >
-                </DictSelection>
-              </div>
-            </template>
-          </el-input>
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 公式 -->
+          <template v-else-if="row[index].paramType == 9">
+            <div style="display: flex">
+              <el-input
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                disabled
+                @input="handleDataChange(row)"
+              ></el-input>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
+                <DictSelection
+                  v-model="row[index].unit"
+                  dictName="工艺参数单位"
+                  placeholder="单位"
+                >
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 时间 -->
+          <el-date-picker
+            v-else-if="row[index].paramType == 5"
+            v-model="row[index].value"
+            type="datetime"
+            placeholder="选择日期时间"
+            style="width: 100%"
+          >
+          </el-date-picker>
+          <!-- 其他 -->
+          <el-input
+            v-else
+            v-model="row[index].value"
+            placeholder="请输入内容"
+          ></el-input>
         </div>
       </template>
     </ele-pro-table>
@@ -92,31 +133,72 @@
         v-slot:[`column_${index}`]="{ row }"
       >
         <div :key="`column_${index}`" class="column_content">
-          <div v-if="row[index].isOnlyShow">
+          <!-- 文本 -->
+          <div v-if="row[index].paramType == 7 || row[index].isOnlyShow">
             {{ row[index].value }}
           </div>
-          <el-input
-            v-else
-            v-model.number="row[index].value"
-            :placeholder="
-              row[index].formula
-                ? row[index].formula.replace(/[\[\]]/g, '')
-                : `请输入${row[index].title}`
-            "
-            :disabled="Boolean(row[index].formula)"
-            @input="handleDataChange(row[index], row)"
-          >
-            <template v-if="!row[index].isOnlyShow" slot="append">
-              <div style="width: 80px; height: 100%">
+          <!-- 数值 -->
+          <template v-else-if="row[index].paramType == 1">
+            <div style="display: flex">
+              <el-input-number
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                :disabled="Boolean(row[index].formula)"
+                :controls="false"
+                @input="handleDataChange(row)"
+              ></el-input-number>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
+                <DictSelection
+                  v-model="row[index].unit"
+                  dictName="工艺参数单位"
+                  placeholder="单位"
+                >
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 公式 -->
+          <template v-else-if="row[index].paramType == 9">
+            <div style="display: flex">
+              <el-input
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                disabled
+                @input="handleDataChange(row)"
+              ></el-input>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
                 <DictSelection
                   v-model="row[index].unit"
                   dictName="工艺参数单位"
                   placeholder="单位"
                 >
-                </DictSelection>
-              </div>
-            </template>
-          </el-input>
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 时间 -->
+          <el-date-picker
+            v-else-if="row[index].paramType == 5"
+            v-model="row[index].value"
+            type="datetime"
+            placeholder="选择日期时间"
+            style="width: 100%"
+          >
+          </el-date-picker>
+          <!-- 其他 -->
+          <el-input
+            v-else
+            v-model="row[index].value"
+            placeholder="请输入内容"
+          ></el-input>
         </div>
       </template>
     </ele-pro-table>
@@ -154,31 +236,72 @@
         v-slot:[`column_${index}`]="{ row }"
       >
         <div :key="`column_${index}`" class="column_content">
-          <div v-if="row[index].isOnlyShow">
+          <!-- 文本 -->
+          <div v-if="row[index].paramType == 7 || row[index].isOnlyShow">
             {{ row[index].value }}
           </div>
-          <el-input
-            v-else
-            v-model.number="row[index].value"
-            :placeholder="
-              row[index].formula
-                ? row[index].formula.replace(/[\[\]]/g, '')
-                : `请输入${row[index].title}`
-            "
-            :disabled="Boolean(row[index].formula)"
-            @input="handleDataChange(row[index], row)"
-          >
-            <template v-if="!row[index].isOnlyShow" slot="append">
-              <div style="width: 80px; height: 100%">
+          <!-- 数值 -->
+          <template v-else-if="row[index].paramType == 1">
+            <div style="display: flex">
+              <el-input
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                :disabled="Boolean(row[index].formula)"
+                :controls="false"
+                @input="handleDataChange(row)"
+              ></el-input>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
+                <DictSelection
+                  v-model="row[index].unit"
+                  dictName="工艺参数单位"
+                  placeholder="单位"
+                >
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 公式 -->
+          <template v-else-if="row[index].paramType == 9">
+            <div style="display: flex">
+              <el-input-number
+                v-model="row[index].value"
+                :placeholder="
+                  row[index].formula
+                    ? row[index].formula.replace(/[\[\]]/g, '')
+                    : `请输入${row[index].title}`
+                "
+                disabled
+                @input="handleDataChange(row)"
+              ></el-input-number>
+              <div style="width: 80px; height: 100%; flex-shrink: 0">
                 <DictSelection
                   v-model="row[index].unit"
                   dictName="工艺参数单位"
                   placeholder="单位"
                 >
-                </DictSelection>
-              </div>
-            </template>
-          </el-input>
+                </DictSelection
+              ></div>
+            </div>
+          </template>
+          <!-- 时间 -->
+          <el-date-picker
+            v-else-if="row[index].paramType == 5"
+            v-model="row[index].value"
+            type="datetime"
+            placeholder="选择日期时间"
+            style="width: 100%"
+          >
+          </el-date-picker>
+          <!-- 其他 -->
+          <el-input
+            v-else
+            v-model="row[index].value"
+            placeholder="请输入内容"
+          ></el-input>
         </div>
       </template>
     </ele-pro-table>
@@ -225,6 +348,16 @@
       ruleId: {
         type: [String, Number],
         default: ''
+      },
+      // 单位
+      unit: {
+        type: String,
+        default: ''
+      },
+      // 要求生产数量
+      formingNum: {
+        type: [Number],
+        default: 0
       }
     },
     watch: {
@@ -391,15 +524,18 @@
           }
         ],
         activeProductTaskName: '全部',
-        keyword: ''
+        keyword: '',
+        _emitChangeTimer: null
       };
     },
 
     methods: {
-      // 通知父组件数据变更
+      // 通知父组件数据变更(防抖 500ms)
       emitChange() {
-        console.log('this.localDetails', this.localDetails);
-        this.$emit('update:details', this.localDetails);
+        if (this._emitChangeTimer) clearTimeout(this._emitChangeTimer);
+        this._emitChangeTimer = setTimeout(() => {
+          this.$emit('update:details', this.localDetails);
+        }, 500);
       },
       // 构建统计数据
       async buildDetials(detials) {
@@ -431,23 +567,24 @@
             this.localDetails[0].statisticsValue.length == 0) ||
           this.localDetails[0].ruleId != this.ruleId
         ) {
+          const list = this.rulesDetailList
+            .filter((i) => i.statisticsType == 1)
+            .map((i) => {
+              return {
+                title: i.paramValue,
+                value: i.defaultValue,
+                formula: i.formula,
+                unit: i.unitName || this.unit,
+                paramType: i.paramType
+              };
+            });
+
           // 已构建过统计数据
           this.localDetails[0] = {
             ...this.localDetails[0],
             ruleId: this.ruleId,
             statisticsType: 1,
-            statisticsValue: [
-              this.rulesDetailList
-                .filter((i) => i.statisticsType == 1)
-                .map((i) => {
-                  return {
-                    title: i.paramValue,
-                    value: i.defaultValue,
-                    formula: i.formula,
-                    unit: i.unitName
-                  };
-                })
-            ]
+            statisticsValue: [list]
           };
         }
         // 构建物料和工序数据
@@ -455,6 +592,17 @@
       },
       // 构建物料和工序数据
       async rebuildMaterialAndProcessData() {
+        if (this.unit) {
+          // 存在单位则 更新statisticsType为1的单位
+          this.localDetails[0].statisticsValue.forEach((rows) => {
+            rows.forEach((item) => {
+              if (!item.unit) {
+                item.unit = this.unit;
+              }
+            });
+          });
+        }
+
         let routingTaskList = [];
         let pickAndFeed = [];
 
@@ -486,7 +634,8 @@
                   title: i.paramValue,
                   value: i.defaultValue,
                   formula: i.formula,
-                  unit: i.unitName
+                  unit: i.unitName || this.unit,
+                  paramType: i.paramType
                 };
               });
 
@@ -494,14 +643,18 @@
               title: '领用量',
               value: pick.pickQuantity,
               formula: '',
-              unit: pick.pickUnit
+              unit: pick.pickUnit,
+              // 1数值类型
+              paramType: 1
             });
 
             data.unshift({
               title: '使用量',
               value: pick.feedQuantity,
               formula: '',
-              unit: pick.feedUnit
+              unit: pick.feedUnit,
+              // 1数值类型
+              paramType: 1
             });
 
             data.unshift({
@@ -510,7 +663,9 @@
               formula: '',
               unit: '',
               // 仅展示不计算和输入
-              isOnlyShow: true
+              isOnlyShow: true,
+              // 7文本类型
+              paramType: 7
             });
 
             data.unshift({
@@ -521,7 +676,9 @@
               // 仅展示不计算和输入
               isOnlyShow: true,
               // produceTaskName 工序名称
-              produceTaskName: pick.produceTaskName
+              produceTaskName: pick.produceTaskName,
+              // 7文本类型
+              paramType: 7
             });
 
             return data;
@@ -540,7 +697,8 @@
                   title: i.paramValue,
                   value: i.defaultValue,
                   formula: i.formula,
-                  unit: i.unitName
+                  unit: i.unitName || this.unit,
+                  paramType: i.paramType
                 };
               });
 
@@ -550,7 +708,9 @@
               formula: '',
               unit: '',
               // 仅展示不计算和输入
-              isOnlyShow: true
+              isOnlyShow: true,
+              // 7文本类型
+              paramType: 7
             });
 
             return data;
@@ -563,15 +723,13 @@
         this.emitChange();
       },
       // 当数据变化时计算公式
-      handleDataChange(item, row) {
+      handleDataChange(row) {
         // todo 计算公式
-        console.log('item', item);
-        console.log('row', row);
         // 寻找当前行的所有可计算项,进行计算更新
         const formulaItmes = row.filter((i) => i.formula);
 
         formulaItmes.forEach((formulaItem) => {
-          // 简单示例 公式为 [(][合格品量][+][取样量][)][/][接收量] 其中合格品量、取样量、接收量为标题在row中寻找对应value进行计算
+          // 简单示例 公式为 [(][合格品量][+][取样量][)][/][接收量]
           const tokens = formulaItem.formula
             ? formulaItem.formula.match(/\[([^\]]+)\]/g) || []
             : [];
@@ -584,6 +742,17 @@
               expr += content;
             } else {
               const target = row.find((r) => r.title === content);
+              // 特殊处理:当标题为“要求生产数量”且当前行未找到对应项时,用 this.formingNum 参与计算
+              if (!target && content === '要求生产数量') {
+                const formingVal = Number(this.formingNum);
+                if (!Number.isFinite(formingVal)) {
+                  invalid = true;
+                  expr = '';
+                  break;
+                }
+                expr += formingVal;
+                continue;
+              }
               // 若对应的项不存在 或 value为空 则取消计算
               if (
                 !target ||
@@ -592,7 +761,7 @@
                 target.value === undefined
               ) {
                 invalid = true;
-                expr = ''; // 置空表达式,后续将不计算
+                expr = '';
                 break;
               }
               const num = Number(target.value);
@@ -605,23 +774,16 @@
             }
           }
           // 若无效则直接跳过后续计算 (expr 已被置空)
-          if (/^[0-9+\-*/().\s]+$/.test(expr)) {
+          if (expr && /^[0-9+\-*/().\s]+$/.test(expr)) {
             try {
-              console.log('expr', expr);
               const result = Function(`"use strict";return (${expr})`)();
               let value =
                 Number.isFinite(result) && !Number.isNaN(result) ? result : '';
 
-              if (value) {
-                // 如果超出4位小数 则保留4位小数
-                if (typeof value === 'number') {
-                  const dec = value.toString().split('.')[1];
-                  if (dec && dec.length > 4) {
-                    const parts = value.toString().split('.');
-                    if (parts[1] && parts[1].length > 4) {
-                      value = Number(parts[0] + '.' + parts[1].slice(0, 4));
-                    }
-                  }
+              if (value !== '' && typeof value === 'number') {
+                const dec = value.toString().split('.')[1];
+                if (dec && dec.length > 4) {
+                  value = Number(value.toFixed(4));
                 }
               }
 
@@ -706,32 +868,132 @@
       },
       getSummaries() {
         const sums = [];
-        if (this.localDetails[0].statisticsValue.length == 0) {
+        // 优化:缓存公式解析、统一数值获取,减少重复正则与遍历
+        if (
+          !this.localDetails[0] ||
+          !this.localDetails[0].statisticsValue ||
+          this.localDetails[0].statisticsValue.length === 0
+        ) {
           return sums;
         }
+
+        const rows = this.localDetails[0].statisticsValue;
+        const firstRow = rows[0] || [];
         sums.push('合计');
-        this.localDetails[0].statisticsValue.forEach((itemList, index) => {
-          itemList.forEach((item, colIndex) => {
-            if (item.isOnlyShow) {
-              sums[colIndex + 1] = '';
+
+        // 缓存结构:{ formulaString: [{type:'op'|'num'|'ref', value:'+'|number|'列标题'}] }
+        if (!this._formulaCache) this._formulaCache = Object.create(null);
+
+        const parseFormula = (formula) => {
+          if (!formula) return [];
+          if (this._formulaCache[formula]) return this._formulaCache[formula];
+
+          // 提取 [xxx] 片段
+          const rawTokens = formula.match(/\[([^\]]+)\]/g) || [];
+          const tokens = [];
+          rawTokens.forEach((token) => {
+            const content = token.slice(1, -1).trim();
+            // 运算符/括号
+            if (['+', '-', '*', '/', '(', ')', '%'].includes(content)) {
+              tokens.push({ type: 'op', value: content });
             } else {
-              if (sums[colIndex + 1]) {
-                if (isNaN(Number(item.value))) {
-                  sums[colIndex + 1] += 0;
-                } else {
-                  sums[colIndex + 1] += Number(item.value) || 0;
-                }
+              // 引用列标题或特殊内置
+              tokens.push({ type: 'ref', value: content });
+            }
+          });
+          this._formulaCache[formula] = tokens;
+          return tokens;
+        };
+
+        // 辅助:安全数值
+        const toNum = (v) => {
+          const n = Number(v);
+          return Number.isFinite(n) ? n : 0;
+        };
+
+        // 先累加所有“非公式数值列”
+        rows.forEach((row) => {
+          row.forEach((cell, colIndex) => {
+            const targetIndex = colIndex + 1;
+            if (sums[targetIndex] === undefined) sums[targetIndex] = '';
+
+            if (cell.isOnlyShow || cell.paramType !== 1) {
+              return;
+            }
+            if (cell.formula) {
+              // 公式列占位为 0,后续再算
+              if (sums[targetIndex] === '') sums[targetIndex] = 0;
+              return;
+            }
+            const num = Number(cell.value);
+            if (!Number.isFinite(num)) return;
+            if (typeof sums[targetIndex] !== 'number') sums[targetIndex] = 0;
+            sums[targetIndex] += num;
+          });
+        });
+
+        // 计算公式列(使用上面得到的合计值作为引用值)
+        firstRow.forEach((meta, colIndex) => {
+          if (!meta.formula) return;
+          const targetIndex = colIndex + 1;
+
+          const tokens = parseFormula(meta.formula);
+          if (!tokens.length) {
+            sums[targetIndex] = '';
+            return;
+          }
+
+          let expr = '';
+          let invalid = false;
+
+          for (const tk of tokens) {
+            if (invalid) break;
+            if (tk.type === 'op') {
+              expr += tk.value;
+              continue;
+            }
+            // 引用列/特殊引用
+            if (tk.value === '要求生产数量') {
+              const formingVal = Number(this.formingNum);
+              if (!Number.isFinite(formingVal)) {
+                invalid = true;
               } else {
-                if (isNaN(Number(item.value))) {
-                  sums[colIndex + 1] = 0;
-                } else {
-                  sums[colIndex + 1] = Number(item.value) || 0;
-                }
+                expr += formingVal;
               }
+              continue;
             }
-          });
+            const refColIdx = firstRow.findIndex((i) => i.title === tk.value);
+            if (refColIdx === -1) {
+              invalid = true;
+              break;
+            }
+            const refVal = sums[refColIdx + 1];
+            if (!Number.isFinite(Number(refVal))) {
+              invalid = true;
+              break;
+            }
+            expr += toNum(refVal);
+          }
+
+          if (invalid || !expr || !/^[0-9+\-*/().\s%]+$/.test(expr)) {
+            sums[targetIndex] = '';
+            return;
+          }
+
+          try {
+            let result = Function('"use strict";return (' + expr + ')')();
+            if (!Number.isFinite(result) || Number.isNaN(result)) {
+              sums[targetIndex] = '';
+            } else {
+              const dec = result.toString().split('.')[1];
+              if (dec && dec.length > 4) result = Number(result.toFixed(4));
+              sums[targetIndex] = result;
+            }
+          } catch (e) {
+            sums[targetIndex] = '';
+          }
         });
-        console.log('sums', sums);
+
         return sums;
       },
       // 添加行

+ 5 - 10
src/views/checklistManagement/components/selectWorkOrder.vue

@@ -437,40 +437,35 @@
             label: '计划开始时间',
             align: 'center',
             showOverflowTooltip: true,
-            minWidth: 150,
-            sortable: 'custom'
+            minWidth: 150
           },
           {
             prop: 'planCompleteTime',
             label: '计划结束时间',
             align: 'center',
             showOverflowTooltip: true,
-            minWidth: 150,
-            sortable: 'custom'
+            minWidth: 150
           },
           {
             prop: 'startTime',
             label: '实际开始时间',
             align: 'center',
             showOverflowTooltip: true,
-            minWidth: 150,
-            sortable: 'custom'
+            minWidth: 150
           },
           {
             prop: 'completeTime',
             label: '实际完成时间',
             align: 'center',
             showOverflowTooltip: true,
-            minWidth: 150,
-            sortable: 'custom'
+            minWidth: 150
           },
           {
             prop: 'createTime',
             label: '创建时间',
             align: 'center',
             showOverflowTooltip: true,
-            minWidth: 150,
-            sortable: 'custom'
+            minWidth: 150
           },
           // {
           //   prop: 'status',

+ 1 - 1
src/views/produce/components/prenatalExamination/releaseRulesDialog.vue

@@ -1016,7 +1016,7 @@
             }
           }
 
-          if (this.$refs.statisticsRef && type != 'cache') {
+          if (this.$refs.statisticsRef && type != 'cache' && type != 'submit-reset') {
             // 验证统计项目
             const valid = this.$refs.statisticsRef.validateStatisticsFilled();
             if (!valid) {

+ 2 - 2
vue.config.js

@@ -37,8 +37,8 @@ module.exports = {
         // target: 'http://192.168.1.251:18086',
         // target: 'http://192.168.1.251:18086',
         // target: 'http://192.168.1.125:18086',
-        target: 'http://192.168.1.116:18086', // 赵沙金
-        // target: 'http://192.168.1.251:18086', // 开发环境
+        // target: 'http://192.168.1.116:18086', // 赵沙金
+        target: 'http://192.168.1.251:18086', // 开发环境
         // target: 'http://192.168.1.103:18086',192.168.1.116
         // target: 'http://192.168.1.144:18086',
         // target: 'http://192.168.1.30:18086',