This commit is contained in:
2026-07-05 02:26:54 +08:00
parent c33167fe6b
commit bc3d031a6e
5 changed files with 252 additions and 0 deletions

View File

@@ -357,6 +357,10 @@ const featureMap = {
name: "人车核验详版",
component: defineAsyncComponent(() => import("@/ui/CQCXGYTS2.vue")),
},
QCXG7K2N: {
name: "人车核验加强版",
component: defineAsyncComponent(() => import("@/ui/CQCXG7K2N.vue")),
},
QCXG5F3A: {
name: "名下车辆(车牌)",
component: defineAsyncComponent(() => import("@/ui/QCXG5F3A.vue")),
@@ -674,6 +678,7 @@ const featureRiskLevels = {
'QCXG7A2B': 5, // 名下车辆
'QCXGGB2Q': 5, // 人车核验简版
'QCXGYTS2': 5, // 人车核验详版
'QCXG7K2N': 5, // 人车核验加强版
'QCXG5F3A': 5, // 名下车辆(车牌)
'QCXG4D2E': 5, 'QCXG5U0Z': 5, 'QCXG1U4U': 5, 'QCXGY7F2': 5, 'QCXG1H7Y': 5,
'QCXG4I1Z': 5, 'QCXG3Y6B': 5, 'QCXG3Z3L': 5, 'QCXGP00W': 5, 'QCXG6B4E': 5,

View File

@@ -619,6 +619,7 @@ const getFeatureIcon = (apiId) => {
QCXG7A2B: "/inquire_icons/mingxiacheliang.svg", // 名下车辆
QCXGGB2Q: "/inquire_icons/mingxiacheliang.svg", // 人车核验简版
QCXGYTS2: "/inquire_icons/mingxiacheliang.svg", // 人车核验详版
QCXG7K2N: "/inquire_icons/mingxiacheliang.svg", // 人车核验加强版
QCXG5F3A: "/inquire_icons/mingxiacheliang.svg", // 名下车辆(车牌)
QCXG4D2E: "/inquire_icons/mingxiacheliang.svg",
QCXG5U0Z: "/inquire_icons/mingxiacheliang.svg",

View File

@@ -120,6 +120,7 @@ export function useInquireForm(featureRef) {
toc_PersonVehicleVerification: ["name", "carType", "carLicense"],
// 人车核验详版:姓名 + 号牌类型 + 车牌号(同简版)
toc_PersonVehicleVerificationDetail: ["name", "carType", "carLicense"],
toc_PersonVehicleVerificationEnhanced: ["name", "carType", "carLicense"],
// 名下车辆(数量) QCXG4D2E仅 user_type + id_card
toc_VehiclesUnderNameCount: ["userType", "idCard"],
// 车辆静态信息 QCXG5U0Z仅 vin_code车辆类不要求手机号与验证码

View File

@@ -92,6 +92,13 @@ export const inquireCategoryConfig = {
icon: "rchyxb.svg",
iconFrom: "category",
},
{
name: "人车核验(加强版)",
feature: "toc_PersonVehicleVerificationEnhanced",
desc: "多源加强核验姓名与车牌是否一致,号牌类型编码如 02小型汽车",
icon: "rchyxb.svg",
iconFrom: "category",
},
{
name: "名下车辆(车牌)",
feature: "toc_VehiclesUnderNamePlate",

238
src/ui/CQCXG7K2N.vue Normal file
View File

@@ -0,0 +1,238 @@
<template>
<div class="card">
<div class="header-box">
<h3 class="header-title">人车核验加强版</h3>
<p class="header-desc">基于 ETC/行驶证等多源数据加强核验人员与车辆是否一致</p>
</div>
<div class="result-section" :class="resultSectionClass">
<div class="result-icon-wrap">
<span class="result-icon" :class="iconClass">
{{ iconChar }}
</span>
</div>
<div class="result-label">核验结果</div>
<div class="result-value" :class="resultTextClass">{{ resultText }}</div>
</div>
<div v-if="hasParams" class="info-rows">
<div class="info-row">
<span class="info-label">姓名</span>
<span class="info-value">{{ maskedName }}</span>
</div>
<div class="info-row">
<span class="info-label">车牌号</span>
<span class="info-value font-mono">{{ params?.plate_no || params?.car_license || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">号牌类型</span>
<span class="info-value">{{ plateTypeLabel }}</span>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { useRiskNotifier } from '@/composables/useRiskNotifier';
const PLATE_TYPE_LABELS = {
'02': '小型汽车(蓝牌)',
'01': '大型汽车(黄牌)',
'03': '使馆汽车',
'04': '领馆汽车',
'05': '境外汽车',
'06': '外籍汽车',
'07': '普通摩托车',
'08': '轻便摩托车',
'09': '使馆摩托车',
'10': '领馆摩托车',
'11': '境外摩托车',
'12': '外籍摩托车',
'13': '低速车',
'14': '拖拉机',
'15': '挂车',
'16': '教练汽车',
'17': '教练摩托车',
'20': '临时入境汽车',
'21': '临时入境摩托车',
'22': '临时行驶车',
'23': '警用汽车',
'24': '警用摩托',
'38': '预留',
'51': '新能源大型车',
'52': '新能源小型车(绿牌)',
};
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 maskedName = computed(() => {
const name = props.params?.name || '';
if (!name) return '-';
return name.length > 1 ? name[0] + '*'.repeat(name.length - 1) : '*';
});
const rawPlateType = computed(() => {
const p = props.params || {};
return p.plate_type || p.carplate_type || p.car_type || '02';
});
const plateTypeLabel = computed(() => {
const code = String(rawPlateType.value);
return PLATE_TYPE_LABELS[code] ? `${code} · ${PLATE_TYPE_LABELS[code]}` : code;
});
// status: 1 一致2 不一致(接口文档为 string兼容 number
const status = computed(() => {
const d = props.data;
const direct = d?.status;
if (direct === '1' || direct === 1) return 'match';
if (direct === '2' || direct === 2) return 'mismatch';
const nested = d?.result?.status;
if (nested === '1' || nested === 1) return 'match';
if (nested === '2' || nested === 2) return 'mismatch';
return null;
});
const resultText = computed(() => {
if (status.value === 'match') return '一致';
if (status.value === 'mismatch') return '不一致';
return '暂无结果';
});
const resultTextClass = computed(() => {
if (status.value === 'match') return 'result-match';
if (status.value === 'mismatch') return 'result-mismatch';
return 'result-unknown';
});
const resultSectionClass = computed(() => {
if (status.value === 'match') return 'result-section match';
if (status.value === 'mismatch') return 'result-section mismatch';
return 'result-section unknown';
});
const iconClass = computed(() => {
if (status.value === 'match') return 'icon-match';
if (status.value === 'mismatch') return 'icon-mismatch';
return 'icon-unknown';
});
const iconChar = computed(() => {
if (status.value === 'match') return '✓';
if (status.value === 'mismatch') return '✕';
return '?';
});
const hasParams = computed(() => {
const p = props.params || {};
return p.name || p.plate_no || p.car_license || p.plate_type || p.carplate_type || p.car_type;
});
const riskScore = computed(() => (status.value === 'mismatch' ? 60 : 100));
useRiskNotifier(props, riskScore);
defineExpose({ riskScore });
</script>
<style scoped>
.card {
@apply bg-white rounded-lg p-4 shadow-sm border border-gray-100;
}
.header-box {
@apply rounded-lg mb-4 p-4;
background: linear-gradient(135deg, #00897b 0%, #00695c 100%);
color: #fff;
}
.header-title {
@apply text-lg font-semibold m-0;
}
.header-desc {
@apply text-sm mt-1 opacity-90 m-0;
}
.result-section {
@apply rounded-xl p-5 text-center mb-4;
}
.result-section.match {
background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);
border: 1px solid rgba(76, 175, 80, 0.3);
}
.result-section.mismatch {
background: linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%);
border: 1px solid rgba(244, 67, 54, 0.3);
}
.result-section.unknown {
@apply bg-gray-50 border border-gray-200;
}
.result-icon-wrap {
@apply mb-2;
}
.result-icon {
@apply inline-flex items-center justify-center w-12 h-12 rounded-full text-2xl font-bold text-white;
}
.result-icon.icon-match {
background: linear-gradient(135deg, #43a047 0%, #2e7d32 100%);
box-shadow: 0 2px 8px rgba(76, 175, 80, 0.4);
}
.result-icon.icon-mismatch {
background: linear-gradient(135deg, #e53935 0%, #c62828 100%);
box-shadow: 0 2px 8px rgba(244, 67, 54, 0.4);
}
.result-icon.icon-unknown {
background: linear-gradient(135deg, #78909c 0%, #546e7a 100%);
box-shadow: 0 2px 8px rgba(96, 125, 139, 0.3);
}
.result-label {
@apply text-sm text-gray-500 mb-1;
}
.result-value {
@apply text-xl font-semibold;
}
.result-match {
color: #2e7d32;
}
.result-mismatch {
color: #c62828;
}
.result-unknown {
@apply text-gray-500;
}
.info-rows {
@apply space-y-3 pt-2 border-t border-gray-100;
}
.info-row {
@apply flex items-center text-sm;
}
.info-label {
@apply w-20 text-gray-500 shrink-0;
}
.info-value {
@apply font-medium text-gray-800;
}
</style>