Files
ccdi/ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue

1424 lines
56 KiB
Vue
Raw Normal View History

<template>
<div class="app-container">
2026-04-24 13:29:13 +08:00
<el-form :model="queryParams" ref="queryForm" size="small" v-show="showSearch" label-width="100px" class="query-form">
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="queryParams.projectName"
placeholder="请输入项目名称"
clearable
style="width: 100%"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="标的物名称" prop="subjectName">
<el-input
v-model="queryParams.subjectName"
placeholder="请输入标的物名称"
clearable
style="width: 100%"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请人" prop="applicantName">
<el-input
v-model="queryParams.applicantName"
placeholder="请输入申请人"
clearable
style="width: 100%"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请日期">
<el-date-picker
v-model="dateRange"
style="width: 100%"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
</el-col>
<el-col :span="1.5">
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['ccdi:purchaseTransaction:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['ccdi:purchaseTransaction:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5" v-if="showFailureButton">
2026-04-22 16:20:37 +08:00
<el-tooltip :content="getLastImportTooltip()" placement="top">
<el-button
type="warning"
plain
icon="el-icon-warning"
size="mini"
@click="viewImportFailures"
>查看导入失败记录</el-button>
</el-tooltip>
</el-col>
2026-04-22 16:20:37 +08:00
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
</el-row>
<el-table v-loading="loading" :data="transactionList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
2026-04-22 16:20:37 +08:00
<el-table-column label="采购事项ID" align="center" prop="purchaseId" width="150" :show-overflow-tooltip="true" />
<el-table-column label="采购类别" align="center" prop="purchaseCategory" width="110" />
<el-table-column label="项目名称" align="center" prop="projectName" :show-overflow-tooltip="true" />
<el-table-column label="标的物名称" align="center" prop="subjectName" :show-overflow-tooltip="true" />
<el-table-column label="采购方式" align="center" prop="purchaseMethod" width="120" />
<el-table-column label="中标供应商" align="center" prop="supplierName" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ scope.row.supplierName || "-" }}</span>
</template>
</el-table-column>
<el-table-column label="参与供应商数" align="center" prop="supplierCount" width="120">
<template slot-scope="scope">
<span>{{ scope.row.supplierCount || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="预算金额(元)" align="center" prop="budgetAmount" width="120">
<template slot-scope="scope">
{{ formatAmount(scope.row.budgetAmount) }}
</template>
</el-table-column>
2026-04-22 16:20:37 +08:00
<el-table-column label="申请人" align="center" prop="applicantName" width="100" />
<el-table-column label="申请部门" align="center" prop="applyDepartment" width="120" />
<el-table-column label="申请日期" align="center" prop="applyDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.applyDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleDetail(scope.row)"
v-hasPermi="['ccdi:purchaseTransaction:query']"
>详情</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['ccdi:purchaseTransaction:edit']"
>编辑</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['ccdi:purchaseTransaction:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
2026-04-22 16:20:37 +08:00
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
2026-04-22 16:20:37 +08:00
<el-dialog :title="title" :visible.sync="open" width="80%" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<el-divider content-position="left">基本信息</el-divider>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="采购事项ID" prop="purchaseId">
<el-input v-model="form.purchaseId" placeholder="请输入采购事项ID" maxlength="32" :disabled="!isAdd" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采购类别" prop="purchaseCategory">
<el-input v-model="form.purchaseCategory" placeholder="请输入采购类别" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入项目名称" maxlength="200" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="标的物名称" prop="subjectName">
<el-input v-model="form.subjectName" placeholder="请输入标的物名称" maxlength="200" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="标的物描述" prop="subjectDesc">
<el-input v-model="form.subjectDesc" type="textarea" :rows="2" placeholder="请输入标的物描述" />
</el-form-item>
<el-divider content-position="left">数量与金额</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="采购数量" prop="purchaseQty">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.purchaseQty" :min="0" :precision="2" placeholder="请输入采购数量" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预算金额(元)" prop="budgetAmount">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.budgetAmount" :min="0" :precision="2" placeholder="请输入预算金额" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="中标金额(元)" prop="bidAmount">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.bidAmount" :min="0" :precision="2" placeholder="请输入中标金额" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="实际采购金额(元)" prop="actualAmount">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.actualAmount" :min="0" :precision="2" placeholder="请输入实际采购金额" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同金额(元)" prop="contractAmount">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.contractAmount" :min="0" :precision="2" placeholder="请输入合同金额" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算金额(元)" prop="settlementAmount">
2026-04-22 16:20:37 +08:00
<el-input-number v-model="form.settlementAmount" :min="0" :precision="2" placeholder="请输入结算金额" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="采购方式" prop="purchaseMethod">
<el-input v-model="form.purchaseMethod" placeholder="请输入采购方式" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
2026-04-22 16:20:37 +08:00
<el-divider content-position="left">供应商明细</el-divider>
<div class="supplier-toolbar">
<span class="supplier-toolbar__tip">支持录入中标供应商之外的全部参标供应商并标记唯一中标供应商</span>
<el-button type="primary" plain size="mini" icon="el-icon-plus" @click="handleAddSupplier">添加供应商</el-button>
</div>
<el-empty
v-if="!form.supplierList.length"
:image-size="72"
description="当前未录入供应商信息"
class="supplier-empty"
/>
<el-table v-else :data="form.supplierList" border size="small" class="supplier-table">
<el-table-column label="中标" width="90" align="center">
<template slot-scope="scope">
<el-radio v-model="winnerSupplierIndex" :label="scope.$index">中标</el-radio>
</template>
</el-table-column>
<el-table-column label="序号" width="70" align="center">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="供应商名称" min-width="220">
<template slot-scope="scope">
<el-form-item
class="supplier-form-item"
label-width="0px"
:prop="'supplierList.' + scope.$index + '.supplierName'"
:rules="getSupplierFieldRules('supplierName')"
>
<el-input v-model="scope.row.supplierName" placeholder="请输入供应商名称" maxlength="200" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="统一信用代码" min-width="200">
<template slot-scope="scope">
<el-form-item
class="supplier-form-item"
label-width="0px"
:prop="'supplierList.' + scope.$index + '.supplierUscc'"
:rules="getSupplierFieldRules('supplierUscc')"
>
<el-input v-model="scope.row.supplierUscc" placeholder="请输入统一信用代码" maxlength="18" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="联系人" min-width="140">
<template slot-scope="scope">
<el-form-item
class="supplier-form-item"
label-width="0px"
:prop="'supplierList.' + scope.$index + '.contactPerson'"
:rules="getSupplierFieldRules('contactPerson')"
>
<el-input v-model="scope.row.contactPerson" placeholder="请输入联系人" maxlength="50" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="联系电话" min-width="160">
<template slot-scope="scope">
<el-form-item
class="supplier-form-item"
label-width="0px"
:prop="'supplierList.' + scope.$index + '.contactPhone'"
:rules="getSupplierFieldRules('contactPhone')"
>
<el-input v-model="scope.row.contactPhone" placeholder="请输入联系电话" maxlength="20" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="银行账户" min-width="180">
<template slot-scope="scope">
<el-form-item
class="supplier-form-item"
label-width="0px"
:prop="'supplierList.' + scope.$index + '.supplierBankAccount'"
:rules="getSupplierFieldRules('supplierBankAccount')"
>
<el-input v-model="scope.row.supplierBankAccount" placeholder="请输入银行账户" maxlength="50" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="handleRemoveSupplier(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-divider content-position="left">重要日期</el-divider>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="采购申请日期" prop="applyDate">
<el-date-picker
v-model="form.applyDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划批准日期" prop="planApproveDate">
<el-date-picker
v-model="form.planApproveDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="公告发布日期" prop="announceDate">
<el-date-picker
v-model="form.announceDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="开标日期" prop="bidOpenDate">
<el-date-picker
v-model="form.bidOpenDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同签订日期" prop="contractSignDate">
<el-date-picker
v-model="form.contractSignDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计交货日期" prop="expectedDeliveryDate">
<el-date-picker
v-model="form.expectedDeliveryDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="实际交货日期" prop="actualDeliveryDate">
<el-date-picker
v-model="form.actualDeliveryDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="acceptanceDate">
<el-date-picker
v-model="form.acceptanceDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结算日期" prop="settlementDate">
<el-date-picker
v-model="form.settlementDate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">申请人信息</el-divider>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="申请人姓名" prop="applicantName">
<el-input v-model="form.applicantName" placeholder="请输入申请人姓名" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="申请人工号" prop="applicantId">
<el-input v-model="form.applicantId" placeholder="请输入申请人工号" maxlength="20" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="申请部门" prop="applyDepartment">
<el-input v-model="form.applyDepartment" placeholder="请输入申请部门" maxlength="100" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">采购负责人信息</el-divider>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="采购负责人姓名" prop="purchaseLeaderName">
<el-input v-model="form.purchaseLeaderName" placeholder="请输入采购负责人姓名" maxlength="50" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采购负责人工号" prop="purchaseLeaderId">
<el-input v-model="form.purchaseLeaderId" placeholder="请输入采购负责人工号" maxlength="20" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="采购部门" prop="purchaseDepartment">
<el-input v-model="form.purchaseDepartment" placeholder="请输入采购部门" maxlength="100" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</el-dialog>
2026-04-22 16:20:37 +08:00
<el-dialog title="招投标信息详情" :visible.sync="detailOpen" width="1200px" append-to-body>
<div class="detail-container">
<el-divider content-position="left">基本信息</el-divider>
<el-descriptions :column="2" border>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="采购事项ID">{{ transactionDetail.purchaseId || "-" }}</el-descriptions-item>
<el-descriptions-item label="采购类别">{{ transactionDetail.purchaseCategory || "-" }}</el-descriptions-item>
<el-descriptions-item label="项目名称" :span="2">{{ transactionDetail.projectName || "-" }}</el-descriptions-item>
<el-descriptions-item label="标的物名称">{{ transactionDetail.subjectName || "-" }}</el-descriptions-item>
<el-descriptions-item label="采购方式">{{ transactionDetail.purchaseMethod || "-" }}</el-descriptions-item>
<el-descriptions-item label="标的物描述" :span="2">{{ transactionDetail.subjectDesc || "-" }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">数量与金额</el-divider>
<el-descriptions :column="3" border>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="采购数量">{{ transactionDetail.purchaseQty || "-" }}</el-descriptions-item>
<el-descriptions-item label="预算金额(元)">{{ formatAmount(transactionDetail.budgetAmount) }}</el-descriptions-item>
<el-descriptions-item label="中标金额(元)">{{ formatAmount(transactionDetail.bidAmount) }}</el-descriptions-item>
<el-descriptions-item label="实际采购金额(元)">{{ formatAmount(transactionDetail.actualAmount) }}</el-descriptions-item>
<el-descriptions-item label="合同金额(元)">{{ formatAmount(transactionDetail.contractAmount) }}</el-descriptions-item>
<el-descriptions-item label="结算金额(元)">{{ formatAmount(transactionDetail.settlementAmount) }}</el-descriptions-item>
</el-descriptions>
2026-04-22 16:20:37 +08:00
<el-divider content-position="left">供应商明细</el-divider>
<el-empty
v-if="!transactionDetail.supplierList || !transactionDetail.supplierList.length"
:image-size="72"
description="未录入供应商信息"
/>
<el-table v-else :data="transactionDetail.supplierList" border size="small">
<el-table-column label="排序" prop="sortOrder" width="90" align="center" />
<el-table-column label="中标结果" width="110" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.isBidWinner === 1 ? 'danger' : 'info'" size="mini">
{{ scope.row.isBidWinner === 1 ? "中标" : "参标" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="供应商名称" prop="supplierName" min-width="220" :show-overflow-tooltip="true" />
<el-table-column label="统一信用代码" prop="supplierUscc" min-width="180" :show-overflow-tooltip="true" />
<el-table-column label="联系人" prop="contactPerson" min-width="120" :show-overflow-tooltip="true" />
<el-table-column label="联系电话" prop="contactPhone" min-width="150" :show-overflow-tooltip="true" />
<el-table-column label="银行账户" prop="supplierBankAccount" min-width="180" :show-overflow-tooltip="true" />
<el-table-column label="操作" width="100" align="center" fixed="right">
<template slot-scope="scope">
<el-button
type="text"
size="mini"
:loading="enterpriseDetailLoading"
@click="handleSupplierEnterpriseDetail(scope.row)"
>详情</el-button>
</template>
</el-table-column>
2026-04-22 16:20:37 +08:00
</el-table>
<el-divider content-position="left">重要日期</el-divider>
<el-descriptions :column="3" border>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="采购申请日期">{{ transactionDetail.applyDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="计划批准日期">{{ transactionDetail.planApproveDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="公告发布日期">{{ transactionDetail.announceDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="开标日期">{{ transactionDetail.bidOpenDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="合同签订日期">{{ transactionDetail.contractSignDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="预计交货日期">{{ transactionDetail.expectedDeliveryDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="实际交货日期">{{ transactionDetail.actualDeliveryDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="验收日期">{{ transactionDetail.acceptanceDate || "-" }}</el-descriptions-item>
<el-descriptions-item label="结算日期">{{ transactionDetail.settlementDate || "-" }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">申请人信息</el-divider>
<el-descriptions :column="2" border>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="申请人姓名">{{ transactionDetail.applicantName || "-" }}</el-descriptions-item>
<el-descriptions-item label="申请人工号">{{ transactionDetail.applicantId || "-" }}</el-descriptions-item>
<el-descriptions-item label="申请部门">{{ transactionDetail.applyDepartment || "-" }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">采购负责人信息</el-divider>
<el-descriptions :column="2" border>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="采购负责人姓名">{{ transactionDetail.purchaseLeaderName || "-" }}</el-descriptions-item>
<el-descriptions-item label="采购负责人工号">{{ transactionDetail.purchaseLeaderId || "-" }}</el-descriptions-item>
<el-descriptions-item label="采购部门">{{ transactionDetail.purchaseDepartment || "-" }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">审计信息</el-divider>
<el-descriptions :column="2" border>
<el-descriptions-item label="创建时间">
2026-04-22 16:20:37 +08:00
{{ transactionDetail.createTime ? parseTime(transactionDetail.createTime) : "-" }}
</el-descriptions-item>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="创建人">{{ transactionDetail.createdBy || "-" }}</el-descriptions-item>
<el-descriptions-item label="更新时间">
2026-04-22 16:20:37 +08:00
{{ transactionDetail.updateTime ? parseTime(transactionDetail.updateTime) : "-" }}
</el-descriptions-item>
2026-04-22 16:20:37 +08:00
<el-descriptions-item label="更新人">{{ transactionDetail.updatedBy || "-" }}</el-descriptions-item>
</el-descriptions>
</div>
<div slot="footer" class="dialog-footer">
2026-04-22 16:20:37 +08:00
<el-button @click="detailOpen = false" icon="el-icon-close">关闭</el-button>
</div>
</el-dialog>
<el-dialog
title="企业信息详情"
:visible.sync="enterpriseDetailOpen"
width="1000px"
append-to-body
@close="resetEnterpriseDetail"
>
<el-descriptions :column="2" border v-loading="enterpriseDetailLoading">
<el-descriptions-item label="统一社会信用代码">{{ enterpriseDetailData.socialCreditCode || "-" }}</el-descriptions-item>
<el-descriptions-item label="企业名称">{{ enterpriseDetailData.enterpriseName || "-" }}</el-descriptions-item>
<el-descriptions-item label="企业类型">{{ enterpriseDetailData.enterpriseType || "-" }}</el-descriptions-item>
<el-descriptions-item label="企业性质">{{ enterpriseDetailData.enterpriseNature || "-" }}</el-descriptions-item>
<el-descriptions-item label="行业分类">{{ enterpriseDetailData.industryClass || "-" }}</el-descriptions-item>
<el-descriptions-item label="所属行业">{{ enterpriseDetailData.industryName || "-" }}</el-descriptions-item>
<el-descriptions-item label="成立日期">{{ parseTime(enterpriseDetailData.establishDate, "{y}-{m}-{d}") || "-" }}</el-descriptions-item>
<el-descriptions-item label="注册地址">{{ enterpriseDetailData.registerAddress || "-" }}</el-descriptions-item>
<el-descriptions-item label="法定代表人">{{ enterpriseDetailData.legalRepresentative || "-" }}</el-descriptions-item>
<el-descriptions-item label="法定代表人证件类型">{{ enterpriseDetailData.legalCertType || "-" }}</el-descriptions-item>
<el-descriptions-item label="法定代表人证件号码">{{ enterpriseDetailData.legalCertNo || "-" }}</el-descriptions-item>
<el-descriptions-item label="经营状态">{{ formatEnterpriseStatus(enterpriseDetailData.status) }}</el-descriptions-item>
<el-descriptions-item label="风险等级">{{ formatEnterpriseRiskLevel(enterpriseDetailData.riskLevel) }}</el-descriptions-item>
<el-descriptions-item label="企业来源">{{ formatEnterpriseSource(enterpriseDetailData.entSource) }}</el-descriptions-item>
<el-descriptions-item label="数据来源">{{ formatEnterpriseDataSource(enterpriseDetailData.dataSource) }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ parseTime(enterpriseDetailData.createTime) || "-" }}</el-descriptions-item>
<el-descriptions-item label="股东1">{{ enterpriseDetailData.shareholder1 || "-" }}</el-descriptions-item>
<el-descriptions-item label="股东2">{{ enterpriseDetailData.shareholder2 || "-" }}</el-descriptions-item>
<el-descriptions-item label="股东3">{{ enterpriseDetailData.shareholder3 || "-" }}</el-descriptions-item>
<el-descriptions-item label="股东4">{{ enterpriseDetailData.shareholder4 || "-" }}</el-descriptions-item>
<el-descriptions-item label="股东5">{{ enterpriseDetailData.shareholder5 || "-" }}</el-descriptions-item>
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button @click="enterpriseDetailOpen = false">关闭</el-button>
</div>
</el-dialog>
<el-dialog
:title="upload.title"
:visible.sync="upload.open"
2026-04-22 16:20:37 +08:00
width="420px"
append-to-body
@close="handleImportDialogClose"
>
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
2026-04-22 16:20:37 +08:00
<i class="el-icon-upload" />
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">
2026-04-22 16:20:37 +08:00
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline;" @click="importTemplate">
下载模板
</el-link>
<span class="upload-tip-text">模板包含招投标主信息供应商明细两个 Sheet</span>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
2026-04-22 16:20:37 +08:00
<el-button type="primary" @click="submitFileForm" :loading="upload.isUploading">确定</el-button>
<el-button @click="upload.open = false" :disabled="upload.isUploading">取消</el-button>
</div>
</el-dialog>
<import-result-dialog
:visible.sync="importResultVisible"
:content="importResultContent"
title="导入结果"
@close="handleImportResultClose"
/>
<el-dialog
2026-04-22 16:20:37 +08:00
title="招投标导入失败记录"
:visible.sync="failureDialogVisible"
width="1200px"
append-to-body
>
<el-alert
v-if="lastImportInfo"
:title="lastImportInfo"
type="info"
:closable="false"
style="margin-bottom: 15px"
/>
<el-table :data="failureList" v-loading="failureLoading">
<el-table-column label="失败Sheet" prop="sheetName" align="center" width="140" />
<el-table-column label="失败行号" prop="sheetRowNum" align="center" width="120">
<template slot-scope="scope">
<span>{{ scope.row.sheetRowNum ? `${scope.row.sheetRowNum}` : "-" }}</span>
</template>
</el-table-column>
<el-table-column label="采购事项ID" prop="purchaseId" align="center" />
2026-04-22 16:20:37 +08:00
<el-table-column label="项目名称" prop="projectName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="标的物名称" prop="subjectName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="失败原因" prop="errorMessage" align="center" min-width="200" :show-overflow-tooltip="true" />
</el-table>
<pagination
v-show="failureTotal > 0"
:total="failureTotal"
:page.sync="failureQueryParams.pageNum"
:limit.sync="failureQueryParams.pageSize"
@pagination="getFailureList"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="failureDialogVisible = false">关闭</el-button>
<el-button type="danger" plain @click="clearImportHistory">清除历史记录</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
2026-02-06 17:22:59 +08:00
import {
addTransaction,
delTransaction,
getImportFailures,
getImportStatus,
getTransaction,
listTransaction,
updateTransaction
} from "@/api/ccdiPurchaseTransaction";
import { getEnterpriseBaseInfo } from "@/api/ccdiEnterpriseBaseInfo";
import {
getDataSourceOptions,
getEnterpriseRiskLevelOptions,
getEnterpriseSourceOptions
} from "@/api/ccdiEnum";
2026-04-22 16:20:37 +08:00
import { getToken } from "@/utils/auth";
import ImportResultDialog from "@/components/ImportResultDialog.vue";
2026-04-22 16:20:37 +08:00
const createSupplierRow = () => ({
supplierName: "",
supplierUscc: "",
contactPerson: "",
contactPhone: "",
supplierBankAccount: "",
sortOrder: null,
isBidWinner: 0
});
const createDefaultForm = () => ({
purchaseId: null,
purchaseCategory: null,
projectName: null,
subjectName: null,
subjectDesc: null,
purchaseQty: null,
budgetAmount: null,
bidAmount: null,
actualAmount: null,
contractAmount: null,
settlementAmount: null,
purchaseMethod: null,
applyDate: null,
planApproveDate: null,
announceDate: null,
bidOpenDate: null,
contractSignDate: null,
expectedDeliveryDate: null,
actualDeliveryDate: null,
acceptanceDate: null,
settlementDate: null,
applicantId: null,
applicantName: null,
applyDepartment: null,
purchaseLeaderId: null,
purchaseLeaderName: null,
purchaseDepartment: null,
supplierList: []
});
export default {
name: "PurchaseTransaction",
components: { ImportResultDialog },
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
transactionList: [],
title: "",
open: false,
detailOpen: false,
enterpriseDetailOpen: false,
enterpriseDetailLoading: false,
enterpriseDetailData: {},
2026-04-22 16:20:37 +08:00
transactionDetail: { supplierList: [] },
isAdd: false,
dateRange: [],
2026-04-22 16:20:37 +08:00
winnerSupplierIndex: null,
enterpriseRiskLevelOptions: [],
enterpriseSourceOptions: [],
enterpriseDataSourceOptions: [],
queryParams: {
pageNum: 1,
pageSize: 10,
projectName: null,
subjectName: null,
applicantName: null
},
2026-04-22 16:20:37 +08:00
form: createDefaultForm(),
rules: {
purchaseId: [
{ required: true, message: "采购事项ID不能为空", trigger: "blur" },
{ max: 32, message: "采购事项ID长度不能超过32个字符", trigger: "blur" }
],
purchaseCategory: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "采购类别不能为空", trigger: "blur" },
{ max: 50, message: "采购类别长度不能超过50个字符", trigger: "blur" }
],
projectName: [
{ max: 200, message: "项目名称长度不能超过200个字符", trigger: "blur" }
],
subjectName: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "标的物名称不能为空", trigger: "blur" },
{ max: 200, message: "标的物名称长度不能超过200个字符", trigger: "blur" }
],
subjectDesc: [
{ max: 500, message: "标的物描述长度不能超过500个字符", trigger: "blur" }
],
2026-02-06 17:22:59 +08:00
purchaseQty: [
{ required: true, message: "采购数量不能为空", trigger: "blur" },
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.0001, message: "采购数量必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
budgetAmount: [
{ required: true, message: "预算金额不能为空", trigger: "blur" },
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.01, message: "预算金额必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
bidAmount: [
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.01, message: "中标金额必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
actualAmount: [
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.01, message: "实际采购金额必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
contractAmount: [
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.01, message: "合同金额必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
settlementAmount: [
2026-04-22 16:20:37 +08:00
{ type: "number", min: 0.01, message: "结算金额必须大于0", trigger: "blur" }
2026-02-06 17:22:59 +08:00
],
purchaseMethod: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "采购方式不能为空", trigger: "blur" },
{ max: 50, message: "采购方式长度不能超过50个字符", trigger: "blur" }
],
2026-02-06 17:22:59 +08:00
applyDate: [
{ required: true, message: "采购申请日期不能为空", trigger: "change" }
],
applicantName: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "申请人姓名不能为空", trigger: "blur" },
{ max: 50, message: "申请人姓名长度不能超过50个字符", trigger: "blur" }
],
applicantId: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "申请人工号不能为空", trigger: "blur" },
{ pattern: /^\d{7}$/, message: "申请人工号必须为7位数字", trigger: "blur" }
],
applyDepartment: [
2026-02-06 17:22:59 +08:00
{ required: true, message: "申请部门不能为空", trigger: "blur" },
{ max: 100, message: "申请部门长度不能超过100个字符", trigger: "blur" }
],
purchaseLeaderName: [
{ max: 50, message: "采购负责人姓名长度不能超过50个字符", trigger: "blur" }
],
purchaseLeaderId: [
2026-02-06 17:22:59 +08:00
{ pattern: /^\d{7}$/, message: "采购负责人工号必须为7位数字", trigger: "blur" }
],
purchaseDepartment: [
{ max: 100, message: "采购部门长度不能超过100个字符", trigger: "blur" }
]
},
upload: {
open: false,
title: "",
isUploading: false,
headers: { Authorization: "Bearer " + getToken() },
url: process.env.VUE_APP_BASE_API + "/ccdi/purchaseTransaction/importData"
},
importResultVisible: false,
importResultContent: "",
importPollingTimer: null,
showFailureButton: false,
currentTaskId: null,
failureDialogVisible: false,
failureList: [],
failureLoading: false,
failureTotal: 0,
failureQueryParams: {
pageNum: 1,
pageSize: 10
}
};
},
computed: {
lastImportInfo() {
const savedTask = this.getImportTaskFromStorage();
if (savedTask && savedTask.totalCount) {
return `导入时间: ${this.parseTime(savedTask.saveTime)} | 总数: ${savedTask.totalCount}条 | 成功: ${savedTask.successCount}条 | 失败: ${savedTask.failureCount}`;
}
2026-04-22 16:20:37 +08:00
return "";
}
},
created() {
this.getList();
2026-04-22 16:20:37 +08:00
this.restoreImportState();
this.loadEnterpriseDetailOptions();
},
beforeDestroy() {
if (this.importPollingTimer) {
clearInterval(this.importPollingTimer);
this.importPollingTimer = null;
}
},
methods: {
loadEnterpriseDetailOptions() {
return Promise.all([
getEnterpriseRiskLevelOptions(),
getEnterpriseSourceOptions(),
getDataSourceOptions()
]).then(([riskRes, sourceRes, dataSourceRes]) => {
this.enterpriseRiskLevelOptions = riskRes.data || [];
this.enterpriseSourceOptions = sourceRes.data || [];
this.enterpriseDataSourceOptions = dataSourceRes.data || [];
}).catch(() => {
this.enterpriseRiskLevelOptions = [];
this.enterpriseSourceOptions = [];
this.enterpriseDataSourceOptions = [];
});
},
getEnterpriseOptionLabel(options, value) {
if (!value) return "-";
const matched = (options || []).find(item => item.value === value);
return matched ? matched.label : value;
},
getList() {
this.loading = true;
2026-04-22 16:20:37 +08:00
const params = this.addDateRangeFlat(this.queryParams, this.dateRange, "applyDateStart", "applyDateEnd");
listTransaction(params).then(response => {
2026-04-22 16:20:37 +08:00
this.transactionList = response.rows || [];
this.total = response.total || 0;
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
restoreImportState() {
const savedTask = this.getImportTaskFromStorage();
if (!savedTask) {
this.showFailureButton = false;
this.currentTaskId = null;
return;
}
if (savedTask.hasFailures && savedTask.taskId) {
this.currentTaskId = savedTask.taskId;
this.showFailureButton = true;
}
},
getLastImportTooltip() {
const savedTask = this.getImportTaskFromStorage();
if (savedTask && savedTask.saveTime) {
const date = new Date(savedTask.saveTime);
2026-04-22 16:20:37 +08:00
return `上次导入: ${this.parseTime(date, "{y}-{m}-{d} {h}:{i}")}`;
}
2026-04-22 16:20:37 +08:00
return "";
},
formatAmount(amount) {
2026-04-22 16:20:37 +08:00
if (amount === null || amount === undefined || amount === "") return "-";
return parseFloat(amount).toLocaleString("zh-CN", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
},
formatEnterpriseRiskLevel(value) {
return this.getEnterpriseOptionLabel(this.enterpriseRiskLevelOptions, value);
},
formatEnterpriseSource(value) {
return this.getEnterpriseOptionLabel(this.enterpriseSourceOptions, value);
},
formatEnterpriseDataSource(value) {
return this.getEnterpriseOptionLabel(this.enterpriseDataSourceOptions, value);
},
formatEnterpriseStatus(value) {
return value || "-";
},
2026-04-22 16:20:37 +08:00
getSupplierFieldRules(field) {
const ruleMap = {
supplierName: [
{ required: true, message: "供应商名称不能为空", trigger: "blur" }
2026-04-22 16:20:37 +08:00
],
supplierUscc: [
{ required: true, message: "统一信用代码不能为空", trigger: "blur" }
2026-04-22 16:20:37 +08:00
],
};
return ruleMap[field] || [];
},
cancel() {
this.open = false;
this.reset();
},
reset() {
2026-04-22 16:20:37 +08:00
this.form = createDefaultForm();
this.winnerSupplierIndex = null;
this.resetForm("form");
},
resetEnterpriseDetail() {
this.enterpriseDetailOpen = false;
this.enterpriseDetailLoading = false;
this.enterpriseDetailData = {};
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.purchaseId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
handleAdd() {
this.reset();
this.open = true;
2026-04-22 16:20:37 +08:00
this.title = "添加招投标信息";
this.isAdd = true;
},
handleUpdate(row) {
this.reset();
const purchaseId = row.purchaseId || this.ids[0];
getTransaction(purchaseId).then(response => {
2026-04-22 16:20:37 +08:00
this.applyFormData(response.data);
this.open = true;
2026-04-22 16:20:37 +08:00
this.title = "修改招投标信息";
this.isAdd = false;
2026-04-22 16:20:37 +08:00
this.$nextTick(() => {
this.$refs.form && this.$refs.form.clearValidate();
});
});
},
handleDetail(row) {
2026-04-22 16:20:37 +08:00
getTransaction(row.purchaseId).then(response => {
this.transactionDetail = this.normalizeTransactionData(response.data);
this.detailOpen = true;
});
},
async handleSupplierEnterpriseDetail(row) {
const socialCreditCode = row && row.supplierUscc ? row.supplierUscc.trim() : "";
if (!socialCreditCode) {
this.$message.warning("暂无企业信息");
return;
}
this.enterpriseDetailLoading = true;
this.enterpriseDetailData = {};
try {
const response = await getEnterpriseBaseInfo(socialCreditCode);
if (!response || !response.data) {
this.$message.warning("暂无企业信息");
return;
}
this.enterpriseDetailData = response.data;
this.enterpriseDetailOpen = true;
} catch (error) {
this.$message.warning("暂无企业信息");
} finally {
this.enterpriseDetailLoading = false;
}
},
2026-04-22 16:20:37 +08:00
handleAddSupplier() {
this.form.supplierList.push(createSupplierRow());
},
handleRemoveSupplier(index) {
this.form.supplierList.splice(index, 1);
if (this.winnerSupplierIndex === index) {
this.winnerSupplierIndex = null;
} else if (this.winnerSupplierIndex !== null && this.winnerSupplierIndex > index) {
this.winnerSupplierIndex -= 1;
}
},
submitForm() {
2026-04-22 16:20:37 +08:00
this.$refs.form.validate(valid => {
if (!valid) {
return;
}
2026-04-22 16:20:37 +08:00
const payload = this.buildSubmitPayload();
if (!this.validateSupplierDuplicates(payload.supplierList)) {
return;
}
const request = this.isAdd ? addTransaction(payload) : updateTransaction(payload);
request.then(() => {
this.$modal.msgSuccess(this.isAdd ? "新增成功" : "修改成功");
this.open = false;
this.getList();
});
});
},
2026-04-22 16:20:37 +08:00
buildSubmitPayload() {
const payload = JSON.parse(JSON.stringify(this.form));
payload.supplierList = this.form.supplierList
.filter(item => this.hasAnySupplierValue(item))
.map((item, index) => ({
...item,
supplierName: item.supplierName ? item.supplierName.trim() : "",
supplierUscc: item.supplierUscc ? item.supplierUscc.trim() : "",
contactPerson: item.contactPerson ? item.contactPerson.trim() : "",
contactPhone: item.contactPhone ? item.contactPhone.trim() : "",
supplierBankAccount: item.supplierBankAccount ? item.supplierBankAccount.trim() : "",
sortOrder: item.sortOrder || index + 1,
isBidWinner: this.winnerSupplierIndex === index ? 1 : 0
}));
return payload;
},
validateSupplierDuplicates(supplierList) {
const seen = new Set();
for (const item of supplierList) {
const key = `${item.supplierName || ""}|${item.supplierUscc || ""}`;
if (seen.has(key)) {
this.$message.error("同一招投标事项存在重复供应商,请检查供应商名称和统一信用代码");
return false;
}
seen.add(key);
}
return true;
},
hasAnySupplierValue(item) {
return !!(
item.supplierName ||
item.supplierUscc ||
item.contactPerson ||
item.contactPhone ||
item.supplierBankAccount
);
},
handleDelete(row) {
const purchaseIds = row.purchaseId || this.ids;
2026-04-22 16:20:37 +08:00
this.$modal.confirm(`是否确认删除采购事项ID为"${purchaseIds}"的数据项?`).then(function() {
return delTransaction(purchaseIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
handleImport() {
2026-04-22 16:20:37 +08:00
this.upload.title = "招投标信息导入";
this.upload.open = true;
},
importTemplate() {
2026-04-22 16:20:37 +08:00
this.download("ccdi/purchaseTransaction/importTemplate", {}, `招投标信息维护导入模板_${new Date().getTime()}.xlsx`);
},
2026-04-22 16:20:37 +08:00
handleFileUploadProgress() {
this.upload.isUploading = true;
},
2026-04-22 16:20:37 +08:00
handleFileSuccess(response) {
this.upload.isUploading = false;
this.upload.open = false;
2026-04-22 16:20:37 +08:00
if (response.code !== 200) {
this.$modal.msgError(response.msg);
return;
}
if (!response.data || !response.data.taskId) {
this.$modal.msgError("导入任务创建失败: 缺少任务ID");
this.upload.open = true;
return;
}
2026-04-22 16:20:37 +08:00
const taskId = response.data.taskId;
if (this.importPollingTimer) {
clearInterval(this.importPollingTimer);
this.importPollingTimer = null;
}
2026-04-22 16:20:37 +08:00
this.clearImportTaskFromStorage();
this.saveImportTaskToStorage({
taskId,
status: "PROCESSING",
timestamp: Date.now(),
hasFailures: false
});
this.showFailureButton = false;
this.currentTaskId = taskId;
2026-04-22 16:20:37 +08:00
this.$notify({
title: "导入任务已提交",
message: "正在后台处理中,处理完成后将通知您",
type: "info",
duration: 3000
});
2026-04-22 16:20:37 +08:00
this.startImportStatusPolling(taskId);
},
startImportStatusPolling(taskId) {
let pollCount = 0;
2026-04-22 16:20:37 +08:00
const maxPolls = 150;
this.importPollingTimer = setInterval(async () => {
try {
2026-04-22 16:20:37 +08:00
pollCount += 1;
if (pollCount > maxPolls) {
clearInterval(this.importPollingTimer);
2026-04-22 16:20:37 +08:00
this.$modal.msgWarning("导入任务处理超时,请联系管理员");
return;
}
const response = await getImportStatus(taskId);
2026-04-22 16:20:37 +08:00
if (response.data && response.data.status !== "PROCESSING") {
clearInterval(this.importPollingTimer);
this.handleImportComplete(response.data);
}
} catch (error) {
clearInterval(this.importPollingTimer);
2026-04-22 16:20:37 +08:00
this.$modal.msgError("查询导入状态失败: " + error.message);
}
2026-04-22 16:20:37 +08:00
}, 2000);
},
getFailureList() {
this.failureLoading = true;
getImportFailures(
this.currentTaskId,
this.failureQueryParams.pageNum,
this.failureQueryParams.pageSize
).then(response => {
this.failureList = response.rows;
this.failureTotal = response.total;
this.failureLoading = false;
}).catch(error => {
this.failureLoading = false;
if (error.response) {
const status = error.response.status;
if (status === 404) {
2026-04-22 16:20:37 +08:00
this.$modal.msgWarning("导入记录已过期,无法查看失败记录");
this.clearImportTaskFromStorage();
this.showFailureButton = false;
this.currentTaskId = null;
this.failureDialogVisible = false;
} else if (status === 500) {
2026-04-22 16:20:37 +08:00
this.$modal.msgError("服务器错误,请稍后重试");
} else {
2026-04-22 16:20:37 +08:00
this.$modal.msgError(`查询失败: ${error.response.data.msg || "未知错误"}`);
}
} else if (error.request) {
2026-04-22 16:20:37 +08:00
this.$modal.msgError("网络连接失败,请检查网络");
} else {
2026-04-22 16:20:37 +08:00
this.$modal.msgError("查询失败记录失败: " + error.message);
}
});
},
viewImportFailures() {
this.failureDialogVisible = true;
this.getFailureList();
},
handleImportComplete(statusResult) {
this.saveImportTaskToStorage({
taskId: statusResult.taskId,
status: statusResult.status,
hasFailures: statusResult.failureCount > 0,
totalCount: statusResult.totalCount,
successCount: statusResult.successCount,
failureCount: statusResult.failureCount
});
2026-04-22 16:20:37 +08:00
if (statusResult.status === "SUCCESS") {
this.$notify({
2026-04-22 16:20:37 +08:00
title: "导入完成",
message: `全部成功! 共导入${statusResult.totalCount}条数据`,
type: "success",
duration: 5000
});
2026-04-22 16:20:37 +08:00
this.showFailureButton = false;
this.getList();
2026-04-22 16:20:37 +08:00
return;
}
if (statusResult.failureCount > 0) {
this.$notify({
2026-04-22 16:20:37 +08:00
title: "导入完成",
message: `成功${statusResult.successCount}条,失败${statusResult.failureCount}`,
type: "warning",
duration: 5000
});
this.showFailureButton = true;
this.currentTaskId = statusResult.taskId;
this.getList();
}
},
handleImportResultClose() {
this.importResultVisible = false;
this.importResultContent = "";
},
submitFileForm() {
this.$refs.upload.submit();
},
handleImportDialogClose() {
this.upload.isUploading = false;
2026-04-22 16:20:37 +08:00
this.$refs.upload && this.$refs.upload.clearFiles();
},
saveImportTaskToStorage(taskData) {
try {
2026-04-22 16:20:37 +08:00
localStorage.setItem(
"purchase_transaction_import_last_task",
JSON.stringify({ ...taskData, saveTime: Date.now() })
);
} catch (error) {
2026-04-22 16:20:37 +08:00
console.error("保存导入任务状态失败:", error);
}
},
getImportTaskFromStorage() {
try {
2026-04-22 16:20:37 +08:00
const data = localStorage.getItem("purchase_transaction_import_last_task");
if (!data) return null;
const task = JSON.parse(data);
if (!task || !task.taskId) {
this.clearImportTaskFromStorage();
return null;
}
2026-04-22 16:20:37 +08:00
if (task.saveTime && typeof task.saveTime !== "number") {
this.clearImportTaskFromStorage();
return null;
}
const sevenDays = 7 * 24 * 60 * 60 * 1000;
if (Date.now() - task.saveTime > sevenDays) {
this.clearImportTaskFromStorage();
return null;
}
return task;
} catch (error) {
2026-04-22 16:20:37 +08:00
console.error("读取导入任务状态失败:", error);
this.clearImportTaskFromStorage();
return null;
}
},
clearImportHistory() {
2026-04-22 16:20:37 +08:00
this.$confirm("确认清除上次导入记录?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.clearImportTaskFromStorage();
this.showFailureButton = false;
this.currentTaskId = null;
this.failureDialogVisible = false;
2026-04-22 16:20:37 +08:00
this.$message.success("已清除");
}).catch(() => {});
},
clearImportTaskFromStorage() {
try {
2026-04-22 16:20:37 +08:00
localStorage.removeItem("purchase_transaction_import_last_task");
} catch (error) {
2026-04-22 16:20:37 +08:00
console.error("清除导入任务状态失败:", error);
}
},
applyFormData(data) {
const normalized = this.normalizeTransactionData(data);
this.form = normalized;
this.winnerSupplierIndex = normalized.supplierList.findIndex(item => item.isBidWinner === 1);
if (this.winnerSupplierIndex < 0) {
this.winnerSupplierIndex = null;
}
2026-04-22 16:20:37 +08:00
},
normalizeTransactionData(data) {
const normalized = {
...createDefaultForm(),
...(data || {})
};
let supplierList = Array.isArray(data && data.supplierList) ? data.supplierList : [];
if (!supplierList.length && data && data.supplierName) {
supplierList = [{
supplierName: data.supplierName || "",
supplierUscc: data.supplierUscc || "",
contactPerson: data.contactPerson || "",
contactPhone: data.contactPhone || "",
supplierBankAccount: data.supplierBankAccount || "",
sortOrder: 1,
isBidWinner: 1
}];
}
normalized.supplierList = supplierList.map((item, index) => ({
...createSupplierRow(),
...item,
sortOrder: item.sortOrder || index + 1,
isBidWinner: item.isBidWinner === 1 ? 1 : 0
}));
return normalized;
}
}
};
</script>
<style scoped>
2026-04-24 13:29:13 +08:00
.query-form ::v-deep .el-row {
display: flex;
flex-wrap: wrap;
}
.query-form ::v-deep .el-col {
float: none;
}
.query-form ::v-deep .el-form-item {
margin-right: 0;
}
.detail-container {
padding: 0 20px;
}
.el-divider {
margin: 16px 0;
}
2026-04-22 16:20:37 +08:00
.supplier-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.supplier-toolbar__tip {
color: #606266;
font-size: 13px;
}
.supplier-empty {
margin-bottom: 16px;
}
.supplier-table {
margin-bottom: 8px;
}
.supplier-form-item {
margin-bottom: 0;
}
.upload-tip-text {
margin-left: 8px;
color: #909399;
font-size: 12px;
}
</style>