张诺
6 小时以前 7c86b549b27bd54f6bd5de81c13f8242f91c87ff
优化文件上传组件及表格显示
已修改8个文件
1246 ■■■■■ 文件已修改
src/components/FileUpload/index.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/ETable.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/EtableModify.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/archiveManagement/mould/archiveDialog.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDetailsTable.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDetailsTableExample.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/components/ProductionDialog.vue 417 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/production/index.vue 319 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue
@@ -121,15 +121,15 @@
// 上传前校检格式和大小
function handleBeforeUpload(file) {
  // 校检文件类型
  if (props.fileType.length) {
    const fileName = file.name.split('.')
    const fileExt = fileName[fileName.length - 1]
    const isTypeOk = props.fileType.indexOf(fileExt) >= 0
    if (!isTypeOk) {
      proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}格式文件!`)
      return false
    }
  }
  // if (props.fileType.length) {
  //   const fileName = file.name.split('.')
  //   const fileExt = fileName[fileName.length - 1]
  //   const isTypeOk = props.fileType.indexOf(fileExt) >= 0
  //   if (!isTypeOk) {
  //     proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}格式文件!`)
  //     return false
  //   }
  // }
  // 校检文件名是否包含特殊字符
  if (file.name.includes(',')) {
    proxy.$modal.msgError('文件名不正确,不能包含英文逗号!')
@@ -237,6 +237,11 @@
.upload-file-uploader {
  margin-bottom: 5px;
}
.upload-file-list {
  margin-top: 10px;
  max-height: 150px;
  overflow-y: auto;
}
.upload-file-list .el-upload-list__item {
  border: 1px solid #e4e7ed;
  line-height: 2;
@@ -249,8 +254,12 @@
  justify-content: space-between;
  align-items: center;
  color: inherit;
  max-height: 20px;
}
.ele-upload-list__item-content-action .el-link {
  margin-right: 10px;
}
.el-icon-document{
  padding-left: 10px;
}
</style>
src/components/Table/ETable.vue
@@ -1,9 +1,24 @@
<template>
  <el-table v-loading="loading" :data="tableData" :border="border" :show-selection="showSelection" :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }" @selection-change="handleSelectionChange"
    @row-click="handleRowClick" @row-dblclick="handleRowDblClick" @cell-click="handleCellClick" :max-width="maxWidth"
    @export="handleExport">
    <el-table-column v-if="showSelection" type="selection" width="55" align="center" />    <el-table-column v-if="showIndex" label="序号" type="index" width="60" align="center" />
<template>  <el-table
    v-loading="loading"
    :data="tableData"
    :border="border"
    :show-selection="showSelection"
    :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }"
    @selection-change="handleSelectionChange"
    @row-click="handleRowClick"
    @row-dblclick="handleRowDblClick"
    @cell-click="handleCellClick"
    :max-width="maxWidth"
    @export="handleExport"
    :default-selection="defaultSelection"
    :show-overflow-tooltip="showOverflowTooltip"
    ref="tableRef"
    :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="序号" type="index" width="60" align="center" />
    <template v-for="col in columns" :key="col.prop">
      <el-table-column v-bind="col" :show-overflow-tooltip="shouldShowTooltip(col, tableData)"
        :formatter="col.formatter || defaultFormatter" align="center">
@@ -32,7 +47,7 @@
</template>
  
  <script setup>
