已修改13个文件
690 ■■■■ 文件已修改
src/api/tool/publicInterface.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/ETable.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useDelete.js 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useFormData.js 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/archiveManagement/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/archiveManagement/mould/archiveDialog.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicInformation/index.vue 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicInformation/mould/coal.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procureMent/components/ProductionDialog.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procureMent/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDialog.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/warehouseManagement/index.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/tool/publicInterface.js
@@ -3,7 +3,7 @@
// 获取路由
export const testUserList = () => {
  return request({
    url: '/test/user/list',
    url: '/system/user/listAll',
    method: 'get'
  })
}
src/components/Table/ETable.vue
@@ -17,8 +17,8 @@
    :row-key="rowKey"
    style="width: 100%;"
  >
    <el-table-column v-if="showSelection" type="selection" width="55" align="center" />
    <el-table-column v-if="showIndex" label="序号" width="60" align="center" fixed="left">
    <el-table-column v-if="showSelection" type="selection" width="55" align="center" :show-overflow-tooltip="false" />
    <el-table-column v-if="showIndex" label="序号" width="60" align="center" fixed="left" :show-overflow-tooltip="false">
      <template #default="scope">
        {{ getRowIndex(scope.$index) }}
      </template>
src/hooks/useDelete.js
@@ -7,8 +7,8 @@
/**
 * 创建删除功能
 * @param {Object} options 配置选项
 * @param {Function} options.deleteApi 删除API函数
 * @param {Function} options.getList 重新获取列表数据的函数
 * @param {Function|Function} options.deleteApi 删除API函数或返回API函数的函数
 * @param {Function|Function} options.getList 重新获取列表数据的函数或返回函数的函数
 * @param {Ref} options.selectedRows 选中行的响应式引用
 * @param {Ref} options.tableData 表格数据的响应式引用
 * @param {Ref} options.total 总数的响应式引用
@@ -28,6 +28,41 @@
    successText = "删除成功",
    useLocalUpdate = false
  } = options;
  /**
   * 获取实际的删除API函数
   * 支持直接传入函数或返回函数的函数
   */
  const getDeleteApi = () => {
    if (typeof deleteApi === 'function') {
      // 尝试调用看是否返回函数
      try {
        const result = deleteApi();
        return typeof result === 'function' ? result : deleteApi;
      } catch (error) {
        // 如果调用出错,说明这本身就是API函数
        return deleteApi;
      }
    }
    return deleteApi;
  };
  /**
   * 获取实际的获取列表函数
   * 支持直接传入函数或返回函数的函数
   */
  const getListFunction = () => {
    if (typeof getList === 'function') {
      try {
        const result = getList();
        return typeof result === 'function' ? result : getList;
      } catch (error) {
        // 如果调用出错,说明这本身就是列表函数
        return getList;
      }
    }
    return getList;
  };
  /**
   * 批量删除方法
@@ -55,9 +90,16 @@
      // 提取ID
      const ids = rowsToDelete.map(item => item.id);
      // 获取当前的删除API函数
      const currentDeleteApi = getDeleteApi();
      if (!currentDeleteApi) {
        ElMessage.error("删除API未配置");
        return false;
      }
      // 调用删除API
      const res = await deleteApi(ids);
      const res = await currentDeleteApi(ids);
      if (res.code === 200) {
        // 根据配置选择更新方式
@@ -69,8 +111,9 @@
          }
        } else {
          // 重新获取数据
          if (getList) {
            await getList();
          const currentGetList = getListFunction();
          if (currentGetList) {
            await currentGetList();
          }
        }
src/hooks/useFormData.js
@@ -1,8 +1,330 @@
import { reactive } from "vue";
/**
 * 通用表单数据管理组合式函数
 * 提供表单数据的增删改查、验证、重置等功能
 */
