已修改8个文件
已添加4个文件
1457 ■■■■ 文件已修改
src/api/equipment/management/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipment/requisition/index.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/home/index.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/publicApi/index.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipment/management/index.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipment/management/mould/equipmentRequisitionDialog.vue 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipment/management/mould/usageRecord.vue 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index.vue 707 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procureMent/index.vue 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDetailsTable.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDialog.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipment/management/index.js
@@ -29,4 +29,4 @@
    method: 'delete',
    data
  })
}
}
src/api/equipment/requisition/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
// è®¾å¤‡ç®¡ç†
import request from '@/utils/request'
// /equipmentUsageRecord/list
// æŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½•
export function getUsageRecordList(query) {
  return request({
    url: '/equipmentUsageRecord/list',
    method: 'get',
    params: query
  })
}
// /equipmentUsageRecord/addOrEditUsageRecord
// æ·»åŠ æˆ–ç¼–è¾‘è®¾å¤‡ä½¿ç”¨è®°å½•
export function addOrEditUsageRecord(data) {
  return request({
    url: '/equipmentUsageRecord/addOrEditUsageRecord',
    method: 'post',
    data
  })
}
src/api/home/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
// ç…¤ç§ä¿¡æ¯
import request from '@/utils/request'
// /homePage/allInfo
// èŽ·å–é¦–é¡µä¿¡æ¯
export function getCoalInfo(query) {
    return request({
        url: '/homePage/allInfo',
        method: 'get',
        params: query
    })
}
// /homePage/yearlySales
// èŽ·å–å¹´åº¦é”€å”®ä¿¡æ¯
export function getYearlySales(data) {
    return request({
            url: '/homePage/yearlySales',
            method: 'post',
            data: data
        })
}
src/api/publicApi/index.js
@@ -9,4 +9,24 @@
    url: '/system/user/listAll',
    method: 'get'
  })
}
// /equipmentManagement/equipmentList
// æŸ¥è¯¢è®¾å¤‡åˆ—表
export function getEquipmentList(query) {
  return request({
    url: '/equipmentManagement/equipmentList',
    method: 'get',
    params: query
  })
}
// /coalInfo/coalInfoList
// æŸ¥è¯¢ç…¤ç§åˆ—表
export function getCoalInfoList(query) {
    return request({
        url: '/coalInfo/coalInfoList',
        method: 'get',
        params: query
    })
}
src/store/modules/user.js
@@ -2,6 +2,7 @@
import { getToken, setToken, removeToken } from '@/utils/auth'
import { isHttp, isEmpty } from "@/utils/validate"
import defAva from '@/assets/images/profile.jpg'
import {userListAll} from '@/api/publicApi/index.js'
const useUserStore = defineStore(
  'user',
@@ -13,7 +14,8 @@
      nickName: '',
      avatar: '',
      roles: [],
      permissions: []
      permissions: [],
      userList: []
    }),
    actions: {
      // ç™»å½•
@@ -70,6 +72,20 @@
            reject(error)
          })
        })
      },
      // èŽ·å–ç”¨æˆ·åˆ—è¡¨ï¼ˆå¦‚æžœå·²ç¼“å­˜åˆ™ç›´æŽ¥è¿”å›žï¼Œå¦åˆ™é‡æ–°èŽ·å–ï¼‰
      async getUserList () {
        if (Array.isArray(this.userList) && this.userList.length > 0) {
          return this.userList;
        }
        // ä¸ºç©ºæ—¶é‡æ–°èŽ·å–
        return userListAll().then(res => {
          this.userList = res.data;
          return this.userList;
        }).catch(error => {
          throw error;
        });
      }
    }
  })
src/views/equipment/management/index.vue
@@ -87,12 +87,28 @@
        @pagination="handPagination"
      />
      <managementDialog
      v-if="activeTab == 'management'"
        v-model:copyForm="copyForm"
        v-model:managementFormDialog="manaDialog"
        :addOrEdit="addOrEdit"
        :form="form"
        @submit="getList"
      ></managementDialog>
      <EquipmentRequisition
        v-if="activeTab == 'equipmentRequisition'"
        v-model="equipmentRequisitionDialog"
        :formData="form"
        :maxQuantity="getMaxQuantity()"
        @submit="onEquipmentRequisitionSubmit"
      />
      <UsageRecord
        v-if="activeTab == 'usageRecord'"
        v-model:copyForm="copyForm"
        v-model:usageRecordDialog="usageRecordDialog"
        :addOrEdit="addOrEdit"
        :form="form"
        @submit="getList"
      />
    </el-card>
  </div>
