From 8a72d17f6cf36376017f51a8039a4ffc90bff885 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 09 三月 2026 17:54:54 +0800
Subject: [PATCH] 主生产计划页面部分
---
src/views/productionPlan/productionPlan/components/PIMTable.vue | 462 +++++++++++++++++++++++++
src/views/productionPlan/productionPlan/index.vue | 576 ++++++++++++++++++++++++++++++++
vite.config.js | 2
3 files changed, 1,039 insertions(+), 1 deletions(-)
diff --git a/src/views/productionPlan/productionPlan/components/PIMTable.vue b/src/views/productionPlan/productionPlan/components/PIMTable.vue
new file mode 100644
index 0000000..c0f7616
--- /dev/null
+++ b/src/views/productionPlan/productionPlan/components/PIMTable.vue
@@ -0,0 +1,462 @@
+<template>
+ <el-table ref="multipleTable"
+ v-loading="tableLoading"
+ :border="border"
+ :data="tableData"
+ :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+ :height="height"
+ :highlight-current-row="highlightCurrentRow"
+ :row-class-name="rowClassName"
+ :row-style="rowStyle"
+ :row-key="rowKey"
+ :style="tableStyle"
+ tooltip-effect="dark"
+ :expand-row-keys="expandRowKeys"
+ :show-summary="isShowSummary"
+ :summary-method="summaryMethod"
+ @row-click="rowClick"
+ @current-change="currentChange"
+ @selection-change="handleSelectionChange"
+ @expand-change="expandChange"
+ @select-all="handleSelectAll"
+ class="lims-table">
+ <el-table-column align="center"
+ type="selection"
+ width="55"
+ v-if="isSelection"
+ :selectable="selectable" />
+ <el-table-column align="center"
+ label="搴忓彿"
+ type="index"
+ width="60" />
+ <el-table-column v-for="(item, index) in column"
+ :key="index"
+ :column-key="item.columnKey"
+ :filter-method="item.filterHandler"
+ :filter-multiple="item.filterMultiple"
+ :filtered-value="item.filteredValue"
+ :filters="item.filters"
+ :fixed="item.fixed"
+ :label="item.label"
+ :prop="item.prop"
+ :show-overflow-tooltip="item.dataType !== 'action' && item.dataType !== 'slot'"
+ :align="item.align"
+ :sortable="!!item.sortable"
+ :type="item.type"
+ :width="item.width">
+ <template #header="scope">
+ <div class="pim-table-header-cell">
+ <div class="pim-table-header-title">
+ {{ item.label }}
+ </div>
+ <div v-if="item.headerSlot"
+ class="pim-table-header-extra">
+ <slot :name="item.headerSlot"
+ :column="scope.column" />
+ </div>
+ </div>
+ </template>
+ <template v-if="item.hasOwnProperty('colunmTemplate')"
+ #[item.colunmTemplate]="scope">
+ <slot v-if="item.theadSlot"
+ :name="item.theadSlot"
+ :index="scope.$index"
+ :row="scope.row" />
+ </template>
+ <template #default="scope">
+ <!-- 鎻掓Ы -->
+ <div v-if="item.dataType == 'slot'">
+ <slot v-if="item.slot"
+ :index="scope.$index"
+ :name="item.slot"
+ :row="scope.row" />
+ </div>
+ <!-- 杩涘害鏉� -->
+ <div v-else-if="item.dataType == 'progress'">
+ <el-progress :percentage="Number(scope.row[item.prop])" />
+ </div>
+ <!-- 鍥剧墖 -->
+ <div v-else-if="item.dataType == 'image'">
+ <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'">
+ <el-tag v-if="
+ typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
+ 'string'
+ "
+ :title="formatters(scope.row[item.prop], item.formatData)"
+ :type="formatType(scope.row[item.prop], item.formatType)">
+ {{ formatters(scope.row[item.prop], item.formatData) }}
+ </el-tag>
+ <el-tag v-for="(tag, index) in dataTypeFn(
+ scope.row[item.prop],
+ item.formatData
+ )"
+ v-else-if="
+ typeof dataTypeFn(scope.row[item.prop], item.formatData) ===
+ 'object'
+ "
+ :key="index"
+ :title="formatters(scope.row[item.prop], item.formatData)"
+ :type="formatType(tag, item.formatType)">
+ {{ item.tagGroup ? tag[item.tagGroup.label] ?? tag : tag }}
+ </el-tag>
+ <el-tag v-else
+ :title="formatters(scope.row[item.prop], item.formatData)"
+ :type="formatType(scope.row[item.prop], item.formatType)">
+ {{ formatters(scope.row[item.prop], item.formatData) }}
+ </el-tag>
+ </div>
+ <!-- 鎸夐挳 -->
+ <div v-else-if="item.dataType == 'action'"
+ @click.stop>
+ <template v-for="(o, key) in item.operation"
+ :key="key">
+ <el-button v-show="o.type != 'upload'"
+ v-if="o.showHide ? o.showHide(scope.row) : true"
+ :disabled="o.disabled ? o.disabled(scope.row) : false"
+ :plain="o.plain"
+ type="primary"
+ :style="{
+ color:
+ o.name === '鍒犻櫎' || o.name === 'delete'
+ ? '#f56c6c'
+ : o.color,
+ }"
+ link
+ @click.stop="o.clickFun(scope.row)"
+ :key="key">
+ {{ o.name }}
+ </el-button>
+ <el-upload :action="
+ javaApi +
+ o.url +
+ '?id=' +
+ (o.uploadIdFun ? o.uploadIdFun(scope.row) : scope.row.id)
+ "
+ ref="uploadRef"
+ :multiple="o.multiple ? o.multiple : false"
+ :limit="1"
+ :disabled="o.disabled ? o.disabled(scope.row) : false"
+ :accept="
+ o.accept
+ ? o.accept
+ : '.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'
+ "
+ v-if="o.type == 'upload'"
+ style="display: inline-block; width: 50px"
+ v-show="o.showHide ? o.showHide(scope.row) : true"
+ :headers="uploadHeader"
+ :before-upload="(file) => beforeUpload(file, scope.$index)"
+ :on-change="
+ (file, fileList) => handleChange(file, fileList, scope.$index)
+ "
+ :on-error="
+ (error, file, fileList) =>
+ onError(error, file, fileList, scope.$index)
+ "
+ :on-success="
+ (response, file, fileList) =>
+ handleSuccessUp(response, file, fileList, scope.$index)
+ "
+ :on-exceed="onExceed"
+ :show-file-list="false">
+ <el-button link
+ type="primary"
+ :disabled="o.disabled ? o.disabled(scope.row) : false">{{ o.name }}</el-button>
+ </el-upload>
+ </template>
+ </div>
+ <!-- 鍙偣鍑荤殑鏂囧瓧 -->
+ <div v-else-if="item.dataType == 'link'"
+ class="cell link"
+ style="width: 100%"
+ @click="goLink(scope.row, item.linkMethod)">
+ <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
+ </div>
+ <!-- 榛樿绾睍绀烘暟鎹� -->
+ <div v-else
+ class="cell"
+ style="width: 100%">
+ <span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
+ <span v-else>{{
+ formatters(scope.row[item.prop], item.formatData)
+ }}</span>
+ </div>
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination v-if="isShowPagination"
+ :total="page.total"
+ :layout="page.layout"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationSearch" />
+</template>
+
+<script setup>
+ import pagination from "../../../../components/PIMTable/Pagination.vue";
+ import { ref, inject, getCurrentInstance } from "vue";
+ import { ElMessage } from "element-plus";
+
+ // 鑾峰彇鍏ㄥ眬鐨� uploadHeader
+ const { proxy } = getCurrentInstance();
+ const uploadHeader = proxy.uploadHeader;
+ const javaApi = proxy.javaApi;
+
+ const emit = defineEmits([
+ "pagination",
+ "expand-change",
+ "selection-change",
+ "row-click",
+ ]);
+
+ // Filters
+ const typeFn = (val, row) => {
+ return typeof val === "function" ? val(row) : val;
+ };
+
+ const formatters = (val, format) => {
+ return typeof format === "function" ? format(val) : val;
+ };
+
+ // Props锛堜娇鐢� defineProps 鐨勯潪 TS 褰㈠紡锛�
+ const props = defineProps({
+ tableLoading: {
+ type: Boolean,
+ default: false,
+ },
+ height: {
+ type: [Number, String],
+ default: "calc(100vh - 22em)",
+ },
+ expandRowKeys: {
+ type: Array,
+ default: () => [],
+ },
+ summaryMethod: {
+ type: Function,
+ default: () => {},
+ },
+ rowClick: {
+ type: Function,
+ default: () => {},
+ },
+ currentChange: {
+ type: Function,
+ default: () => {},
+ },
+ border: {
+ type: Boolean,
+ default: true,
+ },
+ isSelection: {
+ type: Boolean,
+ default: false,
+ },
+ selectable: {
+ type: Function,
+ default: () => true,
+ },
+ isShowPagination: {
+ type: Boolean,
+ default: true,
+ },
+ isShowSummary: {
+ type: Boolean,
+ default: false,
+ },
+ highlightCurrentRow: {
+ type: Boolean,
+ default: false,
+ },
+ headerCellStyle: {
+ type: Object,
+ default: () => ({}),
+ },
+ column: {
+ type: Array,
+ default: () => [],
+ },
+ rowClassName: {
+ type: Function,
+ default: () => "",
+ },
+ rowStyle: {
+ type: [Object, Function],
+ default: () => ({}),
+ },
+ tableData: {
+ type: Array,
+ default: () => [],
+ },
+ rowKey: {
+ type: String,
+ default: "id",
+ },
+ page: {
+ type: Object,
+ default: () => ({
+ total: 0,
+ current: 0,
+ size: 10,
+ layout: "total, sizes, prev, pager, next, jumper",
+ }),
+ },
+ total: {
+ type: Number,
+ default: 0,
+ },
+ tableStyle: {
+ type: [String, Object],
+ default: () => ({ width: "100%" }),
+ },
+ });
+
+ // Data
+ const multipleTable = ref(null);
+ const uploadRefs = ref([]);
+ const currentFiles = ref({});
+ const uploadKeys = ref({});
+
+ const indexMethod = index => {
+ return (props.page.current - 1) * props.page.size + index + 1;
+ };
+
+ // 鐐瑰嚮 link 浜嬩欢
+ const goLink = (row, linkMethod) => {
+ if (!linkMethod) {
+ return ElMessage.warning("璇烽厤缃� link 浜嬩欢");
+ }
+ const parentMethod = getParentMethod(linkMethod);
+ if (typeof parentMethod === "function") {
+ parentMethod(row);
+ } else {
+ console.warn(`鐖剁粍浠朵腑鏈壘鍒版柟娉�: ${linkMethod}`);
+ }
+ };
+
+ // 鑾峰彇鐖剁粍浠舵柟娉曪紙绀轰緥瀹炵幇锛�
+ const getParentMethod = methodName => {
+ const parentMethods = inject("parentMethods", {});
+ return parentMethods[methodName];
+ };
+
+ const dataTypeFn = (val, format) => {
+ if (typeof format === "function") {
+ return format(val);
+ } else return val;
+ };
+
+ const formatType = (val, format) => {
+ if (typeof format === "function") {
+ return format(val);
+ } else return "";
+ };
+
+ // 鏂囦欢鍙樺寲澶勭悊
+ const handleChange = (file, fileList, index) => {
+ if (fileList.length > 1) {
+ const earliestFile = fileList[0];
+ uploadRefs.value[index]?.handleRemove(earliestFile);
+ }
+ currentFiles.value[index] = file;
+ };
+
+ // 鏂囦欢涓婁紶鍓嶆牎楠�
+ const beforeUpload = (rawFile, index) => {
+ currentFiles.value[index] = {};
+ if (rawfile.size > 1024 * 1024 * 10 * 10) {
+ ElMessage.error("涓婁紶鏂囦欢涓嶈秴杩�10M");
+ return false;
+ }
+ return true;
+ };
+
+ // 涓婁紶鎴愬姛
+ const handleSuccessUp = (response, file, fileList, index) => {
+ if (response.code == 200) {
+ if (uploadRefs[index]) {
+ uploadRefs[index].clearFiles();
+ }
+ currentFiles[index] = file;
+ ElMessage.success("涓婁紶鎴愬姛");
+ resetUploadComponent(index);
+ } else {
+ ElMessage.error(response.message);
+ }
+ };
+
+ const resetUploadComponent = index => {
+ uploadKeys[index] = Date.now();
+ };
+
+ // 涓婁紶澶辫触
+ const onError = (error, file, fileList, index) => {
+ ElMessage.error("鏂囦欢涓婁紶澶辫触锛岃閲嶈瘯");
+ if (uploadRefs.value[index]) {
+ uploadRefs.value[index].clearFiles();
+ }
+ };
+
+ // 鏂囦欢鏁伴噺瓒呴檺鎻愮ず
+ const onExceed = () => {
+ ElMessage.warning("瓒呭嚭鏂囦欢涓暟");
+ };
+
+ const paginationSearch = ({ page, limit }) => {
+ emit("pagination", { page: page, limit: limit });
+ };
+
+ const rowClick = row => {
+ emit("row-click", row);
+ };
+
+ const expandChange = (row, expandedRows) => {
+ emit("expand-change", row, expandedRows);
+ };
+
+ const handleSelectionChange = newSelection => {
+ emit("selection-change", newSelection);
+ };
+
+ // 澶勭悊鍏ㄩ�夋搷浣�
+ const handleSelectAll = selection => {
+ if (selection.length) {
+ console.log(selection, "selection");
+ // 鍏ㄩ�夋椂锛屽彧閫夋嫨鍙�夋嫨鐨勮
+ const selectableRows = props.tableData.filter(row => props.selectable(row));
+ // 娓呯┖褰撳墠閫夋嫨
+ multipleTable.value.clearSelection();
+ // 鍙�夋嫨鍙�夋嫨鐨勮
+ selectableRows.forEach(row => {
+ multipleTable.value.toggleRowSelection(row, true);
+ });
+ } else {
+ // 鍙栨秷鍏ㄩ�夋椂锛屽彧鍙栨秷鍙�夋嫨鐨勮鐨勯�夋嫨
+ props.tableData.forEach(row => {
+ if (props.selectable(row)) {
+ multipleTable.value.toggleRowSelection(row, false);
+ }
+ });
+ }
+ };
+</script>
+
+<style scoped lang="scss">
+ .cell {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-right: 0 !important;
+ padding-left: 0 !important;
+ }
+
+ .pim-table-header-extra :deep(.el-input),
+ .pim-table-header-extra :deep(.el-select) {
+ width: 100%;
+ }
+</style>
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
new file mode 100644
index 0000000..15c1fa9
--- /dev/null
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -0,0 +1,576 @@
+<template>
+ <div class="app-container">
+ <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>
+ <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>
+ <el-form-item>
+ <el-button type="primary"
+ @click="handleQuery">鎼滅储</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">
+ <PIMTable rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ :tableLoading="tableLoading"
+ :isSelection="true"
+ :selectable="isSelectable"
+ @selection-change="handleSelectionChange"
+ @pagination="pagination">
+ </PIMTable>
+ </div>
+ <!-- 鍚堝苟涓嬪彂寮圭獥 -->
+ <el-dialog v-model="isShowNewModal"
+ title="鍚堝苟涓嬪彂"
+ width="500px">
+ <el-form :model="mergeForm"
+ label-width="120px">
+ <el-form-item label="鐢熶骇璁″垝鍙�">
+ <el-input v-model="mergeForm.productionPlanNo"
+ disabled />
+ </el-form-item>
+ <el-form-item label="鐢熶骇璁″垝鏁伴噺">
+ <el-input-number v-model="mergeForm.totalManufactureQuantity"
+ :min="1"
+ :step="1"
+ style="width: 100%" />
+ </el-form-item>
+ <el-form-item label="澶囨敞">
+ <el-input v-model="mergeForm.remark"
+ type="textarea" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="isShowNewModal = false">鍙栨秷</el-button>
+ <el-button type="primary"
+ @click="handleMergeSubmit">纭畾涓嬪彂</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ <!-- 浜у搧绫诲埆姹囨�诲脊绐� -->
+ <el-dialog v-model="showCategorySummaryDialog"
+ title="浜у搧绫诲埆姹囨�荤粺璁�"
+ width="400px">
+ <el-table :data="categorySummary"
+ border
+ style="width: 100%">
+ <el-table-column prop="productCategory"
+ label="浜у搧绫诲埆"
+ align="center"
+ width="150" />
+ <el-table-column prop="totalManufactureQuantity"
+ label="鎬诲埗閫犳暟閲�"
+ align="center" />
+ </el-table>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="showCategorySummaryDialog = false">鍏抽棴</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+ import { onMounted, ref } from "vue";
+ import { ElMessage } from "element-plus";
+ import dayjs from "dayjs";
+ import { productOrderListPage } from "@/api/productionManagement/productionOrder.js";
+ import PIMTable from "./components/PIMTable.vue";
+
+ const tableColumn = ref([
+ {
+ label: "鏉ユ簮",
+ prop: "source",
+ width: "100px",
+ },
+ {
+ label: "鐘舵��",
+ prop: "status",
+ width: "80px",
+ },
+ {
+ label: "瀹℃牳鐘舵��",
+ prop: "auditStatus",
+ width: "100px",
+ },
+ {
+ label: "璁㈠崟鍙�",
+ prop: "orderNo",
+ width: "120px",
+ },
+ {
+ label: "鐢熶骇璁″垝鍙�",
+ prop: "productionPlanNo",
+ width: "140px",
+ },
+ {
+ label: "闆朵欢鍙�",
+ prop: "partNo",
+ width: "120px",
+ },
+ {
+ label: "闆朵欢",
+ prop: "partName",
+ width: "120px",
+ },
+ {
+ label: "浜у搧绫诲埆",
+ prop: "productCategory",
+ width: "100px",
+ },
+ {
+ label: "宸ヨ壓鏂囦欢鍙�",
+ prop: "processFileNo",
+ width: "140px",
+ },
+ {
+ label: "閿�鍞暟閲�",
+ prop: "salesQuantity",
+ width: "100px",
+ align: "right",
+ },
+ {
+ label: "鍒堕�犳暟閲�",
+ prop: "manufactureQuantity",
+ 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",
+ width: "150px",
+ },
+ {
+ label: "鏇存柊鏃堕棿",
+ prop: "updateTime",
+ formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+ width: "120px",
+ },
+ {
+ label: "鏇存柊浜�",
+ prop: "updateBy",
+ width: "100px",
+ },
+ {
+ label: "鍒涘缓鏃堕棿",
+ prop: "createTime",
+ formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
+ width: "120px",
+ },
+ {
+ label: "鍒涘缓浜�",
+ prop: "createBy",
+ width: "100px",
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ align: "center",
+ fixed: "right",
+ width: 200,
+ operation: [
+ {
+ name: "涓嬪彂",
+ type: "text",
+ clickFun: row => {
+ // 鍗曠嫭涓嬪彂鎿嶄綔
+ // 璁剧疆琛ㄥ崟鏁版嵁
+ mergeForm.productionPlanNo = row.productionPlanNo;
+ mergeForm.totalManufactureQuantity = row.manufactureQuantity;
+ mergeForm.remark = "";
+
+ // 鎵撳紑寮圭獥
+ isShowNewModal.value = true;
+ },
+ },
+ {
+ name: "杩借釜杩涘害",
+ type: "text",
+ clickFun: row => {
+ // 杩借釜杩涘害鎿嶄綔
+ ElMessage.warning("杩借釜杩涘害鍔熻兘寰呭紑鍙�");
+ },
+ },
+ ],
+ },
+ ]);
+ 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({
+ productionPlanNo: "",
+ totalManufactureQuantity: 0,
+ remark: "",
+ });
+
+ const data = reactive({
+ searchForm: {
+ customerName: "",
+ salesContractNo: "",
+ projectName: "",
+ productCategory: "",
+ specificationModel: "",
+ },
+ });
+ const { searchForm } = toRefs(data);
+
+ // 鏌ヨ鍒楄〃
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ const handleQuery = () => {
+ 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.productCategory;
+ if (!summary[category]) {
+ summary[category] = {
+ productCategory: category,
+ totalManufactureQuantity: 0,
+ };
+ }
+ summary[category].totalManufactureQuantity += row.manufactureQuantity;
+ });
+
+ // 杞崲涓烘暟缁勬牸寮�
+ categorySummary.value = Object.values(summary);
+ };
+
+ const getList = () => {
+ tableLoading.value = true;
+ // 鏋勯�犱竴涓柊鐨勫璞★紝涓嶅寘鍚玡ntryDate瀛楁
+ const params = { ...searchForm.value, ...page };
+ params.entryDate = undefined;
+ tableData.value = [
+ {
+ id: 1,
+ source: "閿�鍞鍗�",
+ status: "寰呭鐞�",
+ auditStatus: "宸插鏍�",
+ orderNo: "SO20260301001",
+ productionPlanNo: "PP20260301001",
+ partNo: "P001",
+ partName: "闆朵欢A",
+ productCategory: "绫诲埆1",
+ processFileNo: "PF20260301001",
+ salesQuantity: 100,
+ manufactureQuantity: 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",
+ productionPlanNo: "PP20260301001",
+ partNo: "P002",
+ partName: "闆朵欢B",
+ productCategory: "绫诲埆1",
+ processFileNo: "PF20260301002",
+ salesQuantity: 200,
+ manufactureQuantity: 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",
+ productionPlanNo: "PP20260301002",
+ partNo: "P003",
+ partName: "闆朵欢C",
+ productCategory: "绫诲埆2",
+ processFileNo: "PF20260301003",
+ salesQuantity: 150,
+ manufactureQuantity: 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",
+ productionPlanNo: "PP20260301002",
+ partNo: "P004",
+ partName: "闆朵欢D",
+ productCategory: "绫诲埆2",
+ processFileNo: "PF20260301004",
+ salesQuantity: 300,
+ manufactureQuantity: 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",
+ productionPlanNo: "PP20260301003",
+ partNo: "P005",
+ partName: "闆朵欢E",
+ productCategory: "绫诲埆3",
+ processFileNo: "PF20260301005",
+ salesQuantity: 250,
+ manufactureQuantity: 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();
+ // productOrderListPage(params)
+ // .then(res => {
+ // tableLoading.value = false;
+
+ // tableData.value = res.data.records;
+ // page.total = res.data.total;
+ // // 璁$畻浜у搧绫诲埆姹囨�荤粺璁�
+ // calculateCategorySummary();
+ // })
+ // .catch(() => {
+ // tableLoading.value = false;
+ // });
+ };
+
+ // 閫変腑鐨勭敓浜ц鍒掑彿
+ const selectedProductionPlanNo = ref("");
+
+ // 琛ㄦ牸閫夋嫨鏁版嵁
+ const handleSelectionChange = selection => {
+ selectedRows.value = selection;
+ // 濡傛灉鏈夐�変腑鐨勮锛岃褰曠涓�涓�変腑琛岀殑鐢熶骇璁″垝鍙�
+ if (selection.length > 0) {
+ selectedProductionPlanNo.value = selection[0].productionPlanNo;
+ } else {
+ // 濡傛灉娌℃湁閫変腑鐨勮锛屾竻绌虹敓浜ц鍒掑彿
+ selectedProductionPlanNo.value = "";
+ }
+ };
+
+ // 鍒ゆ柇琛屾槸鍚﹀彲閫夋嫨
+ const isSelectable = row => {
+ // 濡傛灉娌℃湁閫変腑鐨勮锛屾墍鏈夎閮藉彲閫夋嫨
+ if (!selectedProductionPlanNo.value) {
+ return true;
+ }
+ // 濡傛灉鏈夐�変腑鐨勮锛屽彧鏈夌敓浜ц鍒掑彿鐩稿悓鐨勮鎵嶅彲閫夋嫨
+ return row.productionPlanNo === selectedProductionPlanNo.value;
+ };
+
+ // 澶勭悊鍚堝苟涓嬪彂鎸夐挳鐐瑰嚮
+ const handleMerge = () => {
+ if (selectedRows.value.length === 0) {
+ ElMessage.warning("璇烽�夋嫨瑕佸悎骞朵笅鍙戠殑鐢熶骇璁″垝");
+ return;
+ }
+
+ // 璁$畻鎬诲埗閫犳暟閲�
+ const totalQuantity = selectedRows.value.reduce((sum, row) => {
+ return sum + row.manufactureQuantity;
+ }, 0);
+
+ // 璁剧疆琛ㄥ崟鏁版嵁
+ mergeForm.productionPlanNo = selectedProductionPlanNo.value;
+ mergeForm.totalManufactureQuantity = totalQuantity;
+ mergeForm.remark = "";
+
+ // 鎵撳紑寮圭獥
+ isShowNewModal.value = true;
+ };
+
+ // 澶勭悊鍚堝苟涓嬪彂鎻愪氦
+ const handleMergeSubmit = () => {
+ // 杩欓噷鍙互娣诲姞涓嬪彂閫昏緫
+ ElMessage.success("鍚堝苟涓嬪彂鎴愬姛");
+ isShowNewModal.value = false;
+ // 鍙互閫夋嫨鍒锋柊鍒楄〃鎴栧叾浠栨搷浣�
+ };
+
+ onMounted(() => {
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ .search_form {
+ align-items: start;
+ }
+
+ .summary-section {
+ margin-bottom: 16px;
+ }
+
+ .horizontal-summary {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+ padding: 10px 0;
+ }
+
+ .summary-item {
+ flex: 1;
+ min-width: 120px;
+ text-align: center;
+ padding: 10px;
+ background-color: #f5f7fa;
+ border-radius: 4px;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ }
+
+ .summary-label {
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 5px;
+ }
+
+ .summary-value {
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ ::v-deep .yellow {
+ background-color: #faf0de;
+ }
+
+ ::v-deep .pink {
+ background-color: #fae1de;
+ }
+
+ ::v-deep .red {
+ background-color: #f80202;
+ }
+
+ ::v-deep .purple {
+ background-color: #f4defa;
+ }
+</style>
diff --git a/vite.config.js b/vite.config.js
index dc687a8..31ed13b 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -8,7 +8,7 @@
const { VITE_APP_ENV } = env;
const baseUrl =
env.VITE_APP_ENV === "development"
- ? "http://1.15.17.182:9003"
+ ? "http://192.168.1.248:9090"
: env.VITE_BASE_API;
const javaUrl =
env.VITE_APP_ENV === "development"
--
Gitblit v1.9.3