Jelajahi Sumber

✨ feat(category): 优化分类页面功能与用户体验

- 修改tab-bar中"商品"为"分类",更新对应路由
- 集成TabBarLayout布局组件,统一页面导航体验
- 添加图片加载组件,支持加载状态和错误显示
- 实现错误提示toast,当分类数据加载失败时显示
- 完善分类页面布局结构,优化侧边栏和内容区域展示

♻️ refactor(category): 重构分类页面代码结构

- 调整分类数据加载逻辑,优化错误处理流程
- 改进分类切换交互,提升用户操作体验
- 整合广告图展示组件,统一图片加载策略
- 优化组件导入顺序,提高代码可读性
yourname 1 bulan lalu
induk
melakukan
fcfb94fcea
2 mengubah file dengan 118 tambahan dan 83 penghapusan
  1. 4 4
      mini/src/layouts/tab-bar-layout.tsx
  2. 114 79
      mini/src/pages/category/index.tsx

+ 4 - 4
mini/src/layouts/tab-bar-layout.tsx

@@ -17,8 +17,8 @@ const tabBarItems: TabBarItem[] = [
     selectedIconClass: 'i-heroicons-home-20-solid',
   },
   {
-    key: 'goods-list',
-    title: '商品',
+    key: 'category',
+    title: '分类',
     iconClass: 'i-heroicons-squares-2x2-20-solid',
     selectedIconClass: 'i-heroicons-squares-2x2-20-solid',
   },
