Browse Source
- 添加文章列表页面,支持搜索、分页加载、下拉刷新等功能 - 实现文章详情查看、编辑和删除功能- 新增文章发布页面,支持富文本编辑和图片上传 - 优化地址管理页面,统一底部按钮样式 - 新增 FixedButton 组件用于底部固定按钮master
8 changed files with 681 additions and 184 deletions
@ -0,0 +1,26 @@ |
|||
import {View} from '@tarojs/components'; |
|||
import {Button} from '@nutui/nutui-react-taro' |
|||
|
|||
function FixedButton({text, onClick, icon}) { |
|||
return ( |
|||
<> |
|||
{/* 底部安全区域占位 */ |
|||
} |
|||
<View className="h-20 w-full"></View> |
|||
<View |
|||
className="fixed z-50 bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-3 safe-area-bottom"> |
|||
<Button |
|||
type="success" |
|||
size="large" |
|||
block |
|||
icon={icon} |
|||
className="px-6" |
|||
onClick={onClick}> |
|||
{text || '新增'} |
|||
</Button> |
|||
</View> |
|||
</> |
|||
) |
|||
} |
|||
|
|||
export default FixedButton; |
@ -0,0 +1,4 @@ |
|||
export default definePageConfig({ |
|||
navigationBarTitleText: '新增收货地址', |
|||
navigationBarTextStyle: 'black' |
|||
}) |
@ -0,0 +1,323 @@ |
|||
import {useEffect, useState, useRef} from "react"; |
|||
import {useRouter} from '@tarojs/taro' |
|||
import {Button, Loading, CellGroup, Input, TextArea, Form, Switch, InputNumber, Radio, Image} from '@nutui/nutui-react-taro' |
|||
import {Edit, Upload as UploadIcon} from '@nutui/icons-react-taro' |
|||
import Taro from '@tarojs/taro' |
|||
import {View} from '@tarojs/components' |
|||
import {ShopArticle} from "@/api/shop/shopArticle/model"; |
|||
import {getShopArticle, addShopArticle, updateShopArticle} from "@/api/shop/shopArticle"; |
|||
import FixedButton from "@/components/FixedButton"; |
|||
|
|||
const AddShopArticle = () => { |
|||
const {params} = useRouter(); |
|||
const [loading, setLoading] = useState<boolean>(true) |
|||
const [formData, setFormData] = useState<ShopArticle>({ |
|||
type: 0, // 默认常规文章
|
|||
status: 0, // 默认已发布
|
|||
permission: 0, // 默认所有人可见
|
|||
recommend: 0, // 默认不推荐
|
|||
showType: 10, // 默认小图展示
|
|||
virtualViews: 0, // 默认虚拟阅读量
|
|||
actualViews: 0, // 默认实际阅读量
|
|||
sortNumber: 0 // 默认排序
|
|||
}) |
|||
const formRef = useRef<any>(null) |
|||
|
|||
// 判断是编辑还是新增模式
|
|||
const isEditMode = !!params.id |
|||
const articleId = params.id ? Number(params.id) : undefined |
|||
|
|||
// 文章类型选项
|
|||
const typeOptions = [ |
|||
{ text: '常规文章', value: 0 }, |
|||
{ text: '视频文章', value: 1 } |
|||
] |
|||
|
|||
// 状态选项
|
|||
const statusOptions = [ |
|||
{ text: '已发布', value: 0 }, |
|||
{ text: '待审核', value: 1 }, |
|||
{ text: '已驳回', value: 2 }, |
|||
{ text: '违规内容', value: 3 } |
|||
] |
|||
|
|||
// 可见性选项
|
|||
const permissionOptions = [ |
|||
{ text: '所有人可见', value: 0 }, |
|||
{ text: '登录可见', value: 1 }, |
|||
{ text: '密码可见', value: 2 } |
|||
] |
|||
|
|||
// 显示方式选项
|
|||
const showTypeOptions = [ |
|||
{ text: '小图展示', value: 10 }, |
|||
{ text: '大图展示', value: 20 } |
|||
] |
|||
|
|||
const reload = async () => { |
|||
// 如果是编辑模式,加载文章数据
|
|||
if (isEditMode && articleId) { |
|||
try { |
|||
const article = await getShopArticle(articleId) |
|||
setFormData(article) |
|||
// 更新表单值
|
|||
if (formRef.current) { |
|||
formRef.current.setFieldsValue(article) |
|||
} |
|||
} catch (error) { |
|||
console.error('加载文章失败:', error) |
|||
Taro.showToast({ |
|||
title: '加载文章失败', |
|||
icon: 'error' |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 图片上传处理
|
|||
const handleImageUpload = async () => { |
|||
try { |
|||
const res = await Taro.chooseImage({ |
|||
count: 1, |
|||
sizeType: ['compressed'], |
|||
sourceType: ['album', 'camera'] |
|||
}); |
|||
|
|||
if (res.tempFilePaths && res.tempFilePaths.length > 0) { |
|||
// 这里应该调用上传接口,暂时使用本地路径
|
|||
const imagePath = res.tempFilePaths[0]; |
|||
setFormData({ |
|||
...formData, |
|||
image: imagePath |
|||
}); |
|||
|
|||
Taro.showToast({ |
|||
title: '图片选择成功', |
|||
icon: 'success' |
|||
}); |
|||
} |
|||
} catch (error) { |
|||
Taro.showToast({ |
|||
title: '图片选择失败', |
|||
icon: 'error' |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// 提交表单
|
|||
const submitSucceed = async (values: any) => { |
|||
try { |
|||
// 准备提交的数据
|
|||
const submitData = { |
|||
...formData, |
|||
...values, |
|||
}; |
|||
|
|||
// 如果是编辑模式,添加id
|
|||
if (isEditMode && articleId) { |
|||
submitData.articleId = articleId; |
|||
} |
|||
|
|||
// 执行新增或更新操作
|
|||
if (isEditMode) { |
|||
await updateShopArticle(submitData); |
|||
} else { |
|||
await addShopArticle(submitData); |
|||
} |
|||
|
|||
Taro.showToast({ |
|||
title: `${isEditMode ? '更新' : '保存'}成功`, |
|||
icon: 'success' |
|||
}); |
|||
|
|||
setTimeout(() => { |
|||
Taro.navigateBack(); |
|||
}, 1000); |
|||
|
|||
} catch (error) { |
|||
console.error('保存失败:', error); |
|||
Taro.showToast({ |
|||
title: `${isEditMode ? '更新' : '保存'}失败`, |
|||
icon: 'error' |
|||
}); |
|||
} |
|||
} |
|||
|
|||
const submitFailed = (error: any) => { |
|||
console.log(error, 'err...') |
|||
} |
|||
|
|||
useEffect(() => { |
|||
// 动态设置页面标题
|
|||
Taro.setNavigationBarTitle({ |
|||
title: isEditMode ? '编辑文章' : '新增文章' |
|||
}); |
|||
|
|||
reload().then(() => { |
|||
setLoading(false) |
|||
}) |
|||
}, [isEditMode]); |
|||
|
|||
if (loading) { |
|||
return <Loading className={'px-2'}>加载中</Loading> |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<Form |
|||
ref={formRef} |
|||
divider |
|||
initialValues={formData} |
|||
labelPosition="left" |
|||
onFinish={(values) => submitSucceed(values)} |
|||
onFinishFailed={(errors) => submitFailed(errors)} |
|||
> |
|||
{/* 基本信息 */} |
|||
<CellGroup title="基本信息"> |
|||
<Form.Item |
|||
name="title" |
|||
label="文章标题" |
|||
required |
|||
rules={[{ required: true, message: '请输入文章标题' }]} |
|||
initialValue={formData.title} |
|||
> |
|||
<Input placeholder="请输入文章标题" maxLength={100}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="overview" label="文章概述" initialValue={formData.overview}> |
|||
<TextArea placeholder="请输入文章概述,用于列表展示" maxLength={200} rows={3}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item |
|||
name="detail" |
|||
label="文章内容" |
|||
required |
|||
rules={[{ required: true, message: '请输入文章内容' }]} |
|||
initialValue={formData.detail} |
|||
> |
|||
<TextArea placeholder="请输入文章内容" maxLength={10000} rows={8}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="author" label="作者" initialValue={formData.author}> |
|||
<Input placeholder="请输入作者名称" maxLength={50}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="source" label="来源" initialValue={formData.source}> |
|||
<Input placeholder="请输入文章来源" maxLength={100}/> |
|||
</Form.Item> |
|||
</CellGroup> |
|||
|
|||
{/* 文章设置 */} |
|||
<CellGroup title="文章设置"> |
|||
<Form.Item name="type" label="文章类型" initialValue={formData.type}> |
|||
<Radio.Group direction="horizontal" value={formData.type}> |
|||
{typeOptions.map(option => ( |
|||
<Radio key={option.value} value={option.value}> |
|||
{option.text} |
|||
</Radio> |
|||
))} |
|||
</Radio.Group> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="status" label="发布状态" initialValue={formData.status}> |
|||
<Radio.Group direction="horizontal" value={formData.status}> |
|||
{statusOptions.map(option => ( |
|||
<Radio key={option.value} value={option.value}> |
|||
{option.text} |
|||
</Radio> |
|||
))} |
|||
</Radio.Group> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="permission" label="可见性" initialValue={formData.permission}> |
|||
<Radio.Group direction="horizontal" value={formData.permission}> |
|||
{permissionOptions.map(option => ( |
|||
<Radio key={option.value} value={option.value}> |
|||
{option.text} |
|||
</Radio> |
|||
))} |
|||
</Radio.Group> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="showType" label="显示方式" initialValue={formData.showType}> |
|||
<Radio.Group direction="horizontal" value={formData.showType}> |
|||
{showTypeOptions.map(option => ( |
|||
<Radio key={option.value} value={option.value}> |
|||
{option.text} |
|||
</Radio> |
|||
))} |
|||
</Radio.Group> |
|||
</Form.Item> |
|||
</CellGroup> |
|||
|
|||
{/* 高级设置 */} |
|||
<CellGroup title="高级设置"> |
|||
<Form.Item name="recommend" label="推荐文章" initialValue={formData.recommend}> |
|||
<Switch |
|||
checked={formData.recommend === 1} |
|||
onChange={(checked) => |
|||
setFormData({...formData, recommend: checked ? 1 : 0}) |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="price" label="付费金额" initialValue={formData.price}> |
|||
<Input placeholder="0.00" type="number"/> |
|||
<View className="text-xs text-gray-500 mt-1">单位:元</View> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="virtualViews" label="虚拟阅读量" initialValue={formData.virtualViews}> |
|||
<InputNumber min={0} defaultValue={formData.virtualViews || 0}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="actualViews" label="实际阅读量" initialValue={formData.actualViews}> |
|||
<InputNumber min={0} defaultValue={formData.actualViews || 0}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="sortNumber" label="排序" initialValue={formData.sortNumber}> |
|||
<InputNumber min={0} defaultValue={formData.sortNumber || 0}/> |
|||
<View className="text-xs text-gray-500 mt-1">数字越小越靠前</View> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="tags" label="标签" initialValue={formData.tags}> |
|||
<Input placeholder="请输入标签,多个标签用逗号分隔" maxLength={200}/> |
|||
</Form.Item> |
|||
|
|||
<Form.Item name="topic" label="话题" initialValue={formData.topic}> |
|||
<Input placeholder="请输入话题" maxLength={100}/> |
|||
</Form.Item> |
|||
</CellGroup> |
|||
|
|||
{/* 图片上传 */} |
|||
<CellGroup title="文章图片"> |
|||
<Form.Item name="image" label="封面图片" initialValue={formData.image}> |
|||
<View className="flex items-center gap-3"> |
|||
{formData.image && ( |
|||
<Image |
|||
src={formData.image} |
|||
width="80" |
|||
height="80" |
|||
radius="8" |
|||
/> |
|||
)} |
|||
<Button |
|||
size="small" |
|||
type="primary" |
|||
fill="outline" |
|||
icon={<UploadIcon />} |
|||
onClick={handleImageUpload} |
|||
> |
|||
{formData.image ? '更换图片' : '上传图片'} |
|||
</Button> |
|||
</View> |
|||
</Form.Item> |
|||
</CellGroup> |
|||
|
|||
{/* 提交按钮 */} |
|||
<FixedButton text={isEditMode ? '更新文章' : '发布文章'} onClick={submitSucceed} icon={<Edit />} /> |
|||
</Form> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default AddShopArticle; |
@ -1,151 +1,272 @@ |
|||
import {useState} from "react"; |
|||
import Taro, {useDidShow} from '@tarojs/taro' |
|||
import {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Divider} from '@nutui/nutui-react-taro' |
|||
import {Dongdong, ArrowRight, CheckNormal, Checked} from '@nutui/icons-react-taro' |
|||
import {Button, Cell, CellGroup, Empty, ConfigProvider, SearchBar, Tag, InfiniteLoading, Loading, PullToRefresh} from '@nutui/nutui-react-taro' |
|||
import {Edit, Del, Eye} from '@nutui/icons-react-taro' |
|||
import {View} from '@tarojs/components' |
|||
import {ShopUserAddress} from "@/api/shop/shopUserAddress/model"; |
|||
import {listShopUserAddress, removeShopUserAddress, updateShopUserAddress} from "@/api/shop/shopUserAddress"; |
|||
import {ShopArticle} from "@/api/shop/shopArticle/model"; |
|||
import {pageShopArticle, removeShopArticle} from "@/api/shop/shopArticle"; |
|||
import FixedButton from "@/components/FixedButton"; |
|||
import dayjs from "dayjs"; |
|||
|
|||
const Address = () => { |
|||
const [list, setList] = useState<ShopUserAddress[]>([]) |
|||
const [address, setAddress] = useState<ShopUserAddress>() |
|||
const ShopArticleManage = () => { |
|||
const [list, setList] = useState<ShopArticle[]>([]) |
|||
const [loading, setLoading] = useState(false) |
|||
const [refreshing, setRefreshing] = useState(false) |
|||
const [hasMore, setHasMore] = useState(true) |
|||
const [searchValue, setSearchValue] = useState('') |
|||
const [page, setPage] = useState(1) |
|||
const [total, setTotal] = useState(0) |
|||
|
|||
const reload = () => { |
|||
listShopUserAddress({ |
|||
userId: Taro.getStorageSync('UserId') |
|||
}) |
|||
.then(data => { |
|||
setList(data || []) |
|||
// 默认地址
|
|||
setAddress(data.find(item => item.isDefault)) |
|||
const reload = async (isRefresh = false) => { |
|||
if (isRefresh) { |
|||
setPage(1) |
|||
setList([]) |
|||
setHasMore(true) |
|||
} |
|||
|
|||
setLoading(true) |
|||
try { |
|||
const currentPage = isRefresh ? 1 : page |
|||
const res = await pageShopArticle({ |
|||
page: currentPage, |
|||
limit: 10, |
|||
keywords: searchValue |
|||
}) |
|||
.catch(() => { |
|||
|
|||
if (res && res.list) { |
|||
const newList = isRefresh ? res.list : [...list, ...res.list] |
|||
setList(newList) |
|||
setTotal(res.count || 0) |
|||
|
|||
// 判断是否还有更多数据
|
|||
setHasMore(res.list.length === 10) // 如果返回的数据等于limit,说明可能还有更多
|
|||
|
|||
if (!isRefresh) { |
|||
setPage(currentPage + 1) |
|||
} else { |
|||
setPage(2) // 刷新后下一页是第2页
|
|||
} |
|||
} else { |
|||
setHasMore(false) |
|||
setTotal(0) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取文章失败:', error) |
|||
Taro.showToast({ |
|||
title: '获取地址失败', |
|||
title: '获取文章失败', |
|||
icon: 'error' |
|||
}); |
|||
}) |
|||
} finally { |
|||
setLoading(false) |
|||
} |
|||
} |
|||
|
|||
const onDefault = async (item: ShopUserAddress) => { |
|||
if (address) { |
|||
await updateShopUserAddress({ |
|||
...address, |
|||
isDefault: false |
|||
}) |
|||
// 搜索功能
|
|||
const handleSearch = (value: string) => { |
|||
setSearchValue(value) |
|||
reload(true) |
|||
} |
|||
await updateShopUserAddress({ |
|||
id: item.id, |
|||
isDefault: true |
|||
}) |
|||
Taro.showToast({ |
|||
title: '设置成功', |
|||
icon: 'success' |
|||
}); |
|||
reload(); |
|||
|
|||
// 下拉刷新
|
|||
const handleRefresh = async () => { |
|||
setRefreshing(true) |
|||
await reload(true) |
|||
setRefreshing(false) |
|||
} |
|||
|
|||
const onDel = async (id?: number) => { |
|||
await removeShopUserAddress(id) |
|||
// 删除文章
|
|||
const handleDelete = async (id?: number) => { |
|||
Taro.showModal({ |
|||
title: '确认删除', |
|||
content: '确定要删除这篇文章吗?', |
|||
success: async (res) => { |
|||
if (res.confirm) { |
|||
try { |
|||
await removeShopArticle(id) |
|||
Taro.showToast({ |
|||
title: '删除成功', |
|||
icon: 'success' |
|||
}); |
|||
reload(); |
|||
reload(true); |
|||
} catch (error) { |
|||
Taro.showToast({ |
|||
title: '删除失败', |
|||
icon: 'error' |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
const selectAddress = async (item: ShopUserAddress) => { |
|||
if (address) { |
|||
await updateShopUserAddress({ |
|||
...address, |
|||
isDefault: false |
|||
}) |
|||
// 编辑文章
|
|||
const handleEdit = (item: ShopArticle) => { |
|||
Taro.navigateTo({ |
|||
url: `/shop/shopArticle/add?id=${item.articleId}` |
|||
}); |
|||
} |
|||
await updateShopUserAddress({ |
|||
id: item.id, |
|||
isDefault: true |
|||
|
|||
// 查看文章详情
|
|||
const handleView = (item: ShopArticle) => { |
|||
// 这里可以跳转到文章详情页面
|
|||
Taro.navigateTo({ |
|||
url: `/cms/detail/index?id=${item.articleId}` |
|||
}) |
|||
setTimeout(() => { |
|||
Taro.navigateBack() |
|||
},500) |
|||
} |
|||
|
|||
// 获取状态标签
|
|||
const getStatusTag = (status?: number) => { |
|||
switch (status) { |
|||
case 0: |
|||
return <Tag type="success">已发布</Tag> |
|||
case 1: |
|||
return <Tag type="warning">待审核</Tag> |
|||
case 2: |
|||
return <Tag type="danger">已驳回</Tag> |
|||
case 3: |
|||
return <Tag type="danger">违规内容</Tag> |
|||
default: |
|||
return <Tag>未知</Tag> |
|||
} |
|||
} |
|||
|
|||
// 加载更多
|
|||
const loadMore = async () => { |
|||
if (!loading && hasMore) { |
|||
await reload(false) // 不刷新,追加数据
|
|||
} |
|||
} |
|||
|
|||
useDidShow(() => { |
|||
reload() |
|||
reload(true).then() |
|||
}); |
|||
|
|||
if (list.length == 0) { |
|||
return ( |
|||
<ConfigProvider> |
|||
<div className={'h-full flex flex-col justify-center items-center'} style={{ |
|||
height: 'calc(100vh - 300px)', |
|||
}}> |
|||
<Empty |
|||
style={{ |
|||
backgroundColor: 'transparent' |
|||
}} |
|||
description="您还没有地址哦" |
|||
{/* 搜索栏 */} |
|||
<View className="py-2"> |
|||
<SearchBar |
|||
placeholder="搜索关键词" |
|||
value={searchValue} |
|||
onChange={setSearchValue} |
|||
onSearch={handleSearch} |
|||
/> |
|||
<Space> |
|||
<Button onClick={() => Taro.navigateTo({url: '/user/address/add'})}>新增地址</Button> |
|||
<Button type="success" fill="dashed" |
|||
onClick={() => Taro.navigateTo({url: '/user/address/wxAddress'})}>获取微信地址</Button> |
|||
</Space> |
|||
</div> |
|||
</ConfigProvider> |
|||
) |
|||
} |
|||
</View> |
|||
|
|||
return ( |
|||
<> |
|||
<CellGroup> |
|||
<Cell |
|||
onClick={() => Taro.navigateTo({url: '/user/address/wxAddress'})} |
|||
{/* 统计信息 */} |
|||
{total > 0 && ( |
|||
<View className="px-4 py-2 text-sm text-gray-500"> |
|||
共找到 {total} 篇文章 |
|||
</View> |
|||
)} |
|||
|
|||
{/* 文章列表 */} |
|||
<PullToRefresh |
|||
onRefresh={handleRefresh} |
|||
pullDistance={60} |
|||
headHeight={60} |
|||
> |
|||
<div className={'flex justify-between items-center w-full'}> |
|||
<div className={'flex items-center gap-3'}> |
|||
<Dongdong className={'text-green-600'}/> |
|||
<div>获取微信地址</div> |
|||
</div> |
|||
<ArrowRight className={'text-gray-400'}/> |
|||
</div> |
|||
</Cell> |
|||
</CellGroup> |
|||
{list.map((item, _) => ( |
|||
<Cell.Group> |
|||
<Cell className={'flex flex-col gap-1'} onClick={() => selectAddress(item)}> |
|||
<View> |
|||
<View className={'font-medium text-sm'}>{item.name} {item.phone}</View> |
|||
<View className="px-4" style={{ height: 'calc(100vh - 160px)', overflowY: 'auto' }} id="article-scroll"> |
|||
{list.length === 0 && !loading ? ( |
|||
<View className="flex flex-col justify-center items-center" style={{height: 'calc(100vh - 200px)'}}> |
|||
<Empty |
|||
description="暂无文章数据" |
|||
style={{backgroundColor: 'transparent'}} |
|||
/> |
|||
</View> |
|||
<View className={'text-xs'}> |
|||
{item.province} {item.city} {item.region} {item.address} |
|||
) : ( |
|||
<InfiniteLoading |
|||
target="article-scroll" |
|||
hasMore={hasMore} |
|||
onLoadMore={loadMore} |
|||
loadingText={ |
|||
<View className="flex justify-center items-center py-4"> |
|||
<Loading /> |
|||
<View className="ml-2">加载中...</View> |
|||
</View> |
|||
</Cell> |
|||
<Cell |
|||
align="center" |
|||
title={ |
|||
<View className={'flex items-center gap-1'} onClick={() => onDefault(item)}> |
|||
{item.isDefault ? <Checked className={'text-green-600'} size={16}/> : <CheckNormal size={16}/>} |
|||
<View className={'text-gray-400'}>默认地址</View> |
|||
} |
|||
loadMoreText={ |
|||
<View className="text-center py-4 text-gray-500"> |
|||
{list.length === 0 ? "暂无数据" : "没有更多了"} |
|||
</View> |
|||
} |
|||
extra={ |
|||
<> |
|||
<View className={'text-gray-400'} onClick={() => onDel(item.id)}> |
|||
> |
|||
{list.map((item, index) => ( |
|||
<CellGroup key={item.articleId || index} className="mb-4"> |
|||
<Cell> |
|||
<View className="flex flex-col gap-3 w-full"> |
|||
{/* 文章标题和状态 */} |
|||
<View className="flex justify-between items-start"> |
|||
<View className="flex-1 pr-2"> |
|||
<View className="text-lg font-bold text-gray-900 line-clamp-2"> |
|||
{item.title} |
|||
</View> |
|||
</View> |
|||
{getStatusTag(item.status)} |
|||
</View> |
|||
|
|||
{/* 文章概述 */} |
|||
{item.overview && ( |
|||
<View className="text-sm text-gray-600 line-clamp-2"> |
|||
{item.overview} |
|||
</View> |
|||
)} |
|||
|
|||
{/* 文章信息 */} |
|||
<View className="flex justify-between items-center text-xs text-gray-500"> |
|||
<View className="flex items-center gap-4"> |
|||
<View>阅读: {item.actualViews || 0}</View> |
|||
{item.price && <View>价格: ¥{item.price}</View>} |
|||
<View>创建: {dayjs(item.createTime).format('MM-DD HH:mm')}</View> |
|||
</View> |
|||
</View> |
|||
|
|||
{/* 操作按钮 */} |
|||
<View className="flex justify-end gap-2 pt-2 border-t border-gray-100"> |
|||
<Button |
|||
size="small" |
|||
fill="outline" |
|||
icon={<Eye/>} |
|||
onClick={() => handleView(item)} |
|||
> |
|||
查看 |
|||
</Button> |
|||
<Button |
|||
size="small" |
|||
fill="outline" |
|||
icon={<Edit/>} |
|||
onClick={() => handleEdit(item)} |
|||
> |
|||
编辑 |
|||
</Button> |
|||
<Button |
|||
size="small" |
|||
type="danger" |
|||
fill="outline" |
|||
icon={<Del/>} |
|||
onClick={() => handleDelete(item.articleId)} |
|||
> |
|||
删除 |
|||
</Button> |
|||
</View> |
|||
<Divider direction={'vertical'}/> |
|||
<View className={'text-gray-400'} |
|||
onClick={() => Taro.navigateTo({url: '/user/address/add?id=' + item.id})}> |
|||
修改 |
|||
</View> |
|||
</> |
|||
} |
|||
/> |
|||
</Cell.Group> |
|||
</Cell> |
|||
</CellGroup> |
|||
))} |
|||
</> |
|||
</InfiniteLoading> |
|||
)} |
|||
</View> |
|||
</PullToRefresh> |
|||
|
|||
{/* 底部浮动按钮 */} |
|||
<FixedButton |
|||
text="发布文章" |
|||
icon={<Edit />} |
|||
onClick={() => Taro.navigateTo({url: '/shop/shopArticle/add'})} |
|||
/> |
|||
</ConfigProvider> |
|||
); |
|||
|
|||
}; |
|||
|
|||
export default Address; |
|||
export default ShopArticleManage; |
|||
|
Loading…
Reference in new issue