493 lines
17 KiB
Vue
493 lines
17 KiB
Vue
<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>
|