spring
2 天以前 252320f72318ccee0f02c66dfa1ce7fa61df0f58
src/views/productionManagement/productStructure/index.vue
@@ -1,42 +1,26 @@
<template>
  <div class="app-container">
    <div style="text-align: right; margin-bottom: 10px;">
      <el-button type="info" plain icon="Upload" @click="handleImport"
        v-hasPermi="['product:bom:import']">导入</el-button>
      <el-button type="warning" plain icon="Download" @click="handleExport" :disabled="selectedRows.length !== 1"
        v-hasPermi="['product:bom:export']">导出</el-button>
      <el-button type="primary" @click="handleAdd">新增</el-button>
      <el-button type="danger" plain @click="handleBatchDelete" :disabled="selectedRows.length === 0">删除</el-button>
    </div>
    <PIMTable
        rowKey="id"
        :column="tableColumn"
        :tableData="tableData"
        :page="page"
        :isSelection="true"
        @selection-change="handleSelectionChange"
        :tableLoading="tableLoading"
        @pagination="pagination"
    >
      <template #detail="{row}">
        <el-button
            type="primary"
            text
            @click="showDetail(row.id)">{{ row.productName }}
    <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true"
      @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination">
      <template #detail="{ row }">
        <el-button type="primary" text @click="showDetail(row)">{{ row.bomNo }}
        </el-button>
      </template>
    </PIMTable>
    <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow"/>
    <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow" />
    <!-- 新增/编辑弹窗 -->
    <el-dialog
        v-model="dialogVisible"
        :title="operationType === 'add' ? '新增BOM' : '编辑BOM'"
        width="600px"
        @close="closeDialog"
    >
      <el-form
          ref="formRef"
          :model="form"
          :rules="rules"
          label-width="120px"
      >
    <el-dialog v-model="dialogVisible" :title="operationType === 'add' ? '新增BOM' : '编辑BOM'" width="600px"
      @close="closeDialog">
      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
        <el-form-item label="产品名称" prop="productModelId">
          <el-button type="primary" @click="showProductSelectDialog = true">
            {{ form.productName || '选择产品' }}
@@ -46,13 +30,7 @@
          <el-input v-model="form.version" placeholder="请输入版本号" clearable />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input
              v-model="form.remark"
              type="textarea"
              :rows="3"
              placeholder="请输入备注"
              clearable
          />
          <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable />
        </el-form-item>
      </el-form>
      <template #footer>
@@ -60,22 +38,26 @@
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>
    <!-- 产品选择弹窗 -->
    <ProductSelectDialog
        v-model="showProductSelectDialog"
        @confirm="handleProductSelect"
        single
    />
    <ProductSelectDialog v-model="showProductSelectDialog" @confirm="handleProductSelect" single />
    <!-- BOM导入对话框 -->
    <ImportDialog ref="uploadRef" v-model="upload.open" :title="upload.title" :action="upload.url"
      :headers="upload.headers" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress"
      :on-success="handleFileSuccess" :show-download-template="true" @confirm="submitFileForm"
      @download-template="handleDownloadTemplate" @close="handleImportClose" />
  </div>
</template>
<script setup>
import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from "vue";
import { listPage, add, update, batchDelete } from "@/api/productionManagement/productBom.js";
import { getToken } from "@/utils/auth";
import { listPage, add, update, batchDelete, exportBom, downloadTemplate } from "@/api/productionManagement/productBom.js";
import { useRouter } from 'vue-router'
import { ElMessageBox } from 'element-plus'
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import ImportDialog from "@/components/Dialog/ImportDialog.vue";
const router = useRouter()
const { proxy } = getCurrentInstance()
@@ -85,13 +67,14 @@
  {
    label: "BOM编号",
    prop: "bomNo",
    dataType: 'slot',
    slot: "detail",
    minWidth: 140
  },
  {
    label: "产品名称",
    prop: "productName",
    dataType: 'slot',
    slot: "detail",
    minWidth: 160
  },
  {
@@ -144,6 +127,20 @@
const operationType = ref('add'); // add | edit
const formRef = ref(null);
const showProductSelectDialog = ref(false);
//  BOM导入参数
const upload = reactive({
  // 是否显示弹出层(BOM导入)
  open: false,
  // 弹出层标题(BOM导入)
  title: "",
  // 是否禁用上传
  isUploading: false,
  // 设置上传的请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + "/productBom/uploadBom"
});
const page = reactive({
  current: 1,
@@ -245,7 +242,7 @@
          proxy.$modal.msgError('删除失败');
        });
    })
    .catch(() => {});
    .catch(() => { });
};
// 批量删除
@@ -270,7 +267,7 @@
          proxy.$modal.msgError('删除失败');
        });
    })
    .catch(() => {});
    .catch(() => { });
};
// 产品选择
@@ -320,12 +317,112 @@
  formRef.value?.resetFields();
};
//  导入按钮操作
const handleImport = () => {
  upload.title = "BOM导入";
  upload.open = true;
};
// 关闭导入对话框时清除文件
const handleImportClose = () => {
  proxy.$refs["uploadRef"].clearFiles();
};
//  文件上传中处理
const handleFileUploadProgress = (event, file, fileList) => {
  upload.isUploading = true;
};
//  文件上传成功处理
const handleFileSuccess = (response, file, fileList) => {
  upload.open = false;
  upload.isUploading = false;
  proxy.$refs["uploadRef"].clearFiles();
  if (response.code === 200) {
    proxy.$modal.msgSuccess(response.msg || "导入成功");
    getList();
  } else {
    proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
  }
};
// 提交上传文件
const submitFileForm = () => {
  proxy.$refs["uploadRef"].submit();
};
//  导出按钮操作
const handleExport = () => {
  if (selectedRows.value.length !== 1) {
    proxy.$modal.msgWarning("请选择一条数据进行导出");
    return;
  }
  const bomId = selectedRows.value[0].id;
  const fileName = `BOM_${selectedRows.value[0].bomNo || bomId}.xlsx`;
  exportBom(bomId).then(res => {
    // 返回的数据是否为空
    if (!res) {
      proxy.$modal.msgError("导出失败,返回数据为空");
      return;
    }
    const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const downloadElement = document.createElement('a');
    const href = window.URL.createObjectURL(blob);
    downloadElement.style.display = 'none';
    downloadElement.href = href;
    downloadElement.download = fileName;
    document.body.appendChild(downloadElement);
    downloadElement.click();
    document.body.removeChild(downloadElement);
    window.URL.revokeObjectURL(href);
    proxy.$modal.msgSuccess("导出成功");
  }).catch(err => {
    console.error("导出异常:", err);
    proxy.$modal.msgError("系统异常,导出失败");
  });
};
//  下载模板
const handleDownloadTemplate = async () => {
  const res = await downloadTemplate();
  // 返回的数据是否为空
  if (!res) {
    proxy.$modal.msgError("下载失败,返回数据为空");
    return;
  }
  const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
  const downloadElement = document.createElement('a');
  const href = window.URL.createObjectURL(blob);
  downloadElement.href = href;
  downloadElement.download = "BOM模板.xlsx";
  document.body.appendChild(downloadElement);
  downloadElement.click();
  document.body.removeChild(downloadElement);
  window.URL.revokeObjectURL(href);
  proxy.$modal.msgSuccess("下载成功");
};
// 查看详情
const showDetail = (id) => {
const showDetail = (row) => {
  router.push({
    path: '/productionManagement/productStructureDetail',
    query: {
      id: id
      id: row.id,
      bomNo: row.bomNo || '',
      productName: row.productName || '',
      productModelName: row.productModelName || ''
    }
  });
};