</template>
@@ -106,10 +122,13 @@
import DataTable from "@/components/Table/ETable.vue";
import Pagination from "@/components/Pagination";
import managementDialog from "./mould/managementDialog.vue";
import EquipmentRequisition from "./mould/equipmentRequisitionDialog.vue";
import UsageRecord from "./mould/usageRecord.vue";
// API æœåС坼入
import { useDelete } from "@/hooks/useDelete.js";
import { getManagementList, delEquipment } from "@/api/equipment/management/index.js";
import { getUsageRecordList } from "@/api/equipment/requisition/index.js";
// å“åº”式状态管理
const form = ref({});
@@ -117,6 +136,8 @@
const copyForm = ref({});
const addOrEdit = ref("add");
const manaDialog = ref(false);
const equipmentRequisitionDialog = ref(false);
const usageRecordDialog = ref(false);
const loading = ref(false);
const activeTab = ref("management");
const selectedRows = ref([]);
@@ -141,6 +162,48 @@
    api: getManagementList,
    deleteApi: delEquipment,
    columns: [
      { prop: "equipmentNo", label: "设备编号", minWidth: 100 },
      { prop: "equipmentName", label: "设备名称", minWidth: 100 },
      { prop: "quantity", label: "数量", minWidth: 100 },
      { prop: "specification", label: "规格型号", minWidth: 100 },
      {
        prop: "usageStatus",
        label: "使用状态",
        minWidth: 100,
        formatter: (row) => row.usageStatus == 1 ? "启用" : "禁用"
      },
      { prop: "purchaseDate", label: "采购日期", minWidth: 100 },
      { prop: "purchasePrice", label: "采购价格", minWidth: 100 },
    ]
  },
  equipmentRequisition:{
    label: "设备领用",
    searchPlaceholder: "设备编号/设备名称/规格型号",
    showSearch: true,
    api: getUsageRecordList,
    deleteApi: null,
    columns: [
      { prop: "userId", label: "领用人", minWidth: 100 },
      { prop: "equipmentId", label: "设备ID", minWidth: 100 },
      { prop: "usageQuantity", label: "领用数量", minWidth: 100 },
      {
        prop: "equipmentStatus",
        label: "使用状态",
        minWidth: 100,
        formatter: (row) => row.usageStatus == 1 ? "启用" : "禁用"
      },
      { prop: "usageStartTime", label: "使用开始时间", minWidth: 100 },
      { prop: "usageEndTime", label: "使用结束时间", minWidth: 100 },
      { prop: "remarks", label: "备注", minWidth: 100 },
    ]
  },
  usageRecord:{
    label: "领用记录",
    searchPlaceholder: "设备编号/设备名称/规格型号",
    showSearch: true,
    api: getManagementList,
    deleteApi: delEquipment,
    columns: [
      { prop: "equipmentId", label: "设备编号", minWidth: 100 },
      { prop: "equipmentName", label: "设备名称", minWidth: 100 },
      { prop: "quantity", label: "数量", minWidth: 100 },
@@ -151,11 +214,11 @@
        minWidth: 100,
        formatter: (row) => row.usageStatus == 1 ? "启用" : "禁用"
      },
      { prop: "usingDepartment", label: "使用部门", minWidth: 100 },
      { prop: "purchaseDate", label: "采购日期", minWidth: 100 },
      { prop: "purchasePrice", label: "采购价格", minWidth: 100 },
    ]
  }
  },
  // åŽç»­å¯ä»¥åœ¨è¿™é‡Œæ·»åŠ æ–°çš„æ ‡ç­¾é¡µé…ç½®
};
@@ -209,7 +272,15 @@
  addOrEdit.value = "add";
  form.value = {};
  title.value = `新增${currentTabConfig.value.label}`;
  manaDialog.value = true;
  // é€šç”¨çš„
  copyForm.value = {};
  if (activeTab.value === "equipmentRequisition") {
    equipmentRequisitionDialog.value = true;
  } else if (activeTab.value === "usageRecord") {
    usageRecordDialog.value = true;
  } else {
    manaDialog.value = true;
  }
};
const handleEdit = (row) => {
@@ -217,7 +288,13 @@
  addOrEdit.value = "edit";
  title.value = `编辑${currentTabConfig.value.label}`;
  copyForm.value = { ...row };
  manaDialog.value = true;
  if (activeTab.value === "equipmentRequisition") {
    equipmentRequisitionDialog.value = true;
  } else if (activeTab.value === "usageRecord") {
    usageRecordDialog.value = true;
  } else {
    manaDialog.value = true;
  }
};
const handleView = (row) => {
@@ -225,7 +302,13 @@
  addOrEdit.value = "viewRow";
  title.value = `查看${currentTabConfig.value.label}`;
  copyForm.value = { ...row };
  manaDialog.value = true;
  if (activeTab.value === "equipmentRequisition") {
    equipmentRequisitionDialog.value = true;
  } else if (activeTab.value === "usageRecord") {
    usageRecordDialog.value = true;
  } else {
    manaDialog.value = true;
  }
};
const handPagination = (val) => {
@@ -250,6 +333,22 @@
  successText: "删除成功",
});
// èŽ·å–è®¾å¤‡æœ€å¤§å¯é¢†ç”¨æ•°é‡
const getMaxQuantity = () => {
  if (form.value.equipmentId) {
    const equipment = tableData.value.find(item => item.equipmentId === form.value.equipmentId);
    return equipment ? equipment.quantity : null;
  }
  return null;
};
// è®¾å¤‡é¢†ç”¨å¼¹çª—提交处理
const onEquipmentRequisitionSubmit = (formData) => {
  ElMessage.success('设备领用成功');
  equipmentRequisitionDialog.value = false;
  getList();
};
// æ•°æ®èŽ·å–
const getList = async () => {
  try {
src/views/equipment/management/mould/equipmentRequisitionDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,199 @@
<template>
  <el-dialog
    v-model="visible"
    :title="isEdit ? '编辑设备领用' : '新增设备领用'"
    width="600px"
    @close="handleClose"
  >
    <el-form :model="form" :rules="rules" ref="formRef" label-width="150px">
      <el-form-item label="领用人" prop="userId">
        <el-select v-model="form.userId" placeholder="请选择">
          <el-option
            v-for="item in userList"
            :key="item.userId"
            :label="item.nickName"
            :value="item.userId"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="设备名称" prop="equipmentId">
        <el-select v-model="form.equipmentId" placeholder="请选择">
          <el-option
            v-for="item in equipmentList"
            :key="item.id"
            :label="item.equipmentName"
            :value="item.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="设备库存" prop="equipmentStock">
        <el-input
          :value="
            equipmentList.find((item) => item.id == form.equipmentId)
              ?.quantity || 0
          "
          disabled
          style="width: 100%"
        />
      </el-form-item>
      <el-form-item label="领用数量" prop="usageQuantity">
        <el-input-number
          v-model="form.usageQuantity"
          :min="1"
          :max="maxQuantity || 999"
          style="width: 100%"
        />
        <span
          v-if="maxQuantity !== null"
          style="color: #999; font-size: 12px; margin-left: 8px"
          >(最多{{ maxQuantity }}台)</span
        >
      </el-form-item>
      <el-form-item label="使用状态" prop="equipmentStatus">
        <el-select v-model="form.equipmentStatus" placeholder="请选择">
          <el-option label="启用" :value="1" />
          <el-option label="禁用" :value="0" />
          <el-option label="维修中" :value="2" />
          <el-option label="报废" :value="3" />
          <el-option label="待领用" :value="4" />
        </el-select>
      </el-form-item>
      <el-form-item label="使用开始时间" prop="usageStartTime">
        <el-date-picker
          v-model="form.usageStartTime"
          type="datetime"
          placeholder="选择开始时间"
          style="width: 100%"
          value-format="YYYY-MM-DD"
          format="YYYY-MM-DD"
        />
      </el-form-item>
      <!-- <el-form-item label="使用结束时间" prop="usageEndTime">
        <el-date-picker
          v-model="form.usageEndTime"
          type="datetime"
          placeholder="选择结束时间"
          style="width: 100%"
        />
      </el-form-item> -->
      <el-form-item label="备注" prop="remarks">
        <el-input
          v-model="form.remarks"
          type="textarea"
          placeholder="请输入备注"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" @click="handleSubmit">确定</el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { ref, watch, computed, onMounted } from "vue";
import { ElMessage } from "element-plus";
import { getEquipmentList } from "@/api/publicApi/index.js";
import { addOrEditUsageRecord } from "@/api/equipment/requisition/index.js";
import useUserStore from "@/store/modules/user";
onMounted(() => {});
const userStore = useUserStore();
let userList = ref([]);
userStore.getUserList().then((res) => {
  userList.value = res;
});
// èŽ·å–è®¾å¤‡åˆ—è¡¨
const equipmentList = ref([]);
getEquipmentList().then((res) => {
  equipmentList.value = res.data;
});
const props = defineProps({
  modelValue: Boolean,
  formData: {
    type: Object,
    default: () => ({}),
  },
});
const maxQuantity = computed(() => {
  if (!props.formData.equipmentId) return 0;
  const eq = equipmentList.value.find(
    (item) => item.id == props.formData.equipmentId
  );
  // é˜²æ­¢ä¸º0或负数,最小为1
  return eq && eq.quantity > 0 ? eq.quantity : 999;
});
const emit = defineEmits(["update:modelValue", "submit"]);
const visible = computed({
  get: () => props.modelValue,
  set: (v) => emit("update:modelValue", v),
});
const isEdit = computed(() => !!props.formData?.id);
const formRef = ref();
// é»˜è®¤è¡¨å•初始值
const defaultForm = {
  userId: "",
  equipmentId: "",
  usageQuantity: 1,
  equipmentStatus: 1,
  usageStartTime: "",
  remarks: ""
};
const form = ref({ ...defaultForm });
watch(
  () => props.formData,
  (val) => {
    if (val && Object.keys(val).length > 0) {
      form.value = { ...defaultForm, ...val };
    } else {
      // æ–°å»ºæ—¶é‡ç½®ä¸ºåˆå§‹å€¼ï¼Œé˜²æ­¢è„æ•°æ®
      form.value = { ...defaultForm };
    }
  },
  { immediate: true }
);
const rules = {
  userId: [{ required: true, message: "请输入领用人", trigger: "blur" }],
  equipmentId: [{ required: true, message: "请输入设备ID", trigger: "blur" }],
  usageQuantity: [
    { required: true, message: "请输入领用数量", trigger: "blur" },
    { type: "number", min: 1, message: "至少领用1台", trigger: "blur" },
    {
      validator: (rule, value, callback) => {
        if (maxQuantity.value !== null && value > maxQuantity.value) {
          callback(new Error("领用数量不能大于设备数量"));
        } else {
          callback();
        }
      },
      trigger: "blur",
    },
  ],
  equipmentStatus: [
    { required: true, message: "请选择使用状态", trigger: "change" },
  ],
  usageStartTime: [
    { required: true, message: "请选择开始时间", trigger: "change" },
  ],
};
function handleClose() {
  emit("update:modelValue", false);
}
function handleSubmit() {
  formRef.value.validate((valid) => {
    if (!valid) return;
    let res = addOrEditUsageRecord(form.value);
    emit("submit", { ...form.value });
    handleClose();
  });
}
</script>
src/views/equipment/management/mould/usageRecord.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,241 @@
<template>
  <div>
    <el-dialog
      v-model="dialogVisible"
      :title="addOrEdit === 'edit' ? '编辑' : '新增' + '设备'"
      width="800"
      :title-style="{ textAlign: 'center' }"
      :close-on-click-modal="false"
      :before-close="handleClose"
    >
      <el-form
        ref="formRef"
        :model="formData"
        :rules="rules"
        label-width="auto"
      >
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="设备编号" prop="equipmentId">
              <el-input
                v-model="formData.equipmentId"
                placeholder="请输入设备编号"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="设备名称" prop="equipmentName">
              <el-input
                v-model="formData.equipmentName"
                placeholder="请输入设备名称"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="数量" prop="quantity">
              <el-input
                v-model="formData.quantity"
                placeholder="请输入数量"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="规格型号" prop="specification">
              <el-input
                v-model="formData.specification"
                placeholder="请输入规格型号"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="使用状态" prop="usageStatus">
              <el-select
                v-model="formData.usageStatus"
                placeholder="请选择使用状态"
                :disabled="isViewMode"
              >
                <el-option label="启用" value="1" />
                <el-option label="禁用" value="0" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="使用部门" prop="usingDepartment">
              <el-input
                v-model="formData.usingDepartment"
                placeholder="请输入使用部门"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="存放位置" prop="storageLocation">
              <el-input
                v-model="formData.storageLocation"
                placeholder="请输入存放位置"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="采购价格" prop="purchasePrice">
              <el-input
                v-model="formData.purchasePrice"
                placeholder="请输入采购价格"
                :disabled="isViewMode"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="采购日期" prop="purchaseDate">
              <el-date-picker
                v-model="formData.purchaseDate"
                type="date"
                placeholder="请选择采购日期"
                size="default"
                :value-format="'YYYY-MM-DD'"
                style="width: 100%;"
                :disabled="isViewMode"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item class="dialog-footer">
          <el-button v-if="!isViewMode" @click="cancelForm">取消</el-button>
          <el-button v-if="!isViewMode" type="primary" @click="submitForm">确定</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, watch, computed, reactive } from "vue";
import { addOrEditEquipment } from "@/api/equipment/management/index.js";
const props = defineProps({
  beforeClose: {
    type: Function,
    default: () => {},
  },
  form: {
    type: Object,
    default: () => ({}),
  },
  addOrEdit: {
    type: String,
    default: "add",
  },
  title: {
    type: String,
    default: "",
  },
});
const emit = defineEmits(["submit", "handleBeforeClose"]);
// è®¡ç®—属性:统一控制是否禁用
const isViewMode = computed(() => props.addOrEdit === "viewRow");
// è¡¨å•引用和数据
const formRef = ref(null);
const formData = ref({});
const copyForm = defineModel("copyForm", {
  required: true,
  type: Object,
  default: () => ({}),
});
// å¼¹çª—可见性
const dialogVisible = defineModel("managementFormDialog", {
  required: true,
  type: Boolean,
});
// ç›‘听外部传入的表单数据变化,合并监听逻辑
watch(
  [() => props.form, () => props.addOrEdit],
  ([newForm, newAddOrEdit]) => {
    formData.value = { ...newForm };
  },
  { deep: true, immediate: true }
);
// æäº¤è¡¨å•
const submitForm = async () => {
  if (!formRef.value) return;
  await formRef.value.validate(async (valid) => {
    if (!valid) return;
    try {
      const result = await addOrEditEquipment({ ...formData.value });
      const title = props.title.includes("新增") ? "新增" : "编辑";
      if (result.code === 200 && result.msg) {
        ElMessage.success(`${title}成功:${result.msg}`);
        emit("submit", { title, ...formData.value, result });
        closeDialog();
      } else {
        ElMessage.error(`${title}失败:${result.msg}`);
      }
    } catch (error) {
      console.error("提交失败:", error);
      ElMessage.error("提交失败,请重试");
    }
  });
};
// å…³é—­å¼¹çª—的统一方法
const closeDialog = () => {
  emit("update:managementFormDialog", false);
  formData.value = {};
};
// å–消表单
const cancelForm = () => {
  closeDialog();
};
// é‡ç½®è¡¨å•
const resetForm = () => {
  if (!formRef.value) return;
  formData.value = JSON.parse(JSON.stringify(copyForm.value));
};
// å…³é—­å¼¹çª—
const handleClose = () => {
  emit("handleBeforeClose");
  closeDialog();
};
const rules = reactive({
  equipmentId: [
    { required: true, message: "请输入供货商名称", trigger: "blur" },
  ],
});
</script>
<style lang="scss" scoped>
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
  flex-direction: column;
}
// åªä¸ºdialog头部加下划线
:deep(.el-dialog__header) {
  border-bottom: 1px solid #e8eaec;
  padding: 0 20px 10px 0;
  margin-bottom: 14px;
}
</style>
src/views/index.vue
@@ -8,24 +8,50 @@
        </div>
        <div class="card-content">
          <div class="card-title">营收金额</div>
          <div class="card-value">Â¥1,234,567</div>
          <div class="card-trend">
          <div class="card-value">
            Â¥{{
              homePageData.revenueAmount
                ? formatThousand(homePageData.revenueAmount)
                : "--"
            }}
          </div>
          <div class="card-trend" v-if="homePageData.trend == '+'">
            <span class="trend-label">较昨日</span>
            <span class="trend-value up">+12.5%</span>
            <span class="trend-value up">+ {{ homePageData.changeRate }}</span>
          </div>
          <div class="card-trend" v-if="homePageData.trend == '-'">
            <span class="trend-label">较昨日</span>
            <span class="trend-value down"
              >- {{ homePageData.changeRate }}</span
            >
          </div>
        </div>
      </div>
      <div class="stat-card supply">
        <div class="card-icon">
          <i class="el-icon-truck"></i>
        </div>
        <div class="card-content">
          <div class="card-title">供应量</div>
          <div class="card-value">8,965 å¨</div>
          <div class="card-trend">
          <div class="card-value">
            {{
              homePageData.saleQuantity
                ? formatThousand(homePageData.saleQuantity)
                : "--"
            }}吨
          </div>
          <div class="card-trend" v-if="homePageData.trendQuantity == '+'">
            <span class="trend-label">较昨日</span>
            <span class="trend-value up">+8.2%</span>
            <span class="trend-value up"
              >+ {{ homePageData.saleQuantityRate }}</span
            >
          </div>
          <div class="card-trend" v-if="homePageData.trendQuantity == '-'">
            <span class="trend-label">较昨日</span>
            <span class="trend-value down"
              >- {{ homePageData.saleQuantityRate }}</span
            >
          </div>
        </div>
      </div>
