Browse Source

refactor(category):重构文章分类页面结构和加载逻辑

- 调整文章列表组件路径并优化渲染逻辑
- 添加骨架屏加载效果提升用户体验
- 完善错误处理机制增强页面稳定性- 更新页面配置文件路径引用
- 移除冗余的页面配置和组件引用
-优化首页Banner组件加载状态处理
- 增强热销商品Tab切换功能和空状态展示- 调整用户经销商组件调试日志- 修改全局应用配置中的页面路径引用
- 调整主题处理逻辑执行时机
master
科技小王子 3 days ago
parent
commit
b8e13fdc68
  1. 4
      src/app.config.ts
  2. 2
      src/app.ts
  3. 18
      src/pages/category/components/ArticleList.tsx
  4. 0
      src/pages/category/components/ArticleTabs.tsx
  5. 0
      src/pages/category/components/Banner.tsx
  6. 0
      src/pages/category/index.config.ts
  7. 0
      src/pages/category/index.scss
  8. 96
      src/pages/category/index.tsx
  9. 71
      src/pages/cms/category/index.tsx
  10. 3
      src/pages/cms/detail/index.config.ts
  11. 0
      src/pages/cms/detail/index.scss
  12. 53
      src/pages/cms/detail/index.tsx
  13. 137
      src/pages/index/Banner.tsx
  14. 48
      src/pages/index/BestSellers.tsx
  15. 2
      src/pages/user/components/IsDealer.tsx

4
src/app.config.ts

