实现结果总览详情资产和征信页签

This commit is contained in:
wkc
2026-06-02 17:17:49 +08:00
parent 457e6c1d27
commit d45e9410ef
15 changed files with 433 additions and 85 deletions

View File

@@ -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'
})
}

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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;
});
},

View File

@@ -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

View File

@@ -193,12 +193,12 @@ export const projectAnalysisTabs = [
{
key: "assetAnalysis",
label: "资产分析",
description: "静态承载资产分析页签内容,本轮不接入新接口。",
description: "展示员工家庭资产负债专项核查资产详情。",
},
{
key: "creditSummary",
label: "征信摘要",
description: "静态承载征信摘要页签内容,本轮不接入新接口。",
key: "creditDetail",
label: "征信详情",
description: "展示征信信息维护中的征信详情。",
},
{
key: "relationshipGraph",