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

631 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>