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 {CmsAd} from "@/api/cms/cmsAd/model"; |
||||
import {Image} from '@nutui/nutui-react-taro' |
import {Image} from '@nutui/nutui-react-taro' |
||||
import {getCmsAd} from "@/api/cms/cmsAd"; |
import {getCmsAd} from "@/api/cms/cmsAd"; |
||||
import navTo from "@/utils/common"; |
import navTo from "@/utils/common"; |
||||
|
|
||||
|
|
||||
const MyPage = () => { |
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 => { |
getCmsAd(439).then(data => { |
||||
setItem(data) |
|
||||
|
setCarouselData(data) |
||||
|
}) |
||||
|
// 今日热卖素材(上层图片)
|
||||
|
getCmsAd(444).then(data => { |
||||
|
setHotToday(data) |
||||
|
}) |
||||
|
// 社区拼团素材(下层图片)
|
||||
|
getCmsAd(445).then(data => { |
||||
|
setGroupBuy(data) |
||||
}) |
}) |
||||
} |
} |
||||
|
|
||||
useEffect(() => { |
useEffect(() => { |
||||
reload() |
|
||||
|
loadData() |
||||
}, []) |
}, []) |
||||
|
|
||||
|
// 轮播图高度,默认200px
|
||||
|
const carouselHeight = carouselData?.height || 200; |
||||
|
|
||||
return ( |
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 |
export default MyPage |
||||
|
|
||||
|
@ -1,4 +1,9 @@ |
|||||
.header-bg{ |
.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%; |
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