hookehuyr

feat(轮播): 为认证车源页面添加分类轮播功能

重构认证车源页面的轮播组件,使用通用BannerSwiper组件替代硬编码实现
在car.js接口中添加category参数支持,首页和认证车源页面分别传入不同分类参数获取对应轮播数据
/*
* @Date: 2025-07-09 14:58:51
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-08-01 14:58:39
* @LastEditTime: 2025-08-04 13:29:22
* @FilePath: /jgdl/src/api/car.js
* @Description: 车辆相关API接口
*/
......@@ -120,6 +120,7 @@ export const changeVehicleStatusAPI = (params) => fn(fetch.post(Api.CHANGE_STATU
/**
* @description: 首页轮播列表
* @param category 分类(homepage=首页轮播,verification=认证车源)
* @returns data.list[{ id 文章ID, icon 封面图, post_title 文章标题, post_link 车辆ID, post_content 文章内容, type 类型(icon=只显示封面图,content=只显示文章详情,vehicle=只进入车辆详情页) }]
*/
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-08-04 10:30:09
* @LastEditTime: 2025-08-04 13:29:45
* @FilePath: /jgdl/src/pages/authCar/index.vue
* @Description: 认证车源
-->
<template>
<view class="auth-car-page">
<!-- Banner轮播图 -->
<view class="p-4">
<nut-swiper :init-page="0" :pagination-visible="true" pagination-color="#ffffff" auto-play="3000"
class="rounded-lg overflow-hidden" height="160">
<nut-swiper-item v-for="(image, index) in bannerImages" :key="index">
<image :src="image" mode="aspectFill" class="w-full h-40 object-cover" />
</nut-swiper-item>
</nut-swiper>
</view>
<!-- Banner -->
<BannerSwiper :banner-list="bannerList" />
<!-- 我要认证按钮 -->
<view class="px-16 mt-5">
......@@ -86,14 +79,8 @@
<nut-toast v-model:visible="toastVisible" :msg="toastMessage" :type="toastType" />
<!-- 认证费用说明弹窗 -->
<nut-popup
v-model:visible="showAuthInfoPopup"
position="bottom"
:style="{ width: '100%', height: '100%' }"
closeable
close-icon-position="top-right"
@close="showAuthInfoPopup = false"
>
<nut-popup v-model:visible="showAuthInfoPopup" position="bottom" :style="{ width: '100%', height: '100%' }"
closeable close-icon-position="top-right" @close="showAuthInfoPopup = false">
<view class="auth-info-popup">
<!-- 标题 -->
<view class="popup-header">
......@@ -116,19 +103,10 @@
<!-- 底部按钮 -->
<view class="popup-footer">
<nut-button
plain
class="footer-btn cancel-btn"
@click="showAuthInfoPopup = false"
>
<nut-button plain class="footer-btn cancel-btn" @click="showAuthInfoPopup = false">
关闭
</nut-button>
<nut-button
type="warning"
class="footer-btn confirm-btn"
color="#fb923c"
@click="handleConfirmAuth"
>
<nut-button type="warning" class="footer-btn confirm-btn" color="#fb923c" @click="handleConfirmAuth">
知道了
</nut-button>
</view>
......@@ -142,18 +120,15 @@ import Taro from '@tarojs/taro'
import { ref, computed, onMounted } from 'vue'
import { Check, Heart1, HeartFill } from '@nutui/icons-vue-taro'
import { useFavorite } from '@/composables/useFavorite'
import BannerSwiper from '@/components/BannerSwiper.vue'
import './index.less'
// 接口导入
import { getVehicleListAPI } from '@/api/car';
import { getVehicleListAPI, getArticleListAPI } from '@/api/car';
import { getVerificationPriceAPI } from '@/api/other';
import { DEFAULT_COVER_IMG } from '@/utils/config'
// Banner图片数据
const bannerImages = ref([
'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=800&h=400&fit=crop',
'https://images.unsplash.com/photo-1571068316344-75bc76f77890?w=800&h=400&fit=crop',
'https://images.unsplash.com/photo-1571068316344-75bc76f77890?w=800&h=400&fit=crop'
])
// Banner数据
const bannerList = ref([])
// 认证车源数据
const authCars = ref([])
......@@ -223,58 +198,58 @@ const { toggleFavorite } = useFavorite()
* @param {boolean} isLoadMore - 是否为加载更多
*/
const loadAuthCarData = async (isLoadMore = false) => {
if (loading.value) return
loading.value = true
try {
// 构建请求参数 - 只获取认证车辆
const params = {
page: currentPage.value,
limit: pageSize.value,
verification_status: 5 // 只获取已认证的车辆
}
const response = await getVehicleListAPI(params)
if (response && response.code === 1 && response.data) {
const vehicleList = response.data.list || []
// 处理图片数据
const processedData = vehicleList.map(item => ({
...item,
front_photo: item.front_photo || DEFAULT_COVER_IMG,
}))
if (isLoadMore) {
authCars.value.push(...processedData)
} else {
authCars.value = processedData
}
// 检查是否还有更多数据 - 基于总数和当前已加载数量
const totalLoaded = (currentPage.value + 1) * pageSize.value
hasMore.value = totalLoaded < response.data.total
} else {
console.error('API返回错误:', response)
showToast(response?.msg || '获取数据失败', 'error')
}
} catch (error) {
console.error('加载认证车辆数据失败:', error)
showToast('网络错误,请稍后重试', 'error')
} finally {
loading.value = false
if (loading.value) return
loading.value = true
try {
// 构建请求参数 - 只获取认证车辆
const params = {
page: currentPage.value,
limit: pageSize.value,
verification_status: 5 // 只获取已认证的车辆
}
const response = await getVehicleListAPI(params)
if (response && response.code === 1 && response.data) {
const vehicleList = response.data.list || []
// 处理图片数据
const processedData = vehicleList.map(item => ({
...item,
front_photo: item.front_photo || DEFAULT_COVER_IMG,
}))
if (isLoadMore) {
authCars.value.push(...processedData)
} else {
authCars.value = processedData
}
// 检查是否还有更多数据 - 基于总数和当前已加载数量
const totalLoaded = (currentPage.value + 1) * pageSize.value
hasMore.value = totalLoaded < response.data.total
} else {
console.error('API返回错误:', response)
showToast(response?.msg || '获取数据失败', 'error')
}
} catch (error) {
console.error('加载认证车辆数据失败:', error)
showToast('网络错误,请稍后重试', 'error')
} finally {
loading.value = false
}
}
/**
* 加载更多数据
*/
const loadMore = async () => {
if (loading.value || !hasMore.value) return
if (loading.value || !hasMore.value) return
currentPage.value++
await loadAuthCarData(true)
currentPage.value++
await loadAuthCarData(true)
}
/**
......@@ -288,9 +263,9 @@ const scroll = (e) => {
* 显示提示信息
*/
const showToast = (message, type = 'success') => {
toastMessage.value = message
toastType.value = type
toastVisible.value = true
toastMessage.value = message
toastType.value = type
toastVisible.value = true
}
/**
......@@ -298,25 +273,42 @@ const showToast = (message, type = 'success') => {
*/
const getVerificationPrice = async () => {
try {
const response = await getVerificationPriceAPI()
if (response && response.code === 1 && response.data) {
// 处理认证费用数据
authFee.value = response.data.verification_price
authDesc.value = response.data.verification_desc
}
} catch (error) {
console.error('获取认证费用失败:', error)
showToast('网络错误,请稍后重试', 'error')
try {
const response = await getVerificationPriceAPI()
if (response && response.code === 1 && response.data) {
// 处理认证费用数据
authFee.value = response.data.verification_price
authDesc.value = response.data.verification_desc
}
} catch (error) {
console.error('获取认证费用失败:', error)
showToast('网络错误,请稍后重试', 'error')
}
}
// 初始化
onMounted(async () => {
// 加载初始认证车辆数据
await loadAuthCarData()
// 获取认证费用
await getVerificationPrice()
// 加载初始认证车辆数据
await loadAuthCarData()
// 获取认证费用
await getVerificationPrice()
// 获取轮播图数据
const response = await getArticleListAPI({ category: 'verification' })
if (response.code && response.data.list.length) {
// 将API数据转换为轮播图格式
const articleBanners = response.data.list.map(item => ({
id: item.post_link || item.id, // 使用post_link作为车辆ID,如果没有则使用文章ID
type: item.type || 'icon', // 使用接口返回的type字段
image: item.icon, // 使用icon作为封面图
title: item.post_title, // 使用post_title作为标题
content: item.post_content // 使用post_content作为文章内容
}))
bannerList.value = articleBanners
} else {
// API调用失败时设置为空数组
bannerList.value = []
console.warn('获取轮播图数据失败')
}
})
</script>
......
<!--
* @Date: 2025-06-28 10:33:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-29 11:00:46
* @LastEditTime: 2025-08-04 13:28:57
* @FilePath: /jgdl/src/pages/index/index.vue
* @Description: 捡个电驴首页
-->
......@@ -171,7 +171,7 @@ useReady(async () => {
onMounted(async () => {
// 获取首页轮播
const { code, data } = await getArticleListAPI()
const { code, data } = await getArticleListAPI({ category: 'homepage' })
if (code && data.list.length) {
// 将API数据转换为轮播图格式
const articleBanners = data.list.map(item => ({
......