2026-01-22 16:03:28 +08:00
|
|
|
|
<template>
|
2026-02-12 19:48:28 +08:00
|
|
|
|
<div class="inquire-bg min-h-screen relative" :class="isDefaultBackground ? 'pt-12' : 'pt-48'"
|
|
|
|
|
|
:style="backgroundStyle">
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<!-- 主要内容区域 - 覆盖背景图片 -->
|
|
|
|
|
|
<div class="min-h-screen relative mx-4 pb-12">
|
|
|
|
|
|
<div class="card-container">
|
2026-02-12 19:48:28 +08:00
|
|
|
|
<!-- 卡片头部:产品名 -->
|
|
|
|
|
|
<div class="card-header text-lg text-center font-bold text-gray-800 mb-4 pb-3 border-b border-gray-200">
|
|
|
|
|
|
{{ featureData.product_name }}
|
|
|
|
|
|
</div>
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<!-- 基本信息标题 -->
|
|
|
|
|
|
<div class="mb-6 flex items-center">
|
|
|
|
|
|
<SectionTitle title="基本信息" />
|
|
|
|
|
|
<div class="ml-auto flex items-center text-gray-600 cursor-pointer" @click="toExample">
|
|
|
|
|
|
<img src="@/assets/images/report/slbg_inquire_icon.png" alt="示例报告" class="w-4 h-4 mr-1" />
|
|
|
|
|
|
<span class="">示例报告</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 表单输入区域 -->
|
|
|
|
|
|
<div class="space-y-4 mb-6">
|
2026-02-12 19:48:28 +08:00
|
|
|
|
<!-- 姓名 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('name')">
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<label for="name" class="w-20 font-medium text-gray-700">姓名</label>
|
|
|
|
|
|
<input v-model="formData.name" id="name" type="text" placeholder="请输入正确的姓名"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
2026-02-12 19:48:28 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 身份证号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('idCard')">
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<label for="idCard" class="w-20 font-medium text-gray-700">身份证号</label>
|
|
|
|
|
|
<input v-model="formData.idCard" id="idCard" type="text" placeholder="请输入准确的身份证号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
2026-02-12 19:48:28 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 企业名称 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('entName')">
|
|
|
|
|
|
<label for="entName" class="w-20 font-medium text-gray-700">企业名称</label>
|
|
|
|
|
|
<input v-model="formData.entName" id="entName" type="text" placeholder="请输入企业名称"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 统一社会信用代码 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('entCode')">
|
|
|
|
|
|
<label for="entCode" class="w-32 font-medium text-gray-700">统一社会信用代码</label>
|
|
|
|
|
|
<input v-model="formData.entCode" id="entCode" type="text" placeholder="请输入统一社会信用代码"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 双人婚姻:男方姓名 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('nameMan')">
|
|
|
|
|
|
<label for="nameMan" class="w-24 font-medium text-gray-700">男方姓名</label>
|
|
|
|
|
|
<input v-model="formData.nameMan" id="nameMan" type="text" placeholder="请输入男方姓名"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 双人婚姻:男方身份证号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('idCardMan')">
|
|
|
|
|
|
<label for="idCardMan" class="w-28 font-medium text-gray-700">男方身份证号</label>
|
|
|
|
|
|
<input v-model="formData.idCardMan" id="idCardMan" type="text" placeholder="请输入男方身份证号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 双人婚姻:女方姓名 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('nameWoman')">
|
|
|
|
|
|
<label for="nameWoman" class="w-24 font-medium text-gray-700">女方姓名</label>
|
|
|
|
|
|
<input v-model="formData.nameWoman" id="nameWoman" type="text" placeholder="请输入女方姓名"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 双人婚姻:女方身份证号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('idCardWoman')">
|
|
|
|
|
|
<label for="idCardWoman" class="w-28 font-medium text-gray-700">女方身份证号</label>
|
|
|
|
|
|
<input v-model="formData.idCardWoman" id="idCardWoman" type="text" placeholder="请输入女方身份证号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 手机号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('mobile')">
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<label for="mobile" class="w-20 font-medium text-gray-700">手机号</label>
|
|
|
|
|
|
<input v-model="formData.mobile" id="mobile" type="tel" placeholder="请输入手机号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
2026-02-12 19:48:28 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 车牌号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('carLicense')">
|
|
|
|
|
|
<label for="carLicense" class="w-20 font-medium text-gray-700">车牌号</label>
|
|
|
|
|
|
<input v-model="formData.carLicense" id="carLicense" type="text" placeholder="请输入车牌号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 号牌类型 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('carType')">
|
|
|
|
|
|
<label for="carType" class="w-24 font-medium text-gray-700">号牌类型</label>
|
|
|
|
|
|
<input v-model="formData.carType" id="carType" type="text" placeholder="请输入号牌类型"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 关系类型(名下车辆数量) -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('userType')">
|
|
|
|
|
|
<label for="userType" class="w-28 font-medium text-gray-700">关系类型</label>
|
|
|
|
|
|
<div class="flex-1">
|
|
|
|
|
|
<van-field :model-value="userTypeDisplay" readonly is-link placeholder="请选择关系类型"
|
|
|
|
|
|
input-align="right" @click="showUserTypePicker = true" class="!p-0 !min-h-0" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<van-popup v-model:show="showUserTypePicker" round position="bottom">
|
|
|
|
|
|
<van-picker :columns="userTypeOptions" @confirm="onUserTypeConfirm"
|
|
|
|
|
|
@cancel="showUserTypePicker = false" />
|
|
|
|
|
|
</van-popup>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 车架号/VIN -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('vinCode')">
|
|
|
|
|
|
<label for="vinCode" class="w-24 font-medium text-gray-700">车架号/VIN</label>
|
|
|
|
|
|
<input v-model="formData.vinCode" id="vinCode" type="text" placeholder="请输入车架号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 行驶证图片 URL(里程混合等):行驶证形状框上传,接口返回 URL,限制 3MB -->
|
|
|
|
|
|
<div class="py-3 border-b border-gray-100" v-if="isHasInput('imageUrl')">
|
|
|
|
|
|
<p class="text-sm text-gray-600 mb-2">上传行驶证照片(将生成可访问链接)</p>
|
|
|
|
|
|
<input ref="imageUrlFileInputRef" type="file" accept="image/*" class="hidden"
|
|
|
|
|
|
@change="onImageUrlFileChange" />
|
|
|
|
|
|
<div class="vlphoto-frame" role="button" tabindex="0" @click="imageUrlFileInputRef?.click()"
|
|
|
|
|
|
@keydown.enter.space.prevent="imageUrlFileInputRef?.click()">
|
|
|
|
|
|
<img v-if="formData.imageUrl" :src="formData.imageUrl" alt="行驶证" class="vlphoto-preview"
|
|
|
|
|
|
@error="onImageUrlError" />
|
|
|
|
|
|
<div v-else class="vlphoto-placeholder">
|
|
|
|
|
|
<span v-if="imageUrlUploading" class="vlphoto-hint">上传中...</span>
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
|
<span class="vlphoto-icon">📄</span>
|
|
|
|
|
|
<span class="vlphoto-hint">点击上传行驶证</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p class="mt-1 text-xs text-amber-600">图片不能超过 3M</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 车辆所在地区 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('vehicleLocation')">
|
|
|
|
|
|
<label for="vehicleLocation" class="w-28 font-medium text-gray-700">车辆所在地区</label>
|
|
|
|
|
|
<input v-model="formData.vehicleLocation" id="vehicleLocation" type="text" placeholder="必填"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 初次登记日期 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100"
|
|
|
|
|
|
v-if="isHasInput('firstRegistrationDate')">
|
|
|
|
|
|
<label for="firstRegistrationDate" class="w-28 font-medium text-gray-700">初次登记日期</label>
|
|
|
|
|
|
<div class="flex-1">
|
|
|
|
|
|
<van-field :model-value="firstRegistrationDateDisplay" readonly is-link placeholder="请选择日期"
|
|
|
|
|
|
input-align="right" @click="openFirstRegistrationDatePicker" class="!p-0 !min-h-0" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<van-popup v-model:show="showFirstRegistrationDatePicker" round position="bottom">
|
|
|
|
|
|
<van-date-picker v-model="firstRegistrationDateColumns" title="选择初次登记日期"
|
|
|
|
|
|
:columns-type="['year', 'month']" @confirm="onFirstRegistrationDateConfirm"
|
|
|
|
|
|
@cancel="showFirstRegistrationDatePicker = false" />
|
|
|
|
|
|
</van-popup>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 行驶证图片上传(出险详版):行驶证形状框,点击上传,限制 3MB -->
|
|
|
|
|
|
<div class="py-3 border-b border-gray-100" v-if="isHasInput('vlphotoData')">
|
|
|
|
|
|
<p class="text-sm text-gray-600 mb-2">上传行驶证照片</p>
|
|
|
|
|
|
<input ref="vlphotoFileInputRef" type="file" accept="image/*" class="hidden"
|
|
|
|
|
|
@change="onVlphotoFileChange" />
|
|
|
|
|
|
<div class="vlphoto-frame" role="button" tabindex="0" @click="vlphotoFileInputRef?.click()"
|
|
|
|
|
|
@keydown.enter.space.prevent="vlphotoFileInputRef?.click()">
|
|
|
|
|
|
<img v-if="vlphotoPreviewUrl" :src="vlphotoPreviewUrl" alt="行驶证" class="vlphoto-preview" />
|
|
|
|
|
|
<div v-else class="vlphoto-placeholder">
|
|
|
|
|
|
<span class="vlphoto-icon">📄</span>
|
|
|
|
|
|
<span class="vlphoto-hint">点击上传行驶证</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p class="mt-1 text-xs text-amber-600">图片不能超过 3M</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 银行卡号 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('bankCard')">
|
|
|
|
|
|
<label for="bankCard" class="w-24 font-medium text-gray-700">银行卡号</label>
|
|
|
|
|
|
<input v-model="formData.bankCard" id="bankCard" type="text" placeholder="请输入银行卡号"
|
|
|
|
|
|
class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 人像图片上传(公安三要素):人像照片框,点击上传,限制 500KB,jpg/png,15~4000px -->
|
|
|
|
|
|
<div class="py-3 border-b border-gray-100" v-if="isHasInput('photoData')">
|
|
|
|
|
|
<p class="text-sm text-gray-600 mb-2">上传人像照片</p>
|
|
|
|
|
|
<input type="file" accept="image/jpeg,image/png" class="hidden" ref="photoDataInputRef"
|
|
|
|
|
|
@change="onPhotoDataFileChange" />
|
|
|
|
|
|
<div class="vlphoto-frame" role="button" tabindex="0" @click="photoDataInputRef?.click()"
|
|
|
|
|
|
@keydown.enter.space.prevent="photoDataInputRef?.click()">
|
|
|
|
|
|
<img v-if="photoDataPreviewUrl" :src="photoDataPreviewUrl" alt="人像照片"
|
|
|
|
|
|
class="vlphoto-preview" />
|
|
|
|
|
|
<div v-else class="vlphoto-placeholder">
|
|
|
|
|
|
<span class="vlphoto-icon">📷</span>
|
|
|
|
|
|
<span class="vlphoto-hint">点击上传人像照片</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p class="mt-1 text-xs text-amber-600">
|
|
|
|
|
|
图片格式需为 jpg/png,大小不超过 500KB,宽高需在 15px ~ 4000px 之间
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 是否取得用户授权 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('authorized')">
|
|
|
|
|
|
<label for="authorized" class="w-32 font-medium text-gray-700">用户授权</label>
|
|
|
|
|
|
<div class="flex-1">
|
|
|
|
|
|
<van-field :model-value="authorizedDisplay" readonly is-link placeholder="请选择"
|
|
|
|
|
|
input-align="right" @click="showAuthorizedPicker = true" class="!p-0 !min-h-0" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<van-popup v-model:show="showAuthorizedPicker" round position="bottom">
|
|
|
|
|
|
<van-picker :columns="authorizedOptions" @confirm="onAuthorizedConfirm"
|
|
|
|
|
|
@cancel="showAuthorizedPicker = false" />
|
|
|
|
|
|
</van-popup>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 验证码 -->
|
|
|
|
|
|
<div class="flex items-center py-3 border-b border-gray-100" v-if="isHasInput('verificationCode')">
|
2026-01-22 16:03:28 +08:00
|
|
|
|
<label for="verificationCode" class="w-20 font-medium text-gray-700">验证码</label>
|
|
|
|
|
|
<input v-model="formData.verificationCode" id="verificationCode" placeholder="请输入验证码"
|
|
|
|
|
|
maxlength="6" class="flex-1 border-none outline-none" @click="handleInputClick" />
|
|
|
|
|
|
<button class="text-primary font-medium text-nowrap"
|
|
|
|
|
|
:disabled="isCountingDown || !isPhoneNumberValid" @click="sendVerificationCode">
|
|
|
|
|
|
{{
|
|
|
|
|
|
isCountingDown
|
|
|
|
|
|
? `${countdown}s重新获取`
|
|
|
|
|
|
: "获取验证码"
|
|
|
|
|
|
}}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 协议同意 -->
|
|
|
|
|
|
<div class="flex items-center mb-6">
|
|
|
|
|
|
<input type="checkbox" v-model="formData.agreeToTerms" class="mr-3 accent-primary" />
|
|
|
|
|
|
<span class="text-sm text-gray-500">
|
|
|
|
|
|
我已阅读并同意
|
|
|
|
|
|
<span @click="toUserAgreement" class="text-primary cursor-pointer">《用户协议》</span>
|
|
|
|
|
|
<span @click="toPrivacyPolicy" class="text-primary cursor-pointer">《隐私政策》</span>
|
|
|
|
|
|
<span @click="toAuthorization" class="text-primary cursor-pointer">《授权书》</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 查询按钮 -->
|
|
|
|
|
|
<button
|
|
|
|
|
|
class="w-full bg-primary text-white py-4 rounded-[48px] text-lg font-medium mb-4 flex items-center justify-center mt-10"
|
|
|
|
|
|
@click="handleSubmit">
|
|
|
|
|
|
<span>{{ buttonText }}</span>
|
|
|
|
|
|
<span class="ml-4">¥{{ featureData.sell_price }}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<!-- <div class="text-xs text-gray-500 leading-relaxed mt-8" v-html="featureData.description">
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<!-- 免责声明 -->
|
|
|
|
|
|
<div class="text-xs text-center text-gray-500 leading-relaxed mt-2">
|
|
|
|
|
|
为保证用户的隐私及数据安全,查询结果生成30天后将自动删除
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 报告包含内容 -->
|
|
|
|
|
|
<div class="card mt-3" v-if="featureData.features && featureData.features.length > 1">
|
|
|
|
|
|
<div class="mb-3 text-base font-semibold flex items-center" style="color: var(--van-text-color);">
|
|
|
|
|
|
<div class="w-1 h-5 rounded-full mr-2"
|
|
|
|
|
|
style="background: linear-gradient(to bottom, var(--van-theme-primary), var(--van-theme-primary-dark));">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
报告包含内容
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="grid grid-cols-4 gap-2">
|
|
|
|
|
|
<template v-for="(feature, index) in featureData.features" :key="feature.id">
|
|
|
|
|
|
<!-- FLXG0V4B 特殊处理:显示8个独立的案件类型 -->
|
|
|
|
|
|
<template v-if="feature.api_id === 'FLXG0V4B'">
|
|
|
|
|
|
<div v-for="(caseType, caseIndex) in [
|
|
|
|
|
|
{ name: '管辖案件', icon: 'beijianguanrenyuan.svg' },
|
|
|
|
|
|
{ name: '刑事案件', icon: 'xingshi.svg' },
|
|
|
|
|
|
{ name: '民事案件', icon: 'minshianjianguanli.svg' },
|
|
|
|
|
|
{ name: '失信被执行', icon: 'shixinren.svg' },
|
|
|
|
|
|
{ name: '行政案件', icon: 'xingzhengfuwu.svg' },
|
|
|
|
|
|
{ name: '赔偿案件', icon: 'yuepeichang.svg' },
|
|
|
|
|
|
{ name: '执行案件', icon: 'zhixinganjian.svg' },
|
|
|
|
|
|
{ name: '限高被执行', icon: 'xianzhigaoxiaofei.svg' },
|
|
|
|
|
|
]" :key="`${feature.id}-${caseIndex}`"
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-center p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index + caseIndex)">
|
|
|
|
|
|
<div class="mb-1">
|
|
|
|
|
|
<img :src="`/inquire_icons/${caseType.icon}`" :alt="caseType.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm mx-auto" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight font-medium"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.1; min-height: 28px; display: flex; align-items: center; justify-content: center;">
|
|
|
|
|
|
{{ caseType.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- DWBG8B4D 特殊处理:显示拆分模块 -->
|
|
|
|
|
|
<template v-else-if="feature.api_id === 'DWBG8B4D'">
|
|
|
|
|
|
<div v-for="(module, moduleIndex) in [
|
|
|
|
|
|
{ name: '要素核查', icon: 'beijianguanrenyuan.svg' },
|
|
|
|
|
|
{ name: '运营商核验', icon: 'mingxiacheliang.svg' },
|
|
|
|
|
|
{ name: '公安重点人员检验', icon: 'xingshi.svg' },
|
|
|
|
|
|
{ name: '逾期风险综述', icon: 'huankuanyali.svg' },
|
|
|
|
|
|
{ name: '法院曝光台信息', icon: 'sifasheyu.svg' },
|
|
|
|
|
|
{ name: '借贷评估', icon: 'jiedaishenqing.svg' },
|
|
|
|
|
|
{ name: '租赁风险评估', icon: 'jiedaixingwei.svg' },
|
|
|
|
|
|
{ name: '关联风险监督', icon: 'renqiguanxi.svg' },
|
|
|
|
|
|
{ name: '规则风险提示', icon: 'fengxianxingwei.svg' },
|
|
|
|
|
|
]" :key="`${feature.id}-${moduleIndex}`"
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-center p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index + moduleIndex)">
|
|
|
|
|
|
<div class="text-xl mb-1 flex items-center justify-center">
|
|
|
|
|
|
<img :src="`/inquire_icons/${module.icon}`" :alt="module.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight px-1 font-medium"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.2">
|
|
|
|
|
|
{{ module.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- CJRZQ5E9F 特殊处理:显示拆分模块 -->
|
|
|
|
|
|
<template v-else-if="feature.api_id === 'JRZQ5E9F'">
|
|
|
|
|
|
<div v-for="(module, moduleIndex) in [
|
|
|
|
|
|
{ name: '信用评分', icon: 'huankuanyali.svg' },
|
|
|
|
|
|
{ name: '贷款行为分析', icon: 'jiedaixingwei.svg' },
|
|
|
|
|
|
{ name: '机构分析', icon: 'jiedaishenqing.svg' },
|
|
|
|
|
|
{ name: '时间趋势分析', icon: 'zhixinganjian.svg' },
|
|
|
|
|
|
{ name: '风险指标详情', icon: 'fengxianxingwei.svg' },
|
|
|
|
|
|
{ name: '专业建议', icon: 'yuepeichang.svg' },
|
|
|
|
|
|
]" :key="`${feature.id}-${moduleIndex}`"
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-center p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index + moduleIndex)">
|
|
|
|
|
|
<div class="text-xl mb-1 flex items-center justify-center">
|
|
|
|
|
|
<img :src="`/inquire_icons/${module.icon}`" :alt="module.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight px-1 font-medium"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.2">
|
|
|
|
|
|
{{ module.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- PersonEnterprisePro/CQYGL3F8E 特殊处理:显示拆分模块 -->
|
|
|
|
|
|
<template v-else-if="feature.api_id === 'PersonEnterprisePro' || feature.api_id === 'QYGL3F8E'">
|
|
|
|
|
|
<div v-for="(module, moduleIndex) in [
|
|
|
|
|
|
{ name: '投资企业记录', icon: 'renqiguanxi.svg' },
|
|
|
|
|
|
{ name: '高管任职记录', icon: 'beijianguanrenyuan.svg' },
|
|
|
|
|
|
{ name: '涉诉风险', icon: 'sifasheyu.svg' },
|
|
|
|
|
|
{ name: '对外投资历史', icon: 'renqiguanxi.svg' },
|
|
|
|
|
|
{ name: '融资历史', icon: 'huankuanyali.svg' },
|
|
|
|
|
|
{ name: '行政处罚', icon: 'xingzhengfuwu.svg' },
|
|
|
|
|
|
{ name: '经营异常', icon: 'fengxianxingwei.svg' },
|
|
|
|
|
|
]" :key="`${feature.id}-${moduleIndex}`"
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-center p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index + moduleIndex)">
|
|
|
|
|
|
<div class="text-xl mb-1 flex items-center justify-center">
|
|
|
|
|
|
<img :src="`/inquire_icons/${module.icon}`" :alt="module.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight px-1 font-medium"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.2">
|
|
|
|
|
|
{{ module.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- DWBG6A2C 特殊处理:显示拆分模块 -->
|
|
|
|
|
|
<template v-else-if="feature.api_id === 'DWBG6A2C'">
|
|
|
|
|
|
<div v-for="(module, moduleIndex) in [
|
|
|
|
|
|
{ name: '命中风险标注', icon: 'fengxianxingwei.svg' },
|
|
|
|
|
|
{ name: '公安重点人员核验', icon: 'beijianguanrenyuan.svg' },
|
|
|
|
|
|
{ name: '涉赌涉诈人员核验', icon: 'xingshi.svg' },
|
|
|
|
|
|
{ name: '风险名单', icon: 'jiedaiweiyue.svg' },
|
|
|
|
|
|
{ name: '历史借贷行为', icon: 'jiedaixingwei.svg' },
|
|
|
|
|
|
{ name: '近24个月放款情况', icon: 'jiedaishenqing.svg' },
|
|
|
|
|
|
{ name: '履约情况', icon: 'huankuanyali.svg' },
|
|
|
|
|
|
{ name: '历史逾期记录', icon: 'jiedaiweiyue.svg' },
|
|
|
|
|
|
{ name: '授信详情', icon: 'huankuanyali.svg' },
|
|
|
|
|
|
{ name: '租赁行为', icon: 'mingxiacheliang.svg' },
|
|
|
|
|
|
{ name: '关联风险监督', icon: 'renqiguanxi.svg' },
|
|
|
|
|
|
{ name: '法院风险信息', icon: 'sifasheyu.svg' },
|
|
|
|
|
|
]" :key="`${feature.id}-${moduleIndex}`"
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-center p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index + moduleIndex)">
|
|
|
|
|
|
<div class="text-xl mb-1 flex items-center justify-center">
|
|
|
|
|
|
<img :src="`/inquire_icons/${module.icon}`" :alt="module.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight px-1 font-medium"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.2">
|
|
|
|
|
|
{{ module.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 其他功能正常显示 -->
|
|
|
|
|
|
<div v-else
|
|
|
|
|
|
class="aspect-square rounded-xl text-center text-sm text-gray-700 font-medium flex flex-col items-center justify-between p-2 shadow-lg"
|
|
|
|
|
|
:class="getCardClass(index)">
|
|
|
|
|
|
<div class="flex items-center justify-center flex-1">
|
|
|
|
|
|
<img :src="getFeatureIcon(feature.api_id)" :alt="feature.name"
|
|
|
|
|
|
class="w-6 h-6 drop-shadow-sm" @error="handleIconError" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="text-xs leading-tight font-medium h-8 flex items-center justify-center"
|
|
|
|
|
|
style="word-break: break-all; line-height: 1.1">
|
|
|
|
|
|
{{ feature.name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mt-3 text-center">
|
|
|
|
|
|
<div class="inline-flex items-center px-3 py-1.5 rounded-full border transition-all"
|
|
|
|
|
|
style="background: linear-gradient(135deg, var(--van-theme-primary-light), rgba(255,255,255,0.8)); border-color: var(--van-theme-primary);">
|
|
|
|
|
|
<div class="w-1.5 h-1.5 rounded-full mr-1.5"
|
|
|
|
|
|
style="background-color: var(--van-theme-primary);">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="text-xs font-medium" style="color: var(--van-theme-primary);">更多信息请解锁报告</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 产品详情卡片 -->
|
|
|
|
|
|
<div class="card mt-4">
|
|
|
|
|
|
<div class="mb-4 text-xl font-bold" style="color: var(--van-text-color);">
|
|
|
|
|
|
{{ featureData.product_name }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mb-4 flex items-start justify-between">
|
|
|
|
|
|
<div class="text-lg" style="color: var(--van-text-color-2);">价格:</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="text-2xl font-semibold text-danger">
|
|
|
|
|
|
¥{{ featureData.sell_price }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-4 leading-relaxed" style="color: var(--van-text-color-2);"
|
|
|
|
|
|
v-html="featureData.description">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mb-2 text-xs italic text-danger">
|
|
|
|
|
|
为保证用户的隐私以及数据安全,查询的结果生成30天之后将自动清除。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 支付组件 -->
|
|
|
|
|
|
<Payment v-model="showPayment" :data="featureData" :id="queryId" type="query" @close="showPayment = false" />
|
|
|
|
|
|
<BindPhoneDialog @bind-success="handleBindSuccess" />
|
|
|
|
|
|
<LoginDialog @login-success="handleLoginSuccess" />
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 历史查询按钮 - 仅推广查询且已登录时显示 -->
|
|
|
|
|
|
<div v-if="props.type === 'promotion' && isLoggedIn" @click="toHistory"
|
|
|
|
|
|
class="fixed right-2 top-3/4 px-4 py-2 text-sm bg-primary rounded-xl cursor-pointer text-white font-bold shadow active:bg-blue-500">
|
|
|
|
|
|
历史查询
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-02-12 19:48:28 +08:00
|
|
|
|
import { ref, computed, onMounted, onUnmounted, nextTick } from "vue";
|
2026-01-22 16:03:28 +08:00
|
|
|
|
import { aesEncrypt } from "@/utils/crypto";
|
|
|
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
|
|
|
import { useUserStore } from "@/stores/userStore";
|
|
|
|
|
|
import { useDialogStore } from "@/stores/dialogStore";
|
|
|
|
|
|
import { useEnv } from "@/composables/useEnv";
|
2026-02-12 19:48:28 +08:00
|
|
|
|
import { showConfirmDialog, showToast, DatePicker } from "vant";
|
|
|
|
|
|
import { useInquireForm } from "@/composables/useInquireForm";
|
2026-01-22 16:03:28 +08:00
|
|
|
|
|
|
|
|
|
|
import Payment from "@/components/Payment.vue";
|
|
|
|
|
|
import BindPhoneDialog from "@/components/BindPhoneDialog.vue";
|
|
|
|
|
|
import LoginDialog from "@/components/LoginDialog.vue";
|
|
|
|
|
|
import SectionTitle from "@/components/SectionTitle.vue";
|
|
|
|
|
|
|
|
|
|
|
|
// Props
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
// 查询类型:'normal' | 'promotion'
|
|
|
|
|
|
type: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'normal'
|
|
|
|
|
|
},
|
|
|
|
|
|
// 产品特征
|
|
|
|
|
|
feature: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
required: true
|
|
|
|
|
|
},
|
|
|
|
|
|
// 推广链接标识符(仅推广查询需要)
|
|
|
|
|
|
linkIdentifier: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
// 产品数据(从外部传入)
|
|
|
|
|
|
featureData: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => ({})
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
const { feature } = toRefs(props);
|
|
|
|
|
|
|
|
|
|
|
|
// Emits
|
|
|
|
|
|
const emit = defineEmits(['submit-success']);
|
|
|
|
|
|
|
|
|
|
|
|
// 动态导入产品背景图片的函数
|
|
|
|
|
|
const loadProductBackground = async (productType) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('1动态导入加载产品背景图片', productType);
|
|
|
|
|
|
switch (productType) {
|
|
|
|
|
|
case 'companyinfo':
|
|
|
|
|
|
return (await import("@/assets/images/report/xwqy_inquire_bg.jpg")).default;
|
|
|
|
|
|
case 'preloanbackgroundcheck':
|
|
|
|
|
|
return (await import("@/assets/images/report/dqfx_inquire_bg.jpg")).default;
|
|
|
|
|
|
case 'personalData':
|
|
|
|
|
|
return (await import("@/assets/images/report/grdsj_inquire_bg.jpg")).default;
|
|
|
|
|
|
case 'marriage':
|
|
|
|
|
|
console.log('2动态导入loadProductBackground :marriage_inquire_bg.jpg');
|
|
|
|
|
|
return (await import("@/assets/images/report/marriage_inquire_bg.jpg")).default;
|
|
|
|
|
|
case 'homeservice':
|
|
|
|
|
|
return (await import("@/assets/images/report/homeservice_inquire_bg.jpg")).default;
|
|
|
|
|
|
case 'backgroundcheck':
|
|
|
|
|
|
return (await import("@/assets/images/report/backgroundcheck_inquire_bg.png")).default;
|
|
|
|
|
|
default:
|
|
|
|
|
|
console.log('No matching case for product type:', productType);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.warn(`Failed to load background image for ${productType}:`, error);
|
|
|
|
|
|
console.log('Failed to load background image for ${productType}:', error);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const dialogStore = useDialogStore();
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
const { isWeChat } = useEnv();
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式数据
|
|
|
|
|
|
const showPayment = ref(false);
|
|
|
|
|
|
const pendingPayment = ref(false);
|
|
|
|
|
|
const queryId = ref(null);
|
|
|
|
|
|
const productBackground = ref('');
|
|
|
|
|
|
const isDefaultBackground = ref(false);
|
|
|
|
|
|
const isCountingDown = ref(false);
|
|
|
|
|
|
const countdown = ref(60);
|
2026-02-12 19:48:28 +08:00
|
|
|
|
const vlphotoFileInputRef = ref(null);
|
|
|
|
|
|
const vlphotoFileName = ref('');
|
|
|
|
|
|
const vlphotoPreviewUrl = ref('');
|
|
|
|
|
|
const photoDataInputRef = ref(null);
|
|
|
|
|
|
const photoDataFileName = ref('');
|
|
|
|
|
|
const photoDataPreviewUrl = ref('');
|
|
|
|
|
|
const imageUrlFileInputRef = ref(null);
|
|
|
|
|
|
const imageUrlUploading = ref(false);
|
|
|
|
|
|
const showUserTypePicker = ref(false);
|
|
|
|
|
|
const showAuthorizedPicker = ref(false);
|
|
|
|
|
|
const showFirstRegistrationDatePicker = ref(false);
|
|
|
|
|
|
// 初次登记日期(年、月)选择的列值,例如 ['2024', '01']
|
|
|
|
|
|
const firstRegistrationDateColumns = ref([]);
|
2026-01-22 16:03:28 +08:00
|
|
|
|
|
|
|
|
|
|
// 使用传入的featureData或创建响应式引用
|
|
|
|
|
|
const featureData = computed(() => props.featureData || {});
|
|
|
|
|
|
|
2026-02-12 19:48:28 +08:00
|
|
|
|
// 使用通用查询表单 composable(根据 feature 自动决定字段)
|
|
|
|
|
|
const { formData, isPhoneNumberValid, isIdCardValid, isHasInput, buildRequestPayload } = useInquireForm(feature);
|
|
|
|
|
|
|
|
|
|
|
|
const userTypeOptions = [
|
|
|
|
|
|
{ text: "ETC开户人", value: "1" },
|
|
|
|
|
|
{ text: "车辆所有人", value: "2" },
|
|
|
|
|
|
{ text: "ETC经办人", value: "3" },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const authorizedOptions = [
|
|
|
|
|
|
{ text: "是", value: "1" },
|
|
|
|
|
|
{ text: "否", value: "0" },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const userTypeDisplay = computed(() => {
|
|
|
|
|
|
const opt = userTypeOptions.find((o) => o.value === formData.userType);
|
|
|
|
|
|
return opt ? opt.text : "";
|
2026-01-22 16:03:28 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-12 19:48:28 +08:00
|
|
|
|
const authorizedDisplay = computed(() => {
|
|
|
|
|
|
const opt = authorizedOptions.find((o) => o.value === formData.authorized);
|
|
|
|
|
|
return opt ? opt.text : "";
|
2026-01-22 16:03:28 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-12 19:48:28 +08:00
|
|
|
|
const firstRegistrationDateDisplay = computed(() => formData.firstRegistrationDate || "");
|
|
|
|
|
|
|
|
|
|
|
|
// 额外字段校验(复用旧项目的规则思路)
|
|
|
|
|
|
const isIdCardManValid = computed(() => /^\d{17}[\dX]$/i.test(formData.idCardMan || ""));
|
|
|
|
|
|
const isIdCardWomanValid = computed(() => /^\d{17}[\dX]$/i.test(formData.idCardWoman || ""));
|
|
|
|
|
|
const isCreditCodeValid = computed(() => /^.{18}$/.test(formData.entCode || ""));
|
2026-01-22 16:03:28 +08:00
|
|
|
|
|
|
|
|
|
|
const isLoggedIn = computed(() => userStore.isLoggedIn);
|
|
|
|
|
|
|
|
|
|
|
|
const buttonText = computed(() => {
|
|
|
|
|
|
return isLoggedIn.value ? '立即查询' : '前往登录';
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取产品背景图片
|
|
|
|
|
|
const getProductBackground = computed(() => productBackground.value);
|
|
|
|
|
|
|
|
|
|
|
|
// 背景图片样式
|
|
|
|
|
|
const backgroundStyle = computed(() => {
|
|
|
|
|
|
console.log('getProductBackground', getProductBackground.value);
|
|
|
|
|
|
if (getProductBackground.value) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundImage: `url(${getProductBackground.value})`,
|
|
|
|
|
|
backgroundSize: 'contain',
|
|
|
|
|
|
backgroundPosition: 'center -20px',
|
|
|
|
|
|
backgroundRepeat: 'no-repeat',
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return {};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取功能图标
|
|
|
|
|
|
const getFeatureIcon = (apiId) => {
|
|
|
|
|
|
const iconMap = {
|
|
|
|
|
|
JRZQ4AA8: "/inquire_icons/huankuanyali.svg", // 还款压力
|
|
|
|
|
|
QCXG7A2B: "/inquire_icons/mingxiacheliang.svg", // 名下车辆
|
2026-02-12 19:48:28 +08:00
|
|
|
|
QCXGGB2Q: "/inquire_icons/mingxiacheliang.svg", // 人车核验简版
|
|
|
|
|
|
QCXGYTS2: "/inquire_icons/mingxiacheliang.svg", // 人车核验详版
|
|
|
|
|
|
QCXG5F3A: "/inquire_icons/mingxiacheliang.svg", // 名下车辆(车牌)
|
|
|
|
|
|
QCXG4D2E: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG5U0Z: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG1U4U: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXGY7F2: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG1H7Y: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG4I1Z: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG3Y6B: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG3Z3L: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXGP00W: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QCXG6B4E: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
IVYZ9K7F: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
IVYZA1B3: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
IVYZ6M8P: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
JRZQ8B3C: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSY3M8S: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYK9R4: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYF2T7: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYK8R3: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYS9W1: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYE7V5: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSYP0T4: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSY6F2B: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
YYSY9E4A: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
QYGL5F6A: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
JRZQACAB: "/inquire_icons/mingxiacheliang.svg",
|
|
|
|
|
|
JRZQ0B6Y: "/inquire_icons/mingxiacheliang.svg",
|
2026-01-22 16:03:28 +08:00
|
|
|
|
BehaviorRiskScan: "/inquire_icons/fengxianxingwei.svg", // 风险行为扫描
|
|
|
|
|
|
IVYZ5733: "/inquire_icons/hunyinzhuangtai.svg", // 婚姻状态
|
|
|
|
|
|
PersonEnterprisePro: "/inquire_icons/renqiguanxi.svg", // 人企关系加强版
|
|
|
|
|
|
JRZQ0A03: "/inquire_icons/jiedaishenqing.svg", // 借贷申请记录
|
|
|
|
|
|
FLXG3D56: "/inquire_icons/jiedaiweiyue.svg", // 借贷违约失信
|
|
|
|
|
|
FLXG0V4B: "/inquire_icons/sifasheyu.svg", // 司法涉诉
|
|
|
|
|
|
JRZQ8203: "/inquire_icons/jiedaixingwei.svg", // 借贷行为记录
|
|
|
|
|
|
JRZQ09J8: "/inquire_icons/beijianguanrenyuan.svg", // 收入评估
|
|
|
|
|
|
JRZQ4B6C: "/inquire_icons/fengxianxingwei.svg", // 探针C风险评估
|
|
|
|
|
|
};
|
|
|
|
|
|
return iconMap[apiId] || "/inquire_icons/default.svg";
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理图标加载错误
|
|
|
|
|
|
const handleIconError = (event) => {
|
|
|
|
|
|
event.target.style.display = "none";
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取卡片样式类
|
|
|
|
|
|
const getCardClass = (index) => {
|
|
|
|
|
|
const colorIndex = index % 4;
|
|
|
|
|
|
const colorClasses = [
|
|
|
|
|
|
'bg-gradient-to-br from-blue-50 via-blue-25 to-white border-2 border-blue-200',
|
|
|
|
|
|
'bg-gradient-to-br from-green-50 via-green-25 to-white border-2 border-green-200',
|
|
|
|
|
|
'bg-gradient-to-br from-purple-50 via-purple-25 to-white border-2 border-purple-200',
|
|
|
|
|
|
'bg-gradient-to-br from-orange-50 via-orange-25 to-white border-2 border-orange-200'
|
|
|
|
|
|
];
|
|
|
|
|
|
return colorClasses[colorIndex];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法
|
|
|
|
|
|
const validateField = (field, value, validationFn, errorMessage) => {
|
|
|
|
|
|
if (isHasInput(field) && !validationFn(value)) {
|
|
|
|
|
|
showToast({ message: errorMessage });
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-12 19:48:28 +08:00
|
|
|
|
const MAX_VLPHOTO_SIZE = 3 * 1024 * 1024; // 3MB
|
|
|
|
|
|
function onVlphotoFileChange(e) {
|
|
|
|
|
|
const file = e.target?.files?.[0];
|
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
if (file.size > MAX_VLPHOTO_SIZE) {
|
|
|
|
|
|
showToast({ message: '图片不能超过 3M' });
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
reader.onload = () => {
|
|
|
|
|
|
const dataUrl = reader.result;
|
|
|
|
|
|
let base64 = dataUrl;
|
|
|
|
|
|
if (typeof base64 === 'string' && base64.includes(',')) {
|
|
|
|
|
|
base64 = base64.split(',')[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
formData.vlphotoData = base64;
|
|
|
|
|
|
vlphotoFileName.value = file.name;
|
|
|
|
|
|
vlphotoPreviewUrl.value = dataUrl;
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const MAX_PHOTO_DATA_SIZE = 500 * 1024; // 500KB 公安三要素
|
|
|
|
|
|
function onPhotoDataFileChange(e) {
|
|
|
|
|
|
const file = e.target?.files?.[0];
|
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 大小校验
|
|
|
|
|
|
if (file.size > MAX_PHOTO_DATA_SIZE) {
|
|
|
|
|
|
showToast({ message: '人像图片不能超过 500KB' });
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
reader.onload = () => {
|
|
|
|
|
|
const dataUrl = reader.result;
|
|
|
|
|
|
if (typeof dataUrl !== 'string') {
|
|
|
|
|
|
showToast({ message: '图片读取失败,请重试' });
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尺寸校验:宽高需在 15px ~ 4000px 之间
|
|
|
|
|
|
const img = new Image();
|
|
|
|
|
|
img.onload = () => {
|
|
|
|
|
|
const w = img.width;
|
|
|
|
|
|
const h = img.height;
|
|
|
|
|
|
if (w < 15 || h < 15 || w > 4000 || h > 4000) {
|
|
|
|
|
|
showToast({ message: '人像图片宽高需在 15px ~ 4000px 之间' });
|
|
|
|
|
|
photoDataFileName.value = '';
|
|
|
|
|
|
photoDataPreviewUrl.value = '';
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let base64 = dataUrl;
|
|
|
|
|
|
if (typeof base64 === 'string' && base64.includes(',')) {
|
|
|
|
|
|
base64 = base64.split(',')[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
formData.photoData = base64;
|
|
|
|
|
|
photoDataFileName.value = file.name;
|
|
|
|
|
|
photoDataPreviewUrl.value = dataUrl;
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
img.onerror = () => {
|
|
|
|
|
|
showToast({ message: '图片格式不正确,请选择 jpg 或 png 图片' });
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
img.src = dataUrl;
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function onImageUrlFileChange(e) {
|
|
|
|
|
|
const file = e.target?.files?.[0];
|
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
if (file.size > MAX_VLPHOTO_SIZE) {
|
|
|
|
|
|
showToast({ message: '图片不能超过 3M' });
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
reader.onload = async () => {
|
|
|
|
|
|
let base64 = reader.result;
|
|
|
|
|
|
if (typeof base64 === 'string' && base64.includes(',')) {
|
|
|
|
|
|
base64 = base64.split(',')[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
imageUrlUploading.value = true;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { data, error } = await useApiFetch('/upload/image')
|
|
|
|
|
|
.post({ image_base64: base64 })
|
|
|
|
|
|
.json();
|
|
|
|
|
|
if (data.value && data.value.code === 200 && data.value.data?.url) {
|
|
|
|
|
|
formData.imageUrl = data.value.data.url;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showToast({ message: (data.value?.msg || error.value?.message) || '上传失败' });
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
imageUrlUploading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
e.target.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onImageUrlError() {
|
|
|
|
|
|
formData.imageUrl = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openFirstRegistrationDatePicker() {
|
|
|
|
|
|
if (formData.firstRegistrationDate) {
|
|
|
|
|
|
const [y, m] = (formData.firstRegistrationDate || "").split("-");
|
|
|
|
|
|
if (y && m) {
|
|
|
|
|
|
firstRegistrationDateColumns.value = [y, m];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const year = String(now.getFullYear());
|
|
|
|
|
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
|
|
|
|
firstRegistrationDateColumns.value = [year, month];
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const year = String(now.getFullYear());
|
|
|
|
|
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
|
|
|
|
firstRegistrationDateColumns.value = [year, month];
|
|
|
|
|
|
}
|
|
|
|
|
|
showFirstRegistrationDatePicker.value = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onFirstRegistrationDateConfirm({ selectedValues }) {
|
|
|
|
|
|
const [year, month] = selectedValues || [];
|
|
|
|
|
|
if (year && month) {
|
|
|
|
|
|
formData.firstRegistrationDate = `${year}-${month}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
showFirstRegistrationDatePicker.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onUserTypeConfirm({ selectedOptions }) {
|
|
|
|
|
|
const option = selectedOptions?.[0];
|
|
|
|
|
|
if (option) {
|
|
|
|
|
|
formData.userType = option.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
showUserTypePicker.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onAuthorizedConfirm({ selectedOptions }) {
|
|
|
|
|
|
const option = selectedOptions?.[0];
|
|
|
|
|
|
if (option) {
|
|
|
|
|
|
formData.authorized = option.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
showAuthorizedPicker.value = false;
|
|
|
|
|
|
}
|
2026-01-22 16:03:28 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理绑定手机号成功的回调
|
|
|
|
|
|
function handleBindSuccess() {
|
|
|
|
|
|
if (pendingPayment.value) {
|
|
|
|
|
|
pendingPayment.value = false;
|
|
|
|
|
|
submitRequest();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理登录成功的回调
|
|
|
|
|
|
function handleLoginSuccess() {
|
|
|
|
|
|
if (pendingPayment.value) {
|
|
|
|
|
|
pendingPayment.value = false;
|
|
|
|
|
|
submitRequest();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理输入框点击事件
|
|
|
|
|
|
const handleInputClick = async () => {
|
|
|
|
|
|
if (!isLoggedIn.value) {
|
|
|
|
|
|
// 非微信浏览器环境:未登录用户提示打开登录弹窗
|
|
|
|
|
|
if (!isWeChat.value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await showConfirmDialog({
|
|
|
|
|
|
title: '提示',
|
|
|
|
|
|
message: '您需要登录后才能进行查询,是否立即登录?',
|
|
|
|
|
|
confirmButtonText: '立即登录',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
});
|
|
|
|
|
|
dialogStore.openLogin();
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// 用户点击取消,什么都不做
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 微信浏览器环境:已登录但检查是否需要绑定手机号
|
|
|
|
|
|
if (isWeChat.value && !userStore.mobile) {
|
|
|
|
|
|
dialogStore.openBindPhone();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function handleSubmit() {
|
|
|
|
|
|
// 非微信浏览器环境:检查登录状态
|
|
|
|
|
|
if (!isWeChat.value && !isLoggedIn.value) {
|
|
|
|
|
|
dialogStore.openLogin();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 基本协议验证
|
|
|
|
|
|
if (!formData.agreeToTerms) {
|
|
|
|
|
|
showToast({ message: `请阅读并同意用户协议和隐私政策` });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
!validateField("name", formData.name, (v) => v, "请输入姓名") ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"mobile",
|
|
|
|
|
|
formData.mobile,
|
|
|
|
|
|
(v) => isPhoneNumberValid.value,
|
|
|
|
|
|
"请输入有效的手机号"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"idCard",
|
|
|
|
|
|
formData.idCard,
|
|
|
|
|
|
(v) => isIdCardValid.value,
|
|
|
|
|
|
"请输入有效的身份证号码"
|
|
|
|
|
|
) ||
|
2026-02-12 19:48:28 +08:00
|
|
|
|
!validateField(
|
|
|
|
|
|
"entName",
|
|
|
|
|
|
formData.entName,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入企业名称"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"entCode",
|
|
|
|
|
|
formData.entCode,
|
|
|
|
|
|
(v) => isCreditCodeValid.value,
|
|
|
|
|
|
"请输入统一社会信用代码"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"nameMan",
|
|
|
|
|
|
formData.nameMan,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入男方姓名"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"idCardMan",
|
|
|
|
|
|
formData.idCardMan,
|
|
|
|
|
|
(v) => isIdCardManValid.value,
|
|
|
|
|
|
"请输入有效的男方身份证号码"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"nameWoman",
|
|
|
|
|
|
formData.nameWoman,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入女方姓名"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"idCardWoman",
|
|
|
|
|
|
formData.idCardWoman,
|
|
|
|
|
|
(v) => isIdCardWomanValid.value,
|
|
|
|
|
|
"请输入有效的女方身份证号码"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"carLicense",
|
|
|
|
|
|
formData.carLicense,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入车牌号"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"carType",
|
|
|
|
|
|
formData.carType,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入号牌类型"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"vinCode",
|
|
|
|
|
|
formData.vinCode,
|
|
|
|
|
|
(v) => v && v.trim(),
|
|
|
|
|
|
"请输入车架号/VIN"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"imageUrl",
|
|
|
|
|
|
formData.imageUrl,
|
|
|
|
|
|
(v) => props.feature !== "toc_VehicleMileageMixed" || (v && v.trim()),
|
|
|
|
|
|
"请输入行驶证图片链接"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"vehicleLocation",
|
|
|
|
|
|
formData.vehicleLocation,
|
|
|
|
|
|
(v) => v && v.trim(),
|
|
|
|
|
|
"请输入车辆所在地区"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"firstRegistrationDate",
|
|
|
|
|
|
formData.firstRegistrationDate,
|
|
|
|
|
|
(v) => v && v.trim() && /^\d{4}-\d{2}$/.test(v.trim()),
|
|
|
|
|
|
"请输入初次登记日期(yyyy-MM)"
|
|
|
|
|
|
) ||
|
|
|
|
|
|
!validateField(
|
|
|
|
|
|
"vlphotoData",
|
|
|
|
|
|
formData.vlphotoData,
|
|
|
|
|
|
(v) => v && v.trim(),
|
|
|
|
|
|
"请提供行驶证图片(base64)"
|
|
|
|
|
|
) ||
|
2026-01-22 16:03:28 +08:00
|
|
|
|
!validateField(
|
|
|
|
|
|
"verificationCode",
|
|
|
|
|
|
formData.verificationCode,
|
|
|
|
|
|
(v) => v,
|
|
|
|
|
|
"请输入验证码"
|
|
|
|
|
|
)
|
|
|
|
|
|
) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否需要绑定手机号
|
|
|
|
|
|
if (!userStore.mobile) {
|
|
|
|
|
|
pendingPayment.value = true;
|
|
|
|
|
|
dialogStore.openBindPhone();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
submitRequest();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function submitRequest() {
|
2026-02-12 19:48:28 +08:00
|
|
|
|
// 根据当前 feature 与字段配置组装请求体
|
|
|
|
|
|
const req = buildRequestPayload();
|
2026-01-22 16:03:28 +08:00
|
|
|
|
const reqStr = JSON.stringify(req);
|
|
|
|
|
|
const encodeData = aesEncrypt(reqStr, "ff83609b2b24fc73196aac3d3dfb874f");
|
|
|
|
|
|
|
|
|
|
|
|
let apiUrl = '';
|
|
|
|
|
|
let requestData = { data: encodeData };
|
|
|
|
|
|
|
|
|
|
|
|
if (props.type === 'promotion') {
|
|
|
|
|
|
apiUrl = `/query/service_agent/${props.feature}`;
|
|
|
|
|
|
requestData.agent_identifier = props.linkIdentifier;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
apiUrl = `/query/service/${props.feature}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { data, error } = await useApiFetch(apiUrl)
|
|
|
|
|
|
.post(requestData)
|
|
|
|
|
|
.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (data.value.code === 200) {
|
|
|
|
|
|
queryId.value = data.value.data.id;
|
|
|
|
|
|
|
|
|
|
|
|
// 推广查询需要保存token
|
|
|
|
|
|
if (props.type === 'promotion') {
|
|
|
|
|
|
localStorage.setItem("token", data.value.data.accessToken);
|
|
|
|
|
|
localStorage.setItem("refreshAfter", data.value.data.refreshAfter);
|
|
|
|
|
|
localStorage.setItem("accessExpire", data.value.data.accessExpire);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
showPayment.value = true;
|
|
|
|
|
|
emit('submit-success', data.value.data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function sendVerificationCode() {
|
|
|
|
|
|
if (isCountingDown.value || !isPhoneNumberValid.value) return;
|
|
|
|
|
|
if (!isPhoneNumberValid.value) {
|
|
|
|
|
|
showToast({ message: "请输入有效的手机号" });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { data, error } = await useApiFetch("/auth/sendSms")
|
|
|
|
|
|
.post({ mobile: formData.mobile, actionType: "query" })
|
|
|
|
|
|
.json();
|
|
|
|
|
|
|
|
|
|
|
|
if (!error.value && data.value.code === 200) {
|
|
|
|
|
|
showToast({ message: "验证码发送成功", type: "success" });
|
|
|
|
|
|
startCountdown();
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
const verificationCodeInput = document.getElementById('verificationCode');
|
|
|
|
|
|
if (verificationCodeInput) {
|
|
|
|
|
|
verificationCodeInput.focus();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showToast({ message: "验证码发送失败,请重试" });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let timer = null;
|
|
|
|
|
|
|
|
|
|
|
|
function startCountdown() {
|
|
|
|
|
|
isCountingDown.value = true;
|
|
|
|
|
|
countdown.value = 60;
|
|
|
|
|
|
timer = setInterval(() => {
|
|
|
|
|
|
if (countdown.value > 0) {
|
|
|
|
|
|
countdown.value--;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
|
isCountingDown.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function toUserAgreement() {
|
|
|
|
|
|
router.push(`/userAgreement`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function toPrivacyPolicy() {
|
|
|
|
|
|
router.push(`/privacyPolicy`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function toAuthorization() {
|
|
|
|
|
|
router.push(`/authorization`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const toExample = () => {
|
|
|
|
|
|
router.push(`/example?feature=${props.feature}`);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toHistory = () => {
|
|
|
|
|
|
router.push("/historyQuery");
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 生命周期
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
await loadBackgroundImage();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 加载背景图片
|
|
|
|
|
|
const loadBackgroundImage = async () => {
|
|
|
|
|
|
console.log(' 加载背景图片loadBackgroundImage :feature', props.feature);
|
|
|
|
|
|
const background = await loadProductBackground(props.feature);
|
|
|
|
|
|
if (background) {
|
|
|
|
|
|
productBackground.value = background;
|
|
|
|
|
|
isDefaultBackground.value = false;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 未匹配到背景时,使用默认背景 bg_2.png
|
|
|
|
|
|
try {
|
|
|
|
|
|
const defaultBgModule = await import("@/assets/images/bg_2.png");
|
|
|
|
|
|
productBackground.value = defaultBgModule.default;
|
|
|
|
|
|
isDefaultBackground.value = true;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.warn('Failed to load default background bg_2.png:', error);
|
|
|
|
|
|
productBackground.value = '';
|
|
|
|
|
|
isDefaultBackground.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
if (timer) {
|
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
watch(feature, async () => {
|
|
|
|
|
|
await loadBackgroundImage();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
/* 背景样式 */
|
|
|
|
|
|
.inquire-bg {
|
|
|
|
|
|
background-color: #D2DFFA;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 卡片样式优化 */
|
|
|
|
|
|
.card {
|
|
|
|
|
|
@apply shadow-lg rounded-xl p-6 transition-all hover:shadow-xl;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.95);
|
|
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
|
|
|
|
0 2px 4px -1px rgba(0, 0, 0, 0.06),
|
|
|
|
|
|
0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 按钮悬停效果 */
|
|
|
|
|
|
button:hover {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
button:active {
|
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 卡片容器样式 */
|
|
|
|
|
|
.card-container {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-radius: 8px;
|
2026-02-12 19:48:28 +08:00
|
|
|
|
padding: 16px;
|
2026-01-22 16:03:28 +08:00
|
|
|
|
box-shadow: 0px 0px 24px 0px #3F3F3F0F;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-container input::placeholder {
|
|
|
|
|
|
color: #DDDDDD;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 功能标签样式 */
|
|
|
|
|
|
.feature-tag {
|
|
|
|
|
|
background-color: var(--color-primary-light);
|
|
|
|
|
|
color: var(--color-primary);
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
border-radius: 9999px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 功能标签圆点 */
|
|
|
|
|
|
.feature-dot {
|
|
|
|
|
|
width: 6px;
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
background-color: var(--color-primary);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
|
}
|
2026-02-12 19:48:28 +08:00
|
|
|
|
|
|
|
|
|
|
/* 行驶证形状上传框 */
|
|
|
|
|
|
.vlphoto-frame {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
max-width: 320px;
|
|
|
|
|
|
aspect-ratio: 1.55;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
border-radius: 14px;
|
|
|
|
|
|
border: 2px dashed #c9c9c9;
|
|
|
|
|
|
background: linear-gradient(145deg, #f8f9fa 0%, #eef0f2 100%);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: border-color 0.2s, background 0.2s;
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-frame:hover {
|
|
|
|
|
|
border-color: var(--color-primary, #2563eb);
|
|
|
|
|
|
background: linear-gradient(145deg, #f0f4ff 0%, #e8eeff 100%);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-frame:focus-visible {
|
|
|
|
|
|
border-color: var(--color-primary, #2563eb);
|
|
|
|
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-preview {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-placeholder {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-icon {
|
|
|
|
|
|
font-size: 2.5rem;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vlphoto-hint {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
}
|
2026-01-22 16:03:28 +08:00
|
|
|
|
</style>
|