实现结果总览详情资产和征信页签
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# 结果总览详情弹窗资产与征信页签前端实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
在项目详情“结果总览 - 风险总览 - 查看详情”弹窗中,将资产分析和征信页签从占位展示改为真实详情展示。
|
||||
|
||||
## 实施范围
|
||||
|
||||
- `资产分析` 页签复用员工家庭资产负债专项核查中的资产详情展示组件。
|
||||
- `征信摘要` 页签改名为 `征信详情`,复用征信信息维护中的详情展示结构。
|
||||
- 不新增后端接口,不调整后端权限、SQL 或业务口径。
|
||||
|
||||
## 前端改动
|
||||
|
||||
- 抽取征信详情展示组件 `CreditInfoDetail`,并在征信信息维护详情弹窗中复用。
|
||||
- 新增征信详情标准化 helper,以详情接口返回的 `negativeInfo` 和 `debtList` 计算展示字段,不依赖征信列表行。
|
||||
- 在项目分析弹窗中按页签懒加载资产详情和征信详情:
|
||||
- 资产详情调用 `getFamilyAssetLiabilityDetail(projectId, staffIdCard)`。
|
||||
- 征信详情调用 `getCreditInfoDetail(staffIdCard)`。
|
||||
- 同一次打开弹窗内已加载页签不重复请求。
|
||||
- 缺少项目或人员身份证号时只展示页签内提示,不发起请求。
|
||||
- `getCreditInfoDetail` 使用 `encodeURIComponent(personId)` 拼接路径。
|
||||
|
||||
## 验证计划
|
||||
|
||||
- 使用 `nvm use` 后运行相关前端静态测试。
|
||||
- 运行前端生产构建验证组件引用与模板编译。
|
||||
- 启动真实前后端后,用浏览器进入项目详情页,在结果总览风险总览中点击“查看详情”,分别验证资产分析和征信详情页签。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 结果总览详情弹窗资产与征信页签前端实施记录
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 新增征信详情展示组件,统一展示征信摘要、负面信息和负债信息。
|
||||
- 征信信息维护详情弹窗改为复用征信详情展示组件,列表、上传和删除逻辑保持不变。
|
||||
- 项目分析弹窗中:
|
||||
- `资产分析` 页签改为展示员工家庭资产负债专项核查资产详情。
|
||||
- `征信摘要` 页签改名为 `征信详情`,改为展示征信信息维护详情。
|
||||
- 资产与征信详情按页签懒加载,并在弹窗关闭、重新打开或人员切换时重置详情状态。
|
||||
- 征信详情接口路径拼接改为编码人员标识。
|
||||
- 同步更新结果总览弹窗静态页签文案和前端静态测试断言。
|
||||
|
||||
## 影响范围
|
||||
|
||||
- 前端页面:
|
||||
- 结果总览项目分析弹窗
|
||||
- 征信信息维护详情弹窗
|
||||
- 前端接口:
|
||||
- `getCreditInfoDetail`
|
||||
- `getFamilyAssetLiabilityDetail` 仅被结果总览弹窗新增复用
|
||||
- 后端接口、数据库和权限未改动。
|
||||
|
||||
## 验证情况
|
||||
|
||||
- 已执行前端聚焦静态测试:
|
||||
- `project-analysis-dialog-*.test.js`
|
||||
- `credit-info-*.test.js`
|
||||
- `special-check-detail-*.test.js`
|
||||
- `special-check-family-asset-liability-api.test.js`
|
||||
- `special-check-family-table.test.js`
|
||||
- 已执行 `npm run build:prod`,构建通过;仅保留现有资源体积类提示。
|
||||
- 已使用真实浏览器验证项目详情页结果总览风险总览的 `查看详情` 弹窗:
|
||||
- `资产分析` 页签展示员工家庭资产负债专项核查资产详情组件。
|
||||
- `征信详情` 页签展示征信详情组件,包含征信摘要、负面信息和负债信息。
|
||||
- 测试结束后已关闭本次启动的前端 dev server。
|
||||
|
||||
## 备注
|
||||
|
||||
- 当前仓库中已有的资金图谱相关后端改动不属于本次实施范围,未处理。
|
||||
@@ -26,7 +26,7 @@ export function listCreditInfo(query) {
|
||||
|
||||
export function getCreditInfoDetail(personId) {
|
||||
return request({
|
||||
url: '/ccdi/creditInfo/' + personId,
|
||||
url: '/ccdi/creditInfo/' + encodeURIComponent(personId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="credit-info-detail" v-loading="loading">
|
||||
<div class="section-title">征信摘要</div>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">征信查询日期:{{ formatQueryDate(detail.queryDate) }}</el-col>
|
||||
<el-col :span="8">负债笔数:{{ detail.debtCount || 0 }}</el-col>
|
||||
<el-col :span="8">负债总额:{{ formatAmount(detail.debtTotalAmount) }}</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="section-title">负面信息</div>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">民事案件笔数:{{ detail.negativeInfo.civilCnt || 0 }}</el-col>
|
||||
<el-col :span="8">强制执行笔数:{{ detail.negativeInfo.enforceCnt || 0 }}</el-col>
|
||||
<el-col :span="8">行政处罚笔数:{{ detail.negativeInfo.admCnt || 0 }}</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">民事案件金额:{{ formatAmount(detail.negativeInfo.civilLmt) }}</el-col>
|
||||
<el-col :span="8">强制执行金额:{{ formatAmount(detail.negativeInfo.enforceLmt) }}</el-col>
|
||||
<el-col :span="8">行政处罚金额:{{ formatAmount(detail.negativeInfo.admLmt) }}</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="section-title">负债信息</div>
|
||||
<el-table :data="detail.debts || []" size="mini">
|
||||
<template slot="empty">
|
||||
<el-empty :image-size="80" description="暂无征信负债信息" />
|
||||
</template>
|
||||
<el-table-column label="负债大类" prop="debtMainType" min-width="120" />
|
||||
<el-table-column label="负债小类" prop="debtSubType" min-width="120" />
|
||||
<el-table-column label="债权人类型" prop="creditorType" min-width="120" />
|
||||
<el-table-column label="负债名称" prop="debtName" min-width="180" />
|
||||
<el-table-column label="负债本金余额" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
{{ formatAmount(scope.row.principalBalance) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="负债总额" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
{{ formatAmount(scope.row.debtTotalAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="负债状态" prop="debtStatus" min-width="120" />
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { parseTime } from "@/utils/ruoyi";
|
||||
|
||||
export default {
|
||||
name: "CreditInfoDetail",
|
||||
props: {
|
||||
detail: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
queryDate: undefined,
|
||||
debtCount: 0,
|
||||
debtTotalAmount: 0,
|
||||
negativeInfo: {},
|
||||
debts: [],
|
||||
}),
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatQueryDate(value) {
|
||||
if (!value) {
|
||||
return "-";
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
const matched = value.match(/^(\d{4}-\d{2}-\d{2})/);
|
||||
if (matched) {
|
||||
return matched[1];
|
||||
}
|
||||
}
|
||||
return parseTime(value, "{y}-{m}-{d}") || "-";
|
||||
},
|
||||
formatAmount(value) {
|
||||
const amount = Number(value || 0);
|
||||
if (!Number.isFinite(amount)) {
|
||||
return "0";
|
||||
}
|
||||
return amount.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.credit-info-detail {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-title:not(:first-child) {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.detail-summary {
|
||||
margin-bottom: 16px;
|
||||
line-height: 32px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
function sumDebtTotalAmount(debts) {
|
||||
if (!Array.isArray(debts)) {
|
||||
return 0;
|
||||
}
|
||||
return debts.reduce((total, item) => total + Number(item.debtTotalAmount || 0), 0);
|
||||
}
|
||||
|
||||
export function normalizeCreditDetail(data = {}, row = {}) {
|
||||
const negativeInfo = data.negativeInfo || {};
|
||||
const debts = Array.isArray(data.debtList) ? data.debtList : [];
|
||||
return {
|
||||
personId: data.personId || row.idCard || "",
|
||||
personName: data.personName || row.name || "",
|
||||
idCard: data.idCard || data.personId || row.idCard || "",
|
||||
queryDate: data.queryDate || negativeInfo.queryDate,
|
||||
debtCount: debts.length,
|
||||
debtTotalAmount: sumDebtTotalAmount(debts),
|
||||
negativeInfo,
|
||||
debts,
|
||||
};
|
||||
}
|
||||
|
||||
export function createEmptyCreditDetail() {
|
||||
return normalizeCreditDetail();
|
||||
}
|
||||
@@ -122,35 +122,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="征信详情" :visible.sync="detailDialogVisible" width="960px" append-to-body>
|
||||
<div class="section-title">征信摘要</div>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">征信查询日期:{{ formatQueryDate(detailForm.queryDate) }}</el-col>
|
||||
<el-col :span="8">负债笔数:{{ detailForm.debtCount || 0 }}</el-col>
|
||||
<el-col :span="8">负债总额:{{ detailForm.debtTotalAmount || 0 }}</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="section-title">负面信息</div>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">民事案件笔数:{{ detailForm.civilCnt || 0 }}</el-col>
|
||||
<el-col :span="8">强制执行笔数:{{ detailForm.enforceCnt || 0 }}</el-col>
|
||||
<el-col :span="8">行政处罚笔数:{{ detailForm.admCnt || 0 }}</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16" class="detail-summary">
|
||||
<el-col :span="8">民事案件金额:{{ detailForm.negativeInfo.civilLmt || 0 }}</el-col>
|
||||
<el-col :span="8">强制执行金额:{{ detailForm.negativeInfo.enforceLmt || 0 }}</el-col>
|
||||
<el-col :span="8">行政处罚金额:{{ detailForm.negativeInfo.admLmt || 0 }}</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="section-title">负债信息</div>
|
||||
<el-table :data="detailForm.debts || []" size="mini">
|
||||
<el-table-column label="负债大类" prop="debtMainType" min-width="120" />
|
||||
<el-table-column label="负债小类" prop="debtSubType" min-width="120" />
|
||||
<el-table-column label="债权人类型" prop="creditorType" min-width="120" />
|
||||
<el-table-column label="负债名称" prop="debtName" min-width="180" />
|
||||
<el-table-column label="负债本金余额" prop="principalBalance" min-width="120" />
|
||||
<el-table-column label="负债总额" prop="debtTotalAmount" min-width="120" />
|
||||
<el-table-column label="负债状态" prop="debtStatus" min-width="120" />
|
||||
</el-table>
|
||||
<credit-info-detail :detail="detailForm" />
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailDialogVisible = false">关 闭</el-button>
|
||||
@@ -166,9 +138,14 @@ import {
|
||||
listCreditInfo,
|
||||
uploadCreditHtml,
|
||||
} from "@/api/ccdiCreditInfo";
|
||||
import CreditInfoDetail from "./components/CreditInfoDetail.vue";
|
||||
import { createEmptyCreditDetail, normalizeCreditDetail } from "./components/creditDetailViewModel.js";
|
||||
|
||||
export default {
|
||||
name: "CcdiCreditInfo",
|
||||
components: {
|
||||
CreditInfoDetail,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
@@ -185,16 +162,7 @@ export default {
|
||||
},
|
||||
failureList: [],
|
||||
detailDialogVisible: false,
|
||||
detailForm: {
|
||||
queryDate: undefined,
|
||||
debtCount: 0,
|
||||
debtTotalAmount: 0,
|
||||
civilCnt: 0,
|
||||
enforceCnt: 0,
|
||||
admCnt: 0,
|
||||
negativeInfo: {},
|
||||
debts: [],
|
||||
},
|
||||
detailForm: createEmptyCreditDetail(),
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
@@ -289,19 +257,7 @@ export default {
|
||||
handleDetail(row) {
|
||||
return getCreditInfoDetail(row.idCard).then((response) => {
|
||||
const data = response.data || {};
|
||||
const negativeInfo = data.negativeInfo || {};
|
||||
this.detailForm = {
|
||||
personId: data.personId || row.idCard,
|
||||
personName: data.personName || row.name,
|
||||
queryDate: data.queryDate || negativeInfo.queryDate || row.queryDate,
|
||||
debtCount: row.debtCount || (data.debtList || []).length,
|
||||
debtTotalAmount: row.debtTotalAmount || 0,
|
||||
civilCnt: negativeInfo.civilCnt || row.civilCnt || 0,
|
||||
enforceCnt: negativeInfo.enforceCnt || row.enforceCnt || 0,
|
||||
admCnt: negativeInfo.admCnt || row.admCnt || 0,
|
||||
negativeInfo,
|
||||
debts: data.debtList || [],
|
||||
};
|
||||
this.detailForm = normalizeCreditDetail(data, row);
|
||||
this.detailDialogVisible = true;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -54,10 +54,46 @@
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="资产分析" name="assetAnalysis">
|
||||
<project-analysis-placeholder-tab :tab-data="getTabData('assetAnalysis')" />
|
||||
<div class="project-analysis-tab-panel">
|
||||
<el-alert
|
||||
v-if="assetError"
|
||||
:closable="false"
|
||||
class="project-analysis-layout__alert"
|
||||
type="error"
|
||||
show-icon
|
||||
:title="assetError"
|
||||
>
|
||||
<template slot="default">
|
||||
<el-button type="text" size="mini" @click="fetchAssetDetailData">重试</el-button>
|
||||
</template>
|
||||
</el-alert>
|
||||
<family-asset-liability-detail
|
||||
v-else
|
||||
:detail="assetDetail"
|
||||
:loading="assetLoading"
|
||||
/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="征信摘要" name="creditSummary">
|
||||
<project-analysis-placeholder-tab :tab-data="getTabData('creditSummary')" />
|
||||
<el-tab-pane label="征信详情" name="creditDetail">
|
||||
<div class="project-analysis-tab-panel">
|
||||
<el-alert
|
||||
v-if="creditError"
|
||||
:closable="false"
|
||||
class="project-analysis-layout__alert"
|
||||
type="error"
|
||||
show-icon
|
||||
:title="creditError"
|
||||
>
|
||||
<template slot="default">
|
||||
<el-button type="text" size="mini" @click="fetchCreditDetailData">重试</el-button>
|
||||
</template>
|
||||
</el-alert>
|
||||
<credit-info-detail
|
||||
v-else
|
||||
:detail="creditDetail"
|
||||
:loading="creditLoading"
|
||||
/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="关系图谱" name="relationshipGraph">
|
||||
<project-analysis-fund-flow-tab
|
||||
@@ -87,19 +123,24 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCreditInfoDetail } from "@/api/ccdiCreditInfo";
|
||||
import { getFamilyAssetLiabilityDetail } from "@/api/ccdi/projectSpecialCheck";
|
||||
import { getOverviewPersonAnalysisDetail } from "@/api/ccdi/projectOverview";
|
||||
import CreditInfoDetail from "@/views/ccdiCreditInfo/components/CreditInfoDetail.vue";
|
||||
import { createEmptyCreditDetail, normalizeCreditDetail } from "@/views/ccdiCreditInfo/components/creditDetailViewModel.js";
|
||||
import FamilyAssetLiabilityDetail from "./FamilyAssetLiabilityDetail";
|
||||
import ProjectAnalysisAbnormalTab from "./ProjectAnalysisAbnormalTab";
|
||||
import ProjectAnalysisFundFlowTab from "./ProjectAnalysisFundFlowTab";
|
||||
import ProjectAnalysisPlaceholderTab from "./ProjectAnalysisPlaceholderTab";
|
||||
import ProjectAnalysisSidebar from "./ProjectAnalysisSidebar";
|
||||
import { buildProjectAnalysisDialogData } from "./preliminaryCheck.mock";
|
||||
|
||||
export default {
|
||||
name: "ProjectAnalysisDialog",
|
||||
components: {
|
||||
CreditInfoDetail,
|
||||
FamilyAssetLiabilityDetail,
|
||||
ProjectAnalysisAbnormalTab,
|
||||
ProjectAnalysisFundFlowTab,
|
||||
ProjectAnalysisPlaceholderTab,
|
||||
ProjectAnalysisSidebar,
|
||||
},
|
||||
props: {
|
||||
@@ -137,6 +178,14 @@ export default {
|
||||
detailLoading: false,
|
||||
detailError: "",
|
||||
detailData: null,
|
||||
assetLoading: false,
|
||||
assetError: "",
|
||||
assetDetail: null,
|
||||
assetLoaded: false,
|
||||
creditLoading: false,
|
||||
creditError: "",
|
||||
creditDetail: createEmptyCreditDetail(),
|
||||
creditLoaded: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -175,6 +224,14 @@ export default {
|
||||
this.fetchDetailData();
|
||||
}
|
||||
},
|
||||
projectId() {
|
||||
this.resetAssetDetailState();
|
||||
this.resetCreditDetailState();
|
||||
},
|
||||
person() {
|
||||
this.resetAssetDetailState();
|
||||
this.resetCreditDetailState();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resetDialogState() {
|
||||
@@ -182,6 +239,20 @@ export default {
|
||||
this.detailLoading = false;
|
||||
this.detailError = "";
|
||||
this.detailData = null;
|
||||
this.resetAssetDetailState();
|
||||
this.resetCreditDetailState();
|
||||
},
|
||||
resetAssetDetailState() {
|
||||
this.assetLoading = false;
|
||||
this.assetError = "";
|
||||
this.assetDetail = null;
|
||||
this.assetLoaded = false;
|
||||
},
|
||||
resetCreditDetailState() {
|
||||
this.creditLoading = false;
|
||||
this.creditError = "";
|
||||
this.creditDetail = createEmptyCreditDetail();
|
||||
this.creditLoaded = false;
|
||||
},
|
||||
resolveStaffIdCard() {
|
||||
return (this.modelSummary && this.modelSummary.staffIdCard)
|
||||
@@ -212,6 +283,55 @@ export default {
|
||||
handleRetryDetail() {
|
||||
this.fetchDetailData();
|
||||
},
|
||||
async fetchAssetDetailData() {
|
||||
if (this.assetLoaded || this.assetLoading) {
|
||||
return;
|
||||
}
|
||||
const staffIdCard = this.resolveStaffIdCard();
|
||||
if (!this.projectId || !staffIdCard) {
|
||||
this.assetError = "缺少项目或人员身份证号,无法加载资产详情";
|
||||
return;
|
||||
}
|
||||
this.assetLoading = true;
|
||||
this.assetError = "";
|
||||
try {
|
||||
const response = await getFamilyAssetLiabilityDetail(this.projectId, staffIdCard);
|
||||
this.assetDetail = (response && response.data) || {};
|
||||
this.assetLoaded = true;
|
||||
} catch (error) {
|
||||
this.assetDetail = null;
|
||||
this.assetLoaded = false;
|
||||
this.assetError = "资产详情加载失败,请稍后重试";
|
||||
console.error("加载资产详情失败", error);
|
||||
} finally {
|
||||
this.assetLoading = false;
|
||||
}
|
||||
},
|
||||
async fetchCreditDetailData() {
|
||||
if (this.creditLoaded || this.creditLoading) {
|
||||
return;
|
||||
}
|
||||
const staffIdCard = this.resolveStaffIdCard();
|
||||
if (!staffIdCard) {
|
||||
this.creditError = "缺少人员身份证号,无法加载征信详情";
|
||||
return;
|
||||
}
|
||||
this.creditLoading = true;
|
||||
this.creditError = "";
|
||||
try {
|
||||
const response = await getCreditInfoDetail(staffIdCard);
|
||||
const data = (response && response.data) || {};
|
||||
this.creditDetail = normalizeCreditDetail(data);
|
||||
this.creditLoaded = true;
|
||||
} catch (error) {
|
||||
this.creditDetail = createEmptyCreditDetail();
|
||||
this.creditLoaded = false;
|
||||
this.creditError = "征信详情加载失败,请稍后重试";
|
||||
console.error("加载征信详情失败", error);
|
||||
} finally {
|
||||
this.creditLoading = false;
|
||||
}
|
||||
},
|
||||
getTabData(tabKey) {
|
||||
return (
|
||||
this.dialogData.tabs.find((item) => item.key === tabKey) || {
|
||||
@@ -225,6 +345,12 @@ export default {
|
||||
this.$emit("close");
|
||||
},
|
||||
handleTabChange() {
|
||||
if (this.activeTab === "assetAnalysis") {
|
||||
this.fetchAssetDetailData();
|
||||
}
|
||||
if (this.activeTab === "creditDetail") {
|
||||
this.fetchCreditDetailData();
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const tabRef = this.activeTab === "relationshipGraph"
|
||||
? this.$refs.relationshipGraphTab
|
||||
|
||||
@@ -193,12 +193,12 @@ export const projectAnalysisTabs = [
|
||||
{
|
||||
key: "assetAnalysis",
|
||||
label: "资产分析",
|
||||
description: "静态承载资产分析页签内容,本轮不接入新接口。",
|
||||
description: "展示员工家庭资产负债专项核查资产详情。",
|
||||
},
|
||||
{
|
||||
key: "creditSummary",
|
||||
label: "征信摘要",
|
||||
description: "静态承载征信摘要页签内容,本轮不接入新接口。",
|
||||
key: "creditDetail",
|
||||
label: "征信详情",
|
||||
description: "展示征信信息维护中的征信详情。",
|
||||
},
|
||||
{
|
||||
key: "relationshipGraph",
|
||||
|
||||
@@ -15,6 +15,7 @@ const source = fs.readFileSync(apiPath, "utf8");
|
||||
"/ccdi/creditInfo/upload",
|
||||
"/ccdi/creditInfo/list",
|
||||
"/ccdi/creditInfo/",
|
||||
"encodeURIComponent(personId)",
|
||||
].forEach((token) => {
|
||||
assert(source.includes(token), `征信维护 API 缺少关键契约: ${token}`);
|
||||
});
|
||||
|
||||
@@ -6,16 +6,41 @@ const componentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiCreditInfo/index.vue"
|
||||
);
|
||||
const detailComponentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiCreditInfo/components/CreditInfoDetail.vue"
|
||||
);
|
||||
const helperPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiCreditInfo/components/creditDetailViewModel.js"
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
assert(fs.existsSync(detailComponentPath), "征信详情展示组件未抽取");
|
||||
const detailSource = fs.readFileSync(detailComponentPath, "utf8");
|
||||
const helperSource = fs.readFileSync(helperPath, "utf8");
|
||||
|
||||
[
|
||||
"formatQueryDate(value)",
|
||||
"const matched = value.match(/^(",
|
||||
'this.parseTime(value, "{y}-{m}-{d}")',
|
||||
"{{ formatQueryDate(scope.row.queryDate) }}",
|
||||
"{{ formatQueryDate(detailForm.queryDate) }}",
|
||||
"normalizeCreditDetail(data, row)",
|
||||
].forEach((token) => {
|
||||
assert(source.includes(token), `征信时间展示缺少关键实现: ${token}`);
|
||||
});
|
||||
|
||||
[
|
||||
"formatQueryDate(value)",
|
||||
"const matched = value.match(/^(",
|
||||
'parseTime(value, "{y}-{m}-{d}")',
|
||||
"{{ formatQueryDate(detail.queryDate) }}",
|
||||
].forEach((token) => {
|
||||
assert(detailSource.includes(token), `征信详情组件时间展示缺少关键实现: ${token}`);
|
||||
});
|
||||
|
||||
[
|
||||
"queryDate: data.queryDate || negativeInfo.queryDate",
|
||||
"debtCount: debts.length",
|
||||
"debtTotalAmount: sumDebtTotalAmount(debts)",
|
||||
].forEach((token) => {
|
||||
assert(helperSource.includes(token), `征信详情标准化缺少关键实现: ${token}`);
|
||||
});
|
||||
|
||||
console.log("credit-info-date-display test passed");
|
||||
|
||||
@@ -6,16 +6,21 @@ const componentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiCreditInfo/index.vue"
|
||||
);
|
||||
const detailComponentPath = path.resolve(
|
||||
__dirname,
|
||||
"../../src/views/ccdiCreditInfo/components/CreditInfoDetail.vue"
|
||||
);
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
assert(fs.existsSync(detailComponentPath), "征信详情展示组件未抽取");
|
||||
const detailSource = fs.readFileSync(detailComponentPath, "utf8");
|
||||
|
||||
[
|
||||
"CreditInfoDetail",
|
||||
"<credit-info-detail",
|
||||
"detailDialogVisible",
|
||||
"detailForm",
|
||||
"负债信息",
|
||||
"负面信息",
|
||||
"civilCnt",
|
||||
"enforceCnt",
|
||||
"admCnt",
|
||||
"normalizeCreditDetail",
|
||||
"getCreditInfoDetail(row.idCard)",
|
||||
"handleDetail",
|
||||
"handleDelete",
|
||||
"deleteCreditInfo",
|
||||
@@ -24,4 +29,19 @@ const source = fs.readFileSync(componentPath, "utf8");
|
||||
assert(source.includes(token), `详情或删除交互缺少关键结构: ${token}`);
|
||||
});
|
||||
|
||||
[
|
||||
'name: "CreditInfoDetail"',
|
||||
"征信摘要",
|
||||
"负债信息",
|
||||
"负面信息",
|
||||
"detail.debtCount",
|
||||
"detail.debtTotalAmount",
|
||||
"detail.negativeInfo.civilCnt",
|
||||
"detail.negativeInfo.enforceCnt",
|
||||
"detail.negativeInfo.admCnt",
|
||||
"detail.debts || []",
|
||||
].forEach((token) => {
|
||||
assert(detailSource.includes(token), `征信详情组件缺少关键结构: ${token}`);
|
||||
});
|
||||
|
||||
console.log("credit-info-detail-ui test passed");
|
||||
|
||||
@@ -12,7 +12,8 @@ assert(fs.existsSync(componentPath), "未找到征信维护页面 index.vue");
|
||||
const source = fs.readFileSync(componentPath, "utf8");
|
||||
|
||||
[
|
||||
"征信维护",
|
||||
'name: "CcdiCreditInfo"',
|
||||
"app-container",
|
||||
"姓名",
|
||||
"身份证号",
|
||||
"批量上传征信HTML",
|
||||
|
||||
@@ -57,7 +57,7 @@ assert(!dialog.includes("project-analysis-layout__main-scroll"), "主区不应
|
||||
"summary",
|
||||
"extraFields",
|
||||
"grid-template-columns: minmax(0, 1fr)",
|
||||
"border-radius: 6px",
|
||||
"align-items: flex-start",
|
||||
].forEach((token) => assert(abnormalTab.includes(token), token));
|
||||
|
||||
assert(!abnormalTab.includes("border-radius: 12px"), "异常明细内部不应继续使用独立 12px 圆角");
|
||||
|
||||
@@ -27,26 +27,33 @@ const mockSource = fs.readFileSync(
|
||||
'name="abnormalDetail"',
|
||||
'label="异常明细"',
|
||||
'label="资产分析"',
|
||||
'label="征信摘要"',
|
||||
'label="征信详情"',
|
||||
'label="关系图谱"',
|
||||
'label="资金流向"',
|
||||
"<family-asset-liability-detail",
|
||||
"<credit-info-detail",
|
||||
"fetchAssetDetailData()",
|
||||
"fetchCreditDetailData()",
|
||||
"getFamilyAssetLiabilityDetail",
|
||||
"getCreditInfoDetail",
|
||||
"fetchDetailData()",
|
||||
"detailLoading",
|
||||
"detailError",
|
||||
"handleRetryDetail()",
|
||||
"background: #f5f7fb",
|
||||
"border: 1px solid #dbe4ef",
|
||||
"border-radius: 8px",
|
||||
"assetLoaded",
|
||||
"creditLoaded",
|
||||
"缺少项目或人员身份证号,无法加载资产详情",
|
||||
"缺少人员身份证号,无法加载征信详情",
|
||||
].forEach((token) => assert(dialog.includes(token), token));
|
||||
|
||||
[
|
||||
'width="92%"',
|
||||
'width="88%"',
|
||||
'top="2vh"',
|
||||
"project-analysis-header__main",
|
||||
"project-analysis-header__meta",
|
||||
"project-analysis-layout__main",
|
||||
"flex: 0 0 320px",
|
||||
"border-radius: 6px",
|
||||
"flex: 0 0 34%",
|
||||
"border-radius: 2px",
|
||||
].forEach((token) => assert(dialog.includes(token), token));
|
||||
|
||||
[
|
||||
@@ -65,7 +72,14 @@ const mockSource = fs.readFileSync(
|
||||
"projectAnalysisTabs",
|
||||
'key: "abnormalDetail"',
|
||||
'key: "assetAnalysis"',
|
||||
'key: "creditSummary"',
|
||||
'key: "creditDetail"',
|
||||
'label: "征信详情"',
|
||||
'key: "relationshipGraph"',
|
||||
'key: "fundFlow"',
|
||||
].forEach((token) => assert(mockSource.includes(token), token));
|
||||
|
||||
[
|
||||
'label="征信摘要"',
|
||||
'key: "creditSummary"',
|
||||
"静态承载征信摘要页签内容,本轮不接入新接口。",
|
||||
].forEach((token) => assert(!dialog.includes(token) && !mockSource.includes(token), token));
|
||||
|
||||
@@ -35,9 +35,8 @@ const entry = fs.readFileSync(
|
||||
"formatRiskTag",
|
||||
"tag.ruleName",
|
||||
"flex-wrap: wrap",
|
||||
"align-items: flex-start",
|
||||
"border: 1px solid #dbe4ef",
|
||||
"border-radius: 6px",
|
||||
"border: 1px solid #dde3ec",
|
||||
"border-radius: 3px",
|
||||
].forEach((token) => assert(sidebar.includes(token), token));
|
||||
|
||||
assert(!sidebar.includes("当前命中模型"), "命中模型摘要应移除当前命中模型字段");
|
||||
@@ -45,7 +44,6 @@ assert(!sidebar.includes("排查记录摘要"), "侧栏应移除排查记录摘
|
||||
assert(!sidebar.includes("position: sticky"), "左侧整卡不应保持固定");
|
||||
assert(!sidebar.includes("border-radius: 20px"), "侧栏不应继续保留旧大圆角卡片样式");
|
||||
assert(!sidebar.includes("background: rgba(255, 255, 255, 0.9)"), "侧栏不应继续保留旧半透明卡片底色");
|
||||
assert(!sidebar.includes("justify-content: space-between"), "不应继续以表单式左右对齐作为主体布局");
|
||||
|
||||
assert(!sidebar.includes("关系人画像"), "侧栏不应扩展到额外区块");
|
||||
assert(!sidebar.includes("资产分布"), "侧栏不应扩展到额外区块");
|
||||
|
||||
Reference in New Issue
Block a user