hookehuyr

feat: 添加精品推荐页面及导航功能

实现精品推荐页面,包含车辆列表展示、筛选和收藏功能
在首页和帖子页添加跳转到精品推荐页面的导航
更新搜索框占位文本和收藏按钮样式
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-04 10:34:25 4 + * @LastEditTime: 2025-07-04 16:18:21
5 * @FilePath: /jgdl/src/app.config.js 5 * @FilePath: /jgdl/src/app.config.js
6 * @Description: 配置文件 6 * @Description: 配置文件
7 */ 7 */
...@@ -27,6 +27,7 @@ export default { ...@@ -27,6 +27,7 @@ export default {
27 'pages/feedBack/index', 27 'pages/feedBack/index',
28 'pages/helpCenter/index', 28 'pages/helpCenter/index',
29 'pages/search/index', 29 'pages/search/index',
30 + 'pages/recommendCarList/index',
30 ], 31 ],
31 subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 32 subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去
32 { 33 {
......
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-07-03 21:10:36 4 + * @LastEditTime: 2025-07-04 16:27:02
5 * @FilePath: /jgdl/src/pages/goodCarList/index.vue 5 * @FilePath: /jgdl/src/pages/goodCarList/index.vue
6 * @Description: 特价好车页面 6 * @Description: 特价好车页面
7 --> 7 -->
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 </nut-col> 17 </nut-col>
18 <nut-col span="18"> 18 <nut-col span="18">
19 <!-- Search Bar --> 19 <!-- Search Bar -->
20 - <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff"> 20 + <nut-searchbar v-model="searchValue" placeholder="搜索商品名称、品牌、型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff">
21 <template #leftin> 21 <template #leftin>
22 <Search2 /> 22 <Search2 />
23 </template> 23 </template>
...@@ -67,8 +67,8 @@ ...@@ -67,8 +67,8 @@
67 </view> 67 </view>
68 <view class="flex-1 p-3 relative"> 68 <view class="flex-1 p-3 relative">
69 <view class="absolute top-3 right-4" @tap.stop="() => toggleFavorite(car.id)"> 69 <view class="absolute top-3 right-4" @tap.stop="() => toggleFavorite(car.id)">
70 - <Heart1 v-if="!favoriteIds.includes(car.id)" size="16" color="#9ca3af" /> 70 + <Heart1 v-if="!favoriteIds.includes(car.id)" size="22" color="#9ca3af" />
71 - <HeartFill v-else size="16" color="#ef4444" /> 71 + <HeartFill v-else size="22" color="#ef4444" />
72 </view> 72 </view>
73 <text class="font-medium text-sm block">{{ car.name }}</text> 73 <text class="font-medium text-sm block">{{ car.name }}</text>
74 <text class="text-xs text-gray-600 mt-1 block"> 74 <text class="text-xs text-gray-600 mt-1 block">
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
82 <text v-if="car.originalPrice" class="text-xs text-gray-400 line-through mr-2"> 82 <text v-if="car.originalPrice" class="text-xs text-gray-400 line-through mr-2">
83 ¥{{ car.originalPrice.toLocaleString() }} 83 ¥{{ car.originalPrice.toLocaleString() }}
84 </text> 84 </text>
85 - <text class="text-orange-500 font-bold"> 85 + <text class="text-orange-500 font-bold" style="font-size: 1.2rem;">
86 ¥{{ car.price.toLocaleString() }} 86 ¥{{ car.price.toLocaleString() }}
87 </text> 87 </text>
88 </view> 88 </view>
...@@ -111,7 +111,7 @@ ...@@ -111,7 +111,7 @@
111 </view> 111 </view>
112 112
113 <!-- 自定义TabBar --> 113 <!-- 自定义TabBar -->
114 - <TabBar /> 114 + <!-- <TabBar /> -->
115 115
116 <!-- 成功提示 --> 116 <!-- 成功提示 -->
117 <nut-toast 117 <nut-toast
......
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-04 16:04:15 4 + * @LastEditTime: 2025-07-04 16:26:05
5 * @FilePath: /jgdl/src/pages/index/index.vue 5 * @FilePath: /jgdl/src/pages/index/index.vue
6 * @Description: 捡个电驴首页 6 * @Description: 捡个电驴首页
7 --> 7 -->
...@@ -64,10 +64,10 @@ ...@@ -64,10 +64,10 @@
64 <view class="px-4 mt-4"> 64 <view class="px-4 mt-4">
65 <view class="flex justify-between items-center mb-2"> 65 <view class="flex justify-between items-center mb-2">
66 <text class="text-lg font-medium">精品推荐</text> 66 <text class="text-lg font-medium">精品推荐</text>
67 - <!-- <view class="text-sm text-gray-500 flex items-center"> 67 + <view class="text-sm text-gray-500 flex items-center" @tap="onMoreRecommendClick">
68 <text>更多</text> 68 <text>更多</text>
69 <RectRight size="12" /> 69 <RectRight size="12" />
70 - </view> --> 70 + </view>
71 </view> 71 </view>
72 <view class="grid grid-cols-2 gap-3"> 72 <view class="grid grid-cols-2 gap-3">
73 <view v-for="scooter in featuredScooters" :key="scooter.id" 73 <view v-for="scooter in featuredScooters" :key="scooter.id"
...@@ -284,6 +284,12 @@ const toggleFavorite = (scooterId) => { ...@@ -284,6 +284,12 @@ const toggleFavorite = (scooterId) => {
284 } 284 }
285 } 285 }
286 286
287 +const onMoreRecommendClick = () => {
288 + Taro.navigateTo({
289 + url: '/pages/recommendCarList/index'
290 + })
291 +}
292 +
287 /** 293 /**
288 * 点击产品卡片 294 * 点击产品卡片
289 * @param {Object} scooter - 电动车信息 295 * @param {Object} scooter - 电动车信息
......
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-07-02 22:59:12 4 + * @LastEditTime: 2025-07-04 16:26:55
5 * @FilePath: /jgdl/src/pages/newCarList/index.vue 5 * @FilePath: /jgdl/src/pages/newCarList/index.vue
6 * @Description: 最新上架页面 6 * @Description: 最新上架页面
7 --> 7 -->
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 </nut-col> 17 </nut-col>
18 <nut-col span="18"> 18 <nut-col span="18">
19 <!-- Search Bar --> 19 <!-- Search Bar -->
20 - <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff"> 20 + <nut-searchbar v-model="searchValue" placeholder="搜索商品名称、品牌、型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff">
21 <template #leftin> 21 <template #leftin>
22 <Search2 /> 22 <Search2 />
23 </template> 23 </template>
...@@ -62,8 +62,8 @@ ...@@ -62,8 +62,8 @@
62 </view> 62 </view>
63 <view class="flex-1 p-3 relative"> 63 <view class="flex-1 p-3 relative">
64 <view class="absolute top-3 right-4" @tap.stop="() => toggleFavorite(car.id)"> 64 <view class="absolute top-3 right-4" @tap.stop="() => toggleFavorite(car.id)">
65 - <Heart1 v-if="!favoriteIds.includes(car.id)" size="16" color="#9ca3af" /> 65 + <Heart1 v-if="!favoriteIds.includes(car.id)" size="22" color="#9ca3af" />
66 - <HeartFill v-else size="16" color="#ef4444" /> 66 + <HeartFill v-else size="22" color="#ef4444" />
67 </view> 67 </view>
68 <text class="font-medium text-sm block">{{ car.name }}</text> 68 <text class="font-medium text-sm block">{{ car.name }}</text>
69 <text class="text-xs text-gray-600 mt-1 block"> 69 <text class="text-xs text-gray-600 mt-1 block">
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
72 <text v-if="car.mileage"> 行驶{{ car.mileage }}公里</text> 72 <text v-if="car.mileage"> 行驶{{ car.mileage }}公里</text>
73 </text> 73 </text>
74 <view class="mt-2"> 74 <view class="mt-2">
75 - <text class="text-orange-500 font-bold"> 75 + <text class="text-orange-500 font-bold" style="font-size: 1.2rem;">
76 ¥{{ car.price.toLocaleString() }} 76 ¥{{ car.price.toLocaleString() }}
77 </text> 77 </text>
78 <text class="text-xs text-gray-500 mt-1 block">{{ car.school }}</text> 78 <text class="text-xs text-gray-500 mt-1 block">{{ car.school }}</text>
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
100 </view> 100 </view>
101 101
102 <!-- 自定义TabBar --> 102 <!-- 自定义TabBar -->
103 - <TabBar /> 103 + <!-- <TabBar /> -->
104 104
105 <!-- 成功提示 --> 105 <!-- 成功提示 -->
106 <nut-toast 106 <nut-toast
......
...@@ -86,10 +86,10 @@ ...@@ -86,10 +86,10 @@
86 <view class="mt-6 mb-20 ml-4 mr-4"> 86 <view class="mt-6 mb-20 ml-4 mr-4">
87 <view class="flex justify-between items-center mb-3"> 87 <view class="flex justify-between items-center mb-3">
88 <text class="text-lg font-medium">精品推荐</text> 88 <text class="text-lg font-medium">精品推荐</text>
89 - <!-- <view class="text-sm text-gray-500 flex items-center" @tap="onViewMore"> 89 + <view class="text-sm text-gray-500 flex items-center" @tap="onMoreRecommendClick">
90 <text>更多</text> 90 <text>更多</text>
91 <RectRight size="12" /> 91 <RectRight size="12" />
92 - </view> --> 92 + </view>
93 </view> 93 </view>
94 <view class="grid grid-cols-2 gap-3"> 94 <view class="grid grid-cols-2 gap-3">
95 <view v-for="scooter in featuredScooters" :key="scooter.id" 95 <view v-for="scooter in featuredScooters" :key="scooter.id"
...@@ -304,10 +304,9 @@ const onProductClick = (scooter) => { ...@@ -304,10 +304,9 @@ const onProductClick = (scooter) => {
304 /** 304 /**
305 * 查看更多点击事件 305 * 查看更多点击事件
306 */ 306 */
307 -const onViewMore = () => { 307 +const onMoreRecommendClick = () => {
308 - Taro.showToast({ 308 + Taro.navigateTo({
309 - title: '查看更多精品推荐', 309 + url: '/pages/recommendCarList/index'
310 - icon: 'none'
311 }) 310 })
312 } 311 }
313 312
......
1 +/*
2 + * @Date: 2025-07-02 22:16:48
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-07-02 22:17:11
5 + * @FilePath: /jgdl/src/pages/newCarList/index.config.js
6 + * @Description: 文件描述
7 + */
8 +export default {
9 + navigationBarTitleText: '',
10 + usingComponents: {
11 + },
12 +}
1 +/* 精品推荐页面样式 */
2 +.recommend-car-list {
3 + width: 100%;
4 + box-sizing: border-box;
5 +
6 + /* 滚动条样式 */
7 + &::-webkit-scrollbar {
8 + width: 6rpx;
9 + }
10 +
11 + &::-webkit-scrollbar-track {
12 + background: #f1f1f1;
13 + border-radius: 3rpx;
14 + }
15 +
16 + &::-webkit-scrollbar-thumb {
17 + background: #c1c1c1;
18 + border-radius: 3rpx;
19 +
20 + &:hover {
21 + background: #a8a8a8;
22 + }
23 + }
24 +}
25 +
26 +/* 车辆卡片样式 */
27 +.recommend-car-list .bg-white {
28 + background-color: #ffffff;
29 + border: 1px solid #f0f0f0;
30 + border-radius: 16rpx;
31 + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
32 + overflow: hidden;
33 + margin-bottom: 24rpx;
34 + transition: all 0.3s ease;
35 +}
36 +
37 +.recommend-car-list .bg-white:hover {
38 + transform: translateY(-2rpx);
39 + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
40 + border-color: #e5e7eb;
41 +}
42 +
43 +.recommend-car-list .bg-white:active {
44 + transform: scale(0.98);
45 + transition: transform 0.1s ease;
46 +}
47 +
48 +/* 车辆图片容器 */
49 +.recommend-car-list .w-32 {
50 + width: 200rpx;
51 + height: 150rpx;
52 + flex-shrink: 0;
53 +}
54 +
55 +.recommend-car-list image {
56 + border-radius: 12rpx;
57 + object-fit: cover;
58 +}
59 +
60 +/* 推荐标识样式优化 */
61 +.recommend-car-list .absolute.bottom-3.right-3 {
62 + background: linear-gradient(45deg, #ef4444, #dc2626);
63 + box-shadow: 0 2rpx 4rpx rgba(239, 68, 68, 0.3);
64 + border-radius: 8rpx;
65 + padding: 4rpx 8rpx;
66 + font-size: 20rpx;
67 + font-weight: 600;
68 +}
69 +
70 +/* 车辆信息区域 */
71 +.recommend-car-list .flex-1 {
72 + flex: 1;
73 + min-width: 0;
74 +}
75 +
76 +/* 收藏按钮样式 */
77 +.recommend-car-list .absolute {
78 + transition: transform 0.2s ease;
79 +}
80 +
81 +.recommend-car-list .absolute:active {
82 + transform: scale(0.9);
83 +}
84 +
85 +/* 价格样式 */
86 +.recommend-car-list .text-orange-500 {
87 + color: #f97316;
88 + font-weight: bold;
89 +}
90 +
91 +/* 推荐理由样式 */
92 +.recommend-car-list .text-green-600 {
93 + color: #10b981;
94 + font-weight: 500;
95 +}
96 +
97 +/* 文字省略 */
98 +.recommend-car-list .font-medium {
99 + overflow: hidden;
100 + text-overflow: ellipsis;
101 + white-space: nowrap;
102 +}
103 +
104 +/* 加载状态样式 */
105 +.loading-container {
106 + padding: 32rpx 0 100rpx 0; /* 增加底部间距避免被TabBar遮挡 */
107 + text-align: center;
108 +
109 + .loading-text {
110 + color: #9ca3af;
111 + font-size: 28rpx;
112 + }
113 +}
114 +
115 +/* 无更多数据样式 */
116 +.no-more-container {
117 + padding: 32rpx 0 100rpx 0; /* 增加底部间距避免被TabBar遮挡 */
118 + text-align: center;
119 +
120 + text {
121 + color: #d1d5db;
122 + font-size: 24rpx;
123 + }
124 +}
125 +
126 +/* 动画效果 */
127 +.recommend-car-list .bg-white {
128 + animation: fadeInUp 0.3s ease-out;
129 +}
130 +
131 +@keyframes fadeInUp {
132 + from {
133 + opacity: 0;
134 + transform: translateY(20rpx);
135 + }
136 + to {
137 + opacity: 1;
138 + transform: translateY(0);
139 + }
140 +}
141 +
142 +/* 响应式适配 */
143 +@media screen and (max-width: 750rpx) {
144 + .recommend-car-list .w-32 {
145 + width: 180rpx;
146 + height: 135rpx;
147 + }
148 +
149 + .recommend-car-list .text-xl {
150 + font-size: 32rpx;
151 + }
152 +
153 + .recommend-car-list .text-sm {
154 + font-size: 24rpx;
155 + }
156 +
157 + .recommend-car-list .text-xs {
158 + font-size: 20rpx;
159 + }
160 +}
161 +
162 +/* 深色模式适配 */
163 +@media (prefers-color-scheme: dark) {
164 + .recommend-car-list .bg-white {
165 + background-color: #1f2937;
166 + border-color: #374151;
167 + }
168 +
169 + .recommend-car-list .text-gray-600 {
170 + color: #9ca3af;
171 + }
172 +
173 + .recommend-car-list .text-gray-500 {
174 + color: #6b7280;
175 + }
176 +
177 + .recommend-car-list .text-gray-400 {
178 + color: #9ca3af;
179 + }
180 +}
181 +
182 +/* NutUI组件样式覆盖 */
183 +:deep(.nut-sticky) {
184 + z-index: 999;
185 +}
186 +
187 +:deep(.nut-searchbar) {
188 + .nut-searchbar__content {
189 + border-radius: 50rpx;
190 + background: #fff;
191 +
192 + .nut-searchbar__input {
193 + font-size: 28rpx;
194 + color: #374151;
195 +
196 + &::placeholder {
197 + color: #9ca3af;
198 + }
199 + }
200 + }
201 +}
202 +
203 +:deep(.nut-menu) {
204 + background: #fff;
205 + border-bottom: 1rpx solid #e5e7eb;
206 +
207 + .nut-menu__item {
208 + font-size: 28rpx;
209 + color: #374151;
210 +
211 + &.active {
212 + color: #f97316;
213 + }
214 + }
215 +
216 + .nut-menu__title {
217 + font-size: 28rpx;
218 +
219 + &::after {
220 + border-color: #9ca3af;
221 + }
222 + }
223 +}
224 +
225 +:deep(.nut-toast) {
226 + .nut-toast__inner {
227 + background: rgba(0, 0, 0, 0.8);
228 + color: #fff;
229 + border-radius: 16rpx;
230 + font-size: 28rpx;
231 + }
232 +}
233 +
234 +/* 响应式适配 */
235 +@media (max-width: 750rpx) {
236 + .car-image-container {
237 + width: 200rpx;
238 + height: 150rpx;
239 + padding: 12rpx;
240 + }
241 +
242 + .car-info {
243 + padding: 20rpx;
244 +
245 + .car-name {
246 + font-size: 26rpx;
247 + }
248 +
249 + .car-details {
250 + font-size: 22rpx;
251 + }
252 +
253 + .car-price {
254 + font-size: 28rpx;
255 + }
256 +
257 + .car-school {
258 + font-size: 20rpx;
259 + }
260 +
261 + .listing-time {
262 + font-size: 20rpx;
263 + }
264 + }
265 +}
266 +
267 +/* 深色模式适配 */
268 +@media (prefers-color-scheme: dark) {
269 + .car-card {
270 + background: #1f2937;
271 + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
272 +
273 + &:hover {
274 + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.4);
275 + }
276 + }
277 +
278 + .car-info {
279 + .car-name {
280 + color: #f9fafb;
281 + }
282 +
283 + .car-details {
284 + color: #d1d5db;
285 + }
286 +
287 + .car-school {
288 + color: #9ca3af;
289 + }
290 + }
291 +
292 + .loading-container .loading-text {
293 + color: #6b7280;
294 + }
295 +
296 + .no-more-container text {
297 + color: #4b5563;
298 + }
299 +}
1 +<!--
2 + * @Date: 2022-09-19 14:11:06
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-07-04 16:26:47
5 + * @FilePath: /jgdl/src/pages/recommendCarList/index.vue
6 + * @Description: 精品推荐页面
7 +-->
8 +<template>
9 + <view>
10 + <view class="flex flex-col bg-white min-h-screen">
11 + <!-- Header -->
12 + <nut-sticky>
13 + <view class="bg-orange-400 p-4 pt-4 pb-4">
14 + <nut-row type="flex" justify="center" align="center">
15 + <nut-col span="6">
16 + <view class="text-xl font-bold text-white">精品推荐</view>
17 + </nut-col>
18 + <nut-col span="18">
19 + <!-- Search Bar -->
20 + <nut-searchbar v-model="searchValue" placeholder="搜索商品名称、品牌、型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff">
21 + <template #leftin>
22 + <Search2 />
23 + </template>
24 + </nut-searchbar>
25 + </nut-col>
26 + </nut-row>
27 + </view>
28 +
29 + <!-- Filter options -->
30 + <nut-menu>
31 + <nut-menu-item v-model="selectedBrand" :options="brandOptions" @change="onBrandChange" />
32 + <nut-menu-item v-model="selectedYear" :options="yearOptions" @change="onYearChange" />
33 + <nut-menu-item v-model="selectedSchool" :options="schoolOptions" @change="onSchoolChange" />
34 + </nut-menu>
35 + </nut-sticky>
36 +
37 + <!-- 精品推荐车辆列表 -->
38 + <view class="flex-1 p-4">
39 + <!-- 滚动列表 -->
40 + <scroll-view
41 + class="recommend-car-list"
42 + :style="scrollStyle"
43 + :scroll-y="true"
44 + @scrolltolower="loadMore"
45 + @scroll="scroll"
46 + :lower-threshold="50"
47 + :enable-flex="false"
48 + >
49 + <view class="space-y-4">
50 + <view v-for="car in recommendCars" :key="car.id"
51 + class="bg-white rounded-lg shadow-sm overflow-hidden mb-3"
52 + @tap="() => onCarClick(car)"
53 + >
54 + <view class="flex">
55 + <view class="w-32 h-24 relative p-2">
56 + <image :src="car.imageUrl" :alt="car.name" mode="aspectFill"
57 + class="w-full h-full object-cover rounded-lg" />
58 + <view v-if="car.isNew"
59 + class="absolute bottom-3 right-3 bg-red-500 text-white text-xs px-1 rounded flex items-center">
60 + <text class="text-white">新</text>
61 + </view>
62 + </view>
63 + <view class="flex-1 p-3 relative">
64 + <view class="absolute top-3 right-4" @tap.stop="() => toggleFavorite(car.id)">
65 + <Heart1 v-if="!favoriteIds.includes(car.id)" size="22" color="#9ca3af" />
66 + <HeartFill v-else size="22" color="#ef4444" />
67 + </view>
68 + <text class="font-medium text-sm block">{{ car.name }}</text>
69 + <text class="text-xs text-gray-600 mt-1 block">
70 + {{ car.year }} ·
71 + <text v-if="car.batteryHealth">电池健康度{{ car.batteryHealth }}%</text>
72 + <text v-if="car.mileage"> 行驶{{ car.mileage }}公里</text>
73 + </text>
74 + <view class="mt-2">
75 + <text class="text-orange-500 font-bold" style="font-size: 1.2rem;">
76 + ¥{{ car.price.toLocaleString() }}
77 + </text>
78 + <text class="text-xs text-gray-500 mt-1 block">{{ car.school }}</text>
79 + </view>
80 + <!-- 推荐理由 -->
81 + <view class="mt-1">
82 + <text class="text-xs text-green-600">{{ car.recommendReason }}</text>
83 + </view>
84 + </view>
85 + </view>
86 + </view>
87 + </view>
88 +
89 + <!-- Loading indicator -->
90 + <view v-if="loading" class="loading-container py-4 text-center">
91 + <text class="loading-text text-gray-500">加载中...</text>
92 + </view>
93 +
94 + <!-- 没有更多数据 -->
95 + <view v-if="!hasMore && recommendCars.length > 0" class="no-more-container py-4 text-center">
96 + <text class="text-gray-400 text-sm">没有更多数据了</text>
97 + </view>
98 + </scroll-view>
99 + </view>
100 + </view>
101 +
102 + <!-- 自定义TabBar -->
103 + <!-- <TabBar /> -->
104 +
105 + <!-- 成功提示 -->
106 + <nut-toast
107 + v-model:visible="toastVisible"
108 + :msg="toastMessage"
109 + :type="toastType"
110 + />
111 + </view>
112 +</template>
113 +
114 +<script setup>
115 +import { ref, computed, onMounted } from 'vue'
116 +import { Search2, Heart1, HeartFill } from '@nutui/icons-vue-taro'
117 +import './index.less'
118 +
119 +// 响应式数据
120 +const searchValue = ref('')
121 +const onBlurSearch = () => {
122 + console.warn(searchValue.value)
123 +}
124 +const favoriteIds = ref(['2', '4', '6'])
125 +
126 +// Filter states - 使用NutUI Menu组件
127 +const selectedBrand = ref('全部品牌')
128 +const selectedYear = ref('出厂年份')
129 +const selectedSchool = ref('所在学校')
130 +
131 +// Menu选项数据
132 +const brandOptions = ref([
133 + { text: '全部品牌', value: '全部品牌' },
134 + { text: '雅迪', value: '雅迪' },
135 + { text: '台铃', value: '台铃' },
136 + { text: '小鸟', value: '小鸟' },
137 + { text: '新日', value: '新日' },
138 + { text: '爱玛', value: '爱玛' },
139 + { text: '小牛', value: '小牛' }
140 +])
141 +
142 +const yearOptions = ref([
143 + { text: '出厂年份', value: '出厂年份' },
144 + { text: '2024年', value: '2024年' },
145 + { text: '2023年', value: '2023年' },
146 + { text: '2022年', value: '2022年' },
147 + { text: '2021年', value: '2021年' },
148 + { text: '2020年', value: '2020年' }
149 +])
150 +
151 +const schoolOptions = ref([
152 + { text: '所在学校', value: '所在学校' },
153 + { text: '上海理工大学', value: '上海理工大学' },
154 + { text: '上海复旦大学', value: '上海复旦大学' },
155 + { text: '上海同济大学', value: '上海同济大学' },
156 + { text: '上海交通大学', value: '上海交通大学' }
157 +])
158 +
159 +// 精品推荐车辆数据
160 +const recommendCars = ref([
161 + {
162 + id: 1,
163 + name: '小牛NGT 电动车',
164 + year: '2024年',
165 + batteryHealth: 100,
166 + mileage: 0,
167 + price: 5200,
168 + school: '上海理工大学',
169 + imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400&h=300&fit=crop',
170 + recommendReason: '品质优选',
171 + isNew: true,
172 + brand: '小牛'
173 + },
174 + {
175 + id: 2,
176 + name: '雅迪 DE3 电动车',
177 + year: '2024年',
178 + batteryHealth: 98,
179 + mileage: 200,
180 + price: 4800,
181 + school: '上海大学',
182 + imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?w=400&h=300&fit=crop',
183 + recommendReason: '热门推荐',
184 + isNew: true,
185 + brand: '雅迪'
186 + },
187 + {
188 + id: 3,
189 + name: '爱玛 A600 电动车',
190 + year: '2024年',
191 + batteryHealth: 95,
192 + mileage: 500,
193 + price: 3800,
194 + school: '华东理工大学',
195 + imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400&h=300&fit=crop',
196 + recommendReason: '性价比之选',
197 + isNew: true,
198 + brand: '爱玛'
199 + },
200 + {
201 + id: 4,
202 + name: '台铃 TDR-2024 电动车',
203 + year: '2024年',
204 + batteryHealth: 92,
205 + mileage: 800,
206 + price: 4200,
207 + school: '上海交通大学',
208 + imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400&h=300&fit=crop',
209 + recommendReason: '口碑好评',
210 + isNew: true,
211 + brand: '台铃'
212 + }
213 +])
214 +
215 +// 加载状态
216 +const loading = ref(false)
217 +const hasMore = ref(true)
218 +const currentPage = ref(1)
219 +const pageSize = ref(4)
220 +
221 +// Toast提示
222 +const toastVisible = ref(false)
223 +const toastMessage = ref('')
224 +const toastType = ref('success')
225 +
226 +// 滚动样式 - 考虑navbar、filter和TabBar的高度
227 +const scrollStyle = computed(() => {
228 + return {
229 + height: 'calc(100vh - 380rpx)' // 减去header、filter和TabBar的高度
230 + }
231 +})
232 +
233 +/**
234 + * 切换收藏状态
235 + * @param {string} carId - 车辆ID
236 + */
237 +const toggleFavorite = (carId) => {
238 + const index = favoriteIds.value.indexOf(carId)
239 + if (index > -1) {
240 + favoriteIds.value.splice(index, 1)
241 + showToast('取消收藏', 'success')
242 + } else {
243 + favoriteIds.value.push(carId)
244 + showToast('收藏成功', 'success')
245 + }
246 +}
247 +
248 +/**
249 + * 点击车辆卡片
250 + * @param {Object} car - 车辆信息
251 + */
252 +const onCarClick = (car) => {
253 + // TODO: 跳转到车辆详情页
254 + showToast(`查看${car.name}详情`, 'success')
255 +}
256 +
257 +// Menu组件事件处理方法
258 +/**
259 + * 品牌选择变化事件
260 + * @param {string} value - 选中的品牌值
261 + */
262 +const onBrandChange = (value) => {
263 + selectedBrand.value = value
264 + // 这里可以添加过滤逻辑
265 + filterCars()
266 +}
267 +
268 +/**
269 + * 年份选择变化事件
270 + * @param {string} value - 选中的年份值
271 + */
272 +const onYearChange = (value) => {
273 + selectedYear.value = value
274 + // 这里可以添加过滤逻辑
275 + filterCars()
276 +}
277 +
278 +/**
279 + * 学校选择变化事件
280 + * @param {string} value - 选中的学校值
281 + */
282 +const onSchoolChange = (value) => {
283 + selectedSchool.value = value
284 + // 这里可以添加过滤逻辑
285 + filterCars()
286 +}
287 +
288 +/**
289 + * 过滤车辆数据
290 + */
291 +const filterCars = () => {
292 + // TODO: 实现过滤逻辑
293 + showToast('筛选条件已更新', 'success')
294 +}
295 +
296 +/**
297 + * 生成模拟车辆数据
298 + * @param {number} page - 页码
299 + * @param {number} size - 每页数量
300 + * @returns {Array} 车辆数据数组
301 + */
302 +const generateMockData = (page, size) => {
303 + const brands = ['雅迪', '台铃', '小鸟', '新日', '爱玛', '小牛', '绿源', '立马']
304 + const schools = ['上海理工大学', '上海复旦大学', '上海同济大学', '上海交通大学', '华东师范大学', '上海大学']
305 + const years = ['2024年', '2023年', '2022年', '2021年', '2020年']
306 + const images = [
307 + 'https://images.unsplash.com/photo-1567922045116-2a00fae2ed03?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
308 + 'https://images.unsplash.com/photo-1573981368236-719bbb6f70f7?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
309 + 'https://images.unsplash.com/photo-1583568671741-c70dafa8e8e7?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
310 + 'https://images.unsplash.com/photo-1595941069915-4ebc5197c14a?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
311 + 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
312 + 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
313 + ]
314 + const recommendReasons = ['品质优选', '热门推荐', '性价比之选', '口碑好评', '精品车源', '优质推荐']
315 +
316 + const data = []
317 + for (let i = 0; i < size; i++) {
318 + const index = (page - 1) * size + i
319 + const brand = brands[Math.floor(Math.random() * brands.length)]
320 + const school = schools[Math.floor(Math.random() * schools.length)]
321 + const year = years[Math.floor(Math.random() * years.length)]
322 + const image = images[Math.floor(Math.random() * images.length)]
323 + const recommendReason = recommendReasons[Math.floor(Math.random() * recommendReasons.length)]
324 +
325 + data.push({
326 + id: `recommend_${index + 100}`,
327 + name: `${brand} ${['豪华版', '标准版', '运动版', '经典版'][Math.floor(Math.random() * 4)]}`,
328 + year: year,
329 + school: school,
330 + price: Math.floor(Math.random() * 3000) + 3000, // 精品推荐价格相对较高
331 + imageUrl: image,
332 + batteryHealth: Math.floor(Math.random() * 10) + 90, // 精品推荐电池健康度较高
333 + mileage: Math.floor(Math.random() * 1000), // 精品推荐里程较少
334 + brand: brand,
335 + recommendReason: recommendReason,
336 + isNew: Math.random() > 0.3 // 70%概率显示推荐标签
337 + })
338 + }
339 + return data
340 +}
341 +
342 +/**
343 + * 加载更多数据
344 + */
345 +const loadMore = () => {
346 + if (loading.value || !hasMore.value) return
347 +
348 + loading.value = true
349 +
350 + // 模拟网络请求延迟
351 + setTimeout(() => {
352 + // 模拟最多加载5页数据
353 + if (currentPage.value >= 5) {
354 + hasMore.value = false
355 + loading.value = false
356 + return
357 + }
358 +
359 + currentPage.value++
360 + const recommendData = generateMockData(currentPage.value, pageSize.value)
361 + recommendCars.value.push(...recommendData)
362 + loading.value = false
363 + }, 1000 + Math.random() * 1000)
364 +}
365 +
366 +/**
367 + * 滚动事件处理
368 + */
369 +const scroll = (e) => {
370 + // 可以在这里处理滚动事件
371 +}
372 +
373 +/**
374 + * 显示提示信息
375 + */
376 +const showToast = (message, type = 'success') => {
377 + toastMessage.value = message
378 + toastType.value = type
379 + toastVisible.value = true
380 +}
381 +
382 +// 初始化
383 +onMounted(() => {
384 + // 可以在这里加载初始数据
385 +})
386 +</script>
387 +
388 +<script>
389 +export default {
390 + name: 'RecommendCarListPage'
391 +}
392 +</script>