1066 lines
39 KiB
Vue
1066 lines
39 KiB
Vue
<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 shouldn’tbe 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>
|