Files
tydata-webview-v2/src/ui/CDWBG8B4D/components/LeasingRiskSection.vue
2025-10-28 12:12:48 +08:00

493 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="leasing-risk-section card">
<div class="p-2 relative">
<div class="flex items-center justify-between mb-3 border border-[#DDDDDD] rounded-lg p-4 bg-[#F9F9F9]">
<div class="flex items-center">
<div class="w-10 h-10 flex items-center justify-center mr-2">
<img src="@/assets/images/report/jd.png" alt="租赁风险评估概览" class="w-10 h-10 object-contain" />
</div>
<span class="font-bold text-gray-800">租赁风险评估概览</span>
</div>
<div class="font-bold" :class="getRiskFlagTagClass(leasingRiskAssessment.riskFlag)">
{{ getRiskFlagText(leasingRiskAssessment.riskFlag) }}
</div>
</div>
<!-- 3C机构申请统计 -->
<div class="border border-[#DDDDDD] mb-4 rounded-lg">
<div class="flex items-center p-4">
<LTitle title="3C机构申请统计" />
</div>
<div class="space-y-4 py-2">
<div class="performance-item">
<div class="text-[#333333] pl-4 font-bold">近期申请数</div>
<div class="loan-evaluation-wrap">
<!-- 标签页 -->
<div class="mb-3">
<van-tabs v-model:active="activeInstitutionPeriod" line-width="20" line-height="2"
color="var(--color-primary)" class="loan-evaluation-tabs">
<van-tab v-for="period in timePeriods" :key="period.key" :name="period.key" :title="period.label" />
</van-tabs>
</div>
<!-- 内容显示 -->
<div class="loan-evaluation-content">
<div class="space-y-2">
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">总申请数</span>
<span class="text-lg font-bold text-gray-800">{{ institutionTotalValue }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">周末申请数</span>
<span class="text-lg font-bold text-gray-800">{{ institutionWeekendValue }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">夜间申请数</span>
<span class="text-lg font-bold text-gray-800">{{ institutionNightValue }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 3C平台申请统计 -->
<div class="border border-[#DDDDDD] mb-4 rounded-lg">
<div class="flex items-center p-4">
<LTitle title="3C平台申请统计" />
</div>
<div class="space-y-4 py-2">
<div class="performance-item">
<div class="text-[#333333] pl-4 font-bold">近期申请数</div>
<div class="loan-evaluation-wrap">
<!-- 标签页 -->
<div class="mb-3">
<van-tabs v-model:active="activePlatformPeriod" line-width="20" line-height="2"
color="var(--color-primary)" class="loan-evaluation-tabs">
<van-tab v-for="period in timePeriods" :key="period.key" :name="period.key" :title="period.label" />
</van-tabs>
</div>
<!-- 内容显示 -->
<div class="loan-evaluation-content">
<div class="space-y-2">
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">总申请数</span>
<span class="text-lg font-bold text-gray-800">{{ platformTotalValue }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">周末申请数</span>
<span class="text-lg font-bold text-gray-800">{{ platformWeekendValue }}</span>
</div>
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">夜间申请数</span>
<span class="text-lg font-bold text-gray-800">{{ platformNightValue }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 温馨提示 -->
<LRemark
content="租赁风险评估基于申请人在3C机构和3C平台的申请行为进行综合分析。数据格式为'X/Y'其中X表示身份证匹配到的数据Y表示手机号匹配到的数据。统计包括不同时间段的总申请、周末申请可能存在较高风险和夜间申请22:00-6:00风险较高。建议重点关注近期申请频率异常的情况特别是短期内多次申请可能暗示资金紧张或其他风险因素。数据更新可能存在1-2天延迟。" />
</template>
<script setup>
import LRemark from '@/components/LRemark.vue'
import { ref, computed } from 'vue'
import { useRiskNotifier } from '@/composables/useRiskNotifier'
const props = defineProps({
data: {
type: Object,
required: true,
},
apiId: {
type: String,
default: '',
},
index: {
type: Number,
default: 0,
},
notifyRiskStatus: {
type: Function,
default: () => { },
},
})
// 从data中解构出需要的字段
const { leasingRiskAssessment = {} } = props.data
// 标签页状态管理
const activeInstitutionPeriod = ref('last3Day')
const activePlatformPeriod = ref('last3Day')
// 时间段配置
const timePeriods = [
{ key: 'last3Day', label: '近3天' },
{ key: 'last7Day', label: '近7天' },
{ key: 'last14Day', label: '近14天' },
{ key: 'last1Month', label: '近1个月' },
{ key: 'last3Month', label: '近3个月' },
{ key: 'last6Month', label: '近6个月' },
{ key: 'last12Month', label: '近12个月' }
]
// 机构申请统计数值 - 使用 computed 实现响应式
const institutionTotalValue = computed(() => {
const period = activeInstitutionPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3Days || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast7Days || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast14Days || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLastMonth || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3Months || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast6Months || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast12Months || '0/0'
break
}
return value
})
const institutionWeekendValue = computed(() => {
const period = activeInstitutionPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3DaysWeekend || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast7DaysWeekend || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast14DaysWeekend || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLastMonthWeekend || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3MonthsWeekend || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast6MonthsWeekend || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast12MonthsWeekend || '0/0'
break
}
return value
})
const institutionNightValue = computed(() => {
const period = activeInstitutionPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3DaysNight || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast7DaysNight || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast14DaysNight || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLastMonthNight || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast3MonthsNight || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast6MonthsNight || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCInstitutionApplicationCountLast12MonthsNight || '0/0'
break
}
return value
})
// 平台申请统计数值 - 使用 computed 实现响应式
const platformTotalValue = computed(() => {
const period = activePlatformPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3Days || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast7Days || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast14Days || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLastMonth || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3Months || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast6Months || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast12Months || '0/0'
break
}
return value
})
const platformWeekendValue = computed(() => {
const period = activePlatformPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3DaysWeekend || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast7DaysWeekend || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast14DaysWeekend || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLastMonthWeekend || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3MonthsWeekend || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast6MonthsWeekend || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast12MonthsWeekend || '0/0'
break
}
return value
})
const platformNightValue = computed(() => {
const period = activePlatformPeriod.value
let value = '0/0'
switch (period) {
case 'last3Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3DaysNight || '0/0'
break
case 'last7Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast7DaysNight || '0/0'
break
case 'last14Day':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast14DaysNight || '0/0'
break
case 'last1Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLastMonthNight || '0/0'
break
case 'last3Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast3MonthsNight || '0/0'
break
case 'last6Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast6MonthsNight || '0/0'
break
case 'last12Month':
value = leasingRiskAssessment.threeCPlatformApplicationCountLast12MonthsNight || '0/0'
break
}
return value
})
// 获取风险标识文本
const getRiskFlagText = (flag) => {
if (flag === 1) return '高风险'
if (flag === 2) return '低风险'
return '未查得'
}
// 获取风险标识标签颜色
const getRiskFlagTagClass = (flag) => {
if (flag === 1) return 'text-[#EB3C3C]'
if (flag === 2) return 'text-[#4CAF50]'
return 'text-gray-500'
}
// 计算风险评分0-100分分数越高越安全
const riskScore = computed(() => {
const assessment = leasingRiskAssessment.value || {};
// 没有数据 -> 无风险 -> 100分
if (Object.keys(assessment).length === 0) {
return 100;
}
// 风险标识为高风险 -> 高风险 -> 30分
if (assessment.riskFlag === 1) {
return 30;
}
// 风险标识为低风险 -> 低风险 -> 90分
if (assessment.riskFlag === 2) {
return 90;
}
// 根据租赁申请行为计算风险分数
let riskPoints = 0;
// 3C机构申请统计 - 近3天
const institutionLast3Days = assessment.threeCInstitutionApplicationCountLast3Days || '0/0';
const [idCardCount1, phoneCount1] = institutionLast3Days.split('/').map(v => parseInt(v) || 0);
const count1 = Math.max(idCardCount1, phoneCount1);
// 3C机构周末申请 - 近3天
const institutionWeekendLast3Days = assessment.threeCInstitutionApplicationCountLast3DaysWeekend || '0/0';
const [idCardCount2, phoneCount2] = institutionWeekendLast3Days.split('/').map(v => parseInt(v) || 0);
const weekendCount1 = Math.max(idCardCount2, phoneCount2);
// 3C机构夜间申请 - 近3天
const institutionNightLast3Days = assessment.threeCInstitutionApplicationCountLast3DaysNight || '0/0';
const [idCardCount3, phoneCount3] = institutionNightLast3Days.split('/').map(v => parseInt(v) || 0);
const nightCount1 = Math.max(idCardCount3, phoneCount3);
// 3C平台申请统计 - 近3天
const platformLast3Days = assessment.threeCPlatformApplicationCountLast3Days || '0/0';
const [idCardCount4, phoneCount4] = platformLast3Days.split('/').map(v => parseInt(v) || 0);
const count2 = Math.max(idCardCount4, phoneCount4);
// 3C平台周末申请 - 近3天
const platformWeekendLast3Days = assessment.threeCPlatformApplicationCountLast3DaysWeekend || '0/0';
const [idCardCount5, phoneCount5] = platformWeekendLast3Days.split('/').map(v => parseInt(v) || 0);
const weekendCount2 = Math.max(idCardCount5, phoneCount5);
// 3C平台夜间申请 - 近3天
const platformNightLast3Days = assessment.threeCPlatformApplicationCountLast3DaysNight || '0/0';
const [idCardCount6, phoneCount6] = platformNightLast3Days.split('/').map(v => parseInt(v) || 0);
const nightCount2 = Math.max(idCardCount6, phoneCount6);
// 计算风险点数
// 总申请数 >= 5 -> 高风险
if (count1 >= 5 || count2 >= 5) {
riskPoints += 3;
} else if (count1 >= 3 || count2 >= 3) {
riskPoints += 2;
} else if (count1 > 0 || count2 > 0) {
riskPoints += 1;
}
// 周末申请 >= 3 -> 高风险
if (weekendCount1 >= 3 || weekendCount2 >= 3) {
riskPoints += 3;
} else if (weekendCount1 > 0 || weekendCount2 > 0) {
riskPoints += 2;
}
// 夜间申请 >= 3 -> 高风险
if (nightCount1 >= 3 || nightCount2 >= 3) {
riskPoints += 3;
} else if (nightCount1 > 0 || nightCount2 > 0) {
riskPoints += 2;
}
// 计算最终分数(风险点数越多,分数越低)
if (riskPoints === 0) {
return 100;
} else if (riskPoints <= 2) {
return 80;
} else if (riskPoints <= 4) {
return 60;
} else if (riskPoints <= 6) {
return 40;
} else {
return 30;
}
});
// 使用 composable 通知父组件风险评分
useRiskNotifier(props, riskScore);
// 暴露给父组件
defineExpose({
riskScore
});
</script>
<style lang="scss" scoped>
.leasing-risk-section {
@apply space-y-4;
}
.loan-evaluation-tabs {}
.loan-evaluation-tabs :deep(.van-tabs__wrap) {
height: 32px !important;
background-color: transparent !important;
padding: 0 !important;
border-bottom: 1px solid #DDDDDD !important;
}
.loan-evaluation-tabs :deep(.van-tabs__nav) {
background-color: transparent !important;
gap: 0;
height: 32px !important;
}
.loan-evaluation-tabs :deep(.van-tab) {
color: #999999 !important;
font-size: 14px !important;
font-weight: 400 !important;
}
.loan-evaluation-tabs :deep(.van-tab--active) {
color: var(--van-theme-primary) !important;
background-color: unset !important;
}
.loan-evaluation-tabs :deep(.van-tabs__line) {
height: 2px !important;
border-radius: 1px !important;
}
/* 内容区域样式 */
.loan-evaluation-wrap {
@apply mx-4 my-1;
border: 1px solid #DDDDDD;
background-color: #F9F9F9;
border-radius: 8px;
}
.loan-evaluation-content {
padding: 8px 16px;
}
</style>