This commit is contained in:
2026-07-08 21:29:20 +08:00
parent a961ef2c3a
commit 2cd82d0572
17 changed files with 2028 additions and 769 deletions

View File

@@ -170,6 +170,10 @@ const featureMap = {
name: "关联风险监督",
component: defineAsyncComponent(() => import("@/ui/DWBG6A2C/components/RiskSupervisionSection.vue")),
},
DWBG6A2C_CourtRiskInfo: {
name: "个人司法信息",
component: defineAsyncComponent(() => import("@/ui/DWBG6A2C/components/CourtRiskInfoSection.vue")),
},
// 司法涉诉
FLXG0V4B: {
@@ -393,6 +397,7 @@ const featureRiskLevels = {
'DWBG6A2C_CreditDetail': 5,
'DWBG6A2C_RentalBehavior': 5,
'DWBG6A2C_RiskSupervision': 8,
'DWBG6A2C_CourtRiskInfo': 14,
// 人企关系加强版子模块
'CQYGL3F8E_Investment': 4,

View File

@@ -1,24 +1,70 @@
<template>
<div class="bg-white rounded-xl shadow-sm p-6">
<LTitle title="法院风险信息" type="red" />
<LTitle title="个人司法信息" type="red" />
<div class="mt-4">
<!-- 法院风险概览 -->
<!-- 案件概览 -->
<div v-if="caseOverview" class="bg-gradient-to-r from-[#F9ECEC] to-[#FCE8E8] rounded-lg p-4 mb-4">
<h3 class="text-lg font-semibold text-[#333333] mb-3 flex items-center">
<span class="w-2 h-2 bg-[#EB3C3C] rounded-full mr-2"></span>
案件概览
</h3>
<div class="grid grid-cols-2 gap-3 text-sm">
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">被告总案件数</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.beigaoTotalCasesCounts ?? 0 }}</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">被告未结案数</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.beigaoTotalWeiCaseCounts ?? 0 }}</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">被告涉案金额</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.beigaoTotalCaseAmounts ?? 0 }}</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">被执行案件数</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.executionCaseCounts ?? 0 }}</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">失信命中</span>
<span :class="caseOverview.disinCaseCounts ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ caseOverview.disinCaseCounts ? '命中' : '未命中' }}
</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">限高命中</span>
<span :class="caseOverview.limitCaseCounts ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ caseOverview.limitCaseCounts ? '命中' : '未命中' }}
</span>
</div>
<div class="flex justify-between py-1 border-b border-red-100">
<span class="text-[#666666]">关联企业</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.affiliateCompany ?? 0 }}</span>
</div>
<div class="flex justify-between py-1">
<span class="text-[#666666]">最近案件年份</span>
<span class="font-semibold text-[#333333]">{{ caseOverview.leastCaseTime || '-' }}</span>
</div>
</div>
</div>
<!-- 概览统计 -->
<div class="bg-gradient-to-r from-[#F9ECEC] to-[#FCE8E8] rounded-lg p-4 mb-4">
<h3 class="text-lg font-semibold text-[#333333] mb-3 flex items-center">
<span class="w-2 h-2 bg-[#EB3C3C] rounded-full mr-2"></span>
风险概览
法风险概览
</h3>
<div class="grid grid-cols-2 gap-4">
<div class="text-center">
<div class="text-2xl font-bold" :class="courtRiskInfos?.length > 0 ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ courtRiskInfos?.length || 0 }}
<div class="text-2xl font-bold" :class="hasJudicialContent ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ totalListCaseCount }}
</div>
<div class="text-sm text-[#666666]">法院案件数</div>
<div class="text-sm text-[#666666]">案件明细</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold" :class="courtRiskInfos?.length > 0 ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ courtRiskInfos?.length > 0 ? '有风险' : '无风险' }}
<div class="text-2xl font-bold" :class="hasJudicialContent ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ hasJudicialContent ? '有风险' : '无风险' }}
</div>
<div class="text-sm text-[#666666]">风险状态</div>
</div>
@@ -26,150 +72,206 @@
</div>
<!-- 案件类型统计 -->
<div v-if="courtRiskInfos && courtRiskInfos.length > 0" class="mb-4">
<div v-if="hasJudicialContent" class="mb-4">
<div class="bg-white rounded-xl border border-[#DDDDDD] p-4">
<div class="flex items-center justify-between mb-3">
<div class="flex items-center">
<div class="w-8 h-8 flex items-center justify-center mr-2">
<img src="@/assets/images/report/ajlxfb.png" alt="案件类型分布" class="w-8 h-8 object-contain" />
</div>
<span class="font-bold text-[#333333]">案件类型分布</span>
<div class="flex items-center mb-3">
<div class="w-8 h-8 flex items-center justify-center mr-2">
<img src="@/assets/images/report/ajlxfb.png" alt="案件类型分布" class="w-8 h-8 object-contain" />
</div>
<span class="font-bold text-[#333333]">案件类型分布</span>
</div>
<!-- 案件类型统计 -->
<div class="grid grid-cols-3 md:grid-cols-6 gap-2">
<div v-for="(typeInfo, type) in caseTypeStats" :key="type" class="text-center p-2 rounded-lg border"
:class="typeInfo.count > 0 ? 'bg-[#F9ECEC] border border-[#F0CACA]' : 'bg-[#ECF9EF] border border-[#CAECD3]'">
<div class="grid grid-cols-3 md:grid-cols-5 gap-2">
<div
v-for="group in JUDICIAL_CASE_GROUPS"
:key="group.listKey"
class="text-center p-2 rounded-lg border"
:class="(caseTypeStats[group.name]?.count || 0) > 0
? 'bg-[#F9ECEC] border-[#F0CACA]'
: 'bg-[#ECF9EF] border-[#CAECD3]'"
>
<div class="flex justify-center mb-1">
<img :src="getCaseTypeIconPath(type)" alt="" class="w-8 h-8 object-contain" />
<img :src="getCaseTypeIconPath(group.name)" alt="" class="w-8 h-8 object-contain" />
</div>
<div class="text-base font-bold" :class="typeInfo.count > 0 ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ typeInfo.count }}
</div>
<div class="text-xs text-[#666666] leading-tight">{{ getCaseTypeShortName(type) }}</div>
<div class="text-xs mt-0.5" :class="typeInfo.count > 0 ? 'text-[#EB3C3C]' : 'text-green-600'">
{{ typeInfo.count > 0 ? '有风险' : '无风险' }}
<div
class="text-base font-bold"
:class="(caseTypeStats[group.name]?.count || 0) > 0 ? 'text-[#EB3C3C]' : 'text-green-600'"
>
{{ caseTypeStats[group.name]?.count || 0 }}
</div>
<div class="text-xs text-[#666666] leading-tight">{{ group.shortName }}</div>
</div>
</div>
</div>
</div>
<!-- 法院案件详情 -->
<div v-if="courtRiskInfos && courtRiskInfos.length > 0" class="space-y-4">
<!-- 按案件类型分组显示 -->
<!-- 案件详情 -->
<div v-if="hasJudicialContent" class="space-y-4">
<div v-for="(cases, caseType) in groupedCases" :key="caseType" class="case-section">
<div class="bg-white rounded-xl border border-[#DDDDDD] p-4">
<div class="flex items-center mb-3">
<div class="w-8 h-8 flex items-center justify-center mr-2">
<img :src="getCaseTypeIconPath(caseType)" alt="" class="w-8 h-8 object-contain" />
</div>
<span class="font-bold text-[#333333]">{{ getCaseTypeName(caseType) }}</span>
<span class="font-bold text-[#333333]">{{ caseType }}</span>
<span class="ml-2 px-2 py-1 rounded-full text-xs font-medium" :class="getCaseTypeBadgeStyle(caseType)">
{{ cases.length }}
</span>
</div>
<van-collapse v-model="activeCases[caseType]" accordion>
<van-collapse-item v-for="(caseItem, index) in cases" :key="`${caseType}-${index}`"
:name="`${caseType}-${index}`" :class="getCaseItemClass(caseItem)">
<van-collapse-item
v-for="(caseItem, index) in cases"
:key="`${caseType}-${index}`"
:name="`${caseType}-${index}`"
:class="getCaseItemClass(caseItem)"
>
<template #title>
<div class="case-header">
<div class="case-number">{{ caseItem.caseNumber || '案号未知' }}</div>
<div class="case-status" :class="getCaseStatusClass(caseItem.caseStatus)">
{{ caseItem.caseStatus || '状态未知' }}
<div class="case-number">{{ getCaseTitle(caseItem) }}</div>
<div v-if="getCaseStatus(caseItem)" class="case-status" :class="getCaseStatusClass(getCaseStatus(caseItem))">
{{ getCaseStatus(caseItem) }}
</div>
</div>
</template>
<div class="case-details-content">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="detail-item">
<span class="label">案件类型</span>
<span class="value">{{ caseItem.caseType || '-' }}</span>
<!-- 标准司法案件 -->
<template v-if="caseItem._kind === 'standard'">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="detail-item">
<span class="label">案号</span>
<span class="value">{{ caseItem.caseNumber || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">案件类型</span>
<span class="value">{{ caseItem.najlx || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">诉讼地位</span>
<span class="value">{{ caseItem.nssdw || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">案件进展</span>
<span class="value">{{ caseItem.caseStatus || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">经办法院</span>
<span class="value">{{ caseItem.njbfy || caseItem.zxfy || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">审理程序</span>
<span class="value">{{ caseItem.nslcx || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">立案时间</span>
<span class="value">{{ caseItem.dlarq || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">结案时间</span>
<span class="value">{{ caseItem.djarq || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">结案方式</span>
<span class="value">{{ caseItem.njafs || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">胜诉估计</span>
<span class="value">{{ caseItem.npjVictory || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">起诉标的</span>
<span class="value">{{ caseItem.nqsbdje || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">结案标的</span>
<span class="value">{{ caseItem.njabdje || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">申请执行标的</span>
<span class="value">{{ caseItem.nsqzxbdje || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">实际到位金额</span>
<span class="value">{{ caseItem.nsjdwje || '-' }}</span>
</div>
</div>
<div class="detail-item">
<span class="label">审理法院</span>
<span class="value">{{ caseItem.court || '-' }}</span>
<div v-if="caseItem.nlaayTree" class="detail-item mt-2">
<span class="label">案由</span>
<span class="value">{{ caseItem.nlaayTree }}</span>
</div>
<div class="detail-item">
<span class="label">诉讼地位</span>
<span class="value">{{ caseItem.litigantType || '-' }}</span>
<div v-if="caseItem.cdsrxx" class="mt-3">
<div class="text-sm text-[#666666] mb-1">当事人</div>
<div class="bg-gray-50 rounded-lg p-3 border text-sm text-gray-700">
{{ truncateText(caseItem.cdsrxx, 300) }}
</div>
</div>
<div class="detail-item">
<span class="label">立案时间</span>
<span class="value">{{ caseItem.filingTime || '-' }}</span>
<div v-if="caseItem.cgkwsPjjg" class="mt-3">
<div class="text-sm text-[#666666] mb-1">判决结果</div>
<div class="bg-gray-50 rounded-lg p-3 border text-sm text-gray-700 leading-relaxed">
{{ truncateText(caseItem.cgkwsPjjg, 400) }}
</div>
</div>
<div class="detail-item">
<span class="label">结案时间</span>
<span class="value">{{ caseItem.disposalTime || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">案件状态</span>
<span class="value" :class="getCaseStatusTextClass(caseItem.caseStatus)">
{{ caseItem.caseStatus || '-' }}
</span>
</div>
<div class="detail-item" v-if="caseItem.executionAmount">
<span class="label">执行金额</span>
<span class="value text-[#EB3C3C] font-bold">{{ caseItem.executionAmount }}</span>
</div>
<div class="detail-item" v-if="caseItem.repaidAmount">
<span class="label">已还款金额</span>
<span class="value text-green-600 font-bold">{{ caseItem.repaidAmount }}</span>
</div>
<div class="detail-item">
<span class="label">案由</span>
<span class="value">{{ caseItem.caseReason || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">结案方式</span>
<span class="value">{{ caseItem.disposalMethod || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">判决结果</span>
<span class="value">{{ caseItem.judgmentResult || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">案件分类</span>
<span class="value">{{ caseItem.type || '-' }}</span>
</div>
</div>
</template>
<!-- 匹配度信息 -->
<div v-if="caseItem.matchScore" class="mt-3 p-3 bg-[#EBF5FF] rounded-lg">
<div class="flex items-center justify-between">
<span class="text-sm text-[#666666]">身份匹配度</span>
<span class="text-sm font-bold text-[#2B79EE]">
{{ (caseItem.matchScore * 100).toFixed(1) }}%
</span>
<!-- 失信公告 -->
<template v-else-if="caseItem._kind === 'disin'">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="detail-item">
<span class="label">案号</span>
<span class="value">{{ caseItem.ah || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">执行法院</span>
<span class="value">{{ caseItem.zxfy || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">立案日期</span>
<span class="value">{{ caseItem.larq || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">发布日期</span>
<span class="value">{{ caseItem.fbrq || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">金额估计</span>
<span class="value">{{ caseItem.pjjeGj || '-' }}</span>
</div>
</div>
<div class="mt-2 w-full bg-gray-200 rounded-full h-2">
<div class="h-2 rounded-full transition-all duration-500"
:class="getMatchScoreBarStyle(caseItem.matchScore)"
:style="{ width: (caseItem.matchScore * 100) + '%' }"></div>
<div v-if="caseItem.yw" class="mt-3">
<div class="text-sm text-[#666666] mb-1">生效法律文书确定的义务</div>
<div class="bg-gray-50 rounded-lg p-3 border text-sm">{{ truncateText(caseItem.yw, 300) }}</div>
</div>
</div>
<div v-if="caseItem.lxqk" class="mt-3">
<div class="text-sm text-[#666666] mb-1">履行情况</div>
<div class="bg-gray-50 rounded-lg p-3 border text-sm">{{ caseItem.lxqk }}</div>
</div>
</template>
<!-- 内容摘要 -->
<div v-if="caseItem.contentSummary" class="mt-3">
<div class="text-sm text-[#666666] mb-2">案件摘要</div>
<div class="bg-gray-50 rounded-lg p-3 border">
<p class="text-sm text-gray-700 leading-relaxed">
{{ formatContentSummary(caseItem.contentSummary) }}
</p>
<!-- 限高公告 -->
<template v-else-if="caseItem._kind === 'limit'">
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="detail-item">
<span class="label">案号</span>
<span class="value">{{ caseItem.ah || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">执行法院</span>
<span class="value">{{ caseItem.zxfy || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">立案时间</span>
<span class="value">{{ caseItem.larq || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">发布时间</span>
<span class="value">{{ caseItem.fbrq || '-' }}</span>
</div>
<div v-if="caseItem.orglegalName" class="detail-item">
<span class="label">企业名称</span>
<span class="value">{{ caseItem.orglegalName }}</span>
</div>
</div>
</div>
<!-- 执行公告ID -->
<div v-if="caseItem.executionAnnouncementId" class="mt-3">
<div class="text-sm text-[#666666] mb-1">公告编号</div>
<div class="bg-gray-100 rounded p-2">
<span class="text-xs font-mono text-gray-700">
{{ caseItem.executionAnnouncementId }}
</span>
</div>
</div>
</template>
</div>
</van-collapse-item>
</van-collapse>
@@ -177,65 +279,59 @@
</div>
</div>
<!-- 高风险警告 -->
<div v-if="hasHighRiskCases" class="mt-4 p-4 bg-[#F9ECEC] border border-[#F0CACA] rounded-lg">
<div v-if="hasJudicialContent" class="mt-4 p-4 bg-[#F9ECEC] border border-[#F0CACA] rounded-lg">
<div class="flex items-start">
<div class="mr-3 mt-1 flex-shrink-0">
<img src="@/assets/images/report/gfx.png" alt="高风险" class="w-10 h-10 object-contain" />
</div>
<div>
<h4 class="font-semibold text-[#EB3C3C] mb-2">风险警告</h4>
<h4 class="font-semibold text-[#EB3C3C] mb-2">法风险警告</h4>
<p class="text-[#666666] text-sm">
检测到法院相关案件记录存在司法风险建议立即停止相关业务并进行详细核实
检测到司法相关记录建议结合案件类型与诉讼地位进行审慎评估
</p>
<div class="mt-2">
<span class="text-[#666666] font-medium">涉及案件类型</span>
<span class="text-[#EB3C3C]">{{ getCaseTypesList.join('、') }}</span>
<div v-if="activeCaseTypeNames.length" class="mt-2 text-sm">
<span class="text-[#666666] font-medium">涉及类型</span>
<span class="text-[#EB3C3C]">{{ activeCaseTypeNames.join('、') }}</span>
</div>
</div>
</div>
</div>
<!-- 无风险提示 -->
<div v-if="!courtRiskInfos || courtRiskInfos.length === 0"
class="mt-4 p-4 bg-[#ECF9EF] border border-[#CAECD3] rounded-lg">
<div
v-if="!hasJudicialContent"
class="mt-4 p-4 bg-[#ECF9EF] border border-[#CAECD3] rounded-lg"
>
<div class="flex items-start">
<div class="mr-3 mt-1">
<img src="@/assets/images/report/zq.png" alt="正常" class="w-8 h-8 object-contain" />
</div>
<div>
<h4 class="font-semibold text-green-600 mb-2">法院风险核验通过</h4>
<p class="text-green-600 text-sm">
未检测到法院相关案件记录司法风险较低
</p>
<h4 class="font-semibold text-green-600 mb-2">司法信息核验通过</h4>
<p class="text-green-600 text-sm">未检测到相关司法案件明细司法风险较低</p>
</div>
</div>
</div>
<!-- 案件类型说明 -->
<div class="mt-4 p-4 bg-gray-50 border border-[#DDDDDD] rounded-lg">
<h4 class="font-semibold text-[#333333] mb-2">案件类型说明</h4>
<div class="text-sm text-[#666666] space-y-1">
<div><strong>民事案件</strong>涉及财产合同等民事纠纷</div>
<div><strong>刑事案件</strong>涉及刑法规定的犯罪行为</div>
<div><strong>行政案件</strong>涉及行政管理相关纠纷</div>
<div><strong>执行案件</strong>强制执行相关案件</div>
<div><strong>非诉保全审查案件</strong>财产保全等非诉讼案件</div>
<div><strong>强制清算与破产案件</strong>企业清算破产相关案件</div>
</div>
</div>
</div>
</div>
<!-- 温馨提示 -->
<LRemark
content="法院风险信息展示申请人的司法风险情况,包括民事案件、执行案件失信记录和限高消费等。数据来源于全国法院执行信息公开网等权威司法数据库。失信和限高记录对个人信用影响极大,会限制高消费和金融服务。执行案件可能涉及财产冻结和强制执行。建议对有司法风险记录的申请进行重点审查。" />
content="个人司法信息来源于法院公开数据,包括民事、刑事、行政、执行案件失信、限高公告。字段与接口文档 judicialLeaseReport 结构一致。建议重点关注被告身份、未结案及被执行类记录。"
/>
</template>
<script setup>
import LTitle from '@/components/LTitle.vue'
import LRemark from '@/components/LRemark.vue'
import { ref, computed, onMounted, watch } from 'vue'
import { ref, computed, watch } from 'vue'
import {
JUDICIAL_CASE_GROUPS,
getJudicialLeaseReport,
hasJudicialLeaseContent,
getCaseTypeStatsFromReport,
getGroupedCasesFromReport,
getTotalCaseListCount,
truncateText,
} from '../utils/judicialLeaseReport.js'
const props = defineProps({
data: {
@@ -252,253 +348,102 @@ const props = defineProps({
},
notifyRiskStatus: {
type: Function,
default: () => { },
default: () => {},
},
})
// 从data中解构出需要的字段
const courtRiskInfos = computed(() => {
return props.data?.judiciaRiskInfos || []
})
const judicialReport = computed(() => getJudicialLeaseReport(props.data))
const caseOverview = computed(() => judicialReport.value?.caseOverviewInfo || null)
const hasJudicialContent = computed(() => hasJudicialLeaseContent(judicialReport.value))
const caseTypeStats = computed(() => getCaseTypeStatsFromReport(judicialReport.value))
const groupedCases = computed(() => getGroupedCasesFromReport(judicialReport.value))
const totalListCaseCount = computed(() => getTotalCaseListCount(judicialReport.value))
const activeCaseTypeNames = computed(() =>
Object.keys(groupedCases.value).filter((name) => groupedCases.value[name]?.length)
)
// 折叠面板状态
const activeCases = ref({})
// 是否有高风险案件
const hasHighRiskCases = computed(() => {
return courtRiskInfos.value && courtRiskInfos.value.length > 0
})
// 获取案件类型列表
const getCaseTypesList = computed(() => {
if (!courtRiskInfos.value) return []
const types = [...new Set(courtRiskInfos.value.map(item => inferCaseType(item)))]
return types.filter(type => type !== '未知类型')
})
// 根据案件信息推断真实案件类型
const inferCaseType = (caseItem) => {
// 如果type字段已经是标准的6种类型之一直接使用
const standardTypes = ['民事案件', '刑事案件', '行政案件', '执行案件', '非诉保全审查案件', '强制清算与破产案件']
if (standardTypes.includes(caseItem.type)) {
return caseItem.type
const getCaseTitle = (caseItem) => {
if (caseItem._kind === 'disin' || caseItem._kind === 'limit') {
return caseItem.ah || '案号未知'
}
// 根据caseType字段推断案件类型
const caseType = caseItem.caseType || ''
if (caseType.includes('刑事')) {
return '刑事案件'
} else if (caseType.includes('民事')) {
return '民事案件'
} else if (caseType.includes('行政')) {
return '行政案件'
} else if (caseType.includes('执行') || caseItem.type === '执行公告') {
return '执行案件'
} else if (caseType.includes('破产') || caseType.includes('清算')) {
return '强制清算与破产案件'
} else if (caseType.includes('保全') || caseItem.type === '非诉保全审查案件') {
return '非诉保全审查案件'
}
// 根据原始type字段的值进行映射
if (caseItem.type === '涉案公告' && caseType.includes('刑事')) {
return '刑事案件'
}
// 默认返回民事案件
return '民事案件'
return caseItem.caseNumber || '案号未知'
}
// 按案件类型分组
const groupedCases = computed(() => {
if (!courtRiskInfos.value) return {}
const getCaseStatus = (caseItem) => {
if (caseItem._kind === 'disin') return '失信公告'
if (caseItem._kind === 'limit') return '限高公告'
return caseItem.caseStatus || ''
}
const grouped = {}
courtRiskInfos.value.forEach(caseItem => {
const type = inferCaseType(caseItem)
if (!grouped[type]) {
grouped[type] = []
}
grouped[type].push(caseItem)
})
return grouped
})
// 案件类型统计
const caseTypeStats = computed(() => {
const stats = {}
const allTypes = ['民事案件', '刑事案件', '行政案件', '执行案件', '非诉保全审查案件', '强制清算与破产案件']
// 初始化所有类型
allTypes.forEach(type => {
stats[type] = { count: 0 }
})
// 统计实际案件
if (courtRiskInfos.value) {
courtRiskInfos.value.forEach(caseItem => {
const type = inferCaseType(caseItem)
if (stats[type]) {
stats[type].count++
} else {
stats[type] = { count: 1 }
}
})
}
return stats
})
// 获取案件类型图标路径
const getCaseTypeIconPath = (type) => {
const iconMap = {
'民事案件': () => new URL('@/assets/images/report/ms.png', import.meta.url).href,
'刑事案件': () => new URL('@/assets/images/report/xs.png', import.meta.url).href,
'行政案件': () => new URL('@/assets/images/report/xz.png', import.meta.url).href,
'执行案件': () => new URL('@/assets/images/report/zxaj.png', import.meta.url).href,
'非诉保全审查案件': () => new URL('@/assets/images/report/fsbq.png', import.meta.url).href,
'强制清算与破产案件': () => new URL('@/assets/images/report/qspc.png', import.meta.url).href,
'default': () => new URL('@/assets/images/report/zxaj.png', import.meta.url).href
民事案件: () => new URL('@/assets/images/report/ms.png', import.meta.url).href,
刑事案件: () => new URL('@/assets/images/report/xs.png', import.meta.url).href,
行政案件: () => new URL('@/assets/images/report/xz.png', import.meta.url).href,
执行案件: () => new URL('@/assets/images/report/zxaj.png', import.meta.url).href,
非诉保全审查案件: () => new URL('@/assets/images/report/fsbq.png', import.meta.url).href,
强制清算与破产案件: () => new URL('@/assets/images/report/qspc.png', import.meta.url).href,
管辖案件: () => new URL('@/assets/images/report/zxaj.png', import.meta.url).href,
赔偿案件: () => new URL('@/assets/images/report/ms.png', import.meta.url).href,
失信公告: () => new URL('@/assets/images/report/gfx.png', import.meta.url).href,
限高公告: () => new URL('@/assets/images/report/gfx.png', import.meta.url).href,
}
const getIcon = iconMap[type] || iconMap.default
const getIcon = iconMap[type] || (() => new URL('@/assets/images/report/zxaj.png', import.meta.url).href)
return getIcon()
}
// 获取案件类型名称
const getCaseTypeName = (type) => {
const nameMap = {
'民事案件': '民事案件',
'刑事案件': '刑事案件',
'行政案件': '行政案件',
'执行案件': '执行案件',
'非诉保全审查案件': '非诉保全审查案件',
'强制清算与破产案件': '强制清算与破产案件'
}
return nameMap[type] || '未知类型'
}
// 获取案件类型简短名称(用于紧凑显示)
const getCaseTypeShortName = (type) => {
const shortNameMap = {
'民事案件': '民事',
'刑事案件': '刑事',
'行政案件': '行政',
'执行案件': '执行',
'非诉保全审查案件': '非诉保全',
'强制清算与破产案件': '清算破产'
}
return shortNameMap[type] || '未知'
}
// 获取案件类型头部样式
const getCaseTypeHeaderStyle = (caseType) => {
const styleMap = {
'民事案件': 'bg-[#2B79EE]',
'刑事案件': 'bg-[#EB3C3C]',
'行政案件': 'bg-[#2B79EE]',
'执行案件': 'bg-[#D6943E]',
'非诉保全审查案件': 'bg-green-500',
'强制清算与破产案件': 'bg-[#666666]'
}
return styleMap[caseType] || 'bg-[#666666]'
}
// 获取案件类型标签样式
const getCaseTypeBadgeStyle = (caseType) => {
const styleMap = {
'民事案件': 'bg-[#2B79EE1A] text-[#2B79EE]',
'刑事案件': 'bg-[#F9ECEC] text-[#EB3C3C]',
'行政案件': 'bg-[#EBF5FF] text-[#2B79EE]',
'执行案件': 'bg-[#FFF8E1] text-[#D6943E]',
'非诉保全审查案件': 'bg-[#ECF9EF] text-green-600',
'强制清算与破产案件': 'bg-gray-100 text-[#666666]'
民事案件: 'bg-[#2B79EE1A] text-[#2B79EE]',
刑事案件: 'bg-[#F9ECEC] text-[#EB3C3C]',
行政案件: 'bg-[#EBF5FF] text-[#2B79EE]',
执行案件: 'bg-[#FFF8E1] text-[#D6943E]',
非诉保全审查案件: 'bg-[#ECF9EF] text-green-600',
强制清算与破产案件: 'bg-gray-100 text-[#666666]',
失信公告: 'bg-[#F9ECEC] text-[#EB3C3C]',
限高公告: 'bg-[#F9ECEC] text-[#EB3C3C]',
}
return styleMap[caseType] || 'bg-gray-100 text-[#666666]'
}
// 获取案件项样式
const getCaseItemClass = (caseItem) => {
if (caseItem.caseStatus === '已结案') return 'case-item-settled'
if (caseItem.caseStatus === '执行中') return 'case-item-executing'
if (caseItem.caseStatus === '审理中') return 'case-item-hearing'
const status = getCaseStatus(caseItem)
if (status === '已结案') return 'case-item-settled'
if (status === '执行中' || status === '未执行') return 'case-item-executing'
return 'case-item-default'
}
// 获取案件状态样式
const getCaseStatusClass = (status) => {
if (status === '已结案') return 'text-green-600 bg-green-100'
if (status === '执行中') return 'text-[#D6943E] bg-[#FFF8E1]'
if (status === '未执行') return 'text-[#EB3C3C] bg-[#F9ECEC]'
if (status === '审理中') return 'text-[#2B79EE] bg-[#EBF5FF]'
if (status === '失信中') return 'text-[#EB3C3C] bg-[#F9ECEC]'
if (status === '限高中') return 'text-[#2B79EE] bg-[#EBF5FF]'
if (status === '未执行' || status === '失信公告') return 'text-[#EB3C3C] bg-[#F9ECEC]'
if (status === '限高公告') return 'text-[#2B79EE] bg-[#EBF5FF]'
return 'text-[#666666] bg-gray-100'
}
// 获取案件状态文字样式
const getCaseStatusTextClass = (status) => {
if (status === '已结案') return 'text-green-600'
if (status === '执行中') return 'text-[#D6943E]'
if (status === '未执行') return 'text-[#EB3C3C]'
if (status === '审理中') return 'text-[#2B79EE]'
if (status === '失信中') return 'text-[#EB3C3C]'
if (status === '限高中') return 'text-[#2B79EE]'
return 'text-[#666666]'
}
// 获取匹配度进度条样式
const getMatchScoreBarStyle = (score) => {
if (score >= 0.9) return 'bg-green-500'
if (score >= 0.8) return 'bg-[#2B79EE]'
if (score >= 0.7) return 'bg-yellow-500'
if (score >= 0.6) return 'bg-[#D6943E]'
return 'bg-[#EB3C3C]'
}
// 格式化内容摘要
const formatContentSummary = (summary) => {
if (!summary) return ''
// 如果是JSON格式尝试解析
if (summary.startsWith('{') && summary.includes('id')) {
try {
const parsed = JSON.parse(summary)
return parsed.content || parsed.summary || '详细信息请查看完整报告'
} catch (e) {
return summary.substring(0, 200) + (summary.length > 200 ? '...' : '')
}
}
// 普通文本,限制长度
return summary.length > 200 ? summary.substring(0, 200) + '...' : summary
}
// 获取默认展开的案件名称
const getDefaultActiveCase = (caseType) => {
return `${caseType}-0` // 默认展开每种类型的第一个案件
}
// 初始化折叠面板状态
onMounted(() => {
Object.keys(groupedCases.value).forEach(caseType => {
if (groupedCases.value[caseType].length > 0) {
activeCases.value[caseType] = getDefaultActiveCase(caseType)
const initActiveCases = () => {
Object.keys(groupedCases.value).forEach((caseType) => {
if (groupedCases.value[caseType]?.length && !activeCases.value[caseType]) {
activeCases.value[caseType] = `${caseType}-0`
}
})
})
}
// 监听数据变化
watch(() => props.data, (newData) => {
if (newData?.judiciaRiskInfos) {
Object.keys(groupedCases.value).forEach(caseType => {
if (groupedCases.value[caseType].length > 0 && !activeCases.value[caseType]) {
activeCases.value[caseType] = getDefaultActiveCase(caseType)
}
})
}
}, { immediate: true, deep: true })
watch(
() => props.data?.judicialLeaseReport,
() => {
initActiveCases()
},
{ immediate: true, deep: true }
)
</script>
<style lang="scss" scoped>
@@ -535,42 +480,37 @@ watch(() => props.data, (newData) => {
color: #666666;
font-size: 13px;
font-weight: 500;
flex-shrink: 0;
}
.value {
color: #333333;
font-size: 13px;
font-weight: 400;
text-align: right;
flex: 1;
margin-left: 8px;
word-break: break-all;
}
}
}
// 案件项样式
:deep(.van-collapse-item) {
margin-bottom: 8px;
border-radius: 8px;
overflow: hidden;
&.case-item-settled {
border: 1px solid #CAECD3;
background-color: #FBFDFC;
}
&.case-item-executing {
border: 1px solid #FFE082;
background-color: #FFFDF9;
}
&.case-item-hearing {
border: 1px solid #EBF5FF;
background-color: #FAFDFF;
border: 1px solid #caecd3;
background-color: #fbfdfc;
}
&.case-item-executing {
border: 1px solid #ffe082;
background-color: #fffdf9;
}
&.case-item-default {
border: 1px solid #DDDDDD;
border: 1px solid #dddddd;
background-color: #f9fafb;
}
}
@@ -584,8 +524,4 @@ watch(() => props.data, (newData) => {
padding: 0 16px 16px;
background-color: transparent;
}
:deep(.van-collapse-item__wrapper) {
border-radius: 8px;
}
</style>
</style>

View File

@@ -209,6 +209,13 @@ const riskListConfig = {
severity: 'medium',
color: 'orange'
},
mediumRelationRisk: {
name: '中介关联风险',
description: '命中中介关联风险名单',
icon: '🔗',
severity: 'high',
color: 'red'
},
phoneNumberStatus: {
name: '手机号码状态异常',
description: '手机号码状态存在异常',

View File

@@ -208,6 +208,20 @@ const riskConfig = {
isHighRisk: true,
icon: '🎰',
color: 'red'
},
registerRisk: {
name: '公证仲裁执行风险',
description: '该地区不予执行先享后付案件',
isHighRisk: true,
icon: '📜',
color: 'red'
},
relationRisk: {
name: '命中中介关联风险',
description: '该用户与中介深度关联',
isHighRisk: true,
icon: '🔗',
color: 'red'
}
}

View File

@@ -39,10 +39,8 @@
<!-- 关联风险监督 -->
<RiskSupervisionSection :data="{ riskSupervision: data.riskSupervision }" />
<!-- 院风险信息 -->
<!-- <CourtRiskInfoSection
:data="{ judiciaRiskInfos: data.judiciaRiskInfos }"
/> -->
<!-- 个人司法信息 -->
<CourtRiskInfoSection :data="{ judicialLeaseReport: data.judicialLeaseReport }" />
</div>
</template>

View File

@@ -0,0 +1,88 @@
/**
* 司南报告 judicialLeaseReport 结构解析
*/
export const JUDICIAL_CASE_GROUPS = [
{ listKey: 'civilCases', name: '民事案件', shortName: '民事', countField: 'civilCasesCount', kind: 'standard' },
{ listKey: 'criminalCases', name: '刑事案件', shortName: '刑事', countField: 'criminalCasesCount', kind: 'standard' },
{ listKey: 'administrativeCases', name: '行政案件', shortName: '行政', countField: 'administrativeCasesCount', kind: 'standard' },
{ listKey: 'preservationCases', name: '非诉保全审查案件', shortName: '非诉保全', countField: 'preservationCasesCount', kind: 'standard' },
{ listKey: 'enforcementCases', name: '执行案件', shortName: '执行', countField: 'enforcementCasesCount', kind: 'standard' },
{ listKey: 'supervisionCases', name: '管辖案件', shortName: '管辖', countField: 'supervisionCasesCount', kind: 'standard' },
{ listKey: 'compensationCases', name: '赔偿案件', shortName: '赔偿', countField: 'compensationCasesCount', kind: 'standard' },
{ listKey: 'bankruptcyCases', name: '强制清算与破产案件', shortName: '清算破产', countField: 'bankruptcyCasesCount', kind: 'standard' },
{ listKey: 'disinCases', name: '失信公告', shortName: '失信', countField: null, kind: 'disin' },
{ listKey: 'limitCases', name: '限高公告', shortName: '限高', countField: null, kind: 'limit' },
]
export function getJudicialLeaseReport(data) {
return data?.judicialLeaseReport || null
}
function listHasItems(list) {
return Array.isArray(list) && list.length > 0
}
export function hasJudicialLeaseContent(report) {
if (!report) return false
const overview = report.caseOverviewInfo || {}
const courtInfo = report.courtInfo || {}
const multi = courtInfo.newMultCourtInfo || {}
if (Number(overview.beigaoTotalCasesCounts) > 0) return true
if (Number(overview.executionCaseCounts) > 0) return true
if (Number(overview.disinCaseCounts) > 0) return true
if (Number(overview.limitCaseCounts) > 0) return true
for (const group of JUDICIAL_CASE_GROUPS) {
const count = group.countField ? Number(courtInfo[group.countField] || 0) : 0
if (count > 0) return true
if (listHasItems(multi[group.listKey])) return true
}
return false
}
export function getCaseTypeStatsFromReport(report) {
const courtInfo = report?.courtInfo || {}
const multi = courtInfo.newMultCourtInfo || {}
const stats = {}
JUDICIAL_CASE_GROUPS.forEach((group) => {
let count = 0
if (group.countField) {
count = Number(courtInfo[group.countField] || 0)
}
if (count === 0 && listHasItems(multi[group.listKey])) {
count = multi[group.listKey].length
}
stats[group.name] = { count, listKey: group.listKey, kind: group.kind }
})
return stats
}
export function getGroupedCasesFromReport(report) {
const multi = report?.courtInfo?.newMultCourtInfo || {}
const grouped = {}
JUDICIAL_CASE_GROUPS.forEach((group) => {
const cases = multi[group.listKey]
if (listHasItems(cases)) {
grouped[group.name] = cases.map((item) => ({ ...item, _kind: group.kind }))
}
})
return grouped
}
export function getTotalCaseListCount(report) {
const grouped = getGroupedCasesFromReport(report)
return Object.values(grouped).reduce((sum, list) => sum + list.length, 0)
}
export function truncateText(text, maxLen = 200) {
if (!text || typeof text !== 'string') return ''
return text.length > maxLen ? `${text.slice(0, maxLen)}...` : text
}

View File

@@ -204,13 +204,13 @@ export function splitDWBG6A2CForTabs(reportData) {
});
}
// 14. 法院风险信息
if (originalData.judiciaRiskInfos && originalData.judiciaRiskInfos.length > 0) {
// 14. 个人司法信息
if (originalData.judicialLeaseReport) {
splitModules.push({
data: {
apiID: 'DWBG6A2C_CourtRiskInfo',
data: {
judiciaRiskInfos: originalData.judiciaRiskInfos
judicialLeaseReport: originalData.judicialLeaseReport
},
success: true,
timestamp: baseTimestamp
@@ -269,7 +269,8 @@ export function formatPhoneStatus(status) {
export function formatVerificationResult(result) {
const resultMap = {
'0': { color: 'text-green-600', bg: 'bg-green-100', text: '一致', icon: '✅' },
'1': { color: 'text-red-600', bg: 'bg-red-100', text: '不一致或不存在', icon: '❌' }
'1': { color: 'text-red-600', bg: 'bg-red-100', text: '不一致或不存在', icon: '❌' },
'-1': { color: 'text-gray-600', bg: 'bg-gray-100', text: '查无记录', icon: '❓' }
};
return resultMap[result] || { color: 'text-gray-600', bg: 'bg-gray-100', text: '未知', icon: '❓' };