From 0cc7997b26301527f6928ba663a532989cf6db56 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期四, 16 四月 2026 16:17:02 +0800
Subject: [PATCH] 工序/排产
---
src/views/productionManagement/productionProcess/Edit.vue | 269 ++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 234 insertions(+), 35 deletions(-)
diff --git a/src/views/productionManagement/productionProcess/Edit.vue b/src/views/productionManagement/productionProcess/Edit.vue
index 3d35f7c..f12e5a5 100644
--- a/src/views/productionManagement/productionProcess/Edit.vue
+++ b/src/views/productionManagement/productionProcess/Edit.vue
@@ -3,29 +3,64 @@
<el-dialog
v-model="isShow"
title="缂栬緫閮ㄤ欢"
- width="400"
+ width="760"
@close="closeModal"
>
<el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
- <el-form-item
- label="閮ㄤ欢锛�"
- prop="name"
+ <el-row :gutter="16">
+ <el-col :span="12">
+ <el-form-item
+ label="浜у搧鍚嶇О锛�"
+ prop="productId"
:rules="[
{
required: true,
- message: '璇疯緭鍏ラ儴浠�',
+ message: '璇烽�夋嫨浜у搧鍚嶇О',
},
- {
- max: 100,
- message: '鏈�澶�100涓瓧绗�',
- }
]">
- <el-input v-model="formState.name" />
- </el-form-item>
- <el-form-item label="閮ㄤ欢缂栧彿" prop="no">
- <el-input v-model="formState.no" />
- </el-form-item>
- <el-form-item
+ <el-tree-select
+ v-model="formState.productId"
+ placeholder="璇烽�夋嫨浜у搧鍚嶇О"
+ clearable
+ filterable
+ check-strictly
+ :data="productCategoryOptions"
+ :render-after-expand="false"
+ style="width: 100%"
+ @change="handleProductChange"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="浜у搧瑙勬牸锛�"
+ prop="productModelId"
+ :rules="[
+ {
+ required: true,
+ message: '璇烽�夋嫨浜у搧瑙勬牸',
+ },
+ ]">
+ <el-select v-model="formState.productModelId"
+ placeholder="璇烽�夋嫨浜у搧瑙勬牸"
+ clearable
+ filterable
+ :disabled="!formState.productId"
+ style="width: 100%">
+ <el-option v-for="item in modelOptions"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閮ㄤ欢缂栧彿" prop="no">
+ <el-input v-model="formState.no" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
label="閮ㄤ欢绫诲瀷"
prop="type"
:rules="[
@@ -34,25 +69,58 @@
message: '璇烽�夋嫨閮ㄤ欢绫诲瀷',
}
]"
- >
- <el-select v-model="formState.type" placeholder="璇烽�夋嫨閮ㄤ欢绫诲瀷">
- <el-option label="鍔犲伐" :value="1" />
- <el-option label="鍒澘鍐疯姱鍒朵綔" :value="2" />
- <el-option label="绠¤矾缁勫" :value="3" />
- <el-option label="缃愪綋杩炴帴鍙婅皟璇�" :value="4" />
- <el-option label="娴嬭瘯鎵撳帇" :value="5" />
- <el-option label="鍏朵粬" :value="6" />
- </el-select>
- </el-form-item>
- <el-form-item label="宸ヨ祫瀹氶" prop="salaryQuota">
- <el-input v-model="formState.salaryQuota" type="number" :step="0.001" />
- </el-form-item>
- <el-form-item label="鏄惁璐ㄦ" prop="isQuality">
- <el-switch v-model="formState.isQuality" :active-value="true" inactive-value="false"/>
- </el-form-item>
- <el-form-item label="澶囨敞" prop="remark">
- <el-input v-model="formState.remark" type="textarea" />
- </el-form-item>
+ >
+ <el-select v-model="formState.type" placeholder="璇烽�夋嫨閮ㄤ欢绫诲瀷">
+ <el-option label="鍔犲伐" :value="1" />
+ <el-option label="鍒澘鍐疯姱鍒朵綔" :value="2" />
+ <el-option label="绠¤矾缁勫" :value="3" />
+ <el-option label="缃愪綋杩炴帴鍙婅皟璇�" :value="4" />
+ <el-option label="娴嬭瘯鎵撳帇" :value="5" />
+ <el-option label="鍏朵粬" :value="6" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="璁″垝宸ユ椂(灏忔椂)"
+ prop="salaryQuota"
+ :rules="[
+ { validator: validateNonNegativeSalaryQuota, trigger: ['blur', 'change'] }
+ ]"
+ >
+ <el-input v-model="formState.salaryQuota" type="number" :step="0.001" :min="0" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璁″垝浜哄憳" prop="plannerId">
+ <el-select
+ v-model="formState.plannerId"
+ placeholder="璇烽�夋嫨璁″垝浜哄憳"
+ clearable
+ filterable
+ style="width: 100%"
+ @change="handlePlannerChange"
+ >
+ <el-option
+ v-for="item in plannerOptions"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.userId"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏄惁璐ㄦ" prop="isQuality">
+ <el-switch v-model="formState.isQuality" :active-value="true" inactive-value="false"/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="formState.remark" type="textarea" />
+ </el-form-item>
+ </el-col>
+ </el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -65,8 +133,10 @@
</template>
<script setup>
-import { ref, computed, getCurrentInstance, watch } from "vue";
+import { ref, computed, getCurrentInstance, watch, onMounted } from "vue";
import {update} from "@/api/productionManagement/productionProcess.js";
+import { modelListPage, productTreeList } from "@/api/basicData/product";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
const props = defineProps({
visible: {
@@ -86,12 +156,19 @@
const formState = ref({
id: props.record.id,
name: props.record.name,
+ productId: props.record.productId,
+ productModelId: props.record.productModelId,
type: props.record.type,
no: props.record.no,
remark: props.record.remark,
salaryQuota: props.record.salaryQuota,
+ plannerId: props.record.plannerId,
+ plannerName: props.record.plannerName,
isQuality: props.record.isQuality,
});
+const productCategoryOptions = ref([]);
+const modelOptions = ref([]);
+const plannerOptions = ref([]);
const isShow = computed({
get() {
@@ -108,10 +185,14 @@
formState.value = {
id: newRecord.id,
name: newRecord.name || '',
+ productId: newRecord.productId,
+ productModelId: newRecord.productModelId,
no: newRecord.no || '',
type: newRecord.type,
remark: newRecord.remark || '',
salaryQuota: newRecord.salaryQuota || '',
+ plannerId: newRecord.plannerId,
+ plannerName: newRecord.plannerName || '',
isQuality: props.record.isQuality,
};
}
@@ -123,16 +204,129 @@
formState.value = {
id: props.record.id,
name: props.record.name || '',
+ productId: props.record.productId,
+ productModelId: props.record.productModelId,
no: props.record.no || '',
type: props.record.type,
remark: props.record.remark || '',
salaryQuota: props.record.salaryQuota || '',
+ plannerId: props.record.plannerId,
+ plannerName: props.record.plannerName || '',
isQuality: props.record.isQuality,
};
}
});
let { proxy } = getCurrentInstance()
+
+const validateNonNegativeSalaryQuota = (rule, value, callback) => {
+ if (value === '' || value === null || value === undefined) {
+ callback(new Error('璇疯緭鍏ヨ鍒掑伐鏃�'));
+ return;
+ }
+ const num = Number(value);
+ if (Number.isNaN(num) || num < 0) {
+ callback(new Error('璁″垝宸ユ椂涓嶈兘灏忎簬0'));
+ return;
+ }
+ callback();
+};
+
+const convertProductTree = list => {
+ return (list || []).map(item => {
+ const children = convertProductTree(item.children || item.childList || []);
+ return {
+ ...item,
+ value: item.id,
+ label: item.name || item.label,
+ children,
+ disabled: children.length > 0,
+ };
+ });
+};
+
+const findNodeById = (nodes, targetId) => {
+ for (const node of nodes || []) {
+ if (String(node.value) === String(targetId)) {
+ return node;
+ }
+ if (node.children && node.children.length > 0) {
+ const found = findNodeById(node.children, targetId);
+ if (found) return found;
+ }
+ }
+ return null;
+};
+
+const findNodeIdByLabel = (nodes, targetLabel) => {
+ for (const node of nodes || []) {
+ if (node.label === targetLabel) {
+ return node.value;
+ }
+ if (node.children && node.children.length > 0) {
+ const found = findNodeIdByLabel(node.children, targetLabel);
+ if (found !== null && found !== undefined) return found;
+ }
+ }
+ return undefined;
+};
+
+const getProductCategoryOptions = async () => {
+ try {
+ const res = await productTreeList();
+ const list = Array.isArray(res) ? res : res?.data || [];
+ productCategoryOptions.value = convertProductTree(list);
+ if (!formState.value.productId && formState.value.name) {
+ formState.value.productId = findNodeIdByLabel(productCategoryOptions.value, formState.value.name);
+ }
+ await getModelOptions(formState.value.productId);
+ } catch (e) {
+ productCategoryOptions.value = [];
+ }
+};
+
+const getModelOptions = async productId => {
+ if (!productId) {
+ modelOptions.value = [];
+ return;
+ }
+ try {
+ const res = await modelListPage({
+ id: productId,
+ current: 1,
+ size: 999,
+ });
+ const records = res?.records || res?.data?.records || [];
+ modelOptions.value = records;
+ } catch (e) {
+ modelOptions.value = [];
+ }
+};
+
+const getPlannerOptions = async () => {
+ try {
+ const res = await userListNoPageByTenantId();
+ plannerOptions.value = res?.data || [];
+ if (!formState.value.plannerId && formState.value.plannerName) {
+ const selectedUser = plannerOptions.value.find(item => item.nickName === formState.value.plannerName);
+ formState.value.plannerId = selectedUser?.userId;
+ }
+ } catch (e) {
+ plannerOptions.value = [];
+ }
+};
+
+const handlePlannerChange = value => {
+ const selectedUser = plannerOptions.value.find(item => String(item.userId) === String(value));
+ formState.value.plannerName = selectedUser?.nickName || '';
+};
+
+const handleProductChange = async value => {
+ const selectedNode = findNodeById(productCategoryOptions.value, value);
+ formState.value.name = selectedNode?.label || '';
+ formState.value.productModelId = undefined;
+ await getModelOptions(value);
+};
const closeModal = () => {
isShow.value = false;
@@ -152,6 +346,11 @@
})
};
+onMounted(() => {
+ getProductCategoryOptions();
+ getPlannerOptions();
+});
+
defineExpose({
closeModal,
handleSubmit,
--
Gitblit v1.9.3