hookehuyr

feat(首页): 重构首页UI组件并优化交互体验

- 使用NutUI组件替换自定义搜索栏和轮播图
- 优化商品卡片布局和收藏按钮样式
- 移除与NutUI冲突的样式和导入
- 更新全局组件声明以支持新增NutUI组件
- 修复文件末尾缺少换行符的问题
...@@ -8,7 +8,9 @@ export {} ...@@ -8,7 +8,9 @@ export {}
8 declare module 'vue' { 8 declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 NavBar: typeof import('./src/components/navBar.vue')['default'] 10 NavBar: typeof import('./src/components/navBar.vue')['default']
11 - NutInput: typeof import('@nutui/nutui-taro')['Input'] 11 + NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar']
12 + NutSwiper: typeof import('@nutui/nutui-taro')['Swiper']
13 + NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem']
12 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] 14 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
13 PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] 15 PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default']
14 RouterLink: typeof import('vue-router')['RouterLink'] 16 RouterLink: typeof import('vue-router')['RouterLink']
......
...@@ -69,7 +69,6 @@ export default defineConfig(async (merge) => { ...@@ -69,7 +69,6 @@ export default defineConfig(async (merge) => {
69 pxtransform: { 69 pxtransform: {
70 enable: true, 70 enable: true,
71 config: { 71 config: {
72 -
73 } 72 }
74 }, 73 },
75 // url: { 74 // url: {
...@@ -134,7 +133,6 @@ export default defineConfig(async (merge) => { ...@@ -134,7 +133,6 @@ export default defineConfig(async (merge) => {
134 } 133 }
135 }, 134 },
136 webpackChain(chain) { 135 webpackChain(chain) {
137 -
138 chain.plugin('unplugin-vue-components').use(Components({ 136 chain.plugin('unplugin-vue-components').use(Components({
139 resolvers: [NutUIResolver({taro: true})] 137 resolvers: [NutUIResolver({taro: true})]
140 })) 138 }))
......
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
3 @tailwind utilities; 3 @tailwind utilities;
4 4
5 /* 修复 NutUI 图标字体样式 */ 5 /* 修复 NutUI 图标字体样式 */
6 -.nut-icon { 6 +// .nut-icon {
7 - font-style: normal !important; 7 +// font-style: normal !important;
8 - font-weight: normal !important; 8 +// font-weight: normal !important;
9 -} 9 +// }
10 10
11 /* 修复所有可能的图标字体 */ 11 /* 修复所有可能的图标字体 */
12 -[class*="nut-icon"] { 12 +// [class*="nut-icon"] {
13 - font-style: normal !important; 13 +// font-style: normal !important;
14 - font-weight: normal !important; 14 +// font-weight: normal !important;
15 -} 15 +// }
......
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-01 18:18:19 4 + * @LastEditTime: 2025-07-01 19:43:08
5 * @FilePath: /jgdl/src/pages/index/index.vue 5 * @FilePath: /jgdl/src/pages/index/index.vue
6 * @Description: 捡个电驴首页 6 * @Description: 捡个电驴首页
7 --> 7 -->
...@@ -11,33 +11,22 @@ ...@@ -11,33 +11,22 @@
11 <view class="bg-orange-400 p-4 pt-8 pb-6"> 11 <view class="bg-orange-400 p-4 pt-8 pb-6">
12 <view class="text-2xl font-bold text-white mb-3">捡个电驴</view> 12 <view class="text-2xl font-bold text-white mb-3">捡个电驴</view>
13 <!-- Search Bar --> 13 <!-- Search Bar -->
14 - <view class="relative"> 14 + <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" shape="round" background="transparent"
15 - <view class="absolute inset-y-0 left-3 flex items-center pointer-events-none"> 15 + input-background="#ffffff">
16 - <Search size="18" color="#9ca3af" /> 16 + <template #leftin>
17 - </view> 17 + <Search2 />
18 - <nut-input 18 + </template>
19 - v-model="searchValue" 19 + </nut-searchbar>
20 - placeholder="搜索品牌型号"
21 - class="w-full py-2 pl-10 pr-4 rounded-full bg-white"
22 - :border="false"
23 - />
24 - </view>
25 </view> 20 </view>
26 21
27 <!-- Banner --> 22 <!-- Banner -->
28 <view class="px-4 mt-4"> 23 <view class="px-4 mt-4">
29 - <view class="relative rounded-lg overflow-hidden"> 24 + <nut-swiper :init-page="0" :pagination-visible="true" pagination-color="#ffffff" auto-play="3000"
30 - <image 25 + class="rounded-lg overflow-hidden" height="160">
31 - :src="bannerImages[0]" 26 + <nut-swiper-item v-for="(image, index) in bannerImages" :key="index">
32 - mode="aspectFill" 27 + <image :src="image" mode="aspectFill" class="w-full h-40 object-cover" />
33 - class="w-full h-40 object-cover rounded-lg" 28 + </nut-swiper-item>
34 - /> 29 + </nut-swiper>
35 - <view class="absolute bottom-2 right-2 flex space-x-1">
36 - <view class="w-2 h-2 bg-white rounded-full opacity-100"></view>
37 - <view class="w-2 h-2 bg-white rounded-full opacity-50"></view>
38 - <view class="w-2 h-2 bg-white rounded-full opacity-50"></view>
39 - </view>
40 - </view>
41 </view> 30 </view>
42 31
43 <!-- Category Icons --> 32 <!-- Category Icons -->
...@@ -74,33 +63,17 @@ ...@@ -74,33 +63,17 @@
74 </view> 63 </view>
75 </view> 64 </view>
76 <view class="grid grid-cols-2 gap-3"> 65 <view class="grid grid-cols-2 gap-3">
77 - <view 66 + <view v-for="scooter in featuredScooters" :key="scooter.id"
78 - v-for="scooter in featuredScooters" 67 + class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)">
79 - :key="scooter.id"
80 - class="bg-white rounded-lg shadow-sm overflow-hidden"
81 - @tap="() => onProductClick(scooter)"
82 - >
83 <view class="relative p-2"> 68 <view class="relative p-2">
84 - <image 69 + <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill"
85 - :src="scooter.imageUrl" 70 + class="w-full h-36 object-cover rounded-lg" />
86 - :alt="scooter.name" 71 + <view class="absolute top-4 right-4 p-1" @tap.stop="() => toggleFavorite(scooter.id)">
87 - mode="aspectFill" 72 + <Heart size="20" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#ffffff'"
88 - class="w-full h-36 object-cover rounded-lg" 73 + :fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" />
89 - /> 74 + </view>
90 - <view 75 + <view v-if="scooter.isVerified"
91 - class="absolute top-4 right-4 p-1" 76 + class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center">
92 - @tap.stop="() => toggleFavorite(scooter.id)"
93 - >
94 - <Heart
95 - size="24"
96 - :color="favoriteIds.includes(scooter.id) ? '#f97316' : '#ffffff'"
97 - :fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'"
98 - />
99 - </view>
100 - <view
101 - v-if="scooter.isVerified"
102 - class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center"
103 - >
104 <Check size="12" color="#ffffff" class="mr-0.5" /> 77 <Check size="12" color="#ffffff" class="mr-0.5" />
105 <text class="text-white">认证</text> 78 <text class="text-white">认证</text>
106 </view> 79 </view>
...@@ -116,10 +89,7 @@ ...@@ -116,10 +89,7 @@
116 <text class="text-orange-500 font-bold"> 89 <text class="text-orange-500 font-bold">
117 ¥{{ scooter.price.toLocaleString() }} 90 ¥{{ scooter.price.toLocaleString() }}
118 </text> 91 </text>
119 - <text 92 + <text v-if="scooter.isVerified" class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded">
120 - v-if="scooter.isVerified"
121 - class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded"
122 - >
123 低于市场价10% 93 低于市场价10%
124 </text> 94 </text>
125 <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text> 95 <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text>
...@@ -139,38 +109,22 @@ ...@@ -139,38 +109,22 @@
139 </view> 109 </view>
140 </view> 110 </view>
141 <view class="flex flex-col"> 111 <view class="flex flex-col">
142 - <view 112 + <view v-for="scooter in latestScooters" :key="scooter.id"
143 - v-for="scooter in latestScooters" 113 + class="bg-white rounded-lg shadow-sm overflow-hidden mb-3" @tap="() => onProductClick(scooter)">
144 - :key="scooter.id"
145 - class="bg-white rounded-lg shadow-sm overflow-hidden mb-3"
146 - @tap="() => onProductClick(scooter)"
147 - >
148 <view class="flex"> 114 <view class="flex">
149 <view class="w-32 h-24 relative p-2"> 115 <view class="w-32 h-24 relative p-2">
150 - <image 116 + <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill"
151 - :src="scooter.imageUrl" 117 + class="w-full h-full object-cover rounded-lg" />
152 - :alt="scooter.name" 118 + <view v-if="scooter.isVerified"
153 - mode="aspectFill" 119 + class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center">
154 - class="w-full h-full object-cover rounded-lg"
155 - />
156 - <view
157 - v-if="scooter.isVerified"
158 - class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center"
159 - >
160 <Check size="12" color="#ffffff" class="mr-0.5" /> 120 <Check size="12" color="#ffffff" class="mr-0.5" />
161 <text class="text-white">认证</text> 121 <text class="text-white">认证</text>
162 </view> 122 </view>
163 </view> 123 </view>
164 <view class="flex-1 p-3 relative"> 124 <view class="flex-1 p-3 relative">
165 - <view 125 + <view class="absolute top-2 right-2" @tap.stop="() => toggleFavorite(scooter.id)">
166 - class="absolute top-2 right-2" 126 + <Heart size="16" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#d1d5db'"
167 - @tap.stop="() => toggleFavorite(scooter.id)" 127 + :fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" />
168 - >
169 - <Heart
170 - size="20"
171 - :color="favoriteIds.includes(scooter.id) ? '#f97316' : '#d1d5db'"
172 - :fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'"
173 - />
174 </view> 128 </view>
175 <text class="font-medium text-sm block">{{ scooter.name }}</text> 129 <text class="font-medium text-sm block">{{ scooter.name }}</text>
176 <text class="text-xs text-gray-600 mt-1 block"> 130 <text class="text-xs text-gray-600 mt-1 block">
...@@ -194,10 +148,10 @@ ...@@ -194,10 +148,10 @@
194 148
195 <script setup> 149 <script setup>
196 import Taro from '@tarojs/taro' 150 import Taro from '@tarojs/taro'
197 -import '@tarojs/taro/html.css' 151 +// import '@tarojs/taro/html.css' 和 nutui组件居然有冲突?
198 import { ref, onMounted } from 'vue' 152 import { ref, onMounted } from 'vue'
199 import { useDidShow, useReady } from '@tarojs/taro' 153 import { useDidShow, useReady } from '@tarojs/taro'
200 -import { Search, Clock, Star, Service, Right, Heart, Check } from '@nutui/icons-vue-taro' 154 +import { Clock, Star, Service, Right, Heart, Check, Search2 } from '@nutui/icons-vue-taro'
201 import "./index.less"; 155 import "./index.less";
202 156
203 // 响应式数据 157 // 响应式数据
...@@ -206,7 +160,9 @@ const favoriteIds = ref([]) ...@@ -206,7 +160,9 @@ const favoriteIds = ref([])
206 160
207 // Banner图片 161 // Banner图片
208 const bannerImages = ref([ 162 const bannerImages = ref([
209 - 'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' 163 + 'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
164 + 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60',
165 + 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
210 ]) 166 ])
211 167
212 // 精品推荐数据 168 // 精品推荐数据
...@@ -391,7 +347,7 @@ import { getCurrentPageParam } from "@/utils/weapp"; ...@@ -391,7 +347,7 @@ import { getCurrentPageParam } from "@/utils/weapp";
391 347
392 export default { 348 export default {
393 name: "indexPage", 349 name: "indexPage",
394 - onHide () { 350 + onHide() {
395 console.warn('index onHide') 351 console.warn('index onHide')
396 }, 352 },
397 onShareAppMessage() { 353 onShareAppMessage() {
......