Files
tydata-webview-v2/src/ui/JRZQ8B3C/index.vue
2026-02-11 15:02:56 +08:00

378 lines
11 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="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>