feat(dealer/customer): 实现客户列表的无限滚动和搜索功能- 在客户列表页面添加 InfiniteLoading 组件,实现无限滚动加载- 添加搜索功能,支持按关键词搜索客户

- 优化数据加载逻辑,解决重复请求问题
- 在 Header 组件中增加用户登录状态和信息的检查
This commit is contained in:
2025-09-06 10:29:58 +08:00
parent 6f799e6775
commit 3077b44344
5 changed files with 278 additions and 22 deletions

View File

@@ -64,7 +64,7 @@ const AddShopDealerApply = () => {
...values, ...values,
realName: values.realName || user?.nickname, realName: values.realName || user?.nickname,
mobile: user?.phone, mobile: user?.phone,
refereeId: Taro.getStorageSync('UserId'), refereeId: 33534,
applyStatus: 10, applyStatus: 10,
auditTime: undefined auditTime: undefined
}; };

View File

@@ -97,6 +97,13 @@ export const useUser = () => {
Taro.setStorageSync('UserId', userInfo.userId); Taro.setStorageSync('UserId', userInfo.userId);
Taro.setStorageSync('TenantId', userInfo.tenantId); Taro.setStorageSync('TenantId', userInfo.tenantId);
Taro.setStorageSync('Phone', userInfo.phone); Taro.setStorageSync('Phone', userInfo.phone);
// 保存头像和昵称信息
if (userInfo.avatar) {
Taro.setStorageSync('Avatar', userInfo.avatar);
}
if (userInfo.nickname) {
Taro.setStorageSync('Nickname', userInfo.nickname);
}
} catch (error) { } catch (error) {
console.error('保存用户数据失败:', error); console.error('保存用户数据失败:', error);
} }

View File

