补充招投标供应商企业详情查看
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
# 招投标详情弹窗供应商企业信息查看实施记录
|
||||||
|
|
||||||
|
## 本次修改
|
||||||
|
- 在招投标信息维护详情弹窗的供应商明细中新增“详情”按钮,固定显示且未新增实体库权限显隐控制。
|
||||||
|
- 复用实体库详情接口,按 `supplierUscc` 查询企业信息,并以二级弹窗展示全部字段。
|
||||||
|
- 缺少统一信用代码、查无数据、接口 500/普通异常时,统一提示“暂无企业信息”。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
- `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`
|
||||||
|
- `ruoyi-ui/tests/unit/purchase-transaction-enterprise-detail-ui.test.js`
|
||||||
|
|
||||||
|
## 验证方式
|
||||||
|
- Node 源码断言测试
|
||||||
|
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && node ruoyi-ui/tests/unit/purchase-transaction-enterprise-detail-ui.test.js`
|
||||||
|
- 前端生产构建
|
||||||
|
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
|
||||||
|
- Playwright 真实页面验证
|
||||||
|
- 页面地址:`http://localhost:8080/maintain/purchaseTransaction`
|
||||||
|
- 覆盖场景:
|
||||||
|
- 供应商 `supplierUscc` 命中实体库时可打开企业详情弹窗
|
||||||
|
- 企业详情字段顺序、日期格式、枚举中文标签与实体库详情页口径一致
|
||||||
|
- `supplierUscc` 为空时提示“暂无企业信息”
|
||||||
|
- 查无数据时提示“暂无企业信息”
|
||||||
|
- 接口 500 时提示“暂无企业信息”
|
||||||
|
- 命中后关闭企业详情弹窗,再查看未命中供应商时不残留上一条详情数据
|
||||||
|
|
||||||
|
## 真实页面验证结论
|
||||||
|
- 使用真实业务页面完成验证,供应商明细“详情”按钮在详情弹窗中固定显示。
|
||||||
|
- 命中实体库样本时,二级弹窗成功展示统一社会信用代码、企业名称、企业类型、企业性质、行业分类、所属行业、法定代表人、风险等级、企业来源、数据来源、股东信息等字段。
|
||||||
|
- 查无数据、缺少统一信用代码、接口异常三类异常分支均统一显示“暂无企业信息”,未出现残留旧详情数据的问题。
|
||||||
|
|
||||||
|
## 测试进程清理
|
||||||
|
- 已关闭本次启动的前端 `npm run dev -- --port 8080` 进程。
|
||||||
|
- 后端 `62318` 端口服务在验证前已存在,本次未重新启动后端进程。
|
||||||
|
- 已关闭 Playwright 浏览器会话,并清理残留 daemon 进程。
|
||||||
|
|
||||||
|
## 备注
|
||||||
|
- 计划中的中间提交步骤未执行:`ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue` 在实施前已存在未提交改动,为避免混入同文件既有变更,本次仅完成实现、验证与文档沉淀。
|
||||||
@@ -506,6 +506,16 @@
|
|||||||
<el-table-column label="联系人" prop="contactPerson" min-width="120" :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="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="银行账户" 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>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-divider content-position="left">重要日期</el-divider>
|
<el-divider content-position="left">重要日期</el-divider>
|
||||||
@@ -552,6 +562,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</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
|
<el-dialog
|
||||||
:title="upload.title"
|
:title="upload.title"
|
||||||
:visible.sync="upload.open"
|
:visible.sync="upload.open"
|
||||||
@@ -608,6 +653,12 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<el-table :data="failureList" v-loading="failureLoading">
|
<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" />
|
<el-table-column label="采购事项ID" prop="purchaseId" align="center" />
|
||||||
<el-table-column label="项目名称" prop="projectName" align="center" :show-overflow-tooltip="true" />
|
<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="subjectName" align="center" :show-overflow-tooltip="true" />
|
||||||
@@ -640,6 +691,12 @@ import {
|
|||||||
listTransaction,
|
listTransaction,
|
||||||
updateTransaction
|
updateTransaction
|
||||||
} from "@/api/ccdiPurchaseTransaction";
|
} from "@/api/ccdiPurchaseTransaction";
|
||||||
|
import { getEnterpriseBaseInfo } from "@/api/ccdiEnterpriseBaseInfo";
|
||||||
|
import {
|
||||||
|
getDataSourceOptions,
|
||||||
|
getEnterpriseRiskLevelOptions,
|
||||||
|
getEnterpriseSourceOptions
|
||||||
|
} from "@/api/ccdiEnum";
|
||||||
import { getToken } from "@/utils/auth";
|
import { getToken } from "@/utils/auth";
|
||||||
import ImportResultDialog from "@/components/ImportResultDialog.vue";
|
import ImportResultDialog from "@/components/ImportResultDialog.vue";
|
||||||
|
|
||||||
@@ -699,10 +756,16 @@ export default {
|
|||||||
title: "",
|
title: "",
|
||||||
open: false,
|
open: false,
|
||||||
detailOpen: false,
|
detailOpen: false,
|
||||||
|
enterpriseDetailOpen: false,
|
||||||
|
enterpriseDetailLoading: false,
|
||||||
|
enterpriseDetailData: {},
|
||||||
transactionDetail: { supplierList: [] },
|
transactionDetail: { supplierList: [] },
|
||||||
isAdd: false,
|
isAdd: false,
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
winnerSupplierIndex: null,
|
winnerSupplierIndex: null,
|
||||||
|
enterpriseRiskLevelOptions: [],
|
||||||
|
enterpriseSourceOptions: [],
|
||||||
|
enterpriseDataSourceOptions: [],
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -813,6 +876,7 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.restoreImportState();
|
this.restoreImportState();
|
||||||
|
this.loadEnterpriseDetailOptions();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.importPollingTimer) {
|
if (this.importPollingTimer) {
|
||||||
@@ -821,6 +885,26 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const params = this.addDateRangeFlat(this.queryParams, this.dateRange, "applyDateStart", "applyDateEnd");
|
const params = this.addDateRangeFlat(this.queryParams, this.dateRange, "applyDateStart", "applyDateEnd");
|
||||||
@@ -859,23 +943,25 @@ export default {
|
|||||||
maximumFractionDigits: 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 || "-";
|
||||||
|
},
|
||||||
getSupplierFieldRules(field) {
|
getSupplierFieldRules(field) {
|
||||||
const ruleMap = {
|
const ruleMap = {
|
||||||
supplierName: [
|
supplierName: [
|
||||||
{ required: true, message: "供应商名称不能为空", trigger: "blur" },
|
{ required: true, message: "供应商名称不能为空", trigger: "blur" }
|
||||||
{ max: 200, message: "供应商名称长度不能超过200个字符", trigger: "blur" }
|
|
||||||
],
|
],
|
||||||
supplierUscc: [
|
supplierUscc: [
|
||||||
{ pattern: /^$|^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/, message: "请输入正确的18位统一信用代码", trigger: "blur" }
|
{ required: true, message: "统一信用代码不能为空", trigger: "blur" }
|
||||||
],
|
|
||||||
contactPerson: [
|
|
||||||
{ max: 50, message: "联系人长度不能超过50个字符", trigger: "blur" }
|
|
||||||
],
|
|
||||||
contactPhone: [
|
|
||||||
{ pattern: /^$|^1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$/, message: "请输入正确的联系电话(手机号或座机号)", trigger: "blur" }
|
|
||||||
],
|
|
||||||
supplierBankAccount: [
|
|
||||||
{ max: 50, message: "银行账户长度不能超过50个字符", trigger: "blur" }
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
return ruleMap[field] || [];
|
return ruleMap[field] || [];
|
||||||
@@ -889,6 +975,11 @@ export default {
|
|||||||
this.winnerSupplierIndex = null;
|
this.winnerSupplierIndex = null;
|
||||||
this.resetForm("form");
|
this.resetForm("form");
|
||||||
},
|
},
|
||||||
|
resetEnterpriseDetail() {
|
||||||
|
this.enterpriseDetailOpen = false;
|
||||||
|
this.enterpriseDetailLoading = false;
|
||||||
|
this.enterpriseDetailData = {};
|
||||||
|
},
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.pageNum = 1;
|
this.queryParams.pageNum = 1;
|
||||||
this.getList();
|
this.getList();
|
||||||
@@ -928,6 +1019,28 @@ export default {
|
|||||||
this.detailOpen = true;
|
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;
|
||||||
|
}
|
||||||
|
},
|
||||||
handleAddSupplier() {
|
handleAddSupplier() {
|
||||||
this.form.supplierList.push(createSupplierRow());
|
this.form.supplierList.push(createSupplierRow());
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user