yyb
昨天 d2fb1300564eaa8166f4db1184c521e468cd2ed3
src/views/productionManagement/productionProcess/Edit.vue
@@ -2,32 +2,125 @@
  <div>
    <el-dialog
        v-model="isShow"
        title="编辑工序"
        width="400"
        title="编辑部件"
        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="salaryQuota">
          <el-input v-model="formState.salaryQuota" type="number" :step="0.001" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formState.remark" type="textarea" />
        </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="[
                {
                required: true,
                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-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">
@@ -40,8 +133,10 @@
</template>
<script setup>
import { ref, computed, getCurrentInstance } 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: {
@@ -61,9 +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() {
@@ -74,7 +179,154 @@
  },
});
// 监听 record 变化,更新表单数据
watch(() => props.record, (newRecord) => {
  if (newRecord && isShow.value) {
    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,
    };
  }
}, { immediate: true, deep: true });
// 监听弹窗打开,重新初始化表单数据
watch(() => props.visible, (visible) => {
  if (visible && props.record) {
    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;
@@ -94,6 +346,11 @@
  })
};
onMounted(() => {
  getProductCategoryOptions();
  getPlannerOptions();
});
defineExpose({
  closeModal,
  handleSubmit,