基于Taro.js开发的H5应用

This commit is contained in:
2025-07-07 13:24:48 +08:00
parent 3db95dbe9b
commit 59f771d542
26 changed files with 919 additions and 193 deletions

View File

@@ -1,50 +0,0 @@
import {useEffect, useState} from "react";
import {ArrowRight} from '@nutui/icons-react-taro'
import {pageCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model";
import Taro from '@tarojs/taro'
/**
* 文章终极列表
* @constructor
*/
const Article = () => {
// const {params} = useRouter();
// const [categoryId, setCategoryId] = useState<number>(3494)
const [list, setList] = useState<CmsArticle[]>([])
const reload = () => {
// if (params.id) {
// setCategoryId(Number(params.id))
// }
pageCmsArticle({}).then(res => {
if (res?.list) {
setList(res?.list)
}
})
}
useEffect(() => {
reload()
}, [])
return (
<div className={'px-3 mt-4 mb-10'}>
<div className={'flex flex-col justify-between items-center bg-white rounded-lg p-4'}>
<div className={'bg-white w-full'}>
{
list.map((item, index) => {
return (
<div key={index} className={'flex justify-between items-center py-2'} onClick={() => Taro.navigateTo({url: `/cms/help?id=${item.articleId}`}) }>
<div className={'text-sm'}>{item.title}</div>
<ArrowRight color={'#cccccc'} size={18} />
</div>
)
})
}
</div>
</div>
</div>
)
}
export default Article

View File

@@ -0,0 +1,54 @@
import {useEffect, useState} from 'react'
import {Tag} from '@nutui/nutui-react-taro'
import {useRouter} from '@tarojs/taro'
import {Divider} from '@nutui/nutui-react-taro'
import {CmsArticle} from "@/api/cms/cmsArticle/model"
import {Eye} from '@nutui/icons-react-taro'
// 显示html富文本
import {View, RichText} from '@tarojs/components'
import './detail.scss'
import Line from "@/components/Gap";
import {getCmsArticle} from "@/api/cms/cmsArticle";
function Detail() {
const {params} = useRouter();
// 文章详情
const [item, setItem] = useState<CmsArticle>()
// 浏览量
const [views, setViews] = useState<number>()
const reload = () => {
getCmsArticle(Number(params.id)).then(data => {
if (data) {
setItem(data)
setViews(data.actualViews)
}
})
}
useEffect(() => {
reload();
}, []);
return (
<div className="mobile-container">
<div className={'bg-white'}>
<div className={'p-3 font-bold text-lg'}>{item?.title}</div>
<div className={'flex justify-between px-3'}>
<Tag type={'success'}>{item?.categoryName}</Tag>
<div className={'flex items-center gap-2 text-sm text-gray-400'}><Eye size={14}/>{views}</div>
</div>
<Divider/>
<View className={'content text-gray-700 text-sm'}>
<RichText
nodes={item?.content || '暂无内容'}
space="nbsp"
/>
</View>
<Line height={44}/>
</div>
</div>
)
}
export default Detail

View File

@@ -6,6 +6,7 @@ import {pageCmsAd} from "@/api/cms/cmsAd";
const MyPage = () => {
const [item, setItem] = useState<CmsAd>()
const [height, setHeight] = useState<string>()
const [width, setWidth] = useState<string>()
const reload = () => {
pageCmsAd({keywords: '幻灯片'}).then(data => {
@@ -13,6 +14,7 @@ const MyPage = () => {
if(data && data?.count > 0){
const cmsAd = data.list[0];
setHeight(cmsAd.height)
setWidth(cmsAd.width)
setItem(data.list[0])
}
})
@@ -23,15 +25,15 @@ const MyPage = () => {
}, [])
return (
<>
<Swiper defaultValue={0} height={height} indicator style={{ height: height + 'px' }}>
<div style={{width: width, height: height}} className={'px-3'}>
<Swiper defaultValue={0} height={height} indicator style={{ height: height + 'px', margin: '0 auto' }}>
{item?.imageList?.map((item) => (
<Swiper.Item key={item}>
<img width="100%" height="100%" src={item.url} alt="" style={{ height: height + 'px' }} />
</Swiper.Item>
))}
</Swiper>
</>
</div>
)
}
export default MyPage

36
src/pages/index/Image.tsx Normal file
View File

@@ -0,0 +1,36 @@
import {useEffect, useState} from 'react'
import {CmsAd} from "@/api/cms/cmsAd/model";
import {pageCmsAd} from "@/api/cms/cmsAd";
const MyPage = () => {
const [item, setItem] = useState<CmsAd>()
const [image, setImage] = useState()
const [height, setHeight] = useState<string>()
const [width, setWidth] = useState<string>()
const reload = () => {
pageCmsAd({keywords: 'TopBanner'}).then(data => {
if (data && data?.count > 0) {
const cmsAd = data.list[0];
setItem(cmsAd)
console.log(item,'ad')
setHeight(cmsAd.height)
setWidth(cmsAd.width)
if (cmsAd.imageList && cmsAd.imageList.length > 0) {
setImage(cmsAd.imageList[0].url)
}
}
})
}
useEffect(() => {
reload()
}, [])
return (
<>
<img src={image} alt="" style={{width: width + 'px', height: height + 'px'}}/>
</>
)
}
export default MyPage

View File

@@ -1,113 +1,39 @@
import {useEffect, useState} from 'react'
import {navigateTo} from '@tarojs/taro'
import Taro from '@tarojs/taro'
import {Button} from '@tarojs/components';
import {Image} from '@nutui/nutui-react-taro'
import {getSiteInfo} from "@/api/layout";
import {TenantId} from "@/utils/config";
import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
const Page = () => {
const [loading, setLoading] = useState(true)
const [isLogin, setIsLogin] = useState<boolean>(false)
const [navItems, setNavItems] = useState<CmsNavigation[]>([])
const [navItems, setNavItems] = useState<CmsNavigation[]>([])
/* 获取用户手机号 */
const handleGetPhoneNumber = ({detail}) => {
const {code, encryptedData, iv} = detail
Taro.login({
success: function () {
if (code) {
Taro.request({
url: 'https://server.gxwebsoft.com/api/wx-login/loginByMpWxPhone',
method: 'POST',
data: {
code,
encryptedData,
iv,
notVerifyPhone: true,
refereeId: 0,
sceneType: 'save_referee',
tenantId: TenantId
},
header: {
'content-type': 'application/json',
TenantId
},
success: function (res) {
Taro.setStorageSync('access_token', res.data.data.access_token)
Taro.setStorageSync('UserId', res.data.data.user.userId)
Taro.setStorageSync('Phone', res.data.data.user.phone)
setIsLogin(true)
Taro.showToast({
title: '登录成功',
icon: 'success'
});
}
})
} else {
console.log('登录失败!')
}
}
})
}
const reload = () => {
getSiteInfo().then(res => {
console.log(res);
console.log(res.topNavs, 'top');
setNavItems(res.topNavs || []);
})
};
const onLogin = (item: any) => {
if(!isLogin){
return navigateTo({url: `/pages/category/category?id=${item.navigationId}`})
}else {
// 善款明细
if(item.navigationId == 4119){
return navigateTo({url: `/bszx/pay-record/pay-record`})
}
return navigateTo({url: `/pages/category/category?id=${item.navigationId}`})
}
}
useEffect(() => {
reload();
}, [])
const reload = () => {
getSiteInfo().then(res => {
console.log(res);
console.log(res.topNavs,'top');
setNavItems(res.topNavs || []);
})
setLoading(false);
};
useEffect(() => {
reload();
}, [])
return (
<div className={'my-3'}>
<div>
<div className={'flex justify-between pb-2 px-1'}>
{
navItems.map((item, index) => (
<div key={index} className={'text-center'}>
return (
<div className={'py-2 my-3 mx-2'}>
<div className={'bg-white grid grid-cols-1 md:grid-cols-3 lg:grid-cols-3 gap-2'}>
{
isLogin && !loading ?
<div className={'flex flex-col justify-center items-center'} onClick={() => {
onLogin(item)
}}>
<Image src={item.icon} height={28} width={28}/>
<div className={'mt-2'} style={{fontSize: '15px'}}>{item?.title}</div>
</div>
:
<Button className={'text-white'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<div className={'flex flex-col justify-center items-center'}>
<Image src={item.icon} height={28} width={28}/>
<div className={'mt-2 text-gray-700'} style={{fontSize: '15px'}}>{item?.title}</div>
</div>
</Button>
navItems.map((item) => (
<div className={'flex flex-col justify-center items-center'} onClick={() => Taro.navigateTo({url: `/${item.model}/index?id=${item.navigationId}`})}>
<Image className={'shadow-xl rounded-lg'} style={{borderRadius: '8px'}} src={item.icon}
height={90} width={90}/>
<div className={'mt-2 text-gray-700'} style={{fontSize: '15px'}}>{item?.title}</div>
</div>
))
}
</div>
))
}
</div>
</div>
</div>
</div>
)
)
}
export default Page

View File

@@ -1,33 +0,0 @@
import { useEffect, useState } from 'react'
import { Swiper } from '@nutui/nutui-react-taro'
import {CmsAd} from "@/api/cms/cmsAd/model";
import {pageCmsAd} from "@/api/cms/cmsAd";
const MyPage = () => {
const [item, setItem] = useState<CmsAd>()
const reload = () => {
pageCmsAd({keywords: 'TopBanner'}).then(data => {
console.log(data,'幻灯片')
if(data && data?.count > 0){
setItem(data.list[0])
}
})
}
useEffect(() => {
reload()
}, [])
return (
<>
<Swiper defaultValue={0} height={279} indicator style={{ height: '280px' }}>
{item?.imageList?.map((item) => (
<Swiper.Item key={item}>
<img width="100%" height="100%" src={item.url} alt="" style={{ height: '280px' }} />
</Swiper.Item>
))}
</Swiper>
</>
)
}
export default MyPage

View File

@@ -1,2 +1,16 @@
page {
}
.mobile-container {
width: 100%;
min-height: 100vh;
// PC端样式
//@media screen and (min-width: 768px) {
// max-width: 414px;
// margin: 0 auto;
// min-height: auto;
// background-color: #fff;
// position: relative;
//}
}

View File

@@ -1,13 +1,12 @@
import './index.scss'
import Taro from '@tarojs/taro';
// import {useShareAppMessage, useShareTimeline} from "@tarojs/taro"
import {useEffect, useState} from "react";
import {getSiteInfo} from "@/api/layout";
import Login from "./Login";
import Banner from "./Banner";
import Menu from "./Menu";
import TopBanner from "./TopBanner";
import TabBar from "@/components/TabBar";
import Image from "./Image";
export interface Market {
// 自增ID
@@ -123,14 +122,14 @@ function Home() {
}, []);
return (
<>
<div className="mobile-container">
{!IsLogin && search ? (<Login done={handleLogin}/>) : (<>
<TopBanner/>
<Image/>
<Menu/>
<Banner/>
<TabBar/>
</>)}
</>
</div>
)
}

View File

@@ -8,13 +8,13 @@ function User() {
useEffect(() => {
}, []);
return (
<>
<div className="mobile-container">
<div className={'fixed w-full'}>
<UserCard />
<UserCell />
<TabBar/>
</div>
</>
</div>
)
}