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