@ -4,7 +4,7 @@ export default {
'pages/cart/cart',
'pages/find/find',
'pages/user/user',
'pages/cms/category/index'
'pages/category/index'
],
"subpackages": [
{
@ -116,7 +116,7 @@ export default {
text: "首页",
},
{
pagePath: "pages/cms/category/index",
pagePath: "pages/category/index",
iconPath: "assets/tabbar/category.png",
selectedIconPath: "assets/tabbar/category-active.png",
text: "基地生活",

2
src/app.ts

@ -53,7 +53,6 @@ function App(props: { children: any; }) {
// 处理小程序启动参数中的邀请信息
const options = Taro.getLaunchOptionsSync()
handleLaunchOptions(options)
handleTheme()
})
// 处理启动参数
@ -103,6 +102,7 @@ function App(props: { children: any; }) {
// 对应 onHide
useDidHide(() => {
handleTheme()
})
return props.children

18
src/pages/cms/category/components/ArticleList.tsx → src/pages/category/components/ArticleList.tsx

@ -1,15 +1,25 @@
import {Image, Cell} from '@nutui/nutui-react-taro'
import {View, Text} from '@tarojs/components'
import Taro from '@tarojs/taro'
const ArticleList = (props: any) => {
return (
<>
<div className={'px-3'}>
{props.data.map((item, index) => {
<View className={'px-3'}>
{props.data.map((item: any, index: number) => {
return (
<Cell
title={item.title}
title={
<View>
<View className="text-base font-medium mb-1">{item.title}</View>
{item.comments && (
<Text className="text-sm text-gray-500 leading-relaxed">
{item.comments}
</Text>
)}
</View>
}
extra={
<Image src={item.image} mode={'aspectFit'} lazyLoad={false} width={100} height="100"/>
}
@ -18,7 +28,7 @@ const ArticleList = (props: any) => {
/>
)
})}
</div>
</View>
</>
)
}

0
src/pages/cms/category/components/ArticleTabs.tsx → src/pages/category/components/ArticleTabs.tsx

0
src/pages/cms/category/components/Banner.tsx → src/pages/category/components/Banner.tsx

0
src/pages/cms/category/index.config.ts → src/pages/category/index.config.ts

0
src/pages/cms/category/index.scss → src/pages/category/index.scss

96
src/pages/category/index.tsx

@ -0,0 +1,96 @@
import Taro from '@tarojs/taro'
import {useShareAppMessage} from "@tarojs/taro"
import {useEffect, useState} from "react"
import {useRouter} from '@tarojs/taro'
import {View} from '@tarojs/components'
import {getCmsNavigation, listCmsNavigation} from "@/api/cms/cmsNavigation";
import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
import {pageCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model";
import ArticleList from './components/ArticleList'
import ArticleTabs from "./components/ArticleTabs";
import './index.scss'
function Category() {
const {params} = useRouter();
const [categoryId, setCategoryId] = useState<number>(0)
const [category, setCategory] = useState<CmsNavigation[]>([])
const [loading, setLoading] = useState<boolean>(true)
const [nav, setNav] = useState<CmsNavigation>()
const [list, setList] = useState<CmsArticle[]>([])
const reload = async () => {
try {
setLoading(true)
// 1.加载远程数据
const id = Number(params.id || 4328)
const nav = await getCmsNavigation(id)
const categoryList = await listCmsNavigation({parentId: id})
const shopGoods = await pageCmsArticle({categoryId: id})
// 2.赋值
setCategoryId(id)
setNav(nav)
setList(shopGoods?.list || [])
setCategory(categoryList)
Taro.setNavigationBarTitle({
title: `${nav?.categoryName}`
})
} catch (error) {
console.error('文章分类加载失败:', error)
} finally {
setLoading(false)
}
};
useEffect(() => {
reload()
}, []);
useShareAppMessage(() => {
return {
title: `${nav?.categoryName}_时里院子市集`,
path: `/shop/category/index?id=${categoryId}`,
success: function () {
console.log('分享成功');
},
fail: function () {
console.log('分享失败');
}
};
});
// 骨架屏组件
const ArticleSkeleton = () => (
<View className="px-3">
{[1, 2, 3, 4, 5].map(i => (
<View key={i} className="flex items-center py-4 border-b border-gray-100">
{/* 左侧文字骨架屏 */}
<View className="flex-1 pr-4">
{/* 标题骨架屏 */}
<View className="bg-gray-200 h-5 rounded animate-pulse mb-2" style={{width: '75%'}}/>
{/* 副标题骨架屏 */}
<View className="bg-gray-200 h-4 rounded animate-pulse" style={{width: '50%'}}/>
</View>
{/* 右侧图片骨架屏 */}
<View
className="bg-gray-200 rounded animate-pulse flex-shrink-0"
style={{width: '100px', height: '100px'}}
/>
</View>
))}
</View>
)
if (loading) {
return <ArticleSkeleton />
}
if(category.length > 0){
return <ArticleTabs data={category}/>
}
return <ArticleList data={list}/>
}
export default Category

71
src/pages/cms/category/index.tsx

@ -1,71 +0,0 @@
import Taro from '@tarojs/taro'
import {useShareAppMessage} from "@tarojs/taro"
import {Loading} from '@nutui/nutui-react-taro'
import {useEffect, useState} from "react"
import {useRouter} from '@tarojs/taro'
import {getCmsNavigation, listCmsNavigation} from "@/api/cms/cmsNavigation";
import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
import {pageCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model";
import ArticleList from './components/ArticleList'
import ArticleTabs from "./components/ArticleTabs";
import './index.scss'
function Category() {
const {params} = useRouter();
const [categoryId, setCategoryId] = useState<number>(0)
const [category, setCategory] = useState<CmsNavigation[]>([])
const [loading, setLoading] = useState<boolean>(true)
const [nav, setNav] = useState<CmsNavigation>()
const [list, setList] = useState<CmsArticle[]>([])
const reload = async () => {
// 1.加载远程数据
const id = Number(params.id || 4328)
const nav = await getCmsNavigation(id)
const categoryList = await listCmsNavigation({parentId: id})
const shopGoods = await pageCmsArticle({categoryId: id})
// 2.赋值
setCategoryId(id)
setNav(nav)
setList(shopGoods?.list || [])
setCategory(categoryList)
Taro.setNavigationBarTitle({
title: `${nav?.categoryName}`
})
};
useEffect(() => {
reload().then(() => {
setLoading(false)
})
}, []);
useShareAppMessage(() => {
return {
title: `${nav?.categoryName}_时里院子市集`,
path: `/shop/category/index?id=${categoryId}`,
success: function () {
console.log('分享成功');
},
fail: function () {
console.log('分享失败');
}
};
});
if (loading) {
return (
<Loading className={'px-2'}></Loading>
)
}
if(category.length > 0){
return <ArticleTabs data={category}/>
}
return <ArticleList data={list}/>
}
export default Category

3
src/pages/cms/detail/index.config.ts

@ -1,3 +0,0 @@
export default definePageConfig({
navigationBarTitleText: '文章详情'
})

0
src/pages/cms/detail/index.scss

53
src/pages/cms/detail/index.tsx

@ -1,53 +0,0 @@
import Taro from '@tarojs/taro'
import {useEffect, useState} from 'react'
import {useRouter} from '@tarojs/taro'
import {Loading} from '@nutui/nutui-react-taro'
import {View, RichText} from '@tarojs/components'
import {wxParse} from "@/utils/common";
import {getCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model"
import Line from "@/components/Gap";
import './index.scss'
function Detail() {
const {params} = useRouter();
const [loading, setLoading] = useState<boolean>(true)
// 文章详情
const [item, setItem] = useState<CmsArticle>()
const reload = async () => {
const item = await getCmsArticle(Number(params.id))
if (item) {
item.content = wxParse(item.content)
setItem(item)
Taro.setNavigationBarTitle({
title: `${item?.categoryName}`
})
}
}
useEffect(() => {
reload().then(() => {
setLoading(false)
});
}, []);
if (loading) {
return (
<Loading className={'px-2'}></Loading>
)
}
return (
<div className={'bg-white'}>
<div className={'p-4 font-bold text-lg'}>{item?.title}</div>
<div className={'text-gray-400 text-sm px-4 '}>{item?.createTime}</div>
<View className={'content p-4'}>
<RichText nodes={item?.content}/>
</View>
<Line height={44}/>
</div>
)
}
export default Detail

137
src/pages/index/Banner.tsx

@ -13,24 +13,32 @@ const MyPage = () => {
const [carouselData, setCarouselData] = useState<CmsAd>()
const [hotToday, setHotToday] = useState<CmsAd>()
const [item, setItem] = useState<CmsArticle>()
const [loading, setLoading] = useState(true)
// 加载数据
const loadData = async () => {
// 轮播图
const flash = await getCmsAdByCode('flash')
// 今日热卖
const hotToday = await getCmsAdByCode('hot_today')
// 时里动态
const news = await pageCmsArticle({limit:1,recommend:1})
// 赋值
if(flash){
setCarouselData(flash)
}
if(hotToday){
setHotToday(hotToday)
}
if(news && news.list.length > 0){
setItem(news.list[0])
try {
setLoading(true)
// 轮播图
const flash = await getCmsAdByCode('flash')
// 今日热卖
const hotToday = await getCmsAdByCode('hot_today')
// 时里动态
const news = await pageCmsArticle({limit:1,recommend:1})
// 赋值
if(flash){
setCarouselData(flash)
}
if(hotToday){
setHotToday(hotToday)
}
if(news && news.list.length > 0){
setItem(news.list[0])
}
} catch (error) {
console.error('Banner数据加载失败:', error)
} finally {
setLoading(false)
}
}
@ -41,30 +49,91 @@ const MyPage = () => {
// 轮播图高度,默认200px
const carouselHeight = carouselData?.height || 200;
// 骨架屏组件
const BannerSkeleton = () => (
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
{/* 左侧轮播图骨架屏 */}
<View style={{width: '50%', height: '100%'}}>
<View
className="bg-gray-200 rounded animate-pulse"
style={{height: `${carouselHeight}px`}}
/>
</View>
{/* 右侧骨架屏 */}
<View className="flex flex-col" style={{width: '50%', height: '100%'}}>
{/* 上层骨架屏 */}
<View className="ml-2 bg-white rounded-lg">
<View className="px-3 my-2">
<View className="bg-gray-200 h-4 w-16 rounded animate-pulse"/>
</View>
<View className="px-3 flex" style={{height: '110px'}}>
{[1, 2].map(i => (
<View key={i} className="item flex flex-col mr-4">
<View className="bg-gray-200 rounded animate-pulse" style={{width: 70, height: 70}}/>
<View className="bg-gray-200 h-3 w-16 rounded mt-2 animate-pulse"/>
</View>
))}
</View>
</View>
{/* 下层骨架屏 */}
<View className="ml-2 bg-white rounded-lg mt-3">
<View className="px-3 my-2">
<View className="bg-gray-200 h-4 w-20 rounded animate-pulse"/>
</View>
<View className="rounded-lg px-3 pb-3">
<View className="bg-gray-200 rounded animate-pulse" style={{width: '100%', height: 106}}/>
</View>
</View>
</View>
</View>
)
// 如果正在加载,显示骨架屏
if (loading) {
return <BannerSkeleton />
}
return (
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
{/* 左侧轮播图区域 */}
<View style={{width: '50%', height: '100%'}}>
<Swiper
defaultValue={0}
height={carouselHeight}
indicator
style={{height: `${carouselHeight}px`}}
<View
style={{
width: '100%',
height: '100%',
touchAction: 'pan-y',
pointerEvents: 'none'
}}
>
{carouselData?.imageList?.map((img, index) => (
<Swiper.Item key={index}>
<Image
width="100%"
height="100%"
src={img.url}
mode={'scaleToFill'}
onClick={() => navTo(`${img.path}`)}
lazyLoad={false}
style={{height: `${carouselHeight}px`, borderRadius: '4px'}}
/>
</Swiper.Item>
))}
</Swiper>
<Swiper
defaultValue={0}
height={carouselHeight}
indicator
autoPlay
duration={3000}
style={{height: `${carouselHeight}px`}}
>
{carouselData && carouselData?.imageList?.map((img, index) => (
<Swiper.Item key={index}>
<Image
width="100%"
height="100%"
src={img.url}
mode={'scaleToFill'}
onClick={() => navTo(`${img.path}`)}
lazyLoad={false}
style={{
height: `${carouselHeight}px`,
borderRadius: '4px',
pointerEvents: 'auto'
}}
/>
</Swiper.Item>
))}
</Swiper>
</View>
</View>
{/* 右侧上下图片区域 - 从API获取数据 */}

48
src/pages/index/BestSellers.tsx

@ -1,5 +1,5 @@
import {useEffect, useState} from "react";
import {Image} from '@nutui/nutui-react-taro'
import {Image, Tabs, Empty} from '@nutui/nutui-react-taro'
import {Share} from '@nutui/icons-react-taro'
import {View, Text} from '@tarojs/components';
import Taro from "@tarojs/taro";
@ -7,6 +7,7 @@ import {ShopGoods} from "@/api/shop/shopGoods/model";
import {pageShopGoods} from "@/api/shop/shopGoods";
const BestSellers = () => {
const [tab1value, setTab1value] = useState<string | number>('0')
const [list, setList] = useState<ShopGoods[]>([])
const [goods, setGoods] = useState<ShopGoods>()
@ -57,8 +58,29 @@ const BestSellers = () => {
return (
<>
<View className={'py-3'}>
{/* Tabs切换组件 */}
<Tabs
value={tab1value}
className={'w-full mb-4'}
onChange={(value) => {
setTab1value(value)
}}
style={{
backgroundColor: 'transparent',
}}
activeType="smile"
>
<Tabs.TabPane title="今日主推">
</Tabs.TabPane>
<Tabs.TabPane title="即将到期">
</Tabs.TabPane>
<Tabs.TabPane title="活动预告">
</Tabs.TabPane>
</Tabs>
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
{list?.map((item, index) => {
{/* 今日主推 */}
{tab1value == '0' && list?.map((item, index) => {
return (
<View key={index} className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}>
<Image src={item.image} mode={'aspectFit'} lazyLoad={false}
@ -95,6 +117,28 @@ const BestSellers = () => {
</View>
)
})}
{/* 即将到期 */}
{tab1value == '1' && (
<Empty
size={'small'}
description="暂无即将到期的商品"
style={{
background: 'transparent',
}}
/>
)}
{/* 活动预告 */}
{tab1value == '2' && (
<Empty
size={'small'}
description="暂无活动预告"
style={{
background: 'transparent',
}}
/>
)}
</View>
</View>
</>

2
src/pages/user/components/IsDealer.tsx

@ -21,7 +21,7 @@ const IsDealer = () => {
setConfig(data)
})
}, [])
console.log(dealerUser,'dealerUserdealerUserdealerUserdealerUserdealerUser')
/**
*
*/

Loading…
Cancel
Save