This commit is contained in:
2026-01-15 18:03:13 +08:00
commit ad794a1312
670 changed files with 92362 additions and 0 deletions

403
src/ui/YYSY8B1C/index.vue Normal file
View File

@@ -0,0 +1,403 @@
<template>
<div class="mobile-online-duration card">
<div class="verification-section mb-4">
<div class="bg-white rounded-xl border border-gray-200 p-4 relative">
<div class="flex items-center mb-3">
<div class="w-8 h-8 flex items-center justify-center mr-3">
<img src="@/assets/images/report/sjh.png" alt="手机在网时长" class="w-8 h-8 object-contain" />
</div>
<span class="font-bold text-gray-800">手机在网时长</span>
</div>
<!-- 查询结果 -->
<div class="verification-details">
<div v-if="hasData" class="space-y-4">
<!-- 运营商 -->
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
<span class="text-sm text-gray-600">运营商</span>
<span class="text-sm font-bold text-gray-800">{{ operators || '-' }}</span>
</div>
<!-- 在网时长信息 -->
<div class="">
<!-- 在网时长区间 -->
<div class="flex justify-between items-center">
<span class="text-sm text-gray-600">在网时长</span>
<span class="text-sm font-bold text-gray-800">{{ friendlyDurationText }}</span>
</div>
<!-- 进度条 -->
<div v-if="showProgressBar" class="mt-16">
<div class="relative">
<!-- 当前值标签上方 -->
<div class="absolute -top-12 left-1/2 transform -translate-x-1/2 whitespace-nowrap transition-all duration-700 ease-out z-30"
:class="progressBarTextColor" :style="{ left: progressBarWidth + '%' }">
<div class="px-3 py-1.5 rounded-lg shadow-lg backdrop-blur-sm bg-white/90 border-2 font-semibold text-sm"
:class="progressBarBorderColor">
{{ friendlyDurationText }}
</div>
<!-- 小三角指向 -->
<div class="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-[6px] border-r-[6px] border-t-[6px] border-transparent transition-colors duration-700"
:style="{ borderTopColor: progressBarArrowBorderColor }">
</div>
</div>
<!-- 进度条容器 -->
<div
class="relative h-6 bg-gradient-to-r from-gray-50 to-gray-100 rounded-full overflow-hidden shadow-inner border-2 border-gray-200/50">
<!-- 背景分段渐变效果 -->
<div class="absolute inset-0 flex h-full">
<div
class="w-[15%] bg-gradient-to-br from-red-50 to-red-100/50 border-r border-red-200/60">
</div>
<div
class="w-[15%] bg-gradient-to-br from-orange-50 to-orange-100/50 border-r border-orange-200/60">
</div>
<div
class="w-[20%] bg-gradient-to-br from-yellow-50 to-yellow-100/50 border-r border-yellow-200/60">
</div>
<div
class="w-[25%] bg-gradient-to-br from-green-50 to-green-100/50 border-r border-green-200/60">
</div>
<div class="flex-1 bg-gradient-to-br from-blue-50 to-indigo-100/50"></div>
</div>
<!-- 进度条填充渐变 -->
<div class="absolute inset-0 flex items-center">
<div class="h-full transition-all duration-700 ease-out rounded-full flex items-center justify-end pr-1.5 shadow-lg"
:class="progressBarGradient" :style="{ width: progressBarWidth + '%' }">
<!-- 标记点带光晕效果 -->
<div class="relative">
<!-- 外圈光晕 -->
<div class="absolute inset-0 rounded-full animate-ping opacity-30"
:class="progressBarColor">
</div>
<!-- 标记点主体 -->
<div class="relative w-3 h-3 rounded-full bg-white shadow-xl"
:class="progressBarBorderColor" style="border-width: 2.5px;">
<!-- 内圈高光 -->
<div class="absolute inset-0.5 rounded-full bg-white/50"></div>
</div>
</div>
</div>
</div>
<!-- 区间分割线更精致 -->
<div class="absolute inset-0 flex h-full pointer-events-none">
<div class="w-[15%] border-r-2 border-dashed border-gray-300/70"></div>
<div class="w-[15%] border-r-2 border-dashed border-gray-300/70"></div>
<div class="w-[20%] border-r-2 border-dashed border-gray-300/70"></div>
<div class="w-[25%] border-r-2 border-dashed border-gray-300/70"></div>
</div>
</div>
<!-- 区间标签底部 -->
<div class="relative mt-2 flex justify-between text-sm text-gray-600">
<span class="font-bold">0</span>
<span class="font-bold">3</span>
<span class="font-bold">6</span>
<span class="font-bold">12</span>
<span class="font-bold">24</span>
<span class="font-bold"></span>
</div>
</div>
</div>
<!-- 特殊状态说明 -->
<div v-if="isSpecialStatus" class="mt-3 p-3 rounded-lg" :class="specialStatusClass">
<div class="text-sm font-medium" :class="specialStatusTextClass">
{{ specialStatusText }}
</div>
<div class="text-sm mt-1" :class="specialStatusDescClass">
{{ specialStatusDesc }}
</div>
</div>
</div>
</div>
<div v-else class="p-8 text-center text-gray-500">
<div class="flex flex-col items-center justify-center">
<van-empty description="暂无查询结果" />
</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: () => { },
},
})
// 获取数据
const reportData = computed(() => {
return props.data?.data?.data || props.data?.data || props.data || {}
})
// 运营商
const operators = computed(() => {
return reportData.value.operators || ''
})
// 在网时长
const inTime = computed(() => {
const value = reportData.value.inTime
if (value === undefined || value === null || value === '') {
return null
}
return String(value)
})
// 是否有数据
const hasData = computed(() => {
return inTime.value !== null || operators.value
})
// 是否显示进度条
const showProgressBar = computed(() => {
const value = inTime.value
return value !== null && value !== '99' && value !== '-1'
})
// 是否特殊状态
const isSpecialStatus = computed(() => {
const value = inTime.value
return value === '99' || value === '-1'
})
// 在网时长文本(原始格式)
const durationText = computed(() => {
const value = inTime.value
if (value === null) return '-'
const durationMap = {
'0': '[0, 3) 个月',
'3': '[3, 6) 个月',
'6': '[6, 12) 个月',
'12': '[12, 24) 个月',
'24': '[24, +∞) 个月',
'99': '手机号已离网/新入网/手机状态异常',
'-1': '查无记录'
}
return durationMap[value] || '-'
})
// 友好的在网时长文本
const friendlyDurationText = computed(() => {
const value = inTime.value
if (value === null) return '-'
const friendlyMap = {
'0': '0-3个月新入网',
'3': '3-6个月短期在网',
'6': '6-12个月中期在网',
'12': '12-24个月长期在网',
'24': '24个月以上稳定在网',
'99': '状态异常',
'-1': '查无记录'
}
return friendlyMap[value] || '-'
})
// 进度条宽度(百分比)- 精准对应区间中点
const progressBarWidth = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return 0
// 区间分布0-3(15%), 3-6(15%), 6-12(20%), 12-24(25%), 24+(25%)
// 计算每个区间的中点位置
const widthMap = {
'0': 7.5, // [0,3) 的中点 = 15% / 2 = 7.5%
'3': 22.5, // [3,6) 的中点 = 15% + 15% / 2 = 22.5%
'6': 40, // [6,12) 的中点 = 30% + 20% / 2 = 40%
'12': 57.5, // [12,24) 的中点 = 50% + 25% / 2 = 57.5%
'24': 87.5 // [24,+) 的中点 = 75% + 25% / 2 = 87.5%
}
return widthMap[value] || 0
})
// 进度条颜色
const progressBarColor = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return ''
const colorMap = {
'0': 'bg-red-500',
'3': 'bg-orange-500',
'6': 'bg-yellow-500',
'12': 'bg-green-500',
'24': 'bg-blue-500'
}
return colorMap[value] || 'bg-gray-500'
})
// 进度条渐变效果
const progressBarGradient = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return ''
const gradientMap = {
'0': 'bg-gradient-to-r from-red-400 via-red-500 to-red-600',
'3': 'bg-gradient-to-r from-orange-400 via-orange-500 to-orange-600',
'6': 'bg-gradient-to-r from-yellow-400 via-yellow-500 to-yellow-600',
'12': 'bg-gradient-to-r from-green-400 via-green-500 to-green-600',
'24': 'bg-gradient-to-r from-blue-400 via-blue-500 to-blue-600'
}
return gradientMap[value] || 'bg-gradient-to-r from-gray-400 to-gray-600'
})
// 进度条边框颜色
const progressBarBorderColor = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return 'border-gray-300'
const colorMap = {
'0': 'border-red-400',
'3': 'border-orange-400',
'6': 'border-yellow-400',
'12': 'border-green-400',
'24': 'border-blue-400'
}
return colorMap[value] || 'border-gray-300'
})
// 进度条文本颜色
const progressBarTextColor = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return 'text-gray-700'
const colorMap = {
'0': 'text-red-600',
'3': 'text-orange-600',
'6': 'text-yellow-600',
'12': 'text-green-600',
'24': 'text-blue-600'
}
return colorMap[value] || 'text-gray-700'
})
// 箭头边框颜色(用于内联样式)
const progressBarArrowBorderColor = computed(() => {
const value = inTime.value
if (!value || value === '99' || value === '-1') return '#d1d5db'
const colorMap = {
'0': '#ef4444', // red-500
'3': '#f97316', // orange-500
'6': '#eab308', // yellow-500
'12': '#22c55e', // green-500
'24': '#3b82f6' // blue-500
}
return colorMap[value] || '#6b7280'
})
// 特殊状态样式
const specialStatusClass = computed(() => {
const value = inTime.value
if (value === '99') return 'bg-orange-50 border border-orange-200'
if (value === '-1') return 'bg-gray-50 border border-gray-200'
return ''
})
const specialStatusTextClass = computed(() => {
const value = inTime.value
if (value === '99') return 'text-orange-700'
if (value === '-1') return 'text-gray-700'
return ''
})
const specialStatusDescClass = computed(() => {
const value = inTime.value
if (value === '99') return 'text-orange-600'
if (value === '-1') return 'text-gray-600'
return ''
})
// 特殊状态文本
const specialStatusText = computed(() => {
const value = inTime.value
if (value === '99') return '状态异常'
if (value === '-1') return '查无记录'
return ''
})
// 特殊状态描述
const specialStatusDesc = computed(() => {
const value = inTime.value
if (value === '99') return '手机号可能已离网、新入网或状态异常,无法准确查询在网时长'
if (value === '-1') return '系统中未查询到该手机号的在网时长记录'
return ''
})
// 计算风险评分(在网时长越长,风险越低)
const riskScore = computed(() => {
const value = inTime.value
if (!value || value === '-1') {
return 50 // 查无记录,中等风险
}
if (value === '99') {
return 30 // 状态异常,较高风险
}
// 在网时长越长,分数越高(越安全)
const scoreMap = {
'0': 20, // [0,3) 个月 - 高风险
'3': 40, // [3,6) 个月 - 中高风险
'6': 60, // [6,12) 个月 - 中等风险
'12': 80, // [12,24) 个月 - 低风险
'24': 100 // [24,+) 个月 - 最低风险
}
return scoreMap[value] || 50
})
// 使用 composable 通知父组件风险评分
useRiskNotifier(props, riskScore)
// 暴露给父组件
defineExpose({
riskScore
})
</script>
<style lang="scss" scoped>
.mobile-online-duration {
@apply space-y-4;
}
.verification-section {
.verification-details {
@apply mt-3;
}
}
</style>