spring
9 天以前 d991871847391f150dd9c5aa9c871a96b75b7880
src/views/qualityManagement/nonconformingManagement/components/formDia.vue
@@ -2,34 +2,16 @@
  <div>
    <el-dialog
        v-model="dialogFormVisible"
        :title="operationType === 'add' ? '新增原材料检验' : '编辑原材料检验'"
        :title="operationType === 'add' ? '新增不合格管理' : '编辑不合格管理'"
        width="70%"
        @close="closeDia"
    >
      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="状态:" prop="inspectState">
              <el-select v-model="form.inspectState">
                <el-option label="待处理" :value="0" />
                <el-option label="已处理" :value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="类别:" prop="inspectType">
              <el-select v-model="form.inspectType">
                <el-option label="原材料检验" :value="0" />
                <el-option label="过程检验" :value="1" />
                <el-option label="出厂检验" :value="2" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="产品名称:" prop="productId">
              <el-tree-select
                  v-if="operationType !== 'edit'"
                  v-model="form.productId"
                  placeholder="请选择"
                  clearable
@@ -39,30 +21,81 @@
                  :render-after-expand="false"
                  style="width: 100%"
              />
              <!-- 编辑态:不依赖下拉选项回显,直接展示文本 -->
              <el-input
                  v-else
                  v-model="form.productName"
                  disabled
                  style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="规格型号:" prop="model">
              <el-input v-model="form.model" placeholder="请输入" clearable/>
            <el-form-item label="规格型号:" prop="productModelId">
              <el-select
                  v-if="operationType !== 'edit'"
                  v-model="form.productModelId"
                  placeholder="请选择"
                  clearable
                  filterable
                  readonly
                  @change="handleChangeModel"
              >
                <el-option
                    v-for="item in modelOptions"
                    :key="item.id"
                    :label="item.model"
                    :value="item.id"
                />
              </el-select>
              <!-- 编辑态:不展示规格型号列表,直接展示文本 -->
              <el-input
                  v-else
                  v-model="form.model"
                  disabled
                  style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="单位:" prop="unit">
              <el-input v-model="form.unit" placeholder="请输入" clearable/>
              <el-input v-model="form.unit" disabled/>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input v-model="form.quantity" placeholder="请输入" clearable/>
            <el-form-item label="批号:" prop="batchNo">
              <el-input style="width: 100%" v-model="form.batchNo" placeholder="请输入" clearable/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检验类型:" prop="checkType">
              <el-select v-model="form.checkType">
                <el-option label="入厂检" :value="0"/>
                <el-option label="车间检" :value="1"/>
                <el-option label="出厂检" :value="2"/>
              </el-select>
            </el-form-item>
          </el-col>
          <!-- <el-col :span="12">
            <el-form-item label="检测结果:" prop="checkResult">
              <el-select v-model="form.checkResult">
                <el-option label="合格" :value="1"/>
                <el-option label="不合格" :value="0"/>
              </el-select>
            </el-form-item>
          </el-col> -->
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="检验员:" prop="checkName">
              <el-input v-model="form.checkName" placeholder="请输入" clearable/>
              <el-select v-model="form.checkName" placeholder="请选择" clearable filterable style="width: 100%">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                           :value="item.nickName"/>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -87,14 +120,25 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="处理结果:" prop="dealResult">
              <el-input v-model="form.dealResult" placeholder="请输入" clearable/>
              <el-select v-model="form.dealResult" placeholder="报废" disabled>
                <el-option
                    :label="item.label"
                    :value="item.value"
                    v-for="item in rejection_handling"
                    :key="item.value"
                    :disabled="String(item.label) !== '报废'"
                />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="处理人:" prop="dealName">
              <el-input v-model="form.dealName" placeholder="请输入" clearable/>
              <el-select v-model="form.dealName" placeholder="请选择" clearable filterable style="width: 100%">
                <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
                           :value="item.nickName"/>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -123,69 +167,216 @@
