From e2dfd4487428f862325b605ca82bdfb430468fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Wed, 13 Aug 2025 12:18:43 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=A8=AD=E5=82=99?= =?UTF-8?q?=E9=81=B8=E6=93=87=E7=B5=84=E4=BB=B6=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=A8=AD=E5=82=99=E9=A0=AD=E5=83=8F=E5=92=8C=E5=A5=BD=E5=8F=8B?= =?UTF-8?q?=E6=95=B8=E6=93=9A=E9=A1=AF=E7=A4=BA=EF=BC=8C=E8=AA=BF=E6=95=B4?= =?UTF-8?q?=E6=A8=A3=E5=BC=8F=E4=BB=A5=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B6?= =?UTF-8?q?=E9=AB=94=E9=A9=97=EF=BC=8C=E4=B8=A6=E6=9B=B4=E6=96=B0=E7=9B=B8?= =?UTF-8?q?=E9=97=9C=E6=95=B8=E6=93=9A=E7=B5=90=E6=A7=8B=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=96=B0=E5=B1=AC=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cunkebao/dist/.vite/manifest.json | 2 +- Cunkebao/dist/index.html | 2 +- .../src/components/DeviceSelection/data.ts | 2 + .../DeviceSelection/index.module.scss | 158 ++++++++++++---- .../src/components/DeviceSelection/index.tsx | 45 ++++- .../DeviceSelection/selectionPopup.tsx | 82 ++++++--- .../pages/mobile/mine/content/form/index.tsx | 4 +- .../pages/mobile/mine/content/list/index.tsx | 2 +- .../mobile/mine/devices/index.module.scss | 173 ++++++++++++++++++ .../src/pages/mobile/mine/devices/index.tsx | 137 ++++++++------ Cunkebao/src/types/device.ts | 1 + 11 files changed, 489 insertions(+), 119 deletions(-) create mode 100644 Cunkebao/src/pages/mobile/mine/devices/index.module.scss diff --git a/Cunkebao/dist/.vite/manifest.json b/Cunkebao/dist/.vite/manifest.json index 4f0c258e..5c1e7050 100644 --- a/Cunkebao/dist/.vite/manifest.json +++ b/Cunkebao/dist/.vite/manifest.json @@ -33,7 +33,7 @@ "name": "vendor" }, "index.html": { - "file": "assets/index-D3HSx5Yt.js", + "file": "assets/index-DTZ_ow5W.js", "name": "index", "src": "index.html", "isEntry": true, diff --git a/Cunkebao/dist/index.html b/Cunkebao/dist/index.html index f79f7013..a3b55d54 100644 --- a/Cunkebao/dist/index.html +++ b/Cunkebao/dist/index.html @@ -11,7 +11,7 @@ - + diff --git a/Cunkebao/src/components/DeviceSelection/data.ts b/Cunkebao/src/components/DeviceSelection/data.ts index abc9a214..e3e189e6 100644 --- a/Cunkebao/src/components/DeviceSelection/data.ts +++ b/Cunkebao/src/components/DeviceSelection/data.ts @@ -8,6 +8,8 @@ export interface DeviceSelectionItem { wxid?: string; nickname?: string; usedInPlans?: number; + avatar?: string; + totalFriend?: number; } // 组件属性接口 diff --git a/Cunkebao/src/components/DeviceSelection/index.module.scss b/Cunkebao/src/components/DeviceSelection/index.module.scss index ea776f81..33642dd7 100644 --- a/Cunkebao/src/components/DeviceSelection/index.module.scss +++ b/Cunkebao/src/components/DeviceSelection/index.module.scss @@ -67,60 +67,154 @@ } .deviceItem { display: flex; - align-items: flex-start; - gap: 12px; - padding: 16px; - border-radius: 12px; - border: 1px solid #f0f0f0; + flex-direction: column; + gap: 8px; + padding: 12px; background: #fff; - cursor: pointer; - transition: background 0.2s; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + transition: all 0.2s ease; + border: 1px solid #f5f5f5; + &:hover { - background: #f5f6fa; + transform: translateY(-1px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); + } +} + +.headerRow { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.checkboxContainer { + flex-shrink: 0; +} + +.imeiText { + font-size: 13px; + color: #666; + font-family: monospace; + flex: 1; +} + +.mainContent { + display: flex; + align-items: center; + gap: 12px; + cursor: pointer; + padding: 8px; + border-radius: 8px; + transition: background-color 0.2s ease; + + &:hover { + background-color: #f8f9fa; } } .deviceCheckbox { - margin-top: 4px; + flex-shrink: 0; } .deviceInfo { flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 12px; } +.deviceAvatar { + width: 64px; + height: 64px; + border-radius: 6px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.25); + flex-shrink: 0; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + + .avatarText { + font-size: 18px; + color: #fff; + font-weight: 700; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + } +} + +.deviceContent { + flex: 1; + min-width: 0; +} + .deviceInfoRow { display: flex; align-items: center; - justify-content: space-between; + gap: 6px; + margin-bottom: 6px; } .deviceName { - font-weight: 500; font-size: 16px; - color: #222; + font-weight: 600; + color: #1a1a1a; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .statusOnline { - width: 56px; - height: 24px; - border-radius: 12px; - background: #52c41a; - color: #fff; - font-size: 13px; - display: flex; - align-items: center; - justify-content: center; + font-size: 11px; + padding: 1px 6px; + border-radius: 8px; + color: #52c41a; + background: #f6ffed; + border: 1px solid #b7eb8f; + font-weight: 500; } .statusOffline { - width: 56px; - height: 24px; - border-radius: 12px; - background: #e5e6eb; - color: #888; - font-size: 13px; - display: flex; - align-items: center; - justify-content: center; + font-size: 11px; + padding: 1px 6px; + border-radius: 8px; + color: #ff4d4f; + background: #fff2f0; + border: 1px solid #ffccc7; + font-weight: 500; } .deviceInfoDetail { + display: flex; + flex-direction: column; + gap: 4px; +} + +.infoItem { + display: flex; + align-items: center; + gap: 8px; +} + +.infoLabel { font-size: 13px; - color: #888; - margin-top: 4px; + color: #666; + min-width: 50px; +} + +.infoValue { + font-size: 13px; + color: #333; + + &.imei { + font-family: monospace; + } + + &.friendCount { + font-weight: 500; + } } .loadingBox { display: flex; diff --git a/Cunkebao/src/components/DeviceSelection/index.tsx b/Cunkebao/src/components/DeviceSelection/index.tsx index 9d31e268..997c56f2 100644 --- a/Cunkebao/src/components/DeviceSelection/index.tsx +++ b/Cunkebao/src/components/DeviceSelection/index.tsx @@ -86,11 +86,52 @@ const DeviceSelection: React.FC = ({ style={{ display: "flex", alignItems: "center", - padding: "4px 8px", + padding: "8px 12px", borderBottom: "1px solid #f0f0f0", fontSize: 14, }} > + {/* 头像 */} +
+ {device.avatar ? ( + 头像 + ) : ( + + {(device.memo || device.wechatId || "设")[0]} + + )} +
+
= ({ textOverflow: "ellipsis", }} > - 【 {device.memo}】 - {device.wechatId} + {device.memo} - {device.wechatId}
{!readonly && ( - - - -); + scenarioOptions, + onConfirm, +}) => { + const [selectedDevices, setSelectedDevices] = useState( + [], + ); + const [packageId, setPackageId] = useState("all"); + const [scenarioId, setScenarioId] = useState("all"); + const [valueLevel, setValueLevel] = useState("all"); + const [userStatus, setUserStatus] = useState("all"); + + const handleApply = () => { + onConfirm({ + deviceIds: selectedDevices.map(d => d.id.toString()), + packageId, + scenarioId, + valueLevel, + userStatus, + }); + onClose(); + }; + + const handleReset = () => { + setSelectedDevices([]); + setPackageId("all"); + setScenarioId("all"); + setValueLevel("all"); + setUserStatus("all"); + }; + + return ( + +
+ 筛选选项 +
+
+
设备
+ +
+
+
流量池
+ ({ label: s.name, value: s.id })), + ]} + /> +
+
+
用户价值
+ setUserStatus(v as UserStatus)} + options={statusOptions} + /> +
+
+ + +
+
+ ); +}; 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..de5bfff1 100644 --- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts +++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/api.ts @@ -17,3 +17,14 @@ export async function fetchPackageOptions(): Promise { { id: "pkg-2", name: "测试流量池" }, ]; } + +// 获取获客场景列表 +export async function fetchScenarioOptions(): Promise { + // TODO: 替换为真实接口 + return [ + { id: "scenario-1", name: "朋友圈推广" }, + { id: "scenario-2", name: "群聊引流" }, + { id: "scenario-3", name: "公众号推广" }, + { id: "scenario-4", name: "线下活动" }, + ]; +} 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..b0d3f8ee 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,10 +24,11 @@ export function useTrafficPoolListLogic() { // 筛选相关 const [showFilter, setShowFilter] = useState(false); - const [deviceOptions, setDeviceOptions] = useState([]); const [packageOptions, setPackageOptions] = useState([]); - const [deviceId, setDeviceId] = useState("all"); + const [scenarioOptions, setScenarioOptions] = useState([]); + const [selectedDevices, setSelectedDevices] = useState([]); const [packageId, setPackageId] = useState("all"); + const [scenarioId, setScenarioId] = useState("all"); const [valueLevel, setValueLevel] = useState("all"); const [userStatus, setUserStatus] = useState("all"); @@ -47,15 +53,38 @@ export function useTrafficPoolListLogic() { const getList = async () => { setLoading(true); try { - const res = await fetchTrafficPoolList({ + const params: any = { page, pageSize, keyword: search, - // deviceId, - // packageId, - // valueLevel, - // userStatus, - }); + }; + + // 添加筛选参数 + if (selectedDevices.length > 0) { + params.deviceId = selectedDevices.map(d => d.id).join(","); + } + if (packageId !== "all") { + params.packageId = packageId; + } + if (scenarioId !== "all") { + params.taskId = scenarioId; + } + if (valueLevel !== "all") { + params.userValue = + valueLevel === "high" ? 3 : valueLevel === "medium" ? 2 : 1; + } + if (userStatus !== "all") { + params.addStatus = + userStatus === "added" + ? 1 + : userStatus === "pending" + ? 0 + : userStatus === "failed" + ? -1 + : -2; + } + + const res = await fetchTrafficPoolList(params); setList(res.list || []); setTotal(res.total || 0); } finally { @@ -66,13 +95,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, + valueLevel, + userStatus, + ]); // 全选/反选 const handleSelectAll = (checked: boolean) => { @@ -108,8 +146,9 @@ export function useTrafficPoolListLogic() { // 筛选重置 const resetFilter = () => { - setDeviceId("all"); + setSelectedDevices([]); setPackageId("all"); + setScenarioId("all"); setValueLevel("all"); setUserStatus("all"); }; @@ -125,12 +164,14 @@ export function useTrafficPoolListLogic() { setSearch, showFilter, setShowFilter, - deviceOptions, packageOptions, - deviceId, - setDeviceId, + scenarioOptions, + selectedDevices, + setSelectedDevices, packageId, setPackageId, + scenarioId, + setScenarioId, valueLevel, setValueLevel, userStatus, 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..4702737d 100644 --- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx +++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx @@ -7,7 +7,7 @@ import { } from "@ant-design/icons"; import { Input, Button, Checkbox } 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,12 +31,14 @@ const TrafficPoolList: React.FC = () => { setSearch, showFilter, setShowFilter, - deviceOptions, packageOptions, - deviceId, - setDeviceId, + scenarioOptions, + selectedDevices, + setSelectedDevices, packageId, setPackageId, + scenarioId, + setScenarioId, valueLevel, setValueLevel, userStatus, @@ -169,17 +157,26 @@ const TrafficPoolList: React.FC = () => { setShowFilter(false)} - deviceOptions={deviceOptions} + onConfirm={filters => { + // 更新筛选条件 + setSelectedDevices( + filters.deviceIds.map(id => ({ + id: parseInt(id), + memo: "", + imei: "", + wechatId: "", + status: "offline" as const, + })), + ); + setPackageId(filters.packageId); + setScenarioId(filters.scenarioId); + setValueLevel(filters.valueLevel); + setUserStatus(filters.userStatus); + // 重新获取列表 + getList(); + }} packageOptions={packageOptions} - deviceId={deviceId} - setDeviceId={setDeviceId} - packageId={packageId} - setPackageId={setPackageId} - valueLevel={valueLevel} - setValueLevel={setValueLevel} - userStatus={userStatus} - setUserStatus={setUserStatus} - onReset={resetFilter} + scenarioOptions={scenarioOptions} />
{list.length === 0 && !loading ? ( @@ -192,7 +189,9 @@ const TrafficPoolList: React.FC = () => { className={styles.card} style={{ cursor: "pointer" }} onClick={() => - navigate(`/traffic-pool/detail/${item.sourceId}/${item.id}`) + navigate( + `/mine/traffic-pool/detail/${item.sourceId}/${item.id}`, + ) } >
diff --git a/Cunkebao/src/router/module/mine.tsx b/Cunkebao/src/router/module/mine.tsx index e41f455d..e5c33623 100644 --- a/Cunkebao/src/router/module/mine.tsx +++ b/Cunkebao/src/router/module/mine.tsx @@ -36,12 +36,12 @@ const routes = [ auth: true, }, { - path: "/traffic-pool", + path: "/mine/traffic-pool", element: , auth: true, }, { - path: "/traffic-pool/detail/:wxid/:userId", + path: "/mine/traffic-pool/detail/:wxid/:userId", element: , auth: true, }, From 94df1469c002897358d65b4eabe9431d51bec25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Wed, 13 Aug 2025 17:07:51 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B5=81=E9=87=8F?= =?UTF-8?q?=E6=B1=A0=E5=88=97=E8=A1=A8=E7=9B=B8=E9=97=9C=E9=82=8F=E8=BC=AF?= =?UTF-8?q?=EF=BC=8C=E6=9B=BF=E6=8F=9B=E7=8D=B2=E5=AE=A2=E5=A0=B4=E6=99=AF?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E8=AA=BF=E6=95=B4=E7=94=A8=E6=88=B6?= =?UTF-8?q?=E5=83=B9=E5=80=BC=E5=92=8C=E7=8B=80=E6=85=8B=E7=9A=84=E7=AF=A9?= =?UTF-8?q?=E9=81=B8=E9=82=8F=E8=BC=AF=EF=BC=8C=E4=B8=A6=E5=84=AA=E5=8C=96?= =?UTF-8?q?=E7=AF=A9=E9=81=B8=E6=A8=A1=E6=85=8B=E6=A1=86=E7=9A=84=E7=8B=80?= =?UTF-8?q?=E6=85=8B=E7=AE=A1=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mine/traffic-pool/list/FilterModal.tsx | 79 ++++++++++--------- .../mobile/mine/traffic-pool/list/api.ts | 9 +-- .../mine/traffic-pool/list/dataAnyx.tsx | 30 +++---- .../mobile/mine/traffic-pool/list/index.tsx | 11 +-- 4 files changed, 56 insertions(+), 73 deletions(-) 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 baeb21c1..3acd9879 100644 --- a/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx +++ b/Cunkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx @@ -1,14 +1,9 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Popup } from "antd-mobile"; import { Select, Button } from "antd"; import DeviceSelection from "@/components/DeviceSelection"; -import type { - PackageOption, - ValueLevel, - UserStatus, - ScenarioOption, -} from "./data"; - +import type { UserStatus, ScenarioOption } from "./data"; +import { fetchScenarioOptions } from "./api"; import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; interface FilterModalProps { @@ -18,59 +13,69 @@ interface FilterModalProps { deviceIds: string[]; packageId: string; scenarioId: string; - valueLevel: ValueLevel; - userStatus: UserStatus; + userValue: number; + userStatus: number; }) => void; - packageOptions: PackageOption[]; 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, - packageOptions, - scenarioOptions, onConfirm, }) => { const [selectedDevices, setSelectedDevices] = useState( [], ); - const [packageId, setPackageId] = useState("all"); - const [scenarioId, setScenarioId] = useState("all"); - const [valueLevel, setValueLevel] = useState("all"); - const [userStatus, setUserStatus] = useState("all"); + 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); + }); + } + }, [visible]); const handleApply = () => { - onConfirm({ + const params = { deviceIds: selectedDevices.map(d => d.id.toString()), packageId, scenarioId, - valueLevel, + userValue, userStatus, - }); + }; + console.log(params); + + onConfirm(params); onClose(); }; const handleReset = () => { setSelectedDevices([]); - setPackageId("all"); - setScenarioId("all"); - setValueLevel("all"); - setUserStatus("all"); + setPackageId(""); + setScenarioId(""); + setUserValue(0); + setUserStatus(0); }; return ( @@ -100,7 +105,7 @@ const FilterModal: React.FC = ({ value={packageId} onChange={setPackageId} options={[ - { label: "全部流量池", value: "all" }, + { label: "全部流量池", value: "" }, ...packageOptions.map(p => ({ label: p.name, value: p.id })), ]} /> @@ -112,7 +117,7 @@ const FilterModal: React.FC = ({ value={scenarioId} onChange={setScenarioId} options={[ - { label: "全部场景", value: "all" }, + { label: "全部场景", value: "" }, ...scenarioOptions.map(s => ({ label: s.name, value: s.id })), ]} /> @@ -121,8 +126,8 @@ const FilterModal: React.FC = ({
用户价值