feat: 本次提交更新内容如下

选择栏做了修改
This commit is contained in:
2025-07-17 09:53:34 +08:00
parent 84e0ed3393
commit 42ba2590f7
3 changed files with 116 additions and 65 deletions

View File

@@ -3,12 +3,7 @@ import { Search, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { get } from "@/api/request";
// 微信好友接口类型
@@ -38,11 +33,12 @@ interface FriendsResponse {
};
}
// 获取好友列表API函数
// 获取好友列表API函数 - 添加 keyword 参数
const fetchFriendsList = async (params: {
page: number;
limit: number;
deviceIds?: string[];
keyword?: string;
}): Promise<FriendsResponse> => {
if (params.deviceIds && params.deviceIds.length === 0) {
return {
@@ -58,8 +54,12 @@ const fetchFriendsList = async (params: {
}
const deviceIdsParam = params?.deviceIds?.join(",") || "";
const keywordParam = params?.keyword
? `&keyword=${encodeURIComponent(params.keyword)}`
: "";
return get<FriendsResponse>(
`/v1/friend?page=${params.page}&limit=${params.limit}&deviceIds=${deviceIdsParam}`
`/v1/friend?page=${params.page}&limit=${params.limit}&deviceIds=${deviceIdsParam}${keywordParam}`
);
};
@@ -94,20 +94,33 @@ export default function FriendSelection({
// 打开弹窗并请求第一页好友
const openDialog = () => {
setCurrentPage(1);
setSearchQuery(""); // 重置搜索关键词
setDialogOpen(true);
fetchFriends(1);
fetchFriends(1, "");
};
// 当页码变化时,拉取对应页数据(弹窗已打开时)
useEffect(() => {
if (dialogOpen && currentPage !== 1) {
fetchFriends(currentPage);
fetchFriends(currentPage, searchQuery);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentPage]);
// 获取好友列表API
const fetchFriends = async (page: number) => {
// 搜索防抖
useEffect(() => {
if (!dialogOpen) return;
const timer = setTimeout(() => {
setCurrentPage(1); // 重置到第一页
fetchFriends(1, searchQuery);
}, 500); // 500 防抖
return () => clearTimeout(timer);
}, [searchQuery, dialogOpen]);
// 获取好友列表API - 添加 keyword 参数
const fetchFriends = async (page: number, keyword: string = "") => {
setLoading(true);
try {
let res;
@@ -119,9 +132,18 @@ export default function FriendSelection({
setLoading(false);
return;
}
res = await fetchFriendsList({ page, limit: 20, deviceIds: deviceIds });
res = await fetchFriendsList({
page,
limit: 20,
deviceIds: deviceIds,
keyword: keyword.trim() || undefined,
});
} else {
res = await fetchFriendsList({ page, limit: 20 });
res = await fetchFriendsList({
page,
limit: 20,
keyword: keyword.trim() || undefined,
});
}
if (res && res.code === 200 && res.data) {
@@ -144,13 +166,6 @@ export default function FriendSelection({
}
};
// 过滤好友
const filteredFriends = friends.filter(
(friend) =>
friend.nickname.toLowerCase().includes(searchQuery.toLowerCase()) ||
friend.wechatId.toLowerCase().includes(searchQuery.toLowerCase())
);
// 处理好友选择
const handleFriendToggle = (friendId: string) => {
let newIds: string[];
@@ -176,6 +191,13 @@ export default function FriendSelection({
setDialogOpen(false);
};
// 清空搜索
const handleClearSearch = () => {
setSearchQuery("");
setCurrentPage(1);
fetchFriends(1, "");
};
return (
<>
{/* 输入框 */}
@@ -221,25 +243,27 @@ export default function FriendSelection({
className="pl-10 py-2 rounded-full border-gray-200"
/>
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
<Button
variant="ghost"
size="icon"
className="absolute right-2 top-1/2 -translate-y-1/2 h-6 w-6 rounded-full"
onClick={() => setSearchQuery("")}
>
<X className="h-4 w-4" />
</Button>
{searchQuery && (
<Button
variant="ghost"
size="icon"
className="absolute right-2 top-1/2 -translate-y-1/2 h-6 w-6 rounded-full"
onClick={handleClearSearch}
>
<X className="h-4 w-4" />
</Button>
)}
</div>
</div>
<ScrollArea className="flex-1 overflow-y-auto">
<div className="flex-1 overflow-y-auto h-[50vh]">
{loading ? (
<div className="flex items-center justify-center h-full">
<div className="text-gray-500">...</div>
</div>
) : filteredFriends.length > 0 ? (
) : friends.length > 0 ? (
<div className="divide-y">
{filteredFriends.map((friend) => (
{friends.map((friend) => (
<label
key={friend.id}
className="flex items-center px-6 py-4 hover:bg-gray-50 cursor-pointer"
@@ -288,11 +312,15 @@ export default function FriendSelection({
) : (
<div className="flex items-center justify-center h-full">
<div className="text-gray-500">
{deviceIds.length === 0 ? "请先选择设备" : "没有找到好友"}
{deviceIds.length === 0
? "请先选择设备"
: searchQuery
? `没有找到包含"${searchQuery}"的好友`
: "没有找到好友"}
</div>
</div>
)}
</ScrollArea>
</div>
<div className="border-t p-4 flex items-center justify-between bg-white">
<div className="text-sm text-gray-500">

View File

@@ -36,12 +36,17 @@ interface GroupsResponse {
};
}
// 修改支持keyword参数
const fetchGroupsList = async (params: {
page: number;
limit: number;
keyword?: string;
}): Promise<GroupsResponse> => {
const keywordParam = params.keyword
? `&keyword=${encodeURIComponent(params.keyword)}`
: "";
return get<GroupsResponse>(
`/v1/chatroom?page=${params.page}&limit=${params.limit}`
`/v1/chatroom?page=${params.page}&limit=${params.limit}${keywordParam}`
);
};
@@ -71,23 +76,38 @@ export default function GroupSelection({
// 打开弹窗并请求第一页群组
const openDialog = () => {
setCurrentPage(1);
setSearchQuery(""); // 重置搜索关键词
setDialogOpen(true);
fetchGroups(1);
fetchGroups(1, "");
};
// 当页码变化时,拉取对应页数据(弹窗已打开时)
useEffect(() => {
if (dialogOpen && currentPage !== 1) {
fetchGroups(currentPage);
fetchGroups(currentPage, searchQuery);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentPage]);
// 获取群组列表API
const fetchGroups = async (page: number) => {
// 搜索防抖
useEffect(() => {
if (!dialogOpen) return;
const timer = setTimeout(() => {
setCurrentPage(1);
fetchGroups(1, searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, dialogOpen]);
// 获取群组列表API - 支持keyword
const fetchGroups = async (page: number, keyword: string = "") => {
setLoading(true);
try {
const res = await fetchGroupsList({ page, limit: 20 });
const res = await fetchGroupsList({
page,
limit: 20,
keyword: keyword.trim() || undefined,
});
if (res && res.code === 200 && res.data) {
setGroups(
res.data.list.map((group) => ({
@@ -110,13 +130,6 @@ export default function GroupSelection({
}
};
// 过滤群组
const filteredGroups = groups.filter(
(group) =>
group.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
group.chatroomId.toLowerCase().includes(searchQuery.toLowerCase())
);
// 处理群组选择
const handleGroupToggle = (groupId: string) => {
let newIds: string[];
@@ -142,6 +155,13 @@ export default function GroupSelection({
setDialogOpen(false);
};
// 清空搜索
const handleClearSearch = () => {
setSearchQuery("");
setCurrentPage(1);
fetchGroups(1, "");
};
return (
<>
{/* 输入框 */}
@@ -186,25 +206,27 @@ export default function GroupSelection({
className="pl-10 py-2 rounded-full border-gray-200"
/>
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
<Button
variant="ghost"
size="icon"
className="absolute right-2 top-1/2 -translate-y-1/2 h-6 w-6 rounded-full"
onClick={() => setSearchQuery("")}
>
<X className="h-4 w-4" />
</Button>
{searchQuery && (
<Button
variant="ghost"
size="icon"
className="absolute right-2 top-1/2 -translate-y-1/2 h-6 w-6 rounded-full"
onClick={handleClearSearch}
>
<X className="h-4 w-4" />
</Button>
)}
</div>
</div>
<ScrollArea className="flex-1 overflow-y-auto">
<div className="flex-1 overflow-y-auto h-[50vh]">
{loading ? (
<div className="flex items-center justify-center h-full">
<div className="text-gray-500">...</div>
</div>
) : filteredGroups.length > 0 ? (
) : groups.length > 0 ? (
<div className="divide-y">
{filteredGroups.map((group) => (
{groups.map((group) => (
<label
key={group.id}
className="flex items-center px-6 py-4 hover:bg-gray-50 cursor-pointer"
@@ -252,14 +274,19 @@ export default function GroupSelection({
</div>
) : (
<div className="flex items-center justify-center h-full">
<div className="text-gray-500"></div>
<div className="text-gray-500">
{searchQuery
? `没有找到包含"${searchQuery}"的群聊`
: "没有找到群聊"}
</div>
</div>
)}
</ScrollArea>
</div>
<div className="border-t p-4 flex items-center justify-between bg-white">
<div className="text-sm text-gray-500">
{totalGroups}
{searchQuery && ` (搜索: "${searchQuery}")`}
</div>
<div className="flex items-center space-x-2">
<Button

View File

@@ -215,11 +215,7 @@ export default function NewPlan() {
<header className="sticky top-0 z-10 bg-white border-b">
<div className="flex items-center justify-between h-14 px-4">
<div className="flex items-center">
<Button
variant="ghost"
size="icon"
onClick={() => router("/scenarios")}
>
<Button variant="ghost" size="icon" onClick={() => router(-1)}>
<ChevronLeft className="h-5 w-5" />
</Button>
</div>