@@ -37,9 +63,25 @@
        <div class="chart-title">营收分布</div>
        <div ref="pieChart" class="chart-content pie-chart"></div>
      </div>
      <div class="chart-container">
        <div class="chart-title">供应量趋势</div>
        <div class="chart-title">
          <span>供应量趋势</span>
          <div>
            <el-date-picker
              :locale="zhCN"
              v-model="selectMonth"
              type="monthrange"
              placeholder="选择日期"
              format="YYYY/MM"
              value-format="YYYY-MM"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              @change="searchMonth"
            />
          </div>
        </div>
        <div ref="areaChart" class="chart-content area-chart"></div>
      </div>
    </div>
@@ -52,25 +94,10 @@
          <h3>库存统计</h3>
        </div>
        <div class="inventory-items">
          <div class="inventory-item">
            <div class="item-name">原煤</div>
            <div class="item-value">15,432 å¨</div>
            <div class="item-status normal">正常</div>
          </div>
          <div class="inventory-item">
            <div class="item-name">精煤</div>
            <div class="item-value">8,765 å¨</div>
            <div class="item-status normal">正常</div>
          </div>
          <div class="inventory-item">
            <div class="item-name">焦煤</div>
            <div class="item-value">3,241 å¨</div>
            <div class="item-status low">偏低</div>
          </div>
          <div class="inventory-item">
            <div class="item-name">块煤</div>
            <div class="item-value">6,789 å¨</div>
            <div class="item-status normal">正常</div>
          <div class="inventory-item" v-for="(item, index) in inventoryList.Yvalues" :key="index">
            <div class="item-name">{{ inventoryList.Xkeys[index]? inventoryList.Xkeys[index] : "--"}}</div>
            <div class="item-value">{{ item ? formatThousand(item) : "0" }}</div>
            <div class="item-status">吨</div>
          </div>
        </div>
      </div>
