Files
cunkebao_v3/Cunkebao/src/components/PoolSelection/selectionPopup.tsx

214 lines
6.6 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect } from "react";
import { Popup, Checkbox } from "antd-mobile";
import { getPoolPackages, Request } 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";
import { GroupSelectionItem, PoolPackageItem } from "./data";
// 弹窗属性接口
interface SelectionPopupProps {
visible: boolean;
onVisibleChange: (visible: boolean) => void;
selectedOptions: GroupSelectionItem[];
onSelect: (items: GroupSelectionItem[]) => void;
onSelectDetail?: (items: PoolPackageItem[]) => void;
readonly?: boolean;
onConfirm?: (
selectedIds: string[],
selectedItems: GroupSelectionItem[],
) => void;
}
export default function SelectionPopup({
visible,
onVisibleChange,
selectedOptions,
onSelect,
onSelectDetail,
readonly = false,
onConfirm,
}: SelectionPopupProps) {
const [poolPackages, setPoolPackages] = useState<PoolPackageItem[]>([]);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalItems, setTotalItems] = useState(0);
const [loading, setLoading] = useState(false);
// 获取流量池包列表API
const fetchPoolPackages = async (page: number, keyword: string = "") => {
setLoading(true);
try {
const params: Request = {
page: String(page),
limit: "20",
keyword: keyword.trim(),
};
const response = await getPoolPackages(params);
if (response && response.list) {
setPoolPackages(response.list);
setTotalItems(response.total || 0);
setTotalPages(Math.ceil((response.total || 0) / 20));
}
} catch (error) {
console.error("获取流量池包列表失败:", error);
} finally {
setLoading(false);
}
};
// 处理流量池包选择
const handlePackageToggle = (item: PoolPackageItem) => {
if (readonly) return;
// 将PoolPackageItem转换为GroupSelectionItem格式
const selectionItem: GroupSelectionItem = {
id: String(item.id),
name: item.name,
description: item.description,
createTime: item.createTime,
num: item.num,
// 保留原始数据
originalData: item,
};
const newSelectedItems = selectedOptions.some(g => g.id === String(item.id))
? selectedOptions.filter(g => g.id !== String(item.id))
: selectedOptions.concat(selectionItem);
onSelect(newSelectedItems);
// 如果有 onSelectDetail 回调,传递完整的流量池包对象
if (onSelectDetail) {
const selectedItemObjs = poolPackages.filter(packageItem =>
newSelectedItems.some(g => g.id === String(packageItem.id)),
);
onSelectDetail(selectedItemObjs);
}
};
// 确认选择
const handleConfirm = () => {
if (onConfirm) {
onConfirm(
selectedOptions.map(item => item.id),
selectedOptions,
);
}
onVisibleChange(false);
};
// 弹窗打开时初始化数据(只执行一次)
useEffect(() => {
if (visible) {
setCurrentPage(1);
setSearchQuery("");
fetchPoolPackages(1, "");
}
}, [visible]);
// 搜索防抖(只在弹窗打开且搜索词变化时执行)
useEffect(() => {
if (!visible || searchQuery === "") return;
const timer = setTimeout(() => {
setCurrentPage(1);
fetchPoolPackages(1, searchQuery);
}, 500);
return () => clearTimeout(timer);
}, [searchQuery, visible]);
// 页码变化时请求数据只在弹窗打开且页码不是1时执行
useEffect(() => {
if (!visible || currentPage === 1) return;
fetchPoolPackages(currentPage, searchQuery);
}, [currentPage, visible, searchQuery]);
return (
<Popup
visible={visible}
onMaskClick={() => onVisibleChange(false)}
position="bottom"
bodyStyle={{ height: "100vh" }}
>
<Layout
header={
<PopupHeader
title="选择流量池包"
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
searchPlaceholder="搜索流量池包"
loading={loading}
onRefresh={() => fetchPoolPackages(currentPage, searchQuery)}
/>
}
footer={
<PopupFooter
total={totalItems}
currentPage={currentPage}
totalPages={totalPages}
loading={loading}
selectedCount={selectedOptions.length}
onPageChange={setCurrentPage}
onCancel={() => onVisibleChange(false)}
onConfirm={handleConfirm}
/>
}
>
<div className={style.groupList}>
{loading ? (
<div className={style.loadingBox}>
<div className={style.loadingText}>...</div>
</div>
) : poolPackages.length > 0 ? (
<div className={style.groupListInner}>
{poolPackages.map(item => (
<div key={item.id} className={style.groupItem}>
<Checkbox
checked={selectedOptions.some(
g => g.id === String(item.id),
)}
onChange={() => !readonly && handlePackageToggle(item)}
disabled={readonly}
style={{ marginRight: 12 }}
/>
<div className={style.groupInfo}>
2025-08-20 17:33:28 +08:00
<div className={style.groupAvatar}>
{item.name ? item.name.charAt(0) : "?"}
</div>
<div className={style.groupDetail}>
<div className={style.groupName}>{item.name}</div>
<div className={style.groupId}>
: {item.description || "无描述"}
</div>
<div className={style.groupOwner}>
: {item.createTime}
</div>
<div className={style.groupOwner}>
: {item.num}
</div>
</div>
</div>
</div>
))}
</div>
) : (
<div className={style.emptyBox}>
<div className={style.emptyText}>
{searchQuery
? `没有找到包含"${searchQuery}"的流量池包`
: "没有找到流量池包"}
</div>
</div>
)}
</div>
</Layout>
</Popup>
);
}