Files
klp-oa/klp-ui/src/views/mes/qc/certificate/book.vue

631 lines
22 KiB
Vue
Raw Normal View History

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="证明书号" prop="certificateNo">
<el-input
v-model="queryParams.certificateNo"
placeholder="请输入证明书号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="合同号" prop="contractNo">
<el-input
v-model="queryParams.contractNo"
placeholder="请输入合同号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input
v-model="queryParams.productName"
placeholder="请输入产品名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="执行标准" prop="standard">
<el-input
v-model="queryParams.standard"
placeholder="请输入执行标准"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="收货单位" prop="consignee">
<el-input
v-model="queryParams.consignee"
placeholder="请输入收货单位"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input
v-model="queryParams.manufacturer"
placeholder="请输入生产厂家"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="审批状态" prop="approveStatus">
<el-select v-model="queryParams.approveStatus" placeholder="请选择审批状态" clearable>
<el-option label="待审批" value="PENDING" />
<el-option label="审批中" value="APPROVING" />
<el-option label="已通过" value="PASSED" />
<el-option label="已驳回" value="REJECTED" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="certificateList"
@selection-change="handleSelectionChange"
border
class="certificate-table"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="证明书号" align="center" prop="certificateNo">
<template #default="scope">
<span class="cert-no">{{ scope.row.certificateNo || '-' }}</span>
</template>
</el-table-column>
<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="manufacturer" />
<el-table-column label="签发日期" align="center" prop="issueDate">
<template #default="scope">
{{ parseTime(scope.row.issueDate, '{y}-{m}-{d}') }}
</template>
</el-table-column>
<el-table-column label="签发状态" align="center" prop="approveStatus" width="180">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.approveStatus)" size="small">
{{ getStatusText(scope.row.approveStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审批信息" align="center" width="220">
<template #default="scope">
<div v-if="(scope.row.approveStatus || 'PENDING') === 'PASSED' || (scope.row.approveStatus || 'PENDING') === 'REJECTED'">
<div>审批人: {{ scope.row.approveBy || '-' }}</div>
<div>审批时间: {{ parseTime(scope.row.approveTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</div>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="220">
<template #default="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" :disabled="(scope.row.approveStatus || 'PENDING') === 'APPROVING' || (scope.row.approveStatus || 'PENDING') === 'PASSED'">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button>
<el-button size="mini" type="text" icon="el-icon-printer" @click="handlePrint(scope.row)">打印</el-button>
<el-button v-if="(scope.row.approveStatus || 'PENDING') === 'PENDING' || (scope.row.approveStatus || 'PENDING') === 'REJECTED'" size="mini" type="text" icon="el-icon-upload" @click="handleSubmit(scope.row)">提交审批</el-button>
<el-button v-hasPermi="['qc:certificate:approve']" v-if="(scope.row.approveStatus || 'PENDING') === 'APPROVING'" size="mini" type="text" icon="el-icon-check" @click="handleApprove(scope.row, 'PASSED')">通过</el-button>
<el-button v-hasPermi="['qc:certificate:approve']" v-if="(scope.row.approveStatus || 'PENDING') === 'APPROVING'" size="mini" type="text" icon="el-icon-close" @click="handleApprove(scope.row, 'REJECTED')">驳回</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改质量证明书主对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="证明书号" prop="certificateNo">
<el-input v-model="form.certificateNo" placeholder="请输入证明书号" />
</el-form-item>
<el-form-item label="合同号" prop="contractNo">
<el-input v-model="form.contractNo" placeholder="请输入合同号" />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="执行标准" prop="standard">
<el-input v-model="form.standard" placeholder="请输入执行标准" />
</el-form-item>
<el-form-item label="收货单位" prop="consignee">
<el-input v-model="form.consignee" placeholder="请输入收货单位" />
</el-form-item>
<el-form-item label="生产厂家" prop="manufacturer">
<el-input v-model="form.manufacturer" placeholder="请输入生产厂家" />
</el-form-item>
<el-form-item label="签发日期" prop="issueDate">
<el-date-picker clearable
v-model="form.issueDate"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择签发日期">
</el-date-picker>
</el-form-item>
<el-form-item label="质保证明说明" prop="note">
<el-input v-model="form.note" type="textarea" placeholder="请输入内容" auto-height />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" auto-height />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 预览对话框 -->
<el-dialog :title="previewTitle" :visible.sync="previewVisible" width="1200px" append-to-body fullscreen>
<div class="preview-content-wrapper">
<CertificatePrintPreview
ref="printComponent"
:visible="true"
:preview="true"
:certificate="previewData"
:items="previewItems"
:template-type="selectedTemplateType"
/>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleExportPdfFromPreview">导出PDF</el-button>
<el-button type="success" @click="handlePrintFromPreview">打印</el-button>
<el-button @click="previewVisible = false">关闭</el-button>
</div>
</el-dialog>
<!-- 隐藏的打印组件 -->
<CertificatePrintPreview
v-show="false"
ref="hiddenPrintComponent"
:certificate="printCertificateData"
:items="printItemsData"
:template-type="selectedTemplateType"
/>
<!-- 模板选择对话框 -->
<el-dialog title="选择质保书模板" :visible.sync="templateDialogVisible" width="500px" append-to-body>
<div class="template-selection">
<el-radio-group v-model="selectedTemplateType" class="template-radio-group">
<el-radio v-for="option in templateOptions" :key="option.value" :label="option.value" class="template-radio">
<div class="template-option">
<i class="el-icon-document"></i>
<span>{{ option.label }}</span>
</div>
</el-radio>
</el-radio-group>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmTemplate"> </el-button>
<el-button @click="templateDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listCertificate, getCertificate, delCertificate, addCertificate, updateCertificate } from "@/api/mes/qc/certificate";
import { listCertificateItem } from "@/api/mes/qc/certificateItem";
import CertificatePrintPreview from "./components/CertificatePrintPreview.vue";
import { templateOptions } from "./components/templates";
import { print as printPdf, downloadPdf } from "./lib/printUtils";
export default {
name: "Certificate",
components: {
CertificatePrintPreview
},
data() {
return {
templateOptions,
buttonLoading: false,
loading: true,
ids: [],
selectedIds: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
certificateList: [],
title: "",
open: false,
previewVisible: false,
previewTitle: "",
previewData: {},
previewItems: [],
printComponentVisible: false,
printCertificateData: {},
printItemsData: [],
templateDialogVisible: false,
selectedTemplateType: 'chromium',
templateActionType: 'print',
templateDialogResolve: null,
queryParams: {
pageNum: 1,
pageSize: 10,
certificateNo: undefined,
contractNo: undefined,
productName: undefined,
standard: undefined,
consignee: undefined,
manufacturer: undefined,
},
form: {},
rules: {
},
statusMap: {
'PENDING': '待提交',
'APPROVING': '审批中',
'PASSED': '已通过',
'REJECTED': '已驳回'
},
statusTypeMap: {
'PENDING': 'info',
'APPROVING': 'warning',
'PASSED': 'success',
'REJECTED': 'danger'
}
};
},
created() {
this.getList();
},
methods: {
getStatusText(status) {
const actualStatus = status || 'PENDING';
return this.statusMap[actualStatus] || '未知';
},
getStatusType(status) {
const actualStatus = status || 'PENDING';
return this.statusTypeMap[actualStatus] || 'info';
},
getActualStatus(status) {
return status || 'PENDING';
},
/** 查询质量证明书主列表 */
getList() {
this.loading = true;
listCertificate(this.queryParams).then(response => {
this.certificateList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
certificateId: undefined,
certificateNo: undefined,
contractNo: undefined,
productName: undefined,
standard: undefined,
consignee: undefined,
manufacturer: undefined,
issueDate: undefined,
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.',
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(val) {
this.selectedIds = val.map(item => item.certificateId);
this.ids = [...this.selectedIds];
this.single = this.selectedIds.length !== 1;
this.multiple = this.selectedIds.length === 0;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加质量证明书主";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const certificateId = row.certificateId || this.ids
getCertificate(certificateId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改质量证明书主";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.certificateId != null) {
updateCertificate(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
const newForm = { ...this.form, approveStatus: 'PENDING' };
addCertificate(newForm).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 提交审批 */
handleSubmit(row) {
this.$modal.confirm('确认提交审批?').then(() => {
this.loading = true;
const params = {
certificateId: row.certificateId,
approveStatus: 'APPROVING'
};
updateCertificate(params).then(response => {
this.$modal.msgSuccess("提交成功");
this.getList();
}).catch(() => {
}).finally(() => {
this.loading = false;
});
});
},
/** 审批操作 */
handleApprove(row, status) {
const statusText = status === 'PASSED' ? '通过' : '驳回';
this.$modal.confirm(`确认${statusText}该审批?`).then(() => {
this.loading = true;
const params = {
certificateId: row.certificateId,
approveStatus: status,
approveBy: this.$store.getters.name,
approveTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
};
updateCertificate(params).then(response => {
this.$modal.msgSuccess(`${statusText}成功`);
this.getList();
}).catch(() => {
}).finally(() => {
this.loading = false;
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const certificateIds = row.certificateId || this.ids;
this.$modal.confirm('是否确认删除质量证明书主编号为"' + certificateIds + '"的数据项?').then(() => {
this.loading = true;
return delCertificate(certificateIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 预览按钮操作 */
async handlePreview(row) {
this.templateActionType = 'preview';
const confirmed = await this.showTemplateDialog();
if (!confirmed) return;
const certificateId = row.certificateId;
this.loading = true;
try {
const [certRes, itemsRes] = await Promise.all([
getCertificate(certificateId),
listCertificateItem({ certificateId, pageSize: 100 })
]);
this.previewData = certRes.data;
this.previewItems = itemsRes.rows || [];
this.previewTitle = `预览 - ${certRes.data.certificateNo}`;
this.previewVisible = true;
} catch (error) {
this.$message.error('获取数据失败');
} finally {
this.loading = false;
}
},
/** 打印按钮操作 */
async handlePrint(row) {
this.templateActionType = 'print';
const confirmed = await this.showTemplateDialog();
if (!confirmed) return;
const certificateId = row.certificateId;
await this.preparePrintComponent(certificateId);
await this.$nextTick();
const el = this.$refs.hiddenPrintComponent.$refs.certificateContent;
await printPdf(el);
},
/** 从预览打印 */
async handlePrintFromPreview() {
await this.$nextTick();
const el = this.$refs.printComponent.$refs.certificateContent;
await printPdf(el);
},
/** 导出PDF按钮操作 */
async handleExportPdf() {
if (this.ids.length !== 1) {
this.$message.warning('请选择一条质保书进行导出');
return;
}
await this.preparePrintComponent(this.ids[0]);
await this.$nextTick();
const fileName = `${this.printCertificateData.certificateNo || '质量证明书'}_${new Date().getTime()}.pdf`;
const el = this.$refs.hiddenPrintComponent.$refs.certificateContent;
await downloadPdf(el, fileName);
this.$message.success('导出成功');
},
/** 从预览导出PDF */
async handleExportPdfFromPreview() {
await this.$nextTick();
const fileName = `${this.previewData.certificateNo || '质量证明书'}_${new Date().getTime()}.pdf`;
const el = this.$refs.printComponent.$refs.certificateContent;
await downloadPdf(el, fileName);
this.$message.success('导出成功');
},
async preparePrintComponent(certificateId) {
this.loading = true;
try {
const [certRes, itemsRes] = await Promise.all([
getCertificate(certificateId),
listCertificateItem({ certificateId, pageSize: 100 })
]);
this.printCertificateData = certRes.data;
this.printItemsData = itemsRes.rows || [];
this.printComponentVisible = true;
await this.$nextTick();
} catch (error) {
this.$message.error('获取数据失败');
} finally {
this.loading = false;
}
},
showTemplateDialog() {
return new Promise((resolve) => {
this.templateDialogResolve = resolve;
this.templateDialogVisible = true;
});
},
confirmTemplate() {
this.templateDialogVisible = false;
if (this.templateDialogResolve) {
this.templateDialogResolve(true);
this.templateDialogResolve = null;
}
}
}
};
</script>
<style scoped>
.preview-content-wrapper {
display: flex;
justify-content: center;
padding: 20px;
}
.certificate-table {
width: 100%;
}
.cert-no {
font-family: "Courier New", monospace;
color: #1f79b9;
font-weight: 500;
}
.template-selection {
padding: 20px;
}
.template-radio-group {
display: flex;
flex-direction: column;
gap: 15px;
}
.template-radio {
display: flex;
align-items: center;
margin: 0;
padding: 15px;
border: 1px solid #e4e7ed;
border-radius: 8px;
transition: all 0.3s ease;
}
.template-radio:hover {
border-color: #409eff;
background-color: #ecf5ff;
}
.template-radio.is-checked {
border-color: #409eff;
background-color: #ecf5ff;
}
.template-option {
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
}
.template-option i {
font-size: 20px;
color: #409eff;
}
</style>