zhangwencui
7 小时以前 4be9b07e00bea78ae394aec67062b4db9895b565
BOM产品选择弹窗改接口
已修改8个文件
2698 ■■■■ 文件已修改
src/views/basicData/parameterMaintenance/index.vue 118 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ProductSelectDialog.vue 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/New.vue 289 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Subtract.vue 310 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/processRoute/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productStructure/index.vue 824 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/New.vue 279 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionProcess/index.vue 548 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/parameterMaintenance/index.vue
@@ -54,6 +54,7 @@
        <el-form-item label="参数类型"
                      prop="paramType">
          <el-select v-model="formData.paramType"
                     @change="handleParamTypeChange"
                     placeholder="请选择参数类型">
            <el-option label="数值格式"
                       value="1" />
@@ -68,7 +69,6 @@
        <el-form-item label="取值模式"
                      prop="valueMode">
          <el-select v-model="formData.valueMode"
                     @change="handleValueModeChange"
                     placeholder="请选择取值模式">
            <el-option label="单值"
                       value="1" />
@@ -81,23 +81,33 @@
          <el-input v-model="formData.unit"
                    placeholder="请输入单位" />
        </el-form-item>
        <el-form-item label="默认值"
                      v-if="formData.valueMode === '1'"
                      prop="defaultValue">
          <el-input v-model="formData.defaultValue"
                    placeholder="请输入默认值" />
        <el-form-item label="取值格式"
                      v-if="formData.paramType == '1' || formData.paramType == '2'"
                      prop="paramFormat">
          <el-input v-model="formData.paramFormat"
                    placeholder="请输入取值格式" />
        </el-form-item>
        <el-form-item label="最小值"
                      v-if="formData.valueMode === '2'"
                      prop="defaultMin">
          <el-input v-model="formData.defaultMin"
                    placeholder="请输入最小值" />
        <el-form-item label="下拉字典"
                      v-else-if="formData.paramType == '3'"
                      prop="paramFormat">
          <el-select v-model="formData.paramFormat"
                     placeholder="请选择取值模式">
            <el-option v-for="item in dictTypes"
                       :key="item.dictType"
                       :label="item.dictName"
                       :value="item.dictType" />
          </el-select>
        </el-form-item>
        <el-form-item label="最大值"
                      v-if="formData.valueMode === '2'"
                      prop="defaultMax">
          <el-input v-model="formData.defaultMax"
                    placeholder="请输入最大值" />
        <el-form-item label="时间格式"
                      v-else-if="formData.paramType == '4'"
                      prop="paramFormat">
          <el-select v-model="formData.paramFormat"
                     placeholder="请选择取值模式">
            <el-option label="YYYY-MM-DD"
                       value="YYYY-MM-DD" />
            <el-option label="YYYY-MM-DD HH:mm:ss"
                       value="YYYY-MM-DD HH:mm:ss" />
          </el-select>
        </el-form-item>
        <el-form-item label="是否必填"
                      prop="isRequired">
@@ -242,24 +252,14 @@
      prop: "unit",
    },
    {
      label: "默认值",
      prop: "defaultValue",
      label: "取值格式",
      prop: "paramFormat",
      formatData: (val, row) => {
        return row.valueMode === 2 ? "-" : val;
      },
    },
    {
      label: "最小值",
      prop: "defaultMin",
      formatData: (val, row) => {
        return row.valueMode === 1 ? "-" : val;
      },
    },
    {
      label: "最大值",
      prop: "defaultMax",
      formatData: (val, row) => {
        return row.valueMode === 1 ? "-" : val;
        if (row.paramType == "3") {
          const dict = dictTypes.value.find(item => item.dictType === val);
          return dict ? "字典:" + dict.dictName : val;
        }
        return val;
      },
    },
    {
@@ -308,15 +308,6 @@
    size: 10,
    total: 0,
  });
  const handleValueModeChange = val => {
    if (val === "2") {
      formData.defaultMin = "";
      formData.defaultMax = "";
    } else {
      formData.defaultValue = "";
    }
  };
  // 搜索表单
  const searchForm = reactive({
    paramName: "",
@@ -333,9 +324,6 @@
    paramType: "",
    valueMode: "1",
    unit: "",
    defaultValue: "",
    defaultMin: "",
    defaultMax: "",
    isRequired: "0",
    remark: "",
  });
@@ -343,7 +331,20 @@
    paramName: [{ required: true, message: "请输入参数名称", trigger: "blur" }],
    paramType: [{ required: true, message: "请选择参数类型", trigger: "change" }],
    valueMode: [{ required: true, message: "请选择取值模式", trigger: "change" }],
    unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
    unit: [
      {
        required: false,
        message: "请输入单位",
        trigger: "blur",
        validator: (rule, value, callback) => {
          if (formData.paramType === "1" && !value) {
            callback(new Error("数值类型必须填写单位"));
          } else {
            callback();
          }
        },
      },
    ],
  });
  // const productTypes = ref([]);
  const isEdit = ref(false);
