From 48c4d75c995e6e986103f1e6510ca0242421cccf Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期三, 08 四月 2026 15:53:31 +0800
Subject: [PATCH] Merge branch 'dev_天津_阳光印刷' of http://114.132.189.42:9002/r/product-inventory-management into dev_天津_阳光印刷

---
 src/views/productionManagement/productionCosting/index.vue |  392 +++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 248 insertions(+), 144 deletions(-)

diff --git a/src/views/productionManagement/productionCosting/index.vue b/src/views/productionManagement/productionCosting/index.vue
index 8e1d40b..737354e 100644
--- a/src/views/productionManagement/productionCosting/index.vue
+++ b/src/views/productionManagement/productionCosting/index.vue
@@ -29,145 +29,196 @@
           </el-form>
 				</div>
 				<PIMTable
-					rowKey="id"
-					:column="leftTableColumn"
-					:tableData="leftTableData"
-					:tableLoading="tableLoading"
-          :page="page"
-          @row-click="handleLeftRowClick"
-          @pagination="pagination"
-        ></PIMTable>
+            rowKey="id"
+            :column="leftTableColumn"
+            :tableData="leftTableData"
+            :tableLoading="tableLoading"
+            :page="page"
+            @row-click="handleLeftRowClick"
+            @pagination="pagination"
+        >
+          <template #workDuration="{ row }">
+            <el-button v-if="Number(row.totalWorkMinutes) > 0"
+                       type="primary"
+                       text
+                       @click.stop="openWorkDurationDialog(row)">
+              {{ row.totalWorkMinutes }}
+            </el-button>
+            <span v-else>-</span>
+          </template>
+        </PIMTable>
 				</div>
 			</el-col>
 
-			<!-- 鍙充晶鏄庣粏 -->
+      <!-- 鍙充晶鏄庣粏 -->
 			<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16" class="right-col">
 				<div class="right-panel">
-				
+
 					<el-form inline>
 						<el-form-item>
 							<el-button type="primary" @click="handleOut">瀵煎嚭</el-button>
 						</el-form-item>
 					</el-form>
 					<PIMTable
-						rowKey="id"
-						:column="tableColumn"
-						:tableData="tableData"
-						:page="page1"
-						:tableLoading="tableLoading1"
-						style="margin-right: 20px;"
-						@pagination="pagination1"
-					></PIMTable>
+              rowKey="id"
+              :column="tableColumn"
+              :tableData="tableData"
+              :page="page1"
+              :tableLoading="tableLoading1"
+              style="margin-right: 20px;"
+              @pagination="pagination1"
+          ></PIMTable>
 				</div>
 			</el-col>
 		</el-row>
+    <el-dialog v-model="workDurationDialogVisible"
+               :title="`宸ユ椂鏄庣粏${currentSchedulingUserName ? ` - ${currentSchedulingUserName}` : ''}`"
+               width="600px">
+      <el-table :data="workDurationDetailList"
+                border
+                style="width: 100%; margin-bottom: 16px;">
+        <el-table-column type="index"
+                         label="搴忓彿"
+                         width="80"/>
+        <el-table-column prop="deviceName"
+                         label="鏈哄彴"
+                         min-width="220"/>
+        <el-table-column prop="workMinutes"
+                         label="宸ヤ綔鏃堕棿(鍒嗛挓)"
+                         min-width="160"/>
+      </el-table>
+    </el-dialog>
 	</div>
 </template>
 
 <script setup>
 import {onMounted, ref} from "vue";
-import { ElMessageBox } from "element-plus";
+import {ElMessageBox} from "element-plus";
 import dayjs from "dayjs";
