From 9c3cca091f8e69a6f96a356a7ad093d68240ebe3 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期三, 08 四月 2026 15:51:23 +0800
Subject: [PATCH] feat(生产核算): 添加工时明细查看功能
---
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