Kaynağa Gözat

✨ feat(goods-list): 商品列表页面功能优化与UI升级

- 新增分类筛选功能,支持全部/热销/新品分类切换
- 优化搜索栏设计,增加清除按钮和搜索图标
- 改进商品卡片UI,采用网格布局和圆角设计
- 商品卡片添加热销标签和库存显示
- 加入购物车按钮改为悬浮圆形按钮,提升交互体验
- 优化空状态和加载状态的展示样式
- 增加商品卡片点击反馈动画效果

💄 style(goods-list): 全面优化页面视觉效果

- 采用渐变背景和阴影效果增强层次感
- 统一按钮样式和交互反馈
- 优化文字排版和颜色对比度
- 调整间距和布局,提升页面整体美观度
- 商品图片添加缩放过渡效果

♻️ refactor(goods-list): 重构商品列表组件结构

- 调整组件层级关系,优化DOM结构
- 将商品列表从列表布局改为网格布局
- 优化加载状态和空状态的代码组织
- 改进事件处理逻辑,避免事件冒泡冲突
yourname 3 ay önce
ebeveyn
işleme
e1e7dab937
1 değiştirilmiş dosya ile 174 ekleme ve 103 silme
  1. 174 103
      mini/src/pages/goods-list/index.tsx

+ 174 - 103
mini/src/pages/goods-list/index.tsx

