From 28fc65c34d1642b007dc45b83782e23be58d718c Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期三, 08 七月 2026 16:43:58 +0800
Subject: [PATCH] 已进行排班并且人员已打卡的前提下,对应的班次配置不能编辑删除。
---
src/views/productionPlan/productionPlan/index.vue | 1375 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,375 insertions(+), 0 deletions(-)
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
new file mode 100644
index 0000000..1acb28f
--- /dev/null
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -0,0 +1,1375 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <el-form :model="searchForm"
+ ref="queryRef"
+ :inline="true">
+ <!-- 绠�鍖栫増鎼滅储鏉′欢 -->
+ <el-form-item label="涓荤敓浜ц鍒掑彿:"
+ prop="mpsNo">
+ <el-input v-model="searchForm.mpsNo"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="閿�鍞悎鍚屽彿:"
+ prop="salesContractNo">
+ <el-input v-model="searchForm.salesContractNo"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="闇�姹傛棩鏈熻寖鍥�:"
+ prop="dateRange">
+ <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 label="涓嬪彂鐘舵��:"
+ prop="status">
+ <el-select v-model="searchForm.status"
+ placeholder="璇烽�夋嫨鐘舵��"
+ clearable
+ filterable
+ style="width: 100px">
+ <el-option label="寰呬笅鍙�"
+ value="0" />
+ <el-option label="閮ㄥ垎涓嬪彂"
+ value="1" />
+ <el-option label="宸蹭笅鍙�"
+ value="2" />
+ </el-select>
+ </el-form-item>
+ <!-- 灞曞紑鐗堟悳绱㈡潯浠� -->
+ <el-form-item label="浜у搧鍚嶇О:"
+ prop="productName">
+ <el-input v-model="searchForm.productName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="handleQuery" />
+ </el-form-item>
+ <el-form-item label="瑙勬牸鍨嬪彿:"
+ prop="model">
+ <el-input v-model="searchForm.model"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 160px;"
+ @keyup.enter="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="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>
+ </div>
+ </div>
+ <div class="table_list">
+ <PIMTable rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ height="calc(100vh - 350px)"
+ :tableLoading="tableLoading"
+ :isSelection="true"
+ :selectable="isSelectable"
+ @selection-change="handleSelectionChange"
+ @pagination="pagination">
+ <template #qtyRequired="{ row }">
+ {{ row.qtyRequired || '-' }}<span style="color:rgba(12, 46, 40, 0.76)"> {{ row.unit || '鏂�' }}</span>
+ </template>
+ <template #salesContractNo="{ row }">
+ <el-button type="primary"
+ text
+ link
+ @click="showDetail(row)">{{ row.salesContractNo }}
+ </el-button>
+ </template>
+ </PIMTable>
+ </div>
+ <!-- 鍚堝苟涓嬪彂寮圭獥 -->
+ <el-dialog v-model="isShowNewModal"
+ destroy-on-close
+ title="鍚堝苟涓嬪彂"
+ width="600px">
+ <el-form :model="mergeForm"
+ label-width="120px">
+ <el-row :gutter="20">
+ <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>
+ <el-form-item label="瑙勬牸鍨嬪彿">
+ <div class="info-display">{{ mergeForm.model || '-' }}</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.totalAssignedQuantity"
+ :min="0"
+ :max="sumAssignedQuantity"
+ @change="onBlur"
+ style="width: 100%" />
+ </el-form-item>
+ <el-form-item label="鍒涘缓鏃堕棿">
+ <el-date-picker v-model="mergeCreateTimeDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ style="width: 100%" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button type="primary"
+ @click="handleMergeSubmit">纭畾涓嬪彂</el-button>
+ <el-button @click="isShowNewModal = false">鍙栨秷</el-button>
+ </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"
+ destroy-on-close
+ :title="operationType === 'add' ? '鏂板鐢熶骇璁″垝' : '缂栬緫鐢熶骇璁″垝'"
+ width="600px">
+ <el-form ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="120px">
+ <el-form-item label="涓荤敓浜ц鍒掑彿"
+ prop="mpsNo">
+ <el-input v-model="form.mpsNo"
+ disabled
+ placeholder="淇濆瓨鍚庤嚜鍔ㄧ敓鎴�" />
+ </el-form-item>
+ <el-form-item label="浜у搧鍚嶇О"
+ prop="productId">
+ <el-tree-select v-model="form.productId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ :data="productOptions"
+ :render-after-expand="false"
+ filterable
+ @change="handleProductChange"
+ style="width: 100%" />
+ </el-form-item>
+ <el-form-item label="瑙勬牸鍨嬪彿"
+ prop="productModelId">
+ <el-select v-model="form.productModelId"
+ @change="handleChangeSpecification"
+ filterable
+ style="width: 100%"
+ placeholder="璇烽�夋嫨">
+ <el-option v-for="item in specificationOptions"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鎵�闇�鏁伴噺"
+ prop="qtyRequired">
+ <el-input-number v-model="form.qtyRequired"
+ :min="0"
+ style="width: 100%"
+ placeholder="璇疯緭鍏ユ暟閲�" />
+ </el-form-item>
+ <el-form-item label="鍗曚綅"
+ prop="unit">
+ <el-input v-model="form.unit"
+ placeholder="璇疯緭鍏ュ崟浣�" />
+ </el-form-item>
+ <el-form-item label="闇�姹傛棩鏈�"
+ prop="requiredDate">
+ <el-date-picker v-model="form.requiredDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ placeholder="璇烽�夋嫨闇�姹傛棩鏈�" />
+ </el-form-item>
+ <el-form-item label="鎵胯鏃ユ湡"
+ prop="promisedDeliveryDate">
+ <el-date-picker v-model="form.promisedDeliveryDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ placeholder="璇烽�夋嫨鎵胯鏃ユ湡" />
+ </el-form-item>
+ <el-form-item label="鍒涘缓鏃堕棿"
+ prop="createTime">
+ <el-date-picker v-model="formCreateTimeDate"
+ type="date"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ placeholder="璇烽�夋嫨鍒涘缓鏃堕棿" />
+ </el-form-item>
+ <el-form-item label="澶囨敞"
+ prop="remark">
+ <el-input v-model="form.remark"
+ type="textarea"
+ placeholder="璇疯緭鍏ュ娉�" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button type="primary"
+ @click="handleSubmit">纭畾</el-button>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+ import {
+ reactive,
+ ref,
+ onMounted,
+ toRefs,
+ getCurrentInstance,
+ computed,
+ } from "vue";
+ import { useRouter } from "vue-router";
+ import dayjs from "dayjs";
+ import { ElMessage } from "element-plus";
+ import { ArrowUp, ArrowDown } from "@element-plus/icons-vue";
+ import { getToken } from "@/utils/auth";
+ import { useDict } from "@/utils/dict";
+ import {
+ productionPlanListPage,
+ productionPlanAdd,
+ productionPlanUpdate,
+ productionPlanDelete,
+ productionPlanCombine,
+ exportProductionPlan,
+ } from "@/api/productionPlan/productionPlan.js";
+ import { productTreeList, modelListPage } from "@/api/basicData/product.js";
+ import PIMTable from "./components/PIMTable.vue";
+ import ImportDialog from "@/components/Dialog/ImportDialog.vue";
+
+ const { proxy } = getCurrentInstance();
+ const router = useRouter();
+
+ const loadProdData = () => {
+ console.log("Mock loadProdData called");
+ return Promise.resolve({ code: 200, msg: "鍚屾鎴愬姛" });
+ };
+
+ // const productionPlanCombine = payload => {
+ // console.log("Mock productionPlanCombine called with:", payload);
+ // return Promise.resolve({ code: 200, msg: "鍚堝苟涓嬪彂鎴愬姛" });
+ // };
+
+ const tableColumn = ref([
+ {
+ label: "涓荤敓浜ц鍒掑彿",
+ prop: "mpsNo",
+ width: "150px",
+ },
+ {
+ label: "鏉ユ簮",
+ prop: "source",
+ width: "150px",
+ dataType: "tag",
+ formatType: params => {
+ return params == "閿�鍞�" ? "primary" : "info";
+ },
+ formatData: params => {
+ return params == "閿�鍞�" ? "閿�鍞�" : "鍐呴儴";
+ },
+ },
+ {
+ label: "閿�鍞悎鍚屽彿",
+ prop: "salesContractNo",
+ width: "200px",
+ dataType: "slot",
+ slot: "salesContractNo",
+ },
+
+ {
+ label: "浜у搧鍚嶇О",
+ prop: "productName",
+ width: "200px",
+ dataType: "tag",
+ formatType: params => {
+ return "primary";
+ },
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "model",
+ width: "150px",
+ className: "spec-cell",
+ },
+ {
+ label: "鍗曚綅",
+ prop: "unit",
+ width: "100px",
+ },
+ {
+ label: "鎵�闇�鏁伴噺",
+ prop: "qtyRequired",
+ width: "150px",
+ dataType: "slot",
+ slot: "qtyRequired",
+ className: "volume-cell",
+ },
+ {
+ label: "涓嬪彂鐘舵��",
+ prop: "status",
+ width: "120px",
+ className: "status-cell",
+ dataType: "tag",
+ formatType: params => {
+ const typeMap = {
+ 0: "warning",
+ 1: "primary",
+ 2: "info",
+ };
+ return typeMap[params] || "info";
+ },
+ formatData: cell => {
+ const statusMap = {
+ 0: "寰呬笅鍙�",
+ 1: "閮ㄥ垎涓嬪彂",
+ 2: "宸蹭笅鍙�",
+ };
+ return statusMap[cell] || "";
+ },
+ },
+ {
+ label: "宸蹭笅鍙戞暟閲�",
+ prop: "quantityIssued",
+ width: "120px",
+ className: "spec-cell",
+ // formatData: (cell, row) => (cell ? `${cell}${row.unit || "鏂�"}` : 0),
+ },
+ {
+ label: "闇�姹傛棩鏈�",
+ prop: "requiredDate",
+ width: "160px",
+ className: "date-cell",
+ formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+ },
+ {
+ label: "鎵胯鏃ユ湡",
+ prop: "promisedDeliveryDate",
+ width: "160px",
+ className: "date-cell",
+ formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+ },
+
+ {
+ label: "瀹㈡埛鍚嶇О",
+ prop: "customerName",
+ width: "150px",
+ },
+ {
+ label: "椤圭洰鍚嶇О",
+ prop: "projectName",
+ width: "150px",
+ },
+ {
+ label: "澶囨敞",
+ width: "150px",
+ prop: "remark",
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: "right",
+ width: 250,
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "primary",
+ link: true,
+ showHide: row => {
+ return row.status == 0 && row.source != "閿�鍞�";
+ },
+ clickFun: row => {
+ handleEdit(row);
+ },
+ },
+ {
+ name: "涓嬪彂",
+ type: "text",
+ showHide: row => {
+ return row.status != 2;
+ },
+ clickFun: row => {
+ mergeForm.productName = row.productName || "";
+ mergeForm.model = row.model || "";
+ mergeForm.totalAssignedQuantity =
+ Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
+ mergeForm.planCompleteTime = row.requiredDate || "";
+ mergeForm.productId = row.productId || "";
+ mergeForm.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
+ mergeForm.ids = [row.id];
+ sumAssignedQuantity.value =
+ Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
+ isShowNewModal.value = true;
+ },
+ },
+ {
+ name: "鍒犻櫎",
+ type: "danger",
+ link: true,
+ showHide: row => {
+ return row.status == 0 && row.source != "閿�鍞�";
+ },
+ clickFun: row => {
+ handleDelete(row);
+ },
+ },
+ ],
+ },
+ ]);
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+ const page = reactive({
+ current: 1,
+ size: 100,
+ total: 0,
+ });
+ const selectedRows = ref([]);
+
+ // 浜у搧绫诲埆姹囨�荤粺璁℃暟鎹�
+ const categorySummary = ref([]);
+ // 浜у搧绫诲埆姹囨�诲脊绐楁帶鍒�
+ const showCategorySummaryDialog = ref(false);
+
+ // 鍚堝苟涓嬪彂寮圭獥鎺у埗
+ const isShowNewModal = ref(false);
+ // 鍚堝苟涓嬪彂琛ㄥ崟鏁版嵁
+ const mergeForm = reactive({
+ productName: "",
+ model: "",
+ totalAssignedQuantity: 0,
+ planCompleteTime: "",
+ productId: "",
+ createTime: "",
+ });
+ const mergeCreateTimeDate = computed({
+ get: () =>
+ mergeForm.createTime ? String(mergeForm.createTime).split(" ")[0] : "",
+ set: value => {
+ mergeForm.createTime = value
+ ? `${value} ${dayjs().format("HH:mm:ss")}`
+ : "";
+ },
+ });
+
+ // 瀵煎叆鐩稿叧
+ 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 productOptions = ref([]);
+ const specificationOptions = ref([]);
+ const queryRef = ref(null);
+ const formRef = ref(null);
+ const form = reactive({
+ id: undefined,
+ mpsNo: "",
+ productId: undefined,
+ productModelId: undefined,
+ productName: "",
+ model: "",
+ qtyRequired: 0,
+ unit: "鏂�",
+ requiredDate: "",
+ promisedDeliveryDate: "",
+ remark: "",
+ createTime: "",
+ });
+ const formCreateTimeDate = computed({
+ get: () => (form.createTime ? String(form.createTime).split(" ")[0] : ""),
+ set: value => {
+ form.createTime = value ? `${value} ${dayjs().format("HH:mm:ss")}` : "";
+ },
+ });
+ const rules = reactive({
+ productId: [{ required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" }],
+ productModelId: [
+ { required: true, message: "璇烽�夋嫨瑙勬牸鍨嬪彿", trigger: "change" },
+ ],
+ qtyRequired: [{ required: true, message: "璇疯緭鍏ユ暟閲�", trigger: "blur" }],
+ requiredDate: [
+ { required: true, message: "璇烽�夋嫨闇�姹傛棩鏈�", trigger: "change" },
+ ],
+ });
+
+ // 澶勭悊杩借釜杩涘害鎸夐挳鐐瑰嚮
+ const handleTrackProgress = row => {
+ // 璺宠浆鍒拌拷韪繘搴﹂〉闈�
+ router.push({
+ path: "/productionPlan/trackProgress",
+ query: {
+ id: row.id,
+ productName: row.productName,
+ model: row.model,
+ },
+ });
+ };
+ const onBlur = value => {
+ // 闄愬埗鍥涗綅灏忔暟
+ mergeForm.totalAssignedQuantity = Number(value.toFixed(4));
+ };
+
+ const fetchProductOptions = () => {
+ return productTreeList().then(res => {
+ productOptions.value = convertIdToValue(res || []);
+ });
+ };
+
+ const convertIdToValue = data => {
+ return data.map(item => {
+ const newItem = {
+ value: item.id,
+ label: item.label,
+ };
+ if (item.children && item.children.length > 0) {
+ newItem.children = convertIdToValue(item.children);
+ }
+ return newItem;
+ });
+ };
+
+ const handleProductChange = value => {
+ form.productModelId = undefined;
+ form.model = undefined;
+ // 鏌ユ壘閫変腑鐨勪骇鍝佸悕绉�
+ const findProductName = (options, val) => {
+ for (const option of options) {
+ if (option.value === val) {
+ return option.label;
+ }
+ if (option.children) {
+ const found = findProductName(option.children, val);
+ if (found) {
+ return found;
+ }
+ }
+ }
+ return "";
+ };
+ form.productName = findProductName(productOptions.value, value);
+ fetchSpecificationOptions(value);
+ };
+
+ const fetchSpecificationOptions = productId => {
+ specificationOptions.value = [];
+ if (productId) {
+ modelListPage({ id: productId, size: 1000, current: 1 }).then(res => {
+ specificationOptions.value = res.records || [];
+ });
+ }
+ };
+
+ const handleChangeSpecification = value => {
+ form.model = undefined;
+ form.unit = "";
+ const selectedModel = specificationOptions.value.find(
+ item => item.id === value
+ );
+ if (selectedModel) {
+ form.model = selectedModel.model;
+ form.unit = selectedModel.unit || "鏂�";
+ }
+ };
+
+ const data = reactive({
+ searchForm: {
+ mpsNo: "",
+ salesContractNo: "",
+ productName: "",
+ model: "",
+ status: "",
+ dateRange: [],
+ },
+ searchFormExpanded: false,
+ });
+ const { searchForm, searchFormExpanded } = toRefs(data);
+
+ // 鍒囨崲鎼滅储琛ㄥ崟灞曞紑/鏀惰捣鐘舵��
+ const toggleSearchForm = () => {
+ data.searchFormExpanded = !data.searchFormExpanded;
+ };
+
+ // 鏌ヨ鍒楄〃
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ const handleQuery = () => {
+ page.current = 1;
+ getList();
+ };
+
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ const handleReset = () => {
+ if (proxy.resetForm) {
+ proxy.resetForm("queryRef");
+ }
+ Object.assign(searchForm.value, {
+ mpsNo: "",
+ salesContractNo: "",
+ productName: "",
+ model: "",
+ status: "",
+ dateRange: [],
+ });
+ page.current = 1;
+ getList();
+ };
+ const pagination = obj => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+ };
+ // 璁$畻浜у搧绫诲埆姹囨�荤粺璁�
+ const calculateCategorySummary = () => {
+ const summary = {};
+
+ // 閬嶅巻琛ㄦ牸鏁版嵁锛屾寜浜у搧绫诲埆姹囨��
+ tableData.value.forEach(row => {
+ const category = row.productName || "鏈煡浜у搧";
+ if (!summary[category]) {
+ summary[category] = {
+ materialCode: category,
+ totalAssignedQuantity: 0,
+ };
+ }
+ summary[category].totalAssignedQuantity += Number(
+ (Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0)).toFixed(
+ 4
+ )
+ );
+ });
+
+ // 杞崲涓烘暟缁勬牸寮�
+ categorySummary.value = Object.values(summary);
+ };
+
+ const getList = () => {
+ tableLoading.value = true;
+ // 鏋勯�犳悳绱㈠弬鏁�
+ const params = { ...searchForm.value, ...page };
+ params.requiredDateStart =
+ params.dateRange && params.dateRange.length > 0 ? params.dateRange[0] : "";
+ params.requiredDateEnd =
+ params.dateRange && params.dateRange.length > 1 ? params.dateRange[1] : "";
+ delete params.dateRange;
+ productionPlanListPage(params)
+ .then(res => {
+ tableLoading.value = false;
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ // 璁$畻浜у搧绫诲埆姹囨�荤粺璁�
+ calculateCategorySummary();
+ })
+ .catch(() => {
+ tableLoading.value = false;
+ });
+ };
+
+ // 閫変腑鐨勮鏍煎瀷鍙稩D
+ const selectedProductModelId = ref("");
+
+ // 琛ㄦ牸閫夋嫨鏁版嵁
+ const handleSelectionChange = selection => {
+ selectedRows.value = selection;
+ // 濡傛灉鏈夐�変腑鐨勮锛岃褰曠涓�涓�変腑琛岀殑瑙勬牸鍨嬪彿ID
+ if (selection.length > 0) {
+ selectedProductModelId.value = selection[0].productModelId;
+ } else {
+ // 濡傛灉娌℃湁閫変腑鐨勮锛屾竻绌鸿鏍煎瀷鍙稩D
+ selectedProductModelId.value = "";
+ }
+ };
+
+ // 鍒ゆ柇琛屾槸鍚﹀彲閫夋嫨
+ const isSelectable = row => {
+ // 濡傛灉鏄凡涓嬪彂鐘舵�侊紝绂佹鍕鹃��
+ if (row.status == 2) {
+ return false;
+ }
+ // 璁$畻鍓╀綑鏁伴噺
+ const remainingQty = (row.qtyRequired || 0) - (row.quantityIssued || 0);
+ // 濡傛灉鍓╀綑鏁伴噺灏忎簬绛変簬0锛岀姝㈤�夋嫨
+ if (remainingQty <= 0) {
+ return false;
+ }
+ // 濡傛灉娌℃湁閫変腑鐨勮锛屾墍鏈夎閮藉彲閫夋嫨
+ if (!selectedProductModelId.value) {
+ return true;
+ }
+ // 濡傛灉鏈夐�変腑鐨勮锛屽彧鏈夎鏍煎瀷鍙稩D鐩稿悓鐨勮鎵嶅彲閫夋嫨
+ return row.productModelId === selectedProductModelId.value;
+ };
+ // 鎷夊彇鏁版嵁鎸夐挳鎿嶄綔
+ const loadProdDataLoading = ref(false);
+ const sumAssignedQuantity = ref(0);
+
+ // 澶勭悊鍚堝苟涓嬪彂鎸夐挳鐐瑰嚮
+ const handleMerge = () => {
+ if (selectedRows.value.length === 0) {
+ ElMessage.warning("璇烽�夋嫨瑕佸悎骞朵笅鍙戠殑鐢熶骇璁″垝");
+ return;
+ }
+ console.log(selectedRows.value);
+ const firstRow = selectedRows.value[0];
+ const productName = firstRow.productName || "";
+
+ // 璁$畻鎬诲埗閫犳暟閲� (榛樿qtyRequired鐨勫拰)
+ const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => {
+ return sum + Number(row.qtyRequired || 0) - Number(row.quantityIssued || 0);
+ }, 0);
+ sumAssignedQuantity.value = totalAssignedQuantity;
+ console.log(totalAssignedQuantity);
+ // 璁剧疆琛ㄥ崟鏁版嵁
+ mergeForm.productName = productName;
+ mergeForm.model = firstRow.model || "";
+ mergeForm.totalAssignedQuantity = totalAssignedQuantity;
+ mergeForm.planCompleteTime = firstRow.requiredDate || "";
+ mergeForm.productId = firstRow.productId || "";
+ mergeForm.createTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
+ mergeForm.ids = selectedRows.value.map(row => row.id);
+
+ // 鎵撳紑寮圭獥
+ isShowNewModal.value = true;
+ };
+ const showDetail = row => {
+ router.push({
+ path: "/salesManagement/salesLedger",
+ query: {
+ salesContractNo: row.salesContractNo,
+ },
+ });
+ };
+
+ // 澶勭悊鍚堝苟涓嬪彂鎻愪氦
+ const handleMergeSubmit = () => {
+ if (mergeForm.totalAssignedQuantity === 0) {
+ ElMessage.warning("璇疯緭鍏ョ敓浜ф暟閲�");
+ return;
+ }
+ console.log(sumAssignedQuantity.value, "sumAssignedQuantity");
+
+ // 楠岃瘉totalAssignedQuantity涓嶈兘澶т簬鎬绘柟鏁�
+ if (mergeForm.totalAssignedQuantity > sumAssignedQuantity.value) {
+ ElMessage.error("鐢熶骇鏁伴噺涓嶈兘澶т簬褰撳墠璁$畻鐨勬�诲��");
+ return;
+ }
+
+ console.log(mergeForm, "mergeForm");
+ const payload = {
+ ...mergeForm,
+ };
+ productionPlanCombine(payload)
+ .then(res => {
+ if (res.code === 200) {
+ ElMessage.success("涓嬪彂鎴愬姛");
+ getList();
+ isShowNewModal.value = false;
+ // 鍙互閫夋嫨鍒锋柊鍒楄〃鎴栧叾浠栨搷浣�
+ getList();
+ } 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.msg || "瀵煎叆澶辫触");
+ }
+ };
+
+ // 瀵煎叆澶辫触
+ 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, {
+ id: undefined,
+ mpsNo: "",
+ productName: "",
+ productId: undefined,
+ productModelId: undefined,
+ model: "",
+ qtyRequired: 0,
+ unit: "鏂�",
+ requiredDate: "",
+ promisedDeliveryDate: "",
+ remark: "",
+ createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ });
+ dialogVisible.value = true;
+ fetchProductOptions();
+ };
+
+ // 缂栬緫
+ const handleEdit = row => {
+ operationType.value = "edit";
+ Object.assign(form, {
+ id: row.id,
+ mpsNo: row.mpsNo || "",
+ productName: row.productName || "",
+ productId: row.productId || undefined,
+ productModelId: row.productModelId || undefined,
+ model: row.model || "",
+ qtyRequired: row.qtyRequired || 0,
+ unit: row.unit || "鏂�",
+ requiredDate: row.requiredDate || "",
+ promisedDeliveryDate: row.promisedDeliveryDate || "",
+ remark: row.remark || "",
+ createTime: row.createTime || "",
+ });
+ dialogVisible.value = true;
+ fetchProductOptions();
+ fetchSpecificationOptions(row.productId);
+ };
+
+ // 鍒犻櫎
+ 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) {
+ if (form.qtyRequired === 0) {
+ proxy.$modal.msgError("鏁伴噺涓嶈兘涓�0");
+ return;
+ }
+ const payload = { ...form };
+ if (operationType.value === "add") {
+ payload.id = null;
+ productionPlanAdd(payload)
+ .then(() => {
+ proxy.$modal.msgSuccess("鏂板鎴愬姛");
+ dialogVisible.value = false;
+ getList();
+ })
+ .catch(() => {
+ proxy.$modal.msgError("鏂板澶辫触");
+ });
+ }
+ if (operationType.value === "edit") {
+ productionPlanUpdate(payload)
+ .then(() => {
+ proxy.$modal.msgSuccess("淇敼鎴愬姛");
+ dialogVisible.value = false;
+ getList();
+ })
+ .catch(() => {
+ proxy.$modal.msgError("淇敼澶辫触");
+ });
+ }
+ }
+ });
+ };
+
+ onMounted(() => {
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ .app-container {
+ padding: 24px;
+ background-color: #f0f2f5;
+ min-height: calc(100vh - 48px);
+ }
+
+ .search_form {
+ // 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);
+ }
+ }
+
+ .search-header {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ // margin-bottom: 5px;
+ // padding-bottom: 5px;
+ position: relative;
+ bottom: 35px;
+ // border-bottom: 1px solid #ebeef5;
+ }
+
+ .search-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .search-header .el-button {
+ color: #606266;
+ transition: all 0.3s ease;
+ }
+
+ .search-header .el-button:hover {
+ color: #409eff;
+ }
+
+ .search-header .el-icon {
+ margin-right: 4px;
+ }
+
+ .table_list {
+ // margin-bottom: 24px;
+ background-color: #ffffff;
+ border-radius: 6px;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+ overflow: hidden;
+ height: calc(100vh - 250px);
+ margin-top: 0px !important;
+ }
+
+ :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;
+ 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;
+ }
+ }
+
+ tr.current-row {
+ background: linear-gradient(
+ 90deg,
+ rgba(102, 126, 234, 0.08) 0%,
+ rgba(118, 75, 162, 0.08) 100%
+ );
+ }
+
+ // 鏁板�煎瓧娈垫牱寮�
+ .volume-cell,
+ .dimension-cell {
+ font-weight: 600;
+ color: #409eff;
+ font-family: "Courier New", monospace;
+ 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-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: 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;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ }
+
+ .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);
+ }
+ }
+
+ :deep(.el-dialog) {
+ border-radius: 6px;
+ overflow: hidden;
+
+ .el-dialog__header {
+ background-color: #fafafa;
+ border-bottom: 1px solid #ebeef5;
+ padding: 20px 24px;
+
+ .el-dialog__title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+ }
+
+ .el-dialog__body {
+ padding: 24px;
+ }
+
+ .el-dialog__footer {
+ padding: 16px 24px;
+ border-top: 1px solid #ebeef5;
+ background-color: #fafafa;
+ }
+ }
+
+ :deep(.el-form) {
+ .el-form-item {
+ margin-bottom: 20px;
+
+ .el-form-item__label {
+ font-weight: 500;
+ color: #303133;
+ }
+
+ .el-input,
+ .el-select,
+ .el-date-picker,
+ .el-input-number {
+ width: 100%;
+
+ // .el-input__inner {
+ // border-radius: 6px;
+ // border: 1px solid #dcdfe6;
+ // transition: all 0.3s ease;
+
+ // &:focus {
+ // border-color: #409eff;
+ // box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+ // }
+ // }
+ }
+ }
+ }
+
+ :deep(.el-tag) {
+ border-radius: 4px;
+ padding: 2px 8px;
+ font-size: 12px;
+ }
+
+ @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%;
+ }
+ }
+
+ > div {
+ width: 100%;
+ display: flex;
+ gap: 12px;
+
+ .el-button {
+ flex: 1;
+ }
+ }
+ }
+
+ :deep(.el-table) {
+ th,
+ td {
+ padding: 10px 0;
+ font-size: 12px;
+ }
+ }
+
+ :deep(.el-dialog) {
+ width: 90% !important;
+ margin: 20px auto !important;
+ }
+ }
+ .consumption-value {
+ font-weight: bold;
+ color: #409eff;
+ }
+
+ .consumption-unit {
+ font-size: 12px;
+ color: #909399;
+ margin-left: 4px;
+ }
+ // .search_form {
+ // :deep(.el-form-item) {
+ // margin-bottom: 0px !important;
+ // }
+ // }
+ :deep(.el-table .el-table__body-wrapper tr td) {
+ background-color: #fff;
+ }
+</style>
--
Gitblit v1.9.3