</template>
<script setup>
import {ref} from "vue";
import {productTreeList} from "@/api/basicData/product.js";
import {ref, reactive, toRefs, getCurrentInstance} from "vue";
import {modelList, productTreeList} from "@/api/basicData/product.js";
import {
  getQualityUnqualifiedInfo,
  qualityUnqualifiedAdd,
  qualityUnqualifiedUpdate
} from "@/api/qualityManagement/nonconformingManagement.js";
import {userListNoPage} from "@/api/system/user.js";
const { proxy } = getCurrentInstance()
const emit = defineEmits(['close'])
const dialogFormVisible = ref(false);
const operationType = ref('')
const { rejection_handling } = proxy.useDict("rejection_handling")
const getScrapDealResultValue = () => {
  const list = rejection_handling?.value || rejection_handling || [];
  const scrap = (list || []).find((it) => String(it?.label ?? "") === "报废");
  return scrap?.value ?? "";
};
const data = reactive({
  form: {
    checkTime: "",
    process: "",
    checkName: "",
    productName: "",
    productId: "",
    productModelId: "",
    model: "",
    unit: "",
    quantity: "",
    checkCompany: "",
    batchNo: "",
    checkType: undefined,
    checkResult: "",
    inspectState: '',
    inspectType: '',
    defectivePhenomena: '',
    dealResult: '',
    dealName: "",
    dealTime: "",
  },
  rules: {
    checkTime: [{ required: false, message: "请输入", trigger: "blur" },],
    process: [{ required: true, message: "请输入", trigger: "blur" }],
    checkName: [{ required: false, message: "请输入", trigger: "blur" }],
    productId: [{ required: true, message: "请输入", trigger: "blur" }],
    model: [{ required: false, message: "请输入", trigger: "blur" }],
    unit: [{ required: false, message: "请输入", trigger: "blur" }],
    quantity: [{ required: true, message: "请输入", trigger: "blur" }],
    checkCompany: [{ required: false, message: "请输入", trigger: "blur" }],
    checkResult: [{ required: false, message: "请输入", trigger: "blur" }],
    checkTime: [{ required: true, message: "请选择检测日期", trigger: "change" }],
    checkName: [{ required: true, message: "请选择检验员", trigger: "change" }],
    productId: [{ required: true, message: "请选择产品名称", trigger: "change" }],
    productModelId: [{ required: true, message: "请选择规格型号", trigger: "change" }],
    batchNo: [{ required: true, message: "请输入批号", trigger: "blur" }],
    checkType: [{ required: true, message: "请选择检验类型", trigger: "change" }],
    checkResult: [{ required: true, message: "请选择检测结果", trigger: "change" }],
    dealResult: [{ required: true, message: "处理结果默认为报废", trigger: "change" }],
    dealTime: [{ required: true, message: "请选择处理日期", trigger: "change" }],
  },
});
const { form, rules } = toRefs(data);
const userList = ref([]);
const productOptions = ref([]);
const modelOptions = ref([])
// 打开弹框
const openDialog = (type, row) => {
const openDialog = async (type, row) => {
  operationType.value = type;
  dialogFormVisible.value = true;
  form.value = {}
  getProductOptions();
  // 编辑态不校验规格型号(prop 仍绑定 productModelId,但编辑态改为文本展示)
  data.rules.productModelId = [
    {
      required: type !== "edit",
      message: "请选择规格型号",
      trigger: "change",
    },
  ];
  // 先加载下拉选项,确保编辑数据可以正确匹配回显
  const userRes = await userListNoPage();
  userList.value = userRes.data || [];
  await getProductOptions();
  // 处理结果默认“报废”,且不可选择其它项
  form.value.dealResult = getScrapDealResultValue();
  if (operationType.value === 'edit') {
    getQualityUnqualifiedInfo(row.id).then(res => {
      form.value = {...res.data}
    })
    const fallback = row || {};
    const res = await getQualityUnqualifiedInfo(fallback.id);
    const { inspectState, ...rest } = res.data || {};
    // 先用列表行数据把“必回显字段”直接填上,避免详情接口字段名不一致导致全空。
    const productName = rest?.productName ?? fallback?.productName;
    const modelName = rest?.model ?? fallback?.model;
    const checkTypeValue = rest?.checkType ?? fallback?.checkType;
    const checkNameValue =
      rest?.checkName ??
      rest?.checkUserName ??
      fallback?.checkName ??
      fallback?.checkUserName;
    const productId =
      rest?.productId ??
      findProductIdByLabel(productOptions.value, productName);
    // 先回填字段(productModelId 需要依赖 modelOptions,稍后再补)
    const normalizedProductId = normalizeProductIdByOptions(productId);
    // 编辑态产品名称展示只展示 label,避免树组件回显依赖 value 匹配
    const productNameLabel =
      rest?.productName ??
      fallback?.productName ??
      findNodeById(productOptions.value, normalizedProductId) ??
      productName;
    form.value = {
      ...rest,
      productName: productNameLabel,
      productId: normalizedProductId,
      productModelId: rest?.productModelId ?? undefined,
      model: rest?.model ?? fallback?.model,
      unit: rest?.unit ?? fallback?.unit,
      batchNo: rest?.batchNo ?? fallback?.batchNo ?? "",
      checkType:
        checkTypeValue === undefined || checkTypeValue === null
          ? undefined
          : Number(checkTypeValue),
      checkName: checkNameValue ?? "",
      checkTime: rest?.checkTime ?? fallback?.checkTime ?? "",
      defectivePhenomena:
        rest?.defectivePhenomena ?? fallback?.defectivePhenomena ?? "",
      dealName: rest?.dealName ?? fallback?.dealName ?? "",
      dealTime: rest?.dealTime ?? fallback?.dealTime ?? "",
      dealResult: getScrapDealResultValue(),
    };
    // 规格型号下拉需要依赖 productId
    await loadModelsForProductId(form.value.productId);
    // 规格型号回显(如详情没给 productModelId,就用 model 名称反查)
    if (!form.value.productModelId) {
      form.value.productModelId = findModelIdByModel(
        modelOptions.value,
        modelName
      );
    }
    // 根据 productModelId 回填 model/unit
    if (form.value.productModelId) {
      form.value.productModelId = normalizeModelIdByOptions(form.value.productModelId);
      handleChangeModel(form.value.productModelId);
    } else if (modelName) {
      // productModelId 仍然拿不到时,至少保证 model/unit 文本回显
      const matched =
        (modelOptions.value || []).find((m) => {
          const model = String(m?.model ?? "");
          const id = String(m?.id ?? "");
          const target = String(modelName ?? "");
          return model === target || id === target;
        }) ?? null;
      if (matched) {
        form.value.model = matched.model ?? form.value.model;
        form.value.unit = matched.unit ?? form.value.unit;
      } else {
        form.value.model = modelName;
      }
    }
  }
}
const getProductOptions = () => {
  productTreeList().then((res) => {
    productOptions.value = convertIdToValue(res);
  });
const getProductOptions = async () => {
  const res = await productTreeList();
  productOptions.value = convertIdToValue(res);
};
const getModels = (value) => {
  form.value.productName = findNodeById(productOptions.value, value);
  form.value.productModelId = undefined;
  form.value.model = "";
  form.value.unit = "";
  modelOptions.value = [];
  modelList({ id: value }).then((res) => {
    modelOptions.value = res;
  })
};
// 编辑模式/或任意需要时:只拉取规格型号列表,不清空已回填的字段
const loadModelsForProductId = async (productId) => {
  if (!productId) return;
  const res = await modelList({ id: productId });
  modelOptions.value = res || [];
  // 让单位/型号等字段保持与当前 productModelId 一致
  if (form.value.productModelId) {
    form.value.productModelId = normalizeModelIdByOptions(form.value.productModelId);
    handleChangeModel(form.value.productModelId);
  }
};
const handleChangeModel = (value) => {
  form.value.model = modelOptions.value.find(item => item.id == value)?.model || '';
  form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || '';
};
// 解决回显时类型不一致导致 el-tree-select / el-select 只显示 value(id)
const normalizeProductIdByOptions = (productId) => {
  if (productId === undefined || productId === null) return productId;
  const target = String(productId);
  const stack = Array.isArray(productOptions.value) ? [...productOptions.value] : [];
  while (stack.length) {
    const node = stack.shift();
    if (node && String(node?.value ?? "") === target) return node?.value;
    if (node?.children?.length) stack.push(...node.children);
  }
  return productId;
};
const normalizeModelIdByOptions = (modelId) => {
  if (modelId === undefined || modelId === null) return modelId;
  const target = String(modelId);
  return (modelOptions.value || []).find((m) => String(m?.id ?? "") === target)?.id ?? modelId;
};
const findNodeById = (nodes, productId) => {
  for (let i = 0; i < nodes.length; i++) {
@@ -200,6 +391,33 @@
    }
  }
  return null; // 没有找到节点,返回null
};
// 根据树节点 label 回填 value(编辑回显兜底用)
const findProductIdByLabel = (nodes, label) => {
  const target = String(label ?? "");
  if (!target) return undefined;
  const stack = Array.isArray(nodes) ? [...nodes] : [];
  while (stack.length) {
    const node = stack.shift();
    if (node && String(node?.label ?? "") === target) return node?.value;
    if (node?.children?.length) stack.push(...node.children);
  }
  return undefined;
};
// 根据规格型号名称反查 id(编辑回显兜底用)
const findModelIdByModel = (models, model) => {
  const target = String(model ?? "");
  if (!target) return undefined;
  return (
    (models || []).find((m) => {
      const mModel = String(m?.model ?? "");
      const mId = String(m?.id ?? "");
      return mModel === target || mId === target;
    })?.id
  );
};
function convertIdToValue(data) {
  return data.map((item) => {
@@ -219,13 +437,15 @@
const submitForm = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      // 状态字段不在表单填写,也不传给后端
      const { inspectState, ...payload } = (form.value || {})
      if (operationType.value === "add") {
        qualityUnqualifiedAdd(form.value).then(res => {
        qualityUnqualifiedAdd(payload).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })
      } else {
        qualityUnqualifiedUpdate(form.value).then(res => {
        qualityUnqualifiedUpdate(payload).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
        })