Compare commits
10 Commits
0a10afcea2
...
14c0f29361
Author | SHA1 | Date |
---|---|---|
![]() |
14c0f29361 | 2 weeks ago |
![]() |
d988caa5ed | 2 weeks ago |
![]() |
7431ce39a5 | 2 weeks ago |
![]() |
8539f04e07 | 2 weeks ago |
![]() |
d46533ac52 | 2 weeks ago |
![]() |
dd1559ba56 | 2 weeks ago |
![]() |
27ddb85aed | 2 weeks ago |
![]() |
7985f0a1a4 | 2 weeks ago |
![]() |
020315838b | 2 weeks ago |
![]() |
d762fa56d4 | 2 weeks ago |
20 changed files with 732 additions and 141 deletions
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 4.3 KiB |
@ -0,0 +1,25 @@ |
|||
import {Image, Cell} from '@nutui/nutui-react-taro' |
|||
import Taro from '@tarojs/taro' |
|||
|
|||
const ArticleList = (props: any) => { |
|||
|
|||
return ( |
|||
<> |
|||
<div className={'px-3'}> |
|||
{props.data.map((item, index) => { |
|||
return ( |
|||
<Cell |
|||
title={item.title} |
|||
extra={ |
|||
<Image src={item.image} mode={'aspectFit'} lazyLoad={false} width={100} height="100"/> |
|||
} |
|||
key={index} |
|||
onClick={() => Taro.navigateTo({url: '/cms/detail/index?id=' + item.articleId})} |
|||
/> |
|||
) |
|||
})} |
|||
</div> |
|||
</> |
|||
) |
|||
} |
|||
export default ArticleList |
@ -0,0 +1,59 @@ |
|||
import {useEffect, useState} from "react"; |
|||
import {Tabs, Loading} from '@nutui/nutui-react-taro' |
|||
import {pageCmsArticle} from "@/api/cms/cmsArticle"; |
|||
import {CmsArticle} from "@/api/cms/cmsArticle/model"; |
|||
import ArticleList from "./ArticleList"; |
|||
|
|||
const ArticleTabs = (props: any) => { |
|||
const [loading, setLoading] = useState<boolean>(true) |
|||
const [tab1value, setTab1value] = useState<string | number>('0') |
|||
const [list, setList] = useState<CmsArticle[]>([]) |
|||
|
|||
const reload = async (value) => { |
|||
const {data} = props |
|||
pageCmsArticle({ |
|||
categoryId: data[value].navigationId, |
|||
page: 1, |
|||
status: 0, |
|||
limit: 10 |
|||
}).then((res) => { |
|||
res && setList(res?.list || []) |
|||
}) |
|||
.catch(err => { |
|||
console.log(err) |
|||
}) |
|||
.finally(() => { |
|||
setTab1value(value) |
|||
setLoading(false) |
|||
}) |
|||
} |
|||
|
|||
useEffect(() => { |
|||
reload(0).then() |
|||
}, []); |
|||
|
|||
if (loading) { |
|||
return ( |
|||
<Loading className={'px-2'}>加载中</Loading> |
|||
) |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<Tabs |
|||
value={tab1value} |
|||
onChange={(value) => { |
|||
reload(value).then() |
|||
}} |
|||
> |
|||
{props.data?.map((item, index) => { |
|||
return ( |
|||
<Tabs.TabPane title={item.categoryName} key={index}/> |
|||
) |
|||
})} |
|||
</Tabs> |
|||
<ArticleList data={list}/> |
|||
</> |
|||
) |
|||
} |
|||
export default ArticleTabs |
@ -0,0 +1,31 @@ |
|||
import { useEffect, useState } from 'react' |
|||
import { Swiper } from '@nutui/nutui-react-taro' |
|||
import {CmsAd} from "@/api/cms/cmsAd/model"; |
|||
import {Image} from '@nutui/nutui-react-taro' |
|||
import {getCmsAd} from "@/api/cms/cmsAd"; |
|||
|
|||
const MyPage = () => { |
|||
const [item, setItem] = useState<CmsAd>() |
|||
const reload = () => { |
|||
getCmsAd(439).then(data => { |
|||
setItem(data) |
|||
}) |
|||
} |
|||
|
|||
useEffect(() => { |
|||
reload() |
|||
}, []) |
|||
|
|||
return ( |
|||
<> |
|||
<Swiper defaultValue={0} height={item?.height} indicator style={{ height: item?.height + 'px', display: 'none' }}> |
|||
{item?.imageList?.map((item) => ( |
|||
<Swiper.Item key={item}> |
|||
<Image width="100%" height="100%" src={item.url} mode={'scaleToFill'} lazyLoad={false} style={{ height: item.height + 'px' }} /> |
|||
</Swiper.Item> |
|||
))} |
|||
</Swiper> |
|||
</> |
|||
) |
|||
} |
|||
export default MyPage |
@ -0,0 +1,4 @@ |
|||
export default definePageConfig({ |
|||
navigationBarTitleText: '文章列表', |
|||
navigationBarTextStyle: 'black' |
|||
}) |
@ -0,0 +1,71 @@ |
|||
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 |
@ -0,0 +1,3 @@ |
|||
export default definePageConfig({ |
|||
navigationBarTitleText: '文章详情' |
|||
}) |
@ -0,0 +1,53 @@ |
|||
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 |
@ -1,32 +1,125 @@ |
|||
import { useEffect, useState } from 'react' |
|||
import { Swiper } from '@nutui/nutui-react-taro' |
|||
import {useEffect, useState} from 'react' |
|||
import {Swiper} from '@nutui/nutui-react-taro' |
|||
import {CmsAd} from "@/api/cms/cmsAd/model"; |
|||
import {Image} from '@nutui/nutui-react-taro' |
|||
import {getCmsAd} from "@/api/cms/cmsAd"; |
|||
import navTo from "@/utils/common"; |
|||
|
|||
|
|||
const MyPage = () => { |
|||
const [item, setItem] = useState<CmsAd>() |
|||
const reload = () => { |
|||
const [carouselData, setCarouselData] = useState<CmsAd>() |
|||
const [hotToday, setHotToday] = useState<CmsAd>() |
|||
const [groupBuy, setGroupBuy] = useState<CmsAd>() |
|||
|
|||
// 加载数据
|
|||
const loadData = () => { |
|||
// 轮播图
|
|||
getCmsAd(439).then(data => { |
|||
setItem(data) |
|||
setCarouselData(data) |
|||
}) |
|||
// 今日热卖素材(上层图片)
|
|||
getCmsAd(444).then(data => { |
|||
setHotToday(data) |
|||
}) |
|||
// 社区拼团素材(下层图片)
|
|||
getCmsAd(445).then(data => { |
|||
setGroupBuy(data) |
|||
}) |
|||
} |
|||
|
|||
useEffect(() => { |
|||
reload() |
|||
loadData() |
|||
}, []) |
|||
|
|||
// 轮播图高度,默认200px
|
|||
const carouselHeight = carouselData?.height || 200; |
|||
|
|||
return ( |
|||
<> |
|||
<Swiper defaultValue={0} height={item?.height} indicator style={{ height: item?.height + 'px' }}> |
|||
{item?.imageList?.map((item) => ( |
|||
<Swiper.Item key={item}> |
|||
<Image width="100%" height="100%" src={item.url} mode={'scaleToFill'} onClick={() => navTo(`${item.path}`)} lazyLoad={false} style={{ height: item.height + 'px' }} /> |
|||
</Swiper.Item> |
|||
))} |
|||
</Swiper> |
|||
</> |
|||
<div className="flex flex-row w-full gap-2 p-2 box-sizing-border" style={{height: `${carouselHeight}px`}}> |
|||
{/* 左侧轮播图区域 */} |
|||
<div className="flex-1" style={{height: '100%'}}> |
|||
<Swiper |
|||
defaultValue={0} |
|||
height={carouselHeight} |
|||
indicator |
|||
style={{height: `${carouselHeight}px`}} |
|||
> |
|||
{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'}} |
|||
alt={`轮播图${index + 1}`} |
|||
/> |
|||
</Swiper.Item> |
|||
))} |
|||
</Swiper> |
|||
</div> |
|||
|
|||
{/* 右侧上下图片区域 - 从API获取数据 */} |
|||
<div className="flex-1 flex flex-col gap-2" style={{height: '100%'}}> |
|||
{/* 上层图片 - 使用今日热卖素材 */} |
|||
<div style={{height: '50%'}}> |
|||
{hotToday?.imageList?.length ? ( |
|||
<Image |
|||
width="100%" |
|||
height="100%" |
|||
src={hotToday.imageList[0].url} |
|||
mode={'scaleToFill'} |
|||
onClick={() => navTo("/cms/category/index?id=4424" || '')} |
|||
lazyLoad={false} |
|||
style={{borderRadius: '4px'}} |
|||
alt="今日热卖" |
|||
/> |
|||
) : ( |
|||
<div style={{ |
|||
height: '100%', |
|||
backgroundColor: '#f5f5f5', |
|||
borderRadius: '4px', |
|||
display: 'flex', |
|||
alignItems: 'center', |
|||
justifyContent: 'center' |
|||
}}> |
|||
<span style={{color: '#999', fontSize: '12px'}}>加载中...</span> |
|||
</div> |
|||
)} |
|||
</div> |
|||
|
|||
{/* 下层图片 - 使用社区拼团素材 */} |
|||
<div style={{height: '50%'}}> |
|||
{groupBuy?.imageList?.length ? ( |
|||
<Image |
|||
width="100%" |
|||
height="100%" |
|||
src={groupBuy.imageList[0].url} |
|||
mode={'scaleToFill'} |
|||
onClick={() => navTo(groupBuy.imageList[0].path || '')} |
|||
lazyLoad={false} |
|||
style={{borderRadius: '4px'}} |
|||
alt="社区拼团" |
|||
/> |
|||
) : ( |
|||
<div style={{ |
|||
height: '100%', |
|||
backgroundColor: '#f5f5f5', |
|||
borderRadius: '4px', |
|||
display: 'flex', |
|||
alignItems: 'center', |
|||
justifyContent: 'center' |
|||
}}> |
|||
<span style={{color: '#999', fontSize: '12px'}}>加载中...</span> |
|||
</div> |
|||
)} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
export default MyPage |
|||
|
|||
|
@ -1,4 +1,9 @@ |
|||
.header-bg{ |
|||
background: url('https://oss.wsdns.cn/20250621/edb5d4da976b4d97ba185cb7077d2858.jpg') no-repeat top center; |
|||
//background: url('https://oss.wsdns.cn/20250621/edb5d4da976b4d97ba185cb7077d2858.jpg') no-repeat top center; |
|||
background: linear-gradient(to bottom, #03605c, #18ae4f); |
|||
background-size: 100%; |
|||
} |
|||
|
|||
.my-bg{ |
|||
background: url('https://oss.wsdns.cn/20250913/5ae575a50dbb4ccaab086c3679c5e2c3.png') no-repeat top center; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
export default definePageConfig({ |
|||
navigationBarTitleText: '企业采购', |
|||
navigationBarTextStyle: 'black' |
|||
}) |
@ -0,0 +1,115 @@ |
|||
import { useEffect, useState, useRef } from 'react' |
|||
import { Image } from '@nutui/nutui-react-taro' |
|||
import { CmsAd } from "@/api/cms/cmsAd/model"; |
|||
import { getCmsAd } from "@/api/cms/cmsAd"; |
|||
import navTo from "@/utils/common"; |
|||
|
|||
const NaturalFullscreenBanner = () => { |
|||
const [bannerData, setBannerData] = useState<CmsAd | null>(null) |
|||
const [isLoading, setIsLoading] = useState(true) |
|||
const containerRef = useRef<HTMLDivElement>(null) |
|||
const imageRef = useRef<HTMLImageElement>(null) |
|||
|
|||
// 加载图片数据
|
|||
const loadBannerData = () => { |
|||
setIsLoading(true) |
|||
getCmsAd(447) |
|||
.then(data => { |
|||
setBannerData(data) |
|||
setIsLoading(false) |
|||
}) |
|||
.catch(error => { |
|||
console.error('图片数据加载失败:', error) |
|||
setIsLoading(false) |
|||
}) |
|||
} |
|||
|
|||
// 处理图片加载完成后调整显示方式
|
|||
const handleImageLoad = () => { |
|||
if (imageRef.current && containerRef.current) { |
|||
// 获取图片原始宽高比
|
|||
const imgRatio = imageRef.current.naturalWidth / imageRef.current.naturalHeight; |
|||
// 获取容器宽高比
|
|||
const containerRatio = containerRef.current.offsetWidth / containerRef.current.offsetHeight; |
|||
|
|||
// 根据比例差异微调显示方式
|
|||
if (imgRatio > containerRatio) { |
|||
// 图片更宽,适当调整以显示更多垂直内容
|
|||
imageRef.current.style.objectPosition = 'center'; |
|||
} else { |
|||
// 图片更高,适当调整以显示更多水平内容
|
|||
imageRef.current.style.objectPosition = 'center'; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 设置全屏尺寸
|
|||
useEffect(() => { |
|||
const setFullscreenSize = () => { |
|||
if (containerRef.current) { |
|||
// 减去可能存在的导航栏高度,使显示更自然
|
|||
const windowHeight = window.innerHeight - 48; // 假设导航栏高度为48px
|
|||
const windowWidth = window.innerWidth; |
|||
|
|||
containerRef.current.style.height = `${windowHeight}px`; |
|||
containerRef.current.style.width = `${windowWidth}px`; |
|||
} |
|||
}; |
|||
|
|||
// 初始化尺寸
|
|||
setFullscreenSize(); |
|||
|
|||
// 监听窗口大小变化
|
|||
const resizeHandler = () => setFullscreenSize(); |
|||
window.addEventListener('resize', resizeHandler); |
|||
return () => window.removeEventListener('resize', resizeHandler); |
|||
}, []); |
|||
|
|||
useEffect(() => { |
|||
loadBannerData() |
|||
}, []) |
|||
|
|||
if (isLoading) { |
|||
return ( |
|||
<div ref={containerRef} className="flex items-center justify-center bg-gray-100"> |
|||
<span className="text-gray-500 text-sm">加载中...</span> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
// 获取第一张图片,如果有
|
|||
const firstImage = bannerData?.imageList?.[0]; |
|||
|
|||
if (!firstImage) { |
|||
return ( |
|||
<div ref={containerRef} className="flex items-center justify-center bg-gray-100"> |
|||
<span className="text-gray-500 text-sm">暂无图片数据</span> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
return ( |
|||
<div ref={containerRef} className="relative overflow-hidden bg-black"> |
|||
<Image |
|||
ref={imageRef} |
|||
className="absolute inset-0" |
|||
src={firstImage.url} |
|||
mode={'scaleToFill'} |
|||
onClick={() => firstImage.path && navTo(firstImage.path)} |
|||
lazyLoad={false} |
|||
alt="全屏 banner 图" |
|||
onLoad={handleImageLoad} |
|||
style={{ |
|||
width: '100%', |
|||
height: '100%', |
|||
// 优先保持比例,只裁剪必要部分
|
|||
objectFit: 'cover', |
|||
// 默认居中显示,保留图片主体内容
|
|||
objectPosition: 'center center' |
|||
}} |
|||
/> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
export default NaturalFullscreenBanner |
Loading…
Reference in new issue