@@ -93,236 +120,376 @@
          style="width: 100%"
          :header-cell-style="tableHeaderStyle"
        >
          <el-table-column prop="product" label="产品" width="80"></el-table-column>
          <el-table-column prop="quantity" label="数量" width="80"></el-table-column>
          <el-table-column prop="amount" label="金额" width="90"></el-table-column>
          <el-table-column prop="status" label="状态" width="70">
            <template #default="scope">
              <el-tag
                :type="scope.row.status === '已完成' ? 'success' : 'warning'"
                size="small"
              >
                {{ scope.row.status }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column
            prop="product"
            label="产品"
            mini-width="50"
          ></el-table-column>
          <el-table-column
            prop="quantity"
            label="数量"
            mini-width="50"
          ></el-table-column>
          <el-table-column
            prop="amount"
            label="金额"
            mini-width="50"
          ></el-table-column>
        </el-table>
      </div>
    </div>
  </div>
</template>
<script>
import * as echarts from 'echarts'
<!-- åˆ é™¤å¤šä½™çš„ script ç»“束标签 -->
<script setup>
import { getCoalInfo, getYearlySales } from "@/api/home/index";
import { ref, onMounted, nextTick } from "vue";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
export default {
  name: 'Dashboard',
  data() {
    return {
      salesData: [
        { product: '原煤', quantity: '1,234吨', amount: 'Â¥456,789', status: '已完成' },
        { product: '精煤', quantity: '567吨', amount: 'Â¥234,567', status: '已完成' },
        { product: '焦煤', quantity: '890吨', amount: 'Â¥345,678', status: '进行中' },
        { product: '块煤', quantity: '432吨', amount: 'Â¥123,456', status: '已完成' },
        { product: '煤泥', quantity: '678吨', amount: 'Â¥234,567', status: '进行中' }
      ],
      tableHeaderStyle: {
        backgroundColor: '#f5f7fa',
        color: '#606266',
        fontSize: '12px'
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initCharts()
    })
  },
  methods: {
    initCharts() {
      this.initPieChart()
      this.initAreaChart()
      this.initBarChart()
    },
    initPieChart() {
      const chart = echarts.init(this.$refs.pieChart)
      const option = {
        tooltip: {
          trigger: 'item',
          formatter: '{a} <br/>{b}: {c} ({d}%)'
        },
        legend: {
          orient: 'vertical',
          left: 'right',
          top: 'center',
          textStyle: {
            fontSize: 12
          }
        },
        series: [
          {
            name: '营收分布',
            type: 'pie',
            radius: ['30%', '70%'],
            center: ['40%', '50%'],
            avoidLabelOverlap: false,
            label: {
              show: false,
              position: 'center'
            },
            emphasis: {
              label: {
                show: true,
                fontSize: '16',
                fontWeight: 'bold'
              }
            },
            labelLine: {
              show: false
            },
            data: [
              { value: 335, name: '原煤', itemStyle: { color: '#409EFF' } },
              { value: 310, name: '精煤', itemStyle: { color: '#67C23A' } },
              { value: 234, name: '焦煤', itemStyle: { color: '#E6A23C' } },
              { value: 135, name: '块煤', itemStyle: { color: '#F56C6C' } },
              { value: 155, name: '其他', itemStyle: { color: '#909399' } }
            ]
          }
        ]
      }
      chart.setOption(option)
      // å“åº”式
      window.addEventListener('resize', () => {
        chart.resize()
      })
    },
    initAreaChart() {
      const chart = echarts.init(this.$refs.areaChart)
      const option = {
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            label: {
              backgroundColor: '#6a7985'
            }
          }
        },
        legend: {
          data: ['供应量'],
          top: 10
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: [
          {
            type: 'category',
            boundaryGap: false,
            data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月'],
            axisLabel: {
              fontSize: 12
            }
          }
        ],
        yAxis: [
          {
            type: 'value',
            axisLabel: {
              fontSize: 12
            }
          }
        ],
        series: [
          {
            name: '供应量',
            type: 'line',
            stack: 'Total',
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(64, 158, 255, 0.3)' },
                { offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
              ])
            },
            emphasis: {
              focus: 'series'
            },
            data: [1200, 1320, 1010, 1340, 900, 1230, 1100],
            lineStyle: {
              color: '#409EFF'
            },
            itemStyle: {
              color: '#409EFF'
            }
          }
        ]
      }
      chart.setOption(option)
      // å“åº”式
      window.addEventListener('resize', () => {
        chart.resize()
      })
    },
    initBarChart() {
      const chart = echarts.init(this.$refs.barChart)
      const option = {
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: ['原煤', '精煤', '焦煤', '块煤', '煤泥'],
          axisLabel: {
            fontSize: 11
          }
        },
        yAxis: {
          type: 'value',
          axisLabel: {
            fontSize: 11
          }
        },
        series: [
          {
            name: '销量',
            type: 'bar',
            data: [320, 302, 301, 334, 290],
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: '#409EFF' },
                { offset: 1, color: '#79bbff' }
              ])
            },
            barWidth: '60%'
          }
        ]
      }
      chart.setOption(option)
      // å“åº”式
      window.addEventListener('resize', () => {
        chart.resize()
      })
    }