@@ -43,8 +43,8 @@ export const TabBarLayout: React.FC<TabBarLayoutProps> = ({ children, activeKey,
       case 'home':
         Taro.switchTab({ url: '/pages/index/index' })
         break
-      case 'goods-list':
-        Taro.switchTab({ url: '/pages/goods-list/index' })
+      case 'category':
+        Taro.switchTab({ url: '/pages/category/index' })
         break
       case 'cart':
         Taro.switchTab({ url: '/pages/cart/index' })

+ 114 - 79
mini/src/pages/category/index.tsx

@@ -5,8 +5,11 @@ import { goodsCategoryClient, advertisementClient } from '@/api';
 import CategorySidebar from '@/components/category/CategorySidebar';
 import CategorySidebarItem from '@/components/category/CategorySidebarItem';
 import CategoryTabbar from '@/components/category/CategoryTabbar';
+import { Image } from '@/components/ui/image';
+import TDesignToast from '@/components/tdesign/toast';
 import { navigateTo } from '@tarojs/taro';
 import { InferResponseType } from 'hono';
+import { TabBarLayout } from '@/layouts/tab-bar-layout';
 import './index.css';
 
 type GoodsCategoryResponse = InferResponseType<typeof goodsCategoryClient.$get, 200>
@@ -18,6 +21,8 @@ type Advertisement = AdvertisementResponse['data'][0]
 const CategoryPage: React.FC = () => {
   const [activeCategoryIndex, setActiveCategoryIndex] = useState<number>(0);
   const [activeSubCategoryId, setActiveSubCategoryId] = useState<string>('');
+  const [toastVisible, setToastVisible] = useState<boolean>(false);
+  const [toastMessage, setToastMessage] = useState<string>('');
 
   // 获取分类数据
   const { data: categoryData, isLoading, error } = useQuery({
@@ -38,6 +43,14 @@ const CategoryPage: React.FC = () => {
     staleTime: 5 * 60 * 1000, // 5分钟缓存
   });
 
+  // 显示错误Toast
+  React.useEffect(() => {
+    if (error) {
+      setToastMessage('获取分类数据失败,请重试');
+      setToastVisible(true);
+    }
+  }, [error]);
+
   // 获取广告数据
   const { data: advertisementData } = useQuery({
     queryKey: ['category-advertisements'],
@@ -95,103 +108,125 @@ const CategoryPage: React.FC = () => {
 
   if (isLoading) {
     return (
-      <View className="category-page">
-        <View className="loading">加载中...</View>
-      </View>
+      <TabBarLayout activeKey="category">
+        <View className="category-page">
+          <View className="loading">加载中...</View>
+        </View>
+      </TabBarLayout>
     );
   }
 
   if (error) {
     return (
-      <View className="category-page">
-        <View className="error">加载失败,请重试</View>
-      </View>
+      <TabBarLayout activeKey="category">
+        <View className="category-page">
+          <View className="error">加载失败,请重试</View>
+        </View>
+      </TabBarLayout>
     );
   }
 
   return (
-    <View className="category-page">
-      <View className="category-container">
-        {/* 左侧边栏 - 一级分类 */}
-        <View className="category-sidebar-container">
-          <CategorySidebar
-            activeKey={activeCategoryIndex}
-            onChange={handleCategoryChange}
-          >
-            {categories.map((category: Category, index: number) => (
-              <CategorySidebarItem
-                key={category.id}
-                title={category.name}
-                onClick={() => handleCategoryChange(index)}
-              />
-            ))}
-          </CategorySidebar>
-        </View>
+    <TabBarLayout activeKey="category">
+      <View className="category-page">
+        {/* Toast 组件 */}
+        <TDesignToast
+          visible={toastVisible}
+          message={toastMessage}
+          theme="error"
+          duration={2000}
+          onClose={() => setToastVisible(false)}
+        />
+        <View className="category-container">
+          {/* 左侧边栏 - 一级分类 */}
+          <View className="category-sidebar-container">
+            <CategorySidebar
+              activeKey={activeCategoryIndex}
+              onChange={handleCategoryChange}
+            >
+              {categories.map((category: Category, index: number) => (
+                <CategorySidebarItem
+                  key={category.id}
+                  title={category.name}
+                  onClick={() => handleCategoryChange(index)}
+                />
+              ))}
+            </CategorySidebar>
+          </View>
 
-        {/* 右侧内容区 */}
-        <View className="category-content">
-          {/* 二级分类标签栏 */}
-          {subCategories.length > 0 && (
-            <View className="sub-category-tabbar">
-              <CategoryTabbar
-                tabList={subCategories.map((cat: Category) => ({
-                  id: cat.id,
-                  name: cat.name,
-                }))}
-                currentActive={activeSubCategoryId}
-                onChange={handleSubCategoryChange}
-                showMore={true}
-              />
-            </View>
-          )}
-
-          {/* 二级分类网格布局 */}
-          <View className="sub-category-grid">
-            {subCategories.map((category: Category) => (
-              <View
-                key={category.id}
-                className="sub-category-item"
-                onClick={() => handleSubCategoryClick(category)}
-              >
-                <View className="sub-category-image-container">
-                  <View className="sub-category-image">
-                    {category.image ? (
-                      <View className="image-placeholder">
-                        {/* 这里需要集成 Shadcn Image 组件 */}
-                        <View className="image-fallback">
-                          {category.name.charAt(0)}
-                        </View>
-                      </View>
-                    ) : (
-                      <View className="image-placeholder">
-                        <View className="image-fallback">
-                          {category.name.charAt(0)}
+          {/* 右侧内容区 */}
+          <View className="category-content">
+            {/* 二级分类标签栏 */}
+            {subCategories.length > 0 && (
+              <View className="sub-category-tabbar">
+                <CategoryTabbar
+                  tabList={subCategories.map((cat: Category) => ({
+                    id: cat.id,
+                    name: cat.name,
+                  }))}
+                  currentActive={activeSubCategoryId}
+                  onChange={handleSubCategoryChange}
+                  showMore={true}
+                />
+              </View>
+            )}
+
+            {/* 二级分类网格布局 */}
+            <View className="sub-category-grid">
+              {subCategories.map((category: Category) => (
+                <View
+                  key={category.id}
+                  className="sub-category-item"
+                  onClick={() => handleSubCategoryClick(category)}
+                >
+                  <View className="sub-category-image-container">
+                    <View className="sub-category-image">
+                      {category.imageFile?.fullUrl ? (
+                        <Image
+                          src={category.imageFile.fullUrl}
+                          alt={category.name}
+                          mode="aspectFill"
+                          rounded="lg"
+                          className="w-full h-full"
+                          showLoading={true}
+                          showError={true}
+                        />
+                      ) : (
+                        <View className="image-placeholder">
+                          <View className="image-fallback">
+                            {category.name.charAt(0)}
+                          </View>
                         </View>
-                      </View>
-                    )}
+                      )}
+                    </View>
+                  </View>
+                  <View className="sub-category-name">
+                    {category.name}
                   </View>
                 </View>
-                <View className="sub-category-name">
-                  {category.name}
-                </View>
-              </View>
-            ))}
-          </View>
+              ))}
+            </View>
 
-          {/* 广告图 */}
-          {advertisementImage && (
-            <View className="advertisement-container">
-              <View className="advertisement-image">
-                {/* 这里需要集成 Shadcn Image 组件 */}
-                <View className="ad-image-placeholder">
-                  广告图
+            {/* 广告图 */}
+            {advertisementImage && (
+              <View className="advertisement-container">
+                <View className="advertisement-image">
+                  <Image
+                    src={advertisementImage}
+                    alt="分类页广告"
+                    mode="aspectFill"
+                    rounded="lg"
+                    className="w-full h-full"
+                    showLoading={true}
+                    showError={true}
+                  />
                 </View>
               </View>
-            </View>
-          )}
+            )}
+          </View>
         </View>
       </View>
-    </View>
+    </TabBarLayout>
   );
 };