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 {useState} from "react"; |
||||
import Taro, {useDidShow} from '@tarojs/taro' |
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 {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)) |
|
||||
}) |
|
||||
.catch(() => { |
|
||||
Taro.showToast({ |
|
||||
title: '获取地址失败', |
|
||||
icon: 'error' |
|
||||
}); |
|
||||
}) |
|
||||
} |
|
||||
|
const reload = async (isRefresh = false) => { |
||||
|
if (isRefresh) { |
||||
|
setPage(1) |
||||
|
setList([]) |
||||
|
setHasMore(true) |
||||
|
} |
||||
|
|
||||
const onDefault = async (item: ShopUserAddress) => { |
|
||||
if (address) { |
|
||||
await updateShopUserAddress({ |
|
||||
...address, |
|
||||
isDefault: false |
|
||||
|
setLoading(true) |
||||
|
try { |
||||
|
const currentPage = isRefresh ? 1 : page |
||||
|
const res = await pageShopArticle({ |
||||
|
page: currentPage, |
||||
|
limit: 10, |
||||
|
keywords: searchValue |
||||
}) |
}) |
||||
|
|
||||
|
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: '获取文章失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} finally { |
||||
|
setLoading(false) |
||||
} |
} |
||||
await updateShopUserAddress({ |
|
||||
id: item.id, |
|
||||
isDefault: true |
|
||||
}) |
|
||||
Taro.showToast({ |
|
||||
title: '设置成功', |
|
||||
icon: 'success' |
|
||||
|
} |
||||
|
|
||||
|
// 搜索功能
|
||||
|
const handleSearch = (value: string) => { |
||||
|
setSearchValue(value) |
||||
|
reload(true) |
||||
|
} |
||||
|
|
||||
|
// 下拉刷新
|
||||
|
const handleRefresh = async () => { |
||||
|
setRefreshing(true) |
||||
|
await reload(true) |
||||
|
setRefreshing(false) |
||||
|
} |
||||
|
|
||||
|
// 删除文章
|
||||
|
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(true); |
||||
|
} catch (error) { |
||||
|
Taro.showToast({ |
||||
|
title: '删除失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
}); |
}); |
||||
reload(); |
|
||||
} |
} |
||||
|
|
||||
const onDel = async (id?: number) => { |
|
||||
await removeShopUserAddress(id) |
|
||||
Taro.showToast({ |
|
||||
title: '删除成功', |
|
||||
icon: 'success' |
|
||||
|
// 编辑文章
|
||||
|
const handleEdit = (item: ShopArticle) => { |
||||
|
Taro.navigateTo({ |
||||
|
url: `/shop/shopArticle/add?id=${item.articleId}` |
||||
}); |
}); |
||||
reload(); |
|
||||
} |
} |
||||
|
|
||||
const selectAddress = async (item: ShopUserAddress) => { |
|
||||
if (address) { |
|
||||
await updateShopUserAddress({ |
|
||||
...address, |
|
||||
isDefault: false |
|
||||
}) |
|
||||
} |
|
||||
await updateShopUserAddress({ |
|
||||
id: item.id, |
|
||||
isDefault: true |
|
||||
|
// 查看文章详情
|
||||
|
const handleView = (item: ShopArticle) => { |
||||
|
// 这里可以跳转到文章详情页面
|
||||
|
Taro.navigateTo({ |
||||
|
url: `/cms/detail/index?id=${item.articleId}` |
||||
}) |
}) |
||||
setTimeout(() => { |
|
||||
Taro.navigateBack() |
|
||||
},500) |
|
||||
} |
} |
||||
|
|
||||
useDidShow(() => { |
|
||||
reload() |
|
||||
}); |
|
||||
|
// 获取状态标签
|
||||
|
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> |
||||
|
} |
||||
|
} |
||||
|
|
||||
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="您还没有地址哦" |
|
||||
/> |
|
||||
<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> |
|
||||
) |
|
||||
|
// 加载更多
|
||||
|
const loadMore = async () => { |
||||
|
if (!loading && hasMore) { |
||||
|
await reload(false) // 不刷新,追加数据
|
||||
|
} |
||||
} |
} |
||||
|
|
||||
|
useDidShow(() => { |
||||
|
reload(true).then() |
||||
|
}); |
||||
|
|
||||
return ( |
return ( |
||||
<> |
|
||||
<CellGroup> |
|
||||
<Cell |
|
||||
onClick={() => Taro.navigateTo({url: '/user/address/wxAddress'})} |
|
||||
> |
|
||||
<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> |
|
||||
<View className={'text-xs'}> |
|
||||
{item.province} {item.city} {item.region} {item.address} |
|
||||
</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> |
|
||||
|
<ConfigProvider> |
||||
|
{/* 搜索栏 */} |
||||
|
<View className="py-2"> |
||||
|
<SearchBar |
||||
|
placeholder="搜索关键词" |
||||
|
value={searchValue} |
||||
|
onChange={setSearchValue} |
||||
|
onSearch={handleSearch} |
||||
|
/> |
||||
|
</View> |
||||
|
|
||||
|
{/* 统计信息 */} |
||||
|
{total > 0 && ( |
||||
|
<View className="px-4 py-2 text-sm text-gray-500"> |
||||
|
共找到 {total} 篇文章 |
||||
|
</View> |
||||
|
)} |
||||
|
|
||||
|
{/* 文章列表 */} |
||||
|
<PullToRefresh |
||||
|
onRefresh={handleRefresh} |
||||
|
pullDistance={60} |
||||
|
headHeight={60} |
||||
|
> |
||||
|
<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> |
||||
|
) : ( |
||||
|
<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> |
</View> |
||||
} |
} |
||||
extra={ |
|
||||
<> |
|
||||
<View className={'text-gray-400'} onClick={() => onDel(item.id)}> |
|
||||
删除 |
|
||||
</View> |
|
||||
<Divider direction={'vertical'}/> |
|
||||
<View className={'text-gray-400'} |
|
||||
onClick={() => Taro.navigateTo({url: '/user/address/add?id=' + item.id})}> |
|
||||
修改 |
|
||||
</View> |
|
||||
</> |
|
||||
|
loadMoreText={ |
||||
|
<View className="text-center py-4 text-gray-500"> |
||||
|
{list.length === 0 ? "暂无数据" : "没有更多了"} |
||||
|
</View> |
||||
} |
} |
||||
/> |
|
||||
</Cell.Group> |
|
||||
))} |
|
||||
</> |
|
||||
|
> |
||||
|
{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> |
||||
|
</View> |
||||
|
</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