feat(admin): 从文章详情页面改为文章管理页面

- 修改页面配置,设置新的导航栏标题和样式
- 重新设计页面布局,增加搜索栏、文章列表和操作按钮
- 添加文章搜索、分页加载和删除功能
- 优化文章列表项的样式和交互
- 新增礼品卡相关API和组件
- 更新优惠券组件,增加到期提醒和筛选功能
This commit is contained in:
2025-08-13 10:11:57 +08:00
parent 0e457f66d8
commit a1cacc04e8
67 changed files with 6278 additions and 2816 deletions

248
src/user/coupon/receive.tsx Normal file
View File

@@ -0,0 +1,248 @@
import {useState} from "react";
import Taro, {useDidShow} from '@tarojs/taro'
import {Button, Empty, ConfigProvider, SearchBar, InfiniteLoading, Loading, PullToRefresh} from '@nutui/nutui-react-taro'
import {Gift, Search} from '@nutui/icons-react-taro'
import {View} from '@tarojs/components'
import {ShopCoupon} from "@/api/shop/shopCoupon/model";
import {pageShopCoupon} from "@/api/shop/shopCoupon";
import CouponList from "@/components/CouponList";
import {CouponCardProps} from "@/components/CouponCard";
const CouponReceive = () => {
const [list, setList] = useState<ShopCoupon[]>([])
const [loading, setLoading] = useState(false)
const [hasMore, setHasMore] = useState(true)
const [searchValue, setSearchValue] = useState('')
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const reload = async (isRefresh = false) => {
if (isRefresh) {
setPage(1)
setList([])
setHasMore(true)
}
setLoading(true)
try {
const currentPage = isRefresh ? 1 : page
// 获取可领取的优惠券(启用状态且未过期)
const res = await pageShopCoupon({
page: currentPage,
limit: 10,
keywords: searchValue,
enabled: '1', // 启用状态
isExpire: 0 // 未过期
})
if (res && res.list) {
const newList = isRefresh ? res.list : [...list, ...res.list]
setList(newList)
setTotal(res.count || 0)
setHasMore(res.list.length === 10)
if (!isRefresh) {
setPage(currentPage + 1)
} else {
setPage(2)
}
} else {
setHasMore(false)
setTotal(0)
}
} catch (error) {
console.error('获取优惠券失败:', error)
Taro.showToast({
title: '获取优惠券失败',
icon: 'error'
});
} finally {
setLoading(false)
}
}
// 搜索功能
const handleSearch = (value: string) => {
setSearchValue(value)
reload(true)
}
// 下拉刷新
const handleRefresh = async () => {
await reload(true)
}
// 转换优惠券数据为CouponCard组件所需格式
const transformCouponData = (coupon: ShopCoupon): CouponCardProps => {
let amount = 0
let type: 1 | 2 | 3 = 1
if (coupon.type === 10) { // 满减券
type = 1
amount = parseFloat(coupon.reducePrice || '0')
} else if (coupon.type === 20) { // 折扣券
type = 2
amount = coupon.discount || 0
} else if (coupon.type === 30) { // 免费券
type = 3
amount = 0
}
return {
amount,
type,
status: 0, // 可领取状态
minAmount: parseFloat(coupon.minPrice || '0'),
title: coupon.name || '优惠券',
startTime: coupon.startTime,
endTime: coupon.endTime,
showReceiveBtn: true, // 显示领取按钮
onReceive: () => handleReceiveCoupon(coupon),
theme: getThemeByType(coupon.type)
}
}
// 根据优惠券类型获取主题色
const getThemeByType = (type?: number): 'red' | 'orange' | 'blue' | 'purple' | 'green' => {
switch (type) {
case 10: return 'red' // 满减券
case 20: return 'orange' // 折扣券
case 30: return 'green' // 免费券
default: return 'blue'
}
}
// 领取优惠券
const handleReceiveCoupon = async (coupon: ShopCoupon) => {
try {
// 这里应该调用领取优惠券的API
// await receiveCoupon(coupon.id)
Taro.showToast({
title: '领取成功',
icon: 'success'
})
// 刷新列表
reload(true)
} catch (error) {
console.error('领取优惠券失败:', error)
Taro.showToast({
title: '领取失败',
icon: 'error'
})
}
}
// 优惠券点击事件
const handleCouponClick = (coupon: CouponCardProps, index: number) => {
const originalCoupon = list[index]
if (originalCoupon) {
// 显示优惠券详情
showCouponDetail(originalCoupon)
}
}
// 显示优惠券详情
const showCouponDetail = (coupon: ShopCoupon) => {
// 跳转到优惠券详情页
Taro.navigateTo({
url: `/user/coupon/detail?id=${coupon.id}`
})
}
// 加载更多
const loadMore = async () => {
if (!loading && hasMore) {
await reload(false)
}
}
useDidShow(() => {
reload(true).then()
});
return (
<ConfigProvider>
{/* 搜索栏 */}
<View className="bg-white px-4 py-3">
<SearchBar
placeholder="搜索优惠券名称"
value={searchValue}
onChange={setSearchValue}
onSearch={handleSearch}
leftIcon={<Search />}
/>
</View>
{/* 统计信息 */}
{total > 0 && (
<View className="px-4 py-2 text-sm text-gray-500 bg-gray-50">
{total}
</View>
)}
{/* 优惠券列表 */}
<PullToRefresh
onRefresh={handleRefresh}
headHeight={60}
>
<View style={{ height: 'calc(100vh - 160px)', overflowY: 'auto' }} id="coupon-scroll">
{list.length === 0 && !loading ? (
<View className="flex flex-col justify-center items-center" style={{height: 'calc(100vh - 250px)'}}>
<Empty
description="暂无可领取优惠券"
style={{backgroundColor: 'transparent'}}
/>
<Button
type="primary"
size="small"
className="mt-4"
onClick={() => Taro.navigateTo({url: '/pages/index/index'})}
>
</Button>
</View>
) : (
<InfiniteLoading
target="coupon-scroll"
hasMore={hasMore}
onLoadMore={loadMore}
loadingText={
<View className="flex justify-center items-center py-4">
<Loading />
<View className="ml-2">...</View>
</View>
}
loadMoreText={
<View className="text-center py-4 text-gray-500">
{list.length === 0 ? "暂无数据" : "没有更多了"}
</View>
}
>
<CouponList
coupons={list.map(transformCouponData)}
onCouponClick={handleCouponClick}
showEmpty={false}
/>
</InfiniteLoading>
)}
</View>
</PullToRefresh>
{/* 底部提示 */}
{list.length === 0 && !loading && (
<View className="text-center py-8">
<View className="text-gray-400 mb-4">
<Gift size="48" />
</View>
<View className="text-gray-500 mb-2"></View>
<View className="text-gray-400 text-sm"></View>
</View>
)}
</ConfigProvider>
);
};
export default CouponReceive;