- 好友数: {device.totalFriend ?? "-"}
+
+ {/* 顶部行:选择框和IMEI */}
+
+
+ {
+ e.stopPropagation();
+ setSelected(prev =>
+ e.target.checked
+ ? [...prev, device.id!]
+ : prev.filter(id => id !== device.id),
+ );
+ }}
+ onClick={e => e.stopPropagation()}
+ />
+
+ IMEI: {device.imei?.toUpperCase()}
+
+
+
+ {/* 主要内容区域:头像和详细信息 */}
+
+ {/* 头像 */}
+
+ {device.avatar ? (
+

+ ) : (
+
+ {(device.memo || device.wechatId || "设")[0]}
+
+ )}
+
+
+ {/* 设备信息 */}
+
+
+
+ {device.memo || "未命名设备"}
+
+
+ {device.status === "online" || device.alive === 1
+ ? "在线"
+ : "离线"}
+
+
+
+
+
+ 微信号:
+
+ {device.wechatId || "未绑定"}
+
+
+
+ 好友数:
+
+ {device.totalFriend ?? "-"}
+
+
+
+
+
+ {/* 箭头图标 */}
+
goDetail(device.id!)}
+ />
-
- {device.status === "online" || device.alive === 1
- ? "在线"
- : "离线"}
-
))}
diff --git a/Cunkebao/src/pages/mobile/mine/main/index.tsx b/Cunkebao/src/pages/mobile/mine/main/index.tsx
index b3d44912..b6fd294f 100644
--- a/Cunkebao/src/pages/mobile/mine/main/index.tsx
+++ b/Cunkebao/src/pages/mobile/mine/main/index.tsx
@@ -64,7 +64,7 @@ const Mine: React.FC = () => {
description: "管理用户流量池和分组",
icon:
,
count: stats.traffic,
- path: "/traffic-pool",
+ path: "/mine/traffic-pool",
bgColor: "#f9f0ff",
iconColor: "#722ed1",
},
diff --git a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx
index b36dedb0..db43fa44 100644
--- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx
+++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx
@@ -1,118 +1,158 @@
-import React from "react";
+import React, { useState, useEffect } from "react";
import { Popup } from "antd-mobile";
import { Select, Button } from "antd";
-import type {
- DeviceOption,
- PackageOption,
- ValueLevel,
- UserStatus,
-} from "./data";
+import DeviceSelection from "@/components/DeviceSelection";
+import type { UserStatus, ScenarioOption } from "./data";
+import { fetchScenarioOptions, fetchPackageOptions } from "./api";
+import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
interface FilterModalProps {
visible: boolean;
onClose: () => void;
- deviceOptions: DeviceOption[];
- packageOptions: PackageOption[];
- deviceId: string;
- setDeviceId: (v: string) => void;
- packageId: string;
- setPackageId: (v: string) => void;
- valueLevel: ValueLevel;
- setValueLevel: (v: ValueLevel) => void;
- userStatus: UserStatus;
- setUserStatus: (v: UserStatus) => void;
- onReset: () => void;
+ onConfirm: (filters: {
+ deviceIds: string[];
+ packageId: string;
+ scenarioId: string;
+ userValue: number;
+ userStatus: number;
+ }) => void;
+ scenarioOptions: ScenarioOption[];
}
const valueLevelOptions = [
- { label: "全部价值", value: "all" },
- { label: "高价值", value: "high" },
- { label: "中价值", value: "medium" },
- { label: "低价值", value: "low" },
+ { label: "全部价值", value: 0 },
+ { label: "高价值", value: 1 },
+ { label: "中价值", value: 2 },
+ { label: "低价值", value: 3 },
];
const statusOptions = [
- { label: "全部状态", value: "all" },
- { label: "已添加", value: "added" },
- { label: "待添加", value: "pending" },
- { label: "添加失败", value: "failed" },
- { label: "重复", value: "duplicate" },
+ { label: "全部状态", value: 0 },
+ { label: "已添加", value: 1 },
+ { label: "待添加", value: 2 },
+ { label: "重复", value: 3 },
+ { label: "添加失败", value: -1 },
];
const FilterModal: React.FC
= ({
visible,
onClose,
- deviceOptions,
- packageOptions,
- deviceId,
- setDeviceId,
- packageId,
- setPackageId,
- valueLevel,
- setValueLevel,
- userStatus,
- setUserStatus,
- onReset,
-}) => (
-
-
- 筛选选项
-
-
-
设备
-
-
-
流量池
-
-
-
用户价值
-
-
-
添加状态
-
-
-
-
-
-
-);
+ onConfirm,
+}) => {
+ const [selectedDevices, setSelectedDevices] = useState(
+ [],
+ );
+ const [packageId, setPackageId] = useState("");
+ const [scenarioId, setScenarioId] = useState("");
+ const [userValue, setUserValue] = useState(0);
+ const [userStatus, setUserStatus] = useState(0);
+ const [scenarioOptions, setScenarioOptions] = useState([]);
+ const [packageOptions, setPackageOptions] = useState([]);
+
+ useEffect(() => {
+ if (visible) {
+ fetchScenarioOptions().then(res => {
+ setScenarioOptions(res);
+ });
+ fetchPackageOptions().then(res => {
+ setPackageOptions(res);
+ });
+ }
+ }, [visible]);
+
+ const handleApply = () => {
+ const params = {
+ deviceIds: selectedDevices.map(d => d.id.toString()),
+ packageId,
+ scenarioId,
+ userValue,
+ userStatus,
+ };
+ console.log(params);
+
+ onConfirm(params);
+ onClose();
+ };
+
+ const handleReset = () => {
+ setSelectedDevices([]);
+ setPackageId("");
+ setScenarioId("");
+ setUserValue(0);
+ setUserStatus(0);
+ };
+
+ return (
+
+
+ 筛选选项
+
+
+
+
流量池
+
+
+
获客场景
+
+
+
用户价值
+
+
+
添加状态
+
+
+
+
+
+
+ );
+};
export default FilterModal;
diff --git a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts
index 0a6162a8..a5b757ef 100644
--- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts
+++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts
@@ -9,11 +9,10 @@ export function fetchTrafficPoolList(params: {
return request("/v1/traffic/pool", params, "GET");
}
-// 获取分组列表(如无真实接口可用mock)
-export async function fetchPackageOptions(): Promise {
- // TODO: 替换为真实接口
- return [
- { id: "pkg-1", name: "高价值客户池" },
- { id: "pkg-2", name: "测试流量池" },
- ];
+export async function fetchScenarioOptions(): Promise {
+ return request("/v1/plan/scenes", {}, "GET");
+}
+
+export async function fetchPackageOptions(): Promise {
+ return request("/v1/traffic/pool/getPackage", {}, "GET");
}
diff --git a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/data.ts b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/data.ts
index f437b129..65ad7f55 100644
--- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/data.ts
+++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/data.ts
@@ -43,3 +43,9 @@ export type ValueLevel = "all" | "high" | "medium" | "low";
// 状态类型
export type UserStatus = "all" | "added" | "pending" | "failed" | "duplicate";
+
+// 获客场景类型
+export interface ScenarioOption {
+ id: string;
+ name: string;
+}
diff --git a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx
index 7a84040a..6894ce1b 100644
--- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx
+++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx
@@ -1,11 +1,16 @@
import { useState, useEffect, useMemo } from "react";
-import { fetchTrafficPoolList, fetchPackageOptions } from "./api";
+import {
+ fetchTrafficPoolList,
+ fetchPackageOptions,
+ fetchScenarioOptions,
+} from "./api";
import type {
TrafficPoolUser,
DeviceOption,
PackageOption,
ValueLevel,
UserStatus,
+ ScenarioOption,
} from "./data";
import { Toast } from "antd-mobile";
@@ -19,12 +24,13 @@ export function useTrafficPoolListLogic() {
// 筛选相关
const [showFilter, setShowFilter] = useState(false);
- const [deviceOptions, setDeviceOptions] = useState([]);
const [packageOptions, setPackageOptions] = useState([]);
- const [deviceId, setDeviceId] = useState("all");
- const [packageId, setPackageId] = useState("all");
- const [valueLevel, setValueLevel] = useState("all");
- const [userStatus, setUserStatus] = useState("all");
+ const [scenarioOptions, setScenarioOptions] = useState([]);
+ const [selectedDevices, setSelectedDevices] = useState([]);
+ const [packageId, setPackageId] = useState(0);
+ const [scenarioId, setScenarioId] = useState(0);
+ const [userValue, setUserValue] = useState(0);
+ const [userStatus, setUserStatus] = useState(0);
// 批量相关
const [selectedIds, setSelectedIds] = useState([]);
@@ -47,15 +53,22 @@ export function useTrafficPoolListLogic() {
const getList = async () => {
setLoading(true);
try {
- const res = await fetchTrafficPoolList({
+ const params: any = {
page,
pageSize,
keyword: search,
- // deviceId,
- // packageId,
- // valueLevel,
- // userStatus,
- });
+ packageId,
+ taskId: scenarioId,
+ userValue,
+ addStatus: userStatus,
+ };
+
+ // 添加筛选参数
+ if (selectedDevices.length > 0) {
+ params.deviceId = selectedDevices.map(d => d.id).join(",");
+ }
+
+ const res = await fetchTrafficPoolList(params);
setList(res.list || []);
setTotal(res.total || 0);
} finally {
@@ -66,13 +79,22 @@ export function useTrafficPoolListLogic() {
// 获取筛选项
useEffect(() => {
fetchPackageOptions().then(setPackageOptions);
+ fetchScenarioOptions().then(setScenarioOptions);
}, []);
// 筛选条件变化时刷新列表
useEffect(() => {
getList();
// eslint-disable-next-line
- }, [page, search /*, deviceId, packageId, valueLevel, userStatus*/]);
+ }, [
+ page,
+ search,
+ selectedDevices,
+ packageId,
+ scenarioId,
+ userValue,
+ userStatus,
+ ]);
// 全选/反选
const handleSelectAll = (checked: boolean) => {
@@ -108,10 +130,11 @@ export function useTrafficPoolListLogic() {
// 筛选重置
const resetFilter = () => {
- setDeviceId("all");
- setPackageId("all");
- setValueLevel("all");
- setUserStatus("all");
+ setSelectedDevices([]);
+ setPackageId(0);
+ setScenarioId(0);
+ setUserValue(0);
+ setUserStatus(0);
};
return {
@@ -125,14 +148,16 @@ export function useTrafficPoolListLogic() {
setSearch,
showFilter,
setShowFilter,
- deviceOptions,
packageOptions,
- deviceId,
- setDeviceId,
+ scenarioOptions,
+ selectedDevices,
+ setSelectedDevices,
packageId,
setPackageId,
- valueLevel,
- setValueLevel,
+ scenarioId,
+ setScenarioId,
+ userValue,
+ setUserValue,
userStatus,
setUserStatus,
selectedIds,
diff --git a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx
index 7e000524..a2a2edec 100644
--- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx
+++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx
@@ -5,9 +5,9 @@ import {
ReloadOutlined,
BarChartOutlined,
} from "@ant-design/icons";
-import { Input, Button, Checkbox } from "antd";
+import { Input, Button, Checkbox, Pagination } from "antd";
import styles from "./index.module.scss";
-import { List, Empty, Avatar, Modal, Selector, Toast, Card } from "antd-mobile";
+import { Empty, Avatar } from "antd-mobile";
import { useNavigate } from "react-router-dom";
import NavCommon from "@/components/NavCommon";
import { useTrafficPoolListLogic } from "./dataAnyx";
@@ -18,20 +18,6 @@ import BatchAddModal from "./BatchAddModal";
const defaultAvatar =
"https://cdn.jsdelivr.net/gh/maokaka/static/avatar-default.png";
-const valueLevelOptions = [
- { label: "全部", value: "all" },
- { label: "高价值", value: "high" },
- { label: "中价值", value: "medium" },
- { label: "低价值", value: "low" },
-];
-const statusOptions = [
- { label: "全部", value: "all" },
- { label: "已添加", value: "added" },
- { label: "待添加", value: "pending" },
- { label: "添加失败", value: "failed" },
- { label: "重复", value: "duplicate" },
-];
-
const TrafficPoolList: React.FC = () => {
const navigate = useNavigate();
const {
@@ -45,15 +31,12 @@ const TrafficPoolList: React.FC = () => {
setSearch,
showFilter,
setShowFilter,
- deviceOptions,
packageOptions,
- deviceId,
- setDeviceId,
- packageId,
+ scenarioOptions,
+ setSelectedDevices,
setPackageId,
- valueLevel,
- setValueLevel,
- userStatus,
+ setScenarioId,
+ setUserValue,
setUserStatus,
selectedIds,
handleSelectAll,
@@ -67,7 +50,6 @@ const TrafficPoolList: React.FC = () => {
setShowStats,
stats,
getList,
- resetFilter,
} = useTrafficPoolListLogic();
return (
@@ -154,6 +136,17 @@ const TrafficPoolList: React.FC = () => {