Files
bdrp-app/_backup/pages/components/InquireForm.vue

885 lines
30 KiB
Vue
Raw Normal View History

2026-04-20 16:42:28 +08:00
<script setup>
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
import BindPhoneDialog from '@/components/BindPhoneDialog.vue'
import LoginDialog from '@/components/LoginDialog.vue'
import Payment from '@/components/Payment.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { useRouter } from '@/composables/uni-router'
2026-04-23 14:57:35 +08:00
import { useAppConfig } from '@/composables/useAppConfig'
2026-04-20 16:42:28 +08:00
import { useDialogStore } from '@/stores/dialogStore'
import { useUserStore } from '@/stores/userStore'
import { aesEncrypt } from '@/utils/crypto'
import { setAuthSession } from '@/utils/storage'
// Props
const props = defineProps({
// 查询类型:'normal' | 'promotion'
type: {
type: String,
default: 'normal',
},
// 产品特征
feature: {
type: String,
required: true,
},
// 推广链接标识符(仅推广查询需要)
linkIdentifier: {
type: String,
default: '',
},
// 产品数据(从外部传入)
featureData: {
type: Object,
default: () => ({}),
},
})
// Emits
const emit = defineEmits(['submit-success'])
const PRODUCT_BACKGROUND_MAP = {
companyinfo: '/static/images/product/xwqy_inquire_bg.png',
preloanbackgroundcheck: '/static/images/product/dqfx_inquire_bg.png',
personalData: '/static/images/product/grdsj_inquire_bg.png',
marriage: '/static/images/product/marriage_inquire_bg.png',
homeservice: '/static/images/product/homeservice_inquire_bg.png',
backgroundcheck: '/static/images/product/backgroundcheck_inquire_bg.png',
rentalinfo: '/static/images/product/rentalinfo_inquire_bg.png',
}
const TRAPEZOID_BACKGROUND_MAP = {
marriage: '/static/images/report/title_inquire_bg_red.png',
homeservice: '/static/images/report/title_inquire_bg_green.png',
default: '/static/images/report/title_inquire_bg.png',
}
function showToast(options) {
const message = typeof options === 'string' ? options : (options?.message || options?.title || '')
if (!message)
return
uni.showToast({
title: message,
icon: options?.type === 'success' ? 'success' : 'none',
})
}
const { feature } = toRefs(props)
function loadProductBackground(productType) {
return PRODUCT_BACKGROUND_MAP[productType] || ''
}
const router = useRouter()
const dialogStore = useDialogStore()
const userStore = useUserStore()
2026-04-23 14:57:35 +08:00
const isWeChat = ref(false)
const { appConfig, loadAppConfig } = useAppConfig()
2026-04-20 16:42:28 +08:00
// 响应式数据
const showPayment = ref(false)
const pendingPayment = ref(false)
const queryId = ref(null)
const productBackground = ref('')
const productMainImage = ref('')
const trapezoidBgImage = ref('')
const isCountingDown = ref(false)
const countdown = ref(60)
const verificationCodeInputRef = ref(null)
// 使用传入的featureData或创建响应式引用
const featureData = computed(() => props.featureData || {})
// 表单数据
const formData = reactive({
name: '',
idCard: '',
mobile: '',
verificationCode: '',
agreeToTerms: false,
})
// 计算属性
const isPhoneNumberValid = computed(() => {
return /^1[3-9]\d{9}$/.test(formData.mobile)
})
const isIdCardValid = computed(() => /^\d{17}[\dX]$/i.test(formData.idCard))
// 小微企业(companyinfo)暂不需要验证码
const needVerificationCode = computed(() => props.feature !== 'companyinfo')
const isLoggedIn = computed(() => userStore.isLoggedIn)
const buttonText = computed(() => {
return isLoggedIn.value ? '立即查询' : '前往登录'
})
const hasHeroImage = computed(() => Boolean(productBackground.value))
2026-04-23 14:57:35 +08:00
const queryRetentionDaysText = computed(() => `${appConfig.value.query.retention_days}`)
2026-04-20 16:42:28 +08:00
function loadTrapezoidBackground() {
trapezoidBgImage.value = TRAPEZOID_BACKGROUND_MAP[props.feature] || TRAPEZOID_BACKGROUND_MAP.default
}
// 牌匾背景图片样式
const trapezoidBgStyle = computed(() => {
if (trapezoidBgImage.value) {
return {
backgroundImage: `url(${trapezoidBgImage.value})`,
}
}
return {}
})
// 牌匾文字样式
const trapezoidTextStyle = computed(() => {
// homeservice 和 marriage 使用白色文字
if (props.feature === 'homeservice' || props.feature === 'marriage') {
return {
color: 'white',
}
}
// 其他情况使用默认字体色(不设置 color使用浏览器默认或继承
return {}
})
// 获取功能图标
function getFeatureIcon(apiId) {
const iconMap = {
JRZQ4AA8: '/static/inquire_icons/huankuanyali.svg', // 还款压力
QCXG7A2B: '/static/inquire_icons/mingxiacheliang.svg', // 名下车辆
BehaviorRiskScan: '/static/inquire_icons/fengxianxingwei.svg', // 风险行为扫描
IVYZ5733: '/static/inquire_icons/hunyinzhuangtai.svg', // 婚姻状态
PersonEnterprisePro: '/static/inquire_icons/renqiguanxi.svg', // 人企关系加强版
JRZQ0A03: '/static/inquire_icons/jiedaishenqing.svg', // 借贷申请记录
FLXG3D56: '/static/inquire_icons/jiedaiweiyue.svg', // 借贷违约失信
FLXG0V4B: '/static/inquire_icons/sifasheyu.svg', // 司法涉诉
JRZQ8203: '/static/inquire_icons/jiedaixingwei.svg', // 借贷行为记录
JRZQ09J8: '/static/inquire_icons/beijianguanrenyuan.svg', // 收入评估
JRZQ4B6C: '/static/inquire_icons/fengxianxingwei.svg', // 探针C风险评估
}
return iconMap[apiId] || '/static/inquire_icons/default.svg'
}
// 处理图标加载错误
function handleIconError(event) {
event.target.style.display = 'none'
}
// 获取卡片样式类
function 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]
}
// 方法
function validateField(field, value, validationFn, errorMessage) {
if (isHasInput(field) && !validationFn(value)) {
showToast({ message: errorMessage })
return false
}
return true
}
const defaultInput = ['name', 'idCard', 'mobile', 'verificationCode']
function isHasInput(input) {
return defaultInput.includes(input)
}
// 处理绑定手机号成功的回调
function handleBindSuccess() {
if (pendingPayment.value) {
pendingPayment.value = false
submitRequest()
}
}
// 处理登录成功的回调
function handleLoginSuccess() {
if (pendingPayment.value) {
pendingPayment.value = false
submitRequest()
}
}
// 处理输入框点击事件
async function handleInputClick() {
if (!isLoggedIn.value) {
// 非微信浏览器环境:未登录用户提示打开登录弹窗
if (!isWeChat.value) {
const { confirm } = await uni.showModal({
title: '提示',
content: '您需要登录后才能进行查询,是否立即登录?',
confirmText: '立即登录',
cancelText: '取消',
})
if (confirm)
dialogStore.openLogin()
}
}
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, value => value, '请输入姓名')
|| !validateField(
'mobile',
formData.mobile,
() => isPhoneNumberValid.value,
'请输入有效的手机号',
)
|| !validateField(
'idCard',
formData.idCard,
() => isIdCardValid.value,
'请输入有效的身份证号码',
)
|| (needVerificationCode.value
&& !validateField(
'verificationCode',
formData.verificationCode,
value => value,
'请输入验证码',
))
) {
return
}
// 检查是否需要绑定手机号
if (!userStore.mobile) {
pendingPayment.value = true
dialogStore.openBindPhone()
}
else {
submitRequest()
}
}
async function submitRequest() {
const req = {
name: formData.name,
id_card: formData.idCard,
mobile: formData.mobile,
}
if (needVerificationCode.value) {
req.code = formData.verificationCode
}
const reqStr = JSON.stringify(req)
const inquireKey = import.meta.env.VITE_INQUIRE_AES_KEY
if (!inquireKey) {
throw new Error('缺少环境变量: VITE_INQUIRE_AES_KEY')
}
const encodeData = aesEncrypt(reqStr, inquireKey)
let apiUrl = ''
const 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 } = await useApiFetch(apiUrl)
.post(requestData)
.json()
if (data.value.code === 200) {
queryId.value = data.value.data.id
// 推广查询需要保存token
if (props.type === 'promotion') {
setAuthSession(data.value.data)
}
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', captchaVerifyParam: '' })
.json()
if (!error.value && data.value?.code === 200) {
showToast({ message: '验证码发送成功', type: 'success' })
startCountdown()
nextTick(() => {
verificationCodeInputRef.value?.focus?.()
})
}
else {
showToast({ message: data.value?.msg || '验证码发送失败,请重试' })
}
}
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`)
}
function toExample() {
router.push(`/example?feature=${props.feature}`)
}
function toHistory() {
router.push('/historyQuery')
}
// 生命周期
onMounted(async () => {
loadBackgroundImage()
loadTrapezoidBackground()
2026-04-23 14:57:35 +08:00
await loadAppConfig()
2026-04-20 16:42:28 +08:00
})
// 加载背景图片
async function loadBackgroundImage() {
productBackground.value = loadProductBackground(props.feature)
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
watch(feature, async () => {
loadBackgroundImage()
loadTrapezoidBackground()
})
</script>
<template>
<view class="inquire-bg relative min-h-screen">
<view v-if="hasHeroImage" class="hero-banner">
<image :src="productBackground" class="hero-banner-image" mode="widthFix" />
<view class="hero-banner-mask" />
<view class="hero-badge-wrap">
<view class="trapezoid-bg-image flex items-center justify-center" :style="trapezoidBgStyle">
<view class="whitespace-nowrap text-xl" :style="trapezoidTextStyle">
{{ featureData.product_name }}
</view>
</view>
</view>
</view>
<view class="content-wrap relative mx-4 min-h-screen pb-12" :class="{ 'with-hero': hasHeroImage }">
<view class="card-container">
<!-- 基本信息标题 -->
<view class="mb-6 flex items-center">
<SectionTitle title="基本信息" />
<view class="ml-auto flex cursor-pointer items-center text-gray-600" @click="toExample">
<image src="/static/images/report/slbg_inquire_icon.png" alt="示例报告" class="mr-1 h-4 w-4" />
<text class="">
示例报告
</text>
</view>
</view>
<!-- 表单输入区域 -->
<view class="mb-6 space-y-4">
<view class="flex items-center border-b border-gray-100 py-3">
2026-04-23 14:57:35 +08:00
<text class="w-20 text-gray-700 font-medium">
2026-04-20 16:42:28 +08:00
姓名
</text>
2026-04-23 14:57:35 +08:00
<wd-input
v-model="formData.name"
class="inquire-wd-input flex-1"
type="text"
placeholder="请输入正确的姓名"
no-border
clearable
@focus="handleInputClick"
/>
2026-04-20 16:42:28 +08:00
</view>
<view class="flex items-center border-b border-gray-100 py-3">
2026-04-23 14:57:35 +08:00
<text class="w-20 text-gray-700 font-medium">
2026-04-20 16:42:28 +08:00
身份证号
</text>
2026-04-23 14:57:35 +08:00
<wd-input
v-model="formData.idCard"
class="inquire-wd-input flex-1"
type="text"
placeholder="请输入准确的身份证号"
no-border
clearable
@focus="handleInputClick"
/>
2026-04-20 16:42:28 +08:00
</view>
<view class="flex items-center border-b border-gray-100 py-3">
2026-04-23 14:57:35 +08:00
<text class="w-20 text-gray-700 font-medium">
2026-04-20 16:42:28 +08:00
手机号
</text>
2026-04-23 14:57:35 +08:00
<wd-input
v-model="formData.mobile"
class="inquire-wd-input flex-1"
type="number"
placeholder="请输入手机号"
maxlength="11"
no-border
clearable
@focus="handleInputClick"
/>
2026-04-20 16:42:28 +08:00
</view>
<!-- 小微企业(companyinfo)暂不展示验证码 -->
<view v-if="needVerificationCode" class="flex items-center border-b border-gray-100 py-3">
2026-04-23 14:57:35 +08:00
<text class="w-20 text-gray-700 font-medium">
2026-04-20 16:42:28 +08:00
验证码
</text>
2026-04-23 14:57:35 +08:00
<wd-input
ref="verificationCodeInputRef"
v-model="formData.verificationCode"
class="inquire-wd-input flex-1"
placeholder="请输入验证码"
maxlength="6"
no-border
clearable
@focus="handleInputClick"
>
<template #suffix>
<wd-button
class="captcha-wd-btn"
size="small"
type="primary"
plain
:disabled="isCountingDown || !isPhoneNumberValid"
@click="sendVerificationCode"
>
{{ isCountingDown ? `${countdown}s` : '获取验证码' }}
</wd-button>
</template>
</wd-input>
2026-04-20 16:42:28 +08:00
</view>
</view>
<!-- 协议同意 -->
<view class="agreement-wrap mb-6">
<wd-checkbox v-model="formData.agreeToTerms" shape="square" size="18px" />
<view class="agreement-text">
<text class="text-sm text-gray-500">
我已阅读并同意
</text>
<text class="agreement-link" @click="toUserAgreement">
用户协议
</text>
<text class="agreement-link" @click="toPrivacyPolicy">
隐私政策
</text>
<text class="agreement-link" @click="toAuthorization">
授权书
</text>
</view>
</view>
<!-- 查询按钮 -->
2026-04-23 14:57:35 +08:00
<wd-button class="submit-wd-btn mb-4 mt-10" block type="primary" @click="handleSubmit">
<view class="w-full flex items-center justify-center">
<text>{{ buttonText }}</text>
<text class="ml-4">
¥{{ featureData.sell_price }}
</text>
</view>
</wd-button>
2026-04-20 16:42:28 +08:00
<!-- <view class="text-xs text-gray-500 leading-relaxed mt-8" v-html="featureData.description">
</view> -->
<!-- 免责声明 -->
<view class="mt-2 text-center text-xs text-gray-500 leading-relaxed">
2026-04-23 14:57:35 +08:00
为保证用户的隐私及数据安全查询结果生成{{ queryRetentionDaysText }}后将自动删除
2026-04-20 16:42:28 +08:00
</view>
</view>
<!-- 报告包含内容 -->
<view v-if="featureData.features && featureData.features.length > 0" class="card mt-3">
2026-04-23 14:57:35 +08:00
<view class="mb-3 flex items-center text-base font-semibold" style="color: var(--color-text-primary);">
2026-04-20 16:42:28 +08:00
<view class="mr-2 h-5 w-1 rounded-full"
2026-04-23 14:57:35 +08:00
style="background: linear-gradient(to bottom, var(--color-primary), var(--color-primary-700));" />
2026-04-20 16:42:28 +08:00
报告包含内容
</view>
<view class="grid grid-cols-4 items-stretch gap-2">
<template v-for="(item, index) in featureData.features" :key="item.id">
<!-- FLXG0V4B 特殊处理显示8个独立的案件类型 -->
<template v-if="item.api_id === 'FLXG0V4B'">
<view 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="`${item.id}-${caseIndex}`"
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index + caseIndex)">
<view class="mb-1 shrink-0">
<image :src="`/static/inquire_icons/${caseType.icon}`" :alt="caseType.name"
class="mx-auto h-6 w-6 drop-shadow-sm" @error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-0.5 text-xs font-medium leading-snug">
{{ caseType.name }}
</view>
</view>
</template>
<!-- DWBG8B4D 特殊处理显示拆分模块 -->
<template v-else-if="item.api_id === 'DWBG8B4D'">
<view 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="`${item.id}-${moduleIndex}`"
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index + moduleIndex)">
<view class="mb-1 flex shrink-0 items-center justify-center text-xl">
<image :src="`/static/inquire_icons/${module.icon}`" :alt="module.name" class="h-6 w-6 drop-shadow-sm"
@error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-1 text-xs font-medium leading-snug">
{{ module.name }}
</view>
</view>
</template>
<!-- CJRZQ5E9F 特殊处理显示拆分模块 -->
<template v-else-if="item.api_id === 'JRZQ5E9F'">
<view 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="`${item.id}-${moduleIndex}`"
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index + moduleIndex)">
<view class="mb-1 flex shrink-0 items-center justify-center text-xl">
<image :src="`/static/inquire_icons/${module.icon}`" :alt="module.name" class="h-6 w-6 drop-shadow-sm"
@error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-1 text-xs font-medium leading-snug">
{{ module.name }}
</view>
</view>
</template>
<!-- PersonEnterprisePro/CQYGL3F8E 特殊处理显示拆分模块 -->
<template v-else-if="item.api_id === 'PersonEnterprisePro' || item.api_id === 'QYGL3F8E'">
<view 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="`${item.id}-${moduleIndex}`"
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index + moduleIndex)">
<view class="mb-1 flex shrink-0 items-center justify-center text-xl">
<image :src="`/static/inquire_icons/${module.icon}`" :alt="module.name" class="h-6 w-6 drop-shadow-sm"
@error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-1 text-xs font-medium leading-snug">
{{ module.name }}
</view>
</view>
</template>
<!-- DWBG6A2C 特殊处理显示拆分模块 -->
<template v-else-if="item.api_id === 'DWBG6A2C'">
<view 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="`${item.id}-${moduleIndex}`"
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index + moduleIndex)">
<view class="mb-1 flex shrink-0 items-center justify-center text-xl">
<image :src="`/static/inquire_icons/${module.icon}`" :alt="module.name" class="h-6 w-6 drop-shadow-sm"
@error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-1 text-xs font-medium leading-snug">
{{ module.name }}
</view>
</view>
</template>
<!-- 其他功能正常显示 -->
<view v-else
class="h-full min-h-0 w-full flex flex-col items-center rounded-xl p-2 text-center text-sm text-gray-700 font-medium shadow-lg"
:class="getCardClass(index)">
<view class="mb-1 flex shrink-0 items-center justify-center">
<image :src="getFeatureIcon(item.api_id)" :alt="item.name" class="h-6 w-6 drop-shadow-sm"
@error="handleIconError" />
</view>
<view
class="w-full flex flex-1 items-center justify-center break-all px-1 text-xs font-medium leading-snug">
{{ item.name }}
</view>
</view>
</template>
</view>
<view class="mt-3 text-center">
<view class="inline-flex items-center border rounded-full px-3 py-1.5 transition-all"
2026-04-23 14:57:35 +08:00
style="background: linear-gradient(135deg, var(--color-primary-light), rgba(255,255,255,0.8)); border-color: var(--color-primary);">
<view class="mr-1.5 h-1.5 w-1.5 rounded-full" style="background-color: var(--color-primary);" />
<text class="text-xs font-medium" style="color: var(--color-primary);">
2026-04-20 16:42:28 +08:00
更多信息请解锁报告
</text>
</view>
</view>
</view>
<!-- 产品详情卡片 -->
<view class="card mt-4">
2026-04-23 14:57:35 +08:00
<view class="mb-4 text-xl font-bold" style="color: var(--color-text-primary);">
2026-04-20 16:42:28 +08:00
{{ featureData.product_name }}
</view>
<view class="mb-4 flex items-start justify-between">
2026-04-23 14:57:35 +08:00
<view class="text-lg" style="color: var(--color-text-secondary);">
2026-04-20 16:42:28 +08:00
价格
</view>
<view>
<view class="text-danger text-2xl font-semibold">
¥{{ featureData.sell_price }}
</view>
</view>
</view>
<image v-if="productMainImage" :src="productMainImage" alt="产品详情主图" class="mb-4 w-full rounded-lg" />
2026-04-23 14:57:35 +08:00
<view class="mb-4 leading-relaxed" style="color: var(--color-text-secondary);" v-html="featureData.description" />
2026-04-20 16:42:28 +08:00
<view class="text-danger mb-2 text-xs italic">
2026-04-23 14:57:35 +08:00
为保证用户的隐私以及数据安全查询的结果生成{{ queryRetentionDaysText }}之后将自动清除
2026-04-20 16:42:28 +08:00
</view>
</view>
</view>
<!-- 支付组件 -->
<Payment :id="queryId" v-model="showPayment" :data="featureData" type="query" @close="showPayment = false" />
<BindPhoneDialog @bind-success="handleBindSuccess" />
<LoginDialog @login-success="handleLoginSuccess" />
<!-- 历史查询按钮 - 仅推广查询且已登录时显示 -->
<view v-if="props.type === 'promotion' && isLoggedIn"
class="bg-primary fixed right-2 top-3/4 cursor-pointer rounded-xl px-4 py-2 text-sm text-white font-bold shadow active:bg-blue-500"
@click="toHistory">
历史查询
</view>
</view>
</template>
<style scoped>
/* 背景样式 */
.inquire-bg {
background-color: var(--color-primary-50);
min-height: 100vh;
position: relative;
}
.hero-banner {
position: relative;
overflow: hidden;
border-bottom-left-radius: 24px;
border-bottom-right-radius: 24px;
background: linear-gradient(180deg, #eef4ff 0%, #dfe9ff 100%);
}
.hero-banner-image {
display: block;
width: 100%;
margin-top: -2px;
}
.hero-banner-mask {
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(20, 32, 64, 0.04) 0%, rgba(20, 32, 64, 0.1) 100%);
pointer-events: none;
}
.hero-badge-wrap {
position: absolute;
left: 50%;
bottom: 34px;
transform: translateX(-50%);
width: 160px;
display: flex;
justify-content: center;
z-index: 3;
}
.content-wrap.with-hero {
margin-top: -68px;
padding-top: 0;
z-index: 2;
}
/* 卡片样式优化 */
.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);
}
/* 梯形背景图片样式 */
.trapezoid-bg-image {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
height: 44px;
width: 100%;
}
/* 卡片容器样式 */
.card-container {
background: white;
border-radius: 20px;
padding: 32px 16px;
box-shadow: 0px 0px 24px 0px #3F3F3F0F;
border: 1px solid rgba(255, 255, 255, 0.75);
}
.card-container input::placeholder {
color: #DDDDDD;
}
.captcha-wd-btn {
margin-left: 12px;
}
2026-04-23 14:57:35 +08:00
:deep(.inquire-wd-input .wd-input__inner) {
text-align: left !important;
}
:deep(.submit-wd-btn.wd-button) {
border-radius: 48px;
min-height: 48px;
}
2026-04-20 16:42:28 +08:00
:deep(.captcha-wd-btn.wd-button) {
min-width: 96px;
}
:deep(.captcha-wd-btn.wd-button.is-small) {
padding: 0 10px;
}
.agreement-wrap {
display: flex;
align-items: flex-start;
gap: 10px;
}
:deep(.agreement-wrap .wd-checkbox) {
margin-top: 1px;
}
.agreement-text {
flex: 1;
font-size: 13px;
line-height: 1.7;
word-break: break-all;
}
.agreement-link {
color: #2563eb;
}
/* 功能标签样式 */
.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;
}
</style>