From ea324e1975ffec307758e00b5736b4399c36e6f6 Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期五, 24 四月 2026 10:02:25 +0800
Subject: [PATCH] 绑定工艺路线调整
---
src/views/productionManagement/productionOrder/BindRouteDialog.vue | 793 +++++++++++++++++++++++++++++++++++++++++
src/views/productionManagement/productionOrder/index.vue | 107 +++--
src/api/productionManagement/productionOrder.js | 20 +
src/components/Upload/ActionFileUpload.vue | 181 +++++++++
4 files changed, 1,051 insertions(+), 50 deletions(-)
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 6c8dbe2..23d52aa 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -129,4 +129,24 @@
method: "post",
data: data,
});
+}
+
+
+// 鐢熶骇璁㈠崟缁戝畾鍏瑰畾浜庡伐鑹鸿矾绾�
+// /productionProductInput/save
+export function saveProductionProductInput(data) {
+ return request({
+ url: "/productionProductInput/save",
+ method: "post",
+ data,
+ })
+}
+
+// 鐢熻景璁㈠崟鏌ョ湅宸ヨ壓璺嚎
+// /productionProductInput/getByProductWordId/{productOrderId}
+export function viewGetByProductWordId(data) {
+ return request({
+ url: "/productionProductInput/getByProductWordId/"+data,
+ method: "post",
+ })
}
\ No newline at end of file
diff --git a/src/components/Upload/ActionFileUpload.vue b/src/components/Upload/ActionFileUpload.vue
new file mode 100644
index 0000000..2d20b60
--- /dev/null
+++ b/src/components/Upload/ActionFileUpload.vue
@@ -0,0 +1,181 @@
+<template>
+ <el-upload
+ v-model:file-list="innerFileList"
+ :action="action"
+ :name="name"
+ :multiple="multiple"
+ ref="fileUploadRef"
+ :auto-upload="autoUpload"
+ :headers="headers"
+ :before-upload="handleBeforeUpload"
+ :on-error="handleUploadError"
+ :on-success="handleUploadSuccess"
+ :on-remove="handleRemove"
+ :on-preview="handlePreview"
+ :show-file-list="showFileList"
+ >
+ <el-button type="primary">{{ buttonText }}</el-button>
+ <template #file="{ file }">
+ <div style="display:flex; align-items:center; gap: 10px; width: 100%;">
+ <span style="flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
+ {{ file.name }}
+ </span>
+ <div style="display:flex; align-items:center; gap: 6px;">
+ <el-button link type="success" :icon="Download" @click="handleDownload(file)" />
+ <el-button link type="primary" :icon="View" @click="handlePreview(file)" />
+ <el-button link type="danger" :icon="Delete" @click="triggerRemoveFile(file)" />
+ </div>
+ </div>
+ </template>
+ <template #tip>
+ <div class="el-upload__tip">
+ {{ tipText }}
+ </div>
+ </template>
+ </el-upload>
+</template>
+
+<script setup>
+import { computed, ref } from "vue";
+import { Delete, Download, View } from "@element-plus/icons-vue";
+
+const props = defineProps({
+ name: {
+ type: String,
+ default: "file",
+ },
+ fileList: {
+ type: Array,
+ default: () => [],
+ },
+ action: {
+ type: String,
+ required: true,
+ },
+ headers: {
+ type: Object,
+ default: () => ({}),
+ },
+ multiple: {
+ type: Boolean,
+ default: true,
+ },
+ autoUpload: {
+ type: Boolean,
+ default: true,
+ },
+ showFileList: {
+ type: Boolean,
+ default: true,
+ },
+ buttonText: {
+ type: String,
+ default: "涓婁紶",
+ },
+ tipText: {
+ type: String,
+ default: "鏀寔鏂囨。鍜屽浘鐗囨牸寮�",
+ },
+ beforeUpload: {
+ type: Function,
+ default: null,
+ },
+ onError: {
+ type: Function,
+ default: null,
+ },
+ onSuccess: {
+ type: Function,
+ default: null,
+ },
+ onRemove: {
+ type: Function,
+ default: null,
+ },
+ onPreview: {
+ type: Function,
+ default: null,
+ },
+ onDownload: {
+ type: Function,
+ default: null,
+ },
+});
+
+const emit = defineEmits([
+ "update:fileList",
+ "error",
+ "success",
+ "remove",
+ "preview",
+ "download",
+]);
+
+const fileUploadRef = ref(null);
+
+const innerFileList = computed({
+ get: () => props.fileList || [],
+ set: (val) => emit("update:fileList", val),
+});
+
+const getFileUrl = (file) => {
+ return file?.url || file?.response?.data?.tempPath || file?.response?.data?.url || "";
+};
+
+const triggerRemoveFile = (file) => {
+ fileUploadRef.value?.handleRemove?.(file);
+};
+
+const handleBeforeUpload = (...args) => {
+ if (props.beforeUpload) {
+ return props.beforeUpload(...args);
+ }
+ return true;
+};
+
+const handleUploadError = (...args) => {
+ props.onError?.(...args);
+ emit("error", ...args);
+};
+
+const handleUploadSuccess = (...args) => {
+ props.onSuccess?.(...args);
+ emit("success", ...args);
+};
+
+const handleRemove = (...args) => {
+ props.onRemove?.(...args);
+ emit("remove", ...args);
+};
+
+const handlePreview = (file, ...rest) => {
+ if (props.onPreview) {
+ props.onPreview(file, ...rest);
+ emit("preview", file, ...rest);
+ return;
+ }
+ const url = getFileUrl(file);
+ if (url) {
+ window.open(url, "_blank");
+ }
+ emit("preview", file, ...rest);
+};
+
+const handleDownload = (file) => {
+ if (props.onDownload) {
+ props.onDownload(file);
+ emit("download", file);
+ return;
+ }
+ const url = getFileUrl(file);
+ if (!url) return;
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = file?.name || "download";
+ link.target = "_blank";
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ emit("download", file);
+};
+</script>
diff --git a/src/views/productionManagement/productionOrder/BindRouteDialog.vue b/src/views/productionManagement/productionOrder/BindRouteDialog.vue
new file mode 100644
index 0000000..a110438
--- /dev/null
+++ b/src/views/productionManagement/productionOrder/BindRouteDialog.vue
@@ -0,0 +1,793 @@
+<template>
+ <FormDialog
+ v-model="visible"
+ :title="type === 'add' ? '缁戝畾宸ヨ壓璺嚎' : '缂栬緫宸ヨ壓璺嚎'"
+ width="1400px"
+ :operation-type="type"
+ :column="8"
+ @close="handleClose"
+ @confirm="handleConfirm"
+ @cancel="handleClose"
+ >
+ <!-- ================= 鍩烘湰淇℃伅 ================= -->
+ <el-descriptions :column="3">
+ <el-descriptions-item label="缂栧彿" align="center" v-if="formData.productOrderList">
+ {{ formData.productOrderList.salesContractNo || "鏆傛棤鏁版嵁" }}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鍒跺崟鏃ユ湡" align="center" v-if="formData.productOrderList">
+ {{ formData.productOrderList.entryDate || "鏆傛棤鏁版嵁" }}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="浜や粯鏃ユ湡" align="center" v-if="formData.productOrderList">
+ {{ formData.productOrderList.deliveryDate || "鏆傛棤鏁版嵁" }}
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <el-descriptions border :column="4">
+ <el-descriptions-item label="濮旀墭鍗曚綅" :span="2" align="center">
+ {{formData.clientName || "--"}}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鏁伴噺" :span="1" align="center">
+ {{formData.orderQty || "--"}}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鎴愬搧灏哄" :span="1" align="center">
+ {{formData.specificationModel || "--"}}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="浜у搧鍚嶇О" :span="2" align="center">
+ {{formData.productName || "--"}}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鍗曟嵁绫诲瀷" :span="2" align="center">
+ <el-checkbox-group v-model="introductionLetterList">
+ <el-checkbox label="浠嬬粛淇�" value="浠嬬粛淇�" />
+ <el-checkbox label="鍟嗘爣娉ㄥ唽涔�" value="鍟嗘爣娉ㄥ唽涔�" />
+ <el-checkbox label="濮斿嵃鍗�" value="濮斿嵃鍗�" />
+ </el-checkbox-group>
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <!-- ================= 鏉愭枡琛� ================= -->
+ <div class="process-table-header">
+ <div class="section-title">鏉愭枡淇℃伅</div>
+ <el-button type="primary" size="small" @click="addMaterialRow">鏂板涓�琛�</el-button>
+ </div>
+ <el-table border :data="formData.materialInfo" style="width: 100%">
+ <el-table-column label="鏉愭枡鍚嶇О">
+ <template #default="{ row }">
+ <el-tree-select
+ v-model="row.productId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ check-strictly
+ @change="(val) => getModels(val, row)"
+ :data="productOptions"
+ :render-after-expand="false"
+ style="width: 100%"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="瑙勬牸">
+ <template #default="{ row }">
+ <el-select
+ v-model="row.productModelId"
+ placeholder="璇烽�夋嫨瑙勬牸"
+ filterable
+ clearable
+ @change="(val) => handleMaterialModelChange(val, row)"
+ >
+ <el-option
+ v-for="item in row.modelOptions || []"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id"
+ />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏁伴噺">
+ <template #default="{ row }">
+ <el-input v-model="row.num" placeholder="鏁伴噺">
+ <template #append>{{ row.numSuffix }}</template>
+ </el-input>
+ </template>
+ </el-table-column>
+ <el-table-column label="璁¢噺鍗曚綅">
+ <template #default="{ row }">
+ <el-input v-model="row.unit" placeholder="璁¢噺鍗曚綅" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鍗曚环">
+ <template #default="{ row }">
+ <el-input v-model="row.price" placeholder="鍗曚环">
+ <template #append>{{ row.unitSuffix }}</template>
+ </el-input>
+ </template>
+ </el-table-column>
+ <el-table-column label="閲戦">
+ <template #default="{ row }">
+ <el-input v-model="row.totalAmount" placeholder="閲戦" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="80">
+ <template #default="{ $index }">
+ <el-button type="danger" size="small" @click="removeMaterialRow($index)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <el-descriptions border :column="2" :span="2">
+ <el-descriptions-item
+ label="娉ㄦ剰浜嬮」"
+ :span="2"
+ align="center"
+ style="white-space: pre-line; word-break: break-all; min-height: 60px;"
+ >
+ <el-input
+ v-model="formData.productDescription"
+ :autosize="{ minRows: 2, maxRows: 4 }"
+ type="textarea"
+ placeholder="璇疯緭鍏ユ敞鎰忎簨椤�"
+ />
+ </el-descriptions-item>
+ </el-descriptions>
+ <hr>
+ <!-- ================= 鍒囨枡鍥剧ず ================= -->
+ <div class="section-title">鍒囨枡鍥剧ず</div>
+ <ActionFileUpload
+ style="width: 50%;"
+ v-model:file-list="fileList"
+ :action="upload.url"
+ :headers="upload.headers"
+ :multiple="false"
+ :name="'files'"
+ :onSuccess="uploadSuccess"
+ tip-text="鏀寔鍥剧墖锛坖pg, jpeg, png锛夋牸寮�"
+ />
+ <!-- ================= 鍒囨枡淇℃伅 ================= -->
+ <el-descriptions
+ border
+ :column="6"
+ direction="vertical"
+ style="width: 100%"
+ class="fixed-desc"
+ >
+ <el-descriptions-item label="鍒囨枡灏哄" align="center">
+ <el-input v-model="formData.cutNum" placeholder="鍒囨枡灏哄" />
+ </el-descriptions-item>
+ <el-descriptions-item label="鍒囨枡鏁伴噺" align="center">
+ <el-input v-model="formData.cutSize" placeholder="鍒囨枡灏哄" />
+ </el-descriptions-item>
+ <el-descriptions-item label="涓洅鏁伴噺" align="center">
+ <el-input v-model="formData.mediumBoxQty" placeholder="涓洅鏁伴噺" />
+ </el-descriptions-item>
+ <el-descriptions-item label="灏忕洅鏁伴噺" align="center">
+ <el-input v-model="formData.smallBoxQty" placeholder="灏忕洅鏁伴噺" />
+ </el-descriptions-item>
+ <el-descriptions-item label="姝f暟" align="center">
+ <el-input v-model="formData.positiveQty" placeholder="姝f暟" />
+ </el-descriptions-item>
+ <el-descriptions-item label="鍔犳斁鏁�" align="center">
+ <el-input v-model="formData.allowanceQty" placeholder="鍔犳斁鏁�" />
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div class="middle-sheet-table">
+ <table class="middle-sheet-table__inner">
+ <tbody>
+ <tr>
+ <th>杞墖鐗�:</th>
+ <th colspan="2">寮�寮犺壊</th>
+ <th>鏅掓澘</th>
+ <th colspan="2">寮�鎷�</th>
+ <th>鍒垁鐗�</th>
+ <th>鑱旇壊鍧�</th>
+ </tr>
+ <tr>
+ <th rowspan="2">鍒剁増</th>
+ <th>璁捐鍒朵綔璐�</th>
+ <th>鎷肩増璐�</th>
+ <th>鍑虹墖璐�</th>
+ <th>鎵撴牱璐�</th>
+ <th>鍒垁鐗堣垂</th>
+ <th>鐑�/鍑哥増璐�</th>
+ <th>灏忚</th>
+ </tr>
+ <tr v-for="(plate, index) in formData.plateMaking" :key="index">
+ <td>
+ <el-input v-model="plate.designProductionFee" placeholder="璇疯緭鍏ヨ璁″埗浣滆垂" />
+ </td>
+ <td>
+ <el-input v-model="plate.impositionFee" placeholder="璇疯緭鍏ユ嫾鐗堣垂" />
+ </td>
+ <td>
+ <el-input v-model="plate.filmOutputFee" placeholder="璇疯緭鍏ュ嚭鐗囪垂" />
+ </td>
+ <td>
+ <el-input v-model="plate.proofingFee" placeholder="璇疯緭鍏ユ墦鏍疯垂" />
+ </td>
+ <td>
+ <el-input v-model="plate.doctorBladePlateFee" placeholder="璇疯緭鍏ュ埆鍒�鐗堣垂" />
+ </td>
+ <td>
+ <el-input v-model="plate.hotEmbossingPlateFee" placeholder="璇疯緭鍏ョ儷/鍑哥増璐�" />
+ </td>
+ <td>
+ <el-input v-model="plate.subtotalFee" placeholder="璇疯緭鍏ュ皬璁�" />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+<!-- class="section-title" -->
+ <!-- ================= 宸ヨ壓鍔犲伐 ================= -->
+ <div class="process-table-header">
+ <div class="section-title">宸ヨ壓鍔犲伐</div>
+ <el-button type="primary" size="small" @click="addProcessRow">鏂板涓�琛�</el-button>
+ </div>
+ <el-table border :data="formData.processContent" style="width: 100%" :span-method="objectSpanMethod">
+ <el-table-column label="宸ュ簭" width="140">
+ <template #default="{ row }">
+ <el-table-column label="宸ュ簭" width="140">
+ <template #default="{ row }">
+ <el-select
+ v-model="row.processId"
+ placeholder="璇烽�夋嫨宸ュ簭"
+ @change="(val) => onProcessChange(val, row)"
+ >
+ <el-option
+ v-for="item in processOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
+ </el-select>
+ </template>
+ </el-table-column>
+ </template>
+ </el-table-column>
+ <el-table-column label="寮�鏁�">
+ <template #default="{ row }">
+ <el-input v-model="row.openCount" placeholder="璇疯緭鍏ュ紑鏁�" />
+ </template>
+ </el-table-column>
+ <el-table-column label="宸ヨ壓姝f暟">
+ <template #default="{ row }">
+ <el-input v-model="row.processPositive" placeholder="璇疯緭鍏ュ伐鑹烘鏁�" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鍔犳斁鏁�">
+ <template #default="{ row }">
+ <el-input v-model="row.allowanceQty" placeholder="璇疯緭鍏ュ姞鏀炬暟" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鏈哄彴" width="180">
+ <template #default="{ row }">
+ <el-select
+ v-model="row.deviceId"
+ placeholder="璇烽�夋嫨鏈哄彴"
+ filterable
+ clearable
+ @change="(val) => handleDeviceChange(val, row)"
+ >
+ <el-option
+ v-for="item in deviceOptions"
+ :key="item.id"
+ :label="item.deviceName"
+ :value="item.id"
+ />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎶ュ伐浜�" width="220">
+ <template #default="{ row }">
+ <el-select
+ v-model="row.reportUserIds"
+ placeholder="璇烽�夋嫨鎶ュ伐浜�"
+ filterable
+ clearable
+ multiple
+ collapse-tags
+ collapse-tags-tooltip
+ @change="(val) => handleReportUsersChange(val, row)"
+ >
+ <el-option
+ v-for="item in userOptions"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.userId"
+ />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="宸ヨ壓瑕佹眰">
+ <template #default="{ rowIndex }">
+ <el-input
+ v-model="formData.processRequirement"
+ type="textarea"
+ :rows="6"
+ placeholder="璇疯緭鍏ュ伐鑹鸿姹�"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="80">
+ <template #default="{ $index }">
+ <el-button type="danger" size="small" @click="removeProcessRow($index)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- ================= 鍖呰淇℃伅 ================= -->
+ <el-descriptions border :column="3" class="mt">
+ <el-descriptions-item label="閫佽揣鍦扮偣" align="center">
+ <el-input v-model="formData.deliveryAddress" placeholder="閫佽揣鍦扮偣" />
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鑱旂郴浜�" align="center">
+ <el-input v-model="formData.contactName" placeholder="鑱旂郴浜�" />
+ </el-descriptions-item>
+
+ <el-descriptions-item label="鍖呰瑕佹眰" align="center">
+ <el-input v-model="formData.packagingRequirement" placeholder="鍖呰瑕佹眰" />
+ </el-descriptions-item>
+
+ <el-descriptions-item label="灏哄" align="center">
+ <el-input v-model="formData.postProcessSize" placeholder="灏哄" />
+ </el-descriptions-item>
+
+ <el-descriptions-item label="瀹氳揣鏁伴噺" align="center">
+ {{formData.orderQty || "--"}}
+ </el-descriptions-item>
+
+ <el-descriptions-item label="瀹炰氦鏁伴噺" :span="3" align="center">
+ <el-input v-model="formData.actualDeliveryQty" placeholder="瀹炰氦鏁伴噺" />
+ </el-descriptions-item>
+ </el-descriptions>
+ </FormDialog>
+</template>
+
+<script setup>
+import { ref, reactive, computed, onMounted, watch } from 'vue'
+import dayjs from 'dayjs'
+import FormDialog from '@/components/Dialog/FormDialog.vue'
+import ActionFileUpload from "@/components/Upload/ActionFileUpload.vue";
+import { list } from "@/api/productionManagement/productionProcess.js"
+import { modelList, productTreeList } from "@/api/basicData/product.js"
+import {getSalesLedgerWithProducts} from "@/api/salesManagement/salesLedger.js"
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js"
+import { userListNoPageByTenantId } from "@/api/system/user.js"
+import { getToken } from "@/utils/auth";
+
+const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false
+ },
+ type: {
+ type: String,
+ default: 'add'
+ },
+ orderData: {
+ type: Object,
+ default: () => ({})
+ },
+ rowData: {
+ type: Object,
+ default: null
+ }
+})
+
+const emit = defineEmits(['update:modelValue', 'confirm'])
+
+const visible = computed({
+ get: () => props.modelValue,
+ set: (val) => emit('update:modelValue', val)
+})
+
+const processOptions = ref([])
+const deviceOptions = ref([])
+const userOptions = ref([])
+const reportWorkerList = ref([])
+const productOptions = ref([])
+const introductionLetterList = ref([])
+const fileList = ref([])
+const upload = reactive({
+ url: import.meta.env.VITE_APP_BASE_API + '/basic/customer-follow/upload',
+ headers: { Authorization: 'Bearer ' + getToken() }
+})
+
+const formData = reactive({
+ productOrderList:null,
+ salesLedgerId: null,
+ productOrderId: null,
+ printOrderTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+ fileList:[],
+ finishTime: "",
+ no: "",
+ productName: "",
+ productDescription: "",
+ clientName: "",
+ finishedSize: "",
+ cutNum: "",
+ cutSize:"",
+ mediumBoxQty: "",
+ smallBoxQty: "",
+ positiveQty: "",
+ allowanceQty: "",
+ introductionLetter: "",
+ plateMaking: [
+ {
+ designProductionFee: "",
+ impositionFee: "",
+ filmOutputFee: "",
+ proofingFee: "",
+ doctorBladePlateFee: "",
+ hotEmbossingPlateFee: "",
+ subtotalFee: ""
+ }
+ ],
+ processContent: [
+ {
+ id: "1",
+ processId: "",
+ processName: "",
+ mediumBoxQty: "",
+ smallBoxQty: "",
+ openCount: "",
+ processPositive: "",
+ allowanceQty: "",
+ deviceId: "",
+ deviceName: "",
+ reportUserIds: [],
+ reportWorkerList: []
+ }
+ ],
+ materialInfo: [
+ {
+ id: "1",
+ productId: "",
+ name: "",
+ productModelId: "",
+ model: "",
+ modelOptions: [],
+ num: "",
+ numSuffix: "寮�",
+ unitSuffix: "鍏�/kg",
+ unit: "",
+ price: "",
+ totalAmount: ""
+ }
+ ],
+ processRequirement: "",
+ deliveryAddress: "",
+ contactName: "",
+ packagingRequirement: "",
+ postProcessSize: "",
+ orderQty: "",
+ actualDeliveryQty: "",
+ productionDept: "",
+ technicalDept: "",
+ warehouseDept: "",
+ productModelId: "",
+ specificationModel:"",
+})
+
+// 鐩戝惉 checkbox group 鍙樺寲骞跺悓姝ュ埌 introductionLetter 瀛楃涓�
+watch(introductionLetterList, (val) => {
+ formData.introductionLetter = val.join(',')
+})
+const onProcessChange = (processId, row) => {
+ const selected = processOptions.find(item => item.id === processId)
+ row.processName = selected?.name || ''
+}
+const cloneDeep = (val) => JSON.parse(JSON.stringify(val))
+
+const uploadSuccess = (...args) => {
+ console.log(...args)
+}
+
+const mergeRowDataToForm = (source) => {
+ if (!source || typeof source !== 'object') {
+ return
+ }
+
+ Object.keys(formData).forEach((key) => {
+ if (source[key] !== undefined) {
+ formData[key] = Array.isArray(source[key]) ? cloneDeep(source[key]) : source[key]
+ }
+ })
+
+ // 鍏煎 index.vue 閲屽父鐢ㄥ瓧娈靛悕涓庡脊绐楀瓧娈靛悕涓嶄竴鑷寸殑鎯呭喌
+ if (source.productName === undefined && source.productCategory !== undefined) {
+ formData.productName = source.productCategory
+ }
+ if (source.orderQty === undefined && source.quantity !== undefined) {
+ formData.orderQty = source.quantity
+ }
+ if (source.no === undefined && source.salesContractNo !== undefined) {
+ formData.no = source.salesContractNo
+ }
+ if (source.clientName === undefined && source.customerName !== undefined) {
+ formData.clientName = source.customerName
+ }
+ if (source.productOrderId === undefined && source.id !== undefined) {
+ formData.productOrderId = source.id
+ }
+}
+
+// 鑾峰彇閿�鍞鍗�
+const getProductOrder = () => {
+ if(!formData.salesLedgerId) return
+ getSalesLedgerWithProducts({
+ type: "1",
+ id: formData.salesLedgerId
+ }).then(res => {
+ if(res){
+ formData.productOrderList = res
+ }
+ console.log(formData)
+ })
+
+}
+
+watch(() => props.orderData, (val) => {
+ mergeRowDataToForm(val)
+}, { immediate: true, deep: true })
+
+watch(
+ () => props.rowData,
+ (val) => {
+ mergeRowDataToForm(val)
+ getProductOrder()
+ },
+ { immediate: true, deep: true }
+)
+
+const getProcessList = () => {
+ list().then(res => {
+ processOptions.value = res.data
+ })
+}
+
+
+
+const getDeviceList = () => {
+ getDeviceLedger().then(res => {
+ deviceOptions.value = Array.isArray(res?.data) ? res.data : []
+ })
+}
+
+const getUserList = () => {
+ userListNoPageByTenantId().then(res => {
+ userOptions.value = Array.isArray(res?.data) ? res.data : []
+ })
+}
+
+const convertProductOptions = (data) => {
+ return data.map(item => ({
+ label: item.label || item.productName || item.name || "",
+ value: item.id,
+ children: item.children?.length ? convertProductOptions(item.children) : undefined
+ }))
+}
+
+const findProductLabelById = (options, productId) => {
+ for (const item of options) {
+ if (item.value === productId) {
+ return item.label
+ }
+ if (item.children?.length) {
+ const label = findProductLabelById(item.children, productId)
+ if (label) {
+ return label
+ }
+ }
+ }
+ return ""
+}
+
+const getMaterialProductOptions = () => {
+ productTreeList().then(res => {
+ const rawData = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
+ productOptions.value = convertProductOptions(rawData)
+ })
+}
+
+const handleProcessChange = (val, row) => {
+ console.log(row)
+ const process = processOptions.value.find(item => item.id === val)
+ if (process) {
+ row.processName = process.name
+ console.log(process)
+ if (process.deviceId) {
+ row.deviceId = process.deviceId || ""
+ row.deviceName = process.deviceName || ""
+ }
+ }
+}
+
+const handleDeviceChange = (val, row) => {
+ const device = deviceOptions.value.find(item => item.id === val)
+ row.deviceName = device?.deviceName || ""
+ row.deviceId = val || ""
+}
+
+const handleReportUsersChange = (val, row) => {
+ const userMap = new Map(
+ userOptions.value.map(item => [item.userId, item.nickName])
+ )
+ row.reportWorkerList = (val || []).map(userId => ({
+ userId,
+ userName: userMap.get(userId) || ''
+ }))
+}
+
+const getModels = (val, row) => {
+ row.productId = val || ""
+ row.name = val ? findProductLabelById(productOptions.value, val) : ""
+ row.productModelId = ""
+ row.model = ""
+ row.unit = ""
+ row.modelOptions = []
+ if (!val) {
+ return
+ }
+ modelList({ id: val }).then(res => {
+ row.modelOptions = Array.isArray(res) ? res : Array.isArray(res?.data) ? res.data : []
+ })
+}
+
+const handleMaterialModelChange = (val, row) => {
+ const currentModel = (row.modelOptions || []).find(item => item.id === val)
+ row.productModelId = val || ""
+ row.model = currentModel?.model || ""
+ row.unit = currentModel?.unit || ""
+}
+
+// 鏉愭枡淇℃伅
+const addMaterialRow = () => {
+ formData.materialInfo.push({
+ id: Date.now().toString(),
+ productId: "",
+ name: "",
+ productModelId: "",
+ model: "",
+ modelOptions: [],
+ num: "",
+ numSuffix: "寮�",
+ unitSuffix: "鍏�/kg",
+ unit: "",
+ price: "",
+ totalAmount: ""
+ })
+}
+
+const removeMaterialRow = (index) => {
+ formData.materialInfo.splice(index, 1)
+}
+
+const addProcessRow = () => {
+ formData.processContent.push({
+ id: Date.now().toString(),
+ processId: "",
+ processName: "",
+ openCount: "",
+ processPositive: "",
+ allowanceQty: "",
+ deviceId: "",
+ deviceName: "",
+ reportUserIds: [],
+ reportWorkerList: []
+ })
+}
+
+const removeProcessRow = (index) => {
+ formData.processContent.splice(index, 1)
+}
+
+const objectSpanMethod = ({ column, rowIndex }) => {
+ if (column.label === "宸ヨ壓瑕佹眰") {
+ if (rowIndex === 0) {
+ return {
+ rowspan: Math.max(formData.processContent.length, 1),
+ colspan: 1,
+ }
+ }
+ return {
+ rowspan: 0,
+ colspan: 0,
+ }
+ }
+}
+
+const handleClose = () => {
+ visible.value = false
+}
+
+const handleConfirm = () => {
+ emit('confirm', JSON.parse(JSON.stringify(formData)))
+}
+
+onMounted(() => {
+ getProcessList()
+ getDeviceList()
+ getUserList()
+ getMaterialProductOptions()
+})
+defineExpose({
+ getProductOrder
+})
+</script>
+
+<style scoped lang="scss">
+.section-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin: 20px 0 10px;
+ padding-left: 10px;
+ border-left: 4px solid #409eff;
+}
+
+.fixed-desc {
+ margin-top: 20px;
+ :deep(.el-descriptions__table) {
+ table-layout: fixed;
+ width: 100%;
+ }
+ :deep(.el-descriptions__cell) {
+ width: 25%;
+ word-break: break-word;
+ }
+}
+
+.middle-sheet-table {
+ margin-top: 20px;
+ width: 100%;
+ border: 1px solid #ebeef5;
+}
+
+.middle-sheet-table__inner {
+ width: 100%;
+ border-collapse: collapse;
+ table-layout: fixed;
+
+ th, td {
+ border: 1px solid #ebeef5;
+ padding: 8px;
+ text-align: center;
+ font-size: 14px;
+ }
+
+ th {
+ background-color: #f5f7fa;
+ color: #606266;
+ font-weight: bold;
+ }
+
+ :deep(.el-input__wrapper) {
+ box-shadow: none !important;
+ background-color: transparent;
+ }
+}
+
+.process-table-header {
+ margin-top: 20px;
+ margin-bottom: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ span {
+ font-size: 16px;
+ font-weight: bold;
+ }
+}
+
+.mt {
+ margin-top: 20px;
+}
+:deep(.el-textarea__inner){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 55fcc05..15e7cba 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -11,7 +11,7 @@
style="width: 160px;"
@change="handleQuery" />
</el-form-item>
- <el-form-item label="鍚堝悓鍙�:">
+ <el-form-item label="璁㈠崟缂栧彿:">
<el-input v-model="searchForm.salesContractNo"
placeholder="璇疯緭鍏�"
clearable
@@ -41,7 +41,7 @@
</el-form-item>
</el-form>
<div>
- <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>
+<!-- <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>-->
<el-button type="danger" @click="handleDelete">鍒犻櫎</el-button>
<el-button @click="handleOut">瀵煎嚭</el-button>
</div>
@@ -65,32 +65,14 @@
</template>
</PIMTable>
</div>
- <el-dialog v-model="bindRouteDialogVisible"
- title="缁戝畾宸ヨ壓璺嚎"
- width="500px">
- <el-form label-width="90px">
- <el-form-item label="宸ヨ壓璺嚎">
- <el-select v-model="bindForm.routeId"
- placeholder="璇烽�夋嫨宸ヨ壓璺嚎"
- style="width: 100%;"
- :loading="bindRouteLoading">
- <el-option v-for="item in routeOptions"
- :key="item.id"
- :label="`${item.processRouteCode || ''}`"
- :value="item.id" />
- </el-select>
- </el-form-item>
- </el-form>
- <template #footer>
- <span class="dialog-footer">
- <el-button type="primary"
- :loading="bindRouteSaving"
- @click="handleBindRouteConfirm">纭� 璁�</el-button>
- <el-button @click="bindRouteDialogVisible = false">鍙� 娑�</el-button>
- </span>
- </template>
- </el-dialog>
+ <BindRouteDialog
+ ref="BindRouteDialogRef"
+ v-model="bindRouteDialogVisible"
+ :type="bindDialogType"
+ :rowData="rowData"
+ @confirm="handleBindRouteSubmit"
+ />
<new-product-order v-if="isShowNewModal"
v-model:visible="isShowNewModal"
@completed="handleQuery" />
@@ -98,25 +80,39 @@
</template>
<script setup>
- import { onMounted, ref } from "vue";
+ import { defineAsyncComponent, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import { useRouter } from "vue-router";
import {
productOrderListPage,
- listProcessRoute,
bindingRoute,
- listProcessBom, delProductOrder,
+ delProductOrder,
+ saveProductionProductInput,
+ viewGetByProductWordId
} from "@/api/productionManagement/productionOrder.js";
import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
- import {fileDel} from "@/api/financialManagement/revenueManagement.js";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
+ import BindRouteDialog from "./BindRouteDialog.vue";
+ import {getDeviceLedger} from "@/api/equipmentManagement/ledger.js";
const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
const { proxy } = getCurrentInstance();
const router = useRouter();
const isShowNewModal = ref(false);
+ const MOCK_MODE = true;
+
+ const loading = ref(false)
+ const dialogVisible = ref(false)
+ const bindDialogType = ref('add')
+ const BindRouteDialogRef = ref(null)
+
+ const handleBindRouteSubmit =async (data)=>{
+ const res = await saveProductionProductInput(data)
+ console.log(res)
+
+ }
const tableColumn = ref([
{
@@ -187,21 +183,22 @@
label: "鎿嶄綔",
align: "center",
fixed: "right",
- width: 200,
+ width: 300,
operation: [
- {
- name: "宸ヨ壓璺嚎",
- type: "text",
- clickFun: row => {
- showRouteItemModal(row);
- },
- },
{
name: "缁戝畾宸ヨ壓璺嚎",
type: "text",
showHide: row => !row.processRouteCode,
clickFun: row => {
openBindRouteDialog(row);
+ },
+ },
+ {
+ name: "鏌ョ湅宸ヨ壓璺嚎",
+ type: "text",
+ showHide: row => row.processRouteCode,
+ clickFun: row => {
+ openBindRouteDialog(row,"view");
},
},
{
@@ -273,25 +270,27 @@
const bindRouteLoading = ref(false);
const bindRouteSaving = ref(false);
const routeOptions = ref([]);
+ const rowData = ref(null)
const bindForm = reactive({
orderId: null,
routeId: null,
});
- const openBindRouteDialog = async row => {
+ const openBindRouteDialog = async (row,type) => {
bindForm.orderId = row.id;
bindForm.routeId = null;
bindRouteDialogVisible.value = true;
routeOptions.value = [];
- if (!row.productModelId) {
- proxy.$modal.msgWarning("褰撳墠璁㈠崟缂哄皯浜у搧鍨嬪彿锛屾棤娉曟煡璇㈠伐鑹鸿矾绾�");
- bindRouteDialogVisible.value = false;
- return;
- }
bindRouteLoading.value = true;
+ if(type === "view") {
+ bindDialogType.value = "view"
+ let res = await viewGetByProductWordId(row.id)
+ console.log(res)
+ }
+ BindRouteDialogRef.value?.getProductOrder()
+
try {
- const res = await listProcessRoute({ productModelId: row.productModelId });
- routeOptions.value = res.data || [];
+ rowData.value = row;
} catch (e) {
console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触锛�", e);
proxy.$modal.msgError("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触");
@@ -443,8 +442,6 @@
});
};
- const handleConfirmRoute = () => {};
-
onMounted(() => {
getList();
});
@@ -464,10 +461,20 @@
}
::v-deep .red {
- background-color: #f80202;
+ background-color: #ffe5e5;
}
::v-deep .purple{
background-color: #F4DEFA;
}
+
+:deep(.fixed-desc .el-descriptions__table) {
+ table-layout: fixed;
+ width: 100%;
+}
+
+:deep(.fixed-desc .el-descriptions__cell) {
+ width: 25%;
+ word-break: break-word;
+}
</style>
--
Gitblit v1.9.3