import { ref, reactive, computed, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { clone } from "lodash";
/**
 * 创建表单数据管理功能
 * @param {Object} options 配置选项
 * @param {Object} options.defaultForm 默认表单结构
 * @param {Function} options.addApi 新增API函数
 * @param {Function} options.updateApi 更新API函数
 * @param {Function} options.getDetailApi 获取详情API函数
 * @param {Object} options.rules 表单验证规则
 * @param {Function} options.beforeSubmit 提交前的数据处理函数
 * @param {Function} options.afterSubmit 提交后的回调函数
 * @param {Boolean} options.autoReset 提交成功后是否自动重置表单
 * @returns {Object} 返回表单管理相关的方法和状态
 */
export function useFormData(options = {}) {
  const {
    defaultForm = {},
    addApi,
    updateApi,
    getDetailApi,
    rules = {},
    beforeSubmit,
    afterSubmit,
    autoReset = true
  } = options;
export default function useFormData(initData) {
  // 表单状态
  const form = ref({ ...defaultForm });
  const originalForm = ref({ ...defaultForm });
  const loading = ref(false);
  const dialogVisible = ref(false);
  const mode = ref('add'); // 'add', 'edit', 'view'
  const title = ref('');
  const formRef = ref(null);
  // 计算属性
  const isAdd = computed(() => mode.value === 'add');
  const isEdit = computed(() => mode.value === 'edit');
  const isView = computed(() => mode.value === 'view');
  const isReadonly = computed(() => mode.value === 'view');
  const submitButtonText = computed(() => {
    return isAdd.value ? '新增' : '保存';
  });
  /**
   * 打开表单对话框
   * @param {String} formMode 表单模式:'add', 'edit', 'view'
   * @param {Object} data 编辑/查看时的数据
   * @param {String} customTitle 自定义标题
   */
  const openForm = async (formMode = 'add', data = null, customTitle = '') => {
    mode.value = formMode;
    // 设置标题
    if (customTitle) {
      title.value = customTitle;
    } else {
      const titleMap = {
        add: '新增',
        edit: '编辑',
        view: '查看'
      };
      title.value = titleMap[formMode] || '表单';
    }
    // 根据模式处理数据
    if (formMode === 'add') {
      resetForm();
    } else if (data) {
      // 编辑/查看模式,如果有详情API则获取最新数据
      if (getDetailApi && data.id) {
        loading.value = true;
        try {
          const res = await getDetailApi(data.id);
          if (res.code === 200) {
            setFormData(res.data);
          } else {
            ElMessage.error('获取详情失败');
            setFormData(data);
          }
        } catch (error) {
          console.error('获取详情失败:', error);
          setFormData(data);
        } finally {
          loading.value = false;
        }
      } else {
        setFormData(data);
      }
    }
    dialogVisible.value = true;
  };
  /**
   * 设置表单数据
   * @param {Object} data 表单数据
   */
  const setFormData = (data) => {
    form.value = { ...defaultForm, ...data };
    originalForm.value = { ...form.value };
  };
  /**
   * 重置表单
   */
  const resetForm = () => {
    form.value = { ...defaultForm };
    originalForm.value = { ...defaultForm };
    if (formRef.value) {
      formRef.value.resetFields();
    }
  };
  /**
   * 恢复表单到原始状态
   */
  const restoreForm = () => {
    form.value = { ...originalForm.value };
    if (formRef.value) {
      formRef.value.clearValidate();
    }
  };
  /**
   * 表单验证
   * @returns {Promise<Boolean>} 验证结果
   */
  const validateForm = async () => {
    if (!formRef.value) return true;
    try {
      await formRef.value.validate();
      return true;
    } catch (error) {
      console.log('表单验证失败:', error);
      return false;
    }
  };
  /**
   * 提交表单
   * @param {Object} customData 自定义提交数据
   * @returns {Promise<Boolean>} 提交结果
   */
  const submitForm = async (customData = null) => {
    // 验证表单
    const isValid = await validateForm();
    if (!isValid) {
      ElMessage.warning('请检查表单数据');
      return false;
    }
    // 准备提交数据
    let submitData = customData || { ...form.value };
    // 执行提交前处理
    if (beforeSubmit && typeof beforeSubmit === 'function') {
      try {
        submitData = await beforeSubmit(submitData, mode.value);
      } catch (error) {
        console.error('提交前处理失败:', error);
        ElMessage.error('数据处理失败');
        return false;
      }
    }
    loading.value = true;
    try {
      let res;
      if (isAdd.value && addApi) {
        res = await addApi(submitData);
      } else if (isEdit.value && updateApi) {
        res = await updateApi(submitData);
      } else {
        ElMessage.error('未配置相应的API接口');
        return false;
      }
      if (res.code === 200) {
        const action = isAdd.value ? '新增' : '更新';
        ElMessage.success(`${action}成功`);
        // 执行提交后回调
        if (afterSubmit && typeof afterSubmit === 'function') {
          await afterSubmit(res.data, mode.value, submitData);
        }
        // 自动重置表单
        if (autoReset) {
          closeForm();
        }
        return true;
      } else {
        ElMessage.error(res.msg || '操作失败');
        return false;
      }
    } catch (error) {
      console.error('提交失败:', error);
      ElMessage.error('操作失败,请稍后重试');
      return false;
    } finally {
      loading.value = false;
    }
  };
  /**
   * 关闭表单对话框
   */
  const closeForm = () => {
    dialogVisible.value = false;
    resetForm();
  };
  /**
   * 检查表单是否有变更
   * @returns {Boolean} 是否有变更
   */
  const hasChanges = computed(() => {
    return JSON.stringify(form.value) !== JSON.stringify(originalForm.value);
  });
  /**
   * 带确认的关闭表单
   */
  const closeFormWithConfirm = async () => {
    if (hasChanges.value && !isView.value) {
      try {
        await ElMessageBox.confirm('表单数据已修改,确定要离开吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        });
        closeForm();
      } catch {
        // 用户取消
      }
    } else {
      closeForm();
    }
  };
  /**
   * 设置表单字段值
   * @param {String} field 字段名
   * @param {Any} value 字段值
   */
  const setFieldValue = (field, value) => {
    form.value[field] = value;
  };
  /**
   * 获取表单字段值
   * @param {String} field 字段名
   * @returns {Any} 字段值
   */
  const getFieldValue = (field) => {
    return form.value[field];
  };
  /**
   * 批量设置表单字段值
   * @param {Object} values 字段值对象
   */
  const setFieldValues = (values) => {
    Object.keys(values).forEach(key => {
      if (form.value.hasOwnProperty(key)) {
        form.value[key] = values[key];
      }
    });
  };
  /**
   * 清除字段验证
   * @param {String|Array} fields 字段名或字段名数组
   */
  const clearValidate = (fields = null) => {
    if (formRef.value) {
      formRef.value.clearValidate(fields);
    }
  };
  return {
    // 状态
    form,
    loading,
    dialogVisible,
    mode,
    title,
    formRef,
    // 计算属性
    isAdd,
    isEdit,
    isView,
    isReadonly,
    submitButtonText,
    hasChanges,
    // 方法
    openForm,
    setFormData,
    resetForm,
    restoreForm,
    validateForm,
    submitForm,
    closeForm,
    closeFormWithConfirm,
    setFieldValue,
    getFieldValue,
    setFieldValues,
    clearValidate
  };
}
// 向后兼容的默认导出
export default function useFormDataSimple(initData) {
  const form = reactive(clone(initData, true));
  function resetForm() {
src/views/archiveManagement/index.vue
@@ -208,13 +208,14 @@
const tableSwitch = ref(false);
// 处理节点点击
const handleNodeClick = (data) => {
  console.log("点击节点", data);
  rowClickData.value = data; // 存储当前点击的节点数据
  tableSwitch.value = true;
  // 切换节点时重置到第一页
  queryParams.current = 1;
  queryParams.treeId = data.id;
  getArchiveListData();
};
const rowClickData = ref({}); // 存储当前点击的节点数据
const archiveDialogs = ref(null); // 表格组件引用
// 新增归档
const add = () => {
@@ -226,7 +227,7 @@
    // 确保组件引用存在后再调用方法
    nextTick(() => {
      if (archiveDialogs.value && typeof archiveDialogs.value.initForm === 'function') {
        archiveDialogs.value.initForm(); // 重置表单
        archiveDialogs.value.initForm(rowClickData.value); // 重置表单
      }
    });
  } catch (error) {
src/views/archiveManagement/mould/archiveDialog.vue
@@ -101,9 +101,9 @@
const initTreeDataId = ref(null);
const fileUploadRef = ref(null);
const initForm = (val) => {
  initTreeDataId.value = val.value.id || null; // 确保 initTreeDataId 初始化为 null
  initTreeDataId.value = val.id || null; // 确保 initTreeDataId 初始化为 null
  ruleForm.value = {};
  ruleForm.value.treeId = val.value.id || null; // 确保 treeId 初始化为 null
  ruleForm.value.treeId = val.id || null; // 确保 treeId 初始化为 null
  nextTick(() => {
    fileUploadRef.value.init();
  });
@@ -146,9 +146,6 @@
      });
      return;
    }
    // 发送 emit 事件
    // 关闭对话框
    centerDialogVisible.value = false;
  } catch (error) {
    ElMessage({
src/views/basicInformation/index.vue
@@ -58,7 +58,6 @@
          @selection-change="handleSelectionChange"
          :operations="['edit', 'viewRow']"
          :operationsWidth="200"
          :show-overflow-tooltip="false"
        >
          <!-- 字段名称列的自定义插槽 - 显示为标签 -->
          <template
@@ -168,7 +167,6 @@
import Coal from "./mould/coal.vue";
import coalQualityMaintenance from "./mould/coalQualityMaintenance.vue";
import coalMeiZhiZiDuanWeiHu from "./mould/coalMeiZhiZiDuanWeiHu.vue";
import Descriptions from "@/components/dialog/Descriptions.vue";
// ===== API 服务导入 =====
import { delSupply, getSupply } from "@/api/basicInformation/supplier.js";
@@ -186,16 +184,12 @@
import {
  getCoalFieldList,
  getCoalPlanList,
  delCoalPlan,
} from "@/api/basicInformation/coalQualityMaintenance";
import { useDelete } from "@/hooks/useDelete.js";
const { proxy } = getCurrentInstance();
// ===== 响应式状态管理 =====
// 弹窗控制状态
const showDialog = ref(false);
const currentViewData = ref({}); // 当前查看的数据
const dialogFormVisible = ref(false);
const form = ref({});
const title = ref("");
@@ -316,10 +310,12 @@
const getUserList = async () => {
  try {
    const res = await testUserList();
    console.log("获取用户列表数据:", res);
    console.log("userMap:", userMap.value);
    if (res && res.data) {
      userList.value = res.data;
      userList.value.forEach((user) => {
        userMap.value[user.userId] = user.username;
        userMap.value[user.userId] = user.nickName;
      });
    }
  } catch (error) {
@@ -721,57 +717,22 @@
 * 批量删除处理
 * @description 批量删除选中的记录
 */
const handleDelete = async () => {
  if (selectedRows.value.length === 0) {
    ElMessage.warning("请选择要删除的数据");
    return;
  }
  const deleteIds = selectedRows.value.map((item) => item.id);
  try {
    await ElMessageBox.confirm("确定删除选中的数据吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    });
    const deleteApiMap = {
  const deleteApiMap = {
      supplier: delSupply,
      coal: delCoalInfo,
      coalQualityMaintenance: () => {
        throw new Error("delCoalQuality API not imported");
      },
      coalQualityMaintenance: delCoalPlan,
      customer: delCustomer,
      coalMeiZhiZiDuanWeiHu: deleteCoalField,
    };
    const deleteApi = deleteApiMap[tabName.value];
    if (!deleteApi) {
      ElMessage.error("删除接口未配置");
      return;
    }
    console.log(deleteIds);
    const res = await deleteApi(deleteIds);
    if (res.code !== 200 && res.msg !== "操作成功") {
      ElMessage.error("删除失败:" + res.msg);
      return;
    }
    ElMessage.success("删除成功");
    await getList();
  } catch (error) {
    if (error.message !== "cancel") {
      console.error("删除操作失败:", error);
      ElMessage.error("删除失败,请稍后再试");
    } else {
      ElMessage.info("已取消删除操作");
    }
  } finally {
    selectedRows.value = [];
  }
};
const {handleDeleteBatch :handleDelete} = useDelete({
  deleteApi: () => deleteApiMap[tabName.value],
  selectedRows: selectedRows,
  getList: () => getList,
  tableData: tableData,
  total: total,
  confirmText: "确认删除选中的数据吗?",
  successText: "删除成功",
})
/**
 * 关闭弹窗处理
src/views/basicInformation/mould/coal.vue
@@ -23,7 +23,7 @@
        </el-form-item>
        <el-form-item label="维护人姓名" prop="maintainerId">
          <el-input
              :value="userStore.name || ''"
              :value="userStore.nickName || ''"
              placeholder="维护人姓名"
              disabled
          />
@@ -79,26 +79,6 @@
  required: true,
  type: Object,
});
// 在组件挂载时获取用户信息
onMounted(async () => {
  // 如果store中没有用户信息,则获取用户信息
  if (!userStore.name) {
    try {
      await userStore.getInfo()
      // 自动填充维护人ID
      if (props.addOrEdit === 'add') {
        formData.value.maintainerId = userStore.id
      }
    } catch (error) {
      console.error('获取用户信息失败:', error)
    }
  } else {
    // 自动填充维护人ID
    if (props.addOrEdit === 'add') {
      formData.value.maintainerId = userStore.id
    }
  }
})
const emit = defineEmits(['submit', 'handleBeforeClose', 'update:coalDialogFormVisible'])
// 表单引用
@@ -127,7 +107,6 @@
  if (!formRef.value) return
  await formRef.value.validate(async (valid, fields) => {
    if (valid) {
      delete formData.value.maintainerName // 删除显示用的字段,只保留ID
      // 确保maintainerId有值
      if (!formData.value.maintainerId) {
@@ -166,12 +145,8 @@
  emit('update:coalDialogFormVisible', false)
}
const rules = reactive({
  supplierName: [
    {required: true, message: "请输入供货商名称", trigger: "blur"},
  ],
  identifyNumber: [
    {required: true, message: "请正确输入纳税人识别号", trigger: "blur"},
    {min: 17, max: 20, message: "请输入17-20位纳税人识别号", trigger: "blur"},
  coal: [
    {required: true, message: "请输入煤种名称", trigger: "blur"},
  ],
});
src/views/procureMent/components/ProductionDialog.vue
@@ -50,10 +50,10 @@
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="单价(不含税)" prop="priceExcludingTax">
        <el-form-item label="单价(含税)" prop="priceIncludingTax">
          <el-input
              v-model.number="form.priceExcludingTax"
              placeholder="请输入"
              v-model.number="form.priceIncludingTax"
              placeholder="请输入含税单价"
              @blur="handlePriceBlur"
              :disabled="isViewMode"
          >
@@ -62,9 +62,9 @@
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="单价(含税)" prop="priceIncludingTax">
        <el-form-item label="单价(不含税)" prop="priceExcludingTax">
          <el-input
              v-model.number="form.priceIncludingTax"
              v-model.number="form.priceExcludingTax"
              placeholder="自动计算"
              disabled
          >
@@ -180,116 +180,95 @@
defineExpose({
  getDropdownData,
});
// 数值格式化工具函数
const toFixed = (num, precision = 2) => {
  if (isNaN(num) || num === null || num === undefined || num === "") {
    return 0;
  }
  return (
      Math.floor(parseFloat(num) * Math.pow(10, precision)) /
      Math.pow(10, precision)
  );
  return Number((Math.floor(parseFloat(num) * Math.pow(10, precision)) / Math.pow(10, precision)).toFixed(precision));
};
// 含税单价计算
const unitPriceWithTax = computed(() => {
  const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0;
  const taxRate = parseFloat(form.value.taxRate) || 0;
  if (!priceExcludingTax || !taxRate) {
    return 0;
  }
  const result = priceExcludingTax * (1 + taxRate / 100);
  return toFixed(result, 2);
});
// 含税总价计算
const totalUnitPriceWithTax = computed(() => {
  const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0;
  const taxRate = parseFloat(form.value.taxRate) || 0;
  const purchaseQuantity = parseFloat(form.value.purchaseQuantity) || 0;
// 安全获取数值
const safeNumber = (value) => {
  const num = parseFloat(value);
  return isNaN(num) ? 0 : num;
};
  if (!priceExcludingTax || !taxRate || !purchaseQuantity) {
    return 0;
  }
// 计算逻辑 - 基于含税单价计算不含税价格
const calculatePrices = () => {
  const priceIncludingTax = safeNumber(form.value.priceIncludingTax); // 含税单价
  const taxRate = safeNumber(form.value.taxRate); // 税率
  const quantity = safeNumber(form.value.purchaseQuantity); // 采购数量
  const unitPriceWithTaxValue = priceExcludingTax * (1 + taxRate / 100);
  const result = unitPriceWithTaxValue * purchaseQuantity;
  return toFixed(result, 2);
});
  // 1. 根据含税单价和税率计算不含税单价
  // 不含税单价 = 含税单价 / (1 + 税率/100)
  const priceExcludingTax = priceIncludingTax && taxRate
    ? toFixed(priceIncludingTax / (1 + taxRate / 100), 2)
    : 0;
// 不含税总价计算
const taxExclusiveTotalPrice = computed(() => {
  const purchaseQuantity = parseFloat(form.value.purchaseQuantity) || 0;
  const priceExcludingTax = parseFloat(form.value.priceExcludingTax) || 0;
  // 2. 计算不含税总价 = 不含税单价 × 数量
  const totalPriceExcludingTax = priceExcludingTax && quantity
    ? toFixed(priceExcludingTax * quantity, 2)
    : 0;
  if (!purchaseQuantity || !priceExcludingTax) {
    return 0;
  }
  // 3. 计算含税总价 = 含税单价 × 数量
  const totalPriceIncludingTax = priceIncludingTax && quantity
    ? toFixed(priceIncludingTax * quantity, 2)
    : 0;
  const result = purchaseQuantity * priceExcludingTax;
  return toFixed(result, 2);
});
  // 更新表单数据
  form.value.priceExcludingTax = priceExcludingTax;
  form.value.totalPriceExcludingTax = totalPriceExcludingTax;
  form.value.totalPriceIncludingTax = totalPriceIncludingTax;
};
// 监听计算值变化,同步到 form 对象中
watch(unitPriceWithTax, (newValue) => {
  form.value.priceIncludingTax = newValue;
});
watch(totalUnitPriceWithTax, (newValue) => {
  form.value.totalPriceIncludingTax = newValue;
});
watch(taxExclusiveTotalPrice, (newValue) => {
  form.value.totalPriceExcludingTax = newValue;
});
// 监听表单对象变化,用于处理编辑模式下的数据加载和实时计算
watch(
  () => [form.value.priceIncludingTax, form.value.taxRate, form.value.purchaseQuantity],
  () => {
    // 防抖处理,避免频繁计算
    nextTick(() => {
      calculatePrices();
    });
  },
  { deep: true }
);
const userStore = useUserStore();
const userInfo = ref({});
const match = () => {
  return userInfo.value.nickName || "未知用户";
};
// 处理税率输入框失焦,确保精度
// 处理税率输入框失焦事件
const handleTaxRateBlur = () => {
  if (
      form.value.taxRate !== null &&
      form.value.taxRate !== undefined &&
      form.value.taxRate !== ""
  ) {
  if (form.value.taxRate !== null && form.value.taxRate !== undefined && form.value.taxRate !== "") {
    form.value.taxRate = toFixed(parseFloat(form.value.taxRate), 2);
    // watch 会自动触发 calculatePrices,不需要手动调用
  }
};
// 处理不含税单价输入框失焦,确保精度
// 处理含税单价输入框失焦事件
const handlePriceBlur = () => {
  if (
      form.value.priceExcludingTax !== null &&
      form.value.priceExcludingTax !== undefined &&
      form.value.priceExcludingTax !== ""
  ) {
    form.value.priceExcludingTax = toFixed(
        parseFloat(form.value.priceExcludingTax),
        2
    );
  if (form.value.priceIncludingTax !== null && form.value.priceIncludingTax !== undefined && form.value.priceIncludingTax !== "") {
    form.value.priceIncludingTax = toFixed(parseFloat(form.value.priceIncludingTax), 2);
    // watch 会自动触发 calculatePrices,不需要手动调用
  }
};
// 处理采购数量输入框失焦,确保精度
// 处理采购数量输入框失焦事件
const handleQuantityBlur = () => {
  if (
      form.value.purchaseQuantity !== null &&
      form.value.purchaseQuantity !== undefined &&
      form.value.purchaseQuantity !== ""
  ) {
    form.value.purchaseQuantity = toFixed(
        parseFloat(form.value.purchaseQuantity),
        3
    ); // 数量保留3位小数
  if (form.value.purchaseQuantity !== null && form.value.purchaseQuantity !== undefined && form.value.purchaseQuantity !== "") {
    form.value.purchaseQuantity = toFixed(parseFloat(form.value.purchaseQuantity), 3); // 数量保留3位小数
    // watch 会自动触发 calculatePrices,不需要手动调用
  }
};
onMounted(async () => {
  let res = await userStore.getInfo();
  userInfo.value = res.user;
  getDropdownData()
  await getDropdownData();
  // 组件加载完成后触发一次计算
  calculatePrices();
});
const rules = {
  supplierName: [
src/views/procureMent/index.vue
@@ -201,7 +201,7 @@
  form.value = {
    supplierName: "",
    coal: "",
    unit: "t",
    unit: "吨",
    purchaseQuantity: "",
    priceExcludingTax: "",
    totalPriceExcludingTax: "",
src/views/production/components/ProductionDialog.vue
@@ -165,6 +165,7 @@
  getCoalInfoList,
  deleteProductionInventory,
} from "@/api/production/index.js";
import { getSupplyList } from "@/api/procureMent/index.js"
import {validateFormData, validateNumber, deepClone, createDefaultProductionRow} from "@/utils/production";
import {useCoalData} from "./useCoalData";
import useUserStore from "@/store/modules/user";
@@ -218,15 +219,13 @@
];
const formalDatabaseColumns = ref([
  {prop: "supplierName", label: "供应商名称", minwidth: 150
  // ,formatter: (row) => {
  //     console.log(row);
  //     return supplierList.value[row.supplierId] || "--";
  //   }
  {prop: "supplierId", label: "供应商名称", minwidth: 150
  ,formatter: (row) => {
      return supplierList.value.find(supplier => supplier.id === row.supplierId)?.supplierName || "--";
    }
  },
  {prop: "coalId", label: "煤种", minwidth: 60,
    formatter: (row) => {
      // return coalList.value[row.coalId].coal || "--";
      return coalList.value.find(coal => coal.id === row.coalId)?.coal || "--";
    }
  },
@@ -251,12 +250,13 @@
// 获取配置数据
const handlData = async () => {
  innerVisible.value = true;
  let getSupplier = await getOfficialAll();
  let OfficialAll = await getOfficialAll();
  let getSupplierList = await getSupplyList();
  let getCoalName = await getCoalInfoList();
  coalList.value = getCoalName.data || [];
  supplierList.value = getSupplier.data || [];
  if (getSupplier.code === 200) {
    formalDatabaseData.value = getSupplier.data;
  supplierList.value = getSupplierList.data || [];
  if (OfficialAll.code === 200) {
    formalDatabaseData.value = OfficialAll.data;
    const existingOfficialIds = tableData.value
        .map((item) => item.officialId)
        .filter((id) => id);
src/views/production/index.vue
@@ -1,5 +1,5 @@
<template>
  <div>
  <div class="app-container">
    <!-- 搜索表单 -->
    <el-form :inline="true" :model="queryParams" class="search-form">
      <el-form-item label="搜索">
src/views/warehouseManagement/index.vue
@@ -134,8 +134,8 @@
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="煤质方案" prop="qualityPlan">
              <el-select v-model="form.qualityPlan" placeholder="请选择" @change="coalPlanByIdList" clearable>
            <el-form-item label="煤质方案" prop="coalPlanId">
              <el-select v-model="form.coalPlanId" placeholder="请选择" @change="coalPlanByIdList" clearable>
                <el-option
                    v-for="dict in qualityPlanOption"
                    :key="dict.id"
@@ -217,6 +217,20 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="煤质方案" prop="coalPlanId">
              <el-select v-model="mergeForm.coalPlanId" placeholder="请选择" @change="coalPlanByIdList" clearable>
                <el-option
                    v-for="dict in qualityPlanOption"
                    :key="dict.id"
                    :label="dict.plan"
                    :value="dict.id"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-divider></el-divider>
        <el-row>
          <el-col :span="12" v-for="item in filteredList" :key="item.id">
@@ -279,7 +293,7 @@
    totalPriceIncludingTax: '',
    priceExcludingTax: '',
    totalPriceExcludingTax: '',
    qualityPlan: '',
    coalPlanId: '',
    pId: '',
  },
  mergeForm: {
@@ -291,20 +305,20 @@
    totalPriceIncludingTax: '',
    priceExcludingTax: '',
    totalPriceExcludingTax: '',
    qualityPlan: '',
    coalPlanId: '',
    pId: '',
  },
  rules: {
    supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }],
    coal: [{ required: true, message: "请输入煤种", trigger: "blur" }],
    unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
    qualityPlan: [{ required: true, message: "请选择", trigger: "change" }],
    coalPlanId: [{ required: true, message: "请选择", trigger: "change" }],
  },
  mergeRules: {
    supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }],
    coal: [{ required: true, message: "请输入煤种", trigger: "blur" }],
    unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
    qualityPlan: [{ required: true, message: "请选择", trigger: "change" }],
    coalPlanId: [{ required: true, message: "请选择", trigger: "change" }],
  }
})