@@ -364,13 +365,17 @@
  //   typeName: [{ required: true, message: "请输入类型名称", trigger: "blur" }],
  // });
  // const isProductTypeEdit = ref(false);
  const handleParameterTypeChange = () => {
    if (formData.parameterType === "数值格式") {
      formData.parameterFormat = "#.0000";
    } else if (formData.parameterType === "时间格式") {
      formData.parameterFormat = "YYYY-MM-DD HH:mm:ss";
  const handleParamTypeChange = () => {
    if (formData.paramType === "1") {
      formData.paramFormat = "#.0000";
    } else if (formData.paramType === "4") {
      formData.paramFormat = "YYYY-MM-DD HH:mm:ss";
    } else {
      formData.parameterFormat = "";
      formData.paramFormat = "";
    }
    // 触发单位字段验证
    if (formRef.value) {
      formRef.value.validateField("unit");
    }
  };
  // 产品类型维护按钮点击事件 - 已注释
@@ -491,9 +496,6 @@
    formData.paramType = "";
    formData.valueMode = "1";
    formData.unit = "";
    formData.defaultValue = "";
    formData.defaultMin = "";
    formData.defaultMax = "";
    formData.isRequired = "0";
    formData.remark = "";
    dialogVisible.value = true;
@@ -510,12 +512,6 @@
    formData.valueMode =
      row.valueMode !== undefined ? String(row.valueMode) : "1";
    formData.unit = row.unit || "";
    formData.defaultValue =
      row.defaultValue !== undefined ? String(row.defaultValue) : "";
    formData.defaultMin =
      row.defaultMin !== undefined ? String(row.defaultMin) : "";
    formData.defaultMax =
      row.defaultMax !== undefined ? String(row.defaultMax) : "";
    formData.isRequired =
      row.isRequired !== undefined ? String(row.isRequired) : "0";
    formData.remark = row.remark || "";
src/views/basicData/product/ProductSelectDialog.vue
@@ -1,39 +1,72 @@
<template>
  <el-dialog v-model="visible" title="选择产品" width="900px" destroy-on-close :close-on-click-modal="false">
    <el-form :inline="true" :model="query" class="mb-2">
      <el-form-item label="产品大类">
        <el-input v-model="query.productName" placeholder="输入产品大类" clearable @keyup.enter="onSearch" />
  <el-dialog v-model="visible"
             title="选择产品"
             width="900px"
             destroy-on-close
             :close-on-click-modal="false">
    <el-form :inline="true"
             :model="query"
             class="mb-2">
      <el-form-item label="规格">
        <el-input v-model="query.specification"
                  placeholder="输入规格"
                  clearable
                  @keyup.enter="onSearch" />
      </el-form-item>
      <el-form-item label="型号名称">
        <el-input v-model="query.model" placeholder="输入型号名称" clearable @keyup.enter="onSearch" />
      <el-form-item label="物料编码">
        <el-input v-model="query.materialCode"
                  placeholder="输入物料编码"
                  clearable
                  @keyup.enter="onSearch" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSearch">搜索</el-button>
        <el-button type="primary"
                   @click="onSearch">搜索</el-button>
        <el-button @click="onReset">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- 列表 -->
    <el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id"
      @selection-change="handleSelectionChange" @select="handleSelect">
      <el-table-column type="selection" width="55" />
      <el-table-column type="index" label="序号" width="60" />
      <el-table-column prop="productName" label="产品大类" min-width="160" />
      <el-table-column prop="model" label="型号名称" min-width="200" />
      <el-table-column prop="unit" label="单位" min-width="160" />
    <el-table ref="tableRef"
              v-loading="loading"
              :data="tableData"
              height="420"
              highlight-current-row
              row-key="skuId"
              @selection-change="handleSelectionChange"
              @select="handleSelect">
      <el-table-column type="selection"
                       width="55" />
      <el-table-column type="index"
                       label="序号"
                       width="60" />
      <el-table-column prop="materialName"
                       label="产品名称"
                       min-width="160" />
      <el-table-column prop="materialCode"
                       label="物料编码"
                       min-width="200" />
      <el-table-column prop="specification"
                       label="规格"
                       min-width="200" />
      <el-table-column prop="baseUnit"
                       label="单位"
                       min-width="160" />
    </el-table>
    <div class="mt-3 flex justify-end">
      <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
        v-model:page-size="page.pageSize" v-model:current-page="page.pageNum" :page-sizes="[10, 20, 50, 100]"
        @size-change="onPageChange" @current-change="onPageChange" />
      <el-pagination background
                     layout="total, sizes, prev, pager, next, jumper"
                     :total="total"
                     v-model:page-size="page.pageSize"
                     v-model:current-page="page.pageNum"
                     :page-sizes="[10, 20, 50, 100]"
                     @size-change="onPageChange"
                     @current-change="onPageChange" />
    </div>
    <template #footer>
      <el-button @click="close()">取消</el-button>
      <el-button type="primary" :disabled="multipleSelection.length === 0" @click="onConfirm">
      <el-button type="primary"
                 :disabled="multipleSelection.length === 0"
                 @click="onConfirm">
        确定
      </el-button>
    </template>
@@ -41,140 +74,147 @@
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch, nextTick } from "vue";
import { ElMessage } from "element-plus";
import { productModelList } from '@/api/basicData/productModel'
  import { computed, onMounted, reactive, ref, watch, nextTick } from "vue";
  import { ElMessage } from "element-plus";
  import { modelListPage } from "@/api/basicData/newProduct";
export type ProductRow = {
  id: number;
  productName: string;
  model: string;
  unit?: string;
};
  export type ProductRow = {
    skuId: number;
    specification: string;
    materialCode: string;
    baseUnit?: string;
    materialName?: string;
  };
const props = defineProps<{
  modelValue: boolean;
  single?: boolean; // 是否只能选择一个,默认false(可选择多个)
}>();
  const props = defineProps<{
    modelValue: boolean;
    single?: boolean; // 是否只能选择一个,默认false(可选择多个)
  }>();
const emit = defineEmits(['update:modelValue', 'confirm']);
  const emit = defineEmits(["update:modelValue", "confirm"]);
const visible = computed({
  get: () => props.modelValue,
  set: (v) => emit("update:modelValue", v),
});
  const visible = computed({
    get: () => props.modelValue,
    set: v => emit("update:modelValue", v),
  });
const query = reactive({
  productName: "",
  model: "",
});
  const query = reactive({
    specification: "",
    materialCode: "",
  });
const page = reactive({
  pageNum: 1,
  pageSize: 10,
});
  const page = reactive({
    pageNum: 1,
    pageSize: 10,
  });
const loading = ref(false);
const tableData = ref<ProductRow[]>([]);
const total = ref(0);
const multipleSelection = ref<ProductRow[]>([]);
const tableRef = ref();
  const loading = ref(false);
  const tableData = ref<ProductRow[]>([]);
  const total = ref(0);
  const multipleSelection = ref<ProductRow[]>([]);
  const tableRef = ref();
function close() {
  visible.value = false;
}
const handleSelectionChange = (val: ProductRow[]) => {
  if (props.single && val.length > 1) {
    // 如果限制为单个选择,只保留最后一个选中的
    const lastSelected = val[val.length - 1];
    multipleSelection.value = [lastSelected];
    // 清空表格选中状态,然后重新选中最后一个
    nextTick(() => {
      if (tableRef.value) {
        tableRef.value.clearSelection();
        tableRef.value.toggleRowSelection(lastSelected, true);
      }
    });
  } else {
    multipleSelection.value = val;
  function close() {
    visible.value = false;
  }
}
// 处理单个选择
const handleSelect = (selection: ProductRow[], row: ProductRow) => {
  if (props.single) {
    // 如果限制为单个,清空其他选择,只保留当前行
    if (selection.includes(row)) {
      // 选中当前行时,清空其他选中
      multipleSelection.value = [row];
  const handleSelectionChange = (val: ProductRow[]) => {
    if (props.single && val.length > 1) {
      // 如果限制为单个选择,只保留最后一个选中的
      const lastSelected = val[val.length - 1];
      multipleSelection.value = [lastSelected];
      // 清空表格选中状态,然后重新选中最后一个
      nextTick(() => {
        if (tableRef.value) {
          tableData.value.forEach((item) => {
            if (item.id !== row.id) {
              tableRef.value.toggleRowSelection(item, false);
            }
          });
          tableRef.value.clearSelection();
          tableRef.value.toggleRowSelection(lastSelected, true);
        }
      });
    } else {
      multipleSelection.value = val;
    }
  };
  // 处理单个选择
  const handleSelect = (selection: ProductRow[], row: ProductRow) => {
    if (props.single) {
      // 如果限制为单个,清空其他选择,只保留当前行
      if (selection.includes(row)) {
        // 选中当前行时,清空其他选中
        multipleSelection.value = [row];
        nextTick(() => {
          if (tableRef.value) {
            tableData.value.forEach(item => {
              if (item.skuId !== row.skuId) {
                tableRef.value.toggleRowSelection(item, false);
              }
            });
          }
        });
      }
    }
  };
  function onSearch() {
    page.pageNum = 1;
    loadData();
  }
  function onReset() {
    query.specification = "";
    query.materialCode = "";
    page.pageNum = 1;
    loadData();
  }
  function onPageChange() {
    loadData();
  }
  function onConfirm() {
    if (multipleSelection.value.length === 0) {
      ElMessage.warning("请选择一条产品");
      return;
    }
    if (props.single && multipleSelection.value.length > 1) {
      ElMessage.warning("只能选择一个产品");
      return;
    }
    emit(
      "confirm",
      props.single ? [multipleSelection.value[0]] : multipleSelection.value
    );
    close();
  }
  async function loadData() {
    loading.value = true;
    try {
      multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期
      const res: any = await modelListPage({
        specification: query.specification.trim(),
        materialCode: query.materialCode.trim(),
        current: page.pageNum,
        size: page.pageSize,
      });
      tableData.value = res.data.records;
      total.value = res.data.total;
    } finally {
      loading.value = false;
    }
  }
}
function onSearch() {
  page.pageNum = 1;
  loadData();
}
  // 监听弹窗打开,重置选择
  watch(
    () => props.modelValue,
    visible => {
      if (visible) {
        multipleSelection.value = [];
      }
    }
  );
function onReset() {
  query.productName = "";
  query.model = "";
  page.pageNum = 1;
  loadData();
}
function onPageChange() {
  loadData();
}
function onConfirm() {
  if (multipleSelection.value.length === 0) {
    ElMessage.warning("请选择一条产品");
    return;
  }
  if (props.single && multipleSelection.value.length > 1) {
    ElMessage.warning("只能选择一个产品");
    return;
  }
  emit("confirm", props.single ? [multipleSelection.value[0]] : multipleSelection.value);
  close();
}
async function loadData() {
  loading.value = true;
  try {
    multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期
    const res: any = await productModelList({
      productName: query.productName.trim(),
      model: query.model.trim(),
      current: page.pageNum,
      size: page.pageSize,
    });
    tableData.value = res.records;
    total.value = res.total;
  } finally {
    loading.value = false;
  }
}
// 监听弹窗打开,重置选择
watch(() => props.modelValue, (visible) => {
  if (visible) {
    multipleSelection.value = [];
  }
});
onMounted(() => {
  loadData()
})
  onMounted(() => {
    loadData();
  });
</script>
src/views/inventoryManagement/stockManagement/New.vue
@@ -1,71 +1,67 @@
<template>
  <div>
    <el-dialog
        v-model="isShow"
        title="新增库存"
        width="800"
        @close="closeModal"
    >
      <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
        <el-form-item
            label="产品名称"
            prop="productModelId"
            :rules="[
    <el-dialog v-model="isShow"
               title="新增库存"
               width="800"
               @close="closeModal">
      <el-form label-width="140px"
               :model="formState"
               label-position="top"
               ref="formRef">
        <el-form-item label="产品名称"
                      prop="productModelId"
                      :rules="[
                {
                required: true,
                message: '请选择产品',
                trigger: 'change',
              }
            ]"
        >
          <el-button type="primary" @click="showProductSelectDialog = true">
            ]">
          <el-button type="primary"
                     @click="showProductSelectDialog = true">
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item
            label="规格"
            prop="productModelName"
        >
          <el-input v-model="formState.productModelName"  disabled />
        <el-form-item label="规格"
                      prop="productModelName">
          <el-input v-model="formState.productModelName"
                    disabled />
        </el-form-item>
        <el-form-item
            label="单位"
            prop="unit"
        >
          <el-input v-model="formState.unit"  disabled />
        <el-form-item label="单位"
                      prop="unit">
          <el-input v-model="formState.unit"
                    disabled />
        </el-form-item>
        <el-form-item
            label="库存数量"
            prop="qualitity"
        >
          <el-input-number v-model="formState.qualitity" :step="1" :min="1" style="width: 100%" />
        <el-form-item label="库存数量"
                      prop="qualitity">
          <el-input-number v-model="formState.qualitity"
                           :step="1"
                           :min="1"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item
            v-if="type === 'qualified'"
            label="库存预警数量"
            prop="warnNum"
        >
          <el-input-number v-model="formState.warnNum" :step="1" :min="0" :max="formState.qualitity" style="width: 100%" />
        <el-form-item v-if="type === 'qualified'"
                      label="库存预警数量"
                      prop="warnNum">
          <el-input-number v-model="formState.warnNum"
                           :step="1"
                           :min="0"
                           :max="formState.qualitity"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formState.remark" type="textarea" />
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="formState.remark"
                    type="textarea" />
        </el-form-item>
      </el-form>
      <!-- 产品选择弹窗 -->
      <ProductSelectDialog
          v-model="showProductSelectDialog"
          @confirm="handleProductSelect"
          single
      />
      <ProductSelectDialog v-model="showProductSelectDialog"
                           @confirm="handleProductSelect"
                           single />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button type="primary"
                     @click="handleSubmit">确认</el-button>
          <el-button @click="closeModal">取消</el-button>
        </div>
      </template>
@@ -74,116 +70,115 @@
</template>
<script setup>
import {ref, computed, getCurrentInstance} from "vue";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import {createStockInventory} from "@/api/inventoryManagement/stockInventory.js";
import {createStockUnInventory} from "@/api/inventoryManagement/stockUninventory.js";
  import { ref, computed, getCurrentInstance } from "vue";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import { createStockInventory } from "@/api/inventoryManagement/stockInventory.js";
  import { createStockUnInventory } from "@/api/inventoryManagement/stockUninventory.js";
const props = defineProps({
  visible: {
    type: Boolean,
    required: true,
  },
  const props = defineProps({
    visible: {
      type: Boolean,
      required: true,
    },
  type: {
    type: String,
    required: true,
    default: 'qualified',
  },
});
    type: {
      type: String,
      required: true,
      default: "qualified",
    },
  });
const emit = defineEmits(['update:visible', 'completed']);
  const emit = defineEmits(["update:visible", "completed"]);
// 响应式数据(替代选项式的 data)
const formState = ref({
  productId: undefined,
  productModelId: undefined,
  productName: "",
  productModelName: "",
  unit: "",
  qualitity: 0,
  warnNum: 0,
  remark: '',
});
const isShow = computed({
  get() {
    return props.visible;
  },
  set(val) {
    emit('update:visible', val);
  },
});
const showProductSelectDialog = ref(false);
let { proxy } = getCurrentInstance()
const closeModal = () => {
  // 重置表单数据
  formState.value = {
  // 响应式数据(替代选项式的 data)
  const formState = ref({
    productId: undefined,
    productModelId: undefined,
    productName: "",
    productModelName: "",
    description: '',
    unit: "",
    qualitity: 0,
    warnNum: 0,
    remark: "",
  });
  const isShow = computed({
    get() {
      return props.visible;
    },
    set(val) {
      emit("update:visible", val);
    },
  });
  const showProductSelectDialog = ref(false);
  let { proxy } = getCurrentInstance();
  const closeModal = () => {
    // 重置表单数据
    formState.value = {
      productId: undefined,
      productModelId: undefined,
      productName: "",
      productModelName: "",
      description: "",
    };
    isShow.value = false;
  };
  isShow.value = false;
};
// 产品选择处理
const handleProductSelect = async (products) => {
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
    formState.value.productName = product.productName;
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    showProductSelectDialog.value = false;
    // 触发表单验证更新
    proxy.$refs["formRef"]?.validateField('productModelId');
  }
};
  // 产品选择处理
  const handleProductSelect = async products => {
    if (products && products.length > 0) {
      const product = products[0];
      formState.value.productId = product.skuId;
      formState.value.productName = product.materialName;
      formState.value.productModelName = product.specification;
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      // 验证是否选择了产品和规格
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择产品");
        return;
      }
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择规格");
        return;
      }
      if (props.type === 'qualified') {
        createStockInventory(formState.value).then(res => {
          // 关闭模态框
          isShow.value = false;
          // 告知父组件已完成
          emit('completed');
          proxy.$modal.msgSuccess("提交成功");
        })
      } else {
        createStockUnInventory(formState.value).then(res => {
          // 关闭模态框
          isShow.value = false;
          // 告知父组件已完成
          emit('completed');
          proxy.$modal.msgSuccess("提交成功");
        })
      }
      formState.value.productModelId = product.skuId;
      formState.value.unit = product.baseUnit;
      showProductSelectDialog.value = false;
      // 触发表单验证更新
      proxy.$refs["formRef"]?.validateField("productModelId");
    }
  })
};
  };
  const handleSubmit = () => {
    proxy.$refs["formRef"].validate(valid => {
      if (valid) {
        // 验证是否选择了产品和规格
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择产品");
          return;
        }
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择规格");
          return;
        }
        if (props.type === "qualified") {
          createStockInventory(formState.value).then(res => {
            // 关闭模态框
            isShow.value = false;
            // 告知父组件已完成
            emit("completed");
            proxy.$modal.msgSuccess("提交成功");
          });
        } else {
          createStockUnInventory(formState.value).then(res => {
            // 关闭模态框
            isShow.value = false;
            // 告知父组件已完成
            emit("completed");
            proxy.$modal.msgSuccess("提交成功");
          });
        }
      }
    });
  };
