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

1066 lines
39 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">
<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="rawCoilNo" width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.rawCoilNo" style="background-color: #fff3e6;" />
</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="Al(%)" align="center" prop="al" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.al" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Ti(%)" align="center" prop="ti" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.ti" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Cr(%)" align="center" prop="cr" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.cr" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Ni(%)" align="center" prop="ni" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.ni" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Cu(%)" align="center" prop="cu" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.cu" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="N(%)" align="center" prop="n" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.n" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="Fe(%)" align="center" prop="fe" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.fe" style="background-color: #e6f7ff;" />
</template>
</el-table-column>
<el-table-column label="B(%)" align="center" prop="b" width="90">
<template slot-scope="scope">
<el-input v-model="scope.row.b" 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="coating" width="80">
<template slot-scope="scope">
<el-input v-model="scope.row.coating" 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="规定塑性延伸强度(MPa)" align="center" prop="plasticExtensionStrength" width="170">
<template slot-scope="scope">
<el-input v-model.number="scope.row.plasticExtensionStrength" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="镀层表面结构" align="center" prop="coatingSurfaceStructure" width="130">
<template slot-scope="scope">
<el-input v-model="scope.row.coatingSurfaceStructure" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="镀层重量(g/m²)" align="center" prop="coatingMass" width="130">
<template slot-scope="scope">
<el-input v-model.number="scope.row.coatingMass" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="表面处理" align="center" prop="surfaceTreatment" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.surfaceTreatment" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<el-table-column label="调制度" align="center" prop="temperDegree" width="100">
<template slot-scope="scope">
<el-input v-model="scope.row.temperDegree" style="background-color: #f6ffed;" />
</template>
</el-table-column>
<!-- <el-table-column label="锌层重量平均值" align="center" prop="zincCoatingWeight" width="160">
<template slot-scope="scope">
<el-input v-model.number="scope.row.zincCoatingWeight" 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="enterCoilNo">
<el-input v-model="coilQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
@keyup.enter.native="handleCoilQuery" />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="coilQueryParams.currentCoilNo" 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="enterCoilNo" />
<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" :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 { 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 { listChemicalItem } from "@/api/mes/qc/chemicalItem";
import { listPhysicalItem } from "@/api/mes/qc/physicalItem";
import CoilSelector from "@/components/CoilSelector/index.vue";
import CertificatePrintPreview from "./components/CertificatePrintPreview.vue";
import { templateOptions } from "./components/templates";
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 {
templateOptions,
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: [],
templateDialogVisible: false,
selectedTemplateType: 'chromium',
templateDialogResolve: null,
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();
},
async fetchLatestChemAndPhys(coilNo) {
if (!coilNo) return {};
const [chemRes, physRes] = await Promise.all([
listChemicalItem({ coilNo, pageNum: 1, pageSize: 1 }),
listPhysicalItem({ coilNo, pageNum: 1, pageSize: 1 })
]);
const chem = chemRes.rows && chemRes.rows[0] || {};
const phys = physRes.rows && physRes.rows[0] || {};
const { c, si, mn, p, s, als, al, ti, cr, ni, cu, n, fe, b } = chem;
const { yieldStrength, tensileStrength, elongation, hardness, bendingTest, surfaceQuality, surfaceStructure, edgeStatus, plasticExtensionStrength, coatingSurfaceStructure, coatingMass, coating, surfaceTreatment, zincCoatingWeight } = phys;
return { c, si, mn, p, s, als, al, ti, cr, ni, cu, n, fe, b, yieldStrength, tensileStrength, elongation, hardness, bendingTest, surfaceQuality, surfaceStructure, edgeStatus, plasticExtensionStrength, coatingSurfaceStructure, coatingMass, coating, surfaceTreatment, zincCoatingWeight };
},
async handleCoilSelect(row) {
if (this.currentEditRow) {
const editRow = this.currentEditRow;
editRow.coilNo = row.currentCoilNo;
editRow.materialNo = row.enterCoilNo;
editRow.materialType = row.material;
editRow.size = row.specification;
editRow.weight = row.netWeight;
editRow.pieces = 1;
const data = await this.fetchLatestChemAndPhys(row.enterCoilNo);
Object.assign(editRow, data);
}
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;
},
async handleBatchAddConfirm(coils) {
if (!coils || coils.length === 0) {
this.$message.warning('请选择钢卷');
return;
}
const totalCount = coils.length;
let successCount = 0;
let failCount = 0;
this.loading = true;
for (let index = 0; index < coils.length; index++) {
const coil = coils[index];
try {
const data = await this.fetchLatestChemAndPhys(coil.enterCoilNo);
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,
...data
};
await addCertificateItem(newRow);
successCount++;
} catch {
failCount++;
}
}
this.batchAddDialogVisible = false;
if (failCount === 0) {
this.$message.success(`批量新增成功,共新增 ${successCount} 条明细`);
} else if (successCount === 0) {
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() {
const confirmed = await this.showTemplateDialog();
if (!confirmed) return;
this.printCertificateData = this.currentCertificateInfo;
this.printItemsData = this.certificateItemList || [];
this.$nextTick(() => {
const el = this.$refs.certificatePrint.$refs.certificateContent;
console.log(el);
printPdf(el);
});
},
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>
.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;
}
.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>