新增两组件
This commit is contained in:
322
src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue
Normal file
322
src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue
Normal file
@@ -0,0 +1,322 @@
|
||||
<template>
|
||||
<div class="card rounded-lg border border-gray-200 mb-2">
|
||||
<div class="mt-4">
|
||||
<LTitle title="借款与逾期概览" />
|
||||
|
||||
<!-- 借款次数汇总图 -->
|
||||
<div class="h-64 px-2 mb-4">
|
||||
<v-chart class="chart-container" :option="loanChartOption" autoresize />
|
||||
</div>
|
||||
|
||||
<!-- 逾期次数汇总图 -->
|
||||
<div class="h-64 px-2 mb-4">
|
||||
<v-chart class="chart-container" :option="overdueChartOption" autoresize />
|
||||
</div>
|
||||
|
||||
<div class="mb-4 mt-4 space-y-4">
|
||||
<!-- 借款次数 / 机构数 -->
|
||||
<div>
|
||||
<div class="mb-4 border border-gray-200 rounded-lg overflow-hidden mx-4">
|
||||
<!-- 表头 -->
|
||||
<div class="bg-[#5d7eeb] text-white">
|
||||
<div class="grid grid-cols-6 text-sm">
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">周期
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">银行
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">消费金融
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">其他机构
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">总次数
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold whitespace-nowrap">机构数</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 数据行 -->
|
||||
<div class="bg-white">
|
||||
<div v-for="(row, idx) in loanRows" :key="row.key"
|
||||
:class="['grid grid-cols-6 text-sm', idx < loanRows.length - 1 ? 'border-b border-gray-200' : '']">
|
||||
<div
|
||||
class="py-3 text-center font-medium text-gray-800 border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.label }}</div>
|
||||
<div class="py-3 text-center text-[#333333] border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.bank }}</div>
|
||||
<div class="py-3 text-center text-[#333333] border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.fin }}</div>
|
||||
<div class="py-3 text-center text-[#333333] border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.other }}</div>
|
||||
<div
|
||||
class="py-3 text-center text-[#333333] font-semibold border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.total }}</div>
|
||||
<div class="py-3 text-center text-[#333333] whitespace-nowrap">{{ row.orgTotal }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 借款等级 -->
|
||||
<div>
|
||||
<div class="mb-4 border border-gray-200 rounded-lg overflow-hidden mx-4">
|
||||
<!-- 表头 -->
|
||||
<div class="bg-[#5d7eeb] text-white">
|
||||
<div class="grid grid-cols-2 text-sm">
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">周期
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold whitespace-nowrap">综合借款等级</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 数据行 -->
|
||||
<div class="bg-white">
|
||||
<div v-for="(row, idx) in loanAmtRows" :key="row.key"
|
||||
:class="['grid grid-cols-2 text-sm', idx < loanAmtRows.length - 1 ? 'border-b border-gray-200' : '']">
|
||||
<div
|
||||
class="py-3 text-center font-medium text-gray-800 border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.label }}</div>
|
||||
<div class="py-3 text-center text-[#333333] font-semibold whitespace-nowrap">{{ row.amt
|
||||
}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 逾期次数与等级 -->
|
||||
<div>
|
||||
<div class="mb-4 border border-gray-200 rounded-lg overflow-hidden mx-4">
|
||||
<!-- 表头 -->
|
||||
<div class="bg-[#5d7eeb] text-white">
|
||||
<div class="grid grid-cols-4 text-sm">
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">周期
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">逾期次数
|
||||
</div>
|
||||
<div class="py-3 text-center font-semibold border-r border-white whitespace-nowrap">
|
||||
逾期机构数</div>
|
||||
<div class="py-3 text-center font-semibold whitespace-nowrap">逾期等级</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 数据行 -->
|
||||
<div class="bg-white">
|
||||
<div v-for="(row, idx) in overdueRows" :key="row.key"
|
||||
:class="['grid grid-cols-4 text-sm', idx < overdueRows.length - 1 ? 'border-b border-gray-200' : '']">
|
||||
<div
|
||||
class="py-3 text-center font-medium text-gray-800 border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.label }}</div>
|
||||
<div class="py-3 text-center text-[#333333] border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.num }}</div>
|
||||
<div class="py-3 text-center text-[#333333] border-r border-gray-200 whitespace-nowrap">
|
||||
{{ row.org }}</div>
|
||||
<div class="py-3 text-center text-[#333333] font-semibold whitespace-nowrap">{{
|
||||
row.level }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import LTitle from '@/components/LTitle.vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { BarChart } from 'echarts/charts'
|
||||
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import { PERIODS, normalizeValue } from '../utils/dataParser'
|
||||
|
||||
use([CanvasRenderer, BarChart, GridComponent, LegendComponent, TooltipComponent])
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
// 借款次数与机构数
|
||||
const loanRows = computed(() => {
|
||||
const v = props.data || {}
|
||||
return PERIODS.map(p => {
|
||||
const prefix = `ppcm_${p.key}`
|
||||
return {
|
||||
key: p.key,
|
||||
label: p.label,
|
||||
bank: normalizeValue(v[`${prefix}_bank_loannum`]),
|
||||
fin: normalizeValue(v[`${prefix}_nbank_fin_loannum`]),
|
||||
other: normalizeValue(v[`${prefix}_nbank_other_loannum`]),
|
||||
total: normalizeValue(v[`${prefix}_loannum`]),
|
||||
orgTotal: normalizeValue(v[`${prefix}_loanorg`])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 借款等级 ppcm_{period}_loanamt
|
||||
const loanAmtRows = computed(() => {
|
||||
const v = props.data || {}
|
||||
return PERIODS.map(p => {
|
||||
const prefix = `ppcm_${p.key}`
|
||||
return {
|
||||
key: p.key,
|
||||
label: p.label,
|
||||
amt: normalizeValue(v[`${prefix}_loanamt`])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 逾期次数 / 机构数 / 等级
|
||||
const overdueRows = computed(() => {
|
||||
const v = props.data || {}
|
||||
const periodKeys = ['d7', 'm1', 'm3', 'm6', 'm12', 'm24']
|
||||
const labelMap = {
|
||||
d7: '近7天',
|
||||
m1: '近1个月',
|
||||
m3: '近3个月',
|
||||
m6: '近6个月',
|
||||
m12: '近1年',
|
||||
m24: '近2年'
|
||||
}
|
||||
return periodKeys.map(key => {
|
||||
const prefix = `ppcm_${key}`
|
||||
return {
|
||||
key,
|
||||
label: labelMap[key],
|
||||
num: normalizeValue(v[`${prefix}_overnum`]),
|
||||
org: normalizeValue(v[`${prefix}_overorg`]),
|
||||
level: normalizeValue(v[`${prefix}_overamt`])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 借款次数汇总柱状图(总借款次数)
|
||||
const loanChartOption = computed(() => {
|
||||
const labels = PERIODS.map(p => p.label)
|
||||
const totals = loanRows.value.map(r => r.total)
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' }
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
top: 20,
|
||||
bottom: 0,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: labels,
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#6b7280'
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#6b7280',
|
||||
formatter: '{value} 次'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f3f4f6'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '总借款次数',
|
||||
type: 'bar',
|
||||
data: totals,
|
||||
barWidth: '35%',
|
||||
barMinHeight: 3,
|
||||
itemStyle: {
|
||||
color: '#60A5FA',
|
||||
borderRadius: [4, 4, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// 逾期次数汇总柱状图
|
||||
const overdueChartOption = computed(() => {
|
||||
const labels = overdueRows.value.map(r => r.label)
|
||||
const nums = overdueRows.value.map(r => r.num)
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' }
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
top: 20,
|
||||
bottom: 0,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: labels,
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#6b7280'
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e5e7eb'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#6b7280',
|
||||
formatter: '{value} 次'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f3f4f6'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '逾期次数',
|
||||
type: 'bar',
|
||||
data: nums,
|
||||
barWidth: '35%',
|
||||
barMinHeight: 3,
|
||||
itemStyle: {
|
||||
color: '#F97316',
|
||||
borderRadius: [4, 4, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user