-import {salesLedgerProductionAccountingListProductionDetails, salesLedgerProductionAccountingList} from "@/api/productionManagement/productionCosting.js";
-const { proxy } = getCurrentInstance();
+import {
+  salesLedgerProductionAccountingListProductionDetails,
+  salesLedgerProductionAccountingList
+} from "@/api/productionManagement/productionCosting.js";
+
+const {proxy} = getCurrentInstance();
 
 const tableColumn = ref([
-	{
-		label: "鐢熶骇鏃ユ湡",
-		prop: "schedulingDate",
+  {
+    label: "鐢熶骇鏃ユ湡",
+    prop: "schedulingDate",
     minWidth: 100,
-	},
-	{
-		label: "鐢熶骇浜�",
-		prop: "schedulingUserName",
+  },
+  {
+    label: "鐢熶骇浜�",
+    prop: "schedulingUserName",
     minWidth: 100,
-	},
-	{
-		label: "鍚堝悓鍙�",
-		prop: "salesContractNo",
+  },
+  {
+    label: "鍚堝悓鍙�",
+    prop: "salesContractNo",
     minWidth: 100,
-	},
-	{
-		label: "瀹㈡埛鍚嶇О",
-		prop: "customerName",
+  },
+  {
+    label: "瀹㈡埛鍚嶇О",
+    prop: "customerName",
     minWidth: 100,
-	},
-	{
-		label: "浜у搧澶х被",
-		prop: "productName",
+  },
+  {
+    label: "浜у搧澶х被",
+    prop: "productName",
     minWidth: 100,
-	},
-	{
-		label: "瑙勬牸鍨嬪彿",
-		prop: "productModelName",
+  },
+  {
+    label: "瑙勬牸鍨嬪彿",
+    prop: "productModelName",
     minWidth: 100,
-	},
-	{
-		label: "鍗曚綅",
-		prop: "unit",
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
     minWidth: 100,
-	},
-	{
-		label: "宸ュ簭",
-		prop: "process",
+  },
+  {
+    label: "宸ュ簭",
+    prop: "process",
     minWidth: 100,
-	},
-	{
-		label: "鐢熶骇鏁伴噺",
-		prop: "quantity",
+  },
+  {
+    label: "鐢熶骇鏁伴噺",
+    prop: "quantity",
     minWidth: 100,
-	},
-	{
-		label: "宸ユ椂瀹氶",
-		prop: "workHours",
+  },
+  {
+    label: "宸ユ椂瀹氶",
+    prop: "workHours",
     minWidth: 100,
-	},
-	{
-		label: "宸ヨ祫",
-		prop: "wages",
+  },
+  {
+    label: "宸ヨ祫",
+    prop: "wages",
     minWidth: 100,
-	},
+  },
+  {
+    label: "鏈哄彴",
+    prop: "deviceName",
+    minWidth: 100,
+  },
+  {
+    label: "宸ユ椂(鍒嗛挓)",
+    prop: "workMinutes",
+    width: 110,
+  },
 ]);
 
 // 宸︿晶姹囨�诲彴璐﹀垪锛堢敓浜т汉銆佷骇閲忋�佸伐璧勩�佸悎鏍肩巼锛�
 const leftTableColumn = ref([
-	{
-		label: "鐢熶骇浜�",
-		prop: "schedulingUserName",
+  {
+    label: "鐢熶骇浜�",
+    prop: "schedulingUserName",
     minWidth: 100,
-	},
-	{
-		label: "浜ч噺",
-		prop: "outputNum",
+  },
+  {
+    label: "浜ч噺",
+    prop: "outputNum",
     minWidth: 100,
 
   },
-	{
-		label: "宸ヨ祫",
-		prop: "wages",
+  {
+    label: "宸ヨ祫",
+    prop: "wages",
     minWidth: 100,
 
-	},
-	{
-		label: "鍚堟牸鐜�",
-		prop: "outputRate",
+  },
+  {
+    label: "鍚堟牸鐜�",
+    prop: "outputRate",
     minWidth: 100,
     formatData: (val) => {
       if (val == null || val === '') return '-'
       return parseFloat(val).toFixed(2)
     },
-	},
+  },
+  {
+    label: "宸ユ椂(鍒嗛挓)",
+    prop: "totalWorkMinutes",
+    minWidth: 120,
+    dataType: "slot",
+    slot: "workDuration",
+  },
 ]);
 
 const tableData = ref([]);
 const tableLoading = ref(false);
 const tableLoading1 = ref(false);
 const leftTableData = ref([]);
+const workDurationDialogVisible = ref(false);
+const workDurationDetailList = ref([]);
+const currentSchedulingUserName = ref("");
 // 鏃� / 鏈� 鍒囨崲锛堥粯璁ゆ寜鏃ワ級
 const page = reactive({
-	current: 1,
-	size: 100,
-	total: 0,
+  current: 1,
+  size: 100,
+  total: 0,
 });
 
 const page1 = reactive({
@@ -177,32 +228,32 @@
 });
 
 const data = reactive({
-	searchForm: {
-		schedulingUserName: "",
-		salesContractNo: "",
+  searchForm: {
+    schedulingUserName: "",
+    salesContractNo: "",
     dateType: "day",
     dateRange: dayjs().format("YYYY-MM-DD"),
-		entryDate: dayjs().format("YYYY-MM-DD"),
-		entryDateStart: undefined,
-		entryDateEnd: undefined,
-	},
+    entryDate: dayjs().format("YYYY-MM-DD"),
+    entryDateStart: undefined,
+    entryDateEnd: undefined,
+  },
 });
-const { searchForm } = toRefs(data);
+const {searchForm} = toRefs(data);
 
 const pagination = (obj) => {
-	page.current = obj.page;
-	page.size = obj.limit;
-	getList();
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
 };
 
 const pagination1 = (obj) => {
   page1.current = obj.page;
   page1.size = obj.limit;
-	getList1();
+  getList1();
 };
 
 const handleDateRangeChange = (value) => {
-	if (value) {
+  if (value) {
     if (searchForm.value.dateType === "day") {
       searchForm.value.entryDate = value;
     } else {
@@ -210,35 +261,46 @@
       searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
     }
 
-	} else {
-		searchForm.value.entryDate = undefined;
-		searchForm.value.entryDateStart = undefined;
-		searchForm.value.entryDateEnd = undefined;
-	}
+  } else {
+    searchForm.value.entryDate = undefined;
+    searchForm.value.entryDateStart = undefined;
+    searchForm.value.entryDateEnd = undefined;
+  }
   reloadData()
 };
 
 const getList = () => {
-	tableLoading.value = true;
-	const params = { ...searchForm.value, ...page };
+  tableLoading.value = true;
+  const params = {...searchForm.value, ...page};
 
   salesLedgerProductionAccountingList(params).then((res) => {
-		const records = res.data.records || [];
-    leftTableData.value = records;
-		page.total = res.data.total || 0;
-	}).finally(() => {
+    const records = res.data.records || [];
+    leftTableData.value = records.map(item => {
+      const workDurationDetailListValue = buildWorkDurationDetailList(item.deviceWorkInfoPairList);
+      const totalWorkMinutes = workDurationDetailListValue.reduce(
+          (sum, detail) => sum + Number(detail.workMinutes || 0),
+          0
+      );
+      return {
+        ...item,
+        workDurationDetailList: workDurationDetailListValue,
+        totalWorkMinutes,
+      };
+    });
+    page.total = res.data.total || 0;
+  }).finally(() => {
     tableLoading.value = false;
   })
-
 
 
 };
 
 const getList1 = () => {
   tableLoading1.value = true;
-  const params = { ...page1, ...searchForm.value };
+  const params = {...page1, ...searchForm.value};
   salesLedgerProductionAccountingListProductionDetails(params).then((res) => {
-    tableData.value = res.data.records || [];;
+    tableData.value = res.data.records || [];
+    ;
     page1.total = res.data.total || 0;
   }).finally(() => {
     tableLoading1.value = false;
@@ -247,30 +309,30 @@
 
 // 鏋勫缓宸︿晶姹囨�诲彴璐︼紙鎸夌敓浜т汉姹囨�讳骇閲忋�佸伐璧勭瓑锛�
 const buildLeftTableData = (records) => {
-	const map = {};
-	records.forEach((item) => {
-		const key = item.schedulingUserName || "鏈煡";
-		if (!map[key]) {
-			map[key] = {
-				id: key,
-				schedulingUserName: key,
-				finishedNum: 0,
-				wages: 0,
-				qualifiedRate: item.qualifiedRate ?? null,
-			};
-		}
-		map[key].finishedNum += Number(item.finishedNum || 0);
-		map[key].wages += Number(item.wages || 0);
-		if (item.qualifiedRate != null) {
-			map[key].qualifiedRate = item.qualifiedRate;
-		}
-	});
-	leftTableData.value = Object.values(map);
+  const map = {};
+  records.forEach((item) => {
+    const key = item.schedulingUserName || "鏈煡";
+    if (!map[key]) {
+      map[key] = {
+        id: key,
+        schedulingUserName: key,
+        finishedNum: 0,
+        wages: 0,
+        qualifiedRate: item.qualifiedRate ?? null,
+      };
+    }
+    map[key].finishedNum += Number(item.finishedNum || 0);
+    map[key].wages += Number(item.wages || 0);
+    if (item.qualifiedRate != null) {
+      map[key].qualifiedRate = item.qualifiedRate;
+    }
+  });
+  leftTableData.value = Object.values(map);
 };
 
 // 宸︿晶鏃�/鏈堝垏鎹�
 const handleDateTypeChange = (value) => {
-	// 杩欓噷鍙綔涓虹瓫閫夋潯浠剁殑涓�閮ㄥ垎锛岀洿鎺ラ噸鏂版煡璇㈠垪琛�
+  // 杩欓噷鍙綔涓虹瓫閫夋潯浠剁殑涓�閮ㄥ垎锛岀洿鎺ラ噸鏂版煡璇㈠垪琛�
   if (value === "day") {
     searchForm.value.entryDate = dayjs().format("YYYY-MM-DD");
     searchForm.value.dateRange = searchForm.value.entryDate
@@ -290,10 +352,52 @@
   tableData.value = []
 }
 
+const buildWorkDurationDetailList = (deviceWorkInfoPairList) => {
+  if (!deviceWorkInfoPairList) {
+    return [];
+  }
+  let listData = deviceWorkInfoPairList;
+  if (typeof deviceWorkInfoPairList === "string") {
+    try {
+      listData = JSON.parse(deviceWorkInfoPairList);
+    } catch {
+      return [];
+    }
+  }
+  if (!Array.isArray(listData)) {
+    return [];
+  }
+  const details = [];
+  listData.forEach(item => {
+    if (!item || typeof item !== "object") {
+      return;
+    }
+    Object.entries(item).forEach(([deviceName, workMinutes]) => {
+      const numericMinutes = Number(workMinutes);
+      if (deviceName) {
+        details.push({
+          deviceName,
+          workMinutes: Number.isFinite(numericMinutes) ? numericMinutes : 0,
+        });
+      }
+    });
+  });
+  return details;
+};
+
+const openWorkDurationDialog = row => {
+  currentSchedulingUserName.value = row?.schedulingUserName || "";
+  const details = Array.isArray(row?.workDurationDetailList)
+      ? row.workDurationDetailList
+      : buildWorkDurationDetailList(row?.deviceWorkInfoPairList);
+  workDurationDetailList.value = details;
+  workDurationDialogVisible.value = true;
+};
+
 // 鐐瑰嚮宸︿晶琛岋紝鍒峰彸渚ф槑缁嗭紙鎸夌敓浜т汉杩囨护锛�
 const handleLeftRowClick = (row) => {
-	searchForm.value.schedulingUserName = row.schedulingUserName || "";
-	handleQuery();
+  searchForm.value.schedulingUserName = row.schedulingUserName || "";
+  handleQuery();
 };
 
 // 鏌ヨ鍒楄〃
@@ -306,21 +410,21 @@
 
 // 瀵煎嚭
 const handleOut = () => {
-	ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-		confirmButtonText: "纭",
-		cancelButtonText: "鍙栨秷",
-		type: "warning",
-	})
-		.then(() => {
-			proxy.download("/salesLedger/productionAccounting/export", {}, "鐢熶骇鏍哥畻.xlsx");
-		})
-		.catch(() => {
-			proxy.$modal.msg("宸插彇娑�");
-		});
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  })
+      .then(() => {
+        proxy.download("/salesLedger/productionAccounting/export", {}, "鐢熶骇鏍哥畻.xlsx");
+      })
+      .catch(() => {
+        proxy.$modal.msg("宸插彇娑�");
+      });
 };
 
 onMounted(() => {
-	getList();
+  getList();
 });
 </script>
 

--
Gitblit v1.9.3