defineExpose({
  closeModal,
  handleSubmit,
  isShow,
});
  defineExpose({
    closeModal,
    handleSubmit,
    isShow,
  });
</script>
src/views/inventoryManagement/stockManagement/Subtract.vue
@@ -1,63 +1,60 @@
<template>
  <div>
    <el-dialog
        v-model="isShow"
        title="领用"
        width="800"
        @close="closeModal"
    >
      <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
        <el-form-item
            label="产品名称"
            prop="productModelId"
            :rules="[
    <el-dialog v-model="isShow"
               title="领用"
               width="800"
               @close="closeModal">
      <el-form label-width="140px"
               :model="formState"
               label-position="top"
               ref="formRef">
        <el-form-item label="产品名称"
                      prop="productModelId"
                      :rules="[
                {
                required: true,
                message: '请选择产品',
                trigger: 'change',
              }
            ]"
        >
          <el-button type="primary" @click="showProductSelectDialog = true" disabled>
            ]">
          <el-button type="primary"
                     @click="showProductSelectDialog = true"
                     disabled>
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item
            label="规格"
            prop="productModelName"
        >
          <el-input v-model="formState.model"  disabled />
        <el-form-item label="规格"
                      prop="productModelName">
          <el-input v-model="formState.model"
                    disabled />
        </el-form-item>
        <el-form-item
            label="单位"
            prop="unit"
        >
          <el-input v-model="formState.unit"  disabled />
        <el-form-item label="单位"
                      prop="unit">
          <el-input v-model="formState.unit"
                    disabled />
        </el-form-item>
        <el-form-item
            label="数量"
            prop="qualitity"
        >
          <el-input-number v-model="formState.qualitity" :step="1" :min="1" :max="maxQuality" style="width: 100%" />
        <el-form-item label="数量"
                      prop="qualitity">
          <el-input-number v-model="formState.qualitity"
                           :step="1"
                           :min="1"
                           :max="maxQuality"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formState.remark" type="textarea" />
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="formState.remark"
                    type="textarea" />
        </el-form-item>
      </el-form>
      <!-- 产品选择弹窗 -->
      <ProductSelectDialog
          v-model="showProductSelectDialog"
          @confirm="handleProductSelect"
          single
      />
      <ProductSelectDialog v-model="showProductSelectDialog"
                           @confirm="handleProductSelect"
                           single />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button type="primary"
                     @click="handleSubmit">确认</el-button>
          <el-button @click="closeModal">取消</el-button>
        </div>
      </template>
@@ -66,134 +63,133 @@
</template>
<script setup>
import {ref, computed, getCurrentInstance} from "vue";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import {subtractStockInventory} from "@/api/inventoryManagement/stockInventory.js";
import {subtractStockUnInventory} from "@/api/inventoryManagement/stockUninventory.js";
  import { ref, computed, getCurrentInstance } from "vue";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import { subtractStockInventory } from "@/api/inventoryManagement/stockInventory.js";
  import { subtractStockUnInventory } from "@/api/inventoryManagement/stockUninventory.js";
const props = defineProps({
  visible: {
    type: Boolean,
    required: true,
  },
  record: {
    type: Object,
    default: () => {},
  },
  type: {
    type: String,
    required: true,
    default: 'qualified',
  },
});
  const props = defineProps({
    visible: {
      type: Boolean,
      required: true,
    },
    record: {
      type: Object,
      default: () => {},
    },
    type: {
      type: String,
      required: true,
      default: "qualified",
    },
  });
const emit = defineEmits(['update:visible', 'completed']);
  const emit = defineEmits(["update:visible", "completed"]);
onMounted(() => {
  initFormData()
})
  onMounted(() => {
    initFormData();
  });
const maxQuality = computed(() => {
  return props.record.unLockedQuantity ? props.record.unLockedQuantity :  0;
})
  const maxQuality = computed(() => {
    return props.record.unLockedQuantity ? props.record.unLockedQuantity : 0;
  });
const initFormData = () => {
  if (props.record) {
    formState.value = {
      ...props.record,
  const initFormData = () => {
    if (props.record) {
      formState.value = {
        ...props.record,
      };
    }
  }
}
  };
// 响应式数据(替代选项式的 data)
const formState = ref({
  productId: undefined,
  productModelId: undefined,
  productName: "",
  model: "",
  unit: "",
  qualitity: 0,
  remark: '',
});
const isShow = computed({
  get() {
    return props.visible;
  },
  set(val) {
    emit('update:visible', val);
  },
});
const showProductSelectDialog = ref(false);
let { proxy } = getCurrentInstance()
const closeModal = () => {
  // 重置表单数据
  formState.value = {
  // 响应式数据(替代选项式的 data)
  const formState = ref({
    productId: undefined,
    productModelId: undefined,
    productName: "",
    productModelName: "",
    description: '',
    model: "",
    unit: "",
    qualitity: 0,
    remark: "",
  });
  const isShow = computed({
    get() {
      return props.visible;
    },
    set(val) {
      emit("update:visible", val);
    },
  });
  const showProductSelectDialog = ref(false);
  let { proxy } = getCurrentInstance();
  const closeModal = () => {
    // 重置表单数据
    formState.value = {
      productId: undefined,
      productModelId: undefined,
      productName: "",
      productModelName: "",
      description: "",
    };
    isShow.value = false;
  };
  isShow.value = false;
};
// 产品选择处理
const handleProductSelect = async (products) => {
  if (products && products.length > 0) {
    const product = products[0];
    console.log(product)
    formState.value.productId = product.productId;
    formState.value.productName = product.productName;
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    showProductSelectDialog.value = false;
    // 触发表单验证更新
    proxy.$refs["formRef"]?.validateField('productModelId');
  }
};
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      // 验证是否选择了产品和规格
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择产品");
        return;
      }
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择规格");
        return;
      }
      if (props.type === 'qualified') {
        subtractStockInventory(formState.value).then(res => {
          // 关闭模态框
          isShow.value = false;
          // 告知父组件已完成
          emit('completed');
          proxy.$modal.msgSuccess("提交成功");
        })
      } else {
        subtractStockUnInventory(formState.value).then(res => {
          // 关闭模态框
          isShow.value = false;
          // 告知父组件已完成
          emit('completed');
          proxy.$modal.msgSuccess("提交成功");
        })
      }
  // 产品选择处理
  const handleProductSelect = async products => {
    if (products && products.length > 0) {
      const product = products[0];
      console.log(product);
      formState.value.productId = product.skuId;
      formState.value.productName = product.materialName;
      formState.value.productModelName = product.specification;
      formState.value.productModelId = product.skuId;
      formState.value.unit = product.baseUnit;
      showProductSelectDialog.value = false;
      // 触发表单验证更新
      proxy.$refs["formRef"]?.validateField("productModelId");
    }
  })
};
  };
  const handleSubmit = () => {
    proxy.$refs["formRef"].validate(valid => {
      if (valid) {
        // 验证是否选择了产品和规格
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择产品");
          return;
        }
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择规格");
          return;
        }
        if (props.type === "qualified") {
          subtractStockInventory(formState.value).then(res => {
            // 关闭模态框
            isShow.value = false;
            // 告知父组件已完成
            emit("completed");
            proxy.$modal.msgSuccess("提交成功");
          });
        } else {
          subtractStockUnInventory(formState.value).then(res => {
            // 关闭模态框
            isShow.value = false;
            // 告知父组件已完成
            emit("completed");
            proxy.$modal.msgSuccess("提交成功");
          });
        }
      }
    });
  };
