feat(add): 新增多页面新增和编辑表单功能

- 添加编辑和新增收货地址页面,支持表单数据加载和提交
- 新增应用密钥凭证、新增应用操作动态、新增应用成员、新增应用版本页面配置
- 实现文章新增及编辑页面,包含图片上传及多种文章属性配置
- 增加注册会员页面,支持头像上传、手机号获取和邀请人关系处理
- 引入统一表单提交成功和失败处理,支持编辑模式数据回显
- 配置统一eslint和editorconfig规则,增强代码规范和编辑体验
- 新增.gitignore规则,屏蔽无关文件和目录,优化版本管理
This commit is contained in:
2026-04-11 12:22:29 +08:00
commit 07f5c92f4b
627 changed files with 85725 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
import {useState, useCallback, useEffect} from 'react'
import {View, Text} from '@tarojs/components'
import Taro from '@tarojs/taro'
import {Loading, InfiniteLoading, Empty, Avatar, Badge} from '@nutui/nutui-react-taro'
import FixedButton from "@/components/FixedButton";
import {ShopChatMessage} from "@/api/shop/shopChatMessage/model";
import {pageShopChatMessage} from "@/api/shop/shopChatMessage";
import navTo from "@/utils/common";
const MessageIndex = () => {
const [list, setList] = useState<ShopChatMessage[]>([])
const [loading, setLoading] = useState<boolean>(false)
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
// 获取消息数据
const fetchMessageData = useCallback(async (resetPage = false, targetPage?: number, searchKeyword?: string) => {
setLoading(true);
try {
const currentPage = resetPage ? 1 : (targetPage || page);
// 构建API参数根据状态筛选
const params: any = {
type: 'text',
page: currentPage,
toUserId: Taro.getStorageSync('UserId')
};
// 添加搜索关键词
if (searchKeyword && searchKeyword.trim()) {
params.keywords = searchKeyword.trim();
}
const res = await pageShopChatMessage(params);
if (res?.list && res.list.length > 0) {
// 正确映射状态
const mappedList = res.list.map(customer => ({
...customer
}));
// 如果是重置页面或第一页,直接设置新数据;否则追加数据
if (resetPage || currentPage === 1) {
setList(mappedList);
} else {
setList(prevList => prevList.concat(mappedList));
}
// 正确判断是否还有更多数据
const hasMoreData = res.list.length >= 10; // 假设每页10条数据
setHasMore(hasMoreData);
} else {
if (resetPage || currentPage === 1) {
setList([]);
}
setHasMore(false);
}
setPage(currentPage);
} catch (error) {
console.error('获取消息数据失败:', error);
Taro.showToast({
title: '加载失败,请重试',
icon: 'none'
});
} finally {
setLoading(false);
}
}, [page]);
const reloadMore = async () => {
if (loading || !hasMore) return; // 防止重复加载
const nextPage = page + 1;
await fetchMessageData(false, nextPage);
}
// 获取列表数据(现在使用服务端搜索,不需要消息端过滤)
const getFilteredList = () => {
return list;
};
useEffect(() => {
// 初始化时加载数据
fetchMessageData(true, 1, '');
}, []);
// 渲染消息项
const renderMessageItem = (item: any) => (
<View key={item.userId} className="bg-white rounded-lg p-4 mb-3 shadow-sm">
<View className="flex items-center" onClick={() => navTo(`/user/chat/message/detail?id=${item.id}`,true)}>
<View className="flex-1">
<View className="flex items-center justify-between mb-1">
<View className={'flex w-full'}>
<Badge style={{marginInlineEnd: '10px'}} dot={item.status === 0} top="2" right="4">
<Avatar
size="40"
src={item.formUserAvatar}
/>
</Badge>
<View className="flex flex-col w-full">
<View className="flex items-center w-full justify-between">
<Text className="font-semibold text-gray-800 mr-2">{item.formUserAlias || item.formUserName}</Text>
<Text className="text-xs text-gray-500">
{item.createTime}
</Text>
</View>
<Text className="text-gray-500 mt-2 mr-2">
{item.content}
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
);
// 渲染消息列表
const renderMessageList = () => {
const filteredList = getFilteredList();
return (
<View className="p-4" style={{
height: '90vh',
overflowY: 'auto',
overflowX: 'hidden'
}}>
<InfiniteLoading
target="scroll"
hasMore={hasMore}
onLoadMore={reloadMore}
onScroll={() => {
// 滚动事件处理
}}
onScrollToUpper={() => {
// 滚动到顶部事件处理
}}
loadingText={
<>
...
</>
}
loadMoreText={
filteredList.length === 0 ? (
<Empty
style={{backgroundColor: 'transparent'}}
description={loading ? "加载中..." : "暂无消息数据"}
/>
) : (
<View className={'h-12 flex items-center justify-center'}>
<Text className="text-gray-500 text-sm"></Text>
</View>
)
}
>
{loading && filteredList.length === 0 ? (
<View className="flex items-center justify-center py-8">
<Loading/>
<Text className="text-gray-500 mt-2 ml-2">...</Text>
</View>
) : (
filteredList.map(renderMessageItem)
)}
</InfiniteLoading>
</View>
);
};
return (
<View className="min-h-screen bg-gray-50">
{/* 消息列表 */}
{renderMessageList()}
<FixedButton text={'发送消息'} onClick={() => navTo(`/user/chat/message/add`,true)}/>
</View>
);
};
export default MessageIndex;