import { defineEmits } from 'vue'
import { defineEmits, ref , defineProps, onMounted ,defineExpose, watch, nextTick} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
const props = defineProps({
  // 最大宽度
@@ -110,13 +125,27 @@
  operations: {
    type: Array,
    default: () => ['edit', 'delete', 'export']
  },
  // 删除确认信息
  },  // 删除确认信息
  deleteConfirmText: {
    type: String,
    default: '确认删除该记录?'
  },
  // 默认选中的行 ID 数组
  defaultSelectedIds: {
    type: Array,
    default: () => []
  },
  // 行唯一标识字段名(默认为 id)
  rowKey: {
    type: String,
    default: 'id'
  },
  showOverflowTooltip: {
    type: Boolean,
    default: true
  }
})
const tableRef = ref(null)
// 检查列是否需要显示tooltip
const shouldShowTooltip = (col, data) => {
  // 如果列配置中明确设置了showOverflowTooltip,使用该设置
@@ -159,6 +188,85 @@
const handleExport = (row) => {
  emit('export', row)
}
// 正确的 toggleRowSelection 方法:针对单行
const toggleRowSelection = (row, selected) => {
  if (tableRef.value && row) {
    tableRef.value.toggleRowSelection(row, selected);
  }
};
// 批量设置行选中状态的方法
const setRowsSelection = (rows, selected = true) => {
  if (tableRef.value && Array.isArray(rows)) {
    rows.forEach((row) => {
      tableRef.value.toggleRowSelection(row, selected);
    });
  }
};
// 复选框默认选中状态
const defaultSelection = ref([])
// 设置默认选中状态
const setDefaultSelection = () => {
  if (!tableRef.value || !props.defaultSelectedIds.length || !props.tableData.length) {
    return;
  }
  // 延迟执行,确保表格完全渲染
  nextTick(() => {
    setTimeout(() => {
      try {
        tableRef.value.clearSelection();
        const rowsToSelect = props.tableData.filter(row => {
          const rowId = row[props.rowKey];
          return props.defaultSelectedIds.includes(rowId);
        });
        rowsToSelect.forEach(row => {
          tableRef.value.toggleRowSelection(row, true);
        });
      } catch (error) {
      }
    }, 100);
  });
};
// 监听数据变化,自动设置默认选中
watch(() => [props.tableData, props.defaultSelectedIds], () => {
  if (props.tableData.length > 0 && props.defaultSelectedIds.length > 0) {
    setDefaultSelection();
  }
}, {
  deep: true,
  immediate: true
});
// 组件挂载后设置默认选中
onMounted(() => {
  if (props.defaultSelectedIds.length > 0) {
    setDefaultSelection();
  }
});
// 暴露 el-table 的实例和常用方法
defineExpose({
  // 单行选中/取消选中
  toggleRowSelection,
  // 批量设置行选中状态
  setRowsSelection,
  // 根据ID数组选中行
  setDefaultSelection,
  // 清除所有选中
  clearSelection: () => tableRef.value?.clearSelection(),
  // 获取选中的行
  getSelectionRows: () => tableRef.value?.getSelectionRows() || [],
  // 设置当前行
  setCurrentRow: (row) => tableRef.value?.setCurrentRow(row),
  // 获取表格实例(如需直接操作)
  getTableRef: () => tableRef.value
});
</script>
  
  <style scoped>
src/components/Table/EtableModify.vue
@@ -1,36 +1,92 @@
<template>
  <el-table v-loading="loading" :data="tableData" :border="border" :show-selection="showSelection" :height="height" :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }" @selection-change="handleSelectionChange"
    @row-click="handleRowClick" @row-dblclick="handleRowDblClick" :row-class-name="tableRowClassName" @cell-click="handleCellClick" :max-width="maxWidth"
    @export="handleExport">
    <el-table-column v-if="showSelection" type="selection" width="55" align="center" />
    <el-table-column v-if="showIndex" label="序号" type="index" width="60" align="center" /> <template
      v-for="col in columns" :key="col.prop">
      <el-table-column v-bind="col" :show-overflow-tooltip="shouldShowTooltip(col, tableData)" align="center"> <template
          #default="scope">
  <el-table
    v-loading="loading"
    :data="tableData"
    :border="border"
    :show-selection="showSelection"
    :height="height"
    :max-height="maxHeight"
    :header-cell-style="{ background: '#EBEEF5', color: '#3D3D3D' }"
    @selection-change="handleSelectionChange"
    @row-click="handleRowClick"
    @row-dblclick="handleRowDblClick"
    :row-class-name="tableRowClassName"
    @cell-click="handleCellClick"
    :max-width="maxWidth"
    @export="handleExport"
    :show-overflow-tooltip="showOverflowTooltip"
  >
    <el-table-column
      v-if="showSelection"
      type="selection"
      width="55"
      align="center"
    />
    <el-table-column
      v-if="showIndex"
      label="序号"
      type="index"
      width="60"
      align="center"
    />
    <template v-for="col in columns" :key="col.prop">
      <el-table-column
        v-bind="col"
        :show-overflow-tooltip="shouldShowTooltip(col, tableData)"
        align="center"
      >
        <template #default="scope">
          <template v-if="col.slot">
            <slot></slot>
          </template>
          <template v-else>
            <div class="cell-edit" @dblclick="handleCellEdit(scope.row, col.prop)"
              :class="{'editable': isColumnEditable(col.prop)}"> <span
                v-if="!scope.row.editing || !scope.row.editing[col.prop]" class="cell-text">
                {{ scope.row[col.prop] == null || scope.row[col.prop] === '' ? '--' : scope.row[col.prop] }}
            <div
              class="cell-edit"
              @dblclick="handleCellEdit(scope.row, col.prop)"
              :class="{ editable: isColumnEditable(col.prop) }"
            >
              <span
                v-if="!scope.row.editing || !scope.row.editing[col.prop]"
                class="cell-text"
              >
                {{
                  scope.row[col.prop] == null || scope.row[col.prop] === ""
                    ? "--"
                    : scope.row[col.prop]
                }}
              </span>
              <el-input v-else v-model="scope.row[col.prop]" size="small"
                @focus="handleCellFocus(scope.row, col.prop, $event)" @blur="handleCellSave(scope.row, col.prop)"
                @keyup.enter="handleCellSave(scope.row, col.prop)" class="cell-input" />
              <el-input
                v-else
                v-model="scope.row[col.prop]"
                size="small"
                @focus="handleCellFocus(scope.row, col.prop, $event)"
                @blur="handleCellSave(scope.row, col.prop)"
                @keyup.enter="handleCellSave(scope.row, col.prop)"
                class="cell-input"
              />
            </div>
          </template>
        </template>
      </el-table-column>
    </template>
    <!-- 操作列 -->
    <el-table-column v-if="showOperations" :label="operationsLabel" :width="operationsWidth" fixed="right" align="center">
    <el-table-column
      v-if="showOperations"
      :label="operationsLabel"
      :width="operationsWidth"
      fixed="right"
      align="center"
    >
      <template #default="scope">
        <slot name="operations" :row="scope.row">
          <el-button v-if="operations.includes('edit')" link type="primary" size="small"
            @click="handleEdit(scope.row)">编辑</el-button>
          <el-button
            v-if="operations.includes('edit')"
            link
            type="primary"
            size="small"
            @click="handleEdit(scope.row)"
            >编辑</el-button
          >
          <!--            <el-button-->
          <!--              v-if="operations.includes('delete')"-->
          <!--              link-->
@@ -43,119 +99,123 @@
    </el-table-column>
  </el-table>
</template>
  <script setup>