defineExpose({
  closeModal,
  handleSubmit,
  isShow,
});
  defineExpose({
    closeModal,
    handleSubmit,
    isShow,
  });
</script>
src/views/productionManagement/processRoute/index.vue
@@ -783,7 +783,7 @@
      const product = products[0];
      // 先查询BOM列表(必选)
      try {
        const res = await getByModel(product.id);
        const res = await getByModel(product.skuId);
        // 处理返回的BOM数据:可能是数组、对象或包含data字段
        let bomList = [];
        if (Array.isArray(res)) {
@@ -795,9 +795,9 @@
        }
        if (bomList.length > 0) {
          routeForm.productModelId = product.id;
          routeForm.productName = product.productName;
          routeForm.productModelName = product.model;
          routeForm.productModelId = product.skuId;
          routeForm.productName = product.materialName;
          routeForm.productModelName = product.specification;
          routeForm.bomId = undefined; // 重置BOM选择
          bomOptions.value = bomList;
          showProductSelectDialog.value = false;
src/views/productionManagement/productStructure/index.vue
@@ -1,380 +1,483 @@
<template>
  <div class="app-container">
    <div style="text-align: right; margin-bottom: 10px;">
      <el-button type="info" plain icon="Upload" @click="handleImport"
        v-hasPermi="['product:bom:import']">导入</el-button>
      <el-button type="warning" plain icon="Download" @click="handleExport" :disabled="selectedRows.length !== 1"
        v-hasPermi="['product:bom:export']">导出</el-button>
      <el-button type="primary" @click="handleAdd">新增</el-button>
      <el-button type="danger" plain @click="handleBatchDelete" :disabled="selectedRows.length === 0">删除</el-button>
      <el-button type="info"
                 plain
                 icon="Upload"
                 @click="handleImport"
                 v-hasPermi="['product:bom:import']">导入</el-button>
      <el-button type="warning"
                 plain
                 icon="Download"
                 @click="handleExport"
                 :disabled="selectedRows.length !== 1"
                 v-hasPermi="['product:bom:export']">导出</el-button>
      <el-button type="primary"
                 @click="handleAdd">新增</el-button>
      <el-button type="danger"
                 plain
                 @click="handleBatchDelete"
                 :disabled="selectedRows.length === 0">删除</el-button>
    </div>
    <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true"
      @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination">
    <PIMTable rowKey="id"
              :column="tableColumn"
              :tableData="tableData"
              :page="page"
              :isSelection="true"
              @selection-change="handleSelectionChange"
              :tableLoading="tableLoading"
              @pagination="pagination">
      <template #detail="{ row }">
        <el-button type="primary" text @click="showDetail(row)">{{ row.bomNo }}
        <el-button type="primary"
                   text
                   @click="showDetail(row)">{{ row.bomNo }}
        </el-button>
      </template>
    </PIMTable>
    <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow" />
    <StructureEdit v-if="showEdit"
                   v-model:show-model="showEdit"
                   :record="currentRow" />
    <!-- 新增/编辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="operationType === 'add' ? '新增BOM' : '编辑BOM'" width="600px"
      @close="closeDialog">
      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
        <el-form-item label="产品名称" prop="productModelId">
          <el-button type="primary" @click="showProductSelectDialog = true">
    <el-dialog v-model="dialogVisible"
               :title="operationType === 'add' ? '新增BOM' : '编辑BOM'"
               width="600px"
               @close="closeDialog">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="120px">
        <el-form-item label="产品名称"
                      prop="productModelId">
          <el-button type="primary"
                     @click="showProductSelectDialog = true">
            {{ form.productName || '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item label="版本号" prop="version">
          <el-input v-model="form.version" placeholder="请输入版本号" clearable />
        <el-form-item label="版本号"
                      prop="version">
          <el-input v-model="form.version"
                    placeholder="请输入版本号"
                    clearable />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="form.remark"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入备注"
                    clearable />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="closeDialog">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
        <el-button type="primary"
                   @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>
    <!-- 产品选择弹窗 -->
    <ProductSelectDialog v-model="showProductSelectDialog" @confirm="handleProductSelect" single />
    <ProductSelectDialog v-model="showProductSelectDialog"
                         @confirm="handleProductSelect"
                         single />
    <!-- BOM导入对话框 -->
    <ImportDialog ref="uploadRef" v-model="upload.open" :title="upload.title" :action="upload.url"
      :headers="upload.headers" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress"
      :on-success="handleFileSuccess" :show-download-template="true" @confirm="submitFileForm"
      @download-template="handleDownloadTemplate" @close="handleImportClose" />
    <ImportDialog ref="uploadRef"
                  v-model="upload.open"
                  :title="upload.title"
                  :action="upload.url"
                  :headers="upload.headers"
                  :disabled="upload.isUploading"
                  :on-progress="handleFileUploadProgress"
                  :on-success="handleFileSuccess"
                  :show-download-template="true"
                  @confirm="submitFileForm"
                  @download-template="handleDownloadTemplate"
                  @close="handleImportClose" />
  </div>
</template>
<script setup>
import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from "vue";
import { getToken } from "@/utils/auth";
import { listPage, add, update, batchDelete, exportBom, downloadTemplate } from "@/api/productionManagement/productBom.js";
import { useRouter } from 'vue-router'
import { ElMessageBox } from 'element-plus'
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import ImportDialog from "@/components/Dialog/ImportDialog.vue";
  import {
    ref,
    reactive,
    toRefs,
    onMounted,
    getCurrentInstance,
    defineAsyncComponent,
  } from "vue";
  import { getToken } from "@/utils/auth";
  import {
    listPage,
    add,
    update,
    batchDelete,
    exportBom,
    downloadTemplate,
  } from "@/api/productionManagement/productBom.js";
  import { useRouter } from "vue-router";
  import { ElMessageBox } from "element-plus";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import ImportDialog from "@/components/Dialog/ImportDialog.vue";
const router = useRouter()
const { proxy } = getCurrentInstance()
const StructureEdit = defineAsyncComponent(() => import('@/views/productionManagement/productStructure/StructureEdit.vue'))
  const router = useRouter();
  const { proxy } = getCurrentInstance();
  const StructureEdit = defineAsyncComponent(() =>
    import("@/views/productionManagement/productStructure/StructureEdit.vue")
  );
const tableColumn = ref([
  {
    label: "BOM编号",
    prop: "bomNo",
    dataType: 'slot',
    slot: "detail",
    minWidth: 140
  },
  {
    label: "产品名称",
    prop: "productName",
  const tableColumn = ref([
    {
      label: "BOM编号",
      prop: "bomNo",
      dataType: "slot",
      slot: "detail",
      minWidth: 140,
    },
    {
      label: "产品名称",
      prop: "productName",
    minWidth: 160
  },
  {
    label: "规格型号",
    prop: "productModelName",
    minWidth: 140
  },
  {
    label: "版本号",
    prop: "version",
    width: 100
  },
  {
    label: "备注",
    prop: "remark",
    minWidth: 160
  },
  {
    dataType: "action",
    label: "操作",
    align: "center",
    fixed: "right",
    width: 150,
    operation: [
      {
        name: "编辑",
        type: "text",
        clickFun: (row) => {
          handleEdit(row)
        }
      },
      {
        name: "删除",
        type: "danger",
        link: true,
        clickFun: (row) => {
          handleDelete(row)
        }
      }
    ]
  }
]);
      minWidth: 160,
    },
    {
      label: "规格型号",
      prop: "productModelName",
      minWidth: 140,
    },
    {
      label: "版本号",
      prop: "version",
      width: 100,
    },
    {
      label: "备注",
      prop: "remark",
      minWidth: 160,
    },
    {
      dataType: "action",
      label: "操作",
      align: "center",
      fixed: "right",
      width: 150,
      operation: [
        {
          name: "编辑",
          type: "text",
          clickFun: row => {
            handleEdit(row);
          },
        },
        {
          name: "删除",
          type: "danger",
          link: true,
          clickFun: row => {
            handleDelete(row);
          },
        },
      ],
    },
  ]);
const tableData = ref([]);
const tableLoading = ref(false);
const showEdit = ref(false);
const selectedRows = ref([]);
const currentRow = ref({});
const dialogVisible = ref(false);
const operationType = ref('add'); // add | edit
const formRef = ref(null);
const showProductSelectDialog = ref(false);
  const tableData = ref([]);
  const tableLoading = ref(false);
  const showEdit = ref(false);
  const selectedRows = ref([]);
  const currentRow = ref({});
  const dialogVisible = ref(false);
  const operationType = ref("add"); // add | edit
  const formRef = ref(null);
  const showProductSelectDialog = ref(false);
//  BOM导入参数
const upload = reactive({
  // 是否显示弹出层(BOM导入)
  open: false,
  // 弹出层标题(BOM导入)
  title: "",
  // 是否禁用上传
  isUploading: false,
  // 设置上传的请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + "/productBom/uploadBom"
});
const page = reactive({
  current: 1,
  size: 10,
  total: 0,
});
const data = reactive({
  form: {
    id: undefined,
    productName: "",
    productModelName: "",
    productModelId: "",
    remark: "",
    version: ""
  },
  rules: {
    productModelId: [{ required: true, message: "请选择产品", trigger: "change" }],
    version: [{ required: true, message: "请输入版本号", trigger: "blur" }]
  }
});
const { form, rules } = toRefs(data);
// 表格选择数据
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
// 分页
const pagination = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
// 查询列表
const getList = () => {
  tableLoading.value = true;
  listPage({
    current: page.current,
    size: page.size,
  })
    .then((res) => {
      const records = res?.data?.records || [];
      tableData.value = records;
      page.total = res?.data?.total || 0;
    })
    .catch((err) => {
      console.error("获取列表失败:", err);
    })
    .finally(() => {
      tableLoading.value = false;
    });
};
// 新增
const handleAdd = () => {
  operationType.value = 'add';
  Object.assign(form.value, {
    id: undefined,
    productName: "",
    productModelName: "",
    productModelId: "",
    remark: "",
    version: ""
  //  BOM导入参数
  const upload = reactive({
    // 是否显示弹出层(BOM导入)
    open: false,
    // 弹出层标题(BOM导入)
    title: "",
    // 是否禁用上传
    isUploading: false,
    // 设置上传的请求头部
    headers: { Authorization: "Bearer " + getToken() },
    // 上传的地址
    url: import.meta.env.VITE_APP_BASE_API + "/productBom/uploadBom",
  });
  dialogVisible.value = true;
};
// 编辑
const handleEdit = (row) => {
  operationType.value = 'edit';
  Object.assign(form.value, {
    id: row.id,
    productName: row.productName || "",
    productModelName: row.productModelName || "",
    productModelId: row.productModelId || "",
    remark: row.remark || "",
    version: row.version || ""
  const page = reactive({
    current: 1,
    size: 10,
    total: 0,
  });
  dialogVisible.value = true;
};
// 删除(单条)
const handleDelete = (row) => {
  ElMessageBox.confirm('确认删除该BOM?', '提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      batchDelete([row.id])
        .then(() => {
          proxy.$modal.msgSuccess('删除成功');
          getList();
        })
        .catch(() => {
          proxy.$modal.msgError('删除失败');
        });
    })
    .catch(() => { });
};
// 批量删除
const handleBatchDelete = () => {
  if (!selectedRows.value.length) {
    proxy.$modal.msgWarning('请选择数据');
    return;
  }
  const ids = selectedRows.value.map(item => item.id);
  ElMessageBox.confirm('选中的内容将被删除,是否确认删除?', '删除提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      batchDelete(ids)
        .then(() => {
          proxy.$modal.msgSuccess('删除成功');
          getList();
        })
        .catch(() => {
          proxy.$modal.msgError('删除失败');
        });
    })
    .catch(() => { });
};
// 产品选择
const handleProductSelect = (products) => {
  if (products && products.length > 0) {
    const product = products[0];
    form.value.productModelId = product.id;
    form.value.productName = product.productName;
    form.value.productModelName = product.model;
  }
  showProductSelectDialog.value = false;
};
// 提交表单
const handleSubmit = () => {
  formRef.value.validate((valid) => {
    if (valid) {
      const payload = { ...form.value };
      if (operationType.value === 'add') {
        add(payload)
          .then(() => {
            proxy.$modal.msgSuccess('新增成功');
            closeDialog();
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError('新增失败');
          });
      } else {
        update(payload)
          .then(() => {
            proxy.$modal.msgSuccess('修改成功');
            closeDialog();
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError('修改失败');
          });
      }
    }
  const data = reactive({
    form: {
      id: undefined,
      productName: "",
      productModelName: "",
      productModelId: "",
      remark: "",
      version: "",
    },
    rules: {
      productModelId: [
        { required: true, message: "请选择产品", trigger: "change" },
      ],
      version: [{ required: true, message: "请输入版本号", trigger: "blur" }],
    },
  });
};
// 关闭弹窗
const closeDialog = () => {
  dialogVisible.value = false;
  formRef.value?.resetFields();
};
  const { form, rules } = toRefs(data);
//  导入按钮操作
const handleImport = () => {
  upload.title = "BOM导入";
  upload.open = true;
};
  // 表格选择数据
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
// 关闭导入对话框时清除文件
const handleImportClose = () => {
  proxy.$refs["uploadRef"].clearFiles();
};
//  文件上传中处理
const handleFileUploadProgress = (event, file, fileList) => {
  upload.isUploading = true;
};
//  文件上传成功处理
const handleFileSuccess = (response, file, fileList) => {
  upload.open = false;
  upload.isUploading = false;
  proxy.$refs["uploadRef"].clearFiles();
  if (response.code === 200) {
    proxy.$modal.msgSuccess(response.msg || "导入成功");
  // 分页
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  } else {
    proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
  }
};
  };
// 提交上传文件
const submitFileForm = () => {
  proxy.$refs["uploadRef"].submit();
};
  // 查询列表
  const getList = () => {
    tableLoading.value = true;
    listPage({
      current: page.current,
      size: page.size,
    })
      .then(res => {
        const records = res?.data?.records || [];
        tableData.value = records;
        page.total = res?.data?.total || 0;
      })
      .catch(err => {
        console.error("获取列表失败:", err);
      })
      .finally(() => {
        tableLoading.value = false;
      });
  };
//  导出按钮操作
const handleExport = () => {
  if (selectedRows.value.length !== 1) {
    proxy.$modal.msgWarning("请选择一条数据进行导出");
    return;
  }
  // 新增
  const handleAdd = () => {
    operationType.value = "add";
    Object.assign(form.value, {
      id: undefined,
      productName: "",
      productModelName: "",
      productModelId: "",
      remark: "",
      version: "",
    });
    dialogVisible.value = true;
  };
  const bomId = selectedRows.value[0].id;
  const fileName = `BOM_${selectedRows.value[0].bomNo || bomId}.xlsx`;
  // 编辑
  const handleEdit = row => {
    operationType.value = "edit";
    Object.assign(form.value, {
      id: row.id,
      productName: row.productName || "",
      productModelName: row.productModelName || "",
      productModelId: row.productModelId || "",
      remark: row.remark || "",
      version: row.version || "",
    });
    dialogVisible.value = true;
  };
  exportBom(bomId).then(res => {
    // 返回的数据是否为空
    if (!res) {
      proxy.$modal.msgError("导出失败,返回数据为空");
  // 删除(单条)
  const handleDelete = row => {
    ElMessageBox.confirm("确认删除该BOM?", "提示", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        batchDelete([row.id])
          .then(() => {
            proxy.$modal.msgSuccess("删除成功");
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError("删除失败");
          });
      })
      .catch(() => {});
  };
  // 批量删除
  const handleBatchDelete = () => {
    if (!selectedRows.value.length) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    const ids = selectedRows.value.map(item => item.id);
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        batchDelete(ids)
          .then(() => {
            proxy.$modal.msgSuccess("删除成功");
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError("删除失败");
          });
      })
      .catch(() => {});
  };
  // 产品选择
  const handleProductSelect = products => {
    if (products && products.length > 0) {
      const product = products[0];
      form.value.productModelId = product.skuId;
      form.value.productName = product.materialName;
      form.value.productModelName = product.specification;
    }
    showProductSelectDialog.value = false;
  };
  // 提交表单
  const handleSubmit = () => {
    formRef.value.validate(valid => {
      if (valid) {
        const payload = { ...form.value };
        if (operationType.value === "add") {
          add(payload)
            .then(() => {
              proxy.$modal.msgSuccess("新增成功");
              closeDialog();
              getList();
            })
            .catch(() => {
              proxy.$modal.msgError("新增失败");
            });
        } else {
          update(payload)
            .then(() => {
              proxy.$modal.msgSuccess("修改成功");
              closeDialog();
              getList();
            })
            .catch(() => {
              proxy.$modal.msgError("修改失败");
            });
        }
      }
    });
  };
  // 关闭弹窗
  const closeDialog = () => {
    dialogVisible.value = false;
    formRef.value?.resetFields();
  };
  //  导入按钮操作
  const handleImport = () => {
    upload.title = "BOM导入";
    upload.open = true;
  };
  // 关闭导入对话框时清除文件
  const handleImportClose = () => {
    proxy.$refs["uploadRef"].clearFiles();
  };
  //  文件上传中处理
  const handleFileUploadProgress = (event, file, fileList) => {
    upload.isUploading = true;
  };
  //  文件上传成功处理
  const handleFileSuccess = (response, file, fileList) => {
    upload.open = false;
    upload.isUploading = false;
    proxy.$refs["uploadRef"].clearFiles();
    if (response.code === 200) {
      proxy.$modal.msgSuccess(response.msg || "导入成功");
      getList();
    } else {
      proxy.$alert(
        "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
          response.msg +
          "</div>",
        "导入结果",
        { dangerouslyUseHTMLString: true }
      );
    }
  };
  // 提交上传文件
  const submitFileForm = () => {
    proxy.$refs["uploadRef"].submit();
  };
  //  导出按钮操作
  const handleExport = () => {
    if (selectedRows.value.length !== 1) {
      proxy.$modal.msgWarning("请选择一条数据进行导出");
      return;
    }
    const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const downloadElement = document.createElement('a');
    const bomId = selectedRows.value[0].id;
    const fileName = `BOM_${selectedRows.value[0].bomNo || bomId}.xlsx`;
    exportBom(bomId)
      .then(res => {
        // 返回的数据是否为空
        if (!res) {
          proxy.$modal.msgError("导出失败,返回数据为空");
          return;
        }
        const blob = new Blob([res], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        const downloadElement = document.createElement("a");
        const href = window.URL.createObjectURL(blob);
        downloadElement.style.display = "none";
        downloadElement.href = href;
        downloadElement.download = fileName;
        document.body.appendChild(downloadElement);
        downloadElement.click();
        document.body.removeChild(downloadElement);
        window.URL.revokeObjectURL(href);
        proxy.$modal.msgSuccess("导出成功");
      })
      .catch(err => {
        console.error("导出异常:", err);
        proxy.$modal.msgError("系统异常,导出失败");
      });
  };
  //  下载模板
  const handleDownloadTemplate = async () => {
    const res = await downloadTemplate();
    // 返回的数据是否为空
    if (!res) {
      proxy.$modal.msgError("下载失败,返回数据为空");
      return;
    }
    const blob = new Blob([res], {
      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    });
    const downloadElement = document.createElement("a");
    const href = window.URL.createObjectURL(blob);
    downloadElement.style.display = 'none';
    downloadElement.href = href;
    downloadElement.download = fileName;
    downloadElement.download = "BOM模板.xlsx";
    document.body.appendChild(downloadElement);
    downloadElement.click();
@@ -382,52 +485,23 @@
    document.body.removeChild(downloadElement);
    window.URL.revokeObjectURL(href);
    proxy.$modal.msgSuccess("导出成功");
  }).catch(err => {
    console.error("导出异常:", err);
    proxy.$modal.msgError("系统异常,导出失败");
    proxy.$modal.msgSuccess("下载成功");
  };
  // 查看详情
  const showDetail = row => {
    router.push({
      path: "/productionManagement/productStructureDetail",
      query: {
        id: row.id,
        bomNo: row.bomNo || "",
        productName: row.productName || "",
        productModelName: row.productModelName || "",
      },
    });
  };
  onMounted(() => {
    getList();
  });
};
//  下载模板
const handleDownloadTemplate = async () => {
  const res = await downloadTemplate();
  // 返回的数据是否为空
  if (!res) {
    proxy.$modal.msgError("下载失败,返回数据为空");
    return;
  }
  const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
  const downloadElement = document.createElement('a');
  const href = window.URL.createObjectURL(blob);
  downloadElement.href = href;
  downloadElement.download = "BOM模板.xlsx";
  document.body.appendChild(downloadElement);
  downloadElement.click();
  document.body.removeChild(downloadElement);
  window.URL.revokeObjectURL(href);
  proxy.$modal.msgSuccess("下载成功");
};
// 查看详情
const showDetail = (row) => {
  router.push({
    path: '/productionManagement/productStructureDetail',
    query: {
      id: row.id,
      bomNo: row.bomNo || '',
      productName: row.productName || '',
      productModelName: row.productModelName || ''
    }
  });
};
onMounted(() => {
  getList();
});
</script>
src/views/productionManagement/productionOrder/New.vue
@@ -1,42 +1,37 @@
<template>
  <div>
    <el-dialog
        v-model="isShow"
        title="新增生产订单"
        width="800"
        @close="closeModal"
    >
      <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
        <el-form-item
            label="产品名称"
            prop="productModelId"
            :rules="[
    <el-dialog v-model="isShow"
               title="新增生产订单"
               width="800"
               @close="closeModal">
      <el-form label-width="140px"
               :model="formState"
               label-position="top"
               ref="formRef">
        <el-form-item label="产品名称"
                      prop="productModelId"
                      :rules="[
                {
                required: true,
                message: '请选择产品',
                trigger: 'change',
              }
            ]"
        >
          <el-button type="primary" @click="showProductSelectDialog = true">
            ]">
          <el-button type="primary"
                     @click="showProductSelectDialog = true">
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item
            label="规格"
            prop="productModelName"
        >
          <el-input v-model="formState.productModelName"  disabled />
        <el-form-item label="规格"
                      prop="productModelName">
          <el-input v-model="formState.productModelName"
                    disabled />
        </el-form-item>
        <el-form-item
            label="单位"
            prop="unit"
        >
          <el-input v-model="formState.unit"  disabled />
        <el-form-item label="单位"
                      prop="unit">
          <el-input v-model="formState.unit"
                    disabled />
        </el-form-item>
        <el-form-item label="工艺路线">
          <el-select v-model="formState.routeId"
                     placeholder="请选择工艺路线"
@@ -48,24 +43,22 @@
                       :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item
            label="需求数量"
            prop="quantity"
        >
          <el-input-number v-model="formState.quantity" :step="1" :min="1" style="width: 100%" />
        <el-form-item label="需求数量"
                      prop="quantity">
          <el-input-number v-model="formState.quantity"
                           :step="1"
                           :min="1"
                           style="width: 100%" />
        </el-form-item>
      </el-form>
      <!-- 产品选择弹窗 -->
      <ProductSelectDialog
          v-model="showProductSelectDialog"
          @confirm="handleProductSelect"
          single
      />
      <ProductSelectDialog v-model="showProductSelectDialog"
                           @confirm="handleProductSelect"
                           single />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button type="primary"
                     @click="handleSubmit">确认</el-button>
          <el-button @click="closeModal">取消</el-button>
        </div>
      </template>
@@ -74,119 +67,123 @@
</template>
<script setup>
import {ref, computed, getCurrentInstance} from "vue";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import {addProductOrder, listProcessRoute} from "@/api/productionManagement/productionOrder.js";
  import { ref, computed, getCurrentInstance } from "vue";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import {
    addProductOrder,
    listProcessRoute,
  } from "@/api/productionManagement/productionOrder.js";
const props = defineProps({
  visible: {
    type: Boolean,
    required: true,
  },
  const props = defineProps({
    visible: {
      type: Boolean,
      required: true,
    },
  type: {
    type: String,
    required: true,
    default: 'qualified',
  },
});
    type: {
      type: String,
      required: true,
      default: "qualified",
    },
  });
const emit = defineEmits(['update:visible', 'completed']);
  const emit = defineEmits(["update:visible", "completed"]);
// 响应式数据(替代选项式的 data)
const formState = ref({
  productId: undefined,
  productModelId: undefined,
  routeId: undefined,
  productName: "",
  productModelName: "",
  unit: "",
  quantity: 0,
});
const isShow = computed({
  get() {
    return props.visible;
  },
  set(val) {
    emit('update:visible', val);
  },
});
const showProductSelectDialog = ref(false);
let { proxy } = getCurrentInstance()
const closeModal = () => {
  // 重置表单数据
  formState.value = {
  // 响应式数据(替代选项式的 data)
  const formState = ref({
    productId: undefined,
    productModelId: undefined,
    routeId: undefined,
    productName: "",
    productModelName: "",
    quantity: '',
    unit: "",
    quantity: 0,
  });
  const isShow = computed({
    get() {
      return props.visible;
    },
    set(val) {
      emit("update:visible", val);
    },
  });
  const showProductSelectDialog = ref(false);
  let { proxy } = getCurrentInstance();
  const closeModal = () => {
    // 重置表单数据
    formState.value = {
      productId: undefined,
      productModelId: undefined,
      routeId: undefined,
      productName: "",
      productModelName: "",
      quantity: "",
    };
    isShow.value = false;
  };
  isShow.value = false;
};
// 产品选择处理
const handleProductSelect = async (products) => {
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
    formState.value.productName = product.productName;
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    showProductSelectDialog.value = false;
    fetchRouteOptions( product.id);
    // 触发表单验证更新
    proxy.$refs["formRef"]?.validateField('productModelId');
  }
};
const routeOptions = ref([]);
const bindRouteLoading = ref(false);
const fetchRouteOptions = (productModelId) => {
  formState.value.routeId = undefined;
  routeOptions.value = []
  bindRouteLoading.value = true;
  listProcessRoute({ productModelId: productModelId }).then(res => {
    routeOptions.value = res.data || [];
  }).finally(() => {
    bindRouteLoading.value = false;
  })
}
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      // 验证是否选择了产品和规格
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择产品");
        return;
      }
      if (!formState.value.productModelId) {
        proxy.$modal.msgError("请选择规格");
        return;
      }
      addProductOrder(formState.value).then(res => {
        // 关闭模态框
        isShow.value = false;
        // 告知父组件已完成
        emit('completed');
        proxy.$modal.msgSuccess("提交成功");
      })
  // 产品选择处理
  const handleProductSelect = async products => {
    if (products && products.length > 0) {
      const product = products[0];
      formState.value.productId = product.skuId;
      formState.value.productName = product.materialName;
      formState.value.productModelName = product.specification;
      formState.value.productModelId = product.skuId;
      formState.value.unit = product.baseUnit;
      showProductSelectDialog.value = false;
      fetchRouteOptions(product.skuId);
      // 触发表单验证更新
      proxy.$refs["formRef"]?.validateField("productModelId");
    }
  })
};
  };
  const routeOptions = ref([]);
  const bindRouteLoading = ref(false);
  const fetchRouteOptions = productModelId => {
    formState.value.routeId = undefined;
    routeOptions.value = [];
    bindRouteLoading.value = true;
    listProcessRoute({ productModelId: productModelId })
      .then(res => {
        routeOptions.value = res.data || [];
      })
      .finally(() => {
        bindRouteLoading.value = false;
      });
  };
defineExpose({
  closeModal,
  handleSubmit,
  isShow,
});
  const handleSubmit = () => {
    proxy.$refs["formRef"].validate(valid => {
      if (valid) {
        // 验证是否选择了产品和规格
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择产品");
          return;
        }
        if (!formState.value.productModelId) {
          proxy.$modal.msgError("请选择规格");
          return;
        }
        addProductOrder(formState.value).then(res => {
          // 关闭模态框
          isShow.value = false;
          // 告知父组件已完成
          emit("completed");
          proxy.$modal.msgSuccess("提交成功");
        });
      }
    });
  };
  defineExpose({
    closeModal,
    handleSubmit,
    isShow,
  });
</script>
src/views/productionManagement/productionProcess/index.vue
@@ -13,14 +13,15 @@
            </el-icon>新增工序
          </el-button>
        </div>
        <div class="process-card-list">
          <div v-for="process in processList"
        <div class="process-card-list"
             v-loading="processLoading">
          <div v-for="process in processValueList"
               :key="process.id"
               class="process-card"
               :class="{ active: selectedProcess?.id === process.id }"
               @click="selectProcess(process)">
            <div class="card-header">
              <span class="process-code">{{ process.processCode }}</span>
              <div class="process-name">{{ process.name }} <span class="process-code">{{ process.no }}</span></div>
              <div class="card-actions">
                <el-button link
                           type="primary"
@@ -41,15 +42,21 @@
              </div>
            </div>
            <div class="card-body">
              <div class="process-name">{{ process.processName }}</div>
              <div class="process-desc">{{ process.processDesc || '暂无描述' }}</div>
              <!-- <div class="process-name">{{ process.name }}</div> -->
              <div class="process-desc">{{ process.remark || '暂无描述' }}</div>
            </div>
            <div class="card-footer">
              <el-tag size="small"
                      :type="process.status === '1' ? 'success' : 'info'">
                {{ process.status === '1' ? '启用' : '停用' }}
              </el-tag>
              <span class="param-count">参数: {{ process.paramCount || 0 }}个</span>
              <div class="status-tag"> <el-tag size="small"
                        :type="process.status ? 'success' : 'info'">
                  {{ process.status ? '启用' : '停用' }}
                </el-tag>
                <el-tag size="small"
                        :type="process.isQuality ? 'warning' : 'info'"
                        style="margin-left: 8px">
                  {{ process.isQuality ? '质检' : '非质检' }}
                </el-tag>
              </div>
              <span class="param-count">工资定额: ¥{{ process.salaryQuota || 0 }}</span>
            </div>
          </div>
        </div>
@@ -58,7 +65,7 @@
      <div class="param-list-section">
        <div class="section-header">
          <h3 class="section-title">
            {{ selectedProcess ? selectedProcess.processName + ' - 参数配置' : '请选择工序' }}
            {{ selectedProcess ? selectedProcess.name + ' - 参数配置' : '请选择工序' }}
          </h3>
          <el-button type="primary"
                     size="small"
@@ -95,18 +102,30 @@
               ref="processFormRef"
               label-width="100px">
        <el-form-item label="工序编码"
                      prop="processCode">
          <el-input v-model="processForm.processCode"
                      prop="no">
          <el-input v-model="processForm.no"
                    placeholder="请输入工序编码" />
        </el-form-item>
        <el-form-item label="工序名称"
                      prop="processName">
          <el-input v-model="processForm.processName"
                      prop="name">
          <el-input v-model="processForm.name"
                    placeholder="请输入工序名称" />
        </el-form-item>
        <el-form-item label="工资定额"
                      prop="salaryQuota">
          <el-input v-model="processForm.salaryQuota"
                    type="number"
                    :step="0.001" />
        </el-form-item>
        <el-form-item label="是否质检"
                      prop="isQuality">
          <el-switch v-model="processForm.isQuality"
                     :active-value="true"
                     inactive-value="false" />
        </el-form-item>
        <el-form-item label="工序描述"
                      prop="processDesc">
          <el-input v-model="processForm.processDesc"
                      prop="remark">
          <el-input v-model="processForm.remark"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入工序描述" />
@@ -114,8 +133,8 @@
        <el-form-item label="状态"
                      prop="status">
          <el-radio-group v-model="processForm.status">
            <el-radio label="1">启用</el-radio>
            <el-radio label="0">停用</el-radio>
            <el-radio :label="true">启用</el-radio>
            <el-radio :label="false">停用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
@@ -156,15 +175,15 @@
            <el-table-column prop="parameterCode"
                             label="参数编号"
                             width="100" />
            <el-table-column prop="parameterName"
            <el-table-column prop="paramName"
                             label="参数名称" />
            <el-table-column prop="parameterType"
            <el-table-column prop="paramType"
                             label="参数类型"
                             width="100">
              <template #default="scope">
                <el-tag size="small"
                        :type="getParamTypeTag(scope.row.parameterType)">
                  {{ scope.row.parameterType }}
                        :type="getParamTypeTag(scope.row.paramType)">
                  {{ scope.row.paramType }}
                </el-tag>
              </template>
            </el-table-column>
@@ -181,28 +200,40 @@
              <span class="detail-text">{{ selectedParam.parameterCode }}</span>
            </el-form-item>
            <el-form-item label="参数名称">
              <span class="detail-text">{{ selectedParam.parameterName }}</span>
              <span class="detail-text">{{ selectedParam.paramName }}</span>
            </el-form-item>
            <el-form-item label="参数模式">
              <el-tag size="small"
                      :type="selectedParam.parameterType2 === '1' ? 'success' : 'warning'">
                {{ selectedParam.parameterType2 === '1' ? '单值' : '区间' }}
                      :type="selectedParam.valueMode == '1' ? 'success' : 'warning'">
                {{ selectedParam.valueMode == '1' ? '单值' : '区间' }}
              </el-tag>
            </el-form-item>
            <el-form-item label="参数类型">
              <el-tag size="small"
                      :type="getParamTypeTag(selectedParam.parameterType)">
                {{ selectedParam.parameterType }}
                      :type="getParamTypeTag(selectedParam.paramType)">
                {{ selectedParam.paramType }}
              </el-tag>
            </el-form-item>
            <el-form-item label="参数格式">
              <span class="detail-text">{{ selectedParam.parameterFormat || '-' }}</span>
            </el-form-item>
            <el-form-item label="标准值">
              <span class="detail-text">{{ selectedParam.standardValue }}</span>
              <span class="detail-text">{{ selectedParam.paramFormat || '-' }}</span>
            </el-form-item>
            <el-form-item label="单位">
              <span class="detail-text">{{ selectedParam.unit || '-' }}</span>
            </el-form-item>
            <el-form-item label="默认值"
                          v-if="selectedParam.valueMode === '1'">
              <el-input v-model="selectedParam.defaultValue"
                        placeholder="请输入默认值" />
            </el-form-item>
            <el-form-item label="最小值"
                          v-if="selectedParam.valueMode === '2'">
              <el-input v-model="selectedParam.defaultMin"
                        placeholder="请输入最小值" />
            </el-form-item>
            <el-form-item label="最大值"
                          v-if="selectedParam.valueMode === '2'">
              <el-input v-model="selectedParam.defaultMax"
                        placeholder="请输入最大值" />
            </el-form-item>
          </el-form>
          <el-empty v-else
@@ -227,9 +258,16 @@
  import { Plus, Edit, Delete, Search } from "@element-plus/icons-vue";
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
  import { listType } from "@/api/system/dict/type";
  import {
    add,
    update,
    del,
    list as getProcessListApi,
    processList,
  } from "@/api/productionManagement/productionProcess.js";
  // 工序列表数据
  const processList = ref([]);
  const processValueList = ref([]);
  const selectedProcess = ref(null);
  const processLoading = ref(false);
@@ -251,14 +289,32 @@
  const processFormRef = ref(null);
  const processForm = reactive({
    id: null,
    processCode: "",
    processName: "",
    processDesc: "",
    status: "1",
    no: "",
    name: "",
    salaryQuota: null,
    isQuality: false,
    remark: "",
    status: true,
  });
  const processRules = {
    processCode: [{ required: true, message: "请输入工序编码", trigger: "blur" }],
    processName: [{ required: true, message: "请输入工序名称", trigger: "blur" }],
    no: [{ required: true, message: "请输入工序编码", trigger: "blur" }],
    name: [{ required: true, message: "请输入工序名称", trigger: "blur" }],
    salaryQuota: [
      {
        required: true,
        message: "请输入工资定额",
        trigger: "blur",
        validator: (rule, value, callback) => {
          if (value === null || value === undefined || value === "") {
            callback(new Error("请输入工资定额"));
          } else if (isNaN(value) || value < 0) {
            callback(new Error("工资定额必须是非负数字"));
          } else {
            callback();
          }
        },
      },
    ],
  };
  // 参数对话框
@@ -277,18 +333,18 @@
    },
    {
      label: "参数名称",
      prop: "parameterName",
      prop: "paramName",
    },
    {
      label: "参数模式",
      prop: "parameterType2",
      prop: "valueMode",
      dataType: "tag",
      formatType: row => (row.parameterType2 === "1" ? "success" : "warning"),
      formatData: row => (row.parameterType2 === "1" ? "单值" : "区间"),
      formatType: row => (row.valueMode === "1" ? "success" : "warning"),
      formatData: row => (row.valueMode === "1" ? "单值" : "区间"),
    },
    {
      label: "参数类型",
      prop: "parameterType",
      prop: "paramType",
      dataType: "tag",
      formatType: row => {
        const typeMap = {
@@ -297,17 +353,38 @@
          下拉选项: "warning",
          时间格式: "success",
        };
        return typeMap[row.parameterType] || "default";
        return typeMap[row.paramType] || "default";
      },
    },
    {
      label: "参数格式",
      prop: "parameterFormat",
      prop: "paramFormat",
    },
    {
      label: "标准值",
      prop: "standardValue",
      className: row => (row.parameterType === "数值格式" ? "quantity-cell" : ""),
      prop: "defaultValue",
      className: row => (row.paramType === "数值格式" ? "quantity-cell" : ""),
    },
    {
      label: "默认值",
      prop: "defaultValue",
      formatData: (val, row) => {
        return row.valueMode === "1" ? val : "-";
      },
    },
    {
      label: "最小值",
      prop: "defaultMin",
      formatData: (val, row) => {
        return row.valueMode === "2" ? val : "-";
      },
    },
    {
      label: "最大值",
      prop: "defaultMax",
      formatData: (val, row) => {
        return row.valueMode === "2" ? val : "-";
      },
    },
    {
      label: "单位",
@@ -328,212 +405,33 @@
  // 获取工序列表
  const getProcessList = () => {
    // 假数据
    processList.value = [
      {
        id: 1,
        processCode: "PROC001",
        processName: "原料配比",
        processDesc: "原材料配比工序",
        status: "1",
        paramCount: 3,
      },
      {
        id: 2,
        processCode: "PROC002",
        processName: "搅拌混合",
        processDesc: "搅拌混合工序",
        status: "1",
        paramCount: 2,
      },
      {
        id: 3,
        processCode: "PROC003",
        processName: "浇筑成型",
        processDesc: "浇筑成型工序",
        status: "1",
        paramCount: 4,
      },
      {
        id: 4,
        processCode: "PROC004",
        processName: "蒸压养护",
        processDesc: "蒸压养护工序",
        status: "0",
        paramCount: 2,
      },
      {
        id: 5,
        processCode: "PROC005",
        processName: "切割加工",
        processDesc: "切割加工工序",
        status: "1",
        paramCount: 3,
      },
    ];
    processLoading.value = true;
    getProcessListApi()
      .then(res => {
        processValueList.value = res.data || [];
      })
      .catch(() => {
        ElMessage.error("获取工序列表失败");
      })
      .finally(() => {
        processLoading.value = false;
      });
  };
  // 获取参数列表
  const getParamList = processId => {
    paramLoading.value = true;
    // 假数据
    setTimeout(() => {
      paramLoading.value = false;
      const mockData = {
        1: [
          {
            id: 1,
            parameterCode: "P001",
            parameterName: "水泥比例",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "30",
            unit: "%",
          },
          {
            id: 2,
            parameterCode: "P002",
            parameterName: "砂比例",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "60",
            unit: "%",
          },
          {
            id: 3,
            parameterCode: "P003",
            parameterName: "水比例",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "10",
            unit: "%",
          },
        ],
        2: [
          {
            id: 4,
            parameterCode: "P004",
            parameterName: "搅拌时间",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "5",
            unit: "分钟",
          },
          {
            id: 5,
            parameterCode: "P005",
            parameterName: "搅拌速度",
            parameterType2: "2",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "100-200",
            unit: "rpm",
          },
        ],
        3: [
          {
            id: 6,
            parameterCode: "P006",
            parameterName: "浇筑温度",
            parameterType2: "2",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "20-30",
            unit: "℃",
          },
          {
            id: 7,
            parameterCode: "P007",
            parameterName: "浇筑压力",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "0.5",
            unit: "MPa",
          },
          {
            id: 8,
            parameterCode: "P008",
            parameterName: "成型状态",
            parameterType2: "1",
            parameterType: "下拉选项",
            parameterFormat: "status",
            standardValue: "正常",
            unit: "",
          },
          {
            id: 9,
            parameterCode: "P009",
            parameterName: "成型时间",
            parameterType2: "1",
            parameterType: "时间格式",
            parameterFormat: "YYYY-MM-DD HH:mm:ss",
            standardValue: "2024-01-01 08:00:00",
            unit: "",
          },
        ],
        4: [
          {
            id: 10,
            parameterCode: "P010",
            parameterName: "蒸压温度",
            parameterType2: "2",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "180-200",
            unit: "℃",
          },
          {
            id: 11,
            parameterCode: "P011",
            parameterName: "蒸压压力",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "1.2",
            unit: "MPa",
          },
        ],
        5: [
          {
            id: 12,
            parameterCode: "P012",
            parameterName: "切割尺寸",
            parameterType2: "1",
            parameterType: "文本格式",
            parameterFormat: "",
            standardValue: "600x200x100",
            unit: "mm",
          },
          {
            id: 13,
            parameterCode: "P013",
            parameterName: "切割精度",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "±1",
            unit: "mm",
          },
          {
            id: 14,
            parameterCode: "P014",
            parameterName: "切割速度",
            parameterType2: "1",
            parameterType: "数值格式",
            parameterFormat: "",
            standardValue: "2",
            unit: "m/min",
          },
        ],
      };
      paramList.value = mockData[processId] || [];
      paramPage.total = paramList.value.length;
    }, 300);
    getProcessParamList(processId)
      .then(res => {
        paramList.value = res.data || [];
        paramPage.total = paramList.value.length;
      })
      .catch(() => {
        ElMessage.error("获取参数列表失败");
      })
      .finally(() => {
        paramLoading.value = false;
      });
  };
  // 选择工序
@@ -546,19 +444,23 @@
  const handleAddProcess = () => {
    isProcessEdit.value = false;
    processForm.id = null;
    processForm.processCode = "";
    processForm.processName = "";
    processForm.processDesc = "";
    processForm.status = "1";
    processForm.no = "";
    processForm.name = "";
    processForm.salaryQuota = null;
    processForm.isQuality = false;
    processForm.remark = "";
    processForm.status = true;
    processDialogVisible.value = true;
  };
  const handleEditProcess = process => {
    isProcessEdit.value = true;
    processForm.id = process.id;
    processForm.processCode = process.processCode;
    processForm.processName = process.processName;
    processForm.processDesc = process.processDesc;
    processForm.no = process.no;
    processForm.name = process.name;
    processForm.salaryQuota = process.salaryQuota;
    processForm.isQuality = process.isQuality || false;
    processForm.remark = process.remark || "";
    processForm.status = process.status;
    processDialogVisible.value = true;
  };
@@ -569,21 +471,34 @@
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {
      ElMessage.success("删除成功");
      getProcessList();
      if (selectedProcess.value?.id === process.id) {
        selectedProcess.value = null;
        paramList.value = [];
      }
      del([process.id])
        .then(() => {
          ElMessage.success("删除成功");
          getProcessList();
          if (selectedProcess.value?.id === process.id) {
            selectedProcess.value = null;
            paramList.value = [];
          }
        })
        .catch(() => {
          ElMessage.error("删除失败");
        });
    });
  };
  const handleProcessSubmit = () => {
    processFormRef.value.validate(valid => {
      if (valid) {
        ElMessage.success(isProcessEdit.value ? "编辑成功" : "新增成功");
        processDialogVisible.value = false;
        getProcessList();
        const apiMethod = isProcessEdit.value ? update : add;
        apiMethod(processForm)
          .then(() => {
            ElMessage.success(isProcessEdit.value ? "编辑成功" : "新增成功");
            processDialogVisible.value = false;
            getProcessList();
          })
          .catch(() => {
            ElMessage.error(isProcessEdit.value ? "编辑失败" : "新增失败");
          });
      }
    });
  };