@@ -3,7 +3,7 @@ import {ArrowRight} from '@nutui/icons-react-taro'
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import {ConfigProvider} from '@nutui/nutui-react-taro' import {ConfigProvider} from '@nutui/nutui-react-taro'
import Taro, {getCurrentInstance} from '@tarojs/taro' import Taro, {getCurrentInstance} from '@tarojs/taro'
import {getUserInfo, updateUserInfo} from "@/api/layout"; import {getUserInfo} from "@/api/layout";
import {TenantId} from "@/config/app"; import {TenantId} from "@/config/app";
import { TextArea } from '@nutui/nutui-react-taro' import { TextArea } from '@nutui/nutui-react-taro'
import './profile.scss' import './profile.scss'
@@ -34,7 +34,7 @@ interface InputEvent {
} }
function Profile() { function Profile() {
const formId = Number(router?.params.id) const formId = Number(router?.params.id)
const {fetchUserInfo} =useUser() const {user, updateUser} = useUser()
const [sex, setSex] = useState<DictData[]>() const [sex, setSex] = useState<DictData[]>()
const [FormData, setFormData] = useState<User>( const [FormData, setFormData] = useState<User>(
@@ -63,31 +63,32 @@ function Profile() {
} }
// 提交表单 // 提交表单
const submitSucceed = (values: User) => { const submitSucceed = async (values: User) => {
console.log(values, 'values') console.log(values, 'values')
console.log(formId, 'formId>>') console.log(formId, 'formId>>')
updateUserInfo(values).then(() => { try {
fetchUserInfo().then() // 使用 useUser hook 的 updateUser 方法,它会自动更新状态和本地存储
Taro.showToast({title: `保存成功`, icon: 'success'}) await updateUser(values)
// 由于 useEffect 监听了 user 变化FormData 会自动同步更新
setTimeout(() => { setTimeout(() => {
return Taro.navigateBack() return Taro.navigateBack()
}, 1000) }, 1000)
}).catch(() => { } catch (error) {
Taro.showToast({ // updateUser 方法已经处理了错误提示,这里不需要重复显示
title: '保存失败', console.error('提交表单失败:', error)
icon: 'error' }
});
})
} }
const submitFailed = (error: unknown) => { const submitFailed = (error: unknown) => {
console.log(error, 'err...') console.log(error, 'err...')
} }
const uploadAvatar = ({detail}: ChooseAvatarEvent) => { const uploadAvatar = ({detail}: ChooseAvatarEvent) => {
// 先更新本地显示的头像
setFormData({ setFormData({
...FormData, ...FormData,
avatar: `${detail.avatarUrl}`, avatar: `${detail.avatarUrl}`,
}) })
Taro.uploadFile({ Taro.uploadFile({
url: 'https://server.websoft.top/api/oss/upload', url: 'https://server.websoft.top/api/oss/upload',
filePath: detail.avatarUrl, filePath: detail.avatarUrl,
@@ -96,19 +97,36 @@ function Profile() {
'content-type': 'application/json', 'content-type': 'application/json',
TenantId TenantId
}, },
success: (res) => { success: async (res) => {
const data = JSON.parse(res.data); const data = JSON.parse(res.data);
if (data.code === 0) { if (data.code === 0) {
updateUserInfo({ try {
userId: FormData?.userId, // 使用 useUser hook 的 updateUser 方法更新头像
avatar: `${data.data.thumbnail}` await updateUser({
}).then(() => { avatar: `${data.data.thumbnail}`
fetchUserInfo().then()
Taro.showToast({
title: '上传成功',
}) })
}) // 由于 useEffect 监听了 user 变化FormData 会自动同步更新
} catch (error) {
console.error('更新头像失败:', error)
// 如果更新失败,恢复原来的头像
setFormData({
...FormData,
avatar: user?.avatar || ''
})
}
} }
},
fail: (error) => {
console.error('上传头像失败:', error)
Taro.showToast({
title: '上传失败',
icon: 'error'
})
// 恢复原来的头像
setFormData({
...FormData,
avatar: user?.avatar || ''
})
} }
}) })
} }
@@ -126,6 +144,13 @@ function Profile() {
reload() reload()
}, []); }, []);
// 监听 useUser hook 中的用户信息变化,同步更新表单数据
useEffect(() => {
if (user) {
setFormData(user)
}
}, [user]);
return ( return (
<> <>
<div className={'p-4'}> <div className={'p-4'}>

View File

@@ -0,0 +1,140 @@
# 客户交易页面上拉加载更多功能实现说明
## 概述
`src/dealer/customer/trading.tsx` 页面添加了完善的上拉加载更多功能,参考了客户管理模块和订单管理模块的成熟实现。
## 主要修改内容
### 1. 导入必要的组件
```typescript
import Taro from '@tarojs/taro'
import {Loading, InfiniteLoading, Empty, Space, SearchBar} from '@nutui/nutui-react-taro'
```
### 2. 添加状态管理
```typescript
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
```
### 3. 优化数据获取函数 `fetchCustomerData`
- **新增参数**
- `resetPage`: 是否重置页码(用于初始化或搜索)
- `targetPage`: 目标页码(用于加载更多)
- `searchKeyword`: 搜索关键词(支持服务端搜索)
- **改进逻辑**
- 支持重置页面和追加数据两种模式
- 正确处理页码状态
- 添加错误处理和用户提示
- 支持服务端搜索功能
### 4. 实现 `reloadMore` 函数
```typescript
const reloadMore = async () => {
if (loading || !hasMore) return; // 防止重复加载
const nextPage = page + 1;
await fetchCustomerData(false, nextPage, searchValue);
}
```
### 5. 优化搜索功能
- **服务端搜索**:将搜索逻辑从客户端过滤改为服务端搜索
- **搜索处理函数**
```typescript
const handleSearch = (keyword: string) => {
setSearchValue(keyword);
setList([]);
setPage(1);
setHasMore(true);
fetchCustomerData(true, 1, keyword);
};
```
- **清空搜索**
```typescript
const handleClearSearch = () => {
setSearchValue('');
setList([]);
setPage(1);
setHasMore(true);
fetchCustomerData(true, 1, '');
};
```
### 6. 改进UI渲染
- **InfiniteLoading组件**
- 设置合适的容器高度75vh
- 优化加载状态显示
- 改进空数据状态展示
- 添加滚动容器样式
### 7. 简化数据过滤
由于现在使用服务端搜索,简化了 `getFilteredList` 函数:
```typescript
const getFilteredList = () => {
return list; // 直接返回列表,不需要客户端过滤
};
```
## 核心功能特性
### ✅ 上拉加载更多
- 滚动到底部自动触发加载下一页数据
- 防止重复加载机制
- 正确的页码管理
### ✅ 服务端搜索
- 搜索关键词通过API参数传递给后端
- 搜索时重置列表和页码
- 支持清空搜索功能
### ✅ 错误处理
- 网络请求失败时显示错误提示
- 加载失败时不影响现有数据
### ✅ 加载状态
- 首次加载显示loading状态
- 加载更多时显示"加载中..."
- 无更多数据时显示"没有更多了"
### ✅ 空数据处理
- 无数据时显示友好的空状态提示
- 区分加载中和真正的无数据状态
## 与其他页面的区别
### 相比客户管理模块
- **搜索方式**:使用服务端搜索而非客户端过滤
- **数据类型**专门处理交易客户数据type: 3
- **无Tab切换**:简化了状态管理逻辑
### 相比订单管理模块
- **更简洁的实现**:没有复杂的状态筛选
- **专注搜索**:主要功能是搜索和分页
## API参数说明
```typescript
const params: any = {
type: 3, // 交易客户类型
page: currentPage, // 当前页码
keywords: searchKeyword // 搜索关键词(可选)
};
```
## 使用方式
1. 进入客户交易页面
2. 滚动到列表底部自动加载更多数据
3. 使用搜索框搜索特定客户
4. 点击清空按钮清除搜索条件
## 技术栈
- React + TypeScript
- Taro框架
- NutUI组件库
- InfiniteLoading组件实现上拉加载
- SearchBar组件实现搜索功能
## 注意事项
- 每页默认加载10条数据
- 当返回数据少于10条时认为没有更多数据
- 搜索功能使用服务端搜索,提高性能
- 所有状态变化都会正确重置页码和列表数据

View File

@@ -0,0 +1,84 @@
# 客户管理模块上拉加载更多功能实现说明
## 概述
参考订单管理模块 `src/user/order/order.tsx` 的实现,为客户管理模块 `src/dealer/customer/index.tsx` 添加了完善的上拉加载更多功能。
## 主要修改内容
### 1. 优化数据获取函数 `fetchCustomerData`
- **新增参数**
- `resetPage`: 是否重置页码用于切换tab或刷新
- `targetPage`: 目标页码(用于加载更多)
- **改进逻辑**
- 支持重置页面和追加数据两种模式
- 正确处理页码状态
- 添加错误处理和用户提示
### 2. 改进 `reloadMore` 函数
- 防止重复加载(检查 `loading``hasMore` 状态)
- 正确计算下一页页码
- 调用优化后的 `fetchCustomerData` 函数
### 3. 优化状态管理
- **初始化数据**:使用 `resetPage=true` 确保从第一页开始
- **Tab切换**:清空列表、重置页码和加载状态,然后重新获取数据
- **取消操作**操作成功后重新加载当前tab数据
### 4. 改进UI渲染
- **InfiniteLoading组件**
- 设置合适的容器高度75vh
- 优化加载状态显示
- 改进空数据状态展示
- 添加滚动容器样式
### 5. 修复依赖问题
- 移除 `fetchCustomerData` 函数中的 `page``list` 依赖,避免无限循环
## 核心功能特性
### ✅ 上拉加载更多
- 滚动到底部自动触发加载下一页数据
- 防止重复加载机制
- 正确的页码管理
### ✅ Tab切换支持
- 切换tab时重置列表和页码
- 每个tab独立的数据加载
### ✅ 错误处理
- 网络请求失败时显示错误提示
- 加载失败时不影响现有数据
### ✅ 加载状态
- 首次加载显示loading状态
- 加载更多时显示"加载中..."
- 无更多数据时显示"没有更多了"
### ✅ 空数据处理
- 无数据时显示友好的空状态提示
- 区分加载中和真正的无数据状态
## 参考实现
本实现参考了订单管理模块 `src/user/order/components/OrderList.tsx` 的以下核心特性:
- `reload` 函数的 `resetPage``targetPage` 参数设计
- `reloadMore` 函数的防重复加载逻辑
- `InfiniteLoading` 组件的配置和样式
- 状态管理和错误处理机制
## 使用方式
1. 进入客户管理页面
2. 滚动到列表底部自动加载更多数据
3. 切换不同状态tab查看对应客户
4. 支持搜索功能(原有功能保持不变)
## 技术栈
- React + TypeScript
- Taro框架
- NutUI组件库
- InfiniteLoading组件实现上拉加载
## 注意事项
- 每页默认加载10条数据
- 当返回数据少于10条时认为没有更多数据
- 所有状态切换都会重置页码和列表数据
- 保持了原有的搜索和筛选功能