feat(组件): 新增精品推荐组件并替换多处重复代码
将精品推荐功能抽离为独立组件FeaturedRecommendations,并在首页和发布页中使用 移除重复的精品推荐代码逻辑,统一数据获取和展示方式
Showing
4 changed files
with
138 additions
and
164 deletions
| ... | @@ -8,6 +8,7 @@ export {} | ... | @@ -8,6 +8,7 @@ export {} |
| 8 | declare module 'vue' { | 8 | declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default'] | 10 | BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default'] |
| 11 | + FeaturedRecommendations: typeof import('./src/components/FeaturedRecommendations.vue')['default'] | ||
| 11 | NavBar: typeof import('./src/components/navBar.vue')['default'] | 12 | NavBar: typeof import('./src/components/navBar.vue')['default'] |
| 12 | NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] | 13 | NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] |
| 13 | NutButton: typeof import('@nutui/nutui-taro')['Button'] | 14 | NutButton: typeof import('@nutui/nutui-taro')['Button'] | ... | ... |
src/components/FeaturedRecommendations.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="px-4 mt-4"> | ||
| 3 | + <view class="flex justify-between items-center mb-2"> | ||
| 4 | + <text class="text-lg font-medium">精品推荐</text> | ||
| 5 | + <view class="text-sm text-gray-500 flex items-center" @tap="onMoreRecommendClick"> | ||
| 6 | + <text>更多</text> | ||
| 7 | + <RectRight size="12" /> | ||
| 8 | + </view> | ||
| 9 | + </view> | ||
| 10 | + <view class="grid grid-cols-2 gap-3"> | ||
| 11 | + <view v-for="scooter in featuredScooters" :key="scooter.id" | ||
| 12 | + class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)"> | ||
| 13 | + <view class="relative p-2"> | ||
| 14 | + <image :src="scooter.front_photo" mode="aspectFill" class="w-full h-36 object-cover rounded-lg" /> | ||
| 15 | + <view | ||
| 16 | + class="absolute top-4 right-3 w-7 h-7 rounded-full bg-white bg-opacity-80 flex items-center justify-center" | ||
| 17 | + @tap.stop="() => toggleFavorite(scooter)"> | ||
| 18 | + <Heart1 v-if="!scooter.is_favorite" size="22" :color="'#9ca3af'" /> | ||
| 19 | + <HeartFill v-else size="22" :color="'#ef4444'" /> | ||
| 20 | + </view> | ||
| 21 | + <view v-if="scooter.verification_status === 5" | ||
| 22 | + class="absolute bottom-4 right-4 text-white text-xs px-1.5 py-0.5 rounded flex items-center" | ||
| 23 | + style="background-color: #EB5305;"> | ||
| 24 | + <Check size="12" color="#ffffff" class="mr-0.5" /> | ||
| 25 | + <text class="text-white">认证</text> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | + <view class="p-2 pl-3"> | ||
| 29 | + <text class="font-medium text-sm block">{{ scooter.brand }} {{ scooter.model }}</text> | ||
| 30 | + <text class="text-xs text-gray-500 block mt-1 mb-1"> | ||
| 31 | + {{ scooter.manufacture_year }}年 · {{ scooter.school_name }} | ||
| 32 | + </text> | ||
| 33 | + <view class="mt-1"> | ||
| 34 | + <text class="text-orange-500 font-bold" style="font-size: 1.25rem;"> | ||
| 35 | + ¥{{ scooter.price.toLocaleString() }} | ||
| 36 | + </text> | ||
| 37 | + </view> | ||
| 38 | + </view> | ||
| 39 | + </view> | ||
| 40 | + </view> | ||
| 41 | + </view> | ||
| 42 | +</template> | ||
| 43 | + | ||
| 44 | +<script setup> | ||
| 45 | +import Taro from '@tarojs/taro' | ||
| 46 | +import { ref, onMounted } from 'vue' | ||
| 47 | +import { RectRight, Check, Heart1, HeartFill } from '@nutui/icons-vue-taro' | ||
| 48 | +import { getRecommendVehicleAPI } from '@/api/car' | ||
| 49 | +import { useFavorite } from '@/composables/useFavorite' | ||
| 50 | +import { DEFAULT_COVER_IMG } from '@/utils/config' | ||
| 51 | + | ||
| 52 | +// 定义组件名称 | ||
| 53 | +defineOptions({ | ||
| 54 | + name: 'FeaturedRecommendations' | ||
| 55 | +}) | ||
| 56 | + | ||
| 57 | +// 精品推荐数据 | ||
| 58 | +const featuredScooters = ref([]) | ||
| 59 | + | ||
| 60 | +// 使用收藏功能composables | ||
| 61 | +const { toggleFavorite } = useFavorite() | ||
| 62 | + | ||
| 63 | +/** | ||
| 64 | + * 查看更多点击事件 | ||
| 65 | + */ | ||
| 66 | +const onMoreRecommendClick = () => { | ||
| 67 | + Taro.navigateTo({ | ||
| 68 | + url: '/pages/recommendCarList/index' | ||
| 69 | + }) | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +/** | ||
| 73 | + * 点击产品卡片 | ||
| 74 | + * @param {Object} scooter - 电动车信息 | ||
| 75 | + */ | ||
| 76 | +const onProductClick = (scooter) => { | ||
| 77 | + Taro.navigateTo({ | ||
| 78 | + url: `/pages/productDetail/index?id=${scooter.id}` | ||
| 79 | + }) | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +/** | ||
| 83 | + * 加载精品推荐数据 | ||
| 84 | + */ | ||
| 85 | +const loadFeaturedData = async () => { | ||
| 86 | + try { | ||
| 87 | + const res = await getRecommendVehicleAPI({ section: 3, page: 0, limit: 4 }) | ||
| 88 | + if (res.code) { | ||
| 89 | + // 处理图片数据 | ||
| 90 | + const processedData = res.data.list.map(item => ({ | ||
| 91 | + ...item, | ||
| 92 | + front_photo: item.front_photo || DEFAULT_COVER_IMG, | ||
| 93 | + // 确保价格为数字类型 | ||
| 94 | + price: Number(item.price) || 0, | ||
| 95 | + market_price: Number(item.market_price) || 0 | ||
| 96 | + })) | ||
| 97 | + featuredScooters.value = processedData | ||
| 98 | + } | ||
| 99 | + } catch (error) { | ||
| 100 | + console.error('加载精品推荐数据失败:', error) | ||
| 101 | + } | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +// 组件挂载时加载数据 | ||
| 105 | +onMounted(() => { | ||
| 106 | + loadFeaturedData() | ||
| 107 | +}) | ||
| 108 | +</script> | ||
| 109 | + | ||
| 110 | +<style lang="less" scoped> | ||
| 111 | +// 使用Tailwind CSS类,只保留必要的自定义样式 | ||
| 112 | +.grid { | ||
| 113 | + display: grid; | ||
| 114 | +} | ||
| 115 | + | ||
| 116 | +.grid-cols-2 { | ||
| 117 | + grid-template-columns: repeat(2, 1fr); | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +.gap-3 { | ||
| 121 | + gap: 0.75rem; | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +// 确保图片正确显示 | ||
| 125 | +image { | ||
| 126 | + display: block; | ||
| 127 | +} | ||
| 128 | +</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 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-11 10:58:14 | 4 | + * @LastEditTime: 2025-07-11 11:14:57 |
| 5 | * @FilePath: /jgdl/src/pages/index/index.vue | 5 | * @FilePath: /jgdl/src/pages/index/index.vue |
| 6 | * @Description: 捡个电驴首页 | 6 | * @Description: 捡个电驴首页 |
| 7 | --> | 7 | --> |
| ... | @@ -65,52 +65,7 @@ | ... | @@ -65,52 +65,7 @@ |
| 65 | </view> | 65 | </view> |
| 66 | 66 | ||
| 67 | <!-- Featured Recommendations --> | 67 | <!-- Featured Recommendations --> |
| 68 | - <view class="px-4 mt-4"> | 68 | + <FeaturedRecommendations /> |
| 69 | - <view class="flex justify-between items-center mb-2"> | ||
| 70 | - <text class="text-lg font-medium">精品推荐</text> | ||
| 71 | - <view class="text-sm text-gray-500 flex items-center" @tap="onMoreRecommendClick"> | ||
| 72 | - <text>更多</text> | ||
| 73 | - <RectRight size="12" /> | ||
| 74 | - </view> | ||
| 75 | - </view> | ||
| 76 | - <view class="grid grid-cols-2 gap-3"> | ||
| 77 | - <view v-for="scooter in featuredScooters" :key="scooter.id" | ||
| 78 | - class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)"> | ||
| 79 | - <view class="relative p-2"> | ||
| 80 | - <image :src="scooter.front_photo" mode="aspectFill" class="w-full h-36 object-cover rounded-lg" /> | ||
| 81 | - <view | ||
| 82 | - class="absolute top-4 right-3 w-7 h-7 rounded-full bg-white bg-opacity-80 flex items-center justify-center" | ||
| 83 | - @tap.stop="() => toggleFavorite(scooter)"> | ||
| 84 | - <Heart1 v-if="!scooter.is_favorite" size="22" :color="'#9ca3af'" /> | ||
| 85 | - <HeartFill v-else size="22" :color="'#ef4444'" /> | ||
| 86 | - </view> | ||
| 87 | - <view v-if="scooter.verification_status === 5" | ||
| 88 | - class="absolute bottom-4 right-4 text-white text-xs px-1.5 py-0.5 rounded flex items-center" | ||
| 89 | - style="background-color: #EB5305;"> | ||
| 90 | - <Check size="12" color="#ffffff" class="mr-0.5" /> | ||
| 91 | - <text class="text-white">认证</text> | ||
| 92 | - </view> | ||
| 93 | - </view> | ||
| 94 | - <view class="p-2 pl-3"> | ||
| 95 | - <text class="font-medium text-sm block">{{ scooter.brand }} {{ scooter.model }}</text> | ||
| 96 | - <text class="text-xs text-gray-500 block mt-1 mb-1"> | ||
| 97 | - {{ scooter.manufacture_year }}年 · {{ scooter.school_name }} | ||
| 98 | - <!-- <text v-if="scooter.battery_capacity_ah">电池容量{{ scooter.battery_capacity_ah }}Ah</text> | ||
| 99 | - <text v-if="scooter.total_mileage_km"> 行驶{{ scooter.total_mileage_km }}公里</text> --> | ||
| 100 | - </text> | ||
| 101 | - <view class="mt-1"> | ||
| 102 | - <text class="text-orange-500 font-bold" style="font-size: 1.25rem;"> | ||
| 103 | - ¥{{ scooter.price.toLocaleString() }} | ||
| 104 | - </text> | ||
| 105 | - <!-- <text v-if="scooter.isVerified" class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded"> | ||
| 106 | - 低于市场价10% | ||
| 107 | - </text> --> | ||
| 108 | - <!-- <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text> --> | ||
| 109 | - </view> | ||
| 110 | - </view> | ||
| 111 | - </view> | ||
| 112 | - </view> | ||
| 113 | - </view> | ||
| 114 | 69 | ||
| 115 | <!-- Latest Listings --> | 70 | <!-- Latest Listings --> |
| 116 | <view class="px-4 mt-6 mb-20"> | 71 | <view class="px-4 mt-6 mb-20"> |
| ... | @@ -173,6 +128,7 @@ import { ref, onMounted } from 'vue' | ... | @@ -173,6 +128,7 @@ import { ref, onMounted } from 'vue' |
| 173 | import { Clock, Star, RectRight, Check, Search2, Shop, Heart1, HeartFill } from '@nutui/icons-vue-taro' | 128 | import { Clock, Star, RectRight, Check, Search2, Shop, Heart1, HeartFill } from '@nutui/icons-vue-taro' |
| 174 | import TabBar from '@/components/TabBar.vue' | 129 | import TabBar from '@/components/TabBar.vue' |
| 175 | import SearchPopup from '@/components/SearchPopup.vue' | 130 | import SearchPopup from '@/components/SearchPopup.vue' |
| 131 | +import FeaturedRecommendations from '@/components/FeaturedRecommendations.vue' | ||
| 176 | import "./index.less"; | 132 | import "./index.less"; |
| 177 | // 导入接口 | 133 | // 导入接口 |
| 178 | import { getRecommendVehicleAPI, getVehicleListAPI } from '@/api/car'; | 134 | import { getRecommendVehicleAPI, getVehicleListAPI } from '@/api/car'; |
| ... | @@ -191,21 +147,12 @@ const onSearchHandle = () => { | ... | @@ -191,21 +147,12 @@ const onSearchHandle = () => { |
| 191 | // Banner图片 | 147 | // Banner图片 |
| 192 | const bannerImages = ref([]) | 148 | const bannerImages = ref([]) |
| 193 | 149 | ||
| 194 | -// 精品推荐数据 | ||
| 195 | -const featuredScooters = ref([]) | ||
| 196 | - | ||
| 197 | // 最新上架数据 | 150 | // 最新上架数据 |
| 198 | const latestScooters = ref([]) | 151 | const latestScooters = ref([]) |
| 199 | 152 | ||
| 200 | // 使用收藏功能composables | 153 | // 使用收藏功能composables |
| 201 | const { toggleFavorite } = useFavorite() | 154 | const { toggleFavorite } = useFavorite() |
| 202 | 155 | ||
| 203 | -const onMoreRecommendClick = () => { | ||
| 204 | - Taro.navigateTo({ | ||
| 205 | - url: '/pages/recommendCarList/index' | ||
| 206 | - }) | ||
| 207 | -} | ||
| 208 | - | ||
| 209 | /** | 156 | /** |
| 210 | * 点击产品卡片 | 157 | * 点击产品卡片 |
| 211 | * @param {Object} scooter - 电动车信息 | 158 | * @param {Object} scooter - 电动车信息 |
| ... | @@ -292,21 +239,6 @@ onMounted(async () => { | ... | @@ -292,21 +239,6 @@ onMounted(async () => { |
| 292 | if (res1.code) { | 239 | if (res1.code) { |
| 293 | bannerImages.value = res1.data.list.map(item => item.front_photo); | 240 | bannerImages.value = res1.data.list.map(item => item.front_photo); |
| 294 | } | 241 | } |
| 295 | - // 获取精品推荐 | ||
| 296 | - const res2 = await getRecommendVehicleAPI({ section: 3 }) | ||
| 297 | - if (res2.code) { | ||
| 298 | - featuredScooters.value = res2.data.list | ||
| 299 | - // 处理图片数据 | ||
| 300 | - const processedData = res2.data.list.map(item => ({ | ||
| 301 | - ...item, | ||
| 302 | - front_photo: item.front_photo || DEFAULT_COVER_IMG, | ||
| 303 | - // 确保价格为数字类型 | ||
| 304 | - price: Number(item.price) || 0, | ||
| 305 | - market_price: Number(item.market_price) || 0 | ||
| 306 | - })) | ||
| 307 | - | ||
| 308 | - featuredScooters.value = processedData | ||
| 309 | - } | ||
| 310 | // 获取最新上架 | 242 | // 获取最新上架 |
| 311 | const res3 = await getVehicleListAPI({ page: 0, limit: 5 }) | 243 | const res3 = await getVehicleListAPI({ page: 0, limit: 5 }) |
| 312 | if (res3.code) { | 244 | if (res3.code) { | ... | ... |
| ... | @@ -83,46 +83,8 @@ | ... | @@ -83,46 +83,8 @@ |
| 83 | </view> | 83 | </view> |
| 84 | 84 | ||
| 85 | <!-- Featured recommendations section --> | 85 | <!-- Featured recommendations section --> |
| 86 | - <view class="mt-6 mb-20 ml-4 mr-4"> | 86 | + <view class="mb-20"> |
| 87 | - <view class="flex justify-between items-center mb-3"> | 87 | + <FeaturedRecommendations /> |
| 88 | - <text class="text-lg font-medium">精品推荐</text> | ||
| 89 | - <view class="text-sm text-gray-500 flex items-center" @tap="onMoreRecommendClick"> | ||
| 90 | - <text>更多</text> | ||
| 91 | - <RectRight size="12" /> | ||
| 92 | - </view> | ||
| 93 | - </view> | ||
| 94 | - <view class="grid grid-cols-2 gap-3"> | ||
| 95 | - <view v-for="scooter in featuredScooters" :key="scooter.id" | ||
| 96 | - class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)"> | ||
| 97 | - <view class="relative p-2"> | ||
| 98 | - <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill" | ||
| 99 | - class="w-full h-36 object-cover rounded-lg" /> | ||
| 100 | - <view class="absolute top-4 right-3 w-7 h-7 rounded-full bg-white bg-opacity-80 flex items-center justify-center" @tap.stop="() => toggleFavorite(scooter)"> | ||
| 101 | - <Heart1 v-if="!scooter.is_favorite" size="20" color="#9ca3af" /> | ||
| 102 | - <HeartFill v-else size="20" color="#ef4444" /> | ||
| 103 | - </view> | ||
| 104 | - <view v-if="scooter.isVerified" | ||
| 105 | - class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center"> | ||
| 106 | - <Check size="12" color="#ffffff" class="mr-0.5" /> | ||
| 107 | - <text class="text-white">认证</text> | ||
| 108 | - </view> | ||
| 109 | - </view> | ||
| 110 | - <view class="p-2"> | ||
| 111 | - <text class="font-medium text-sm block">{{ scooter.name }}</text> | ||
| 112 | - <text class="text-xs text-gray-500 block"> | ||
| 113 | - {{ scooter.year }} · | ||
| 114 | - <text v-if="scooter.batteryHealth">电池健康度{{ scooter.batteryHealth }}%</text> | ||
| 115 | - <text v-if="scooter.mileage"> 行驶{{ scooter.mileage }}公里</text> | ||
| 116 | - </text> | ||
| 117 | - <view class="mt-1"> | ||
| 118 | - <text class="text-orange-500 font-bold"> | ||
| 119 | - ¥{{ scooter.price.toLocaleString() }} | ||
| 120 | - </text> | ||
| 121 | - <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text> | ||
| 122 | - </view> | ||
| 123 | - </view> | ||
| 124 | - </view> | ||
| 125 | - </view> | ||
| 126 | </view> | 88 | </view> |
| 127 | </view> | 89 | </view> |
| 128 | 90 | ||
| ... | @@ -134,8 +96,9 @@ | ... | @@ -134,8 +96,9 @@ |
| 134 | <script setup> | 96 | <script setup> |
| 135 | import { ref } from 'vue' | 97 | import { ref } from 'vue' |
| 136 | import Taro from '@tarojs/taro' | 98 | import Taro from '@tarojs/taro' |
| 137 | -import { Search2, RectRight, Check, Heart1, HeartFill } from '@nutui/icons-vue-taro' | 99 | +import { Search2, Check, Heart1, HeartFill } from '@nutui/icons-vue-taro' |
| 138 | import TabBar from '@/components/TabBar.vue' | 100 | import TabBar from '@/components/TabBar.vue' |
| 101 | +import FeaturedRecommendations from '@/components/FeaturedRecommendations.vue' | ||
| 139 | import { useFavorite } from '@/composables/useFavorite' | 102 | import { useFavorite } from '@/composables/useFavorite' |
| 140 | 103 | ||
| 141 | // 响应式数据 | 104 | // 响应式数据 |
| ... | @@ -234,50 +197,7 @@ const scooters = ref([ | ... | @@ -234,50 +197,7 @@ const scooters = ref([ |
| 234 | } | 197 | } |
| 235 | ]) | 198 | ]) |
| 236 | 199 | ||
| 237 | -// 精品推荐数据 - 参考PostPage.tsx | 200 | + |
| 238 | -const featuredScooters = ref([ | ||
| 239 | - { | ||
| 240 | - id: '1', | ||
| 241 | - name: '小龟电动车', | ||
| 242 | - year: '2023年', | ||
| 243 | - school: '上海理工大学', | ||
| 244 | - price: 3880, | ||
| 245 | - batteryHealth: 92, | ||
| 246 | - mileage: 2000, | ||
| 247 | - imageUrl: 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 248 | - isVerified: true | ||
| 249 | - }, | ||
| 250 | - { | ||
| 251 | - id: '2', | ||
| 252 | - name: '立马电动车', | ||
| 253 | - year: '2022年', | ||
| 254 | - school: '上海复旦大学', | ||
| 255 | - price: 2999, | ||
| 256 | - batteryHealth: 95, | ||
| 257 | - mileage: 1500, | ||
| 258 | - imageUrl: 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | ||
| 259 | - }, | ||
| 260 | - { | ||
| 261 | - id: '3', | ||
| 262 | - name: '绿源电动车', | ||
| 263 | - year: '2024年', | ||
| 264 | - school: '上海同济大学', | ||
| 265 | - price: 6000, | ||
| 266 | - batteryHealth: 98, | ||
| 267 | - mileage: 500, | ||
| 268 | - imageUrl: 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | ||
| 269 | - }, | ||
| 270 | - { | ||
| 271 | - id: '4', | ||
| 272 | - name: '新日电动车', | ||
| 273 | - year: '2024年', | ||
| 274 | - school: '上海同济大学', | ||
| 275 | - price: 6700, | ||
| 276 | - batteryHealth: 96, | ||
| 277 | - mileage: 500, | ||
| 278 | - imageUrl: 'https://images.unsplash.com/photo-1595941069915-4ebc5197c14a?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | ||
| 279 | - } | ||
| 280 | -]) | ||
| 281 | 201 | ||
| 282 | /** | 202 | /** |
| 283 | * 切换收藏状态 | 203 | * 切换收藏状态 |
| ... | @@ -296,14 +216,7 @@ const onProductClick = (scooter) => { | ... | @@ -296,14 +216,7 @@ const onProductClick = (scooter) => { |
| 296 | }) | 216 | }) |
| 297 | } | 217 | } |
| 298 | 218 | ||
| 299 | -/** | 219 | + |
| 300 | - * 查看更多点击事件 | ||
| 301 | - */ | ||
| 302 | -const onMoreRecommendClick = () => { | ||
| 303 | - Taro.navigateTo({ | ||
| 304 | - url: '/pages/recommendCarList/index' | ||
| 305 | - }) | ||
| 306 | -} | ||
| 307 | 220 | ||
| 308 | // Menu组件事件处理方法 | 221 | // Menu组件事件处理方法 |
| 309 | /** | 222 | /** | ... | ... |
-
Please register or login to post a comment