@@ -17,8 +17,15 @@ type Goods = GoodsResponse['data'][0]
 
 export default function GoodsListPage() {
   const [searchKeyword, setSearchKeyword] = useState('')
+  const [activeCategory, setActiveCategory] = useState('all')
   const { addToCart } = useCart()
 
+  const categories = [
+    { id: 'all', name: '全部' },
+    { id: 'hot', name: '热销' },
+    { id: 'new', name: '新品' },
+  ]
+
   const {
     data,
     isLoading,
@@ -93,129 +100,193 @@ export default function GoodsListPage() {
 
   return (
     <TabBarLayout activeKey="goods-list">
-      <View className="min-h-screen bg-gray-50">
-        <Navbar
-          title="商品列表"
-          leftIcon="i-heroicons-chevron-left-20-solid"
-          onClickLeft={() => Taro.navigateBack()}
-        />
-        
-        <ScrollView
-          className="h-screen pt-12"
-          scrollY
-          onScrollToLower={handleScrollToLower}
-          refresherEnabled
-          refresherTriggered={false}
-          onRefresherRefresh={onPullDownRefresh}
-        >
-          <View className="px-4 py-4">
-            {/* 搜索栏 */}
-            <View className="bg-white rounded-lg p-3 mb-4 shadow-sm">
-              <Input
-                type="text"
-                placeholder="搜索商品"
-                className="w-full outline-none"
-                value={searchKeyword}
-                onChange={(value) => setSearchKeyword(value)}
-                onConfirm={() => refetch()}
-              />
+      <Navbar
+        title="商品列表"
+        leftIcon="i-heroicons-chevron-left-20-solid"
+        onClickLeft={() => Taro.navigateBack()}
+        className="bg-white shadow-sm"
+      />
+      
+      <ScrollView
+        className="flex-1"
+        scrollY
+        onScrollToLower={handleScrollToLower}
+        refresherEnabled
+        refresherTriggered={false}
+        onRefresherRefresh={onPullDownRefresh}
+      >
+        <View className="px-4 py-4">
+          {/* 搜索栏 */}
+          <View className="bg-white rounded-2xl p-4 mb-4 shadow-lg">
+            <View className="flex items-center space-x-3">
+              <View className="flex-1 relative">
+                <View className="absolute left-4 top-1/2 -translate-y-1/2">
+                  <View className="i-heroicons-magnifying-glass-20-solid w-5 h-5 text-gray-400" />
+                </View>
+                <Input
+                  type="text"
+                  placeholder="搜索你想要的商品..."
+                  className="w-full pl-12 pr-4 py-3 bg-gray-50 rounded-xl outline-none focus:bg-gray-100 transition-colors text-sm"
+                  value={searchKeyword}
+                  onChange={(value) => setSearchKeyword(value)}
+                  onConfirm={() => refetch()}
+                />
+              </View>
+              {searchKeyword && (
+                <Button
+                  size="mini"
+                  variant="ghost"
+                  className="!w-8 !h-8 !p-0"
+                  onClick={() => {
+                    setSearchKeyword('')
+                    refetch()
+                  }}
+                >
+                  <View className="i-heroicons-x-mark-20-solid w-4 h-4 text-gray-500" />
+                </Button>
+              )}
             </View>
+          </View>
 
-            {/* 商品列表 */}
-            {isLoading ? (
-              <View className="flex justify-center py-10">
-                <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-blue-500" />
-              </View>
-            ) : (
-              <>
+          {/* 分类筛选 */}
+          <View className="flex space-x-2 mb-4 overflow-x-auto">
+            {categories.map((category) => (
+              <Button
+                key={category.id}
+                size="sm"
+                variant={activeCategory === category.id ? "solid" : "ghost"}
+                className={`whitespace-nowrap rounded-full px-4 py-2 transition-all ${
+                  activeCategory === category.id
+                    ? 'bg-blue-500 text-white shadow-md'
+                    : 'text-gray-600 hover:bg-gray-100'
+                }`}
+                onClick={() => {
+                  setActiveCategory(category.id)
+                  refetch()
+                }}
+              >
+                {category.name}
+              </Button>
+            ))}
+          </View>
+
+          {/* 商品列表 */}
+          {isLoading ? (
+            <View className="flex justify-center py-10">
+              <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-blue-500" />
+            </View>
+          ) : (
+            <>
+              <View className="grid grid-cols-2 gap-4">
                 {allGoods.map((goods) => (
-                  <Card key={goods.id} className="mb-4 overflow-hidden">
-                    <View className="flex p-4">
-                      <View
-                        className="w-24 h-24 bg-gray-100 rounded-lg mr-4"
-                        onClick={() => handleGoodsClick(goods)}
-                      >
+                  <Card
+                    key={goods.id}
+                    className="overflow-hidden bg-white rounded-2xl shadow-sm active:shadow-lg transition-all duration-300 active:scale-95"
+                    onClick={() => handleGoodsClick(goods)}
+                  >
+                    <View className="relative">
+                      <View className="w-full aspect-square bg-gradient-to-br from-gray-100 to-gray-200 overflow-hidden">
                         {goods.imageFile?.fullUrl ? (
                           <Image
                             src={goods.imageFile.fullUrl}
-                            className="w-full h-full object-cover rounded-lg"
+                            className="w-full h-full object-cover transition-transform duration-300 active:scale-110"
                             mode="aspectFill"
                           />
                         ) : (
                           <View className="w-full h-full flex items-center justify-center text-gray-400">
-                            <View className="i-heroicons-photo-20-solid w-8 h-8" />
+                            <View className="i-heroicons-photo-20-solid w-12 h-12" />
                           </View>
                         )}
                       </View>
                       
-                      <View className="flex-1">
-                        <Text
-                          className="text-lg font-medium text-gray-900 mb-2 line-clamp-2"
-                          onClick={() => handleGoodsClick(goods)}
-                        >
-                          {goods.name}
-                        </Text>
-                        
-                        <Text className="text-sm text-gray-500 mb-2">
-                          {goods.instructions || '暂无描述'}
-                        </Text>
-                        
-                        <View className="flex items-center justify-between">
-                          <View>
-                            <Text className="text-red-500 text-lg font-bold">
-                              ¥{goods.price.toFixed(2)}
-                            </Text>
-                            <Text className="text-xs text-gray-400 ml-2">
-                              已售{goods.salesNum}
-                            </Text>
-                          </View>
-                          
-                          <View className="flex items-center space-x-2">
-                            <Button
-                              size="sm"
-                              variant="outline"
-                              onClick={() => handleGoodsClick(goods)}
-                            >
-                              详情
-                            </Button>
-                            <Button
-                              size="sm"
-                              onClick={() => handleAddToCart(goods)}
-                              disabled={goods.stock <= 0}
-                            >
-                              {goods.stock > 0 ? '加入购物车' : '已售罄'}
-                            </Button>
-                          </View>
+                      {goods.stock <= 0 && (
+                        <View className="absolute inset-0 bg-black/50 flex items-center justify-center">
+                          <Text className="text-white font-bold text-sm">已售罄</Text>
+                        </View>
+                      )}
+                      
+                      {goods.stock > 0 && goods.salesNum > 100 && (
+                        <View className="absolute top-2 left-2 bg-gradient-to-r from-orange-500 to-red-500 text-white text-xs px-2 py-1 rounded-full shadow-lg">
+                          热销
+                        </View>
+                      )}
+                      
+                      {goods.stock > 0 && goods.salesNum <= 100 && (
+                        <View className="absolute top-2 right-2 bg-white/90 backdrop-blur text-gray-700 text-xs px-2 py-1 rounded-full shadow-md">
+                          库存{goods.stock}
+                        </View>
+                      )}
+                    </View>
+                    
+                    <View className="p-3">
+                      <Text className="text-sm font-semibold text-gray-900 mb-1 line-clamp-2 h-10 leading-tight">
+                        {goods.name}
+                      </Text>
+                      
+                      <Text className="text-xs text-gray-500 mb-2 line-clamp-1">
+                        {goods.instructions || '优质商品,值得信赖'}
+                      </Text>
+                      
+                      <View className="flex items-center justify-between">
+                        <View>
+                          <Text className="text-red-500 text-lg font-bold">
+                            ¥{goods.price.toFixed(2)}
+                          </Text>
+                          <Text className="text-xs text-gray-400 ml-1">
+                            已售{goods.salesNum}
+                          </Text>
                         </View>
+                        
+                        <Button
+                          size="mini"
+                          className={`!w-8 !h-8 !p-0 rounded-full transition-all ${
+                            goods.stock > 0
+                              ? 'bg-gradient-to-r from-blue-500 to-blue-600 text-white shadow-md active:shadow-lg'
+                              : 'bg-gray-200 text-gray-400'
+                          }`}
+                          onClick={(e) => {
+                            e.stopPropagation()
+                            if (goods.stock > 0) {
+                              handleAddToCart(goods)
+                            }
+                          }}
+                          disabled={goods.stock <= 0}
+                        >
+                          <View className={`w-4 h-4 ${goods.stock > 0 ? 'i-heroicons-plus-20-solid' : 'i-heroicons-minus-20-solid'}`} />
+                        </Button>
                       </View>
                     </View>
                   </Card>
                 ))}
-                
-                {isFetchingNextPage && (
-                  <View className="flex justify-center py-4">
-                    <View className="i-heroicons-arrow-path-20-solid animate-spin w-6 h-6 text-blue-500" />
-                    <Text className="ml-2 text-sm text-gray-500">加载更多...</Text>
-                  </View>
-                )}
-                
-                {!hasNextPage && allGoods.length > 0 && (
-                  <View className="text-center py-4 text-sm text-gray-400">
-                    没有更多了
-                  </View>
-                )}
-                
-                {!isLoading && allGoods.length === 0 && (
-                  <View className="flex flex-col items-center py-10">
-                    <View className="i-heroicons-inbox-20-solid w-12 h-12 text-gray-300 mb-4" />
-                    <Text className="text-gray-500">暂无商品</Text>
+              </View>
+              
+              {isFetchingNextPage && (
+                <View className="flex justify-center py-4 mt-4">
+                  <View className="i-heroicons-arrow-path-20-solid animate-spin w-6 h-6 text-blue-500" />
+                  <Text className="ml-2 text-sm text-gray-500">加载更多...</Text>
+                </View>
+              )}
+              
+              {!hasNextPage && allGoods.length > 0 && (
+                <View className="text-center py-8 text-sm text-gray-400">
+                  <View className="flex items-center justify-center">
+                    <View className="i-heroicons-check-circle-20-solid w-4 h-4 mr-1" />
+                    已经到底啦
                   </View>
-                )}
-              </>
-            )}
-          </View>
-        </ScrollView>
-      </View>
+                </View>
+              )}
+              
+              {!isLoading && allGoods.length === 0 && (
+                <View className="flex flex-col items-center py-10">
+                  <View className="i-heroicons-inbox-20-solid w-16 h-16 text-gray-300 mb-4" />
+                  <Text className="text-gray-500 text-lg mb-2">暂无商品</Text>
+                  <Text className="text-gray-400 text-sm">换个关键词试试吧</Text>
+                </View>
+              )}
+            </>
+          )}
+        </View>
+      </ScrollView>
     </TabBarLayout>
   )
 }