hookehuyr

refactor(productDetail): 重构商品详情页布局和样式

- 重新组织商品信息区域的布局结构
- 优化分享和收藏按钮的样式和交互方式
- 简化代码结构,减少嵌套层级
- 统一按钮和交互元素的视觉风格
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-04 17:15:46 4 + * @LastEditTime: 2025-07-04 21:19:14
5 * @FilePath: /jgdl/src/pages/productDetail/index.vue 5 * @FilePath: /jgdl/src/pages/productDetail/index.vue
6 * @Description: 商品详情页 6 * @Description: 商品详情页
7 --> 7 -->
...@@ -9,55 +9,40 @@ ...@@ -9,55 +9,40 @@
9 <view class="product-detail-page"> 9 <view class="product-detail-page">
10 <!-- 图片轮播 --> 10 <!-- 图片轮播 -->
11 <view class="image-carousel"> 11 <view class="image-carousel">
12 - <nut-swiper 12 + <nut-swiper :init-page="currentImageIndex" :pagination-visible="true" pagination-color="#426543"
13 - :init-page="currentImageIndex" 13 + auto-play="3000" @change="onSwiperChange">
14 - :pagination-visible="true"
15 - pagination-color="#426543"
16 - auto-play="3000"
17 - @change="onSwiperChange"
18 - >
19 <nut-swiper-item v-for="(image, index) in product.images" :key="index" style="height: 400rpx"> 14 <nut-swiper-item v-for="(image, index) in product.images" :key="index" style="height: 400rpx">
20 - <image 15 + <image :src="image" :alt="product.name" mode="aspectFill" class="w-full h-full object-cover"
21 - :src="image" 16 + @error="onImageError" @load="onImageLoad" />
22 - :alt="product.name"
23 - mode="aspectFill"
24 - class="w-full h-full object-cover"
25 - @error="onImageError"
26 - @load="onImageLoad"
27 - />
28 </nut-swiper-item> 17 </nut-swiper-item>
29 </nut-swiper> 18 </nut-swiper>
30 </view> 19 </view>
31 20
32 <!-- 商品信息 --> 21 <!-- 商品信息 -->
33 <view class="product-info bg-white p-4"> 22 <view class="product-info bg-white p-4">
34 - <text class="text-xl font-bold block mb-3">{{ product.name }}</text> 23 + <view class="flex items-center justify-between mb-3">
35 - <view class="flex items-center justify-between"> 24 + <text class="text-xl font-bold">{{ product.name }}</text>
36 - <view class="flex items-center"> 25 + <view class="flex space-x-3">
37 - <text class="text-2xl text-orange-500 font-bold"> 26 + <view class="w-8 h-8 bg-gray-100 rounded-full relative">
38 - ¥{{ product.price.toLocaleString() }} 27 + <button open-type="share" class="absolute inset-0 w-full h-full" style="border-radius: 50%;">
39 - </text> 28 + <view class="absolute inset-0 flex items-center justify-center" @tap="handleShare">
40 - <view class="ml-2 text-xs px-2 py-1 bg-orange-100 text-orange-600 rounded"> 29 + <Share size="16" color="#666" />
41 - 低于市场价{{ product.discountPercent }}%
42 </view> 30 </view>
31 + </button>
43 </view> 32 </view>
44 - <view class="flex space-x-4"> 33 + <view @tap="toggleFavorite"
45 - <button 34 + class="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center">
46 - open-type="share" 35 + <HeartFill v-if="isFavorite" size="18" color="#ef4444" />
47 - class="flex flex-col items-center" 36 + <Heart1 v-else size="18" color="#666" />
48 - >
49 - <view style="height: 2.55rem;">
50 - <Share size="18" color="#666" style="margin-bottom: 0.05rem;"/>
51 </view> 37 </view>
52 - <text class="text-xs text-gray-500" style="margin-top: 0.35rem;">分享</text>
53 - </button>
54 - <view @tap="toggleFavorite" class="flex flex-col items-center ml-3">
55 - <view class="p-2">
56 - <HeartFill v-if="isFavorite" size="20" color="#ef4444" />
57 - <Heart1 v-else size="20" color="#666" />
58 </view> 38 </view>
59 - <text class="text-xs text-gray-500 mt-1">{{ isFavorite ? '已收藏' : '收藏' }}</text>
60 </view> 39 </view>
40 + <view class="flex items-center mb-3">
41 + <text class="text-2xl font-bold text-orange-500 mr-2">
42 + ¥{{ product.price.toLocaleString() }}
43 + </text>
44 + <view class="ml-2 text-xs px-2 py-1 bg-orange-100 text-orange-600 rounded">
45 + 低于市场价{{ product.discountPercent }}%
61 </view> 46 </view>
62 </view> 47 </view>
63 </view> 48 </view>
...@@ -118,11 +103,8 @@ ...@@ -118,11 +103,8 @@
118 <view class="flex justify-between items-center"> 103 <view class="flex justify-between items-center">
119 <text>刹车磨损度</text> 104 <text>刹车磨损度</text>
120 <view class="flex"> 105 <view class="flex">
121 - <text 106 + <text v-for="star in 5" :key="star"
122 - v-for="star in 5" 107 + :class="star <= Math.round(product.brakeCondition) ? 'text-orange-400' : 'text-gray-300'">
123 - :key="star"
124 - :class="star <= Math.round(product.brakeCondition) ? 'text-orange-400' : 'text-gray-300'"
125 - >
126 108
127 </text> 109 </text>
128 </view> 110 </view>
...@@ -130,11 +112,8 @@ ...@@ -130,11 +112,8 @@
130 <view class="flex justify-between items-center"> 112 <view class="flex justify-between items-center">
131 <text>轮胎磨损度</text> 113 <text>轮胎磨损度</text>
132 <view class="flex"> 114 <view class="flex">
133 - <text 115 + <text v-for="star in 5" :key="star"
134 - v-for="star in 5" 116 + :class="star <= product.tireCondition ? 'text-orange-400' : 'text-gray-300'">
135 - :key="star"
136 - :class="star <= product.tireCondition ? 'text-orange-400' : 'text-gray-300'"
137 - >
138 117
139 </text> 118 </text>
140 </view> 119 </view>
...@@ -146,14 +125,8 @@ ...@@ -146,14 +125,8 @@
146 <view class="vehicle-description bg-white mt-2 p-4"> 125 <view class="vehicle-description bg-white mt-2 p-4">
147 <text class="text-lg font-medium mb-3 block">车辆描述</text> 126 <text class="text-lg font-medium mb-3 block">车辆描述</text>
148 <rich-text :nodes="product.richDescription" class="rich-content"></rich-text> 127 <rich-text :nodes="product.richDescription" class="rich-content"></rich-text>
149 - <image 128 + <image :src="product.images[1]" alt="车辆细节" mode="aspectFill"
150 - :src="product.images[1]" 129 + class="w-full h-40 object-cover rounded-lg mt-3" @error="onImageError" @load="onImageLoad" />
151 - alt="车辆细节"
152 - mode="aspectFill"
153 - class="w-full h-40 object-cover rounded-lg mt-3"
154 - @error="onImageError"
155 - @load="onImageLoad"
156 - />
157 </view> 130 </view>
158 131
159 <!-- 卖家信息 --> 132 <!-- 卖家信息 -->
...@@ -161,11 +134,13 @@ ...@@ -161,11 +134,13 @@
161 <text class="text-lg font-medium mb-3 block">卖家信息</text> 134 <text class="text-lg font-medium mb-3 block">卖家信息</text>
162 <view class="flex items-center justify-between"> 135 <view class="flex items-center justify-between">
163 <view class="flex items-center"> 136 <view class="flex items-center">
164 - <image :src="product.seller.avatar || defaultAvatar" :alt="product.seller.name" mode="aspectFill" class="w-10 h-10 rounded-full object-cover mr-3" /> 137 + <image :src="product.seller.avatar || defaultAvatar" :alt="product.seller.name" mode="aspectFill"
138 + class="w-10 h-10 rounded-full object-cover mr-3" />
165 <view> 139 <view>
166 <view class="flex items-center"> 140 <view class="flex items-center">
167 <text class="font-medium">{{ product.seller.name }}</text> 141 <text class="font-medium">{{ product.seller.name }}</text>
168 - <view v-if="product.seller.verified" class="ml-1 text-xs text-blue-500 bg-blue-50 px-1 py-0.5 rounded"> 142 + <view v-if="product.seller.verified"
143 + class="ml-1 text-xs text-blue-500 bg-blue-50 px-1 py-0.5 rounded">
169 已认证卖家 144 已认证卖家
170 </view> 145 </view>
171 </view> 146 </view>
...@@ -189,24 +164,14 @@ ...@@ -189,24 +164,14 @@
189 <view class="bottom-actions"> 164 <view class="bottom-actions">
190 <nut-row :gutter="10"> 165 <nut-row :gutter="10">
191 <nut-col :span="12"> 166 <nut-col :span="12">
192 - <nut-button @click="handleContactSeller" 167 + <nut-button @click="handleContactSeller" block type="default" shape="round"
193 - block 168 + style="border-color: #f97316; color: #f97316;">
194 - type="default"
195 - shape="round"
196 - style="border-color: #f97316; color: #f97316;"
197 - >
198 联系卖家 169 联系卖家
199 </nut-button> 170 </nut-button>
200 </nut-col> 171 </nut-col>
201 <nut-col :span="12"> 172 <nut-col :span="12">
202 - <nut-button 173 + <nut-button @click="handlePurchase" block type="primary" shape="round" color="#EB5305"
203 - @click="handlePurchase" 174 + style="background-color: #f97316; border-color: #f97316;">
204 - block
205 - type="primary"
206 - shape="round"
207 - color="#EB5305"
208 - style="background-color: #f97316; border-color: #f97316;"
209 - >
210 我想购买 175 我想购买
211 </nut-button> 176 </nut-button>
212 </nut-col> 177 </nut-col>
...@@ -214,40 +179,27 @@ ...@@ -214,40 +179,27 @@
214 </view> 179 </view>
215 180
216 <!-- 微信号弹框 --> 181 <!-- 微信号弹框 -->
217 - <nut-dialog 182 + <nut-dialog v-model:visible="showWechat" title="卖家微信号" :close-on-click-overlay="true" :no-footer="true">
218 - v-model:visible="showWechat"
219 - title="卖家微信号"
220 - :close-on-click-overlay="true"
221 - :no-footer="true"
222 - >
223 <view class="text-center p-4"> 183 <view class="text-center p-4">
224 <text class="text-lg font-medium block mb-2">{{ product.seller.wechat }}</text> 184 <text class="text-lg font-medium block mb-2">{{ product.seller.wechat }}</text>
225 <!-- <text class="text-sm text-gray-500 block mb-4">长按复制微信号</text> --> 185 <!-- <text class="text-sm text-gray-500 block mb-4">长按复制微信号</text> -->
226 - <nut-button 186 + <nut-button @click="copyWechat" type="primary" size="small"
227 - @click="copyWechat" 187 + style="background-color: #f97316; border-color: #f97316;">
228 - type="primary"
229 - size="small"
230 - style="background-color: #f97316; border-color: #f97316;"
231 - >
232 复制微信号 188 复制微信号
233 </nut-button> 189 </nut-button>
234 </view> 190 </view>
235 </nut-dialog> 191 </nut-dialog>
236 192
237 <!-- 联系卖家弹框 --> 193 <!-- 联系卖家弹框 -->
238 - <nut-popup 194 + <nut-popup v-model:visible="showContactModal" position="bottom" :style="{ height: '60%' }" round>
239 - v-model:visible="showContactModal"
240 - position="bottom"
241 - :style="{ height: '60%' }"
242 - round
243 - >
244 <view class="contact-modal p-4"> 195 <view class="contact-modal p-4">
245 <view class="text-center mb-4"> 196 <view class="text-center mb-4">
246 <text class="text-lg font-medium">联系卖家</text> 197 <text class="text-lg font-medium">联系卖家</text>
247 </view> 198 </view>
248 <view class="seller-card bg-gray-50 rounded-lg p-3 mb-4"> 199 <view class="seller-card bg-gray-50 rounded-lg p-3 mb-4">
249 <view class="flex items-center"> 200 <view class="flex items-center">
250 - <image :src="product.seller.avatar || defaultAvatar" :alt="product.seller.name" mode="aspectFill" class="w-12 h-12 rounded-full object-cover mr-3" /> 201 + <image :src="product.seller.avatar || defaultAvatar" :alt="product.seller.name"
202 + mode="aspectFill" class="w-12 h-12 rounded-full object-cover mr-3" />
251 <view> 203 <view>
252 <text class="font-medium block">{{ product.seller.name }}</text> 204 <text class="font-medium block">{{ product.seller.name }}</text>
253 <text class="text-sm text-gray-500 block">{{ product.seller.school }}</text> 205 <text class="text-sm text-gray-500 block">{{ product.seller.school }}</text>
...@@ -257,40 +209,24 @@ ...@@ -257,40 +209,24 @@
257 209
258 <!-- 留言输入框 --> 210 <!-- 留言输入框 -->
259 <view class="message-input mb-4"> 211 <view class="message-input mb-4">
260 - <nut-textarea 212 + <nut-textarea v-model="messageText" placeholder="请输入您想对卖家说的话..." :rows="4" :max-length="200"
261 - v-model="messageText" 213 + show-word-limit class="w-full" />
262 - placeholder="请输入您想对卖家说的话..."
263 - :rows="4"
264 - :max-length="200"
265 - show-word-limit
266 - class="w-full"
267 - />
268 </view> 214 </view>
269 215
270 <!-- 快捷标签 --> 216 <!-- 快捷标签 -->
271 <view class="quick-tags mb-4"> 217 <view class="quick-tags mb-4">
272 <text class="text-sm text-gray-600 block mb-2">快捷输入:</text> 218 <text class="text-sm text-gray-600 block mb-2">快捷输入:</text>
273 <view class="flex flex-wrap gap-2"> 219 <view class="flex flex-wrap gap-2">
274 - <view 220 + <view v-for="tag in quickTags" :key="tag" @click="addQuickTag(tag)"
275 - v-for="tag in quickTags" 221 + class="quick-tag px-3 py-1 bg-orange-50 text-orange-600 rounded-full text-sm cursor-pointer">
276 - :key="tag"
277 - @click="addQuickTag(tag)"
278 - class="quick-tag px-3 py-1 bg-orange-50 text-orange-600 rounded-full text-sm cursor-pointer"
279 - >
280 {{ tag }} 222 {{ tag }}
281 </view> 223 </view>
282 </view> 224 </view>
283 </view> 225 </view>
284 226
285 <!-- 发送按钮 --> 227 <!-- 发送按钮 -->
286 - <nut-button 228 + <nut-button @click="sendMessageToSeller" block type="primary" shape="round"
287 - @click="sendMessageToSeller" 229 + style="background-color: #f97316; border-color: #f97316;" :disabled="!messageText.trim()">
288 - block
289 - type="primary"
290 - shape="round"
291 - style="background-color: #f97316; border-color: #f97316;"
292 - :disabled="!messageText.trim()"
293 - >
294 发送消息 230 发送消息
295 </nut-button> 231 </nut-button>
296 </view> 232 </view>
...@@ -566,15 +502,15 @@ const onImageError = (e) => { ...@@ -566,15 +502,15 @@ const onImageError = (e) => {
566 } 502 }
567 } 503 }
568 504
569 -.space-x-3 > view:not(:first-child) { 505 +.space-x-3>view:not(:first-child) {
570 margin-left: 0.75rem; 506 margin-left: 0.75rem;
571 } 507 }
572 508
573 -.space-x-6 > view:not(:first-child) { 509 +.space-x-6>view:not(:first-child) {
574 margin-left: 1.5rem; 510 margin-left: 1.5rem;
575 } 511 }
576 512
577 -.space-y-3 > view:not(:first-child) { 513 +.space-y-3>view:not(:first-child) {
578 margin-top: 0.75rem; 514 margin-top: 0.75rem;
579 } 515 }
580 516
......