Files
ycc-proxy-webview/src/ui/CFLXGDEA9.vue
2026-02-08 16:56:41 +08:00

669 lines
26 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="personal-bad-record card">
<!-- 空数据提示 -->
<div v-if="!hasData" class="py-8 text-center text-gray-500">
<div class="flex flex-col items-center">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-3">
<span class="text-2xl text-gray-400">📋</span>
</div>
<p>暂无本人不良数据</p>
</div>
</div>
<div v-else class="space-y-4">
<!-- 风险总览 -->
<div class="">
<div class="flex items-center mb-3">
<div class="w-12 h-12">
<img src="@/assets/images/report/gazdryhycp.png" alt="本人不良记录" class="w-8 h-8 object-contain" />
</div>
<div>
<h2 class="text-lg font-bold text-gray-800">风险总览</h2>
<p class="text-sm text-[#999999]">本人不良记录风险评估</p>
</div>
</div>
<!-- 风险统计 -->
<div class="bg-[#FFF0F0] border border-red-200 rounded-lg p-4" v-if="!isNormalPerson">
<div class="grid grid-cols-3 gap-4">
<div class="text-center">
<div class="text-sm text-[#666666] mb-1">总风险点</div>
<div class="text-lg font-bold text-[#E53935]">{{ hitRiskTypes.length }}</div>
</div>
<div class="text-center">
<div class="text-sm text-[#666666] mb-1">高风险</div>
<div class="text-lg font-bold text-[#E53935]">{{ getHighRiskCount() }}</div>
</div>
<div class="text-center">
<div class="text-sm text-[#666666] mb-1">中风险</div>
<div class="text-lg font-bold text-[#FFC107]">{{ getMiddleRiskCount() }}</div>
</div>
</div>
</div>
<!-- 正常人员显示 -->
<div class="bg-[#F0FFF0] border border-green-200 rounded-lg p-4" v-else>
<div class="flex items-center justify-center">
<div class="w-10 h-10 mr-4">
<img src="@/assets/images/report/zq.png" alt="暂无风险" class="w-10 h-10 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-[#333333] text-center">正常人员</div>
<div class="text-sm text-[#999999] text-center">无不良记录属于正常人员</div>
</div>
</div>
</div>
</div>
<!-- 所有风险类型列表 -->
<div class="space-y-3">
<!-- 人员状态 -->
<div class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass('0')">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass('0')]">
{{ getNormalPersonBadgeText() }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon('0')" :alt="isNormalPerson ? '正常人员' : '存在风险'"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor('0')">
{{ isNormalPerson ? '正常人员' : '人员状态' }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ isNormalPerson ? '无不良记录,属于正常人员' : '存在不良记录风险'
}}</div>
</div>
</div>
</div>
<!-- A类侵犯公民人身权利民主权利 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">A类侵犯公民人身权利民主权利</div>
<div class="space-y-2">
<div v-for="code in ['A', 'A1', 'A2', 'A3', 'A4', 'A5']" :key="code"
class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass(code)">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass(code)]">
{{ isHit(code) ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon(code)" :alt="getRiskTypeInfo(code).text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor(code)">
{{ getRiskTypeInfo(code).text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo(code).description }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- B类经济类前科 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">B类经济类前科</div>
<div class="space-y-2">
<div v-for="code in ['B', 'B1', 'B2', 'B3', 'B4', 'B5']" :key="code"
class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass(code)">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass(code)]">
{{ isHit(code) ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon(code)" :alt="getRiskTypeInfo(code).text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor(code)">
{{ getRiskTypeInfo(code).text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo(code).description }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- C类妨害社会管理秩序 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">C类妨害社会管理秩序</div>
<div class="space-y-2">
<div v-for="code in ['C', 'C1', 'C2', 'C3', 'C4', 'C5']" :key="code"
class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass(code)">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass(code)]">
{{ isHit(code) ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon(code)" :alt="getRiskTypeInfo(code).text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor(code)">
{{ getRiskTypeInfo(code).text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo(code).description }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- D类重点 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">D类重点</div>
<div class="space-y-2">
<div v-for="code in ['D', 'D1', 'D2', 'D3', 'D4', 'D5']" :key="code"
class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass(code)">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass(code)]">
{{ isHit(code) ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon(code)" :alt="getRiskTypeInfo(code).text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor(code)">
{{ getRiskTypeInfo(code).text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo(code).description }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- E类涉交通案件 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">E类涉交通案件</div>
<div class="space-y-2">
<div class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass('E')">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass('E')]">
{{ isHit('E') ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon('E')" :alt="getRiskTypeInfo('E').text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor('E')">
{{ getRiskTypeInfo('E').text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo('E').description }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- F类法院文书 -->
<div class="risk-group">
<div class="text-sm font-semibold text-gray-700 mb-2 px-2">F类法院文书</div>
<div class="space-y-2">
<div class="rounded-lg p-4 border-2 relative" :class="getRiskItemClass('F')">
<div
:class="['absolute top-0 right-0 px-1.5 py-0.5 text-sm font-bold text-white rounded-bl-lg rounded-tr-lg', getRiskBadgeClass('F')]">
{{ isHit('F') ? '异常' : '正常' }}
</div>
<div class="flex items-center pr-12">
<div class="w-8 h-8 mr-3 flex-shrink-0 flex items-center justify-center">
<img :src="getRiskItemIcon('F')" :alt="getRiskTypeInfo('F').text"
class="w-8 h-8 object-contain" />
</div>
<div class="flex-1">
<div class="font-bold text-sm" :class="getRiskItemTextColor('F')">
{{ getRiskTypeInfo('F').text }}
</div>
<div class="text-sm text-[#999999] mt-0.5">{{ getRiskTypeInfo('F').description }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
import LRemark from '@/components/LRemark.vue'
import { useRiskNotifier } from '@/composables/useRiskNotifier'
// 导入风险类型图标
import iconZfx from '@/assets/images/report/zfx.png'
import iconGfx from '@/assets/images/report/gfx.png'
import iconSafe from '@/assets/images/report/zq.png'
const props = defineProps({
data: {
type: Object,
default: () => ({}),
},
params: {
type: Object,
default: () => ({}),
},
apiId: {
type: String,
default: '',
},
index: {
type: Number,
default: 0,
},
notifyRiskStatus: {
type: Function,
default: () => { },
},
})
// 风险类型代码映射
const riskTypeMap = {
'0': {
text: '正常人员',
description: '无不良记录,属于正常人员',
level: 'normal',
riskLevel: '正常'
},
'A': {
text: '前科:侵犯公民人身权利,民主权利',
description: '存在侵犯公民人身权利、民主权利的前科记录(在逃,盗窃、诈骗、抢劫、故意伤害、强奸等在刑或前科等)',
level: 'high',
riskLevel: '高风险'
},
'A1': {
text: '盗窃',
description: '存在盗窃前科记录',
level: 'high',
riskLevel: '高风险'
},
'A2': {
text: '诈骗',
description: '存在诈骗前科记录',
level: 'high',
riskLevel: '高风险'
},
'A3': {
text: '抢劫/夺',
description: '存在抢劫、抢夺前科记录',
level: 'high',
riskLevel: '高风险'
},
'A4': {
text: '故意伤害/杀人',
description: '存在故意伤害、杀人前科记录',
level: 'high',
riskLevel: '高风险'
},
'A5': {
text: '强奸/性侵/猥亵',
description: '存在强奸、性侵、猥亵前科记录',
level: 'high',
riskLevel: '高风险'
},
'B': {
text: '经济类前科',
description: '存在破坏金融秩序、非法吸存、违发贷款、金融诈骗、集资诈骗、保险诈骗、假币等在刑或前科等',
level: 'medium',
riskLevel: '中风险'
},
'B1': {
text: '走私',
description: '存在走私前科记录',
level: 'medium',
riskLevel: '中风险'
},
'B2': {
text: '破坏金融管理秩序',
description: '存在破坏金融管理秩序前科记录',
level: 'medium',
riskLevel: '中风险'
},
'B3': {
text: '金融诈骗',
description: '存在金融诈骗前科记录',
level: 'medium',
riskLevel: '中风险'
},
'B4': {
text: '洗钱',
description: '存在洗钱前科记录',
level: 'medium',
riskLevel: '中风险'
},
'B5': {
text: '偷漏税',
description: '存在偷漏税前科记录',
level: 'medium',
riskLevel: '中风险'
},
'C': {
text: '妨害社会管理秩序',
description: '存在扰乱公共秩序、妨害司法、妨害国境管理、妨害文物管理、涉毒、涉黄等在刑或前科等',
level: 'medium',
riskLevel: '中风险'
},
'C1': {
text: '扰乱公共秩序',
description: '存在扰乱公共秩序前科记录',
level: 'medium',
riskLevel: '中风险'
},
'C2': {
text: '妨害司法',
description: '存在妨害司法前科记录',
level: 'medium',
riskLevel: '中风险'
},
'C3': {
text: '涉毒',
description: '存在涉毒前科记录',
level: 'medium',
riskLevel: '中风险'
},
'C4': {
text: '涉黄刑案',
description: '存在涉黄刑案前科记录',
level: 'medium',
riskLevel: '中风险'
},
'C5': {
text: '帮信/掩隐/侵公',
description: '存在帮助信息网络犯罪活动、掩饰隐瞒犯罪所得、侵犯公民个人信息前科记录',
level: 'medium',
riskLevel: '中风险'
},
'D': {
text: '重点',
description: '存在危害国家、公共安全,涉恐、疆藏,涉稳、涉黑、涉及境外等',
level: 'critical',
riskLevel: '高风险'
},
'D1': {
text: '危害国家、公共安全',
description: '存在危害国家、公共安全前科记录',
level: 'critical',
riskLevel: '高风险'
},
'D2': {
text: '涉稳',
description: '存在涉稳前科记录',
level: 'critical',
riskLevel: '高风险'
},
'D3': {
text: '涉及境外',
description: '存在涉及境外前科记录',
level: 'critical',
riskLevel: '高风险'
},
'D4': {
text: '涉恐、疆藏',
description: '存在涉恐、疆藏前科记录',
level: 'critical',
riskLevel: '高风险'
},
'D5': {
text: '涉黑',
description: '存在涉黑前科记录',
level: 'critical',
riskLevel: '高风险'
},
'E': {
text: '涉交通案件',
description: '存在危险驾驶、交通肇事等交通案件前科记录',
level: 'low',
riskLevel: '低风险'
},
'F': {
text: '法院文书',
description: '存在法院文书记录',
level: 'low',
riskLevel: '低风险'
}
}
// 获取风险类型信息
const getRiskTypeInfo = (type) => {
return riskTypeMap[type] || riskTypeMap['F']
}
// 解析命中的风险代码
const hitRiskCodes = computed(() => {
const levelData = props.data?.data?.level || props.data?.level
if (!levelData) return []
const levelStr = levelData.toString()
return levelStr.split(',').map(code => code.trim()).filter(code => code)
})
// 判断是否命中某个风险代码
const isHit = (code) => {
if (code === '0') {
// 如果level是'0',则正常人员命中
return hitRiskCodes.value.includes('0')
}
// 如果直接包含该代码,则命中
if (hitRiskCodes.value.includes(code)) {
return true
}
// 对于父级类型A、B、C、D如果子类型命中父类型也算命中
if (code === 'A') {
// 如果 A1、A2、A3、A4、A5 任何一个命中A 也算命中
return ['A1', 'A2', 'A3', 'A4', 'A5'].some(subCode => hitRiskCodes.value.includes(subCode))
}
if (code === 'B') {
// 如果 B1、B2、B3、B4、B5 任何一个命中B 也算命中
return ['B1', 'B2', 'B3', 'B4', 'B5'].some(subCode => hitRiskCodes.value.includes(subCode))
}
if (code === 'C') {
// 如果 C1、C2、C3、C4、C5 任何一个命中C 也算命中
return ['C1', 'C2', 'C3', 'C4', 'C5'].some(subCode => hitRiskCodes.value.includes(subCode))
}
if (code === 'D') {
// 如果 D1、D2、D3、D4、D5 任何一个命中D 也算命中
return ['D1', 'D2', 'D3', 'D4', 'D5'].some(subCode => hitRiskCodes.value.includes(subCode))
}
return false
}
// 获取命中的风险类型列表
const hitRiskTypes = computed(() => {
return hitRiskCodes.value.filter(code => code !== '0').map(code => ({
code,
...getRiskTypeInfo(code)
}))
})
// 判断是否有数据
const hasData = computed(() => {
const levelData = props.data?.data?.level || props.data?.level
return levelData && Object.keys(props.data || {}).length > 0
})
// 判断是否为正常人员
const isNormalPerson = computed(() => {
return hitRiskCodes.value.includes('0') && hitRiskCodes.value.length === 1
})
// 获取高风险数量
const getHighRiskCount = () => {
return hitRiskTypes.value.filter(risk =>
risk.level === 'high' || risk.level === 'critical'
).length
}
// 获取中风险数量
const getMiddleRiskCount = () => {
return hitRiskTypes.value.filter(risk => risk.level === 'medium').length
}
// 获取风险项样式类
const getRiskItemClass = (code) => {
const hit = isHit(code)
const riskInfo = getRiskTypeInfo(code)
if (code === '0') {
// 正常人员:如果是正常人员显示绿色,否则显示红色(存在异常)
return isNormalPerson.value ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'
}
if (hit) {
if (riskInfo.level === 'critical' || riskInfo.level === 'high') {
return 'bg-red-50 border-red-200'
} else if (riskInfo.level === 'medium') {
return 'bg-orange-50 border-orange-200'
} else {
return 'bg-yellow-50 border-yellow-200'
}
}
return 'bg-gray-50 border-gray-200'
}
// 获取风险项文本颜色
const getRiskItemTextColor = (code) => {
const hit = isHit(code)
const riskInfo = getRiskTypeInfo(code)
if (code === '0') {
// 正常人员:如果是正常人员显示绿色,否则显示红色(存在异常)
return isNormalPerson.value ? 'text-green-600' : 'text-red-600'
}
if (hit) {
if (riskInfo.level === 'critical' || riskInfo.level === 'high') {
return 'text-red-600'
} else if (riskInfo.level === 'medium') {
return 'text-orange-600'
} else {
return 'text-yellow-600'
}
}
return 'text-gray-600'
}
// 获取风险项图标
const getRiskItemIcon = (code) => {
const hit = isHit(code)
const riskInfo = getRiskTypeInfo(code)
if (code === '0') {
// 正常人员:如果是正常人员显示安全图标,否则显示风险图标(存在异常)
return isNormalPerson.value ? iconSafe : iconGfx
}
if (hit) {
if (riskInfo.level === 'critical' || riskInfo.level === 'high') {
return iconGfx
} else {
return iconZfx
}
}
return iconSafe
}
// 获取正常人员标签文本
const getNormalPersonBadgeText = () => {
// 只有当 level 只有 '0' 时才显示"正常人员"
if (isNormalPerson.value) {
return '正常'
}
// 否则显示"存在异常"
return '存在异常'
}
// 获取风险标签样式类
const getRiskBadgeClass = (code) => {
const hit = isHit(code)
const riskInfo = getRiskTypeInfo(code)
if (code === '0') {
// 正常人员:如果是正常人员显示绿色,否则显示红色(存在异常)
return isNormalPerson.value ? 'bg-green-500' : 'bg-[#E53935]'
}
if (hit) {
if (riskInfo.level === 'critical' || riskInfo.level === 'high') {
return 'bg-[#E53935]'
} else if (riskInfo.level === 'medium') {
return 'bg-[#D6943E]'
} else {
return 'bg-yellow-500'
}
}
// 未命中显示绿色(正常)
return 'bg-green-500'
}
// 计算风险评分0-100分分数越高越安全
const riskScore = computed(() => {
if (isNormalPerson.value) {
return 100 // 正常人员,最安全
}
if (hitRiskTypes.value.length === 0) {
return 100 // 无风险数据,最安全
}
// 获取高风险和中风险数量
const highRiskCount = getHighRiskCount()
const middleRiskCount = getMiddleRiskCount()
// 高风险数量越多,分数越低
let score = 100
// 高风险扣分每个高风险扣15分
score -= highRiskCount * 15
// 中风险扣分每个中风险扣8分
score -= middleRiskCount * 8
// 确保分数在合理范围内最低20分
return Math.max(20, Math.min(100, score))
})
// 使用 composable 通知父组件风险评分
useRiskNotifier(props, riskScore)
// 暴露给父组件
defineExpose({
riskScore
})
</script>
<style lang="scss" scoped>
.personal-bad-record {
@apply space-y-4;
}
.risk-group {
@apply mb-4;
}
</style>