378 lines
11 KiB
Vue
378 lines
11 KiB
Vue
<template>
|
||
<div class="card">
|
||
<div class="rounded-lg border border-gray-200 pb-2 mb-4">
|
||
|
||
<!-- 标题区域 -->
|
||
<div class="flex items-center mb-4 p-4">
|
||
<div class="w-8 h-8 flex items-center justify-center mr-2">
|
||
<img src="@/assets/images/report/srpg.png" alt="个人消费能力等级" class="w-8 h-8 object-contain" />
|
||
</div>
|
||
<span class="font-bold text-gray-800">个人消费能力等级</span>
|
||
</div>
|
||
|
||
<div class="px-4 pb-4">
|
||
<!-- 月消费能力 -->
|
||
<div class="mb-6 text-center">
|
||
<div class="text-sm text-gray-600 mb-2">月消费能力</div>
|
||
<div class="text-3xl font-bold mb-3 text-[#333333]">
|
||
<span class="amount-number">{{ getConsumptionAmount(score) }}</span>
|
||
<span class="amount-unit">元/月</span>
|
||
</div>
|
||
<div class="level-bar" :style="getLevelBarBgStyle(score)">
|
||
<div class="level-fill" :style="getLevelBarStyle(score)"></div>
|
||
</div>
|
||
<div class="text-sm text-gray-600 mt-2">{{ getConsumptionDescription(score) }}</div>
|
||
</div>
|
||
|
||
<!-- 评估结果 -->
|
||
<div class="assessment-card">
|
||
<div class="flex items-center">
|
||
<div class="flex-1">
|
||
<div class="flex items-center justify-between mb-2">
|
||
<h4 class="font-semibold text-gray-800">评估结果</h4>
|
||
</div>
|
||
<p class="text-gray-400 text-sm">
|
||
{{ getAssessmentDescription(score) }}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 市场对比 -->
|
||
<div class="assessment-card">
|
||
<div class="flex items-center mb-8">
|
||
<div class="flex-1">
|
||
<div class="flex items-center justify-between mb-2">
|
||
<h4 class="font-semibold text-gray-800">市场对比</h4>
|
||
</div>
|
||
<p class="text-gray-400 text-sm">
|
||
{{ getMarketComparison(score) }}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="comparison-indicator mt-4">
|
||
<div class="indicator-bar">
|
||
<div class="indicator-fill" :style="getIndicatorStyle(score)"></div>
|
||
<div class="indicator-marker" :style="getMarkerPosition(score)">
|
||
<img src="@/assets/images/report/srbq.png" alt="市场对比" class="marker-image" />
|
||
<div class="marker-dot"></div>
|
||
</div>
|
||
</div>
|
||
<div class="indicator-labels">
|
||
<span>低消费</span>
|
||
<span>高消费</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消费能力 -->
|
||
<div class="assessment-card">
|
||
<div class="flex items-center">
|
||
<div class="flex-1">
|
||
<div class="mb-2">
|
||
<h4 class="font-semibold text-gray-800">消费能力</h4>
|
||
</div>
|
||
<p class="text-gray-400 text-sm">
|
||
{{ getConsumptionCapacity(score) }}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from 'vue'
|
||
import { useRiskNotifier } from '@/composables/useRiskNotifier';
|
||
|
||
const props = defineProps({
|
||
data: {
|
||
type: Object,
|
||
required: true,
|
||
default: () => ({})
|
||
},
|
||
apiId: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
index: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
notifyRiskStatus: {
|
||
type: Function,
|
||
default: () => { },
|
||
},
|
||
})
|
||
|
||
// 确保data是响应式的
|
||
const data = computed(() => props.data || {})
|
||
|
||
// 获取评分值(字符串转数字,处理-1特殊值)
|
||
const score = computed(() => {
|
||
const value = data.value['personincome_index_2.0'];
|
||
if (!value || value === '-1') return -1;
|
||
const num = parseInt(value, 10);
|
||
return isNaN(num) ? -1 : num;
|
||
})
|
||
|
||
// 获取消费金额显示(直接显示金额区间)
|
||
const getConsumptionAmount = (score) => {
|
||
if (score === -1) return '无法评估'
|
||
|
||
const amountMap = {
|
||
100: '2,000 - 4,000',
|
||
200: '2,000 - 4,000',
|
||
300: '4,000 - 6,000',
|
||
400: '6,000 - 8,000',
|
||
500: '8,000 - 10,000',
|
||
600: '10,000 - 12,000',
|
||
700: '12,000 - 15,000',
|
||
800: '15,000 - 20,000',
|
||
900: '20,000 - 25,000',
|
||
1000: '25,000+'
|
||
}
|
||
return amountMap[score] || '数据异常'
|
||
}
|
||
|
||
// 消费能力描述
|
||
const getConsumptionDescription = (score) => {
|
||
if (score === -1) return '暂未发现消费能力信息'
|
||
|
||
const descriptionMap = {
|
||
100: '基础消费能力',
|
||
200: '基础消费能力',
|
||
300: '中等消费能力',
|
||
400: '中等消费能力',
|
||
500: '良好消费能力',
|
||
600: '良好消费能力',
|
||
700: '较强消费能力',
|
||
800: '较强消费能力',
|
||
900: '很强消费能力',
|
||
1000: '很强消费能力'
|
||
}
|
||
return descriptionMap[score] || '数据异常'
|
||
}
|
||
|
||
// 等级进度条样式
|
||
const getLevelBarStyle = (score) => {
|
||
if (score === -1) {
|
||
return {
|
||
width: '0%',
|
||
background: '#94a3b8'
|
||
}
|
||
}
|
||
|
||
// 计算百分比:100分=10%, 200分=20%, ..., 1000分=100%
|
||
const percentage = (score / 1000) * 100
|
||
|
||
// 统一使用蓝色渐变
|
||
return {
|
||
width: percentage + '%',
|
||
background: 'linear-gradient(90deg, #3b82f6 0%, #2563eb 100%)'
|
||
}
|
||
}
|
||
|
||
// 进度条背景色样式
|
||
const getLevelBarBgStyle = (score) => {
|
||
// 统一使用淡蓝色背景
|
||
return {
|
||
background: '#eff6ff'
|
||
}
|
||
}
|
||
|
||
// 评估描述
|
||
const getAssessmentDescription = (score) => {
|
||
if (score === -1) {
|
||
return '根据个人消费能力等级分析,无法获取该用户的消费能力信息,无法进行评估。'
|
||
}
|
||
|
||
const descriptions = {
|
||
100: '根据个人消费能力等级分析,该用户月消费能力较低,消费水平有限。',
|
||
200: '根据个人消费能力等级分析,该用户月消费能力较低,消费水平有限。',
|
||
300: '根据个人消费能力等级分析,该用户月消费能力中等,消费水平良好。',
|
||
400: '根据个人消费能力等级分析,该用户月消费能力中等,消费水平良好。',
|
||
500: '根据个人消费能力等级分析,该用户月消费能力中等偏上,消费水平较强。',
|
||
600: '根据个人消费能力等级分析,该用户月消费能力中等偏上,消费水平较强。',
|
||
700: '根据个人消费能力等级分析,该用户月消费能力较高,消费水平很强。',
|
||
800: '根据个人消费能力等级分析,该用户月消费能力较高,消费水平很强。',
|
||
900: '根据个人消费能力等级分析,该用户月消费能力很高,消费水平顶级。',
|
||
1000: '根据个人消费能力等级分析,该用户月消费能力很高,消费水平顶级。'
|
||
}
|
||
return descriptions[score] || '数据异常,无法进行准确评估。'
|
||
}
|
||
|
||
// 市场对比分析
|
||
const getMarketComparison = (score) => {
|
||
if (score === -1) {
|
||
return '无消费能力信息,无法与市场平均水平进行对比。'
|
||
}
|
||
|
||
const comparisons = {
|
||
100: '低于市场平均消费水平,处于消费分布的底部区间。',
|
||
200: '低于市场平均消费水平,处于消费分布的中下区间。',
|
||
300: '接近市场平均消费水平,处于消费分布的中等区间。',
|
||
400: '接近市场平均消费水平,处于消费分布的中等区间。',
|
||
500: '高于市场平均消费水平,处于消费分布的中上区间。',
|
||
600: '高于市场平均消费水平,处于消费分布的中上区间。',
|
||
700: '明显高于市场平均消费水平,处于消费分布的上层区间。',
|
||
800: '显著高于市场平均消费水平,处于消费分布的高层区间。',
|
||
900: '远高于市场平均消费水平,处于消费分布的顶部区间。',
|
||
1000: '超越市场绝大多数消费水平,处于消费分布的顶级区间。'
|
||
}
|
||
return comparisons[score] || '数据异常,无法进行市场对比。'
|
||
}
|
||
|
||
// 消费能力分析
|
||
const getConsumptionCapacity = (score) => {
|
||
if (score === -1) {
|
||
return '缺乏消费能力信息,月消费能力存在不确定性,需要谨慎评估。'
|
||
}
|
||
|
||
const capacities = {
|
||
100: '月消费能力较低,消费水平有限,建议理性消费。',
|
||
200: '月消费能力较低,消费水平有限,建议理性消费。',
|
||
300: '月消费能力稳定,消费水平良好,具备一定的消费潜力。',
|
||
400: '月消费能力稳定,消费水平良好,具备一定的消费潜力。',
|
||
500: '月消费能力较高,消费水平较强,可以支持中等消费。',
|
||
600: '月消费能力较高,消费水平较强,可以支持中等消费。',
|
||
700: '月消费能力很强,消费水平很高,可以支持较高消费。',
|
||
800: '月消费能力很强,消费水平很高,可以支持较高消费。',
|
||
900: '月消费能力顶级,消费水平极高,可以支持高端消费。',
|
||
1000: '月消费能力顶级,消费水平极高,可以支持顶级消费。'
|
||
}
|
||
return capacities[score] || '数据异常,无法进行消费能力分析。'
|
||
}
|
||
|
||
// 指示器样式
|
||
const getIndicatorStyle = (score) => {
|
||
if (score === -1) return { width: '0%', background: 'transparent' }
|
||
|
||
// 100分=0%, 1000分=100%
|
||
const percentage = ((score - 100) / 900) * 100
|
||
return {
|
||
width: percentage + '%',
|
||
background: `linear-gradient(90deg, #93c5fd 0%, #3b82f6 50%, #1d4ed8 100%)`
|
||
}
|
||
}
|
||
|
||
// 标记位置
|
||
const getMarkerPosition = (score) => {
|
||
if (score === -1) return { left: '0%' }
|
||
|
||
// 100分=0%, 1000分=100%
|
||
const percentage = ((score - 100) / 900) * 100
|
||
return {
|
||
left: percentage + '%'
|
||
}
|
||
}
|
||
|
||
// 计算风险评分(0-100分,分数越高越安全)
|
||
const riskScore = computed(() => {
|
||
if (score.value === -1) return 30 // 未命中,风险较高
|
||
// 100分对应30分,1000分对应100分
|
||
return 30 + ((score.value - 100) / 900) * 70
|
||
});
|
||
|
||
// 使用 composable 通知父组件风险评分
|
||
useRiskNotifier(props, riskScore);
|
||
|
||
// 暴露给父组件
|
||
defineExpose({
|
||
riskScore
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 金额数字样式 */
|
||
.amount-number {
|
||
color: #333333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.amount-unit {
|
||
font-size: 0.5em;
|
||
color: #999999;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
/* 进度条 */
|
||
.level-bar {
|
||
height: 12px;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.level-fill {
|
||
height: 100%;
|
||
border-radius: 4px;
|
||
transition: all 0.6s ease;
|
||
}
|
||
|
||
/* 评估卡片 */
|
||
.assessment-card {
|
||
padding: 16px;
|
||
border-radius: 8px;
|
||
margin-bottom: 16px;
|
||
border: 1px solid;
|
||
}
|
||
|
||
/* 评估卡片统一样式 */
|
||
.assessment-card {
|
||
background: #f8fafc;
|
||
border-color: #e2e8f0;
|
||
}
|
||
|
||
/* 对比指示器 */
|
||
.comparison-indicator {
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.indicator-bar {
|
||
position: relative;
|
||
height: 6px;
|
||
border-radius: 3px;
|
||
margin-bottom: 8px;
|
||
background: linear-gradient(90deg, #93c5fd 0%, #3b82f6 50%, #1d4ed8 100%);
|
||
}
|
||
|
||
.indicator-fill {
|
||
height: 100%;
|
||
border-radius: 3px;
|
||
transition: all 0.5s ease;
|
||
background: transparent;
|
||
}
|
||
|
||
.indicator-marker {
|
||
position: absolute;
|
||
top: -26px;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.marker-image {
|
||
width: 24px;
|
||
margin-bottom: 0px;
|
||
}
|
||
|
||
.marker-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
background: white;
|
||
border-radius: 50%;
|
||
box-shadow: 0px 4px 4px 0px #00000040;
|
||
}
|
||
|
||
.indicator-labels {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 0.7rem;
|
||
color: #9ca3af;
|
||
}
|
||
</style>
|