213 lines
6.0 KiB
Vue
213 lines
6.0 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="card">
|
|||
|
|
<div class="header-box">
|
|||
|
|
<div class="header-left">
|
|||
|
|
<h3 class="header-title">车辆静态信息查询</h3>
|
|||
|
|
<p class="header-desc">查看车辆生产、排放标准及燃料等核心静态信息</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<template v-if="records && records.length">
|
|||
|
|
<div v-for="(item, idx) in records" :key="idx" class="vehicle-card">
|
|||
|
|
<div class="vehicle-title">
|
|||
|
|
<div>
|
|||
|
|
<div class="vehicle-chip">车辆 {{ idx + 1 }}</div>
|
|||
|
|
<div class="vehicle-model">
|
|||
|
|
{{ item.vType || '未知车型' }}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="vehicle-meta">
|
|||
|
|
<span class="badge">{{ item.vFuelType || '燃料未知' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="field-grid">
|
|||
|
|
<div class="field">
|
|||
|
|
<div class="field-label">发动机号</div>
|
|||
|
|
<div class="field-value code">{{ item.engineNO || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field">
|
|||
|
|
<div class="field-label">发动机型号</div>
|
|||
|
|
<div class="field-value code">{{ item.engineType || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field">
|
|||
|
|
<div class="field-label">生产日期</div>
|
|||
|
|
<div class="field-value">{{ item.vScdate || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field">
|
|||
|
|
<div class="field-label">排放阶段</div>
|
|||
|
|
<div class="field-value">{{ item.dischargeStage || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field">
|
|||
|
|
<div class="field-label">车辆分类</div>
|
|||
|
|
<div class="field-value">{{ item.vClassification || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field field-span">
|
|||
|
|
<div class="field-label">生产企业名称</div>
|
|||
|
|
<div class="field-value">{{ item.vManufacturer || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="field field-span">
|
|||
|
|
<div class="field-label">生产厂地址</div>
|
|||
|
|
<div class="field-value">{{ item.vSccdz || '-' }}</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<div v-else class="empty">
|
|||
|
|
<div class="icon">ℹ️</div>
|
|||
|
|
<div class="title">暂无车辆静态信息</div>
|
|||
|
|
<div class="sub">未查询到车辆静态信息或返回格式不正确</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { computed } from 'vue';
|
|||
|
|
import { useRiskNotifier } from '@/composables/useRiskNotifier';
|
|||
|
|
|
|||
|
|
const props = defineProps({
|
|||
|
|
data: { type: [Object, String, Array], default: () => ({}) },
|
|||
|
|
params: { type: Object, default: () => ({}) },
|
|||
|
|
apiId: { type: String, default: '' },
|
|||
|
|
index: { type: Number, default: 0 },
|
|||
|
|
notifyRiskStatus: { type: Function, default: () => { } },
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 解析返回的 JSON 字符串,得到数组
|
|||
|
|
const records = computed(() => {
|
|||
|
|
const raw = props.data;
|
|||
|
|
if (!raw) return [];
|
|||
|
|
|
|||
|
|
// data 本身是字符串
|
|||
|
|
if (typeof raw === 'string') {
|
|||
|
|
try {
|
|||
|
|
const parsed = JSON.parse(raw);
|
|||
|
|
if (Array.isArray(parsed)) return parsed;
|
|||
|
|
return [];
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// data 已经是数组
|
|||
|
|
if (Array.isArray(raw)) {
|
|||
|
|
return raw;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// data 是对象,里层再包了一层字符串/数组的情况
|
|||
|
|
if (typeof raw === 'object') {
|
|||
|
|
if (Array.isArray(raw.list)) return raw.list;
|
|||
|
|
if (typeof raw.data === 'string') {
|
|||
|
|
try {
|
|||
|
|
const parsed = JSON.parse(raw.data);
|
|||
|
|
if (Array.isArray(parsed)) return parsed;
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return [];
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const riskScore = computed(() => 100);
|
|||
|
|
useRiskNotifier(props, riskScore);
|
|||
|
|
defineExpose({ riskScore });
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.card {
|
|||
|
|
@apply bg-white rounded-2xl p-6 shadow-sm border border-gray-100;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-box {
|
|||
|
|
@apply rounded-2xl mb-5 px-5 py-4 bg-gradient-to-r from-blue-50 via-indigo-50 to-blue-50 flex items-center justify-between;
|
|||
|
|
color: #1e40af;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-title {
|
|||
|
|
@apply text-xl font-semibold m-0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-desc {
|
|||
|
|
@apply text-sm mt-2 m-0 opacity-80 text-gray-700;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-left {
|
|||
|
|
@apply flex flex-col;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-tag {
|
|||
|
|
@apply inline-flex items-center gap-2 px-3 py-1 rounded-full text-base font-medium bg-white/80 text-blue-700 shadow-sm;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-tag .dot {
|
|||
|
|
@apply w-2 h-2 rounded-full bg-green-500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-card {
|
|||
|
|
@apply mb-4 p-5 rounded-2xl border border-gray-100 bg-gray-50/80;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-title {
|
|||
|
|
@apply flex items-start justify-between text-base text-gray-700;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-title .label {
|
|||
|
|
@apply text-base uppercase tracking-wide text-gray-500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-title .value {
|
|||
|
|
@apply font-semibold text-lg text-gray-900 mt-1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-model {
|
|||
|
|
@apply text-base font-semibold text-gray-900 mt-1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.vehicle-meta {
|
|||
|
|
@apply flex items-center gap-2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.badge {
|
|||
|
|
@apply inline-flex items-center px-3 py-1 rounded-full text-base font-medium bg-blue-100 text-blue-700;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.field-label {
|
|||
|
|
@apply text-base text-gray-500 mb-1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.field-value {
|
|||
|
|
@apply text-base text-gray-900;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.field-value.code {
|
|||
|
|
@apply font-mono tracking-wide;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.field-grid {
|
|||
|
|
@apply grid gap-y-3 gap-x-6 mt-4;
|
|||
|
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.field-span {
|
|||
|
|
grid-column: 1 / -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty {
|
|||
|
|
@apply text-center py-10 text-gray-500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty .icon {
|
|||
|
|
@apply text-3xl mb-2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty .title {
|
|||
|
|
@apply text-base font-medium mb-1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty .sub {
|
|||
|
|
@apply text-base;
|
|||
|
|
}
|
|||
|
|
</style>
|