// å…¼å®¹æ¨¡æ¿å˜é‡åï¼Œæš´éœ²ç»™æ¨¡æ¿ä½¿ç”¨
const zhCN = zhCn;
import * as echarts from "echarts";
const homePageData = ref({});
const selectMonth = ref([]);
// ç”Ÿæˆæ— é™éšæœºé¢œè‰²ï¼ˆHSL算法保证高辨识度、柔和不刺眼)
function generateRandomColors(count = 10) {
  const colors = [];
  const goldenAngle = 137.508; // é»„金角度,保证颜色分布均匀
  for (let i = 0; i < count; i++) {
    // ä½¿ç”¨é»„金角度分割确保颜色差异大
    const hue = (i * goldenAngle) % 360;
    // é¥±å’Œåº¦ï¼š40-70% é¿å…è¿‡äºŽé²œè‰³
    const saturation = 40 + Math.random() * 30;
    // æ˜Žåº¦ï¼š45-75% é¿å…è¿‡æš—或过亮
    const lightness = 45 + Math.random() * 30;
    colors.push(
      `hsl(${Math.round(hue)}, ${Math.round(saturation)}%, ${Math.round(
        lightness
      )}%)`
    );
  }
  return colors;
}
// HSL转16进制(可选,如果需要hex格式)
function hslToHex(hsl) {
  const match = hsl.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/);
  if (!match) return hsl;
  const h = parseInt(match[1]) / 360;
  const s = parseInt(match[2]) / 100;
  const l = parseInt(match[3]) / 100;
  const hue2rgb = (p, q, t) => {
    if (t < 0) t += 1;
    if (t > 1) t -= 1;
    if (t < 1 / 6) return p + (q - p) * 6 * t;
    if (t < 1 / 2) return q;
    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
    return p;
  };
  let r, g, b;
  if (s === 0) {
    r = g = b = l;
  } else {
    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    r = hue2rgb(p, q, h + 1 / 3);
    g = hue2rgb(p, q, h);
    b = hue2rgb(p, q, h - 1 / 3);
  }
  const toHex = (c) => {
    const hex = Math.round(c * 255).toString(16);
    return hex.length === 1 ? "0" + hex : hex;
  };
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
// ä¾¿æ·æ–¹æ³•:直接获取16进制颜色数组
function getRandomHexColors(count = 1) {
  return generateRandomColors(count).map(hslToHex);
}
// åƒåˆ†ä½æ ¼å¼åŒ–函数
function formatThousand(num) {
  if (typeof num === "number") return num.toLocaleString();
  if (typeof num === "string") {
    const n = Number(num.replace(/,/g, ""));
    if (isNaN(n)) return num;
    return n.toLocaleString();
  }
  return num;
}
// é”€å”®æ•°æ®åŽŸå§‹
const salesData = [
  { product: "原煤", quantity: "1234吨", amount: "Â¥456789", status: "已完成" },
  { product: "精煤", quantity: "567吨", amount: "Â¥234567", status: "已完成" },
  { product: "焦煤", quantity: "890吨", amount: "Â¥345678", status: "进行中" },
  { product: "块煤", quantity: "432吨", amount: "Â¥123456", status: "已完成" },
  { product: "煤泥", quantity: "20000吨", amount: "Â¥234567", status: "进行中" },
];
const tableHeaderStyle = {
  backgroundColor: "#f5f7fa",
  color: "#606266",
  fontSize: "12px",
};
// å›¾è¡¨ref
const pieChart = ref(null);
const areaChart = ref(null);
const barChart = ref(null);
// é¥¼å›¾åˆå§‹åŒ–
const initPieChart = () => {
  const chart = echarts.init(pieChart.value);
  const option = {
    tooltip: {
      trigger: "item",
      formatter: "{a} <br/>{b}: {c} ({d}%)",
    },
    legend: {
      orient: "vertical",
      left: "right",
      top: "center",
      textStyle: {
        fontSize: 12,
      },
    },
    series: [
      {
        name: "营收分布",
        type: "pie",
        radius: ["30%", "70%"],
        center: ["40%", "50%"],
        avoidLabelOverlap: false,
        label: {
          show: false,
          position: "center",
        },
        emphasis: {
          label: {
            show: true,
            fontSize: "16",
            fontWeight: "bold",
          },
        },
        labelLine: {
          show: false,
        },
        data: revenueDistribution.value,
      },
    ],
  };
  chart.setOption(option);
  window.addEventListener("resize", () => {
    chart.resize();
  });
};
// é¢ç§¯å›¾åˆå§‹åŒ–
const initAreaChart = () => {
  const chart = echarts.init(areaChart.value);
  const option = {
    title: {
      show: supplyTrend.value.length == 0, // æ²¡æ•°æ®æ‰æ˜¾ç¤º
      extStyle: {
        color: "grey",
        fontSize: 20,
      },
      text: "暂无数据",
      left: "center",
      top: "center",
    },
    tooltip: {
      trigger: "axis",
      axisPointer: {
        type: "cross",
        label: {
          backgroundColor: "#6a7985",
        },
      },
    },
    legend: {
      data: ["供应量"],
      top: 10,
    },
    grid: {
      left: "3%",
      right: "4%",
      bottom: "3%",
      containLabel: true,
    },
    xAxis: [
      {
        type: "category",
        boundaryGap: false,
        data: supplyTrend.value.Xkeys || [],
        axisLabel: {
          fontSize: 12,
        },
      },
    ],
    yAxis: [
      {
        type: "value",
        axisLabel: {
          fontSize: 12,
        },
      },
    ],
    series: [
      {
        name: "供应量",
        type: "line",
        stack: "Total",
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: "rgba(64, 158, 255, 0.3)" },
            { offset: 1, color: "rgba(64, 158, 255, 0.1)" },
          ]),
        },
        emphasis: {
          focus: "series",
        },
        data: supplyTrend.value.Yvalues || [],
        lineStyle: {
          color: "#409EFF",
        },
        itemStyle: {
          color: "#409EFF",
        },
      },
    ],
  };
  chart.setOption(option);
  window.addEventListener("resize", () => {
    chart.resize();
  });
};
// æŸ±çŠ¶å›¾åˆå§‹åŒ–
const initBarChart = () => {
  const chart = echarts.init(barChart.value);
  const option = {
    tooltip: {
      trigger: "axis",
      axisPointer: {
        type: "shadow",
      },
    },
    grid: {
      left: "3%",
      right: "4%",
      bottom: "3%",
      containLabel: true,
    },
    xAxis: {
      type: "category",
      data: ["原煤", "精煤", "焦煤", "块煤", "煤泥"],
      axisLabel: {
        fontSize: 11,
      },
    },
    yAxis: {
      type: "value",
      axisLabel: {
        fontSize: 11,
      },
    },
    series: [
      {
        name: "销量",
        type: "bar",
        data: [320, 302, 301, 334, 290],
        itemStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: "#409EFF" },
            { offset: 1, color: "#79bbff" },
          ]),
        },
        barWidth: "60%",
      },
    ],
  };
  chart.setOption(option);
  window.addEventListener("resize", () => {
    chart.resize();
  });
};
// æ”¶å…¥åˆ†å¸ƒæ•°æ®
const revenueDistribution = ref([]);
// åˆå§‹åŒ–所有图表
const initCharts = () => {
  initPieChart();
  initAreaChart();
  initBarChart();
};
const getList = async () => {
  try {
    searchMonth();
    const res = await getCoalInfo();
    homePageData.value = res.data || {};
    revenueDistribution.value = [];
    if (homePageData.value.revenueDistribution) {
      Object.keys(homePageData.value.revenueDistribution).forEach((key) => {
        let obj = {};
        obj.name = key;
        obj.value = homePageData.value.revenueDistribution[key];
        obj.itemStyle = {
          color: getRandomHexColors(1)[0], // ä½¿ç”¨éšæœºé¢œè‰²
        };
        revenueDistribution.value.push(obj);
      });
    }
    if (homePageData.value.inventory) {
      let inventoryListXkeys = Object.keys(homePageData.value.inventory);
      let inventoryListYvalues = Object.values(homePageData.value.inventory);
      inventoryList.value = {
        Xkeys: inventoryListXkeys,
        Yvalues: inventoryListYvalues,
      };
    }
    console.log(inventoryList.value)
    // æ•°æ®åŠ è½½å®ŒæˆåŽé‡æ–°åˆå§‹åŒ–å›¾è¡¨
    nextTick(() => {
      initCharts();
    });
  } catch (error) {
    console.error("获取煤种信息失败:", error);
  }
};
const inventoryList = ref([]);
const supplyTrend = ref({});
const searchMonth = async () => {
  let res = await getYearlySales({
    timeRange: selectMonth.value ? selectMonth.value : null,
  });
  let Xkeys = Object.keys(res.data.data);
  let Yvalues = Object.values(res.data.data);
  supplyTrend.value = {
    Xkeys,
    Yvalues,
  };
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss">
@@ -363,11 +530,11 @@
}
.revenue .card-icon {
  background: linear-gradient(135deg, #409EFF, #79bbff);
  background: linear-gradient(135deg, #409eff, #79bbff);
}
.supply .card-icon {
  background: linear-gradient(135deg, #67C23A, #95d475);
  background: linear-gradient(135deg, #67c23a, #95d475);
}
.card-content {
@@ -397,7 +564,10 @@
}
.trend-value.up {
  color: #67C23A;
  color: #67c23a;
}
.trend-value.down {
  color: #f56c6c;
}
/* ä¸­é—´å›¾è¡¨åŒºåŸŸ */
@@ -406,7 +576,7 @@
  gap: 20px;
  margin-bottom: 20px;
}
.el-scrollbar__view{
.el-scrollbar__view {
  width: 100%;
}
.chart-container {
@@ -424,6 +594,8 @@
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 2px solid #f0f0f0;
  display: flex;
  justify-content: space-between;
}
.chart-content {
@@ -471,7 +643,7 @@
  padding: 12px;
  background: #f8f9fa;
  border-radius: 6px;
  border-left: 3px solid #409EFF;
  border-left: 3px solid #409eff;
}
.item-name {
@@ -493,12 +665,12 @@
.item-status.normal {
  background: #f0f9ff;
  color: #67C23A;
  color: #67c23a;
}
.item-status.low {
  background: #fef0e6;
  color: #E6A23C;
  color: #e6a23c;
}
/* æŸ±çж图容噍 */
@@ -519,22 +691,21 @@
.bottom-card.table .el-table th {
  padding: 8px 0;
}
:deep(.el-scrollbar__view){
:deep(.el-scrollbar__view) {
  width: 100% !important;
}
:deep(.el-table__header,){
    width: 100% !important;
  }
:deep(.el-table__body,){
    width: 100% !important;
  }
:deep(.el-table__header, ) {
  width: 100% !important;
}
:deep(.el-table__body, ) {
  width: 100% !important;
}
/* å“åº”式设计 */
@media (max-width: 1200px) {
  .bottom-section {
    flex-direction: column;
  }
  .chart-section {
    flex-direction: column;
  }
@@ -544,15 +715,15 @@
  .top-cards {
    flex-direction: column;
  }
  .dashboard {
    padding: 10px;
  }
  .stat-card {
    padding: 15px;
  }
  .card-value {
    font-size: 20px;
  }
src/views/procureMent/index.vue
@@ -20,9 +20,9 @@
        <el-button type="primary" :icon="Plus" @click="handleAdd"
          >新建
        </el-button>
        <el-button type="danger" :icon="Delete" @click="handleDelete"
        <!-- <el-button type="danger" :icon="Delete" @click="handleDelete"
          >删除
        </el-button>
        </el-button> -->
      </el-row>
      <!-- è¡¨æ ¼ç»„ä»¶ -->
      <data-table
@@ -76,8 +76,12 @@
  delPR
} from "@/api/procureMent";
import { useDelete } from "@/hooks/useDelete";
const userStore = useUserStore();
import useUserStore from "@/store/modules/user";
let userList = ref([]);
userStore.getUserList().then((res) => {
  userList.value = res;
});
// å¼•入字典数据
const { proxy } = getCurrentInstance();
const dialogFormVisible = ref(false);
@@ -109,7 +113,7 @@
  // è¿™é‡Œæ·»åŠ å®žé™…çš„æŸ¥è¯¢é€»è¾‘
  getList();
};
const userStore = useUserStore();
// èŽ·å–ç”¨æˆ·ä¿¡æ¯
const userInfo = ref({});
onMounted(async () => {
@@ -148,7 +152,13 @@
  { prop: "totalPriceIncludingTax", label: "总价(含税)", minWidth: 100 },
  { prop: "taxRate", label: "税率", minWidth: 100 },
  { prop: "priceExcludingTax", label: "不含税单价", minWidth: 100 },
  { prop: "registrantId", label: "登记人", minWidth: 100 },
  { prop: "registrantId", label: "登记人", minWidth: 100,
    formatter: (row) => {
      // åŒ¹é…ç”¨æˆ·ä¿¡æ¯
      const user = userList.value.find((user) => user.userId === row.registrantId);
      return user ? user.nickName : "未知用户";
    },
  },
  { prop: "registrationDate", label: "登记日期", minWidth: 100 },
]);
src/views/production/components/ProductionDetailsTable.vue
@@ -50,10 +50,13 @@
    <el-table-column label="能耗成本" min-width="120">
      <template #default="{ row, $index }">
        <!-- ä¸èƒ½ä¸ºè´Ÿæ•° -->
        <el-input
            v-model="row.energyConsumptionCost"
            placeholder="请输入能耗成本"
            type="number"
            min="0"
            step="0.01"
            @input="handleInput('energyConsumptionCost', $index, $event)"
            :disabled="isViewMode"
        >
@@ -156,6 +159,7 @@
<script setup name="ProductionDetailsTable">
import {ref, computed, watch, onMounted, nextTick} from "vue";
import {Delete} from "@element-plus/icons-vue";
import {ElMessage} from "element-plus";
import {getCoalFieldList} from "@/api/basicInformation/coalQualityMaintenance";
import {getCoalInfoList} from "@/api/production";
import {userListAll} from "@/api/publicApi";
@@ -197,6 +201,11 @@
// å¤„理输入变化
const handleInput = (field, index, value) => {
  // ç¡®ä¿è¾“入值是数字或空字符串而且非负数
  if (!/^\d*\.?\d*$/.test(value) && value !== "") {
    ElMessage.error("请输入有效的数字");
    return;
  }
  const newData = [...tableData.value];
  newData[index][field] = value;
src/views/production/components/ProductionDialog.vue
@@ -200,10 +200,10 @@
const currentRow = ref(null);
const copyForm = ref(null);
const coalList = ref([])
const supplierList = ref({});
const supplierList = ref([]);
// è¡¨æ ¼åˆ—配置
const columns = [
  {prop: "coalId", label: "煤种", minwidth: 60,slot:false,
  {prop: "coalId", label: "煤种", minwidth: 60,
    formatter: (row) => {
      return coalList.value.find(coal => coal.id === row.coalId)?.coal || "--";
    }
@@ -219,11 +219,6 @@
];
const formalDatabaseColumns = ref([
  {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.find(coal => coal.id === row.coalId)?.coal || "--";
@@ -247,29 +242,51 @@
  currentRow.value = row;
};
// èŽ·å–åŸºç¡€æ•°æ®ï¼ˆç…¤ç§å’Œä¾›åº”å•†ï¼‰
const loadBasicData = async () => {
  try {
    const [coalResponse, supplierResponse] = await Promise.all([
      getCoalInfoList(),
      getSupplyList()
    ]);
    coalList.value = coalResponse.data || [];
    supplierList.value = supplierResponse.data || [];
  } catch (error) {
    ElMessage.error("获取基础数据失败");
  }
};
// èŽ·å–é…ç½®æ•°æ®
const handlData = async () => {
  innerVisible.value = true;
  let OfficialAll = await getOfficialAll();
  let getSupplierList = await getSupplyList();
  let getCoalName = await getCoalInfoList();
  coalList.value = getCoalName.data || [];
  supplierList.value = getSupplierList.data || [];
  if (OfficialAll.code === 200) {
    formalDatabaseData.value = OfficialAll.data;
    const existingOfficialIds = tableData.value
        .map((item) => item.officialId)
        .filter((id) => id);
    selectedIds.value = existingOfficialIds;
    debugIdMatching();
    nextTick(() => {
      setTimeout(() => {
        if (etableRef.value && existingOfficialIds.length > 0) {
          etableRef.value.setDefaultSelection();
        }
      }, 100);
    });
  } else {
  // ç¡®ä¿åŸºç¡€æ•°æ®å·²åŠ è½½
  if (coalList.value.length === 0 || supplierList.value.length === 0) {
    await loadBasicData();
  }
  try {
    const OfficialAll = await getOfficialAll();
    if (OfficialAll.code === 200) {
      formalDatabaseData.value = OfficialAll.data;
      const existingOfficialIds = tableData.value
          .map((item) => item.officialId)
          .filter((id) => id);
      selectedIds.value = existingOfficialIds;
      debugIdMatching();
      nextTick(() => {
        setTimeout(() => {
          if (etableRef.value && existingOfficialIds.length > 0) {
            etableRef.value.setDefaultSelection();
          }
        }, 100);
      });
    } else {
      ElMessage.error("获取配置数据失败");
    }
  } catch (error) {
    ElMessage.error("获取配置数据失败");
  }
};
@@ -296,14 +313,17 @@
};
// åˆå§‹åŒ–和编辑初始化
const Initialization = () => {
const Initialization = async () => {
  tableData.value = [];
  detailsTableData.value = [];
  copyForm.value = null;
  dialogType.value = "add";
  // åŠ è½½åŸºç¡€æ•°æ®
  await loadBasicData();
};
const editInitialization = (type,data) => {
const editInitialization = async (type, data) => {
  copyForm.value = deepClone(data);
  tableData.value = data.productionInventoryList || [];
  detailsTableData.value = data.productionList || [];
@@ -312,6 +332,9 @@
      .map((item) => item.officialId)
      .filter((id) => id);
  selectedIds.value = existingOfficialIds;
  // åŠ è½½åŸºç¡€æ•°æ®
  await loadBasicData();
};
// ç›‘听对话框状态,在打开时设置选中状态
watch(innerVisible, (newVal) => {
@@ -457,12 +480,13 @@
  }
};
// èŽ·å–ç”¨æˆ·ä¿¡æ¯
// èŽ·å–ç”¨æˆ·ä¿¡æ¯å¹¶åŠ è½½åŸºç¡€æ•°æ®
onMounted(async () => {
  try {
    userInfo = await userStore.getInfo();
    await loadBasicData();
  } catch (error) {
    ElMessage.error("获取用户信息失败,请重试");
    ElMessage.error("初始化失败,请重试");
  }
});