Эх сурвалжийг харах

feat(productionPlan): 支持订单排程甘特图按选中项过滤并统计派单数量

yusheng 2 долоо хоног өмнө
parent
commit
61f219b25b

+ 352 - 2
src/views/productionPlan/components/newFactoryProductionScheduling.vue

@@ -10,9 +10,9 @@
   >
     <projectGantt
       :style="{ height: ganttHeight }"
-      :ganttTasks="tableData"
+      :ganttTasks="displayGanttTableData"
       :planList="planDataList"
-      :calendarSourceData="calendarSourceData"
+      :calendarSourceData="displayCalendarSourceData"
       :defaultTab="defaultGanttTab"
       :resource-tabs-config="resourceTabsConfig"
       :resource-label-mode="schedulingMode"
@@ -412,6 +412,23 @@
       },
       taskConfigTableMaxHeight() {
         return Math.max(260, this.schedulingContentHeightValue - 132);
+      },
+      hasOrderSchedulingGanttSelection() {
+        return Array.isArray(this.selection) && this.selection.length > 0;
+      },
+      displayCalendarSourceData() {
+        if (!this.hasOrderSchedulingGanttSelection) {
+          return this.calendarSourceData;
+        }
+        return this.filterOrderSchedulingGanttDataBySelection(
+          this.calendarSourceData
+        );
+      },
+      displayGanttTableData() {
+        if (!this.hasOrderSchedulingGanttSelection) {
+          return this.tableData;
+        }
+        return this.initGanttFlatRows(this.displayCalendarSourceData);
       }
     },
     created() {
@@ -449,6 +466,339 @@
       optionMatchesId(optionId, targetId) {
         return this.normalizeId(optionId) === this.normalizeId(targetId);
       },
+      normalizeOrderSchedulingGanttMatchValue(value) {
+        if (value === null || value === undefined || value === '') {
+          return '';
+        }
+        return String(value).trim();
+      },
+      createOrderSchedulingGanttMatchGroups() {
+        return {
+          orderIds: [],
+          orderCodes: [],
+          planIds: [],
+          planCodes: []
+        };
+      },
+      addOrderSchedulingGanttMatchValue(groups, groupName, value) {
+        const text = this.normalizeOrderSchedulingGanttMatchValue(value);
+        if (!text || groups[groupName].includes(text)) {
+          return;
+        }
+        groups[groupName].push(text);
+      },
+      collectSelectedOrderSchedulingGanttMatchGroups(rows = []) {
+        const groups = this.createOrderSchedulingGanttMatchGroups();
+        (Array.isArray(rows) ? rows : []).forEach((row) => {
+          // 班组排程:行是工单数据,同时收集工单键与关联计划键
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderIds',
+            row?.workOrderId || row?.id
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderIds',
+            row?.apsWorkOrderId
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderIds',
+            row?.mesWorkOrderId
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderIds',
+            row?.sourceWorkOrderId || row?.orderId
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderCodes',
+            row?.productionOrderNumber || row?.code
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderCodes',
+            row?.mesWorkOrderCode
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderCodes',
+            row?.apsWorkOrderCode || row?.workOrderCode
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'orderCodes',
+            row?.productionOrderCode || row?.orderCode
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'planIds',
+            row?.productionPlanId || row?.planId
+          );
+          this.addOrderSchedulingGanttMatchValue(
+            groups,
+            'planCodes',
+            row?.productionPlanCode || row?.planCode
+          );
+        });
+        return groups;
+      },
+      collectOrderSchedulingGanttEntryMatchGroups(entry = {}) {
+        const groups = this.createOrderSchedulingGanttMatchGroups();
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderIds',
+          entry?.apsWorkOrderId || entry?.workOrderId
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderIds',
+          entry?.mesWorkOrderId
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderIds',
+          entry?.sourceWorkOrderId || entry?.orderId
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderCodes',
+          entry?.productionOrderNumber || entry?.apsWorkOrderCode
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderCodes',
+          entry?.mesWorkOrderCode
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderCodes',
+          entry?.workOrderCode || entry?.productionOrderCode
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'orderCodes',
+          entry?.orderCode
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'planIds',
+          entry?.productionPlanId || entry?.planId
+        );
+        this.addOrderSchedulingGanttMatchValue(
+          groups,
+          'planCodes',
+          entry?.productionPlanCode || entry?.planCode
+        );
+        return groups;
+      },
+      hasOrderSchedulingGanttMatch(left = [], right = []) {
+        if (!left.length || !right.length) {
+          return false;
+        }
+        return left.some((item) => right.includes(item));
+      },
+      hasOrderSchedulingGanttOrderKey(entry = {}) {
+        const groups = this.collectOrderSchedulingGanttEntryMatchGroups(entry);
+        return groups.orderIds.length > 0 || groups.orderCodes.length > 0;
+      },
+      isOrderSchedulingGanttEntryMatched(entry, selectedGroups) {
+        if (!entry || !selectedGroups) {
+          return false;
+        }
+        const entryGroups =
+          this.collectOrderSchedulingGanttEntryMatchGroups(entry);
+        const hasEntryOrderKey =
+          entryGroups.orderIds.length > 0 || entryGroups.orderCodes.length > 0;
+        const hasSelectedOrderKey =
+          selectedGroups.orderIds.length > 0 ||
+          selectedGroups.orderCodes.length > 0;
+        const orderMatched =
+          this.hasOrderSchedulingGanttMatch(
+            entryGroups.orderIds,
+            selectedGroups.orderIds
+          ) ||
+          this.hasOrderSchedulingGanttMatch(
+            entryGroups.orderCodes,
+            selectedGroups.orderCodes
+          );
+        if (hasEntryOrderKey && hasSelectedOrderKey) {
+          return orderMatched;
+        }
+        return (
+          orderMatched ||
+          this.hasOrderSchedulingGanttMatch(
+            entryGroups.planIds,
+            selectedGroups.planIds
+          ) ||
+          this.hasOrderSchedulingGanttMatch(
+            entryGroups.planCodes,
+            selectedGroups.planCodes
+          )
+        );
+      },
+      getOrderSchedulingGanttPeriodResourceIndex(
+        resourceList = [],
+        period = {},
+        periodIndex = -1
+      ) {
+        const periodPlanId = this.normalizeOrderSchedulingGanttMatchValue(
+          period?.planId || period?.productionPlanId
+        );
+        if (periodPlanId) {
+          const matchedIndex = resourceList.findIndex((resource) =>
+            [
+              resource?.planId,
+              resource?.productionPlanId,
+              resource?.apsWorkOrderId,
+              resource?.workOrderId
+            ].some(
+              (value) =>
+                this.normalizeOrderSchedulingGanttMatchValue(value) ===
+                periodPlanId
+            )
+          );
+          if (matchedIndex > -1) {
+            return matchedIndex;
+          }
+        }
+        return resourceList[periodIndex] ? periodIndex : -1;
+      },
+      getOrderSchedulingGanttMatchedResourceIndex(
+        resourceList = [],
+        period = {},
+        periodIndex = -1
+      ) {
+        const indexedResource = resourceList[periodIndex];
+        if (
+          indexedResource &&
+          this.isSameOrderSchedulingGanttRecord(indexedResource, period)
+        ) {
+          return periodIndex;
+        }
+        const strictMatchedIndex = resourceList.findIndex((resource) =>
+          this.isSameOrderSchedulingGanttRecord(resource, period, true)
+        );
+        if (strictMatchedIndex > -1) {
+          return strictMatchedIndex;
+        }
+        return this.getOrderSchedulingGanttPeriodResourceIndex(
+          resourceList,
+          period,
+          periodIndex
+        );
+      },
+      isSameOrderSchedulingGanttRecord(left = {}, right = {}, strict = false) {
+        if (!left || !right) {
+          return false;
+        }
+        const leftGroups =
+          this.collectOrderSchedulingGanttEntryMatchGroups(left);
+        const rightGroups =
+          this.collectOrderSchedulingGanttEntryMatchGroups(right);
+        const orderMatched =
+          this.hasOrderSchedulingGanttMatch(
+            leftGroups.orderIds,
+            rightGroups.orderIds
+          ) ||
+          this.hasOrderSchedulingGanttMatch(
+            leftGroups.orderCodes,
+            rightGroups.orderCodes
+          );
+        if (orderMatched || strict) {
+          return orderMatched;
+        }
+        return (
+          this.hasOrderSchedulingGanttMatch(
+            leftGroups.planIds,
+            rightGroups.planIds
+          ) ||
+          this.hasOrderSchedulingGanttMatch(
+            leftGroups.planCodes,
+            rightGroups.planCodes
+          )
+        );
+      },
+      filterOrderSchedulingGanttDataBySelection(data = []) {
+        const selectedGroups =
+          this.collectSelectedOrderSchedulingGanttMatchGroups(this.selection);
+        const hasSelectedKeys = Object.values(selectedGroups).some(
+          (list) => list.length > 0
+        );
+        if (!hasSelectedKeys) {
+          return data;
+        }
+        return (Array.isArray(data) ? data : [])
+          .map((item) => {
+            const parentMatched = this.isOrderSchedulingGanttEntryMatched(
+              item,
+              selectedGroups
+            );
+            const resourceList = Array.isArray(item.resourceList)
+              ? item.resourceList
+              : [];
+            const resourcePeriods = Array.isArray(item.resourcePeriods)
+              ? item.resourcePeriods
+              : [];
+            if (parentMatched && this.hasOrderSchedulingGanttOrderKey(item)) {
+              return item;
+            }
+            if (!resourceList.length && !resourcePeriods.length) {
+              return parentMatched ? item : null;
+            }
+            const matchedResourceIndexes = new Set();
+            const filteredPeriods = resourcePeriods.filter(
+              (period, periodIndex) => {
+                const resourceIndex =
+                  this.getOrderSchedulingGanttMatchedResourceIndex(
+                    resourceList,
+                    period,
+                    periodIndex
+                  );
+                const linkedResource =
+                  resourceIndex > -1 ? resourceList[resourceIndex] : null;
+                const matched =
+                  this.isOrderSchedulingGanttEntryMatched(
+                    period,
+                    selectedGroups
+                  ) ||
+                  this.isOrderSchedulingGanttEntryMatched(
+                    linkedResource,
+                    selectedGroups
+                  ) ||
+                  this.isOrderSchedulingGanttEntryMatched(
+                    {
+                      ...(linkedResource || {}),
+                      ...period
+                    },
+                    selectedGroups
+                  );
+                if (matched && resourceIndex > -1) {
+                  matchedResourceIndexes.add(resourceIndex);
+                }
+                return matched;
+              }
+            );
+            const filteredResourceList = resourceList.filter(
+              (resource, resourceIndex) =>
+                matchedResourceIndexes.has(resourceIndex) ||
+                this.isOrderSchedulingGanttEntryMatched(
+                  resource,
+                  selectedGroups
+                )
+            );
+            if (!filteredPeriods.length && !filteredResourceList.length) {
+              return null;
+            }
+            return {
+              ...item,
+              resourceList: filteredResourceList,
+              resourcePeriods: filteredPeriods
+            };
+          })
+          .filter(Boolean);
+      },
       // Plan list helpers
       getPlanRowKey(row) {
         return String(row?.id ?? row?.planId ?? '');

+ 19 - 0
src/views/productionPlan/components/newFactoryProductionScheduling/TaskConfigPanel.vue

@@ -7,6 +7,19 @@
       <div v-else class="dispatch-style-panel">
         <div class="dispatch-report-type">
           <div class="dispatch-plan-info">
+            <span class="dispatch-plan-item">
+              <span class="dispatch-plan-label">已派单数量:</span>
+              <span class="dispatch-plan-value">
+                {{ quantityLimit || 0 }}{{ currentPlan.unit }}
+              </span>
+            </span>
+            <span class="dispatch-plan-item">
+              <span class="dispatch-plan-label">未派单数量:</span>
+              <span class="dispatch-plan-value">
+                {{ currentPlan.productNum - quantityLimit || 0
+                }}{{ currentPlan.unit }}
+              </span>
+            </span>
             <span class="dispatch-plan-item">
               <span class="dispatch-plan-label">计划数量:</span>
               <span class="dispatch-plan-value">
@@ -568,6 +581,7 @@
               />
             </template>
           </el-table-column>
+
           <el-table-column label="执行开始时间" min-width="164" align="center">
             <template slot-scope="{ row }">
               <el-date-picker
@@ -1003,6 +1017,11 @@
       },
       normalTableMaxHeight() {
         return this.fillTableHeight ? undefined : this.tableMaxHeight;
+      },
+      quantityLimit() {
+        return this.pagedDispatchObjectRows?.reduce((total, row) => {
+          return total + this.parseDispatchQuantity(row.quantity);
+        }, 0);
       }
     },
     watch: {