hookehuyr

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

重构认证车源页面的轮播组件,使用通用BannerSwiper组件替代硬编码实现
在car.js接口中添加category参数支持,首页和认证车源页面分别传入不同分类参数获取对应轮播数据
1 /* 1 /*
2 * @Date: 2025-07-09 14:58:51 2 * @Date: 2025-07-09 14:58:51
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-01 14:58:39 4 + * @LastEditTime: 2025-08-04 13:29:22
5 * @FilePath: /jgdl/src/api/car.js 5 * @FilePath: /jgdl/src/api/car.js
6 * @Description: 车辆相关API接口 6 * @Description: 车辆相关API接口
7 */ 7 */
...@@ -120,6 +120,7 @@ export const changeVehicleStatusAPI = (params) => fn(fetch.post(Api.CHANGE_STATU ...@@ -120,6 +120,7 @@ export const changeVehicleStatusAPI = (params) => fn(fetch.post(Api.CHANGE_STATU
120 120
121 /** 121 /**
122 * @description: 首页轮播列表 122 * @description: 首页轮播列表
123 + * @param category 分类(homepage=首页轮播,verification=认证车源)
123 * @returns data.list[{ id 文章ID, icon 封面图, post_title 文章标题, post_link 车辆ID, post_content 文章内容, type 类型(icon=只显示封面图,content=只显示文章详情,vehicle=只进入车辆详情页) }] 124 * @returns data.list[{ id 文章ID, icon 封面图, post_title 文章标题, post_link 车辆ID, post_content 文章内容, type 类型(icon=只显示封面图,content=只显示文章详情,vehicle=只进入车辆详情页) }]
124 */ 125 */
125 126
......
1 <!-- 1 <!--
2 * @Date: 2022-09-19 14:11:06 2 * @Date: 2022-09-19 14:11:06
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-04 10:30:09 4 + * @LastEditTime: 2025-08-04 13:29:45
5 * @FilePath: /jgdl/src/pages/authCar/index.vue 5 * @FilePath: /jgdl/src/pages/authCar/index.vue
6 * @Description: 认证车源 6 * @Description: 认证车源
7 --> 7 -->
8 <template> 8 <template>
9 <view class="auth-car-page"> 9 <view class="auth-car-page">
10 - <!-- Banner轮播图 --> 10 + <!-- Banner -->
11 - <view class="p-4"> 11 + <BannerSwiper :banner-list="bannerList" />
12 - <nut-swiper :init-page="0" :pagination-visible="true" pagination-color="#ffffff" auto-play="3000"
13 - class="rounded-lg overflow-hidden" height="160">
14 - <nut-swiper-item v-for="(image, index) in bannerImages" :key="index">
15 - <image :src="image" mode="aspectFill" class="w-full h-40 object-cover" />
16 - </nut-swiper-item>
17 - </nut-swiper>
18 - </view>
19 12
20 <!-- 我要认证按钮 --> 13 <!-- 我要认证按钮 -->
21 <view class="px-16 mt-5"> 14 <view class="px-16 mt-5">
...@@ -86,14 +79,8 @@ ...@@ -86,14 +79,8 @@
86 <nut-toast v-model:visible="toastVisible" :msg="toastMessage" :type="toastType" /> 79 <nut-toast v-model:visible="toastVisible" :msg="toastMessage" :type="toastType" />
87 80
88 <!-- 认证费用说明弹窗 --> 81 <!-- 认证费用说明弹窗 -->
89 - <nut-popup 82 + <nut-popup v-model:visible="showAuthInfoPopup" position="bottom" :style="{ width: '100%', height: '100%' }"
90 - v-model:visible="showAuthInfoPopup" 83 + closeable close-icon-position="top-right" @close="showAuthInfoPopup = false">
91 - position="bottom"
92 - :style="{ width: '100%', height: '100%' }"
93 - closeable
94 - close-icon-position="top-right"
95 - @close="showAuthInfoPopup = false"
96 - >
97 <view class="auth-info-popup"> 84 <view class="auth-info-popup">
98 <!-- 标题 --> 85 <!-- 标题 -->
99 <view class="popup-header"> 86 <view class="popup-header">
...@@ -116,19 +103,10 @@ ...@@ -116,19 +103,10 @@
116 103
117 <!-- 底部按钮 --> 104 <!-- 底部按钮 -->
118 <view class="popup-footer"> 105 <view class="popup-footer">
119 - <nut-button 106 + <nut-button plain class="footer-btn cancel-btn" @click="showAuthInfoPopup = false">
120 - plain
121 - class="footer-btn cancel-btn"
122 - @click="showAuthInfoPopup = false"
123 - >
124 关闭 107 关闭
125 </nut-button> 108 </nut-button>
126 - <nut-button 109 + <nut-button type="warning" class="footer-btn confirm-btn" color="#fb923c" @click="handleConfirmAuth">
127 - type="warning"
128 - class="footer-btn confirm-btn"
129 - color="#fb923c"
130 - @click="handleConfirmAuth"
131 - >
132 知道了 110 知道了
133 </nut-button> 111 </nut-button>
134 </view> 112 </view>
...@@ -142,18 +120,15 @@ import Taro from '@tarojs/taro' ...@@ -142,18 +120,15 @@ import Taro from '@tarojs/taro'
142 import { ref, computed, onMounted } from 'vue' 120 import { ref, computed, onMounted } from 'vue'
143 import { Check, Heart1, HeartFill } from '@nutui/icons-vue-taro' 121 import { Check, Heart1, HeartFill } from '@nutui/icons-vue-taro'
144 import { useFavorite } from '@/composables/useFavorite' 122 import { useFavorite } from '@/composables/useFavorite'
123 +import BannerSwiper from '@/components/BannerSwiper.vue'
145 import './index.less' 124 import './index.less'
146 // 接口导入 125 // 接口导入
147 -import { getVehicleListAPI } from '@/api/car'; 126 +import { getVehicleListAPI, getArticleListAPI } from '@/api/car';
148 import { getVerificationPriceAPI } from '@/api/other'; 127 import { getVerificationPriceAPI } from '@/api/other';
149 128
150 import { DEFAULT_COVER_IMG } from '@/utils/config' 129 import { DEFAULT_COVER_IMG } from '@/utils/config'
151 -// Banner图片数据 130 +// Banner数据
152 -const bannerImages = ref([ 131 +const bannerList = ref([])
153 - 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=800&h=400&fit=crop',
154 - 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?w=800&h=400&fit=crop',
155 - 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?w=800&h=400&fit=crop'
156 -])
157 132
158 // 认证车源数据 133 // 认证车源数据
159 const authCars = ref([]) 134 const authCars = ref([])
...@@ -223,58 +198,58 @@ const { toggleFavorite } = useFavorite() ...@@ -223,58 +198,58 @@ const { toggleFavorite } = useFavorite()
223 * @param {boolean} isLoadMore - 是否为加载更多 198 * @param {boolean} isLoadMore - 是否为加载更多
224 */ 199 */
225 const loadAuthCarData = async (isLoadMore = false) => { 200 const loadAuthCarData = async (isLoadMore = false) => {
226 - if (loading.value) return 201 + if (loading.value) return
227 - 202 +
228 - loading.value = true 203 + loading.value = true
229 - 204 +
230 - try { 205 + try {
231 - // 构建请求参数 - 只获取认证车辆 206 + // 构建请求参数 - 只获取认证车辆
232 - const params = { 207 + const params = {
233 - page: currentPage.value, 208 + page: currentPage.value,
234 - limit: pageSize.value, 209 + limit: pageSize.value,
235 - verification_status: 5 // 只获取已认证的车辆 210 + verification_status: 5 // 只获取已认证的车辆
236 - } 211 + }
237 - 212 +
238 - const response = await getVehicleListAPI(params) 213 + const response = await getVehicleListAPI(params)
239 - 214 +
240 - if (response && response.code === 1 && response.data) { 215 + if (response && response.code === 1 && response.data) {
241 - const vehicleList = response.data.list || [] 216 + const vehicleList = response.data.list || []
242 - 217 +
243 - // 处理图片数据 218 + // 处理图片数据
244 - const processedData = vehicleList.map(item => ({ 219 + const processedData = vehicleList.map(item => ({
245 - ...item, 220 + ...item,
246 - front_photo: item.front_photo || DEFAULT_COVER_IMG, 221 + front_photo: item.front_photo || DEFAULT_COVER_IMG,
247 - })) 222 + }))
248 - 223 +
249 - if (isLoadMore) { 224 + if (isLoadMore) {
250 - authCars.value.push(...processedData) 225 + authCars.value.push(...processedData)
251 - } else { 226 + } else {
252 - authCars.value = processedData 227 + authCars.value = processedData
253 - } 228 + }
254 - 229 +
255 - // 检查是否还有更多数据 - 基于总数和当前已加载数量 230 + // 检查是否还有更多数据 - 基于总数和当前已加载数量
256 - const totalLoaded = (currentPage.value + 1) * pageSize.value 231 + const totalLoaded = (currentPage.value + 1) * pageSize.value
257 - hasMore.value = totalLoaded < response.data.total 232 + hasMore.value = totalLoaded < response.data.total
258 - } else { 233 + } else {
259 - console.error('API返回错误:', response) 234 + console.error('API返回错误:', response)
260 - showToast(response?.msg || '获取数据失败', 'error') 235 + showToast(response?.msg || '获取数据失败', 'error')
261 - }
262 - } catch (error) {
263 - console.error('加载认证车辆数据失败:', error)
264 - showToast('网络错误,请稍后重试', 'error')
265 - } finally {
266 - loading.value = false
267 } 236 }
237 + } catch (error) {
238 + console.error('加载认证车辆数据失败:', error)
239 + showToast('网络错误,请稍后重试', 'error')
240 + } finally {
241 + loading.value = false
242 + }
268 } 243 }
269 244
270 /** 245 /**
271 * 加载更多数据 246 * 加载更多数据
272 */ 247 */
273 const loadMore = async () => { 248 const loadMore = async () => {
274 - if (loading.value || !hasMore.value) return 249 + if (loading.value || !hasMore.value) return
275 250
276 - currentPage.value++ 251 + currentPage.value++
277 - await loadAuthCarData(true) 252 + await loadAuthCarData(true)
278 } 253 }
279 254
280 /** 255 /**
...@@ -288,9 +263,9 @@ const scroll = (e) => { ...@@ -288,9 +263,9 @@ const scroll = (e) => {
288 * 显示提示信息 263 * 显示提示信息
289 */ 264 */
290 const showToast = (message, type = 'success') => { 265 const showToast = (message, type = 'success') => {
291 - toastMessage.value = message 266 + toastMessage.value = message
292 - toastType.value = type 267 + toastType.value = type
293 - toastVisible.value = true 268 + toastVisible.value = true
294 } 269 }
295 270
296 /** 271 /**
...@@ -298,25 +273,42 @@ const showToast = (message, type = 'success') => { ...@@ -298,25 +273,42 @@ const showToast = (message, type = 'success') => {
298 */ 273 */
299 274
300 const getVerificationPrice = async () => { 275 const getVerificationPrice = async () => {
301 - try { 276 + try {
302 - const response = await getVerificationPriceAPI() 277 + const response = await getVerificationPriceAPI()
303 - if (response && response.code === 1 && response.data) { 278 + if (response && response.code === 1 && response.data) {
304 - // 处理认证费用数据 279 + // 处理认证费用数据
305 - authFee.value = response.data.verification_price 280 + authFee.value = response.data.verification_price
306 - authDesc.value = response.data.verification_desc 281 + authDesc.value = response.data.verification_desc
307 - }
308 - } catch (error) {
309 - console.error('获取认证费用失败:', error)
310 - showToast('网络错误,请稍后重试', 'error')
311 } 282 }
283 + } catch (error) {
284 + console.error('获取认证费用失败:', error)
285 + showToast('网络错误,请稍后重试', 'error')
286 + }
312 } 287 }
313 288
314 // 初始化 289 // 初始化
315 onMounted(async () => { 290 onMounted(async () => {
316 - // 加载初始认证车辆数据 291 + // 加载初始认证车辆数据
317 - await loadAuthCarData() 292 + await loadAuthCarData()
318 - // 获取认证费用 293 + // 获取认证费用
319 - await getVerificationPrice() 294 + await getVerificationPrice()
295 + // 获取轮播图数据
296 + const response = await getArticleListAPI({ category: 'verification' })
297 + if (response.code && response.data.list.length) {
298 + // 将API数据转换为轮播图格式
299 + const articleBanners = response.data.list.map(item => ({
300 + id: item.post_link || item.id, // 使用post_link作为车辆ID,如果没有则使用文章ID
301 + type: item.type || 'icon', // 使用接口返回的type字段
302 + image: item.icon, // 使用icon作为封面图
303 + title: item.post_title, // 使用post_title作为标题
304 + content: item.post_content // 使用post_content作为文章内容
305 + }))
306 + bannerList.value = articleBanners
307 + } else {
308 + // API调用失败时设置为空数组
309 + bannerList.value = []
310 + console.warn('获取轮播图数据失败')
311 + }
320 }) 312 })
321 </script> 313 </script>
322 314
......
1 <!-- 1 <!--
2 * @Date: 2025-06-28 10:33:00 2 * @Date: 2025-06-28 10:33:00
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-07-29 11:00:46 4 + * @LastEditTime: 2025-08-04 13:28:57
5 * @FilePath: /jgdl/src/pages/index/index.vue 5 * @FilePath: /jgdl/src/pages/index/index.vue
6 * @Description: 捡个电驴首页 6 * @Description: 捡个电驴首页
7 --> 7 -->
...@@ -171,7 +171,7 @@ useReady(async () => { ...@@ -171,7 +171,7 @@ useReady(async () => {
171 171
172 onMounted(async () => { 172 onMounted(async () => {
173 // 获取首页轮播 173 // 获取首页轮播
174 - const { code, data } = await getArticleListAPI() 174 + const { code, data } = await getArticleListAPI({ category: 'homepage' })
175 if (code && data.list.length) { 175 if (code && data.list.length) {
176 // 将API数据转换为轮播图格式 176 // 将API数据转换为轮播图格式
177 const articleBanners = data.list.map(item => ({ 177 const articleBanners = data.list.map(item => ({
......