@@ -599,71 +514,71 @@
      {
        id: 101,
        parameterCode: "P101",
        parameterName: "温度",
        parameterType2: "2",
        parameterType: "数值格式",
        parameterFormat: "",
        standardValue: "20-30",
        paramName: "温度",
        valueMode: "2",
        paramType: "数值格式",
        paramFormat: "",
        defaultValue: "20-30",
        unit: "℃",
      },
      {
        id: 102,
        parameterCode: "P102",
        parameterName: "压力",
        parameterType2: "1",
        parameterType: "数值格式",
        parameterFormat: "",
        standardValue: "0.5",
        paramName: "压力",
        valueMode: "1",
        paramType: "数值格式",
        paramFormat: "",
        defaultValue: "0.5",
        unit: "MPa",
      },
      {
        id: 103,
        parameterCode: "P103",
        parameterName: "湿度",
        parameterType2: "2",
        parameterType: "数值格式",
        parameterFormat: "",
        standardValue: "40-60",
        paramName: "湿度",
        valueMode: "2",
        paramType: "数值格式",
        paramFormat: "",
        defaultValue: "40-60",
        unit: "%",
      },
      {
        id: 104,
        parameterCode: "P104",
        parameterName: "速度",
        parameterType2: "1",
        parameterType: "数值格式",
        parameterFormat: "",
        standardValue: "100",
        paramName: "速度",
        valueMode: "1",
        paramType: "数值格式",
        paramFormat: "",
        defaultValue: "100",
        unit: "m/min",
      },
      {
        id: 105,
        parameterCode: "P105",
        parameterName: "状态",
        parameterType2: "1",
        parameterType: "下拉选项",
        parameterFormat: "status",
        standardValue: "正常",
        paramName: "状态",
        valueMode: "1",
        paramType: "下拉选项",
        paramFormat: "status",
        defaultValue: "正常",
        unit: "",
      },
      {
        id: 106,
        parameterCode: "P106",
        parameterName: "记录时间",
        parameterType2: "1",
        parameterType: "时间格式",
        parameterFormat: "YYYY-MM-DD HH:mm:ss",
        standardValue: "2024-01-01 08:00:00",
        paramName: "记录时间",
        valueMode: "1",
        paramType: "时间格式",
        paramFormat: "YYYY-MM-DD HH:mm:ss",
        defaultValue: "2024-01-01 08:00:00",
        unit: "",
      },
      {
        id: 107,
        parameterCode: "P107",
        parameterName: "备注",
        parameterType2: "1",
        parameterType: "文本格式",
        parameterFormat: "",
        standardValue: "无",
        paramName: "备注",
        valueMode: "1",
        paramType: "文本格式",
        paramFormat: "",
        defaultValue: "无",
        unit: "",
      },
    ];
