From f9d502b976ebb53281432faa56899015d49a87b6 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 11 三月 2026 18:00:11 +0800
Subject: [PATCH] 能源管理、生产计划模块开发
---
src/api/productionPlan/productionPlan.js | 60 +
src/views/productionPlan/summaryByProduct/index.vue | 290 ++++++
src/api/energyManagement/energyType.js | 25
src/views/energyManagement/energyType/index2.vue | 128 ++
src/views/productionPlan/productionPlan/components/PIMTable.vue | 18
src/views/productionPlan/productionPlan/index.vue | 1152 +++++++++++++++++++-------
src/views/energyManagement/officeEnergyConsumption/index.vue | 421 +++++++++
src/views/energyManagement/productionEnergyConsumption/index.vue | 413 +++++++++
8 files changed, 2,098 insertions(+), 409 deletions(-)
diff --git a/src/api/energyManagement/energyType.js b/src/api/energyManagement/energyType.js
index 43b8066..71fbc29 100644
--- a/src/api/energyManagement/energyType.js
+++ b/src/api/energyManagement/energyType.js
@@ -50,4 +50,29 @@
url: "/energyConsumptionDetail/" + ids,
method: "delete",
});
+}
+
+// 鏌ヨ闄勪欢鍒楄〃
+export function fileListPage(query) {
+ return request({
+ url: "/energyConsumptionDetailFile/page",
+ method: "get",
+ params: query,
+ });
+}
+
+// 娣诲姞闄勪欢
+export function energyConsumptionDetailFileAdd(query) {
+ return request({
+ url: '/energyConsumptionDetailFile',
+ method: 'post',
+ data: query
+ })
+}
+// 鍒犻櫎闄勪欢
+export function energyConsumptionDetailFileDel(ids) {
+ return request({
+ url: `/energyConsumptionDetailFile/${ids}`,
+ method: 'delete',
+ })
}
\ No newline at end of file
diff --git a/src/api/productionPlan/productionPlan.js b/src/api/productionPlan/productionPlan.js
index 2b08129..f064db9 100644
--- a/src/api/productionPlan/productionPlan.js
+++ b/src/api/productionPlan/productionPlan.js
@@ -9,3 +9,63 @@
params: query,
});
}
+
+// 鎷夊彇鏁版嵁
+export function loadProdData(query) {
+ return request({
+ url: "/productionPlan/loadProdData",
+ method: "get",
+ params: query,
+ });
+}
+
+export function summaryByProductType(query) {
+ return request({
+ url: "/productionPlan/summaryByProductType",
+ method: "get",
+ params: query,
+ });
+}
+
+// 瀵煎嚭鐢熶骇璁″垝
+export function exportProductionPlan(bomId) {
+ return request({
+ url: "/productionPlan/export",
+ method: "post",
+ params: { bomId },
+ responseType: "blob",
+ });
+}
+
+// 鐢熶骇璁″垝-鏂板淇敼
+export function productionPlanAdd(query) {
+ return request({
+ url: "/productionPlan",
+ method: "post",
+ data: query,
+ });
+}
+export function productionPlanUpdate(query) {
+ return request({
+ url: "/productionPlan",
+ method: "put",
+ data: query,
+ });
+}
+
+// 鐢熶骇璁″垝-鍒犻櫎
+export function productionPlanDelete(data) {
+ return request({
+ url: "/productionPlan",
+ method: "delete",
+ data
+ });
+}
+// 鍚堝苟涓嬪彂
+export function productionPlanCombine(query) {
+ return request({
+ url: "/productionPlan/combine",
+ method: "post",
+ data: query,
+ });
+}
\ No newline at end of file
diff --git a/src/views/energyManagement/energyType/index2.vue b/src/views/energyManagement/energyType/index2.vue
index 88296a1..9d0b104 100644
--- a/src/views/energyManagement/energyType/index2.vue
+++ b/src/views/energyManagement/energyType/index2.vue
@@ -11,11 +11,11 @@
style="width: 120px;"
@change="handleQuery">
<el-option label="姘�"
- value="gas" />
+ value="姘�" />
<el-option label="鐢�"
- value="electricity" />
+ value="鐢�" />
<el-option label="姘�"
- value="water" />
+ value="姘�" />
</el-select>
</el-form-item>
<el-form-item label="鑳芥簮鍚嶇О:">
@@ -495,7 +495,9 @@
.search_form {
display: flex;
justify-content: space-between;
- align-items: center;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ gap: 16px;
margin-bottom: 24px;
padding: 20px;
background-color: #ffffff;
@@ -505,6 +507,28 @@
&:hover {
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
+ }
+
+ :deep(.el-form) {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0;
+
+ .el-form-item {
+ margin-right: 16px;
+ margin-bottom: 0;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ > div {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ flex-shrink: 0;
}
}
@@ -637,28 +661,83 @@
font-size: 12px;
}
- @media (max-width: 768px) {
- .app-container {
- padding: 16px;
+ @media (max-width: 1200px) {
+ .search_form {
+ :deep(.el-form) {
+ .el-form-item {
+ margin-right: 12px;
+ margin-bottom: 8px;
+ }
+ }
}
+ }
+ @media (max-width: 992px) {
.search_form {
flex-direction: column;
- align-items: flex-start;
+ align-items: stretch;
gap: 12px;
- .el-form {
+ :deep(.el-form) {
width: 100%;
.el-form-item {
- width: 100%;
+ margin-right: 12px;
+ margin-bottom: 8px;
+ flex: 1;
+ min-width: 200px;
+
+ &:last-child {
+ margin-right: 12px;
+ }
}
}
> div {
width: 100%;
- display: flex;
- gap: 12px;
+ justify-content: flex-end;
+ }
+ }
+ }
+
+ @media (max-width: 768px) {
+ .app-container {
+ padding: 12px;
+ }
+
+ .search_form {
+ padding: 16px;
+ gap: 12px;
+
+ :deep(.el-form) {
+ flex-direction: column;
+ width: 100%;
+
+ .el-form-item {
+ width: 100%;
+ margin-right: 0;
+ margin-bottom: 12px;
+
+ &:last-child {
+ margin-right: 0;
+ margin-bottom: 0;
+ }
+
+ .el-form-item__content {
+ width: 100%;
+
+ .el-input,
+ .el-select,
+ .el-date-editor {
+ width: 100% !important;
+ }
+ }
+ }
+ }
+
+ > div {
+ width: 100%;
+ justify-content: stretch;
.el-button {
flex: 1;
@@ -666,17 +745,36 @@
}
}
+ .table_list {
+ height: calc(100vh - 300px);
+ }
+
:deep(.el-table) {
th,
td {
- padding: 10px 0;
+ padding: 8px 0;
font-size: 12px;
}
}
:deep(.el-dialog) {
- width: 90% !important;
- margin: 20px auto !important;
+ width: 95% !important;
+ margin: 10px auto !important;
+ }
+ }
+
+ @media (max-width: 480px) {
+ .search_form {
+ padding: 12px;
+
+ > div {
+ flex-direction: column;
+ gap: 8px;
+
+ .el-button {
+ width: 100%;
+ }
+ }
}
}
.consumption-value {
diff --git a/src/views/energyManagement/officeEnergyConsumption/index.vue b/src/views/energyManagement/officeEnergyConsumption/index.vue
index c3fbf82..0def5d5 100644
--- a/src/views/energyManagement/officeEnergyConsumption/index.vue
+++ b/src/views/energyManagement/officeEnergyConsumption/index.vue
@@ -11,14 +11,21 @@
style="width: 140px;"
@change="handleQuery">
<el-option label="姘�"
- value="water" />
+ value="姘�" />
<el-option label="鐢�"
- value="electricity" />
+ value="鐢�" />
<el-option label="姘�"
- value="gas" />
+ value="姘�" />
</el-select>
</el-form-item>
- <!-- <el-form-item label="鏃ユ湡鑼冨洿:">
+ <el-form-item label="鑳芥簮鍚嶇О:">
+ <el-input v-model="searchForm.energyName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="鏃ユ湡鑼冨洿:">
<el-date-picker v-model="searchForm.dateRange"
type="daterange"
range-separator="鑷�"
@@ -27,7 +34,7 @@
value-format="YYYY-MM-DD"
style="width: 240px;"
@change="handleQuery" />
- </el-form-item> -->
+ </el-form-item>
<el-form-item>
<el-button type="primary"
@click="handleQuery">鎼滅储</el-button>
@@ -35,10 +42,12 @@
</el-form-item>
</el-form>
<div>
- <!-- <el-button type="primary"
- @click="handleAdd">鏂板</el-button> -->
+ <el-button type="primary"
+ @click="handleAdd">鏂板</el-button>
<el-button type="success"
@click="handleExport">瀵煎嚭</el-button>
+ <el-button type="warning"
+ @click="handleImport">瀵煎叆</el-button>
</div>
</div>
<!-- 鏁版嵁琛ㄦ牸 -->
@@ -102,8 +111,8 @@
label="澶囨敞"
min-width="150"
show-overflow-tooltip />
- <!-- <el-table-column label="鎿嶄綔"
- width="180"
+ <el-table-column label="鎿嶄綔"
+ width="220"
align="center"
fixed="right">
<template #default="scope">
@@ -113,8 +122,11 @@
<el-button type="danger"
link
@click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ <el-button type="info"
+ link
+ @click="downLoadFile(scope.row)">闄勪欢</el-button>
</template>
- </el-table-column> -->
+ </el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination v-model:current-page="page.current"
@@ -199,6 +211,28 @@
</span>
</template>
</el-dialog>
+ <!-- 闄勪欢鍒楄〃寮圭獥 -->
+ <FileListDialog ref="fileListRef"
+ v-model="fileListDialogVisible"
+ :show-upload-button="true"
+ :show-delete-button="true"
+ :is-show-pagination="true"
+ :page="filePagination"
+ :upload-method="handleUpload"
+ :delete-method="handleFileDelete"
+ @pagination="paginationSearch"
+ title="闄勪欢鍒楄〃" />
+ <ImportDialog ref="importDialogRef"
+ v-model="importDialogVisible"
+ title="瀵煎叆鏄庣粏"
+ :action="importAction"
+ :headers="importHeaders"
+ :auto-upload="false"
+ :on-success="handleImportSuccess"
+ :on-error="handleImportError"
+ @confirm="handleImportConfirm"
+ @download-template="handleDownloadTemplate"
+ @close="handleImportClose" />
</div>
</template>
@@ -206,11 +240,18 @@
import { ref, reactive, onMounted, getCurrentInstance } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Watermelon, Lightning } from "@element-plus/icons-vue";
+ import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+ import { getToken } from "@/utils/auth";
+ import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+ import request from "@/utils/request";
import {
energyConsumptionDetailListPage,
energyConsumptionDetailAdd,
energyConsumptionDetailDelete,
energyTypeListPage,
+ fileListPage,
+ energyConsumptionDetailFileAdd,
+ energyConsumptionDetailFileDel,
} from "@/api/energyManagement/energyType";
// 鎼滅储琛ㄥ崟
@@ -247,6 +288,25 @@
const formRef = ref(null);
const isEdit = ref(false);
const currentId = ref(null);
+
+ // 闄勪欢鐩稿叧
+ const fileListRef = ref(null);
+ const fileListDialogVisible = ref(false);
+ const currentFileRow = ref(null);
+ const filePagination = ref({
+ current: 1,
+ size: 10,
+ total: 0,
+ });
+
+ // 瀵煎叆鐩稿叧
+ const importDialogRef = ref(null);
+ const importDialogVisible = ref(false);
+ const importAction =
+ import.meta.env.VITE_APP_BASE_API + "/energyConsumptionDetail/importData";
+ const importHeaders = ref({
+ Authorization: `Bearer ${getToken()}`,
+ });
// 琛ㄥ崟鏁版嵁
const form = reactive({
@@ -314,15 +374,16 @@
current: page.current,
size: page.size,
type: "鍔炲叕",
- // energyType: searchForm.energyType,
- // startDate:
- // searchForm.dateRange && searchForm.dateRange.length === 2
- // ? searchForm.dateRange[0]
- // : null,
- // endDate:
- // searchForm.dateRange && searchForm.dateRange.length === 2
- // ? searchForm.dateRange[1]
- // : null,
+ energyTyep: searchForm.energyType,
+ energyName: searchForm.energyName,
+ startDate:
+ searchForm.dateRange && searchForm.dateRange.length === 2
+ ? searchForm.dateRange[0]
+ : null,
+ endDate:
+ searchForm.dateRange && searchForm.dateRange.length === 2
+ ? searchForm.dateRange[1]
+ : null,
};
energyConsumptionDetailListPage(params)
.then(res => {
@@ -358,6 +419,7 @@
// 閲嶇疆
const handleReset = () => {
searchForm.energyType = "";
+ searchForm.energyName = "";
searchForm.dateRange = [];
page.current = 1;
handleQuery();
@@ -478,6 +540,205 @@
});
};
+ // 涓嬭浇鏂囦欢
+ const downLoadFile = row => {
+ currentFileRow.value = row;
+ fileListPage({
+ energyConsumptionDetailId: row.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ }).then(res => {
+ if (fileListRef.value) {
+ fileListRef.value.open(res.data.records);
+ }
+ filePagination.value.total = res.data.total || 0;
+ });
+ };
+
+ // 涓婁紶闄勪欢
+ const handleUpload = async () => {
+ if (!currentFileRow.value) {
+ ElMessage.warning("璇峰厛閫夋嫨鏁版嵁");
+ return null;
+ }
+
+ return new Promise(resolve => {
+ // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
+ const input = document.createElement("input");
+ input.type = "file";
+ input.style.display = "none";
+ input.onchange = async e => {
+ const file = e.target.files[0];
+ if (!file) {
+ resolve(null);
+ return;
+ }
+
+ try {
+ // 浣跨敤 FormData 涓婁紶鏂囦欢
+ const formData = new FormData();
+ formData.append("file", file);
+
+ const uploadRes = await request({
+ url: "/file/upload",
+ method: "post",
+ data: formData,
+ headers: {
+ "Content-Type": "multipart/form-data",
+ Authorization: `Bearer ${getToken()}`,
+ },
+ });
+
+ if (uploadRes.code === 200) {
+ // 淇濆瓨闄勪欢淇℃伅
+ const fileData = {
+ energyConsumptionDetailId: currentFileRow.value.id,
+ name: uploadRes.data.originalName || file.name,
+ url: uploadRes.data.tempPath || uploadRes.data.url,
+ };
+
+ const saveRes = await energyConsumptionDetailFileAdd(fileData);
+ if (saveRes.code === 200) {
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200 && fileListRef.value) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ // 杩斿洖鏂版枃浠朵俊鎭�
+ resolve({
+ name: fileData.name,
+ url: fileData.url,
+ id: Date.now(),
+ });
+ } else {
+ ElMessage.error(uploadRes.message || "鏂囦欢涓婁紶澶辫触");
+ resolve(null);
+ }
+ }
+ } catch (error) {
+ ElMessage.error("鏂囦欢涓婁紶澶辫触");
+ resolve(null);
+ } finally {
+ document.body.removeChild(input);
+ }
+ };
+
+ document.body.appendChild(input);
+ input.click();
+ });
+ };
+
+ // 鍒嗛〉鎼滅储
+ const paginationSearch = async (page, size) => {
+ filePagination.value.current = page;
+ filePagination.value.size = size;
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ };
+
+ // 鍒犻櫎闄勪欢
+ const handleFileDelete = async row => {
+ try {
+ const res = await energyConsumptionDetailFileDel([row.id]);
+ if (res.code === 200) {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+ if (currentFileRow.value && fileListRef.value) {
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ }
+ return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
+ } else {
+ proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+ return false;
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触");
+ return false;
+ }
+ };
+
+ // 瀵煎叆
+ const handleImport = () => {
+ importDialogVisible.value = true;
+ };
+
+ // 瀵煎叆鎴愬姛
+ const handleImportSuccess = response => {
+ if (response.code === 200) {
+ ElMessage.success("瀵煎叆鎴愬姛");
+ importDialogVisible.value = false;
+ handleQuery();
+ } else {
+ ElMessage.error(response.message || "瀵煎叆澶辫触");
+ }
+ };
+
+ // 瀵煎叆澶辫触
+ const handleImportError = error => {
+ ElMessage.error("瀵煎叆澶辫触锛岃妫�鏌ユ枃浠舵牸寮忔槸鍚︽纭�");
+ };
+
+ // 纭瀵煎叆
+ const handleImportConfirm = () => {
+ if (importDialogRef.value) {
+ importDialogRef.value.submit();
+ }
+ };
+
+ // 涓嬭浇妯℃澘
+ const handleDownloadTemplate = () => {
+ proxy.download(
+ "/energyConsumptionDetail/downloadTemplate",
+ {},
+ "鐢熶骇鑳借�楀鍏ユā鏉�.xlsx"
+ );
+ };
+
+ // 鍏抽棴瀵煎叆寮圭獥
+ const handleImportClose = () => {
+ importDialogVisible.value = false;
+ };
+
onMounted(() => {
getEnergyTypeList();
handleQuery();
@@ -494,7 +755,9 @@
.search_form {
display: flex;
justify-content: space-between;
- align-items: center;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ gap: 16px;
margin-bottom: 24px;
padding: 20px;
background-color: #ffffff;
@@ -504,6 +767,28 @@
&:hover {
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
+ }
+
+ :deep(.el-form) {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0;
+
+ .el-form-item {
+ margin-right: 16px;
+ margin-bottom: 0;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ > div {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ flex-shrink: 0;
}
}
@@ -636,28 +921,83 @@
font-size: 12px;
}
- @media (max-width: 768px) {
- .app-container {
- padding: 16px;
+ @media (max-width: 1200px) {
+ .search_form {
+ :deep(.el-form) {
+ .el-form-item {
+ margin-right: 12px;
+ margin-bottom: 8px;
+ }
+ }
}
+ }
+ @media (max-width: 992px) {
.search_form {
flex-direction: column;
- align-items: flex-start;
+ align-items: stretch;
gap: 12px;
- .el-form {
+ :deep(.el-form) {
width: 100%;
.el-form-item {
- width: 100%;
+ margin-right: 12px;
+ margin-bottom: 8px;
+ flex: 1;
+ min-width: 200px;
+
+ &:last-child {
+ margin-right: 12px;
+ }
}
}
> div {
width: 100%;
- display: flex;
- gap: 12px;
+ justify-content: flex-end;
+ }
+ }
+ }
+
+ @media (max-width: 768px) {
+ .app-container {
+ padding: 12px;
+ }
+
+ .search_form {
+ padding: 16px;
+ gap: 12px;
+
+ :deep(.el-form) {
+ flex-direction: column;
+ width: 100%;
+
+ .el-form-item {
+ width: 100%;
+ margin-right: 0;
+ margin-bottom: 12px;
+
+ &:last-child {
+ margin-right: 0;
+ margin-bottom: 0;
+ }
+
+ .el-form-item__content {
+ width: 100%;
+
+ .el-input,
+ .el-select,
+ .el-date-editor {
+ width: 100% !important;
+ }
+ }
+ }
+ }
+
+ > div {
+ width: 100%;
+ justify-content: stretch;
.el-button {
flex: 1;
@@ -665,17 +1005,36 @@
}
}
+ .table_list {
+ height: calc(100vh - 300px);
+ }
+
:deep(.el-table) {
th,
td {
- padding: 10px 0;
+ padding: 8px 0;
font-size: 12px;
}
}
:deep(.el-dialog) {
- width: 90% !important;
- margin: 20px auto !important;
+ width: 95% !important;
+ margin: 10px auto !important;
+ }
+ }
+
+ @media (max-width: 480px) {
+ .search_form {
+ padding: 12px;
+
+ > div {
+ flex-direction: column;
+ gap: 8px;
+
+ .el-button {
+ width: 100%;
+ }
+ }
}
}
.consumption-value {
diff --git a/src/views/energyManagement/productionEnergyConsumption/index.vue b/src/views/energyManagement/productionEnergyConsumption/index.vue
index 7a69ec2..cf8784f 100644
--- a/src/views/energyManagement/productionEnergyConsumption/index.vue
+++ b/src/views/energyManagement/productionEnergyConsumption/index.vue
@@ -11,14 +11,21 @@
style="width: 140px;"
@change="handleQuery">
<el-option label="姘�"
- value="water" />
+ value="姘�" />
<el-option label="鐢�"
- value="electricity" />
+ value="鐢�" />
<el-option label="姘�"
- value="gas" />
+ value="姘�" />
</el-select>
</el-form-item>
- <!-- <el-form-item label="鏃ユ湡鑼冨洿:">
+ <el-form-item label="鑳芥簮鍚嶇О:">
+ <el-input v-model="searchForm.energyName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="鏃ユ湡鑼冨洿:">
<el-date-picker v-model="searchForm.dateRange"
type="daterange"
range-separator="鑷�"
@@ -27,7 +34,7 @@
value-format="YYYY-MM-DD"
style="width: 240px;"
@change="handleQuery" />
- </el-form-item> -->
+ </el-form-item>
<el-form-item>
<el-button type="primary"
@click="handleQuery">鎼滅储</el-button>
@@ -39,6 +46,8 @@
@click="handleAdd">鏂板</el-button>
<el-button type="success"
@click="handleExport">瀵煎嚭</el-button>
+ <el-button type="warning"
+ @click="handleImport">瀵煎叆</el-button>
</div>
</div>
<!-- 鏁版嵁琛ㄦ牸 -->
@@ -103,7 +112,7 @@
min-width="150"
show-overflow-tooltip />
<el-table-column label="鎿嶄綔"
- width="180"
+ width="220"
align="center"
fixed="right">
<template #default="scope">
@@ -113,6 +122,9 @@
<el-button type="danger"
link
@click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ <el-button type="info"
+ link
+ @click="downLoadFile(scope.row)">闄勪欢</el-button>
</template>
</el-table-column>
</el-table>
@@ -199,6 +211,28 @@
</span>
</template>
</el-dialog>
+ <!-- 闄勪欢鍒楄〃寮圭獥 -->
+ <FileListDialog ref="fileListRef"
+ v-model="fileListDialogVisible"
+ :show-upload-button="true"
+ :show-delete-button="true"
+ :is-show-pagination="true"
+ :page="filePagination"
+ :upload-method="handleUpload"
+ :delete-method="handleFileDelete"
+ @pagination="paginationSearch"
+ title="闄勪欢鍒楄〃" />
+ <ImportDialog ref="importDialogRef"
+ v-model="importDialogVisible"
+ title="瀵煎叆鏄庣粏"
+ :action="importAction"
+ :headers="importHeaders"
+ :auto-upload="false"
+ :on-success="handleImportSuccess"
+ :on-error="handleImportError"
+ @confirm="handleImportConfirm"
+ @download-template="handleDownloadTemplate"
+ @close="handleImportClose" />
</div>
</template>
@@ -206,11 +240,18 @@
import { ref, reactive, onMounted, getCurrentInstance } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Watermelon, Lightning } from "@element-plus/icons-vue";
+ import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+ import { getToken } from "@/utils/auth";
+ import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+ import request from "@/utils/request";
import {
energyConsumptionDetailListPage,
energyConsumptionDetailAdd,
energyConsumptionDetailDelete,
energyTypeListPage,
+ fileListPage,
+ energyConsumptionDetailFileAdd,
+ energyConsumptionDetailFileDel,
} from "@/api/energyManagement/energyType";
// 鎼滅储琛ㄥ崟
@@ -247,6 +288,25 @@
const formRef = ref(null);
const isEdit = ref(false);
const currentId = ref(null);
+
+ // 闄勪欢鐩稿叧
+ const fileListRef = ref(null);
+ const fileListDialogVisible = ref(false);
+ const currentFileRow = ref(null);
+ const filePagination = ref({
+ current: 1,
+ size: 10,
+ total: 0,
+ });
+
+ // 瀵煎叆鐩稿叧
+ const importDialogRef = ref(null);
+ const importDialogVisible = ref(false);
+ const importAction =
+ import.meta.env.VITE_APP_BASE_API + "/energyConsumptionDetail/importData";
+ const importHeaders = ref({
+ Authorization: `Bearer ${getToken()}`,
+ });
// 琛ㄥ崟鏁版嵁
const form = reactive({
@@ -314,15 +374,16 @@
current: page.current,
size: page.size,
type: "鐢熶骇",
- // energyType: searchForm.energyType,
- // startDate:
- // searchForm.dateRange && searchForm.dateRange.length === 2
- // ? searchForm.dateRange[0]
- // : null,
- // endDate:
- // searchForm.dateRange && searchForm.dateRange.length === 2
- // ? searchForm.dateRange[1]
- // : null,
+ energyTyep: searchForm.energyType,
+ energyName: searchForm.energyName,
+ startDate:
+ searchForm.dateRange && searchForm.dateRange.length === 2
+ ? searchForm.dateRange[0]
+ : null,
+ endDate:
+ searchForm.dateRange && searchForm.dateRange.length === 2
+ ? searchForm.dateRange[1]
+ : null,
};
energyConsumptionDetailListPage(params)
.then(res => {
@@ -358,6 +419,7 @@
// 閲嶇疆
const handleReset = () => {
searchForm.energyType = "";
+ searchForm.energyName = "";
searchForm.dateRange = [];
page.current = 1;
handleQuery();
@@ -478,6 +540,205 @@
});
};
+ // 涓嬭浇鏂囦欢
+ const downLoadFile = row => {
+ currentFileRow.value = row;
+ fileListPage({
+ energyConsumptionDetailId: row.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ }).then(res => {
+ if (fileListRef.value) {
+ fileListRef.value.open(res.data.records);
+ }
+ filePagination.value.total = res.data.total || 0;
+ });
+ };
+
+ // 涓婁紶闄勪欢
+ const handleUpload = async () => {
+ if (!currentFileRow.value) {
+ ElMessage.warning("璇峰厛閫夋嫨鏁版嵁");
+ return null;
+ }
+
+ return new Promise(resolve => {
+ // 鍒涘缓涓�涓殣钘忕殑鏂囦欢杈撳叆鍏冪礌
+ const input = document.createElement("input");
+ input.type = "file";
+ input.style.display = "none";
+ input.onchange = async e => {
+ const file = e.target.files[0];
+ if (!file) {
+ resolve(null);
+ return;
+ }
+
+ try {
+ // 浣跨敤 FormData 涓婁紶鏂囦欢
+ const formData = new FormData();
+ formData.append("file", file);
+
+ const uploadRes = await request({
+ url: "/file/upload",
+ method: "post",
+ data: formData,
+ headers: {
+ "Content-Type": "multipart/form-data",
+ Authorization: `Bearer ${getToken()}`,
+ },
+ });
+
+ if (uploadRes.code === 200) {
+ // 淇濆瓨闄勪欢淇℃伅
+ const fileData = {
+ energyConsumptionDetailId: currentFileRow.value.id,
+ name: uploadRes.data.originalName || file.name,
+ url: uploadRes.data.tempPath || uploadRes.data.url,
+ };
+
+ const saveRes = await energyConsumptionDetailFileAdd(fileData);
+ if (saveRes.code === 200) {
+ proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200 && fileListRef.value) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ // 杩斿洖鏂版枃浠朵俊鎭�
+ resolve({
+ name: fileData.name,
+ url: fileData.url,
+ id: Date.now(),
+ });
+ } else {
+ ElMessage.error(uploadRes.message || "鏂囦欢涓婁紶澶辫触");
+ resolve(null);
+ }
+ }
+ } catch (error) {
+ ElMessage.error("鏂囦欢涓婁紶澶辫触");
+ resolve(null);
+ } finally {
+ document.body.removeChild(input);
+ }
+ };
+
+ document.body.appendChild(input);
+ input.click();
+ });
+ };
+
+ // 鍒嗛〉鎼滅储
+ const paginationSearch = async (page, size) => {
+ filePagination.value.current = page;
+ filePagination.value.size = size;
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ };
+
+ // 鍒犻櫎闄勪欢
+ const handleFileDelete = async row => {
+ try {
+ const res = await energyConsumptionDetailFileDel([row.id]);
+ if (res.code === 200) {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ // 閲嶆柊鍔犺浇鏂囦欢鍒楄〃
+ if (currentFileRow.value && fileListRef.value) {
+ const listRes = await fileListPage({
+ energyConsumptionDetailId: currentFileRow.value.id,
+ current: filePagination.value.current,
+ size: filePagination.value.size,
+ });
+ if (listRes.code === 200) {
+ const fileList = (listRes.data?.records || []).map(item => ({
+ name: item.name,
+ url: item.url,
+ id: item.id,
+ ...item,
+ }));
+ fileListRef.value.setList(fileList);
+ filePagination.value.total = listRes.data?.total || 0;
+ }
+ }
+ return true; // 杩斿洖 true 琛ㄧず鍒犻櫎鎴愬姛锛岀粍浠朵細鏇存柊鍒楄〃
+ } else {
+ proxy.$modal.msgError(res.msg || "鍒犻櫎澶辫触");
+ return false;
+ }
+ } catch (error) {
+ ElMessage.error("鍒犻櫎澶辫触");
+ return false;
+ }
+ };
+
+ // 瀵煎叆
+ const handleImport = () => {
+ importDialogVisible.value = true;
+ };
+
+ // 瀵煎叆鎴愬姛
+ const handleImportSuccess = response => {
+ if (response.code === 200) {
+ ElMessage.success("瀵煎叆鎴愬姛");
+ importDialogVisible.value = false;
+ handleQuery();
+ } else {
+ ElMessage.error(response.message || "瀵煎叆澶辫触");
+ }
+ };
+
+ // 瀵煎叆澶辫触
+ const handleImportError = error => {
+ ElMessage.error("瀵煎叆澶辫触锛岃妫�鏌ユ枃浠舵牸寮忔槸鍚︽纭�");
+ };
+
+ // 纭瀵煎叆
+ const handleImportConfirm = () => {
+ if (importDialogRef.value) {
+ importDialogRef.value.submit();
+ }
+ };
+
+ // 涓嬭浇妯℃澘
+ const handleDownloadTemplate = () => {
+ proxy.download(
+ "/energyConsumptionDetail/downloadTemplate",
+ {},
+ "鐢熶骇鑳借�楀鍏ユā鏉�.xlsx"
+ );
+ };
+
+ // 鍏抽棴瀵煎叆寮圭獥
+ const handleImportClose = () => {
+ importDialogVisible.value = false;
+ };
+
onMounted(() => {
getEnergyTypeList();
handleQuery();
@@ -494,7 +755,9 @@
.search_form {
display: flex;
justify-content: space-between;
- align-items: center;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ gap: 16px;
margin-bottom: 24px;
padding: 20px;
background-color: #ffffff;
@@ -504,6 +767,28 @@
&:hover {
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
+ }
+
+ :deep(.el-form) {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0;
+
+ .el-form-item {
+ margin-right: 16px;
+ margin-bottom: 0;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ > div {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ flex-shrink: 0;
}
}
@@ -636,28 +921,83 @@
font-size: 12px;
}
- @media (max-width: 768px) {
- .app-container {
- padding: 16px;
+ @media (max-width: 1200px) {
+ .search_form {
+ :deep(.el-form) {
+ .el-form-item {
+ margin-right: 12px;
+ margin-bottom: 8px;
+ }
+ }
}
+ }
+ @media (max-width: 992px) {
.search_form {
flex-direction: column;
- align-items: flex-start;
+ align-items: stretch;
gap: 12px;
- .el-form {
+ :deep(.el-form) {
width: 100%;
.el-form-item {
- width: 100%;
+ margin-right: 12px;
+ margin-bottom: 8px;
+ flex: 1;
+ min-width: 200px;
+
+ &:last-child {
+ margin-right: 12px;
+ }
}
}
> div {
width: 100%;
- display: flex;
- gap: 12px;
+ justify-content: flex-end;
+ }
+ }
+ }
+
+ @media (max-width: 768px) {
+ .app-container {
+ padding: 12px;
+ }
+
+ .search_form {
+ padding: 16px;
+ gap: 12px;
+
+ :deep(.el-form) {
+ flex-direction: column;
+ width: 100%;
+
+ .el-form-item {
+ width: 100%;
+ margin-right: 0;
+ margin-bottom: 12px;
+
+ &:last-child {
+ margin-right: 0;
+ margin-bottom: 0;
+ }
+
+ .el-form-item__content {
+ width: 100%;
+
+ .el-input,
+ .el-select,
+ .el-date-editor {
+ width: 100% !important;
+ }
+ }
+ }
+ }
+
+ > div {
+ width: 100%;
+ justify-content: stretch;
.el-button {
flex: 1;
@@ -665,17 +1005,36 @@
}
}
+ .table_list {
+ height: calc(100vh - 300px);
+ }
+
:deep(.el-table) {
th,
td {
- padding: 10px 0;
+ padding: 8px 0;
font-size: 12px;
}
}
:deep(.el-dialog) {
- width: 90% !important;
- margin: 20px auto !important;
+ width: 95% !important;
+ margin: 10px auto !important;
+ }
+ }
+
+ @media (max-width: 480px) {
+ .search_form {
+ padding: 12px;
+
+ > div {
+ flex-direction: column;
+ gap: 8px;
+
+ .el-button {
+ width: 100%;
+ }
+ }
}
}
.consumption-value {
diff --git a/src/views/productionPlan/productionPlan/components/PIMTable.vue b/src/views/productionPlan/productionPlan/components/PIMTable.vue
index c0f7616..9431002 100644
--- a/src/views/productionPlan/productionPlan/components/PIMTable.vue
+++ b/src/views/productionPlan/productionPlan/components/PIMTable.vue
@@ -43,7 +43,8 @@
:align="item.align"
:sortable="!!item.sortable"
:type="item.type"
- :width="item.width">
+ :width="item.width"
+ :class-name="item.className || ''">
<template #header="scope">
<div class="pim-table-header-cell">
<div class="pim-table-header-title">
@@ -65,24 +66,28 @@
</template>
<template #default="scope">
<!-- 鎻掓Ы -->
- <div v-if="item.dataType == 'slot'">
+ <div v-if="item.dataType == 'slot'"
+ :class="item.className || ''">
<slot v-if="item.slot"
:index="scope.$index"
:name="item.slot"
:row="scope.row" />
</div>
<!-- 杩涘害鏉� -->
- <div v-else-if="item.dataType == 'progress'">
+ <div v-else-if="item.dataType == 'progress'"
+ :class="item.className || ''">
<el-progress :percentage="Number(scope.row[item.prop])" />
</div>
<!-- 鍥剧墖 -->
- <div v-else-if="item.dataType == 'image'">
+ <div v-else-if="item.dataType == 'image'"
+ :class="item.className || ''">
<img :src="javaApi + '/img/' + scope.row[item.prop]"
alt=""
style="width: 40px; height: 40px; margin-top: 10px" />
</div>
<!-- tag -->
- <div v-else-if="item.dataType == 'tag'">
+ <div v-else-if="item.dataType == 'tag'"
+ :class="item.className || ''">
<el-tag v-if="
typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
'string'
@@ -112,6 +117,7 @@
</div>
<!-- 鎸夐挳 -->
<div v-else-if="item.dataType == 'action'"
+ :class="item.className || ''"
@click.stop>
<template v-for="(o, key) in item.operation"
:key="key">
@@ -172,6 +178,7 @@
</div>
<!-- 鍙偣鍑荤殑鏂囧瓧 -->
<div v-else-if="item.dataType == 'link'"
+ :class="item.className || ''"
class="cell link"
style="width: 100%"
@click="goLink(scope.row, item.linkMethod)">
@@ -180,6 +187,7 @@
<!-- 榛樿绾睍绀烘暟鎹� -->
<div v-else
class="cell"
+ :class="item.className || ''"
style="width: 100%">
<span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
<span v-else>{{
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index 7c475ce..db2ab5e 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -3,46 +3,69 @@
<div class="search_form">
<el-form :model="searchForm"
:inline="true">
- <el-form-item label="杞﹂棿:">
- <el-select v-model="searchForm.workshop"
- placeholder="璇烽�夋嫨"
- clearable
- style="width: 160px;"
- @change="handleQuery">
- <el-option label="杞﹂棿1"
- value="1" />
- <el-option label="杞﹂棿2"
- value="2" />
- <el-option label="杞﹂棿3"
- value="3" />
- </el-select>
+ <el-form-item label="瀹㈡埛鍚嶇О:">
+ <el-input v-model="searchForm.customerName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
</el-form-item>
- <el-form-item label="鐘舵��:">
- <el-select v-model="searchForm.status"
- placeholder="璇烽�夋嫨"
- clearable
- style="width: 160px;"
- @change="handleQuery">
- <el-option label="寰呭鐞�"
- value="pending" />
- <el-option label="杩涜涓�"
- value="processing" />
- <el-option label="宸插畬鎴�"
- value="completed" />
- </el-select>
+ <el-form-item label="浜у搧鍚嶇О:">
+ <el-input v-model="searchForm.productName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="浜у搧瑙勬牸:">
+ <el-input v-model="searchForm.productSpec"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="鐗╂枡缂栫爜:">
+ <el-input v-model="searchForm.materialCode"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="鐢宠鍗曠紪鍙�:">
+ <el-input v-model="searchForm.applyNo"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="璁″垝鏃ユ湡鑼冨洿:">
+ <el-date-picker v-model="searchForm.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ value-format="YYYY-MM-DD"
+ style="width: 240px;"
+ @change="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary"
@click="handleQuery">鎼滅储</el-button>
+ <el-button type="info"
+ @click="handleReset">閲嶇疆</el-button>
+ <el-button type="primary"
+ @click="handleAdd">鏂板</el-button>
+ <el-button type="warning"
+ @click="getLoadProdData">鎷夊彇鏁版嵁</el-button>
+ <el-button type="warning"
+ @click="handleMerge">鍚堝苟涓嬪彂</el-button>
+ <el-button type="warning"
+ @click="handleImport">瀵煎叆</el-button>
+ <el-button type="warning"
+ @click="handleExport">瀵煎嚭</el-button>
</el-form-item>
</el-form>
<div>
- <el-button type="primary"
- @click="handleMerge">鍜屽苟涓嬪彂</el-button>
- <el-button type="info"
- @click="showCategorySummaryDialog = true">浜у搧绫诲埆姹囨��</el-button>
- <!-- <el-button type="danger"
- @click="handleDelete">鍒犻櫎</el-button> -->
</div>
</div>
<div class="table_list">
@@ -61,23 +84,50 @@
<!-- 鍚堝苟涓嬪彂寮圭獥 -->
<el-dialog v-model="isShowNewModal"
title="鍚堝苟涓嬪彂"
- width="500px">
+ width="600px">
<el-form :model="mergeForm"
label-width="120px">
- <el-form-item label="搴忓垪鍙�">
- <el-input v-model="mergeForm.serialNo"
- disabled />
+ <el-row :gutter="20">
+ <el-col :span="10">
+ <el-form-item label="鐗╂枡缂栫爜">
+ <div class="info-display">{{ mergeForm.materialCode || '-' }}</div>
+ </el-form-item>
+ </el-col>
+ <el-col :span="10">
+ <el-form-item label="浜у搧鍚嶇О">
+ <el-tag class="info-display">{{ mergeForm.productName || '-' }}</el-tag>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="10">
+ <el-form-item label="浜у搧瑙勬牸">
+ <div class="info-display">{{ mergeForm.productSpec || '-' }}</div>
+ </el-form-item>
+ </el-col>
+ <el-col :span="10">
+ <el-form-item label="闀�*瀹�*楂�">
+ <div class="info-display">{{ mergeForm.length || '-' }}*{{ mergeForm.width || '-' }}*{{ mergeForm.height || '-' }}</div>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-form-item label="璁″垝瀹屾垚鏃堕棿">
+ <el-date-picker v-model="mergeForm.planCompleteTime"
+ type="date"
+ value-format="YYYY-MM-DD"
+ style="width: 100%" />
</el-form-item>
- <el-form-item label="鐢熶骇璁″垝鏁伴噺">
- <el-input-number v-model="mergeForm.totalquantity"
- :min="1"
- :step="1"
+ <el-form-item label="鐢熶骇鏂规暟">
+ <el-input-number v-model="mergeForm.totalAssignedQuantity"
+ :min="0"
+ :max="sumAssignedQuantity"
+ @change="onBlur"
style="width: 100%" />
</el-form-item>
- <el-form-item label="澶囨敞">
+ <!-- <el-form-item label="澶囨敞">
<el-input v-model="mergeForm.remark"
type="textarea" />
- </el-form-item>
+ </el-form-item> -->
</el-form>
<template #footer>
<span class="dialog-footer">
@@ -87,35 +137,14 @@
</span>
</template>
</el-dialog>
- <!-- 浜у搧绫诲埆姹囨�诲脊绐� -->
- <el-dialog v-model="showCategorySummaryDialog"
- title="浜у搧绫诲埆姹囨�荤粺璁�"
- width="400px">
- <el-table :data="categorySummary"
- border
- style="width: 100%">
- <el-table-column prop="materialCategory"
- label="浜у搧绫诲埆"
- align="center"
- width="150" />
- <el-table-column prop="totalquantity"
- label="鎬诲埗閫犳暟閲�"
- align="center" />
- </el-table>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="showCategorySummaryDialog = false">鍏抽棴</el-button>
- </span>
- </template>
- </el-dialog>
<!-- 杩借釜杩涘害寮圭獥 -->
<el-dialog v-model="showTrackProgressDialog"
- :title="`杩借釜杩涘害 - ${trackProgressForm.serialNo || ''}`"
+ :title="`杩借釜杩涘害 - ${trackProgressForm.materialCode || ''}`"
width="600px">
<el-form :model="trackProgressForm"
label-width="120px">
- <el-form-item label="搴忓垪鍙�">
- <el-input v-model="trackProgressForm.serialNo"
+ <el-form-item label="鐗╂枡缂栫爜">
+ <el-input v-model="trackProgressForm.materialCode"
disabled />
</el-form-item>
<el-form-item label="褰撳墠鐘舵��">
@@ -174,140 +203,295 @@
</span>
</template>
</el-dialog>
+ <!-- 瀵煎叆寮圭獥 -->
+ <ImportDialog ref="importDialogRef"
+ v-model="importDialogVisible"
+ title="瀵煎叆鐢熶骇璁″垝"
+ :action="importAction"
+ :headers="importHeaders"
+ :auto-upload="false"
+ :on-success="handleImportSuccess"
+ :on-error="handleImportError"
+ @confirm="handleImportConfirm"
+ @download-template="handleDownloadTemplate"
+ @close="handleImportClose" />
+ <!-- 鏂板/缂栬緫寮圭獥 -->
+ <el-dialog v-model="dialogVisible"
+ :title="operationType === 'add' ? '鏂板鐢熶骇璁″垝' : '缂栬緫鐢熶骇璁″垝'"
+ width="600px">
+ <el-form ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="120px">
+ <el-form-item label="鐢宠鍗曠紪鍙�"
+ prop="applyNo">
+ <el-input v-model="form.applyNo"
+ placeholder="璇疯緭鍏ョ敵璇峰崟缂栧彿" />
+ </el-form-item>
+ <el-form-item label="瀹㈡埛鍚嶇О"
+ prop="customerName">
+ <el-input v-model="form.customerName"
+ placeholder="璇疯緭鍏ュ鎴峰悕绉�" />
+ </el-form-item>
+ <el-form-item label="浜у搧鍚嶇О"
+ prop="productName">
+ <el-input v-model="form.productName"
+ placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�" />
+ </el-form-item>
+ <el-form-item label="浜у搧瑙勬牸"
+ prop="productSpec">
+ <el-input v-model="form.productSpec"
+ placeholder="璇疯緭鍏ヤ骇鍝佽鏍�" />
+ </el-form-item>
+ <el-form-item label="鐗╂枡缂栫爜"
+ prop="materialCode">
+ <el-input v-model="form.materialCode"
+ placeholder="璇疯緭鍏ョ墿鏂欑紪鐮�" />
+ </el-form-item>
+ <el-form-item label="鍧楁暟"
+ prop="quantity">
+ <el-input-number v-model="form.quantity"
+ :min="0"
+ placeholder="璇疯緭鍏ュ潡鏁�" />
+ </el-form-item>
+ <el-form-item label="鏂规暟"
+ prop="volume">
+ <el-input-number v-model="form.volume"
+ :min="0"
+ placeholder="璇疯緭鍏ユ柟鏁�" />
+ </el-form-item>
+ <el-form-item label="闀�"
+ prop="length">
+ <el-input-number v-model="form.length"
+ :min="0"
+ placeholder="璇疯緭鍏ラ暱搴�" />
+ </el-form-item>
+ <el-form-item label="瀹�"
+ prop="width">
+ <el-input-number v-model="form.width"
+ :min="0"
+ placeholder="璇疯緭鍏ュ搴�" />
+ </el-form-item>
+ <el-form-item label="楂�"
+ prop="height">
+ <el-input-number v-model="form.height"
+ :min="0"
+ placeholder="璇疯緭鍏ラ珮搴�" />
+ </el-form-item>
+ <el-form-item label="璁″垝寮�濮嬫棩鏈�"
+ prop="startDate">
+ <el-date-picker v-model="form.startDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨璁″垝寮�濮嬫棩鏈�" />
+ </el-form-item>
+ <el-form-item label="璁″垝缁撴潫鏃ユ湡"
+ prop="endDate">
+ <el-date-picker v-model="form.endDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨璁″垝缁撴潫鏃ユ湡" />
+ </el-form-item>
+ <el-form-item label="寮哄害"
+ prop="strength">
+ <el-input v-model="form.strength"
+ placeholder="璇疯緭鍏ュ己搴�" />
+ </el-form-item>
+ <el-form-item label="澶囨敞 1"
+ prop="remarkOne">
+ <el-input v-model="form.remarkOne"
+ placeholder="璇疯緭鍏ュ娉� 1" />
+ </el-form-item>
+ <el-form-item label="澶囨敞 2"
+ prop="remarkTwo">
+ <el-input v-model="form.remarkTwo"
+ placeholder="璇疯緭鍏ュ娉� 2" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary"
+ @click="handleSubmit">纭畾</el-button>
+ </span>
+ </template>
+ </el-dialog>
</div>
</template>
<script setup>
- import { onMounted, ref } from "vue";
+ import { onMounted, ref, reactive, getCurrentInstance } from "vue";
import { ElMessage } from "element-plus";
import dayjs from "dayjs";
- import { productionPlanListPage } from "@/api/productionPlan/productionPlan.js";
+ import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+ import { getToken } from "@/utils/auth";
+ import {
+ productionPlanListPage,
+ loadProdData,
+ exportProductionPlan,
+ productionPlanAdd,
+ productionPlanUpdate,
+ productionPlanDelete,
+ productionPlanCombine,
+ } from "@/api/productionPlan/productionPlan.js";
import PIMTable from "./components/PIMTable.vue";
+
+ const { proxy } = getCurrentInstance();
const tableColumn = ref([
{
- label: "鏉ユ簮",
- prop: "source",
- width: "100px",
+ label: "鐢宠鍗曠紪鍙�",
+ prop: "applyNo",
+ width: "150px",
+ className: "code-cell",
},
{
- label: "鐘舵��",
- prop: "status",
- width: "80px",
- },
- {
- label: "瀹℃牳鐘舵��",
- prop: "auditStatus",
- width: "100px",
- },
- {
- label: "璁㈠崟鍙�",
- prop: "orderNo",
- width: "120px",
- },
- {
- label: "搴忓垪鍙�",
- prop: "serialNo",
- width: "140px",
- },
- {
- label: "闆朵欢鍙�",
- prop: "partNo",
- width: "120px",
- },
- {
- label: "闆朵欢",
- prop: "partName",
- width: "120px",
- },
- {
- label: "浜у搧绫诲埆",
- prop: "materialCategory",
- width: "100px",
- },
- {
- label: "宸ヨ壓鏂囦欢鍙�",
- prop: "processFileNo",
- width: "140px",
- },
- {
- label: "閿�鍞暟閲�",
- prop: "salesQuantity",
- width: "100px",
- align: "right",
- },
- {
- label: "鍒堕�犳暟閲�",
- prop: "quantity",
- width: "100px",
- align: "right",
- },
- {
- label: "闆朵欢鍗曚綅",
- prop: "partUnit",
- width: "80px",
- },
- {
- label: "涓昏鍒掗渶姹傛棩鏈�",
- prop: "mainPlanDemandDate",
- formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
- width: "140px",
- },
- {
- label: "鎵胯鏃ユ湡",
- prop: "commitmentDate",
- formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
- width: "120px",
- },
- {
- label: "鍒堕�犲睘鎬�",
- prop: "manufactureProperty",
- width: "100px",
- },
- {
- label: "澶囨敞",
- prop: "remark",
+ label: "瀹㈡埛鍚嶇О",
+ prop: "customerName",
width: "150px",
},
{
- label: "鏇存柊鏃堕棿",
- prop: "updateTime",
- formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
- width: "120px",
- },
- {
- label: "鏇存柊浜�",
- prop: "updateBy",
+ label: "浜у搧鍚嶇О",
+ prop: "productName",
width: "100px",
+ dataType: "tag",
+ formatType: params => {
+ const typeMap = {
+ 鏉挎潗: "primary",
+ 鐮屽潡: "info",
+ };
+ return typeMap[params] || "info";
+ },
},
{
- label: "鍒涘缓鏃堕棿",
- prop: "createTime",
- formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
- width: "120px",
+ label: "浜у搧瑙勬牸",
+ prop: "productSpec",
+ width: "150px",
+ className: "spec-cell",
},
{
- label: "鍒涘缓浜�",
- prop: "createBy",
- width: "100px",
+ label: "鐗╂枡缂栫爜",
+ prop: "materialCode",
+ width: "150px",
+ className: "code-cell",
},
+ {
+ label: "鍧楁暟",
+ prop: "quantity",
+ className: "quantity-cell",
+ },
+ {
+ label: "鏂规暟",
+ prop: "volume",
+ width: "150px",
+ className: "volume-cell",
+ },
+ {
+ label: "宸蹭笅鍙戞柟鏁�",
+ prop: "assignedQuantity",
+ width: "150px",
+ className: "spec-cell",
+ },
+ {
+ label: "闀�",
+ prop: "length",
+ className: "dimension-cell",
+ },
+ {
+ label: "瀹�",
+ prop: "width",
+ className: "dimension-cell",
+ },
+ {
+ label: "楂�",
+ prop: "height",
+ className: "dimension-cell",
+ },
+ {
+ label: "娴佹按鍙�",
+ prop: "serialNo",
+ width: "150px",
+ className: "code-cell",
+ },
+ {
+ label: "璁″垝寮�濮嬫棩鏈�",
+ prop: "startDate",
+ width: "150px",
+ className: "date-cell",
+ formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+ },
+ {
+ label: "璁″垝缁撴潫鏃ユ湡",
+ prop: "endDate",
+ width: "150px",
+ className: "date-cell",
+ formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+ },
+ {
+ label: "寮哄害",
+ prop: "strength",
+ },
+ // {
+ // label: "鏁版嵁鏉ユ簮",
+ // width: "100px",
+ // prop: "dataSourceType",
+ // formatData: cell => (cell == 1 ? "鍚屾" : "鎵嬪姩"),
+ // },
+ {
+ label: "澶囨敞 1",
+ prop: "remarkOne",
+ },
+ {
+ label: "澶囨敞 2",
+ prop: "remarkTwo",
+ },
+
{
dataType: "action",
label: "鎿嶄綔",
align: "center",
fixed: "right",
- width: 200,
+ width: 300,
operation: [
+ {
+ name: "缂栬緫",
+ type: "primary",
+ link: true,
+ clickFun: row => {
+ handleEdit(row);
+ },
+ },
+ {
+ name: "鍒犻櫎",
+ type: "danger",
+ link: true,
+ clickFun: row => {
+ handleDelete(row);
+ },
+ },
{
name: "涓嬪彂",
type: "text",
+ disabled: row => {
+ // 璁$畻鍓╀綑鏂规暟
+ const remainingVolume =
+ (row.volume || 0) - (row.assignedQuantity || 0);
+ // 濡傛灉鍓╀綑鏂规暟灏忎簬绛変簬0锛岀姝㈤�夋嫨
+ return remainingVolume <= 0;
+ },
clickFun: row => {
// 鍗曠嫭涓嬪彂鎿嶄綔
// 璁剧疆琛ㄥ崟鏁版嵁
- mergeForm.serialNo = row.serialNo;
- mergeForm.totalquantity = row.quantity;
- mergeForm.remark = "";
-
+ mergeForm.materialCode = row.materialCode;
+ mergeForm.productName = row.productName || "";
+ mergeForm.productSpec = row.productSpec || "";
+ mergeForm.length = row.length || 0;
+ mergeForm.width = row.width || 0;
+ mergeForm.height = row.height || 0;
+ mergeForm.totalAssignedQuantity =
+ Number(row.volume) - Number(row.assignedQuantity) || 0;
+ mergeForm.planCompleteTime = row.planCompleteTime || "";
+ sumAssignedQuantity.value = mergeForm.totalAssignedQuantity;
// 鎵撳紑寮圭獥
isShowNewModal.value = true;
},
@@ -340,26 +524,74 @@
const isShowNewModal = ref(false);
// 鍚堝苟涓嬪彂琛ㄥ崟鏁版嵁
const mergeForm = reactive({
- serialNo: "",
- totalquantity: 0,
- remark: "",
+ materialCode: "",
+ productName: "",
+ productSpec: "",
+ length: 0,
+ width: 0,
+ height: 0,
+ totalAssignedQuantity: 0,
+ planCompleteTime: "",
});
// 杩借釜杩涘害寮圭獥鎺у埗
const showTrackProgressDialog = ref(false);
// 杩借釜杩涘害琛ㄥ崟鏁版嵁
const trackProgressForm = reactive({
- serialNo: "",
+ materialCode: "",
currentStatus: "",
completionRate: 0,
progressDetails: [],
remark: "",
});
+ // 瀵煎叆鐩稿叧
+ const importDialogRef = ref(null);
+ const importDialogVisible = ref(false);
+ const importAction =
+ import.meta.env.VITE_APP_BASE_API + "/productionPlan/import";
+ const importHeaders = ref({
+ Authorization: `Bearer ${getToken()}`,
+ });
+
+ // 鏂板/缂栬緫鐩稿叧
+ const dialogVisible = ref(false);
+ const operationType = ref("add"); // add | edit
+ const formRef = ref(null);
+ const form = reactive({
+ id: undefined,
+ applyNo: "",
+ customerName: "",
+ productName: "",
+ productSpec: "",
+ materialCode: "",
+ quantity: 0,
+ volume: 0,
+ length: 0,
+ width: 0,
+ height: 0,
+ startDate: "",
+ endDate: "",
+ strength: "",
+ remarkOne: "",
+ remarkTwo: "",
+ });
+ const rules = reactive({
+ applyNo: [{ required: true, message: "璇疯緭鍏ョ敵璇峰崟缂栧彿", trigger: "blur" }],
+ customerName: [
+ { required: true, message: "璇疯緭鍏ュ鎴峰悕绉�", trigger: "blur" },
+ ],
+ productName: [{ required: true, message: "璇疯緭鍏ヤ骇鍝佸悕绉�", trigger: "blur" }],
+ productSpec: [{ required: true, message: "璇疯緭鍏ヤ骇鍝佽鏍�", trigger: "blur" }],
+ materialCode: [
+ { required: true, message: "璇疯緭鍏ョ墿鏂欑紪鐮�", trigger: "blur" },
+ ],
+ });
+
// 澶勭悊杩借釜杩涘害鎸夐挳鐐瑰嚮
const handleTrackProgress = row => {
// 璁剧疆琛ㄥ崟鏁版嵁
- trackProgressForm.serialNo = row.serialNo;
+ trackProgressForm.materialCode = row.materialCode;
trackProgressForm.currentStatus = row.status;
// 鐢熸垚妯℃嫙杩涘害鏁版嵁
@@ -373,6 +605,10 @@
// 鎵撳紑寮圭獥
showTrackProgressDialog.value = true;
+ };
+ const onBlur = value => {
+ // 闄愬埗鍥涗綅灏忔暟
+ mergeForm.totalAssignedQuantity = Number(value.toFixed(4));
};
// 鐢熸垚妯℃嫙杩涘害璇︽儏鏁版嵁
@@ -449,10 +685,11 @@
const data = reactive({
searchForm: {
customerName: "",
- salesContractNo: "",
- projectName: "",
- materialCategory: "",
- specificationModel: "",
+ productName: "",
+ productSpec: "",
+ materialCode: "",
+ applyNo: "",
+ dateRange: [],
},
});
const { searchForm } = toRefs(data);
@@ -460,6 +697,20 @@
// 鏌ヨ鍒楄〃
/** 鎼滅储鎸夐挳鎿嶄綔 */
const handleQuery = () => {
+ page.current = 1;
+ getList();
+ };
+
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ const handleReset = () => {
+ Object.assign(searchForm.value, {
+ customerName: "",
+ productName: "",
+ productSpec: "",
+ materialCode: "",
+ applyNo: "",
+ dateRange: [],
+ });
page.current = 1;
getList();
};
@@ -474,14 +725,15 @@
// 閬嶅巻琛ㄦ牸鏁版嵁锛屾寜浜у搧绫诲埆姹囨��
tableData.value.forEach(row => {
- const category = row.materialCategory;
+ const category = row.materialCode;
if (!summary[category]) {
summary[category] = {
- materialCategory: category,
- totalquantity: 0,
+ materialCode: category,
+ totalAssignedQuantity: 0,
};
}
- summary[category].totalquantity += row.quantity;
+ summary[category].totalAssignedQuantity +=
+ Number(row.volume) - Number(row.assignedQuantity);
});
// 杞崲涓烘暟缁勬牸寮�
@@ -490,130 +742,11 @@
const getList = () => {
tableLoading.value = true;
- // 鏋勯�犱竴涓柊鐨勫璞★紝涓嶅寘鍚玡ntryDate瀛楁
+ // 鏋勯�犳悳绱㈠弬鏁�
const params = { ...searchForm.value, ...page };
- params.entryDate = undefined;
- // tableData.value = [
- // {
- // id: 1,
- // source: "閿�鍞鍗�",
- // status: "寰呭鐞�",
- // auditStatus: "宸插鏍�",
- // orderNo: "SO20260301001",
- // serialNo: "PP20260301001",
- // partNo: "P001",
- // partName: "闆朵欢A",
- // materialCategory: "绫诲埆1",
- // processFileNo: "PF20260301001",
- // salesQuantity: 100,
- // quantity: 105,
- // partUnit: "涓�",
- // mainPlanDemandDate: "2026-03-15",
- // commitmentDate: "2026-03-10",
- // manufactureProperty: "甯歌",
- // remark: "",
- // updateTime: "2026-03-01",
- // updateBy: "admin",
- // createTime: "2026-03-01",
- // createBy: "admin",
- // },
- // {
- // id: 2,
- // source: "閿�鍞鍗�",
- // status: "寰呭鐞�",
- // auditStatus: "宸插鏍�",
- // orderNo: "SO20260301002",
- // serialNo: "PP20260301001",
- // partNo: "P002",
- // partName: "闆朵欢B",
- // materialCategory: "绫诲埆1",
- // processFileNo: "PF20260301002",
- // salesQuantity: 200,
- // quantity: 210,
- // partUnit: "涓�",
- // mainPlanDemandDate: "2026-03-15",
- // commitmentDate: "2026-03-10",
- // manufactureProperty: "甯歌",
- // remark: "",
- // updateTime: "2026-03-01",
- // updateBy: "admin",
- // createTime: "2026-03-01",
- // createBy: "admin",
- // },
- // {
- // id: 3,
- // source: "閿�鍞鍗�",
- // status: "杩涜涓�",
- // auditStatus: "宸插鏍�",
- // orderNo: "SO20260301003",
- // serialNo: "PP20260301002",
- // partNo: "P003",
- // partName: "闆朵欢C",
- // materialCategory: "绫诲埆2",
- // processFileNo: "PF20260301003",
- // salesQuantity: 150,
- // quantity: 155,
- // partUnit: "涓�",
- // mainPlanDemandDate: "2026-03-20",
- // commitmentDate: "2026-03-15",
- // manufactureProperty: "甯歌",
- // remark: "",
- // updateTime: "2026-03-01",
- // updateBy: "admin",
- // createTime: "2026-03-01",
- // createBy: "admin",
- // },
- // {
- // id: 4,
- // source: "閿�鍞鍗�",
- // status: "杩涜涓�",
- // auditStatus: "宸插鏍�",
- // orderNo: "SO20260301004",
- // serialNo: "PP20260301002",
- // partNo: "P004",
- // partName: "闆朵欢D",
- // materialCategory: "绫诲埆2",
- // processFileNo: "PF20260301004",
- // salesQuantity: 300,
- // quantity: 315,
- // partUnit: "涓�",
- // mainPlanDemandDate: "2026-03-20",
- // commitmentDate: "2026-03-15",
- // manufactureProperty: "甯歌",
- // remark: "",
- // updateTime: "2026-03-01",
- // updateBy: "admin",
- // createTime: "2026-03-01",
- // createBy: "admin",
- // },
- // {
- // id: 5,
- // source: "閿�鍞鍗�",
- // status: "宸插畬鎴�",
- // auditStatus: "宸插鏍�",
- // orderNo: "SO20260301005",
- // serialNo: "PP20260301003",
- // partNo: "P005",
- // partName: "闆朵欢E",
- // materialCategory: "绫诲埆3",
- // processFileNo: "PF20260301005",
- // salesQuantity: 250,
- // quantity: 260,
- // partUnit: "涓�",
- // mainPlanDemandDate: "2026-03-10",
- // commitmentDate: "2026-03-05",
- // manufactureProperty: "甯歌",
- // remark: "",
- // updateTime: "2026-03-01",
- // updateBy: "admin",
- // createTime: "2026-03-01",
- // createBy: "admin",
- // },
- // ];
- // tableLoading.value = false;
- // page.total = tableData.value.length;
- // // 璁$畻浜у搧绫诲埆姹囨�荤粺璁�
- // calculateCategorySummary();
+ params.startDate = params.dateRange ? params.dateRange[0] : "";
+ params.endDate = params.dateRange ? params.dateRange[1] : "";
+ delete params.dateRange;
productionPlanListPage(params)
.then(res => {
tableLoading.value = false;
@@ -636,7 +769,7 @@
selectedRows.value = selection;
// 濡傛灉鏈夐�変腑鐨勮锛岃褰曠涓�涓�変腑琛岀殑搴忓垪鍙�
if (selection.length > 0) {
- selectedserialNo.value = selection[0].serialNo;
+ selectedserialNo.value = selection[0].materialCode;
} else {
// 濡傛灉娌℃湁閫変腑鐨勮锛屾竻绌哄簭鍒楀彿
selectedserialNo.value = "";
@@ -645,30 +778,54 @@
// 鍒ゆ柇琛屾槸鍚﹀彲閫夋嫨
const isSelectable = row => {
+ // 璁$畻鍓╀綑鏂规暟
+ const remainingVolume = (row.volume || 0) - (row.assignedQuantity || 0);
+ // 濡傛灉鍓╀綑鏂规暟灏忎簬绛変簬0锛岀姝㈤�夋嫨
+ if (remainingVolume <= 0) {
+ return false;
+ }
// 濡傛灉娌℃湁閫変腑鐨勮锛屾墍鏈夎閮藉彲閫夋嫨
if (!selectedserialNo.value) {
return true;
}
// 濡傛灉鏈夐�変腑鐨勮锛屽彧鏈夊簭鍒楀彿鐩稿悓鐨勮鎵嶅彲閫夋嫨
- return row.serialNo === selectedserialNo.value;
+ return row.materialCode === selectedserialNo.value;
};
-
+ // 鎷夊彇鏁版嵁鎸夐挳鎿嶄綔
+ const getLoadProdData = () => {
+ loadProdData()
+ .then(res => {})
+ .catch(() => {});
+ };
+ const sumAssignedQuantity = ref(0);
// 澶勭悊鍚堝苟涓嬪彂鎸夐挳鐐瑰嚮
const handleMerge = () => {
if (selectedRows.value.length === 0) {
ElMessage.warning("璇烽�夋嫨瑕佸悎骞朵笅鍙戠殑鐢熶骇璁″垝");
return;
}
-
+ console.log(selectedRows.value);
// 璁$畻鎬诲埗閫犳暟閲�
- const totalQuantity = selectedRows.value.reduce((sum, row) => {
- return sum + row.quantity;
+ const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => {
+ return (
+ sum +
+ (row.volume == null
+ ? 0
+ : Number(row.volume) - Number(row.assignedQuantity))
+ );
}, 0);
-
+ sumAssignedQuantity.value = totalAssignedQuantity;
+ console.log(totalAssignedQuantity);
// 璁剧疆琛ㄥ崟鏁版嵁
- mergeForm.serialNo = selectedserialNo.value;
- mergeForm.totalquantity = totalQuantity;
- mergeForm.remark = "";
+ const firstRow = selectedRows.value[0];
+ mergeForm.materialCode = selectedserialNo.value;
+ mergeForm.productName = firstRow.productName || "";
+ mergeForm.productSpec = firstRow.productSpec || "";
+ mergeForm.length = firstRow.length || 0;
+ mergeForm.width = firstRow.width || 0;
+ mergeForm.height = firstRow.height || 0;
+ mergeForm.totalAssignedQuantity = totalAssignedQuantity;
+ mergeForm.planCompleteTime = firstRow.planCompleteTime || "";
// 鎵撳紑寮圭獥
isShowNewModal.value = true;
@@ -676,10 +833,219 @@
// 澶勭悊鍚堝苟涓嬪彂鎻愪氦
const handleMergeSubmit = () => {
- // 杩欓噷鍙互娣诲姞涓嬪彂閫昏緫
- ElMessage.success("鍚堝苟涓嬪彂鎴愬姛");
- isShowNewModal.value = false;
+ console.log(sumAssignedQuantity.value, "sumAssignedQuantity");
+ // 璁$畻褰撳墠閫変腑琛岀殑鎬绘柟鏁�
+ const totalVolume = selectedRows.value.reduce((sum, row) => {
+ return sum + (Number(row.volume) - Number(row.assignedQuantity) || 0);
+ }, 0);
+
+ // 楠岃瘉totalAssignedQuantity涓嶈兘澶т簬鎬绘柟鏁�
+ if (mergeForm.totalAssignedQuantity > sumAssignedQuantity.value) {
+ ElMessage.error("鐢熶骇鏂规暟涓嶈兘澶т簬褰撳墠璁$畻鐨勬�诲��");
+ return;
+ }
+
+ mergeForm.ids = selectedRows.value.map(row => row.id);
+ console.log(mergeForm, "mergeForm");
+ productionPlanCombine(mergeForm)
+ .then(res => {
+ if (res.code === 200) {
+ ElMessage.success("鍚堝苟涓嬪彂鎴愬姛");
+ isShowNewModal.value = false;
+ // 鍙互閫夋嫨鍒锋柊鍒楄〃鎴栧叾浠栨搷浣�
+ } else {
+ ElMessage.error(res.message || "鍚堝苟涓嬪彂澶辫触");
+ }
+ })
+ .catch(err => {
+ console.error("鍚堝苟涓嬪彂寮傚父锛�", err);
+ ElMessage.error("绯荤粺寮傚父锛屽悎骞朵笅鍙戝け璐�");
+ });
// 鍙互閫夋嫨鍒锋柊鍒楄〃鎴栧叾浠栨搷浣�
+ };
+
+ // 瀵煎叆
+ const handleImport = () => {
+ importDialogVisible.value = true;
+ };
+
+ // 瀵煎嚭
+ const handleExport = () => {
+ const fileName = `鐢熶骇璁″垝.xlsx`;
+ exportProductionPlan()
+ .then(res => {
+ // 杩斿洖鐨勬暟鎹槸鍚︿负绌�
+ if (!res) {
+ proxy.$modal.msgError("瀵煎嚭澶辫触锛岃繑鍥炴暟鎹负绌�");
+ return;
+ }
+
+ const blob = new Blob([res], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ const downloadElement = document.createElement("a");
+ const href = window.URL.createObjectURL(blob);
+
+ downloadElement.style.display = "none";
+ downloadElement.href = href;
+ downloadElement.download = fileName;
+
+ document.body.appendChild(downloadElement);
+ downloadElement.click();
+
+ document.body.removeChild(downloadElement);
+ window.URL.revokeObjectURL(href);
+
+ proxy.$modal.msgSuccess("瀵煎嚭鎴愬姛");
+ })
+ .catch(err => {
+ console.error("瀵煎嚭寮傚父锛�", err);
+ proxy.$modal.msgError("绯荤粺寮傚父锛屽鍑哄け璐�");
+ });
+ };
+
+ // 瀵煎叆鎴愬姛
+ const handleImportSuccess = response => {
+ if (response.code === 200) {
+ ElMessage.success("瀵煎叆鎴愬姛");
+ importDialogVisible.value = false;
+ getList();
+ } else {
+ ElMessage.error(response.message || "瀵煎叆澶辫触");
+ }
+ };
+
+ // 瀵煎叆澶辫触
+ const handleImportError = error => {
+ ElMessage.error("瀵煎叆澶辫触锛岃妫�鏌ユ枃浠舵牸寮忔槸鍚︽纭�");
+ };
+
+ // 纭瀵煎叆
+ const handleImportConfirm = () => {
+ if (importDialogRef.value) {
+ importDialogRef.value.submit();
+ }
+ };
+
+ // 涓嬭浇妯℃澘
+ const handleDownloadTemplate = () => {
+ proxy.download(
+ "/productionPlan/downloadTemplate",
+ {},
+ "鐢熶骇璁″垝瀵煎叆妯℃澘.xlsx"
+ );
+ };
+
+ // 鍏抽棴瀵煎叆寮圭獥
+ const handleImportClose = () => {
+ importDialogVisible.value = false;
+ };
+
+ // 鏂板
+ const handleAdd = () => {
+ operationType.value = "add";
+ Object.assign(form, {
+ applyNo: "",
+ customerName: "",
+ productName: "",
+ productSpec: "",
+ materialCode: "",
+ quantity: 0,
+ volume: 0,
+ length: 0,
+ width: 0,
+ height: 0,
+ startDate: "",
+ endDate: "",
+ strength: "",
+ remarkOne: "",
+ remarkTwo: "",
+ });
+ dialogVisible.value = true;
+ };
+
+ // 缂栬緫
+ const handleEdit = row => {
+ operationType.value = "edit";
+ Object.assign(form, {
+ id: row.id,
+ applyNo: row.applyNo || "",
+ customerName: row.customerName || "",
+ productName: row.productName || "",
+ productSpec: row.productSpec || "",
+ materialCode: row.materialCode || "",
+ quantity: row.quantity || 0,
+ volume: row.volume || 0,
+ length: row.length || 0,
+ width: row.width || 0,
+ height: row.height || 0,
+ startDate: row.startDate || "",
+ endDate: row.endDate || "",
+ strength: row.strength || "",
+ remarkOne: row.remarkOne || "",
+ remarkTwo: row.remarkTwo || "",
+ });
+ dialogVisible.value = true;
+ };
+
+ // 鍒犻櫎
+ const handleDelete = row => {
+ proxy.$modal
+ .confirm("纭鍒犻櫎璇ョ敓浜ц鍒掞紵", "鎻愮ず", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ productionPlanDelete([row.id])
+ .then(() => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .catch(() => {
+ proxy.$modal.msgError("鍒犻櫎澶辫触");
+ });
+ })
+ .catch(() => {});
+ };
+
+ // 鎻愪氦琛ㄥ崟
+ const handleSubmit = () => {
+ formRef.value.validate(valid => {
+ if (valid) {
+ const payload = { ...form };
+ if (operationType.value === "add") {
+ productionPlanAdd(payload)
+ .then(() => {
+ proxy.$modal.msgSuccess(
+ operationType.value === "add" ? "鏂板鎴愬姛" : "淇敼鎴愬姛"
+ );
+ dialogVisible.value = false;
+ getList();
+ })
+ .catch(() => {
+ proxy.$modal.msgError(
+ operationType.value === "add" ? "鏂板澶辫触" : "淇敼澶辫触"
+ );
+ });
+ }
+ if (operationType.value === "edit") {
+ productionPlanUpdate(payload)
+ .then(() => {
+ proxy.$modal.msgSuccess(
+ operationType.value === "add" ? "鏂板鎴愬姛" : "淇敼鎴愬姛"
+ );
+ dialogVisible.value = false;
+ getList();
+ })
+ .catch(() => {
+ proxy.$modal.msgError(
+ operationType.value === "add" ? "鏂板澶辫触" : "淇敼澶辫触"
+ );
+ });
+ }
+ }
+ });
};
onMounted(() => {
@@ -723,16 +1089,19 @@
border: none;
border-radius: 6px;
overflow: hidden;
+ box-shadow: 0 4px 16px rgba(102, 126, 234, 0.1);
.el-table__header-wrapper {
- background-color: #fafafa;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
th {
- background-color: #fafafa;
+ background: transparent;
font-weight: 600;
- color: #303133;
- border-bottom: 1px solid #ebeef5;
- padding: 14px 0;
+ color: #ffffff;
+ border-bottom: none;
+ padding: 16px 0;
+ font-size: 14px;
+ letter-spacing: 0.5px;
}
}
@@ -741,23 +1110,144 @@
transition: all 0.3s ease;
&:hover {
- background-color: #f5f7fa;
+ background: linear-gradient(
+ 90deg,
+ rgba(102, 126, 234, 0.05) 0%,
+ rgba(118, 75, 162, 0.05) 100%
+ );
+ transform: scale(1.002);
+ box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
}
td {
- border-bottom: 1px solid #ebeef5;
- padding: 12px 0;
+ border-bottom: 1px solid #f0f0f0;
+ padding: 14px 0;
+ color: #303133;
+ font-size: 13px;
}
}
tr.current-row {
- background-color: #ecf5ff;
+ background: linear-gradient(
+ 90deg,
+ rgba(102, 126, 234, 0.08) 0%,
+ rgba(118, 75, 162, 0.08) 100%
+ );
+ }
+
+ // 鏁板�煎瓧娈垫牱寮�
+ .quantity-cell,
+ .volume-cell,
+ .dimension-cell {
+ font-weight: 600;
+ color: #409eff;
+ font-family: "Courier New", monospace;
+ font-size: 14px;
+ text-shadow: 0 1px 2px rgba(64, 158, 255, 0.2);
+ }
+
+ // 瑙勬牸瀛楁鏍峰紡
+ .spec-cell {
+ color: #67c23a;
+ font-weight: 500;
+
+ padding: 4px 8px;
+ border-radius: 4px;
+ }
+
+ // 缂栫爜瀛楁鏍峰紡
+ .code-cell {
+ color: #e6a23c;
+ font-family: "Courier New", monospace;
+ font-weight: 500;
+ padding: 4px 8px;
+ border-radius: 4px;
+ }
+
+ // 鏃ユ湡瀛楁鏍峰紡
+ .date-cell {
+ color: #909399;
+ font-size: 12px;
+ font-style: italic;
+ }
+
+ // 鐘舵�佹爣绛炬牱寮�
+ .status-tag {
+ &.pending {
+ background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%);
+ color: #d63031;
+ padding: 4px 12px;
+ border-radius: 12px;
+ font-weight: 500;
+ box-shadow: 0 2px 4px rgba(253, 203, 110, 0.3);
+ }
+
+ &.processing {
+ background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
+ color: #ffffff;
+ padding: 4px 12px;
+ border-radius: 12px;
+ font-weight: 500;
+ box-shadow: 0 2px 4px rgba(9, 132, 227, 0.3);
+ }
+
+ &.completed {
+ background: linear-gradient(135deg, #55efc4 0%, #00b894 100%);
+ color: #ffffff;
+ padding: 4px 12px;
+ border-radius: 12px;
+ font-weight: 500;
+ box-shadow: 0 2px 4px rgba(0, 184, 148, 0.3);
+ }
}
}
.el-table__empty-block {
- padding: 40px 0;
+ padding: 60px 0;
+ background-color: #fafafa;
}
+ }
+
+ // 鎿嶄綔鎸夐挳鏍峰紡
+ :deep(.el-table .cell .el-button--text) {
+ padding: 6px 10px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+ font-weight: 500;
+
+ &:hover {
+ background-color: rgba(64, 158, 255, 0.1);
+ transform: translateY(-1px);
+ box-shadow: 0 2px 4px rgba(64, 158, 255, 0.2);
+ }
+
+ &:nth-of-type(1) {
+ color: #409eff;
+ background: linear-gradient(
+ 135deg,
+ rgba(64, 158, 255, 0.1) 0%,
+ rgba(64, 158, 255, 0.05) 100%
+ );
+ }
+
+ &:nth-of-type(2) {
+ color: #67c23a;
+ background: linear-gradient(
+ 135deg,
+ rgba(103, 194, 58, 0.1) 0%,
+ rgba(103, 194, 58, 0.05) 100%
+ );
+ }
+ }
+
+ // 淇℃伅灞曠ず鏍峰紡
+ .info-display {
+ border-radius: 6px;
+ color: #303133;
+ font-size: 14px;
+ min-height: 32px;
+ display: flex;
+ align-items: center;
}
.pagination-container {
@@ -891,9 +1381,9 @@
color: #909399;
margin-left: 4px;
}
- .search_form {
- :deep(.el-form-item) {
- margin-bottom: 0px !important;
- }
- }
+ // .search_form {
+ // :deep(.el-form-item) {
+ // margin-bottom: 0px !important;
+ // }
+ // }
</style>
diff --git a/src/views/productionPlan/summaryByProduct/index.vue b/src/views/productionPlan/summaryByProduct/index.vue
new file mode 100644
index 0000000..62b8010
--- /dev/null
+++ b/src/views/productionPlan/summaryByProduct/index.vue
@@ -0,0 +1,290 @@
+<template>
+ <div class="app-container">
+ <div class="table_list">
+ <PIMTable rowKey="materialCode"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ height="calc(100vh - 200px)"
+ :tableLoading="tableLoading"
+ :isSelection="false"
+ @pagination="pagination">
+ </PIMTable>
+ </div>
+ </div>
+</template>
+
+<script setup>
+ import { onMounted, ref, reactive } from "vue";
+ import { summaryByProductType } from "@/api/productionPlan/productionPlan.js";
+ import PIMTable from "../productionPlan/components/PIMTable.vue";
+
+ const tableColumn = ref([
+ {
+ label: "鐗╂枡缂栫爜",
+ prop: "materialCode",
+ className: "code-cell",
+ },
+ {
+ label: "浜у搧鍚嶇О",
+ prop: "productName",
+ dataType: "tag",
+ formatType: params => {
+ const typeMap = {
+ 鏉挎潗: "primary",
+ 鐮屽潡: "info",
+ };
+ return typeMap[params] || "info";
+ },
+ },
+ {
+ label: "浜у搧瑙勬牸",
+ prop: "productSpec",
+ className: "spec-cell",
+ },
+ {
+ label: "闀�",
+ prop: "length",
+ className: "dimension-cell",
+ },
+ {
+ label: "瀹�",
+ prop: "width",
+ className: "dimension-cell",
+ },
+ {
+ label: "楂�",
+ prop: "height",
+ className: "dimension-cell",
+ },
+ {
+ label: "鍧楁暟",
+ prop: "quantity",
+ className: "quantity-cell",
+ },
+ {
+ label: "鏂规暟",
+ prop: "volume",
+ className: "volume-cell",
+ },
+ ]);
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+ const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+ });
+
+ // 鎼滅储琛ㄥ崟
+ const searchForm = reactive({
+ productName: "",
+ productSpec: "",
+ });
+
+ // 鏌ヨ鍒楄〃
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ const handleQuery = () => {
+ page.current = 1;
+ getList();
+ };
+ const pagination = obj => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+ };
+
+ const getList = () => {
+ tableLoading.value = true;
+ // 鏋勯�犱竴涓柊鐨勫璞★紝涓嶅寘鍚玡ntryDate瀛楁
+ const params = { ...searchForm, ...page };
+ params.entryDate = undefined;
+ summaryByProductType(params)
+ .then(res => {
+ tableLoading.value = false;
+
+ tableData.value = res.data;
+ page.total = res.total;
+ })
+ .catch(() => {
+ tableLoading.value = false;
+ });
+ };
+
+ onMounted(() => {
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ .app-container {
+ padding: 24px;
+ background-color: #f0f2f5;
+ min-height: calc(100vh - 48px);
+ }
+
+ .search_form {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24px;
+ padding: 20px;
+ background-color: #ffffff;
+ border-radius: 6px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+ transition: all 0.3s ease;
+
+ &:hover {
+ box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
+ }
+ }
+
+ .table_list {
+ background-color: #ffffff;
+ border-radius: 6px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+ overflow: hidden;
+ height: calc(100vh - 150px);
+ }
+
+ :deep(.el-table) {
+ border: none;
+ border-radius: 6px;
+ overflow: hidden;
+ box-shadow: 0 4px 16px rgba(102, 126, 234, 0.1);
+
+ .el-table__header-wrapper {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+
+ th {
+ background: transparent;
+ font-weight: 600;
+ color: #ffffff;
+ border-bottom: none;
+ padding: 16px 0;
+ font-size: 14px;
+ letter-spacing: 0.5px;
+ }
+ }
+
+ .el-table__body-wrapper {
+ tr {
+ transition: all 0.3s ease;
+
+ &:hover {
+ background: linear-gradient(
+ 90deg,
+ rgba(102, 126, 234, 0.05) 0%,
+ rgba(118, 75, 162, 0.05) 100%
+ );
+ transform: scale(1.002);
+ box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
+ }
+
+ td {
+ border-bottom: 1px solid #f0f0f0;
+ padding: 14px 0;
+ color: #303133;
+ font-size: 13px;
+ }
+ }
+
+ tr.current-row {
+ background: linear-gradient(
+ 90deg,
+ rgba(102, 126, 234, 0.08) 0%,
+ rgba(118, 75, 162, 0.08) 100%
+ );
+ }
+
+ // 鏁板�煎瓧娈垫牱寮�
+ .quantity-cell,
+ .volume-cell,
+ .dimension-cell {
+ font-weight: 600;
+ color: #409eff;
+ font-family: "Courier New", monospace;
+ font-size: 14px;
+ text-shadow: 0 1px 2px rgba(64, 158, 255, 0.2);
+ }
+
+ // 瑙勬牸瀛楁鏍峰紡
+ .spec-cell {
+ color: #67c23a;
+ font-weight: 500;
+ padding: 4px 8px;
+ border-radius: 4px;
+ }
+
+ // 缂栫爜瀛楁鏍峰紡
+ .code-cell {
+ color: #e6a23c;
+ font-family: "Courier New", monospace;
+ font-weight: 500;
+ padding: 4px 8px;
+ border-radius: 4px;
+ }
+
+ // 鏃ユ湡瀛楁鏍峰紡
+ .date-cell {
+ color: #909399;
+ font-size: 12px;
+ font-style: italic;
+ }
+ }
+
+ .el-table__empty-block {
+ padding: 60px 0;
+ background-color: #fafafa;
+ }
+ }
+
+ .pagination-container {
+ display: flex;
+ justify-content: flex-end;
+ padding: 16px 20px;
+ background-color: #ffffff;
+ border-top: 1px solid #ebeef5;
+ border-radius: 0 0 12px 12px;
+ }
+
+ :deep(.el-button) {
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-1px);
+ }
+ }
+
+ @media (max-width: 768px) {
+ .app-container {
+ padding: 16px;
+ }
+
+ .search_form {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+
+ .el-form {
+ width: 100%;
+
+ .el-form-item {
+ width: 100%;
+ }
+ }
+
+ .el-button {
+ margin-right: 12px;
+ }
+ }
+
+ :deep(.el-table) {
+ th,
+ td {
+ padding: 10px 0;
+ font-size: 12px;
+ }
+ }
+ }
+</style>
--
Gitblit v1.9.3