Files
qncV4uni-app/src/pages/index.vue
2026-05-23 12:14:40 +08:00

585 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { computed, ref } from 'vue'
import { getInquireCategoryConfig, getInquiryItemIconUrl } from '@/config/inquireCategories'
import { getToolboxItem } from '@/config/toolboxRegistry'
definePage({
style: {
navigationBarTitleText: '全能查',
navigationStyle: 'default',
navigationBarBackgroundColor: '#ffffff',
navigationBarTextStyle: 'black',
},
})
interface CaseItem {
id: string
tag: string
vin: string
model: string
}
interface ReviewItem {
id: string
name: string
content: string
}
const caseList = ref<CaseItem[]>([
{ id: '1', tag: '新能源电池查询', vin: 'LBV8********0981', model: '某品牌新能源车型' },
{ id: '2', tag: '里程异常检测', vin: 'LSGN********3389', model: '凯迪拉克 XT5' },
])
const vehicleItems = computed(() => getInquireCategoryConfig('vehicle')?.items ?? [])
/** 首页热门工具 2×5 网格 */
const hotTools = computed(() =>
['tianqishiju', 'jieqi', 'blood', 'zodiac', 'saylove', 'nethot', 'jixiong', 'naowan', 'joke', 'dujitang']
.map(key => getToolboxItem(key))
.filter(Boolean),
)
/** 每日推荐候选池 */
const dailyPool = [
'dream', 'oilprice',
'caihongpi', 'riddle', 'decide', 'caipu', 'godreply', 'tiangou',
'story', 'targa', 'hsjz', 'zimi', 'weather', 'calendar', 'constellation', 'goldprice'
]
/** 随机从候选池中抽取 n 个 */
function pickRandom(pool: string[], n: number): string[] {
const shuffled = [...pool].sort(() => Math.random() - 0.5)
return shuffled.slice(0, n)
}
const dailyKeys = ref<string[]>(pickRandom(dailyPool, 10))
const dailyPicks = computed(() =>
dailyKeys.value.map(key => getToolboxItem(key)).filter(Boolean),
)
function refreshDaily() {
dailyKeys.value = pickRandom(dailyPool, 10)
}
const reviewList = ref<ReviewItem[]>([
{ id: '1', name: '陈先生', content: '查完车况再成交,心里更踏实,避免了重大事故车。' },
{ id: '2', name: '周女士', content: '报告内容很详细,维保、出险一目了然,值得推荐。' },
])
function reviewInitial(name: string) {
return name.slice(0, 1) || '?'
}
function goInquireFeature(feature: string) {
uni.navigateTo({ url: `/pages/inquire/index?feature=${encodeURIComponent(feature)}` })
}
function goToolboxItem(key: string) {
uni.navigateTo({ url: `/pages/toolbox/query?key=${encodeURIComponent(key)}` })
}
function goCategory(categoryKey: string) {
uni.navigateTo({ url: `/pages/toolbox/category?category=${encodeURIComponent(categoryKey)}` })
}
function goVehicleList() {
uni.navigateTo({ url: '/pages/inquire/list' })
}
</script>
<template>
<view class="page-container">
<scroll-view scroll-y class="scroll-view">
<!-- 1. Banner 头部 -->
<view class="banner-box">
<image class="banner" src="/static/home/images/Banner.png" mode="widthFix" />
</view>
<!-- 2. 车辆查询服务 -->
<view class="section">
<view class="section-header">
<text class="title">车辆查询服务</text>
<text class="sub">专业车况核验</text>
</view>
<view class="vehicle-grid">
<view
v-for="item in vehicleItems.slice(0, 7)"
:key="item.feature"
class="vehicle-cell"
@tap="goInquireFeature(item.feature)"
>
<view class="vehicle-icon-wrap">
<image class="vehicle-icon" :src="getInquiryItemIconUrl(item)" mode="aspectFit" />
<text class="vehicle-name">{{ item.name }}</text>
</view>
</view>
<!-- 更多服务入口 -->
<view class="vehicle-cell vehicle-cell--more" @tap="goVehicleList">
<view class="vehicle-icon-wrap vehicle-icon-wrap--more">
<view class="i-carbon-overflow-menu-horizontal vehicle-more-icon" />
<text class="vehicle-name">更多服务</text>
</view>
</view>
</view>
</view>
<!-- 4. 热门工具 -->
<view class="section">
<view class="section-header">
<text class="title">万能工具免费查询</text>
<view class="more-link" @tap="goCategory('all')">
<text class="more-text">查看全部</text>
<text class="more-arrow"></text>
</view>
</view>
<view class="hot-tools-grid">
<view
v-for="(item, idx) in hotTools"
:key="item.key"
class="hot-tool-card"
:class="['hot-tool-card--c' + (idx % 4)]"
@tap="goToolboxItem(item.key)"
>
<view class="hot-tool-icon-wrap">
<view :class="item.icon" class="hot-tool-icon" />
<text class="hot-tool-name">{{ item.name }}</text>
</view>
</view>
</view>
</view>
<!-- 5. 每日推荐 -->
<view class="section">
<view class="section-header">
<view class="daily-title-group">
<text class="title">每日推荐</text>
<text class="daily-badge">精选</text>
</view>
<view class="refresh-btn" @tap="refreshDaily">
<view class="i-carbon-renew refresh-icon" :class="{ 'refresh-icon--spin': false }" />
<text class="refresh-text">换一批</text>
</view>
</view>
<view class="daily-grid">
<view
v-for="(item, idx) in dailyPicks"
:key="item.key"
class="daily-card"
:class="['daily-card--c' + (idx % 4)]"
@tap="goToolboxItem(item.key)"
>
<view class="daily-icon-wrap">
<view :class="item.icon" class="daily-icon" />
<text class="daily-name">{{ item.name }}</text>
</view>
</view>
</view>
</view>
<!-- 6. 真实案例 -->
<view class="section">
<view class="section-header">
<text class="title">真实查询案例</text>
<text class="sub">已服务 29+ 车主</text>
</view>
<view class="case-list">
<view v-for="item in caseList" :key="item.id" class="case-item">
<view class="case-tag">{{ item.tag }}</view>
<view class="case-vin">{{ item.vin }}</view>
<view class="case-model">{{ item.model }}</view>
</view>
</view>
</view>
<!-- 6. 用户评价 -->
<view class="section">
<view class="section-header">
<text class="title">用户真实评价</text>
</view>
<view class="review-list">
<view v-for="item in reviewList" :key="item.id" class="review-item">
<view class="avatar">{{ reviewInitial(item.name) }}</view>
<view class="review-content">
<view class="username">{{ item.name }}</view>
<view class="content">{{ item.content }}</view>
</view>
</view>
</view>
</view>
<view style="height: 40rpx"></view>
</scroll-view>
</view>
</template>
<style scoped lang="scss">
page {
background: #f5f7fa;
}
.page-container {
min-height: 100vh;
padding: 20rpx;
box-sizing: border-box;
}
.scroll-view {
height: 100%;
}
/* Banner */
.banner-box {
border-radius: 24rpx;
overflow: hidden;
margin-bottom: 24rpx;
box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.05);
}
.banner {
width: 100%;
display: block;
}
/* 区块通用 */
.section {
background: #fff;
border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.title {
font-size: 30rpx;
font-weight: 700;
color: #1d2129;
}
.sub {
font-size: 24rpx;
color: #86909c;
}
.more-link {
display: flex;
align-items: center;
gap: 4rpx;
}
.more-text {
font-size: 24rpx;
color: #86909c;
}
.more-arrow {
font-size: 28rpx;
color: #86909c;
}
/* 车辆查询 2×4 网格 */
.vehicle-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12rpx;
}
.vehicle-cell {
position: relative;
border-radius: 16rpx;
background: #f7f8fa;
height: 160rpx;
overflow: hidden;
}
.vehicle-cell:active {
background: #eef1f5;
}
.vehicle-icon-wrap {
position: relative;
width: 100%;
height: 100%;
border-radius: 16rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.vehicle-icon-wrap--more {
background: #f7f8fa;
}
.vehicle-icon {
width: 90rpx;
height: 90rpx;
opacity: 1;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
object-fit: contain;
}
.vehicle-more-icon {
font-size: 80rpx;
opacity: 1;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: #fa8c16;
}
.vehicle-name {
flex: 0 0 auto;
font-size: 20rpx;
color: #333;
text-align: center;
line-height: 1.5;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
padding: 0 4rpx 6rpx;
}
/* 热门工具 2×5 网格 */
.hot-tools-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12rpx;
}
.hot-tool-card {
position: relative;
padding: 0;
border-radius: 16rpx;
background: #f7f8fa;
transition: background 0.2s;
height: 140rpx;
overflow: hidden;
}
.hot-tool-card:active {
background: #eef1f5;
}
.hot-tool-icon-wrap {
position: relative;
width: 100%;
height: 100%;
border-radius: 16rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.hot-tool-card--c0 .hot-tool-icon-wrap {
background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
}
.hot-tool-card--c1 .hot-tool-icon-wrap {
background: linear-gradient(135deg, #e3f2fd, #bbdefb);
}
.hot-tool-card--c2 .hot-tool-icon-wrap {
background: linear-gradient(135deg, #fce4ec, #f8bbd0);
}
.hot-tool-card--c3 .hot-tool-icon-wrap {
background: linear-gradient(135deg, #f3e5f5, #e1bee7);
}
.hot-tool-icon {
font-size: 60rpx;
opacity: 0.15;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.hot-tool-card--c0 .hot-tool-icon {
color: #43a047;
}
.hot-tool-card--c1 .hot-tool-icon {
color: #1e88e5;
}
.hot-tool-card--c2 .hot-tool-icon {
color: #e53935;
}
.hot-tool-card--c3 .hot-tool-icon {
color: #8e24aa;
}
.hot-tool-name {
flex: 0 0 auto;
font-size: 20rpx;
color: #333;
text-align: center;
line-height: 1.5;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4rpx 6rpx;
}
/* 每日推荐 */
.daily-title-group {
display: flex;
align-items: center;
gap: 12rpx;
}
.daily-badge {
font-size: 20rpx;
color: #fff;
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
padding: 4rpx 14rpx;
border-radius: 16rpx;
}
.refresh-btn {
display: flex;
align-items: center;
gap: 6rpx;
padding: 8rpx 18rpx;
border-radius: 24rpx;
background: #f2f3f5;
}
.refresh-btn:active {
background: #e5e6eb;
}
.refresh-icon {
font-size: 26rpx;
color: #86909c;
}
.refresh-text {
font-size: 22rpx;
color: #86909c;
}
.daily-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12rpx;
}
.daily-card {
position: relative;
padding: 0;
border-radius: 16rpx;
background: #f7f8fa;
height: 140rpx;
overflow: hidden;
}
.daily-card:active {
background: #eef1f5;
}
.daily-icon-wrap {
position: relative;
width: 100%;
height: 100%;
border-radius: 16rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.daily-card--c0 .daily-icon-wrap {
background: linear-gradient(135deg, #fff3e0, #ffe0b2);
}
.daily-card--c1 .daily-icon-wrap {
background: linear-gradient(135deg, #e0f7fa, #b2ebf2);
}
.daily-card--c2 .daily-icon-wrap {
background: linear-gradient(135deg, #fce4ec, #f8bbd0);
}
.daily-card--c3 .daily-icon-wrap {
background: linear-gradient(135deg, #f3e5f5, #e1bee7);
}
.daily-icon {
font-size: 60rpx;
opacity: 0.15;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.daily-card--c0 .daily-icon {
color: #ef6c00;
}
.daily-card--c1 .daily-icon {
color: #00838f;
}
.daily-card--c2 .daily-icon {
color: #c62828;
}
.daily-card--c3 .daily-icon {
color: #7b1fa2;
}
.daily-name {
flex: 0 0 auto;
font-size: 20rpx;
color: #333;
text-align: center;
line-height: 1.5;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4rpx 6rpx;
}
/* 案例 */
.case-list {
gap: 16rpx;
display: flex;
flex-direction: column;
}
.case-item {
padding: 20rpx;
background: #f9fafb;
border-radius: 16rpx;
display: flex;
align-items: center;
font-size: 22rpx;
}
.case-tag {
color: #1768ff;
font-weight: 600;
margin-right: 12rpx;
}
.case-vin {
color: #333;
margin-right: 12rpx;
}
.case-model {
color: #86909c;
}
/* 评价 */
.review-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.review-item {
display: flex;
align-items: flex-start;
}
.avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: #eef4ff;
color: #1768ff;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
margin-right: 16rpx;
flex-shrink: 0;
}
.review-content {
flex: 1;
}
.username {
font-size: 24rpx;
color: #1d2129;
margin-bottom: 6rpx;
}
.content {
font-size: 22rpx;
color: #4e5969;
line-height: 1.6;
}
</style>