feat(mes/qc): add quality certificate management function

- 新增质量证明书主、明细的CRUD接口
- 新增质量证明书列表页、明细编辑页
- 新增打印预览组件和PDF导出打印功能
- 添加配套的静态资源和路由依赖
- 优化路由菜单处理逻辑
This commit is contained in:
2026-05-16 17:23:20 +08:00
parent 5c2910987e
commit 56b306d301
11 changed files with 2136 additions and 2 deletions

View File

@@ -0,0 +1,888 @@
<template>
<div class="app-container">
<div class="tab-container">
<div class="select-button" @click="openCertificateDialog">
<i class="el-icon-setting"></i>
</div>
<div class="custom-tabs">
<div class="tab-nav">
<button v-if="certificateList.length > 0 && queryParams.pageNum > 1" class="nav-btn prev" @click="prevPage">
<i class="el-icon-arrow-left"></i>
</button>
<div class="tab-header">
<div v-for="cert in certificateList" :key="cert.certificateId" class="tab-item"
:class="{ active: activeTab === cert.certificateId.toString() }" @click="handleTabClick(cert)">
<div class="tab-title">{{ cert.certificateNo }}</div>
<div class="tab-info">
<span>{{ cert.productName }}</span>
<span class="date">{{ parseTime(cert.issueDate, '{y}-{m}-{d}') }}</span>
</div>
</div>
<div v-if="certificateList.length === 0" class="tab-item disabled">
<div class="tab-title">暂无质保书</div>
<div class="tab-info">请点击齿轮图标选择质保书</div>
</div>
</div>
<button v-if="certificateList.length > 0 && queryParams.pageNum < totalPage" class="nav-btn next" @click="nextPage">
<i class="el-icon-arrow-right"></i>
</button>
</div>
</div>
</div>
<div v-if="currentCertificateId" class="certificate-detail-container">
<div class="card-header">
<h3>{{ currentCertificateInfo.certificateNo || '质保书明细' }}</h3>
<div>
<el-button type="primary" plain @click="handleAdd">新增明细</el-button>
<el-button type="success" plain @click="openBatchAddDialog">批量新增</el-button>
<el-button type="danger" plain @click="handleBatchDelete"
:disabled="selectedRows.length === 0">批量删除</el-button>
<el-button type="warning" plain icon="el-icon-printer" @click="handlePrint">打印</el-button>
<el-button type="info" plain @click="getList">刷新</el-button>
</div>
</div>
<el-form class="certificate-info" :model="currentCertificateInfo" label-width="80px">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="证明书号">
<el-input v-model="currentCertificateInfo.certificateNo" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="合同号">
<el-input v-model="currentCertificateInfo.contractNo" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="产品名称">
<el-input v-model="currentCertificateInfo.productName" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="签发日期">
<el-date-picker v-model="currentCertificateInfo.issueDate" type="date" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="执行标准">
<el-input v-model="currentCertificateInfo.standard" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="收货单位">
<el-input v-model="currentCertificateInfo.consignee" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="生产厂家">
<el-input v-model="currentCertificateInfo.manufacturer" @change="handleCertificateInfoChange" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-table v-loading="loading" :data="certificateItemList" style="width: 100%" border
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" />
<el-table-column label="操作" align="center" width="140" fixed="left">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleSave(scope.row)">保存</el-button>
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
<el-table-column label="钢卷号" align="center" prop="coilNo" width="180">
<template slot-scope="scope">
<el-input v-model="scope.row.coilNo" style="background-color: #fff3e6;" placeholder="点击选择钢卷">
<template slot="append">
<el-button size="mini" icon="el-icon-search" @click="openCoilSelectDialog(scope.row)"></el-button>
</template>
</el-input>
</template>
</el-table-column>
<el-table-column label="炉号" align="center" prop="heatNo" width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.heatNo" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="材质" align="center" prop="materialType" width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.materialType" style="background-color: #fff3e6;" />
</template>
</el-table-column>
<el-table-column label="规格(mm)" align="center" prop="size" width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.size" style="background-color: #fff3e6;" />
</template>
</el-table-column>
<el-table-column label="件数" align="center" prop="pieces" width="80">
<template slot-scope="scope">
<el-input v-model.number="scope.row.pieces" style="background-color: #fff3e6;" />
</template>
</el-table-column>
<el-table-column label="重量(t)" align="center" prop="weight" width="100">
<template slot-scope="scope">
<el-input v-model.number="scope.row.weight" style="background-color: #fff3e6;" />
</template>
</el-table-column>
<el-table-column label="C(%)" align="center" prop="c" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.c" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Si(%)" align="center" prop="si" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.si" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Mn(%)" align="center" prop="mn" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.mn" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="P(%)" align="center" prop="p" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.p" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="S(%)" align="center" prop="s" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.s" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Als(%)" align="center" prop="als" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.als" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="屈服强度(MPa)" align="center" prop="yieldStrength" width="130">
<template slot-scope="scope">
<el-input v-model.number="scope.row.yieldStrength" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="抗拉强度(MPa)" align="center" prop="tensileStrength" width="130">
<template slot-scope="scope">
<el-input v-model.number="scope.row.tensileStrength" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="伸长率(%)" align="center" prop="elongation" width="110">
<template slot-scope="scope">
<el-input v-model="scope.row.elongation" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="硬度(HRB)" align="center" prop="hardness" width="100">
<template slot-scope="scope">
<el-input v-model.number="scope.row.hardness" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="弯曲试验" align="center" prop="bendingTest" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.bendingTest" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="表面质量" align="center" prop="surfaceQuality" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.surfaceQuality" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="表面结构" align="center" prop="surfaceStructure" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.surfaceStructure" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="边缘状态" align="center" prop="edgeStatus" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.edgeStatus" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<!-- <el-table-column label="备注" align="center" prop="remark">
<template slot-scope="scope">
<el-input v-model="scope.row.remark" style="background-color: #fff0f6;" />
</template>
</el-table-column> -->
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
</div>
<el-empty v-else class="appempty" description="选择质保书查看明细" />
<el-dialog :title="'选择钢卷'" :visible.sync="coilDialogVisible" width="900px" append-to-body>
<div class="dialog-toolbar">
<el-form :model="coilQueryParams" ref="coilQueryForm" size="small" :inline="true" label-width="68px">
<el-form-item label="钢卷号" prop="coilNo">
<el-input v-model="coilQueryParams.coilNo" placeholder="请输入钢卷号" clearable
@keyup.enter.native="handleCoilQuery" />
</el-form-item>
<el-form-item label="材质" prop="material">
<el-input v-model="coilQueryParams.material" placeholder="请输入材质" clearable
@keyup.enter.native="handleCoilQuery" />
</el-form-item>
<el-form-item label="规格" prop="specification">
<el-input v-model="coilQueryParams.specification" placeholder="请输入规格" clearable
@keyup.enter.native="handleCoilQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleCoilQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetCoilQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-table v-loading="coilLoading" :data="coilList" height="350px" @row-click="handleCoilSelect">
<el-table-column label="钢卷号" align="center" prop="currentCoilNo" />
<el-table-column label="材质" align="center" prop="material" />
<el-table-column label="规格" align="center" prop="specification" />
<el-table-column label="重量(t)" align="center" prop="netWeight" />
</el-table>
<pagination v-show="coilTotal > 0" :total="coilTotal" :page.sync="coilQueryParams.pageNum"
:limit.sync="coilQueryParams.pageSize" @pagination="getCoilList" />
</el-dialog>
<el-dialog :title="'选择质保书'" :visible.sync="certificateDialogVisible" width="900px" append-to-body>
<div class="dialog-toolbar">
<el-form :model="certificateQueryParams" ref="certificateQueryForm" size="small" :inline="true" label-width="68px">
<el-form-item label="证明书号" prop="certificateNo">
<el-input v-model="certificateQueryParams.certificateNo" placeholder="请输入证明书号" clearable
@keyup.enter.native="handleCertificateQuery" />
</el-form-item>
<el-form-item label="合同号" prop="contractNo">
<el-input v-model="certificateQueryParams.contractNo" placeholder="请输入合同号" clearable
@keyup.enter.native="handleCertificateQuery" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="certificateQueryParams.productName" placeholder="请输入产品名称" clearable
@keyup.enter.native="handleCertificateQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleCertificateQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetCertificateQuery">重置</el-button>
<el-button type="success" icon="el-icon-plus" size="mini" @click="handleAddCertificate">新增质保书</el-button>
</el-form-item>
</el-form>
</div>
<el-table v-loading="certificateLoading" :data="allCertificateList" height="350px" @row-click="handleTabClick">
<el-table-column label="证明书号" align="center" prop="certificateNo" />
<el-table-column label="合同号" align="center" prop="contractNo" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="执行标准" align="center" prop="standard" />
<el-table-column label="收货单位" align="center" prop="consignee" />
<el-table-column label="签发日期" align="center" prop="issueDate" width="140">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.issueDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
<pagination v-show="certificateTotal > 0" :total="certificateTotal" :page.sync="certificateQueryParams.pageNum"
:limit.sync="certificateQueryParams.pageSize" @pagination="getCertificateList" />
</el-dialog>
<el-dialog :title="'新增质保书'" :visible.sync="addCertificateDialogVisible" width="800px" append-to-body>
<el-form :model="certificateForm" ref="certificateForm" label-width="100px">
<el-form-item label="证明书号" prop="certificateNo">
<el-input v-model="certificateForm.certificateNo" placeholder="请输入证明书号" />
</el-form-item>
<el-form-item label="合同号" prop="contractNo">
<el-input v-model="certificateForm.contractNo" placeholder="请输入合同号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="certificateForm.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="执行标准" prop="standard">
<el-input v-model="certificateForm.standard" placeholder="请输入执行标准" />
</el-form-item>
<el-form-item label="收货单位" prop="consignee">
<el-input v-model="certificateForm.consignee" placeholder="请输入收货单位" />
</el-form-item>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input v-model="certificateForm.manufacturer" placeholder="请输入生产厂家" />
</el-form-item>
<el-form-item label="签发日期" prop="issueDate">
<el-date-picker v-model="certificateForm.issueDate" value-format="yyyy-MM-dd HH:mm:ss" type="date" placeholder="请选择签发日期" />
</el-form-item>
<el-form-item label="质保证明说明" prop="note">
<el-input v-model="certificateForm.note" type="textarea" placeholder="请输入内容" auto-height />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="certificateForm.remark" type="textarea" placeholder="请输入内容" auto-height />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addCertificateDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitCertificateForm">确定</el-button>
</div>
</el-dialog>
<CoilSelector
:visible.sync="batchAddDialogVisible"
:use-trigger="false"
:multiple="true"
@confirm="handleBatchAddConfirm"
/>
<!-- 隐藏的打印组件 -->
<CertificatePrintPreview
ref="certificatePrint"
v-show="false"
:certificate="printCertificateData"
:items="printItemsData"
/>
</div>
</template>
<script>
import { listCertificateItem, getCertificateItem, delCertificateItem, addCertificateItem, updateCertificateItem } from "@/api/mes/qc/certificateItem";
import { listCertificate, getCertificate, updateCertificate, addCertificate } from "@/api/mes/qc/certificate";
import { listMaterialCoil } from "@/api/wms/coil";
import CoilSelector from "@/components/CoilSelector/index.vue";
import CertificatePrintPreview from "./components/CertificatePrintPreview.vue";
import { print as printPdf } from "./lib/printUtils";
export default {
components: {
CoilSelector,
CertificatePrintPreview
},
name: "CertificateItem",
computed: {
totalPage() {
return Math.ceil(this.certificateTotal / this.certificateQueryParams.pageSize)
}
},
data() {
return {
buttonLoading: false,
loading: false,
certificateLoading: false,
total: 0,
certificateTotal: 0,
certificateList: [],
allCertificateList: [],
certificateItemList: [],
currentCertificateId: undefined,
currentCertificateInfo: {},
activeTab: '',
certificateDialogVisible: false,
coilDialogVisible: false,
batchAddDialogVisible: false,
addCertificateDialogVisible: false,
printComponentVisible: false,
printCertificateData: {},
printItemsData: [],
certificateForm: {
certificateNo: '',
contractNo: '',
productName: '',
standard: '',
consignee: '',
manufacturer: '',
issueDate: '',
remark: ''
},
coilLoading: false,
coilTotal: 0,
coilList: [],
currentEditRow: null,
selectedRows: [],
queryParams: {
pageNum: 1,
pageSize: 50,
certificateId: undefined
},
certificateQueryParams: {
pageNum: 1,
pageSize: 10,
certificateNo: undefined,
contractNo: undefined,
productName: undefined
},
coilQueryParams: {
pageNum: 1,
pageSize: 10,
coilNo: undefined,
material: undefined,
specification: undefined
}
};
},
created() {
this.getCertificateList();
},
methods: {
parseTime(time, pattern) {
if (!time) return '';
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}';
const date = new Date(time);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
return format.replace('{y}', year)
.replace('{m}', month.toString().padStart(2, '0'))
.replace('{d}', day.toString().padStart(2, '0'))
.replace('{h}', hour.toString().padStart(2, '0'))
.replace('{i}', minute.toString().padStart(2, '0'))
.replace('{s}', second.toString().padStart(2, '0'));
},
getCertificateList() {
this.certificateLoading = true;
listCertificate(this.certificateQueryParams).then(response => {
this.allCertificateList = response.rows;
this.certificateTotal = response.total;
this.certificateList = response.rows;
this.certificateLoading = false;
});
},
handleCertificateQuery() {
this.certificateQueryParams.pageNum = 1;
this.getCertificateList();
},
resetCertificateQuery() {
this.certificateQueryParams = {
pageNum: 1,
pageSize: 10,
certificateNo: undefined,
contractNo: undefined,
productName: undefined
};
this.getCertificateList();
},
handleTabClick(certificate) {
this.activeTab = certificate.certificateId.toString();
this.certificateDialogVisible = false;
this.handleRowClick(certificate);
},
handleRowClick(row) {
this.currentCertificateId = row.certificateId;
this.currentCertificateInfo = row;
this.queryParams.certificateId = row.certificateId;
this.getList();
},
getCertificateDetail(certificateId) {
getCertificate(certificateId).then(response => {
this.currentCertificateInfo = response.data;
});
},
prevPage() {
if (this.certificateQueryParams.pageNum > 1) {
this.certificateQueryParams.pageNum--;
this.getCertificateList();
}
},
nextPage() {
if (this.certificateQueryParams.pageNum < this.totalPage) {
this.certificateQueryParams.pageNum++;
this.getCertificateList();
}
},
openCertificateDialog() {
this.getCertificateList();
this.certificateDialogVisible = true;
},
openCoilSelectDialog(row) {
this.currentEditRow = row;
this.coilDialogVisible = true;
this.getCoilList();
},
getCoilList() {
this.coilLoading = true;
listMaterialCoil(this.coilQueryParams).then(response => {
this.coilList = response.rows;
this.coilTotal = response.total;
this.coilLoading = false;
});
},
handleCoilQuery() {
this.coilQueryParams.pageNum = 1;
this.getCoilList();
},
resetCoilQuery() {
this.coilQueryParams = {
pageNum: 1,
pageSize: 10,
coilNo: undefined,
material: undefined,
specification: undefined
};
this.getCoilList();
},
handleCoilSelect(row) {
if (this.currentEditRow) {
this.currentEditRow.coilNo = row.currentCoilNo;
this.currentEditRow.materialType = row.material;
this.currentEditRow.size = row.specification;
this.currentEditRow.weight = row.netWeight;
this.currentEditRow.pieces = 1;
}
this.coilDialogVisible = false;
this.currentEditRow = null;
},
getList() {
this.loading = true;
listCertificateItem({
...this.queryParams,
certificateId: this.currentCertificateId,
}).then(response => {
this.certificateItemList = response.rows.sort((a, b) => {
return parseInt(a.itemSeqNo) - parseInt(b.itemSeqNo);
});
this.total = response.total;
this.loading = false;
});
},
handleAdd() {
const newRow = {
certificateId: this.currentCertificateId,
itemSeqNo: this.certificateItemList.length + 1
};
addCertificateItem(newRow).then(response => {
this.$message({
message: "新增成功",
type: "success"
});
this.getList();
});
},
openBatchAddDialog() {
this.batchAddDialogVisible = true;
},
handleBatchAddConfirm(coils) {
if (!coils || coils.length === 0) {
this.$message.warning('请选择钢卷');
return;
}
const totalCount = coils.length;
let successCount = 0;
let failCount = 0;
coils.forEach((coil, index) => {
const newRow = {
certificateId: this.currentCertificateId,
itemSeqNo: this.certificateItemList.length + index + 1,
coilNo: coil.currentCoilNo,
materialType: coil.material,
size: coil.specification,
weight: coil.netWeight,
pieces: 1
};
addCertificateItem(newRow).then(() => {
successCount++;
if (successCount + failCount === totalCount) {
this.batchAddDialogVisible = false;
if (successCount === totalCount) {
this.$message.success(`批量新增成功,共新增 ${successCount} 条明细`);
} else {
this.$message.warning(`批量新增完成,成功 ${successCount} 条,失败 ${failCount}`);
}
this.getList();
}
}).catch(() => {
failCount++;
if (successCount + failCount === totalCount) {
this.batchAddDialogVisible = false;
if (failCount === totalCount) {
this.$message.error('批量新增失败');
} else {
this.$message.warning(`批量新增完成,成功 ${successCount} 条,失败 ${failCount}`);
}
this.getList();
}
});
});
},
handleAddCertificate() {
this.certificateForm = {
certificateNo: '',
contractNo: '',
productName: '',
standard: '',
consignee: '',
manufacturer: '',
issueDate: '',
note: 'D.T=Denu_Test \t T.S=Tensile Strength \t D=弯心直径MandrelDiameter \n Strength \t G.L=拉伸标距GaugeLength \t EL=Percentage Elongation After Fracture',
remark: '1.本产品经检验满足订货标准要求。The material has been tested with satisfactory resultsin accordance with the speciicatication \n 2.本质量证明书中空白项目均不作为交货条件。The blank items shouldntbe regarded as delivery conditions. \n 3.盖章后生效。The quality certificate willcome into force with a valid stamp.',
};
this.addCertificateDialogVisible = true;
},
submitCertificateForm() {
addCertificate(this.certificateForm).then(response => {
this.$message({
message: "新增成功",
type: "success"
});
this.addCertificateDialogVisible = false;
this.getCertificateList();
}).catch(error => {
this.$message({
message: "新增失败",
type: "error"
});
});
},
handleCertificateInfoChange() {
if (!this.currentCertificateId) return;
updateCertificate(this.currentCertificateInfo).then(response => {
this.$message({
message: "保存成功",
type: "success"
});
}).catch(error => {
this.$message({
message: "保存失败",
type: "error"
});
this.getCertificateDetail(this.currentCertificateId);
});
},
handleSave(row) {
updateCertificateItem(row).then(response => {
this.$message({
message: "保存成功",
type: "success"
});
}).catch(error => {
this.$message({
message: "保存失败,正在重新获取数据",
type: "error"
});
this.getList();
});
},
handleDelete(row) {
this.$confirm('是否确认删除该质保书明细?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.buttonLoading = true;
delCertificateItem(row.itemId).then(response => {
this.$message({
message: "删除成功",
type: "success"
});
this.buttonLoading = false;
this.getList();
});
});
},
handleSelectionChange(selection) {
this.selectedRows = selection;
},
handleBatchDelete() {
if (this.selectedRows.length === 0) {
this.$message.warning('请至少选择一条明细');
return;
}
this.$confirm(`确认删除选中的 ${this.selectedRows.length} 条明细?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const ids = this.selectedRows.map(row => row.itemId).join(',');
this.buttonLoading = true;
delCertificateItem(ids).then(() => {
this.$message.success('批量删除成功');
this.getList();
this.buttonLoading = false;
}).catch(error => {
this.$message.error('批量删除失败');
this.buttonLoading = false;
});
});
},
async handlePrint() {
this.printCertificateData = this.currentCertificateInfo;
this.printItemsData = this.certificateItemList || [];
this.$nextTick(() => {
const el = this.$refs.certificatePrint.$refs.certificateContent;
console.log(el);
printPdf(el);
});
}
}
};
</script>
<style scoped>
.tab-container {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.select-button {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
border: 1px solid #e4e7ed;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
background-color: #f9f9f9;
color: #606266;
font-size: 14px;
user-select: none;
margin-right: 10px;
color: #409eff;
}
.select-button:hover {
background-color: #ecf5ff;
border-color: #c6e2ff;
color: #409eff;
}
.custom-tabs {
flex: 1;
border-bottom: 1px solid #e4e7ed;
}
.tab-nav {
display: flex;
align-items: flex-end;
gap: 4px;
}
.nav-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 52px;
border: 1px solid #e4e7ed;
border-bottom: none;
border-radius: 4px 4px 0 0;
background-color: #f9f9f9;
cursor: pointer;
transition: all 0.3s ease;
color: #606266;
}
.nav-btn:hover {
background-color: #ecf5ff;
border-color: #c6e2ff;
color: #409eff;
}
.tab-header {
display: flex;
flex-wrap: wrap;
gap: 4px;
flex: 1;
overflow: hidden;
}
.tab-item {
padding: 4px 4px;
border: 1px solid #e4e7ed;
border-bottom: none;
border-radius: 4px 4px 0 0;
cursor: pointer;
transition: all 0.3s ease;
background-color: #f9f9f9;
min-width: 200px;
}
.tab-item:hover {
background-color: #ecf5ff;
border-color: #c6e2ff;
}
.tab-item.active {
background-color: #ffffff;
border-color: #409eff;
border-bottom-color: #ffffff;
color: #409eff;
box-shadow: 0 -2px 0 0 #409eff inset;
}
.tab-item.disabled {
cursor: not-allowed;
background-color: #f5f7fa;
color: #c0c4cc;
border-color: #ebeef5;
}
.tab-title {
font-size: 14px;
font-weight: 500;
margin-bottom: 1px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tab-info {
font-size: 12px;
color: #909399;
display: flex;
justify-content: space-between;
align-items: center;
}
.tab-info .date {
color: #606266;
font-weight: 400;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.card-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.certificate-info {
margin-bottom: 20px;
padding: 15px;
background-color: #fafafa;
border-radius: 8px;
}
.certificate-detail-container {
margin-top: 20px;
}
.el-table {
margin-top: 10px;
}
.el-table .cell {
white-space: normal;
word-break: break-word;
}
.dialog-toolbar {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.appempty {
margin-top: 20px;
}
::v-deep .el-table .cell {
padding: 0;
}
</style>