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

组件更新,先这样吧
This commit is contained in:
笔记本里的永平
2025-07-23 14:12:07 +08:00
parent 4804bab90a
commit 7c33e8fa62
2 changed files with 114 additions and 256 deletions

View File

@@ -1,9 +1,12 @@
import React, { useState, useEffect } from "react";
import { SearchOutlined, DeleteOutlined } from "@ant-design/icons";
import { Popup, Toast } from "antd-mobile";
import { Popup } from "antd-mobile";
import { Button, Input } from "antd";
import { getFriendList } from "./api";
import style from "./index.module.scss";
import Layout from "@/components/Layout/Layout";
import PopupHeader from "@/components/PopuLayout/header";
import PopupFooter from "@/components/PopuLayout/footer";
// 微信好友接口类型
interface WechatFriend {
@@ -104,35 +107,18 @@ export default function FriendSelection({
params.keyword = keyword.trim();
}
if (enableDeviceFilter) {
if (deviceIds.length === 0) {
setFriends([]);
setTotalFriends(0);
setTotalPages(1);
setLoading(false);
return;
}
params.deviceIds = deviceIds.join(",");
if (enableDeviceFilter && deviceIds.length > 0) {
params.deviceIds = deviceIds;
}
const res = await getFriendList(params);
if (res && Array.isArray(res.list)) {
setFriends(
res.list.map((friend: any) => ({
id: friend.id?.toString() || "",
nickname: friend.nickname || "",
wechatId: friend.wechatId || "",
avatar: friend.avatar || "",
customer: friend.customer || "",
}))
);
setTotalFriends(res.total || 0);
setTotalPages(Math.ceil((res.total || 0) / 20));
const response = await getFriendList(params);
if (response && response.list) {
setFriends(response.list);
setTotalFriends(response.total || 0);
setTotalPages(Math.ceil((response.total || 0) / 20));
}
} catch (error) {
console.error("获取好友列表失败:", error);
Toast.show({ content: "获取好友列表失败", position: "top" });
} finally {
setLoading(false);
}
@@ -140,16 +126,20 @@ export default function FriendSelection({
// 处理好友选择
const handleFriendToggle = (friendId: string) => {
let newIds: string[];
if (selectedFriends.includes(friendId)) {
newIds = selectedFriends.filter((id) => id !== friendId);
} else {
newIds = [...selectedFriends, friendId];
}
onSelect(newIds);
if (readonly) return;
const newSelectedFriends = selectedFriends.includes(friendId)
? selectedFriends.filter((id) => id !== friendId)
: [...selectedFriends, friendId];
onSelect(newSelectedFriends);
// 如果有 onSelectDetail 回调,传递完整的好友对象
if (onSelectDetail) {
const selectedObjs = friends.filter((f) => newIds.includes(f.id));
onSelectDetail(selectedObjs);
const selectedFriendObjs = friends.filter((friend) =>
newSelectedFriends.includes(friend.id)
);
onSelectDetail(selectedFriendObjs);
}
};
@@ -160,29 +150,22 @@ export default function FriendSelection({
};
// 获取已选好友详细信息
const selectedFriendObjs = selectedFriends
.map((id) => friends.find((f) => f.id === id))
.filter(Boolean) as WechatFriend[];
const selectedFriendObjs = friends.filter((friend) =>
selectedFriends.includes(friend.id)
);
// 删除已选好友
const handleRemoveFriend = (id: string) => {
if (readonly) return;
onSelect(selectedFriends.filter((f) => f !== id));
onSelect(selectedFriends.filter((d) => d !== id));
};
// 确认按钮逻辑
// 确认选择
const handleConfirm = () => {
setRealVisible(false);
if (onConfirm) {
onConfirm(selectedFriends, selectedFriendObjs);
}
};
// 清空搜索
const handleClearSearch = () => {
setSearchQuery("");
setCurrentPage(1);
fetchFriends(1, "");
setRealVisible(false);
};
return (
@@ -271,40 +254,30 @@ export default function FriendSelection({
position="bottom"
bodyStyle={{ height: "100vh" }}
>
<div className={style.popupContainer}>
<div className={style.popupHeader}>
<div className={style.popupTitle}></div>
<div className={style.searchWrapper}>
<Input
placeholder="搜索好友"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
disabled={readonly}
prefix={<SearchOutlined />}
allowClear
size="large"
/>
{searchQuery && !readonly && (
<Button
type="text"
icon={<DeleteOutlined />}
size="small"
className={style.clearBtn}
onClick={handleClearSearch}
style={{
color: "#ff4d4f",
border: "none",
background: "none",
minWidth: 24,
height: 24,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
/>
)}
</div>
</div>
<Layout
header={
<PopupHeader
title="选择微信好友"
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
searchPlaceholder="搜索好友"
loading={loading}
onRefresh={() => fetchFriends(currentPage, searchQuery)}
/>
}
footer={
<PopupFooter
total={totalFriends}
currentPage={currentPage}
totalPages={totalPages}
loading={loading}
selectedCount={selectedFriends.length}
onPageChange={setCurrentPage}
onCancel={() => setRealVisible(false)}
onConfirm={handleConfirm}
/>
}
>
<div className={style.friendList}>
{loading ? (
<div className={style.loadingBox}>
@@ -372,50 +345,7 @@ export default function FriendSelection({
</div>
)}
</div>
{/* 分页栏 */}
<div className={style.paginationRow}>
<div className={style.totalCount}> {totalFriends} </div>
<div className={style.paginationControls}>
<Button
type="text"
size="small"
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
disabled={currentPage === 1 || loading}
className={style.pageBtn}
style={{ borderRadius: 16 }}
>
&lt;
</Button>
<span className={style.pageInfo}>
{currentPage} / {totalPages}
</span>
<Button
type="text"
size="small"
onClick={() =>
setCurrentPage(Math.min(totalPages, currentPage + 1))
}
disabled={currentPage === totalPages || loading}
className={style.pageBtn}
style={{ borderRadius: 16 }}
>
&gt;
</Button>
</div>
</div>
{/* 底部按钮栏 */}
<div className={style.popupFooter}>
<div className={style.selectedCount}>
{selectedFriends.length}
</div>
<div className={style.footerBtnGroup}>
<Button onClick={() => setRealVisible(false)}></Button>
<Button type="primary" onClick={handleConfirm}>
</Button>
</div>
</div>
</div>
</Layout>
</Popup>
</>
);

View File

@@ -1,15 +1,12 @@
import React, { useState, useEffect } from "react";
import {
SearchOutlined,
CloseOutlined,
ArrowLeftOutlined,
ArrowRightOutlined,
DeleteOutlined,
} from "@ant-design/icons";
import { SearchOutlined, DeleteOutlined } from "@ant-design/icons";
import { Button, Input } from "antd";
import { Popup, Toast } from "antd-mobile";
import { Popup } from "antd-mobile";
import { getGroupList } from "./api";
import style from "./index.module.scss";
import Layout from "@/components/Layout/Layout";
import PopupHeader from "@/components/PopuLayout/header";
import PopupFooter from "@/components/PopuLayout/footer";
// 群组接口类型
interface WechatGroup {
@@ -61,9 +58,9 @@ export default function GroupSelection({
const [loading, setLoading] = useState(false);
// 获取已选群聊详细信息
const selectedGroupObjs = selectedGroups
.map((id) => groups.find((g) => g.id === id))
.filter(Boolean) as WechatGroup[];
const selectedGroupObjs = groups.filter((group) =>
selectedGroups.includes(group.id)
);
// 删除已选群聊
const handleRemoveGroup = (id: string) => {
@@ -101,58 +98,52 @@ export default function GroupSelection({
setCurrentPage(1);
fetchGroups(1, searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, realVisible]);
// 获取群列表API - 支持keyword
// 获取群列表API
const fetchGroups = async (page: number, keyword: string = "") => {
setLoading(true);
try {
const params: any = {
let params: any = {
page,
limit: 20,
};
if (keyword.trim()) {
params.keyword = keyword.trim();
}
const res = await getGroupList(params);
if (res && Array.isArray(res.list)) {
setGroups(
res.list.map((group: any) => ({
id: group.id?.toString() || "",
chatroomId: group.chatroomId || "",
name: group.name || "",
avatar: group.avatar || "",
ownerWechatId: group.ownerWechatId || "",
ownerNickname: group.ownerNickname || "",
ownerAvatar: group.ownerAvatar || "",
}))
);
setTotalGroups(res.total || 0);
setTotalPages(Math.ceil((res.total || 0) / 20));
const response = await getGroupList(params);
if (response && response.list) {
setGroups(response.list);
setTotalGroups(response.total || 0);
setTotalPages(Math.ceil((response.total || 0) / 20));
}
} catch (error) {
console.error("获取群列表失败:", error);
Toast.show({ content: "获取群组列表失败", position: "top" });
console.error("获取群列表失败:", error);
} finally {
setLoading(false);
}
};
// 处理群选择
// 处理群选择
const handleGroupToggle = (groupId: string) => {
let newIds: string[];
if (selectedGroups.includes(groupId)) {
newIds = selectedGroups.filter((id) => id !== groupId);
} else {
newIds = [...selectedGroups, groupId];
}
onSelect(newIds);
if (readonly) return;
const newSelectedGroups = selectedGroups.includes(groupId)
? selectedGroups.filter((id) => id !== groupId)
: [...selectedGroups, groupId];
onSelect(newSelectedGroups);
// 如果有 onSelectDetail 回调,传递完整的群聊对象
if (onSelectDetail) {
const selectedObjs = groups.filter((g) => newIds.includes(g.id));
onSelectDetail(selectedObjs);
const selectedGroupObjs = groups.filter((group) =>
newSelectedGroups.includes(group.id)
);
onSelectDetail(selectedGroupObjs);
}
};
@@ -162,19 +153,12 @@ export default function GroupSelection({
return `已选择 ${selectedGroups.length} 个群聊`;
};
// 确认按钮逻辑
// 确认选择
const handleConfirm = () => {
setRealVisible(false);
if (onConfirm) {
onConfirm(selectedGroups, selectedGroupObjs);
}
};
// 清空搜索
const handleClearSearch = () => {
setSearchQuery("");
setCurrentPage(1);
fetchGroups(1, "");
setRealVisible(false);
};
return (
@@ -263,41 +247,30 @@ export default function GroupSelection({
position="bottom"
bodyStyle={{ height: "100vh" }}
>
<div className={style.popupContainer}>
<div className={style.popupHeader}>
<div className={style.popupTitle}></div>
<div className={style.searchWrapper}>
<Input
placeholder="搜索群聊"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
disabled={readonly}
prefix={<SearchOutlined />}
allowClear
size="large"
/>
<SearchOutlined className={style.searchIcon} />
{searchQuery && !readonly && (
<Button
type="text"
icon={<CloseOutlined />}
size="small"
className={style.clearBtn}
onClick={handleClearSearch}
style={{
color: "#ff4d4f",
border: "none",
background: "none",
minWidth: 24,
height: 24,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
/>
)}
</div>
</div>
<Layout
header={
<PopupHeader
title="选择群聊"
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
searchPlaceholder="搜索群聊"
loading={loading}
onRefresh={() => fetchGroups(currentPage, searchQuery)}
/>
}
footer={
<PopupFooter
total={totalGroups}
currentPage={currentPage}
totalPages={totalPages}
loading={loading}
selectedCount={selectedGroups.length}
onPageChange={setCurrentPage}
onCancel={() => setRealVisible(false)}
onConfirm={handleConfirm}
/>
}
>
<div className={style.groupList}>
{loading ? (
<div className={style.loadingBox}>
@@ -361,52 +334,7 @@ export default function GroupSelection({
</div>
)}
</div>
{/* 分页栏 */}
<div className={style.paginationRow}>
<div className={style.totalCount}> {totalGroups} </div>
<div className={style.paginationControls}>
<Button
type="text"
size="small"
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
disabled={currentPage === 1 || loading}
className={style.pageBtn}
style={{ borderRadius: 16 }}
>
<ArrowLeftOutlined />
</Button>
<span className={style.pageInfo}>
{currentPage} / {totalPages}
</span>
<Button
type="text"
size="small"
onClick={() =>
setCurrentPage(Math.min(totalPages, currentPage + 1))
}
disabled={currentPage === totalPages || loading}
className={style.pageBtn}
style={{ borderRadius: 16 }}
>
<ArrowRightOutlined />
</Button>
</div>
</div>
{/* 底部按钮栏 */}
<div className={style.popupFooter}>
<div className={style.selectedCount}>
{selectedGroups.length}
</div>
<div className={style.footerBtnGroup}>
<Button type="default" onClick={() => setRealVisible(false)}>
</Button>
<Button type="primary" onClick={handleConfirm}>
</Button>
</div>
</div>
</div>
</Layout>
</Popup>
</>
);