@@ -683,7 +598,7 @@
      filteredParamList.value = availableParamList.value;
    } else {
      filteredParamList.value = availableParamList.value.filter(item =>
        item.parameterName.toLowerCase().includes(keyword)
        item.paramName.toLowerCase().includes(keyword)
      );
    }
  };
@@ -704,8 +619,14 @@
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {
      ElMessage.success("删除成功");
      getParamList(selectedProcess.value.id);
      deleteProcessParam(row.id)
        .then(() => {
          ElMessage.success("删除成功");
          getParamList(selectedProcess.value.id);
        })
        .catch(() => {
          ElMessage.error("删除失败");
        });
    });
  };
@@ -714,9 +635,21 @@
      ElMessage.warning("请先选择一个参数");
      return;
    }
    ElMessage.success("添加成功");
    paramDialogVisible.value = false;
    getParamList(selectedProcess.value.id);
    addProcessParam({
      processId: selectedProcess.value.id,
      paramId: selectedParam.value.id,
      defaultValue: selectedParam.value.defaultValue,
      defaultMin: selectedParam.value.defaultMin,
      defaultMax: selectedParam.value.defaultMax,
    })
      .then(() => {
        ElMessage.success("添加成功");
        paramDialogVisible.value = false;
        getParamList(selectedProcess.value.id);
      })
      .catch(() => {
        ElMessage.error("添加失败");
      });
  };
  const handleParamPagination = obj => {
@@ -810,7 +743,8 @@
      .process-code {
        font-size: 12px;
        color: #909399;
        // color: #909399;
        color: #cb9b18;
        font-family: "Courier New", monospace;
      }