import { defineEmits, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
<script setup>
import { defineEmits, nextTick } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
const props = defineProps({
  // 获取行样式
  tableRowClassName: {
    type: Function,
    default: () => ''
    default: () => "",
  },
  // 获取高度
  height: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  // 是否允许编辑单元格
  editableCells: {
    type: Boolean,
    default: true
    default: true,
  },
  // 指定可编辑的列,如果为空数组则表示所有列都不可编辑
  editableColumns: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 最大宽度
  maxWidth: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  handleCellClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleRowClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleExport: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  handleRowDblClick: {
    type: Function,
    default: () => { }
    default: () => {},
  },
  // 高度
  maxHeight: {
    type: [String, Number],
    default: 'auto'
    default: "auto",
  },
  // 加载状态
  loading: {
    type: Boolean,
    default: false
    default: false,
  },
  //   border
  border: {
    type: Boolean,
    default: false
    default: false,
  },
  // 表格数据
  tableData: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 是否显示选择列
  showSelection: {
    type: Boolean,
    default: false
    default: false,
  },
  // 是否显示序号列
  showIndex: {
    type: Boolean,
    default: true
    default: true,
  },
  // 列配置
  columns: {
    type: Array,
    default: () => []
    default: () => [],
  },
  // 是否显示操作列
  showOperations: {
    type: Boolean,
    default: true
    default: true,
  },
  // 操作列标签
  operationsLabel: {
    type: String,
    default: '操作'
    default: "操作",
  },
  // 操作列宽度
  operationsWidth: {
    type: [String, Number],
    default: 100
    default: 100,
  },
  // 显示哪些操作按钮
  operations: {
    type: Array,
    default: () => ['edit', 'delete', 'export']
    default: () => ["edit", "delete", "export"],
  },
  // 删除确认信息
  deleteConfirmText: {
    type: String,
    default: '确认删除该记录?'
  }
})
    default: "确认删除该记录?",
  },
  showOverflowTooltip: {
    type: Boolean,
    default: true,
  },
});
// 检查列是否需要显示tooltip
const shouldShowTooltip = (col, data) => {
  // 如果没有prop,直接返回false
  if (!col.prop) return false;
  // 检查该列在所有数据中是否有非空值
  return data.some(row => row[col.prop] != null && row[col.prop] !== '');
  return data.some((row) => row[col.prop] != null && row[col.prop] !== "");
};
// 处理单元格编辑
@@ -164,7 +224,8 @@
  if (!props.editableCells) return;
  // 如果指定了可编辑列,且当前列不在可编辑列中,则不允许编辑
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop)) return;
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop))
    return;
  // 初始化editing对象
  if (!row.editing) {
@@ -175,28 +236,29 @@
  // 在下一个DOM更新周期,让输入框获得焦点并选中内容
  setTimeout(() => {
    const inputElement = document.querySelector('.cell-edit .el-input__inner');
    const inputElement = document.querySelector(".cell-edit .el-input__inner");
    if (inputElement) {
      inputElement.focus();
      inputElement.select();
    }
  }, 10);
}
};
// 处理单元格保存
const handleCellSave = (row, prop) => {
  // 关闭编辑状态
  row.editing[prop] = false;
  // 触发单元格编辑完成事件
  emit('cell-edit', row, prop, row[prop]);
}
  emit("cell-edit", row, prop, row[prop]);
};
// 处理单元格聚焦事件
const handleCellFocus = (row, prop, event) => {
  // 如果不允许编辑单元格,直接返回
  if (!props.editableCells) return;
  // 如果指定了可编辑列,且当前列不在可编辑列中,则不允许编辑
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop)) return;
  if (props.editableColumns.length > 0 && !props.editableColumns.includes(prop))
    return;
  // 初始化editing对象
  if (!row.editing) {
@@ -209,70 +271,75 @@
  if (event && event.target) {
    event.target.select();
  }
}
};
// 判断列是否可编辑
const isColumnEditable = (prop) => {
  if (props.editableColumns.length === 0) {
    return props.editableCells;
  }
  return props.editableColumns.includes(prop);
}
};
// 处理选择变化、编辑、删除和导出操作
const emit = defineEmits(['selection-change', 'edit', 'delete', 'export', 'cell-edit'])
const emit = defineEmits([
  "selection-change",
  "edit",
  "delete",
  "export",
  "cell-edit",
]);
const handleSelectionChange = (selection) => {
  emit('selection-change', selection)
}
  emit("selection-change", selection);
};
const handleEdit = (row) => {
  emit('edit', row)
}
  emit("edit", row);
};
const handleExport = (row) => {
  emit('export', row)
}
  </script>
  <style scoped lang="scss">
  emit("export", row);
};
</script>
<style scoped lang="scss">
.el-table {
    margin: 20px 0 !important;
  }
  :deep(.el-table th) {
    background-color: #f5f7fa;
  }
  :deep(.cell-edit) {
  margin: 20px 0 !important;
}
:deep(.el-table th) {
  background-color: #f5f7fa;
}
:deep(.cell-edit) {
  width: 100%;
  height: 100%;
  position: relative;
}
:deep(.cell-edit .cell-text) {
  width: 100%;
  display: block;
}
:deep(.cell-edit.editable:hover .cell-text) {
  color: #409eff;
  cursor: pointer;
}
:deep(.cell-input) {
  width: 80%;
  max-width: 120px;
  min-width: 60px;
}
:deep(.cell-input .el-input__inner) {
  border-radius: 4px;
  text-align: center;
  transition: all 0.2s;
}
/* 响应式样式 */
@media screen and (max-width: 768px) {
  :deep(.el-table) {
    width: 100%;
    height: 100%;
    position: relative;
    overflow-x: auto;
  }
  :deep(.cell-edit .cell-text) {
    width: 100%;
    display: block;
  }
  :deep(.cell-edit.editable:hover .cell-text) {
    color: #409EFF;
    cursor: pointer;
  }
  :deep(.cell-input) {
    width: 80%;
    max-width: 120px;
    min-width: 60px;
  }
  :deep(.cell-input .el-input__inner) {
    border-radius: 4px;
    text-align: center;
    transition: all 0.2s;
  }
  /* 响应式样式 */
  @media screen and (max-width: 768px) {
    :deep(.el-table) {
      width: 100%;
      overflow-x: auto;
    }
  }
</style>
}
</style>
src/views/archiveManagement/mould/archiveDialog.vue
@@ -1,5 +1,5 @@
<template>
  <el-dialog v-model="centerDialogVisible" title="Warning" width="500" center>
  <el-dialog v-model="centerDialogVisible" title="文档管理" width="500" center>
    <el-form
      ref="ruleFormRef"
      style="max-width: 600px"
@@ -8,7 +8,7 @@
      label-width="auto"
    >
      <el-form-item label="名称" prop="name">
        <el-input v-model="ruleForm.name" placeholder="请输入文档名称"/>
        <el-input v-model="ruleForm.name" placeholder="请输入文档名称" />
      </el-form-item>
      <el-form-item label="请输入文档类型" prop="type">
        <el-select v-model="ruleForm.type" placeholder="请输入文档类型">
