From c425a8afba0a76eb62d5650cc9c98c42d8339f06 Mon Sep 17 00:00:00 2001
From: zhuguifei <312353457@qq.com>
Date: 星期四, 12 三月 2026 13:01:23 +0800
Subject: [PATCH] perf: 1.优化储丝柜单柜卷包产量计算方式,支持未出料结束计算统计   2.新增储丝柜单柜卷包产量桑基图

---
 ruoyi-plus-soybean/src/views/analy/store-silk/index.vue |  137 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 119 insertions(+), 18 deletions(-)

diff --git a/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue b/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue
index 89f96b8..141fbeb 100644
--- a/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue
+++ b/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue
@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { ref } from 'vue';
+import { computed, ref } from 'vue';
 import { NDivider } from 'naive-ui';
 import { fetchBatchDeleteStoreSilk, fetchGetStoreSilkList } from '@/service/api/analy/store-silk';
 import { useAppStore } from '@/store/modules/app';
@@ -11,6 +11,7 @@
 import StoreSilkOperateDrawer from './modules/store-silk-operate-drawer.vue';
 import StoreSilkSearch from './modules/store-silk-search.vue';
 import StoreSilkDetail from './modules/store-silk-detail.vue';
+import StoreSilkSankey from './modules/store-silk-sankey.vue';
 
 defineOptions({
   name: 'StoreSilkList'
@@ -20,8 +21,32 @@
 const { download } = useDownload();
 const { hasAuth } = useAuth();
 
+
+
 const selectedRollerDetailList = ref<any[]>([]);
 const selectedPackerDetailList = ref<any[]>([]);
+
+// 妗戝熀鍥緎tart
+const showSankey = ref(false);
+const rollerRecordList = ref<any[]>([]);
+const packerRecordList = ref<any[]>([]);
+// 妗戝熀鍥緀nd
+
+const sankeyRollerBoxList = computed(() => {
+  return (rollerRecordList.value || []).map(item => {
+    const v = calcRollerBox((item as any).output);
+    const output = v === null ? null : Number(v.toFixed(2));
+    return { ...(item as any), output };
+  });
+});
+
+const sankeyPackerBoxList = computed(() => {
+  return (packerRecordList.value || []).map(item => {
+    const v = calcPackerBox((item as any).output);
+    const output = v === null ? null : Number(v.toFixed(2));
+    return { ...(item as any), output };
+  });
+});
 
 const searchParams = ref<Api.Analy.StoreSilkSearchParams>({
   pageNum: 1,
@@ -45,9 +70,33 @@
 }
 
 const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
-  useNaivePaginatedTable({
+  useNaivePaginatedTable<any, any>({
     api: () => fetchGetStoreSilkList(searchParams.value),
-    transform: response => defaultTransform(response),
+    transform: response => {
+      const respData = (response as any).data;
+      const error = (response as any).error;
+
+      if (!error) {
+        const rows = Array.isArray(respData?.rows) ? respData.rows : [];
+        const apiRollerRecordList = respData?.rollerRecordList;
+        const apiPackerRecordList = respData?.packerRecordList;
+
+        rollerRecordList.value =
+          Array.isArray(apiRollerRecordList) && apiRollerRecordList.length > 0
+            ? apiRollerRecordList
+            : rows.flatMap((r: any) => (Array.isArray(r?.rollerDetailList) ? r.rollerDetailList : []));
+
+        packerRecordList.value =
+          Array.isArray(apiPackerRecordList) && apiPackerRecordList.length > 0
+            ? apiPackerRecordList
+            : rows.flatMap((r: any) => (Array.isArray(r?.packerDetailList) ? r.packerDetailList : []));
+      } else {
+        rollerRecordList.value = [];
+        packerRecordList.value = [];
+      }
+
+      return defaultTransform(response as any);
+    },
     onPaginationParamsChange: params => {
       searchParams.value.pageNum = params.page;
       searchParams.value.pageSize = params.pageSize;
@@ -64,19 +113,19 @@
         key: 'materialname',
         title: '鐗屽彿',
         align: 'center',
-        minWidth: 120
+        minWidth: 96
       },
       {
         key: 'batchcode',
         title: '鎵规鍙�',
         align: 'center',
-        minWidth: 130
+        minWidth: 110
       },
       {
         key: 'rollerOutput',
         title: '鍗锋帴浜ч噺(绠�)',
         align: 'center',
-        minWidth: 120,
+        minWidth: 112,
         render: row => {
           const v = calcRollerBox((row as any).rollerOutput);
           if (v === null) return '-';
@@ -84,10 +133,27 @@
         }
       },
       {
+        key: 'rollerUnitCost',
+        title: '鍗锋帴鍗曡��',
+        align: 'center',
+        minWidth: 96,
+        render: row => {
+          const box = calcRollerBox((row as any).rollerOutput);
+          if (box === null || box <= 0) return '-';
+          const jobinput = Number((row as any).jobinput);
+          const weight = Number((row as any).weight);
+          const diff = jobinput - weight;
+          if (!Number.isFinite(diff)) return '-';
+          const val = diff / box;
+          if (!Number.isFinite(val)) return '-';
+          return val.toFixed(2);
+        }
+      },
+      {
         key: 'packerOutput',
         title: '鍖呰浜ч噺(绠�)',
         align: 'center',
-        minWidth: 120,
+        minWidth: 112,
         render: row => {
           const v = calcPackerBox((row as any).packerOutput);
           if (v === null) return '-';
@@ -95,46 +161,63 @@
         }
       },
       {
+        key: 'packerUnitCost',
+        title: '鍖呰鍗曡��',
+        align: 'center',
+        minWidth: 96,
+        render: row => {
+          const box = calcPackerBox((row as any).packerOutput);
+          if (box === null || box <= 0) return '-';
+          const jobinput = Number((row as any).jobinput);
+          const weight = Number((row as any).weight);
+          const diff = jobinput - weight;
+          if (!Number.isFinite(diff)) return '-';
+          const val = diff / box;
+          if (!Number.isFinite(val)) return '-';
+          return val.toFixed(2);
+        }
+      },
+      {
         key: 'actualstarttime',
         title: '鎶曟枡鏃ユ湡',
         align: 'center',
-        width: 180
+        width: 160
       },
       {
         key: 'jobinput',
         title: '鎶曟枡閲嶉噺',
         align: 'center',
-        minWidth: 120
+        minWidth: 96
       },
       {
         key: 'weight',
         title: '鍌ㄤ笣鏌滈噸閲�',
         align: 'center',
-        minWidth: 120
+        minWidth: 96
       },
       {
         key: 'distimebegin',
         title: '鍌ㄤ笣鏌滃嚭鏂欏紑濮嬫椂闂�',
         align: 'center',
-        width: 180
+        width: 160
       },
       {
         key: 'distimeend',
         title: '鍌ㄤ笣鏌滃嚭鏂欑粨鏉熸椂闂�',
         align: 'center',
-        width: 180
+        width: 160
       },
       {
         key: 'siloid',
         title: '鏌滃瓙鍙�(鏈綅)',
         align: 'center',
-        width: 160
+        width: 120
       }
     ]
   });
 
 const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
-  useTableOperate(data, 'id', getData);
+  useTableOperate<any>(data, 'id', getData);
 
 async function handleBatchDelete() {
   // request
@@ -194,12 +277,22 @@
           :loading="loading"
           :show-add="false"
           :show-delete="false"
-          :show-export="hasAuth('analy:storeSilk:export')"
+          :show-export="!showSankey && hasAuth('analy:storeSilk:export')"
           @add="handleAdd"
           @delete="handleBatchDelete"
           @export="handleExport"
           @refresh="getData"
         >
+          <template #prefix>
+            <NButton
+              size="small"
+              ghost
+              :type="showSankey ? 'primary' : 'default'"
+              @click="showSankey = !showSankey"
+            >
+              {{ showSankey ? '鍒楄〃' : '妗戝熀鍥�' }}
+            </NButton>
+          </template>
           <template #suffix>
             <NPopover placement="bottom-end" trigger="click">
               <template #trigger>
@@ -221,8 +314,16 @@
           </template>
         </TableHeaderOperation>
       </template>
+      <StoreSilkSankey
+        v-if="showSankey"
+        :roller-record-list="sankeyRollerBoxList"
+        :packer-record-list="sankeyPackerBoxList"
+        :rows="data"
+        class="h-full"
+      />
       <NDataTable
-        :columns="columns"
+        v-else
+        :columns="columns as any"
         :data="data"
         :size="tableSize"
         :flex-height="!appStore.isMobile"
@@ -242,6 +343,7 @@
       />
     </NCard>
     <StoreSilkDetail
+      v-if="!showSankey"
       :roller-detail-list="selectedRollerDetailList"
       :packer-detail-list="selectedPackerDetailList"
       class="h-[192px] overflow-hidden"
@@ -252,7 +354,6 @@
 <style scoped>
 :deep(.n-data-table-th),
 :deep(.n-data-table-td) {
-  padding-top: 4px;
-  padding-bottom: 4px;
+  padding: 4px 6px;
 }
 </style>

--
Gitblit v1.9.3