@@ -18,24 +18,36 @@
      </el-form-item>
      <el-form-item label="请输入文档状态" prop="status">
        <el-select v-model="ruleForm.status" placeholder="请输入文档状态">
          <el-option v-for="option in options" :key="option.value" :label="option.label" :value="option.value" />
          <el-option
            v-for="option in options"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          />
        </el-select>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="centerDialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="submit">
          Confirm
        </el-button>
      </div>
      <el-row>
        <el-col :span="24" style="text-align: right">
          <el-button @click="centerDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="submit"> 确 定 </el-button>
        </el-col>
      </el-row>
    </template>
    <fileUpload
    v-model="ruleForm.file"
    :fileSize="1024"
    :fileType="['pdf', 'docx', 'txt', 'xlsx', 'pptx....']"
    :limit="10"
    />
  </el-dialog>
</template>
<script setup>
import { ref, watch } from "vue";
import { addOrEditArchive } from "@/api/archiveManagement"
import { addOrEditArchive } from "@/api/archiveManagement";
import fileUpload from "@/components/FileUpload/index.vue";
const centerDialogVisible = defineModel("centerDialogVisible", {
  type: Boolean,
@@ -66,22 +78,20 @@
// 初始化表单数据
const ruleFormRef = ref(null);
const ruleForm = ref(initFormData(props.row));
const copyForm = ref()
const copyForm = ref();
// 监听 row 的变化,更新 ruleForm
watch(() => props.row, (newRow) => {
  copyForm.value = initFormData(newRow);
  ruleForm.value = JSON.parse(JSON.stringify(copyForm.value));
}, { deep: true });
watch(
  () => props.row,
  (newRow) => {
    copyForm.value = initFormData(newRow);
    ruleForm.value = JSON.parse(JSON.stringify(copyForm.value));
  },
  { deep: true }
);
const rules = {
  name: [
    { required: true, message: "Please input activity name", trigger: "blur" },
  ],
  type: [
    { required: true, message: "Please select activity zone", trigger: "change" },
  ],
  status: [
    { required: true, message: "Please select activity count", trigger: "change" },
  ],
  name: [{ required: true, message: "请输入文档名称", trigger: "blur" }],
  type: [{ required: true, message: "请选择文档类型", trigger: "blur" }],
  status: [{ required: true, message: "请选择文档状态", trigger: "blur" }],
};
const options = [
@@ -93,27 +103,27 @@
const submit = async () => {
  // 验证表单
  if (!ruleFormRef.value) return;
  try {
    const valid = await ruleFormRef.value.validate();
    if (!valid) {
      return;
    }
    // 调用 API
    let res = await addOrEditArchive(ruleForm.value);
    console.log("API 响应:", res);
    // 发送 emit 事件
    emit("submitForm", res);
    console.log("emit submitForm 已发送");
    // 关闭对话框
    centerDialogVisible.value = false;
  } catch (error) {
    console.error("表单验证失败或API调用失败:", error);
  }
}
};
</script>
<style lang="less" scoped></style>
src/views/production/components/ProductionDetailsTable.vue
@@ -3,9 +3,9 @@
    <el-table-column label="煤种" min-width="120" >
      <template #default="{ row, $index }" >
        <el-input 
          v-model="row.coalType"
          v-model="row.coal"
          placeholder="请输入煤种"
          @input="handleInput('coalType', $index, $event)"
          @input="handleInput('coal', $index, $event)"
        />
      </template>
    </el-table-column>
@@ -191,7 +191,7 @@
  calculateTotalCost,
  addRow: (rowData = {}) => {
    const defaultRow = {
      coalType: '',
      coal: '',
      calorificValue: '',
      productionQuantity: '',
      laborCost: '',
src/views/production/components/ProductionDetailsTableExample.vue
@@ -36,7 +36,7 @@
// 表格数据
const tableData = ref([
  {
    coalType: '动力煤',
    coal: '动力煤',
    calorificValue: '5000',
    productionQuantity: '100',
    laborCost: '1000',
@@ -63,7 +63,7 @@
const addRow = () => {
  if (tableRef.value) {
    tableRef.value.addRow({
      coalType: '新煤种',
      coal: '',
      calorificValue: '0',
      productionQuantity: '0',
      laborCost: '0',
src/views/production/components/ProductionDialog.vue
@@ -1,4 +1,4 @@
div<template>
<template>
  <el-dialog
    v-model="dialogVisible"
    :title="dialogType === 'add' ? '新增生产加工' : '编辑生产加工'"
@@ -6,57 +6,91 @@
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <el-button type="primary" @click="handlData">选择数据</el-button>
    <ETableModify
      :columns="columns"
      height="200"
      @cell-edit="handleCellEdit"
      :showOperations="false"
      :tableData="tableData"
      @row-click="handleRowClick"
      :editableColumns="['used']"
    />
    <div class="empty-table">
    <h1>生产明细</h1>
      <el-row :gutter="10">
      <el-col :span="2">
        <el-button type="primary" @click="addNewRow">
          <el-icon>
            <Plus />
          </el-icon>
          新增
        </el-button>
    <el-row :gutter="10" style="margin-bottom: 10px">
      <el-col :span="3">
        <el-button type="primary" @click="handlData"
          ><el-icon>
            <Plus /> </el-icon
          >选择数据</el-button
        >
      </el-col>
      <el-col :span="2">
        <el-button type="danger" @click="clearAllRows">
      <el-col :span="4">
        <el-button
          type="danger"
          @click="removeSelectedData"
          :disabled="tableData.length === 0"
        >
          <el-icon>
            <Delete />
          </el-icon>
          清空
          清空已选
        </el-button>
      </el-col>
      <!-- <el-col :span="2">
      <el-col :span="17" style="text-align: right; line-height: 32px">
        <el-text type="info" size="small">
          已选择 {{ tableData.length }} 项数据
          <span v-if="tableData.length > 0">
            ,总使用量: {{ totalUsedQuantity.toFixed(2) }}
          </span>
        </el-text>
      </el-col>
    </el-row>
    <ETableModify
      :columns="columns"
      :showOperations="false"
      height="200"
      @cell-edit="handleCellEdit"
      :tableData="tableData"
      :showOverflowTooltip="false"
      @row-click="handleRowClick"
      :editableColumns="['usedQuantity']"
      @delete="handleRemoveItem"
    />
    <div class="empty-table">
      <h1>生产明细</h1>
      <el-row :gutter="10">
        <el-col :span="2">
          <el-button type="primary" @click="addNewRow">
            <el-icon>
              <Plus />
            </el-icon>
            新增
          </el-button>
        </el-col>
        <el-col :span="2">
          <el-button type="danger" @click="clearAllRows">
            <el-icon>
              <Delete />
            </el-icon>
            清空
          </el-button>
        </el-col>
        <!-- <el-col :span="2">
        <el-button type="warning" @click="calculateAllCosts">
          <el-icon>
            <Warning />
          </el-icon> 重新计算
        </el-button>
      </el-col> -->
    </el-row>
    <ProductionDetailsTable
      v-model="detailsTableData"
      :border="false"
      :show-operations="true"
      :auto-calculate="true"
      @input-change="handleDetailsChange"
      @delete-row="handleDeleteRow"
    />
      </el-row>
      <ProductionDetailsTable
        v-model="detailsTableData"
        :border="false"
        :show-operations="true"
        :auto-calculate="true"
        @input-change="handleDetailsChange"
        @delete-row="handleDeleteRow"
      />
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="handleClose">取 消</el-button>
        <el-button @click="handleClose" v-if="dialogType === 'add'"
          >取 消</el-button
        >
        <el-button @click="handleReset" v-if="dialogType === 'edit'"
          >重 置</el-button
        >
        <el-button type="primary" :loading="loading" @click="handleSubmit"
          >确 定</el-button
        >
@@ -70,31 +104,56 @@
    center
    append-to-body
  >
    <div style="margin-bottom: 10px">
      <el-alert
        v-if="tableData.length > 0"
        :title="`当前已选择 ${tableData.length} 条数据`"
        type="info"
        :closable="false"
        show-icon
      />
    </div>
    <ETable
      @selection-change="handleSelectionChange"
      :showOperations="false"
      ref="etableRef"
      :columns="formalDatabaseColumns"
      :tableData="formalDatabaseData"
      :defaultSelectedIds="selectedIds"
      :rowKey="'id'"
      height="400"
      @cell-edit="handleCellEdit"
      :show-selection="true"
    />
    <el-row :gutter="24">
      <el-col :span="2" :offset="22">
        <el-button type="primary" @click="handleSelectData">确定</el-button>
    <el-row :gutter="24" style="margin-top: 15px">
      <el-col :span="12">
        <el-text type="info">
          已选择 {{ formalDatabaseSelectedData.length }} 条数据
        </el-text>
      </el-col>
      <el-col :span="12" style="text-align: right">
        <el-button @click="innerVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="handleSelectData"
          :disabled="formalDatabaseSelectedData.length === 0"
        >
          确定添加
        </el-button>
      </el-col>
    </el-row>
  </el-dialog>
</template>
<script setup>
import { ref, reactive, watch } from "vue";
import { ref, reactive, watch, onMounted, nextTick, computed } from "vue";
import ETable from "@/components/Table/ETable.vue";
import ETableModify from "@/components/Table/EtableModify.vue";
import ProductionDetailsTable from "./ProductionDetailsTable.vue";
import { ElMessage } from "element-plus";
import { ElMessage, ElMessageBox, ElAlert, ElText } from "element-plus";
import { Delete, Warning, Plus } from "@element-plus/icons-vue";
import { getOfficialAll } from "@/api/production/index.js";
import { getOfficialAll, addOrEditPM } from "@/api/production/index.js";
import { getCurrentInstance } from "vue";
const props = defineProps({
  visible: {
@@ -123,22 +182,27 @@
const tableData = ref([]);
const currentRow = ref(null);
const columns = [
  { label: "供应商名称", prop: "supplierName" },
  { label: "煤种", prop: "coal" },
  { label: "单价(不含税)", prop: "priceExcludingTax" },
  { label: "库存数量", prop: "inventoryQuantity" },
  { label: "煤种", prop: "coal", minwidth: 120 },
  { label: "库存数量", prop: "inventoryQuantity", minwidth: 100 },
  {
    label: "使用数量",
    prop: "used",
    prop: "usedQuantity",
    editable: true,
    width: 120,
    minwidth: 120,
    editType: "number",
  },
];
const detailsTableData = ref([
]);
const etableRef = ref(null);
const selectedIds = ref([]); // 默认选中的ID数组
// 调试函数:验证ID匹配逻辑
const debugIdMatching = () => {
  if (formalDatabaseData.value.length > 0 && selectedIds.value.length > 0) {
    const matchedRows = formalDatabaseData.value.filter((row) =>
      selectedIds.value.includes(row.id)
    );
  }
};
const detailsTableData = ref([]);
const handleRowClick = (row) => {
  currentRow.value = row;
};
@@ -164,70 +228,166 @@
  reviewer: "",
  date: "",
});
const handlData =async () => {
const handlData = async () => {
  innerVisible.value = true;
  let res = await getOfficialAll();
  console.log("获取配置数据", res);
  if (res.code === 200) {
    formalDatabaseData.value = res.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("获取配置数据失败");
  }
};
// 手动设置表格选中状态
const setTableSelection = (ids) => {
  if (!etableRef.value || !Array.isArray(ids) || ids.length === 0) {
    return;
  }
  nextTick(() => {
    setTimeout(() => {
      try {
        // 先清除所有选中
        etableRef.value.clearSelection();
        // 找到需要选中的行并设置选中状态
        // 注意:ids中是officialId,需要匹配formalDatabaseData中的id字段
        const rowsToSelect = formalDatabaseData.value.filter((row) =>
          ids.includes(row.id)
        );
        if (rowsToSelect.length > 0) {
          etableRef.value.setRowsSelection(rowsToSelect, true);
          console.log("选中状态设置完成");
        } else {
        }
      } catch (error) {
        console.error("设置选中状态失败:", error);
      }
    }, 150);
  });
};
const formalDatabaseData = ref([]);
const formalDatabaseSelectedData = ref([]);
formalDatabaseData.value = [
];
formalDatabaseData.value = [];
// 初始化
const Initialization = () => {
  tableData.value = [];
  detailsTableData.value = [];
  copyForm.value = null;
  dialogType.value = "add";
};
const copyForm = ref(null);
const editInitialization = (data) => {
  copyForm.value = { ...data }; // 深拷贝数据
  tableData.value = data.productionInventoryList || [];
  detailsTableData.value = data.productionList || [];
  dialogType.value = "edit";
  // 设置默认选中的ID,使用officialId来匹配
  const existingOfficialIds = tableData.value
    .map((item) => item.officialId)
    .filter((id) => id);
  selectedIds.value = existingOfficialIds;
};
// 监听对话框状态,在打开时设置选中状态
watch(innerVisible, (newVal) => {
  if (newVal && selectedIds.value.length > 0) {
    console.log("对话框打开,设置选中状态");
    setTimeout(() => setTableSelection(selectedIds.value), 200);
  }
  // 对话框关闭时清空选择状态
  if (!newVal) {
    formalDatabaseSelectedData.value = [];
  }
});
defineExpose({
  Initialization
  Initialization,
  editInitialization,
});
const handleSelectData = (row) => {
  tableData.value = [];
  if (!innerVisible.value) return;
  // 获取选中的数据
  const selectedData = formalDatabaseSelectedData.value;
  if (selectedData.length === 0) {
    ElMessage.warning("请至少选择一条数据");
    return;
  }
  // 将选中的数据根据需要筛选到表格中
  let addedCount = 0;
  let duplicateCount = 0;
  selectedData.forEach((item) => {
    const existingItem = tableData.value.find(
      (row) => row.id === item.id
    );
    if (!existingItem) {
      tableData.value.push(
        Object.assign({}, item, {
          used: 0, // 初始使用数量为0
        })
      );
    }
    const newItem = {
      ...item, // 复制所有原始数据
      officialId: item.id, // 保存原始的id作为officialId
      usedQuantity: 0, // 初始使用数量为0
      // 可以根据需要添加其他字段
    };
    tableData.value.push(newItem);
    addedCount++;
  });
  // 更新selectedIds,确保包含所有当前tableData中的officialId
  const allOfficialIds = tableData.value
    .map((item) => item.officialId)
    .filter((id) => id);
  selectedIds.value = allOfficialIds;
  console.log("更新后的表格数据:", tableData.value);
  console.log("更新后的选中ID:", selectedIds.value);
  // 关闭选择对话框
  innerVisible.value = false;
  // 显示结果消息
  let message = "";
  if (addedCount > 0) {
    message += `成功添加 ${addedCount} 条数据`;
  }
  if (duplicateCount > 0) {
    message += (message ? "," : "") + `跳过 ${duplicateCount} 条重复数据`;
  }
  if (message) {
    ElMessage.success(message);
  } else {
    ElMessage.info("没有新数据被添加");
  }
};
const handleSelectionChange = (selection) => {
  formalDatabaseSelectedData.value = selection;
};
const reset = () => {
  // formRef
  formRef.value?.resetFields();
const handleReset = () => {
  console.log(copyForm.value);
  tableData.value =
    JSON.parse(JSON.stringify(copyForm.value.productionInventoryList)) || [];
  detailsTableData.value =
    JSON.parse(JSON.stringify(copyForm.value.productionList)) || [];
};
const selectChange = (value) => {};
// 提交表单
const handleSubmit = async () => {
  console.log("提交表单数据:", tableData.value);
  console.log(detailsTableData.value);
  let data = {
    productionList: detailsTableData.value,
    productionInventoryList: tableData.value,
    ...copyForm.value,
  };
  console.log("提交数据", data);
  // dialogVisible.value = false;
  let res = await addOrEditPM(data);
  if (res.code === 200) {
    dialogVisible.value = false;
    emit("success");
  } else {
    ElMessage.error("提交失败");
  }
};
// 关闭弹窗
@@ -251,46 +411,46 @@
// 添加单元格编辑处理函数
const handleCellEdit = (row, prop, value) => {
  if (prop === "used" && Number(value) > Number(row.stock)) {
    ElMessage.warning("使用数量不能大于库存数量!");
    row.used = row.stock;
  if (prop === "usedQuantity") {
    const numValue = Number(value);
    const inventory = Number(row.inventoryQuantity);
    // 验证输入值
    if (isNaN(numValue) || numValue < 0) {
      ElMessage.warning("使用数量必须是非负数!");
      row.usedQuantity = 0;
      return;
    }
    if (numValue > inventory) {
      ElMessage.warning(`使用数量不能大于库存数量(${inventory})!`);
      row.usedQuantity = inventory;
      return;
    }
    // 更新值
    row.usedQuantity = numValue;
    console.log(`更新 ${row.coal} 的使用数量为: ${numValue}`);
  }
};
// 处理生产明细表格的操作
const addNewRow = () => {
  detailsTableData.value.push({
    coalType: "",
    coal: "",
    productionQuantity: "",
    laborCost: "",
    energyConsumptionCost: "",
    equipmentDepreciation: "",
    purchasePrice: "",
    autoCalculate: "0.00",
    producer:"",
    producer: "",
  });
};
const clearAllRows = () => {
  detailsTableData.value = [];
  ElMessage.success("已清空所有数据");
};
const calculateAllCosts = () => {
  detailsTableData.value.forEach((row) => {
    const laborCost = parseFloat(row.laborCost) || 0;
    const energyCost = parseFloat(row.energyCost) || 0;
    const equipmentDepreciation = parseFloat(row.equipmentDepreciation) || 0;
    const purchasePrice = parseFloat(row.purchasePrice) || 0;
    row.totalCost = (
      laborCost +
      energyCost +
      equipmentDepreciation +
      purchasePrice
    ).toFixed(2);
  });
  ElMessage.success("重新计算完成");
};
const handleDetailsChange = (data) => {
@@ -300,6 +460,59 @@
const handleDeleteRow = (index) => {
  ElMessage.success(`已删除第 ${index + 1} 行数据`);
};
// 删除单个已选数据项
const handleRemoveItem = (row) => {
  console.log("删除项:", row);
  const index = tableData.value.findIndex(
    (item) => item.officialId === row.officialId
  );
  if (index > -1) {
    tableData.value.splice(index, 1);
    // 更新selectedIds
    const updatedOfficialIds = tableData.value
      .map((item) => item.officialId)
      .filter((id) => id);
    selectedIds.value = updatedOfficialIds;
    console.log("删除后的表格数据:", tableData.value);
    console.log("更新后的选中ID:", selectedIds.value);
    ElMessage.success("已删除选中项");
  }
};
// 清空所有已选数据
const removeSelectedData = () => {
  if (tableData.value.length === 0) {
    ElMessage.warning("没有可清空的数据");
    return;
  }
  ElMessageBox.confirm("确认清空所有已选择的数据吗?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      tableData.value = [];
      selectedIds.value = [];
      console.log("已清空所有已选数据");
      ElMessage.success("已清空所有数据");
    })
    .catch(() => {
      console.log("取消清空操作");
    });
};
// 计算总使用量
const totalUsedQuantity = computed(() => {
  return tableData.value.reduce((total, item) => {
    const usedQty = Number(item.usedQuantity) || 0;
    return total + usedQty;
  }, 0);
});
</script>
<style scoped lang="scss">
@@ -313,7 +526,7 @@
.el-row > .el-col > h1 {
  font-weight: bolder;
}
.empty-table > .el-row{
.empty-table > .el-row {
  margin-bottom: 12px;
}
</style>
src/views/production/index.vue
@@ -1,226 +1,201 @@
<template>
  <div class="production-container">
        <el-form :inline="true" :model="queryParams" class="search-form" style="width: 100%">
          <el-form-item label="搜索">
            <el-input v-model="queryParams.searchAll" placeholder="请输入关键词" clearable />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="handleSearch">查询</el-button>
            <el-button @click="handleReset">重置</el-button>
          </el-form-item>
        </el-form>
    <!-- 搜索表单 -->
    <el-form :inline="true" :model="queryParams" class="search-form">
      <el-form-item label="搜索">
        <el-input
          v-model="queryParams.searchAll"
          placeholder="请输入关键词"
          clearable
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleSearch">查询</el-button>
        <el-button @click="handleReset">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- 主要内容区域 -->
    <el-card>
      <el-button type="success" :icon="Plus" @click="handleAddBatch">新增加工</el-button>
      <el-button type="danger" :icon="Delete">删除</el-button>
      <el-button type="info" :icon="Download">导出</el-button>
      <ETable :loading="loading" :table-data="tableData" :columns="columns" @selection-change="handleSelectionChange"
        @edit="handleEdit" @view-detail="handleViewDetail" :show-selection="true" :border="true" :maxHeight="480" />
      <!-- 操作按钮 -->
      <div class="toolbar">
        <el-button type="success" :icon="Plus" @click="openDialog('add')">
          新增加工
        </el-button>
        <el-button type="danger" :icon="Delete" :disabled="!selectedRows.length">
          删除
        </el-button>
      </div>
      <!-- 数据表格 -->
      <ETable
        :loading="loading"
        :table-data="tableData"
        :columns="columns"
        @selection-change="handleSelectionChange"
        @edit="row => openDialog('edit', row)"
        :show-selection="true"
        :border="true"
        :maxHeight="480"
      >
        <template #coal="{ row }">
          <div class="coal-tags">
            <el-tag v-for="coal in parseCoalArray(row.coal)" :key="coal" size="small">
              {{ coal }}
            </el-tag>
            <span v-if="!row.coal">--</span>
          </div>
        </template>
      </ETable>
      <!-- 分页组件 -->
      <Pagination
        :total="total"
        :page="queryParams.current"
        :limit="queryParams.size"
        :show-total="true"
        @pagination="handlePageChange"
        :layout="'total, prev, pager, next, jumper'"
      ></Pagination>
      />
    </el-card>
    <ProductionDialog v-model:visible="dialogVisible"  ref="childRef" :type="dialogType"
      @success="handleDialogSuccess" />
    <!-- 生产对话框 -->
    <ProductionDialog
      v-model:visible="dialogVisible"
      ref="dialogRef"
      :type="dialogType"
      @success="handleDialogSuccess"
    />
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Delete, Download, List } from "@element-plus/icons-vue";
import { Plus, Delete } from "@element-plus/icons-vue";
import ProductionDialog from "./components/ProductionDialog.vue";
import ETable from "@/components/Table/ETable.vue";
import Pagination from "@/components/Pagination/index.vue";
import { getProductionMasterList } from "@/api/production";
const childRef = ref(null);
// 表格列配置
const columns = [
  { prop: "category", label: "煤种", minWidth: 150 },
  { prop: "unit", label: "单位", minWidth: 120 },
  { prop: "productionVolume", label: "生产数量", minWidth: 150 },
  { prop: "coal", label: "煤种", minWidth: 150, slot: 'coal' },
  { prop: "productionQuantity", label: "生产数量", minWidth: 120 },
  { prop: "laborCost", label: "人工成本", minWidth: 150 },
  { prop: "materialCost", label: "原料成本", minWidth: 120 },
  { prop: "equipmentCost", label: "设备费用", minWidth: 143 },
  { prop: "energyConsumptionCost", label: "能耗成本", minWidth: 120 },
  { prop: "equipmentDepreciation", label: "设备折旧", minWidth: 143 },
  { prop: "totalCost", label: "总成本", minWidth: 150 },
  { prop: "totalPrice", label: "总售价", minWidth: 150 },
  { prop: "profit", label: "利润", minWidth: 100 },
  { prop: "reviewer", label: "复记人", minWidth: 120 },
  { prop: "date", label: "日期", minWidth: 150 },
  { prop: "producer", label: "生产人", minWidth: 150 },
];
// 搜索表单数据
// 表格数据
// 响应式数据
const tableData = ref([]);
const loading = ref(false);
const total = ref(0);
const queryParams = reactive({
  searchAll:"",
  current: 1,
  size: 10, // 固定每页10条
});
const handlePageChange = ({ page }) => {
  console.log("分页变化:", { page });
  queryParams.current = page;
  getList();
};
// 选中的行数据
const selectedRows = ref([]);
// 弹窗相关
const dialogVisible = ref(false);
const dialogType = ref("add");
const currentRow = ref(null);
const dialogRef = ref(null);
// 生产明细对话框控制
const detailDialogVisible = ref(false);
const currentDetailRow = ref(null);
// 查询参数
const queryParams = reactive({
  searchAll: "",
  current: 1,
  size: 10,
});
// 获取表格数据
// 获取表格数据
const getList = async () => {
  loading.value = true;
  try {
    const res = await getProductionMasterList({...queryParams});
    // 构建正确的分页参数
    const params = {
      searchAll: queryParams.searchAll,
      // 尝试多种常见的分页参数格式
      current: queryParams.current,
      size: queryParams.size,
      page: queryParams.current,
      pageSize: queryParams.size,
      pageNum: queryParams.current,
      limit: queryParams.size,
      offset: (queryParams.current - 1) * queryParams.size
    };
    console.log('发送分页参数:', params);
    console.log(`第${queryParams.current}页应该显示第${(queryParams.current - 1) * queryParams.size + 1}-${queryParams.current * queryParams.size}条数据`);
    const res = await getProductionMasterList(params);
    tableData.value = res.data.records || [];
    total.value = res.data.total || 0;
    console.log('接收到的数据:', {
      当前页: queryParams.current,
      返回条数: tableData.value.length,
      总条数: total.value
    });
  } catch (error) {
    ElMessage.error("获取数据失败");
    console.error('API错误:', error);
  } finally {
    loading.value = false;
  }
};
// 处理表格选择变化
// 搜索和重置
const handleSearch = () => {
  queryParams.current = 1;
  getList();
};
const handleReset = () => {
  queryParams.searchAll = "";
  handleSearch();
};
// 分页处理
const handlePageChange = ({ page }) => {
  queryParams.current = page;
  getList();
};
// 表格选择处理
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
// 搜索方法
const handleSearch = () => {
  pagination.currentPage = 1;
  getList();
};
// 重置搜索
const handleReset = () => {
  handleSearch();
};
// 新增加工
const handleAddBatch = () => {
  dialogType.value = "add";
// 打开对话框 - 统一处理新增和编辑
const openDialog = (type, row = null) => {
  dialogType.value = type;
  dialogVisible.value = true;
  childRef.value.Initialization();
};
// 编辑
const handleEdit = (row) => {
  currentRow.value = row;
  dialogType.value = "edit";
  dialogVisible.value = true;
};
// 打开生产明细对话框
const handleViewDetail = (row) => {
  currentDetailRow.value = row;
  detailDialogVisible.value = true;
};
// 处理弹窗提交
const handleDialogSuccess = async (formData) => {
  try {
    if (dialogType.value === "add") {
      await addProduction(formData);
      ElMessage.success("新增成功");
    } else {
      await updateProduction({
        ...formData,
        id: currentRow.value.id,
      });
      ElMessage.success("更新成功");
    }
    getList();
  } catch (error) {
    ElMessage.error(dialogType.value === "add" ? "新增失败" : "更新失败");
  if (type === 'add') {
    dialogRef.value?.Initialization();
  } else if (type === 'edit' && row) {
    dialogRef.value?.editInitialization({ ...row });
  }
};
// 处理生产明细弹窗提交
const handleDetailDialogSuccess = async (formData) => {
  try {
    ElMessage.success("保存成功");
    getList();
  } catch (error) {
    ElMessage.error("保存失败");
  }
};
// 删除
const handleDelete = (row) => {
  ElMessageBox.confirm("确认删除该记录吗?", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(async () => {
      try {
        await deleteProduction(row.id);
        ElMessage.success("删除成功");
        getList();
      } catch (error) {
        console.error("删除失败:", error);
        ElMessage.error("删除失败");
      }
    })
    .catch(() => {
      ElMessage.info("已取消删除");
    });
};
// 导出
const handleExport = async (row) => {
  try {
    const res = await exportProduction({ id: row.id });
    const blob = new Blob([res], { type: "application/vnd.ms-excel" });
    const fileName = `生产加工记录_${new Date().getTime()}.xlsx`;
    if ("download" in document.createElement("a")) {
      const elink = document.createElement("a");
      elink.download = fileName;
      elink.style.display = "none";
      elink.href = URL.createObjectURL(blob);
      document.body.appendChild(elink);
      elink.click();
      URL.revokeObjectURL(elink.href);
      document.body.removeChild(elink);
    } else {
      navigator.msSaveBlob(blob, fileName);
    }
  } catch (error) {
    ElMessage.error("导出失败");
  }
};
// 处理每页显示数量变化
const handleSizeChange = (val) => {
  pagination.size = val;
// 对话框成功回调
const handleDialogSuccess = () => {
  getList();
  ElMessage.success("操作成功");
};
// 处理页码变化
const handleCurrentChange = (val) => {
  pagination.currentPage = val;
  getList();
// 解析煤种数组 - 简化逻辑
const parseCoalArray = (coalString) => {
  if (!coalString) return [];
  if (Array.isArray(coalString)) return coalString;
  return String(coalString)
    .replace(/^\[|\]$/g, '')
    .split(',')
    .map(item => item.trim())
    .filter(Boolean);
};
// 组件挂载时加载数据
onMounted(() => {
  getList();
});
onMounted(getList);
</script>
<style scoped lang="scss">
@@ -241,7 +216,7 @@
    width: 20%;
  }
}
.search-form{
.search-form {
  display: flex;
  justify-content: space-between;
  align-items: center;
@@ -255,4 +230,18 @@
    margin-left: 10px;
  }
}
.coal-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  .el-tag {
    margin-right: 4px;
    margin-bottom: 4px;
    &:last-child {
      margin-right: 0;
    }
  }
}
</style>