diff --git a/nkebao/src/pages/traffic-pool/detail/index.module.scss b/nkebao/src/pages/traffic-pool/detail/index.module.scss
new file mode 100644
index 00000000..84fa5f36
--- /dev/null
+++ b/nkebao/src/pages/traffic-pool/detail/index.module.scss
@@ -0,0 +1,354 @@
+.container {
+ padding: 16px;
+ background: #f5f5f5;
+ min-height: 100vh;
+}
+
+.notFound {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100vh;
+}
+
+.notFoundText {
+ color: #999;
+ font-size: 16px;
+}
+
+.userCard {
+ margin-bottom: 16px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.userHeader {
+ display: flex;
+ align-items: flex-start;
+ gap: 16px;
+ margin-bottom: 12px;
+}
+
+.userAvatar {
+ width: 64px;
+ height: 64px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.userInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.userName {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 4px;
+ line-height: 1.2;
+}
+
+.starIcon {
+ color: #ff4d4f;
+ font-size: 16px;
+}
+
+.userWechatId {
+ font-size: 14px;
+ color: #1677ff;
+ font-weight: 500;
+ margin-bottom: 8px;
+}
+
+.userTags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+}
+
+.rfmTags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.tabs {
+ background: #fff;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.tabContent {
+ padding: 16px;
+}
+
+.cardTitle {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 12px;
+}
+
+.infoCard {
+ margin-bottom: 16px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.infoItem {
+ padding: 8px 0;
+}
+
+.infoLabel {
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 4px;
+}
+
+.infoValue {
+ font-size: 14px;
+ color: #333;
+ font-weight: 500;
+}
+
+.rfmCard {
+ margin-bottom: 16px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.rfmGrid {
+ display: flex;
+ justify-content: space-around;
+ text-align: center;
+}
+
+.rfmItem {
+ flex: 1;
+}
+
+.rfmValue {
+ font-size: 24px;
+ font-weight: bold;
+ line-height: 1;
+ margin-bottom: 4px;
+}
+
+.rfmLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.rfmItem:nth-child(1) .rfmValue {
+ color: #1677ff;
+}
+
+.rfmItem:nth-child(2) .rfmValue {
+ color: #52c41a;
+}
+
+.rfmItem:nth-child(3) .rfmValue {
+ color: #722ed1;
+}
+
+.poolButtons {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 16px;
+}
+
+.statsCard {
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.statItem {
+ text-align: center;
+ padding: 8px 0;
+}
+
+.statValue {
+ font-size: 18px;
+ font-weight: bold;
+ line-height: 1;
+ margin-bottom: 4px;
+}
+
+.statLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.statItem:nth-child(1) .statValue {
+ color: #52c41a;
+}
+
+.statItem:nth-child(2) .statValue {
+ color: #1677ff;
+}
+
+.statItem:nth-child(3) .statValue {
+ color: #faad14;
+}
+
+.statItem:nth-child(4) .statValue {
+ color: #ff4d4f;
+}
+
+.interactionCard {
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.interactionList {
+ margin: 0;
+ padding: 0;
+}
+
+.interactionItem {
+ padding: 12px 0;
+ border-bottom: 1px solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+.interactionIcon {
+ font-size: 20px;
+ color: #1677ff;
+ margin-right: 12px;
+}
+
+.interactionContent {
+ flex: 1;
+ min-width: 0;
+}
+
+.interactionTitle {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 4px;
+}
+
+.interactionDesc {
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 4px;
+ line-height: 1.4;
+}
+
+.interactionValue {
+ color: #52c41a;
+ font-weight: bold;
+ margin-left: 4px;
+}
+
+.interactionTime {
+ font-size: 11px;
+ color: #999;
+}
+
+.emptyState {
+ text-align: center;
+ color: #999;
+ padding: 32px 0;
+ font-size: 14px;
+}
+
+.tagsCard {
+ margin-bottom: 16px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.tagsList {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 16px;
+}
+
+.valueTags {
+ border-top: 1px solid #f0f0f0;
+ padding-top: 16px;
+}
+
+.valueTitle {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 12px;
+}
+
+.valueTagItem {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 8px;
+}
+
+.rfmScore {
+ font-size: 12px;
+ color: #666;
+}
+
+.valueLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.addTagButton {
+ margin-top: 16px;
+}
+
+// 响应式设计
+@media (max-width: 375px) {
+ .container {
+ padding: 12px;
+ }
+
+ .userHeader {
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ }
+
+ .userAvatar {
+ width: 80px;
+ height: 80px;
+ }
+
+ .rfmGrid {
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .poolButtons {
+ flex-direction: column;
+ }
+
+ .statsCard {
+ .adm-grid {
+ grid-template-columns: 1fr 1fr;
+ }
+ }
+}
diff --git a/nkebao/src/pages/traffic-pool/detail/index.tsx b/nkebao/src/pages/traffic-pool/detail/index.tsx
new file mode 100644
index 00000000..7389b966
--- /dev/null
+++ b/nkebao/src/pages/traffic-pool/detail/index.tsx
@@ -0,0 +1,469 @@
+import React, { useState } from "react";
+import { useParams } from "react-router-dom";
+import { Card, Tabs, Tag, Avatar, Button, List, Grid } from "antd-mobile";
+import {
+ UserOutline,
+ MobileOutline,
+ TeamOutline,
+ StarFill,
+ MessageOutline,
+ EyeOutline,
+ ClickOutline,
+ PayCircleOutline,
+} from "antd-mobile-icons";
+import Layout from "@/components/Layout/Layout";
+import NavCommon from "@/components/NavCommon";
+import styles from "./index.module.scss";
+
+// 复用类型定义和Mock数据生成函数
+import {
+ Device,
+ WechatAccount,
+ CustomerService,
+ TrafficPool,
+ RFMScore,
+ UserTag,
+ UserInteraction,
+ TrafficUser,
+ RFM_SEGMENTS,
+ generateMockDevices,
+ generateMockWechatAccounts,
+ generateMockCustomerServices,
+ generateMockTrafficPools,
+ generateRFMScore,
+ generateMockInteractions,
+ generateUserTags,
+} from "../list";
+
+const mockDevices = generateMockDevices();
+const mockWechatAccounts = generateMockWechatAccounts(mockDevices);
+const mockCustomerServices = generateMockCustomerServices();
+const mockTrafficPools = generateMockTrafficPools();
+
+// 生成Mock用户数据
+const generateMockUsers = (
+ devices: Device[],
+ wechatAccounts: WechatAccount[],
+ customerServices: CustomerService[],
+ trafficPools: TrafficPool[]
+): TrafficUser[] => {
+ return Array.from({ length: 500 }, (_, i) => {
+ const rfmScore = generateRFMScore();
+ const tags = generateUserTags(rfmScore);
+ const interactions = generateMockInteractions();
+
+ const user: TrafficUser = {
+ id: `user-${i + 1}`,
+ avatar: `/placeholder.svg?height=40&width=40&query=user${Math.floor(Math.random() * 100)}`,
+ nickname: `用户${i + 1}`,
+ wechatId: `wx_${Math.random().toString(36).substr(2, 8)}`,
+ phone: `1${Math.floor(Math.random() * 9) + 1}${Math.random().toString().substr(2, 9)}`,
+ region: ["北京", "上海", "广州", "深圳", "杭州", "成都"][
+ Math.floor(Math.random() * 6)
+ ],
+ note: Math.random() > 0.7 ? `这是用户${i + 1}的备注信息` : "",
+ status: ["pending", "added", "failed", "duplicate"][
+ Math.floor(Math.random() * 4)
+ ] as any,
+ addTime: new Date(
+ Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000
+ ).toISOString(),
+ source: "海报获客",
+ scenario: "poster",
+ deviceId: devices[Math.floor(Math.random() * devices.length)].id,
+ wechatAccountId:
+ wechatAccounts[Math.floor(Math.random() * wechatAccounts.length)].id,
+ customerServiceId:
+ customerServices[Math.floor(Math.random() * customerServices.length)]
+ .id,
+ poolIds:
+ Math.random() > 0.5
+ ? [trafficPools[Math.floor(Math.random() * trafficPools.length)].id]
+ : [],
+ tags,
+ rfmScore,
+ lastInteraction: new Date(
+ Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000
+ ).toISOString(),
+ totalSpent: Math.floor(Math.random() * 10000),
+ interactionCount: Math.floor(Math.random() * 50) + 1,
+ conversionRate: Math.floor(Math.random() * 100),
+ isDuplicate: Math.random() > 0.9,
+ mergedAccounts: [],
+ addStatus: ["not_added", "adding", "added", "failed"][
+ Math.floor(Math.random() * 4)
+ ] as any,
+ interactions,
+ };
+
+ return user;
+ });
+};
+
+const users = generateMockUsers(
+ mockDevices,
+ mockWechatAccounts,
+ mockCustomerServices,
+ mockTrafficPools
+);
+
+const TrafficPoolDetail: React.FC = () => {
+ const { id } = useParams();
+ const [activeTab, setActiveTab] = useState("base");
+
+ const user = users.find((u: TrafficUser) => u.id === id);
+
+ if (!user) {
+ return (
+
+
+
+ );
+ }
+
+ const wechatAccount = mockWechatAccounts.find(
+ (acc) => acc.id === user.wechatAccountId
+ );
+ const customerService = mockCustomerServices.find(
+ (cs) => cs.id === user.customerServiceId
+ );
+ const device = mockDevices.find((device) => device.id === user.deviceId);
+ const rfmSegment = Object.values(RFM_SEGMENTS).find(
+ (seg: any) => seg.name === user.rfmScore.segment
+ );
+
+ // 辅助函数
+ const getPoolNames = (poolIds: string[]) => {
+ return poolIds
+ .map((id) => mockTrafficPools.find((pool) => pool.id === id)?.name)
+ .filter(Boolean)
+ .join(", ");
+ };
+
+ const formatDate = (dateString: string) => {
+ if (!dateString) return "--";
+ try {
+ const date = new Date(dateString);
+ return date.toLocaleDateString("zh-CN");
+ } catch (error) {
+ return dateString;
+ }
+ };
+
+ const getInteractionIcon = (type: string) => {
+ switch (type) {
+ case "click":
+ return ;
+ case "message":
+ return ;
+ case "purchase":
+ return ;
+ case "view":
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ const getInteractionTypeText = (type: string) => {
+ switch (type) {
+ case "click":
+ return "点击行为";
+ case "message":
+ return "消息互动";
+ case "purchase":
+ return "购买行为";
+ case "view":
+ return "页面浏览";
+ default:
+ return type;
+ }
+ };
+
+ const getStatusText = (status: string) => {
+ switch (status) {
+ case "added":
+ return "已添加";
+ case "pending":
+ return "未添加";
+ case "failed":
+ return "添加失败";
+ case "duplicate":
+ return "重复";
+ default:
+ return status;
+ }
+ };
+
+ const getStatusColor = (status: string) => {
+ switch (status) {
+ case "added":
+ return "success";
+ case "pending":
+ return "default";
+ case "failed":
+ return "danger";
+ case "duplicate":
+ return "warning";
+ default:
+ return "default";
+ }
+ };
+
+ return (
+ }>
+
+ {/* 用户基本信息 */}
+
+
+
+ {user.nickname?.slice(0, 2) || "用户"}
+
+
+
+ {user.nickname}
+ {user.rfmScore.priority === "high" && (
+
+ )}
+
+
{user.wechatId}
+
+ {user.poolIds.length > 0 && (
+
+ {getPoolNames(user.poolIds)}
+
+ )}
+ {user.status === "added" && (
+
+ 优先添加
+
+ )}
+
+
+
+
+ {/* RFM标签 */}
+
+ {rfmSegment && (
+
+ {rfmSegment.name}
+
+ )}
+ {user.status === "added" && (
+
+ 优先添加
+
+ )}
+
+
+
+ {/* Tab导航 */}
+
+
+
+ {/* 关键信息卡片 */}
+
+ 关键信息
+
+
+
设备
+
+ {device?.name || "--"}
+
+
+
+
微信号
+
+ {wechatAccount?.nickname || "--"}
+
+
+
+
客服
+
+ {customerService?.name || "--"}
+
+
+
+
添加时间
+
+ {formatDate(user.addTime)}
+
+
+
+
最近互动
+
+ {formatDate(user.lastInteraction)}
+
+
+
+
+
+ {/* RFM评分卡片 */}
+
+ RFM评分
+
+
+
+ {user.rfmScore.recency}
+
+
最近性(R)
+
+
+
+ {user.rfmScore.frequency}
+
+
频率(F)
+
+
+
+ {user.rfmScore.monetary}
+
+
金额(M)
+
+
+
+
+ {/* 流量池按钮 */}
+
+
+
+
+
+ {/* 统计数据卡片 */}
+
+
+
+
¥{user.totalSpent}
+
总消费
+
+
+
+ {user.interactionCount}
+
+
互动次数
+
+
+
+ {user.conversionRate}%
+
+
转化率
+
+
+
+ {getStatusText(user.status)}
+
+
添加状态
+
+
+
+
+
+
+
+
+
+ 互动记录
+ {user.interactions && user.interactions.length > 0 ? (
+
+ {user.interactions.slice(0, 4).map((interaction) => (
+
+
+
+ {getInteractionTypeText(interaction.type)}
+
+
+ {interaction.content}
+ {interaction.type === "purchase" &&
+ interaction.value && (
+
+ ¥{interaction.value}
+
+ )}
+
+
+ {formatDate(interaction.timestamp)}{" "}
+ {new Date(interaction.timestamp).toLocaleTimeString(
+ "zh-CN",
+ {
+ hour: "2-digit",
+ minute: "2-digit",
+ }
+ )}
+
+
+
+ ))}
+
+ ) : (
+ 暂无互动记录
+ )}
+
+
+
+
+
+
+
+ 用户标签
+
+ {user.tags.map((tag) => (
+
+ {tag.name}
+
+ ))}
+
+
+
+
价值标签
+
+
+ 重要保持客户
+
+
+ RFM总分:
+ {user.rfmScore.recency +
+ user.rfmScore.frequency +
+ user.rfmScore.monetary}
+ /15
+
+
+
+ 价值等级:
+
+ 高价值
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default TrafficPoolDetail;
diff --git a/nkebao/src/pages/traffic-pool/list/index.module.scss b/nkebao/src/pages/traffic-pool/list/index.module.scss
new file mode 100644
index 00000000..6c5bf3c0
--- /dev/null
+++ b/nkebao/src/pages/traffic-pool/list/index.module.scss
@@ -0,0 +1,365 @@
+.container {
+ padding: 0;
+ background: #f5f5f5;
+ min-height: 100vh;
+}
+
+.headerActions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.spinning {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.analyticsPanel {
+ background: #fff;
+ padding: 16px;
+ margin-bottom: 8px;
+}
+
+.statsGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+ margin-bottom: 16px;
+}
+
+.statCard {
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.statContent {
+ flex: 1;
+}
+
+.statValue {
+ font-size: 24px;
+ font-weight: bold;
+ color: #1677ff;
+ line-height: 1;
+ margin-bottom: 4px;
+}
+
+.statLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.statIcon {
+ font-size: 24px;
+ color: #1677ff;
+}
+
+.efficiencyCard {
+ padding: 16px;
+ border-radius: 8px;
+ background: #fff;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.efficiencyTitle {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 12px;
+}
+
+.efficiencyGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 16px;
+ margin-bottom: 16px;
+}
+
+.efficiencyItem {
+ text-align: center;
+}
+
+.efficiencyValue {
+ font-size: 18px;
+ font-weight: bold;
+ color: #1677ff;
+ line-height: 1;
+ margin-bottom: 4px;
+}
+
+.efficiencyLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.statusGrid {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ gap: 8px;
+ padding-top: 12px;
+ border-top: 1px solid #f0f0f0;
+}
+
+.statusItem {
+ text-align: center;
+}
+
+.statusValue {
+ font-size: 16px;
+ font-weight: bold;
+ line-height: 1;
+ margin-bottom: 4px;
+}
+
+.statusLabel {
+ font-size: 12px;
+ color: #666;
+}
+
+.statusItem:nth-child(1) .statusValue {
+ color: #52c41a;
+}
+
+.statusItem:nth-child(2) .statusValue {
+ color: #faad14;
+}
+
+.statusItem:nth-child(3) .statusValue {
+ color: #ff4d4f;
+}
+
+.searchSection {
+ background: #fff;
+ padding: 12px 16px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 8px;
+}
+
+.filterButton {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ font-size: 14px;
+}
+
+.actionBar {
+ background: #fff;
+ padding: 12px 16px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 8px;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.selectSection {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.addButton {
+ font-size: 12px;
+ padding: 4px 8px;
+ height: 28px;
+}
+
+.totalCount {
+ font-size: 12px;
+ color: #666;
+}
+
+.userList {
+ background: #fff;
+ margin: 0;
+ padding: 0;
+}
+
+.userItem {
+ padding: 16px;
+ border-bottom: 1px solid #f0f0f0;
+ cursor: pointer;
+ transition: background-color 0.2s;
+
+ &:hover {
+ background-color: #fafafa;
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+.userCheckbox {
+ margin-right: 12px;
+}
+
+.userContent {
+ flex: 1;
+ min-width: 0;
+}
+
+.userHeader {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ margin-bottom: 8px;
+}
+
+.userInfo {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex: 1;
+ min-width: 0;
+}
+
+.userAvatar {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.userDetails {
+ flex: 1;
+ min-width: 0;
+}
+
+.userName {
+ font-size: 16px;
+ font-weight: 500;
+ color: #333;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ margin-bottom: 4px;
+ line-height: 1.2;
+}
+
+.starIcon {
+ color: #ff4d4f;
+ font-size: 14px;
+}
+
+.userWechatId {
+ font-size: 14px;
+ color: #1677ff;
+ font-weight: 500;
+}
+
+.userMeta {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ margin-bottom: 8px;
+ font-size: 12px;
+ color: #666;
+}
+
+.metaItem {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.userTags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+ margin-bottom: 8px;
+}
+
+.poolInfo {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 12px;
+ color: #666;
+}
+
+.filterPopup {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: #fff;
+}
+
+.filterHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px;
+ border-bottom: 1px solid #f0f0f0;
+ font-size: 16px;
+ font-weight: 500;
+}
+
+.filterContent {
+ flex: 1;
+ padding: 16px;
+ overflow-y: auto;
+}
+
+.filterItem {
+ margin-bottom: 24px;
+}
+
+.filterLabel {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 8px;
+}
+
+.filterActions {
+ display: flex;
+ gap: 12px;
+ padding: 16px;
+ border-top: 1px solid #f0f0f0;
+ margin-top: auto;
+
+ .adm-button {
+ flex: 1;
+ }
+}
+
+// 响应式设计
+@media (max-width: 375px) {
+ .statsGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .efficiencyGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .statusGrid {
+ grid-template-columns: 1fr 1fr;
+ }
+
+ .userMeta {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+}
diff --git a/nkebao/src/pages/traffic-pool/list/index.tsx b/nkebao/src/pages/traffic-pool/list/index.tsx
new file mode 100644
index 00000000..f4d1da91
--- /dev/null
+++ b/nkebao/src/pages/traffic-pool/list/index.tsx
@@ -0,0 +1,943 @@
+import React, { useState, useEffect, useCallback } from "react";
+import { useNavigate } from "react-router-dom";
+import {
+ Card,
+ List,
+ Button,
+ SearchBar,
+ Checkbox,
+ Tag,
+ Avatar,
+ Toast,
+ SpinLoading,
+ Popup,
+ Selector,
+ InfiniteScroll,
+} from "antd-mobile";
+import {
+ SearchOutline,
+ FilterOutline,
+ RefreshOutline,
+ StarOutline,
+ StarFill,
+ UserOutline,
+ MobileOutline,
+ TeamOutline,
+ BarChartOutline,
+ ChevronDownOutline,
+ ChevronUpOutline,
+} from "antd-mobile-icons";
+import Layout from "@/components/Layout/Layout";
+import NavCommon from "@/components/NavCommon";
+import styles from "./index.module.scss";
+
+// 类型定义
+export interface Device {
+ id: string;
+ name: string;
+ status: "online" | "offline" | "busy";
+ battery: number;
+ location: string;
+ wechatAccounts: number;
+ dailyAddLimit: number;
+ todayAdded: number;
+}
+
+export interface WechatAccount {
+ id: string;
+ nickname: string;
+ wechatId: string;
+ avatar: string;
+ deviceId: string;
+ status: "normal" | "limited" | "blocked";
+ friendCount: number;
+ dailyAddLimit: number;
+}
+
+export interface CustomerService {
+ id: string;
+ name: string;
+ avatar: string;
+ status: "online" | "offline" | "busy";
+ assignedUsers: number;
+}
+
+export interface TrafficPool {
+ id: string;
+ name: string;
+ description: string;
+ userCount: number;
+ tags: string[];
+ createdAt: string;
+}
+
+export interface RFMScore {
+ recency: number;
+ frequency: number;
+ monetary: number;
+ total: number;
+ segment: string;
+ priority: "high" | "medium" | "low";
+}
+
+export interface UserTag {
+ id: string;
+ name: string;
+ color: string;
+ source: string;
+}
+
+export interface UserInteraction {
+ id: string;
+ type: "message" | "purchase" | "view" | "click";
+ content: string;
+ timestamp: string;
+ value?: number;
+}
+
+export interface TrafficUser {
+ id: string;
+ avatar: string;
+ nickname: string;
+ wechatId: string;
+ phone: string;
+ region: string;
+ note: string;
+ status: "pending" | "added" | "failed" | "duplicate";
+ addTime: string;
+ source: string;
+ scenario: string;
+ deviceId: string;
+ wechatAccountId: string;
+ customerServiceId: string;
+ poolIds: string[];
+ tags: UserTag[];
+ rfmScore: RFMScore;
+ lastInteraction: string;
+ totalSpent: number;
+ interactionCount: number;
+ conversionRate: number;
+ isDuplicate: boolean;
+ mergedAccounts: string[];
+ addStatus: "not_added" | "adding" | "added" | "failed";
+ interactions: UserInteraction[];
+}
+
+// 常量定义
+export const SCENARIOS = [
+ { id: "poster", name: "海报获客", icon: "🎨" },
+ { id: "phone", name: "电话获客", icon: "📞" },
+ { id: "douyin", name: "抖音获客", icon: "🎵" },
+ { id: "xiaohongshu", name: "小红书获客", icon: "📖" },
+ { id: "weixinqun", name: "微信群获客", icon: "👥" },
+ { id: "api", name: "API获客", icon: "🔗" },
+ { id: "order", name: "订单获客", icon: "📦" },
+ { id: "payment", name: "付款码获客", icon: "💳" },
+];
+
+export const RFM_SEGMENTS = {
+ "555": {
+ name: "重要价值客户",
+ color: "red",
+ icon: "👑",
+ priority: "high",
+ },
+ "554": {
+ name: "重要保持客户",
+ color: "purple",
+ icon: "💎",
+ priority: "high",
+ },
+ "544": {
+ name: "重要发展客户",
+ color: "blue",
+ icon: "🚀",
+ priority: "high",
+ },
+ "455": {
+ name: "重要挽留客户",
+ color: "orange",
+ icon: "⚠️",
+ priority: "medium",
+ },
+ "444": {
+ name: "一般价值客户",
+ color: "green",
+ icon: "👤",
+ priority: "medium",
+ },
+ "333": {
+ name: "一般保持客户",
+ color: "yellow",
+ icon: "📈",
+ priority: "medium",
+ },
+ "222": {
+ name: "新用户",
+ color: "cyan",
+ icon: "🌟",
+ priority: "low",
+ },
+ "111": {
+ name: "流失预警客户",
+ color: "gray",
+ icon: "😴",
+ priority: "low",
+ },
+} as const;
+
+// Mock数据生成函数
+const generateMockDevices = (): Device[] => {
+ return Array.from({ length: 8 }, (_, i) => ({
+ id: `device-${i + 1}`,
+ name: `设备${i + 1}`,
+ status: ["online", "offline", "busy"][Math.floor(Math.random() * 3)] as
+ | "online"
+ | "offline"
+ | "busy",
+ battery: Math.floor(Math.random() * 100),
+ location: ["北京", "上海", "广州", "深圳"][Math.floor(Math.random() * 4)],
+ wechatAccounts: Math.floor(Math.random() * 5) + 1,
+ dailyAddLimit: Math.random() > 0.5 ? 20 : 10,
+ todayAdded: Math.floor(Math.random() * 15),
+ }));
+};
+
+const generateMockWechatAccounts = (devices: Device[]): WechatAccount[] => {
+ const accounts: WechatAccount[] = [];
+ devices.forEach((device) => {
+ for (let i = 0; i < device.wechatAccounts; i++) {
+ accounts.push({
+ id: `wx-${device.id}-${i + 1}`,
+ nickname: `微信${device.id.split("-")[1]}-${i + 1}`,
+ wechatId: `wxid_${Math.random().toString(36).substr(2, 8)}`,
+ avatar: `/placeholder.svg?height=40&width=40&query=wx${Math.floor(Math.random() * 10)}`,
+ deviceId: device.id,
+ status: ["normal", "limited", "blocked"][
+ Math.floor(Math.random() * 3)
+ ] as "normal" | "limited" | "blocked",
+ friendCount: Math.floor(Math.random() * 4000) + 1000,
+ dailyAddLimit: Math.random() > 0.5 ? 20 : 10,
+ });
+ }
+ });
+ return accounts;
+};
+
+const generateMockCustomerServices = (): CustomerService[] => {
+ return Array.from({ length: 5 }, (_, i) => ({
+ id: `cs-${i + 1}`,
+ name: `客服${i + 1}`,
+ avatar: `/placeholder.svg?height=40&width=40&query=cs${i}`,
+ status: ["online", "offline", "busy"][Math.floor(Math.random() * 3)] as
+ | "online"
+ | "offline"
+ | "busy",
+ assignedUsers: Math.floor(Math.random() * 100) + 50,
+ }));
+};
+
+const generateMockTrafficPools = (): TrafficPool[] => {
+ return [
+ {
+ id: "pool-1",
+ name: "高价值客户池",
+ description: "包含所有高价值客户,优先添加",
+ userCount: 156,
+ tags: ["高价值", "优先添加", "重要客户"],
+ createdAt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString(),
+ },
+ {
+ id: "pool-2",
+ name: "潜在客户池",
+ description: "有潜力的用户,需要进一步培养",
+ userCount: 289,
+ tags: ["潜在客户", "需培养"],
+ createdAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),
+ },
+ {
+ id: "pool-3",
+ name: "新用户池",
+ description: "新注册或新添加的用户",
+ userCount: 432,
+ tags: ["新用户", "待分类"],
+ createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),
+ },
+ ];
+};
+
+const generateRFMScore = (): RFMScore => {
+ const recency = Math.floor(Math.random() * 5) + 1;
+ const frequency = Math.floor(Math.random() * 5) + 1;
+ const monetary = Math.floor(Math.random() * 5) + 1;
+ const total = recency + frequency + monetary;
+
+ let segment: string;
+ let priority: "high" | "medium" | "low";
+
+ if (total >= 12) {
+ segment = Object.values(RFM_SEGMENTS)[Math.floor(Math.random() * 3)].name;
+ priority = "high";
+ } else if (total >= 8) {
+ segment =
+ Object.values(RFM_SEGMENTS)[3 + Math.floor(Math.random() * 3)].name;
+ priority = "medium";
+ } else {
+ segment =
+ Object.values(RFM_SEGMENTS)[6 + Math.floor(Math.random() * 2)].name;
+ priority = "low";
+ }
+
+ return { recency, frequency, monetary, total, segment, priority };
+};
+
+const generateMockInteractions = (): UserInteraction[] => {
+ const types = ["message", "purchase", "view", "click"] as const;
+ return Array.from({ length: Math.floor(Math.random() * 10) + 1 }, (_, i) => {
+ const type = types[Math.floor(Math.random() * types.length)];
+ return {
+ id: `interaction-${i + 1}`,
+ type,
+ content:
+ type === "message"
+ ? "用户发送了消息"
+ : type === "purchase"
+ ? "用户购买了产品"
+ : type === "view"
+ ? "用户查看了产品"
+ : "用户点击了链接",
+ timestamp: new Date(
+ Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000
+ ).toISOString(),
+ value:
+ type === "purchase"
+ ? Math.floor(Math.random() * 1000) + 100
+ : undefined,
+ };
+ });
+};
+
+const generateUserTags = (rfmScore: RFMScore): UserTag[] => {
+ const allTags = [
+ { id: "tag-1", name: "活跃用户", color: "success", source: "system" },
+ { id: "tag-2", name: "高消费", color: "danger", source: "system" },
+ { id: "tag-3", name: "忠实客户", color: "primary", source: "system" },
+ { id: "tag-4", name: "新用户", color: "warning", source: "system" },
+ { id: "tag-5", name: "VIP客户", color: "purple", source: "manual" },
+ { id: "tag-6", name: "潜在客户", color: "default", source: "system" },
+ ];
+
+ const tags: UserTag[] = [];
+
+ if (rfmScore.priority === "high") {
+ tags.push(allTags[1], allTags[2]);
+ if (Math.random() > 0.5) tags.push(allTags[4]);
+ } else if (rfmScore.priority === "medium") {
+ tags.push(allTags[0]);
+ if (Math.random() > 0.5) tags.push(allTags[5]);
+ } else {
+ tags.push(allTags[3]);
+ if (Math.random() > 0.3) tags.push(allTags[5]);
+ }
+
+ return tags;
+};
+
+const mockDevices = generateMockDevices();
+const mockWechatAccounts = generateMockWechatAccounts(mockDevices);
+const mockCustomerServices = generateMockCustomerServices();
+const mockTrafficPools = generateMockTrafficPools();
+
+const generateMockUsers = (
+ devices: Device[],
+ wechatAccounts: WechatAccount[],
+ customerServices: CustomerService[],
+ trafficPools: TrafficPool[]
+): TrafficUser[] => {
+ return Array.from({ length: 500 }, (_, i) => {
+ const rfmScore = generateRFMScore();
+ const tags = generateUserTags(rfmScore);
+ const interactions = generateMockInteractions();
+
+ const user: TrafficUser = {
+ id: `user-${i + 1}`,
+ avatar: `/placeholder.svg?height=40&width=40&query=user${Math.floor(Math.random() * 100)}`,
+ nickname: `用户${i + 1}`,
+ wechatId: `wx_${Math.random().toString(36).substr(2, 8)}`,
+ phone: `1${Math.floor(Math.random() * 9) + 1}${Math.random().toString().substr(2, 9)}`,
+ region: ["北京", "上海", "广州", "深圳", "杭州", "成都"][
+ Math.floor(Math.random() * 6)
+ ],
+ note: Math.random() > 0.7 ? `这是用户${i + 1}的备注信息` : "",
+ status: ["pending", "added", "failed", "duplicate"][
+ Math.floor(Math.random() * 4)
+ ] as any,
+ addTime: new Date(
+ Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000
+ ).toISOString(),
+ source: SCENARIOS[Math.floor(Math.random() * SCENARIOS.length)].name,
+ scenario: SCENARIOS[Math.floor(Math.random() * SCENARIOS.length)].id,
+ deviceId: devices[Math.floor(Math.random() * devices.length)].id,
+ wechatAccountId:
+ wechatAccounts[Math.floor(Math.random() * wechatAccounts.length)].id,
+ customerServiceId:
+ customerServices[Math.floor(Math.random() * customerServices.length)]
+ .id,
+ poolIds:
+ Math.random() > 0.5
+ ? [trafficPools[Math.floor(Math.random() * trafficPools.length)].id]
+ : [],
+ tags,
+ rfmScore,
+ lastInteraction: new Date(
+ Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000
+ ).toISOString(),
+ totalSpent: Math.floor(Math.random() * 10000),
+ interactionCount: Math.floor(Math.random() * 50) + 1,
+ conversionRate: Math.floor(Math.random() * 100),
+ isDuplicate: Math.random() > 0.9,
+ mergedAccounts: [],
+ addStatus: ["not_added", "adding", "added", "failed"][
+ Math.floor(Math.random() * 4)
+ ] as any,
+ interactions,
+ };
+
+ return user;
+ });
+};
+
+const TrafficPoolList: React.FC = () => {
+ const navigate = useNavigate();
+
+ // 基础数据状态
+ const [users, setUsers] = useState([]);
+ const [devices] = useState(mockDevices);
+ const [wechatAccounts] = useState(mockWechatAccounts);
+ const [customerServices] = useState(mockCustomerServices);
+ const [trafficPools] = useState(mockTrafficPools);
+
+ // UI状态
+ const [loading, setLoading] = useState(false);
+ const [selectedUsers, setSelectedUsers] = useState([]);
+ const [showFilters, setShowFilters] = useState(false);
+ const [showAnalytics, setShowAnalytics] = useState(false);
+ const [hasMore, setHasMore] = useState(true);
+ const [page, setPage] = useState(1);
+
+ // 筛选状态
+ const [deviceFilter, setDeviceFilter] = useState("all");
+ const [poolFilter, setPoolFilter] = useState("all");
+ const [valuationFilter, setValuationFilter] = useState("all");
+ const [statusFilter, setStatusFilter] = useState("all");
+ const [searchQuery, setSearchQuery] = useState("");
+
+ // 初始化数据
+ useEffect(() => {
+ const mockUsers = generateMockUsers(
+ devices,
+ wechatAccounts,
+ customerServices,
+ trafficPools
+ );
+ setUsers(mockUsers);
+ }, [devices, wechatAccounts, customerServices, trafficPools]);
+
+ // 计算统计数据
+ const stats = {
+ total: users.length,
+ highValue: users.filter((u) => u.rfmScore.priority === "high").length,
+ mediumValue: users.filter((u) => u.rfmScore.priority === "medium").length,
+ lowValue: users.filter((u) => u.rfmScore.priority === "low").length,
+ duplicates: users.filter((u) => u.isDuplicate).length,
+ pending: users.filter((u) => u.status === "pending").length,
+ added: users.filter((u) => u.status === "added").length,
+ failed: users.filter((u) => u.status === "failed").length,
+ avgSpent: Math.round(
+ users.reduce((sum, u) => sum + u.totalSpent, 0) / users.length
+ ),
+ addSuccessRate: Math.round(
+ (users.filter((u) => u.status === "added").length / users.length) * 100
+ ),
+ duplicateRate: Math.round(
+ (users.filter((u) => u.isDuplicate).length / users.length) * 100
+ ),
+ };
+
+ // 过滤用户
+ const filteredUsers = users.filter((user) => {
+ const matchesSearch =
+ !searchQuery ||
+ user.nickname.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ user.wechatId.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ user.phone.includes(searchQuery);
+
+ const matchesDevice =
+ deviceFilter === "all" || user.deviceId === deviceFilter;
+ const matchesValuation =
+ valuationFilter === "all" || user.rfmScore.priority === valuationFilter;
+ const matchesStatus =
+ statusFilter === "all" || user.status === statusFilter;
+ const matchesPool =
+ poolFilter === "all" ||
+ (poolFilter === "none"
+ ? user.poolIds.length === 0
+ : user.poolIds.includes(poolFilter));
+
+ return (
+ matchesSearch &&
+ matchesDevice &&
+ matchesValuation &&
+ matchesStatus &&
+ matchesPool
+ );
+ });
+
+ // 按优先级排序
+ const sortedUsers = filteredUsers.sort((a, b) => {
+ const priorityOrder = { high: 3, medium: 2, low: 1 };
+ return (
+ priorityOrder[b.rfmScore.priority] - priorityOrder[a.rfmScore.priority]
+ );
+ });
+
+ // 分页数据
+ const pageSize = 20;
+ const paginatedUsers = sortedUsers.slice(0, page * pageSize);
+
+ // 处理用户选择
+ const handleUserSelect = useCallback((userId: string, checked: boolean) => {
+ setSelectedUsers((prev) =>
+ checked ? [...prev, userId] : prev.filter((id) => id !== userId)
+ );
+ }, []);
+
+ // 处理全选
+ const handleSelectAll = useCallback(
+ (checked: boolean) => {
+ if (checked) {
+ setSelectedUsers(paginatedUsers.map((user) => user.id));
+ } else {
+ setSelectedUsers([]);
+ }
+ },
+ [paginatedUsers]
+ );
+
+ // 重置筛选器
+ const resetFilters = useCallback(() => {
+ setDeviceFilter("all");
+ setPoolFilter("all");
+ setValuationFilter("all");
+ setStatusFilter("all");
+ setSearchQuery("");
+ setShowFilters(false);
+ }, []);
+
+ // 刷新数据
+ const handleRefresh = useCallback(() => {
+ setLoading(true);
+ setTimeout(() => {
+ const refreshedUsers = generateMockUsers(
+ devices,
+ wechatAccounts,
+ customerServices,
+ trafficPools
+ );
+ setUsers(refreshedUsers);
+ setLoading(false);
+ Toast.show({ content: "刷新成功" });
+ }, 800);
+ }, [devices, wechatAccounts, customerServices, trafficPools]);
+
+ // 添加到流量池
+ const handleAddToPool = useCallback(() => {
+ if (selectedUsers.length === 0) {
+ Toast.show({ content: "请先选择要添加到流量池的用户" });
+ return;
+ }
+ Toast.show({ content: `已将 ${selectedUsers.length} 个用户添加到流量池` });
+ setSelectedUsers([]);
+ }, [selectedUsers.length]);
+
+ // 加载更多
+ const loadMore = async () => {
+ if (page * pageSize >= sortedUsers.length) {
+ setHasMore(false);
+ return;
+ }
+ setPage((prev) => prev + 1);
+ };
+
+ // 辅助函数
+ const getWechatAccount = (accountId: string) => {
+ return wechatAccounts.find((acc) => acc.id === accountId);
+ };
+
+ const getCustomerService = (csId: string) => {
+ return customerServices.find((cs) => cs.id === csId);
+ };
+
+ const getDevice = (deviceId: string) => {
+ return devices.find((device) => device.id === deviceId);
+ };
+
+ const getPoolNames = (poolIds: string[]) => {
+ return poolIds
+ .map((id) => trafficPools.find((pool) => pool.id === id)?.name)
+ .filter(Boolean)
+ .join(", ");
+ };
+
+ const formatDate = (dateString: string) => {
+ if (!dateString) return "--";
+ try {
+ const date = new Date(dateString);
+ return date.toLocaleDateString("zh-CN");
+ } catch (error) {
+ return dateString;
+ }
+ };
+
+ const getStatusText = (status: string) => {
+ switch (status) {
+ case "added":
+ return "已添加";
+ case "pending":
+ return "未添加";
+ case "failed":
+ return "添加失败";
+ case "duplicate":
+ return "重复";
+ default:
+ return status;
+ }
+ };
+
+ const getStatusColor = (status: string) => {
+ switch (status) {
+ case "added":
+ return "success";
+ case "pending":
+ return "default";
+ case "failed":
+ return "danger";
+ case "duplicate":
+ return "warning";
+ default:
+ return "default";
+ }
+ };
+
+ return (
+
+
+
+
+ }
+ />
+ }
+ loading={loading}
+ >
+
+ {/* 数据分析面板 */}
+ {showAnalytics && (
+
+
+
+
+
{filteredUsers.length}
+
总用户数
+
+
+
+
+
+
{stats.highValue}
+
高价值用户
+
+
+
+
+
+ 添加效率
+
+
+
+ {stats.addSuccessRate}%
+
+
成功率
+
+
+
+ ¥{stats.avgSpent}
+
+
平均消费
+
+
+
+
+
+
{stats.pending}
+
待添加
+
+
+
{stats.failed}
+
添加失败
+
+
+
+
+ )}
+
+ {/* 搜索和筛选 */}
+
+
+
+
+
+ {/* 操作栏 */}
+
+
+ 0
+ }
+ onChange={handleSelectAll}
+ >
+ 全选
+
+ {selectedUsers.length > 0 && (
+
+ )}
+
+
+ 共 {filteredUsers.length} 个用户
+
+
+
+ {/* 用户列表 */}
+
+ {paginatedUsers.map((user) => {
+ const wechatAccount = getWechatAccount(user.wechatAccountId);
+ const customerService = getCustomerService(user.customerServiceId);
+ const device = getDevice(user.deviceId);
+
+ return (
+ navigate(`/traffic-pool/detail/${user.id}`)}
+ prefix={
+
+ handleUserSelect(user.id, checked)}
+ onClick={(e) => e.stopPropagation()}
+ />
+
+ }
+ arrow={false}
+ >
+
+
+
+
+ {user.nickname?.slice(0, 1) || "用户"}
+
+
+
+ {user.nickname}
+ {user.rfmScore.priority === "high" && (
+
+ )}
+
+
+ {user.wechatId}
+
+
+
+
+ {getStatusText(user.status)}
+
+
+
+
+
+
+ {device?.name || "设备0"}
+
+
+
+ {customerService?.name || "客服1"}
+
+
+
+
+ {user.tags.slice(0, 3).map((tag) => (
+
+ {tag.name}
+
+ ))}
+ {user.tags.length > 3 && (
+
+ +{user.tags.length - 3}
+
+ )}
+
+
+ {user.poolIds.length > 0 && (
+
+
+ {getPoolNames(user.poolIds)}
+
+ )}
+
+
+ );
+ })}
+
+
+ {/* 无限滚动 */}
+
+
+
+ {/* 筛选弹窗 */}
+ setShowFilters(false)}
+ position="right"
+ bodyStyle={{ width: "80vw" }}
+ >
+
+
+ 筛选选项
+
+
+
+
+
+
设备
+
({
+ label: `${device.name} - ${device.location}`,
+ value: device.id,
+ })),
+ ]}
+ value={[deviceFilter]}
+ onChange={(arr) => setDeviceFilter(arr[0])}
+ />
+
+
+
+
流量池
+
({
+ label: pool.name,
+ value: pool.id,
+ })),
+ ]}
+ value={[poolFilter]}
+ onChange={(arr) => setPoolFilter(arr[0])}
+ />
+
+
+
+
用户价值
+
setValuationFilter(arr[0])}
+ />
+
+
+
+
添加状态
+
setStatusFilter(arr[0])}
+ />
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default TrafficPoolList;
diff --git a/nkebao/src/pages/workspace/auto-like/list/api.ts b/nkebao/src/pages/workspace/auto-like/list/api.ts
index 34d4424a..fae08ec4 100644
--- a/nkebao/src/pages/workspace/auto-like/list/api.ts
+++ b/nkebao/src/pages/workspace/auto-like/list/api.ts
@@ -5,7 +5,7 @@ import {
UpdateLikeTaskData,
LikeRecord,
PaginatedResponse,
-} from "@/pages/workspace/auto-like/record/api";
+} from "@/pages/workspace/auto-like/record/data";
// 获取自动点赞任务列表
export function fetchAutoLikeTasks(
diff --git a/nkebao/src/pages/workspace/auto-like/list/index.tsx b/nkebao/src/pages/workspace/auto-like/list/index.tsx
index 9851eeaf..81f46d1d 100644
--- a/nkebao/src/pages/workspace/auto-like/list/index.tsx
+++ b/nkebao/src/pages/workspace/auto-like/list/index.tsx
@@ -23,7 +23,7 @@ import {
toggleAutoLikeTask,
copyAutoLikeTask,
} from "./api";
-import { LikeTask } from "@/pages/workspace/auto-like/record/api";
+import { LikeTask } from "@/pages/workspace/auto-like/record/data";
import style from "./index.module.scss";
// 卡片菜单组件
diff --git a/nkebao/src/pages/workspace/auto-like/new/api.ts b/nkebao/src/pages/workspace/auto-like/new/api.ts
index 703d7bb6..8a684aa3 100644
--- a/nkebao/src/pages/workspace/auto-like/new/api.ts
+++ b/nkebao/src/pages/workspace/auto-like/new/api.ts
@@ -3,7 +3,7 @@ import {
CreateLikeTaskData,
UpdateLikeTaskData,
LikeTask,
-} from "@/pages/workspace/auto-like/record/api";
+} from "@/pages/workspace/auto-like/record/data";
// 获取自动点赞任务详情
export function fetchAutoLikeTaskDetail(id: string): Promise {
diff --git a/nkebao/src/pages/workspace/auto-like/new/index.tsx b/nkebao/src/pages/workspace/auto-like/new/index.tsx
index 8d04bc0a..5ad689ea 100644
--- a/nkebao/src/pages/workspace/auto-like/new/index.tsx
+++ b/nkebao/src/pages/workspace/auto-like/new/index.tsx
@@ -15,7 +15,7 @@ import {
import {
CreateLikeTaskData,
ContentType,
-} from "@/pages/workspace/auto-like/record/api";
+} from "@/pages/workspace/auto-like/record/data";
import style from "./new.module.scss";
import MeauMobile from "@/components/MeauMobile/MeauMoible";
diff --git a/nkebao/src/pages/workspace/auto-like/record/api.ts b/nkebao/src/pages/workspace/auto-like/record/api.ts
index bace06ec..a0ffdfa5 100644
--- a/nkebao/src/pages/workspace/auto-like/record/api.ts
+++ b/nkebao/src/pages/workspace/auto-like/record/api.ts
@@ -1,119 +1,63 @@
-// 自动点赞任务状态
-export type LikeTaskStatus = 1 | 2; // 1: 开启, 2: 关闭
+import request from "@/api/request";
+import {
+ LikeTask,
+ CreateLikeTaskData,
+ UpdateLikeTaskData,
+ LikeRecord,
+ PaginatedResponse,
+} from "@/pages/workspace/auto-like/record/data";
-// 内容类型
-export type ContentType = "text" | "image" | "video" | "link";
-
-// 设备信息
-export interface Device {
- id: string;
- name: string;
- status: "online" | "offline";
- lastActive: string;
+// 获取自动点赞任务列表
+export function fetchAutoLikeTasks(
+ params = { type: 1, page: 1, limit: 100 }
+): Promise {
+ return request("/v1/workbench/list", params, "GET");
}
-// 好友信息
-export interface Friend {
- id: string;
- nickname: string;
- wechatId: string;
- avatar: string;
- tags: string[];
- region: string;
- source: string;
+// 获取单个任务详情
+export function fetchAutoLikeTaskDetail(id: string): Promise {
+ return request("/v1/workbench/detail", { id }, "GET");
}
-// 点赞记录
-export interface LikeRecord {
- id: string;
- workbenchId: string;
- momentsId: string;
- snsId: string;
- wechatAccountId: string;
- wechatFriendId: string;
- likeTime: string;
- content: string;
- resUrls: string[];
- momentTime: string;
- userName: string;
- operatorName: string;
- operatorAvatar: string;
- friendName: string;
- friendAvatar: string;
+// 创建自动点赞任务
+export function createAutoLikeTask(data: CreateLikeTaskData): Promise {
+ return request("/v1/workbench/create", { ...data, type: 1 }, "POST");
}
-// 自动点赞任务
-export interface LikeTask {
- id: string;
- name: string;
- status: LikeTaskStatus;
- deviceCount: number;
- targetGroup: string;
- likeCount: number;
- lastLikeTime: string;
- createTime: string;
- creator: string;
- likeInterval: number;
- maxLikesPerDay: number;
- timeRange: { start: string; end: string };
- contentTypes: ContentType[];
- targetTags: string[];
- devices: string[];
- friends: string[];
- friendMaxLikes: number;
- friendTags: string;
- enableFriendTags: boolean;
- todayLikeCount: number;
- totalLikeCount: number;
- updateTime: string;
+// 更新自动点赞任务
+export function updateAutoLikeTask(data: UpdateLikeTaskData): Promise {
+ return request("/v1/workbench/update", { ...data, type: 1 }, "POST");
}
-// 创建任务数据
-export interface CreateLikeTaskData {
- name: string;
- interval: number;
- maxLikes: number;
- startTime: string;
- endTime: string;
- contentTypes: ContentType[];
- devices: string[];
- friends?: string[];
- friendMaxLikes: number;
- friendTags?: string;
- enableFriendTags: boolean;
- targetTags: string[];
+// 删除自动点赞任务
+export function deleteAutoLikeTask(id: string): Promise {
+ return request("/v1/workbench/delete", { id }, "DELETE");
}
-// 更新任务数据
-export interface UpdateLikeTaskData extends CreateLikeTaskData {
- id: string;
+// 切换任务状态
+export function toggleAutoLikeTask(id: string, status: string): Promise {
+ return request("/v1/workbench/update-status", { id, status }, "POST");
}
-// 任务配置
-export interface TaskConfig {
- interval: number;
- maxLikes: number;
- startTime: string;
- endTime: string;
- contentTypes: ContentType[];
- devices: string[];
- friends: string[];
- friendMaxLikes: number;
- friendTags: string;
- enableFriendTags: boolean;
+// 复制自动点赞任务
+export function copyAutoLikeTask(id: string): Promise {
+ return request("/v1/workbench/copy", { id }, "POST");
}
-// API响应类型
-export interface ApiResponse {
- code: number;
- msg: string;
- data: T;
-}
-
-// 分页响应类型
-export interface PaginatedResponse {
- list: T[];
- total: number;
- page: number;
- limit: number;
+// 获取点赞记录
+export function fetchLikeRecords(
+ workbenchId: string,
+ page: number = 1,
+ limit: number = 20,
+ keyword?: string
+): Promise> {
+ const params: any = {
+ workbenchId,
+ page: page.toString(),
+ limit: limit.toString(),
+ };
+ if (keyword) {
+ params.keyword = keyword;
+ }
+ return request("/v1/workbench/like-records", params, "GET");
}
diff --git a/nkebao/src/pages/workspace/auto-like/record/data.ts b/nkebao/src/pages/workspace/auto-like/record/data.ts
index 122a093d..bace06ec 100644
--- a/nkebao/src/pages/workspace/auto-like/record/data.ts
+++ b/nkebao/src/pages/workspace/auto-like/record/data.ts
@@ -1,173 +1,119 @@
-import { request } from "../../../../api/request";
-import {
- LikeTask,
- CreateLikeTaskData,
- UpdateLikeTaskData,
- LikeRecord,
- ApiResponse,
- PaginatedResponse,
-} from "@/pages/workspace/auto-like/record/api";
+// 自动点赞任务状态
+export type LikeTaskStatus = 1 | 2; // 1: 开启, 2: 关闭
-// 获取自动点赞任务列表
-export async function fetchAutoLikeTasks(): Promise {
- try {
- const res = await request>>({
- url: "/v1/workbench/list",
- method: "GET",
- params: {
- type: 1,
- page: 1,
- limit: 100,
- },
- });
+// 内容类型
+export type ContentType = "text" | "image" | "video" | "link";
- if (res.code === 200 && res.data) {
- return res.data.list || [];
- }
- return [];
- } catch (error) {
- console.error("获取自动点赞任务失败:", error);
- return [];
- }
+// 设备信息
+export interface Device {
+ id: string;
+ name: string;
+ status: "online" | "offline";
+ lastActive: string;
}
-// 获取单个任务详情
-export async function fetchAutoLikeTaskDetail(
- id: string
-): Promise {
- try {
- console.log(`Fetching task detail for id: ${id}`);
- const res = await request({
- url: "/v1/workbench/detail",
- method: "GET",
- params: { id },
- });
- console.log("Task detail API response:", res);
-
- if (res.code === 200) {
- if (res.data) {
- if (typeof res.data === "object") {
- return res.data;
- } else {
- console.error(
- "Task detail API response data is not an object:",
- res.data
- );
- return null;
- }
- } else {
- console.error("Task detail API response missing data field:", res);
- return null;
- }
- }
-
- console.error("Task detail API error:", res.msg || "Unknown error");
- return null;
- } catch (error) {
- console.error("获取任务详情失败:", error);
- return null;
- }
+// 好友信息
+export interface Friend {
+ id: string;
+ nickname: string;
+ wechatId: string;
+ avatar: string;
+ tags: string[];
+ region: string;
+ source: string;
}
-// 创建自动点赞任务
-export async function createAutoLikeTask(
- data: CreateLikeTaskData
-): Promise {
- return request({
- url: "/v1/workbench/create",
- method: "POST",
- data: {
- ...data,
- type: 1, // 自动点赞类型
- },
- });
+// 点赞记录
+export interface LikeRecord {
+ id: string;
+ workbenchId: string;
+ momentsId: string;
+ snsId: string;
+ wechatAccountId: string;
+ wechatFriendId: string;
+ likeTime: string;
+ content: string;
+ resUrls: string[];
+ momentTime: string;
+ userName: string;
+ operatorName: string;
+ operatorAvatar: string;
+ friendName: string;
+ friendAvatar: string;
}
-// 更新自动点赞任务
-export async function updateAutoLikeTask(
- data: UpdateLikeTaskData
-): Promise {
- return request({
- url: "/v1/workbench/update",
- method: "POST",
- data: {
- ...data,
- type: 1, // 自动点赞类型
- },
- });
+// 自动点赞任务
+export interface LikeTask {
+ id: string;
+ name: string;
+ status: LikeTaskStatus;
+ deviceCount: number;
+ targetGroup: string;
+ likeCount: number;
+ lastLikeTime: string;
+ createTime: string;
+ creator: string;
+ likeInterval: number;
+ maxLikesPerDay: number;
+ timeRange: { start: string; end: string };
+ contentTypes: ContentType[];
+ targetTags: string[];
+ devices: string[];
+ friends: string[];
+ friendMaxLikes: number;
+ friendTags: string;
+ enableFriendTags: boolean;
+ todayLikeCount: number;
+ totalLikeCount: number;
+ updateTime: string;
}
-// 删除自动点赞任务
-export async function deleteAutoLikeTask(id: string): Promise {
- return request({
- url: "/v1/workbench/delete",
- method: "DELETE",
- params: { id },
- });
+// 创建任务数据
+export interface CreateLikeTaskData {
+ name: string;
+ interval: number;
+ maxLikes: number;
+ startTime: string;
+ endTime: string;
+ contentTypes: ContentType[];
+ devices: string[];
+ friends?: string[];
+ friendMaxLikes: number;
+ friendTags?: string;
+ enableFriendTags: boolean;
+ targetTags: string[];
}
-// 切换任务状态
-export async function toggleAutoLikeTask(
- id: string,
- status: string
-): Promise {
- return request({
- url: "/v1/workbench/update-status",
- method: "POST",
- data: { id, status },
- });
+// 更新任务数据
+export interface UpdateLikeTaskData extends CreateLikeTaskData {
+ id: string;
}
-// 复制自动点赞任务
-export async function copyAutoLikeTask(id: string): Promise {
- return request({
- url: "/v1/workbench/copy",
- method: "POST",
- data: { id },
- });
+// 任务配置
+export interface TaskConfig {
+ interval: number;
+ maxLikes: number;
+ startTime: string;
+ endTime: string;
+ contentTypes: ContentType[];
+ devices: string[];
+ friends: string[];
+ friendMaxLikes: number;
+ friendTags: string;
+ enableFriendTags: boolean;
}
-// 获取点赞记录
-export async function fetchLikeRecords(
- workbenchId: string,
- page: number = 1,
- limit: number = 20,
- keyword?: string
-): Promise> {
- try {
- const params: any = {
- workbenchId,
- page: page.toString(),
- limit: limit.toString(),
- };
-
- if (keyword) {
- params.keyword = keyword;
- }
-
- const res = await request>>({
- url: "/v1/workbench/records",
- method: "GET",
- params,
- });
-
- if (res.code === 200 && res.data) {
- return res.data;
- }
-
- return {
- list: [],
- total: 0,
- page: 1,
- limit: 20,
- };
- } catch (error) {
- console.error("获取点赞记录失败:", error);
- return {
- list: [],
- total: 0,
- page: 1,
- limit: 20,
- };
- }
+// API响应类型
+export interface ApiResponse {
+ code: number;
+ msg: string;
+ data: T;
+}
+
+// 分页响应类型
+export interface PaginatedResponse {
+ list: T[];
+ total: number;
+ page: number;
+ limit: number;
}
diff --git a/nkebao/src/pages/workspace/auto-like/record/index.tsx b/nkebao/src/pages/workspace/auto-like/record/index.tsx
index 5ccc5ce4..9bd51eda 100644
--- a/nkebao/src/pages/workspace/auto-like/record/index.tsx
+++ b/nkebao/src/pages/workspace/auto-like/record/index.tsx
@@ -1,20 +1,27 @@
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
-import { NavBar, Button, Toast, SpinLoading, Card, Avatar } from "antd-mobile";
-import { Input } from "antd";
-import InfiniteList from "@/components/InfiniteList/InfiniteList";
import {
- SearchOutlined,
- ReloadOutlined,
+ Button,
+ Input,
+ Card,
+ Badge,
+ Avatar,
+ Skeleton,
+ message,
+ Spin,
+ Divider,
+ Pagination,
+} from "antd";
+import {
LikeOutlined,
+ ReloadOutlined,
+ SearchOutlined,
UserOutlined,
} from "@ant-design/icons";
-
+import styles from "./record.module.scss";
+import NavCommon from "@/components/NavCommon";
+import { fetchLikeRecords } from "./api";
import Layout from "@/components/Layout/Layout";
-import MeauMobile from "@/components/MeauMobile/MeauMoible";
-import { fetchLikeRecords, fetchAutoLikeTaskDetail } from "./data";
-import { LikeRecord, LikeTask } from "./api";
-import style from "./record.module.scss";
// 格式化日期
const formatDate = (dateString: string) => {
@@ -32,264 +39,271 @@ const formatDate = (dateString: string) => {
}
};
-const AutoLikeDetail: React.FC = () => {
+export default function AutoLikeRecord() {
const { id } = useParams<{ id: string }>();
- const [records, setRecords] = useState([]);
- const [taskDetail, setTaskDetail] = useState(null);
+ const [records, setRecords] = useState([]);
const [recordsLoading, setRecordsLoading] = useState(false);
- const [taskLoading, setTaskLoading] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [total, setTotal] = useState(0);
- const [hasMore, setHasMore] = useState(true);
const pageSize = 10;
- // 获取任务详情
- const fetchTaskDetail = async () => {
- if (!id) return;
- setTaskLoading(true);
- try {
- const detail = await fetchAutoLikeTaskDetail(id);
- setTaskDetail(detail);
- } catch (error) {
- Toast.show({
- content: "获取任务详情失败",
- position: "top",
- });
- } finally {
- setTaskLoading(false);
- }
- };
-
- // 获取点赞记录
- const fetchRecords = async (
- page: number = 1,
- isLoadMore: boolean = false
- ) => {
- if (!id) return;
-
- if (!isLoadMore) {
- setRecordsLoading(true);
- }
-
- try {
- const response = await fetchLikeRecords(id, page, pageSize, searchTerm);
- const newRecords = response.list || [];
-
- if (isLoadMore) {
- setRecords((prev) => [...prev, ...newRecords]);
- } else {
- setRecords(newRecords);
- }
-
- setTotal(response.total || 0);
- setCurrentPage(page);
- setHasMore(newRecords.length === pageSize);
- } catch (error) {
- Toast.show({
- content: "获取点赞记录失败",
- position: "top",
- });
- } finally {
- setRecordsLoading(false);
- }
- };
-
useEffect(() => {
- fetchTaskDetail();
- fetchRecords(1, false);
+ if (!id) return;
+ setRecordsLoading(true);
+ fetchLikeRecords(id, 1, pageSize)
+ .then((response: any) => {
+ setRecords(response.list || []);
+ setTotal(response.total || 0);
+ setCurrentPage(1);
+ })
+ .catch(() => {
+ message.error("获取点赞记录失败,请稍后重试");
+ })
+ .finally(() => setRecordsLoading(false));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
const handleSearch = () => {
setCurrentPage(1);
- fetchRecords(1, false);
+ fetchLikeRecords(id!, 1, pageSize, searchTerm)
+ .then((response: any) => {
+ setRecords(response.list || []);
+ setTotal(response.total || 0);
+ setCurrentPage(1);
+ })
+ .catch(() => {
+ message.error("获取点赞记录失败,请稍后重试");
+ });
};
const handleRefresh = () => {
- fetchRecords(currentPage, false);
+ fetchLikeRecords(id!, currentPage, pageSize, searchTerm)
+ .then((response: any) => {
+ setRecords(response.list || []);
+ setTotal(response.total || 0);
+ })
+ .catch(() => {
+ message.error("获取点赞记录失败,请稍后重试");
+ });
};
- const handleLoadMore = async () => {
- if (hasMore && !recordsLoading) {
- await fetchRecords(currentPage + 1, true);
- }
+ const handlePageChange = (newPage: number) => {
+ fetchLikeRecords(id!, newPage, pageSize, searchTerm)
+ .then((response: any) => {
+ setRecords(response.list || []);
+ setTotal(response.total || 0);
+ setCurrentPage(newPage);
+ })
+ .catch(() => {
+ message.error("获取点赞记录失败,请稍后重试");
+ });
};
- const renderRecordItem = (record: LikeRecord) => (
-
-
-
-
}
- />
-
-
- {record.friendName}
-
-
内容发布者
-
-
-
- {formatDate(record.momentTime || record.likeTime)}
-
-
-
-
- {record.content && (
-
{record.content}
- )}
-
- {Array.isArray(record.resUrls) && record.resUrls.length > 0 && (
-
- {record.resUrls.slice(0, 9).map((image: string, idx: number) => (
-
-

-
- ))}
-
- )}
-
-
-
-
}
- />
-
-
- {record.operatorName}
-
- 点赞了这条内容
-
-
-
- );
-
return (
window.history.back()}
- left={
-
- 点赞记录
-
- }
- />
- }
- footer={}
- >
-
- {/* 任务信息卡片 */}
- {taskDetail && (
-
-
-
{taskDetail.name}
-
- {Number(taskDetail.status) === 1 ? "进行中" : "已暂停"}
-
-
-
-
-
- 今日点赞:
-
- {taskDetail.todayLikeCount || 0}
-
-
-
-
- 总点赞数:
-
- {taskDetail.totalLikeCount || 0}
-
-
-
-
- )}
-
- {/* 搜索区域 */}
-
-
-
-
+ <>
+
+
+
}
placeholder="搜索好友昵称或内容"
- className={style["search-input"]}
+ className={styles.headerSearchInput}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onPressEnter={handleSearch}
+ allowClear
/>
-
}
onClick={handleRefresh}
- disabled={recordsLoading}
- >
-
-
+ loading={recordsLoading}
+ type="default"
+ shape="circle"
+ />
-
-
- {/* 记录列表 */}
-
- {recordsLoading && currentPage === 1 ? (
-
-
-
加载中...
+ >
+ }
+ footer={
+ <>
+
+
+ `第 ${range[0]}-${range[1]} 条,共 ${total} 条`
+ }
+ size="default"
+ className={styles.pagination}
+ />
+
+ >
+ }
+ >
+
+
+ {recordsLoading ? (
+
+ {Array.from({ length: 3 }).map((_, index) => (
+
+ ))}
) : records.length === 0 ? (
-
-
-
暂无点赞记录
+
) : (
-
+ <>
+ {records.map((record) => (
+
+
+
+
}
+ size={40}
+ className={styles.avatarImg}
+ />
+
+
+ {record.friendName}
+
+
内容发布者
+
+
+
+
+
+
+ {record.content && (
+
{record.content}
+ )}
+ {Array.isArray(record.resUrls) &&
+ record.resUrls.length > 0 && (
+
+ {record.resUrls
+ .slice(0, 9)
+ .map((image: string, idx: number) => (
+
+

+
+ ))}
+
+ )}
+
+
+
}
+ size={32}
+ className={styles.operatorAvatar}
+ />
+
+
+ {record.operatorName}
+
+
+
+ 已赞
+
+
+
+
+ ))}
+ >
)}
);
-};
-
-export default AutoLikeDetail;
+}
diff --git a/nkebao/src/pages/workspace/auto-like/record/record.module.scss b/nkebao/src/pages/workspace/auto-like/record/record.module.scss
index 9bc931b6..ae062d02 100644
--- a/nkebao/src/pages/workspace/auto-like/record/record.module.scss
+++ b/nkebao/src/pages/workspace/auto-like/record/record.module.scss
@@ -1,351 +1,266 @@
-.detail-page {
- background: #f5f5f5;
- min-height: 100vh;
- padding-bottom: 80px;
-}
-
-.task-info-card {
- background: white;
- margin: 16px;
- border-radius: 8px;
- padding: 16px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.task-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 16px;
-}
-
-.task-name {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin: 0;
-}
-
-.task-status {
- padding: 2px 8px;
- border-radius: 4px;
- font-size: 12px;
- font-weight: 500;
-
- &.active {
- background: #f6ffed;
- color: #52c41a;
- border: 1px solid #b7eb8f;
- }
-
- &.inactive {
- background: #f5f5f5;
- color: #666;
- border: 1px solid #d9d9d9;
- }
-}
-
-.task-stats {
- display: flex;
- justify-content: space-between;
- gap: 16px;
-}
-
-.stat-item {
- display: flex;
- align-items: center;
- gap: 6px;
- font-size: 14px;
- color: #666;
-}
-
-.stat-icon {
- font-size: 16px;
- color: #1890ff;
-}
-
-.stat-label {
- font-weight: 500;
-}
-
-.stat-value {
- color: #333;
- font-weight: 600;
-}
-
-.search-section {
- padding: 0 16px 16px;
-}
-
-.search-wrapper {
+// 搜索栏
+.headerSearchBar {
display: flex;
align-items: center;
gap: 8px;
- background: white;
- border-radius: 8px;
- padding: 12px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ padding: 16px;
}
-
-.search-input-wrapper {
+.headerSearchInputWrap {
position: relative;
flex: 1;
}
-
-.search-input {
- width: 100%;
- height: 36px;
- padding: 0 12px 0 32px;
- border: 1px solid #d9d9d9;
- border-radius: 6px;
- font-size: 14px;
-
- &:focus {
- border-color: #1890ff;
- box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
- outline: none;
- }
-}
-
-.search-icon {
+.headerSearchIcon {
position: absolute;
- left: 8px;
- top: 50%;
- transform: translateY(-50%);
- color: #999;
- font-size: 14px;
+ left: 12px;
+ top: 10px;
+ width: 16px;
+ height: 16px;
+ color: #a3a3a3;
+}
+.headerSearchInput {
+ padding-left: 32px !important;
+}
+.spin {
+ animation: spin 1s linear infinite;
+}
+@keyframes spin {
+ 100% { transform: rotate(360deg); }
}
-.search-btn {
- height: 36px;
- padding: 0 12px;
- border-radius: 6px;
- font-size: 14px;
- white-space: nowrap;
-}
-
-.refresh-btn {
- height: 36px;
- width: 36px;
- padding: 0;
- border-radius: 6px;
+// 分页
+.footerPagination {
display: flex;
- align-items: center;
justify-content: center;
- border: 1px solid #d9d9d9;
- background: white;
- cursor: pointer;
- transition: all 0.2s;
-
- &:hover {
+ align-items: center;
+ padding: 12px 0;
+ background: #fff;
+}
+.pagination {
+ :global(.ant-pagination-item) {
+ border-radius: 6px;
+ }
+ :global(.ant-pagination-item-active) {
+ background: #1890ff;
border-color: #1890ff;
- color: #1890ff;
}
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
+ :global(.ant-pagination-prev),
+ :global(.ant-pagination-next) {
+ border-radius: 6px;
+ }
+ :global(.ant-pagination-jump-prev),
+ :global(.ant-pagination-jump-next) {
+ border-radius: 6px;
}
}
-.records-section {
- padding: 0 16px;
+// 背景和内容
+.bgWrap {
+ background: #f7f7fa;
+ min-height: 100vh;
+ padding-bottom: 80px;
}
-
-.records-list {
+.contentWrap {
+ padding: 12px;
display: flex;
flex-direction: column;
+ gap: 16px;
+}
+
+// 骨架屏
+.skeletonWrap {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+.skeletonCard {
+ padding: 0px;
+}
+.skeletonCardHeader {
+ display: flex;
+ align-items: center;
gap: 12px;
+ margin-bottom: 12px;
}
-
-.record-card {
- background: white;
+.skeletonAvatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+}
+.skeletonNameWrap {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+.skeletonName {
+ width: 96px;
+ height: 16px;
+}
+.skeletonSub {
+ width: 64px;
+ height: 12px;
+}
+.skeletonSep {
+ margin: 12px 0;
+}
+.skeletonContentWrap {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+.skeletonContent1 {
+ width: 100%;
+ height: 16px;
+}
+.skeletonContent2 {
+ width: 75%;
+ height: 16px;
+}
+.skeletonImgWrap {
+ display: flex;
+ gap: 8px;
+ margin-top: 12px;
+}
+.skeletonImg {
+ width: 80px;
+ height: 80px;
border-radius: 8px;
- padding: 16px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
-.record-header {
+// 空状态
+.emptyWrap {
+ text-align: center;
+ padding: 48px 0;
+}
+.emptyIcon {
+ width: 48px;
+ height: 48px;
+ color: #e5e7eb;
+ margin: 0 auto 12px auto;
+}
+.emptyText {
+ color: #888;
+ font-size: 16px;
+}
+
+// 记录卡片
+.recordCard {
+ background: #fff;
+ border-radius: 16px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.04);
+ padding: 16px;
+}
+.recordCardHeader {
display: flex;
align-items: flex-start;
justify-content: space-between;
- margin-bottom: 12px;
}
-
-.user-info {
+.recordCardHeaderLeft {
display: flex;
align-items: center;
gap: 12px;
max-width: 65%;
}
-
-.user-avatar {
+.avatarImg {
width: 40px;
height: 40px;
border-radius: 50%;
- flex-shrink: 0;
}
-
-.user-details {
+.friendInfo {
min-width: 0;
}
-
-.user-name {
- font-size: 14px;
- font-weight: 600;
- color: #333;
+.friendName {
+ font-weight: 500;
+ white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- white-space: nowrap;
}
-
-.user-role {
- font-size: 12px;
- color: #666;
- margin-top: 2px;
+.friendSub {
+ font-size: 13px;
+ color: #888;
}
-
-.record-time {
- font-size: 12px;
- color: #666;
- background: #f8f9fa;
- padding: 4px 8px;
- border-radius: 4px;
+.timeBadge {
+ background: #e8f0fe;
white-space: nowrap;
flex-shrink: 0;
}
-
-.record-content {
+.cardSep {
+ margin: 12px 0;
+}
+.cardContent {
margin-bottom: 12px;
}
-
-.content-text {
- font-size: 14px;
- color: #333;
- line-height: 1.5;
+.contentText {
+ color: #444;
margin-bottom: 12px;
white-space: pre-line;
}
-
-.content-images {
+.imgGrid {
display: grid;
- gap: 4px;
-
- &.single {
- grid-template-columns: 1fr;
- }
-
- &.double {
- grid-template-columns: 1fr 1fr;
- }
-
- &.multiple {
- grid-template-columns: repeat(3, 1fr);
- }
+ gap: 8px;
}
-
-.image-item {
- aspect-ratio: 1;
- border-radius: 6px;
+.grid1 {
+ grid-template-columns: 1fr;
+}
+.grid2 {
+ grid-template-columns: 1fr 1fr;
+}
+.grid3 {
+ grid-template-columns: 1fr 1fr 1fr;
+}
+.grid6 {
+ grid-template-columns: 1fr 1fr 1fr;
+ grid-template-rows: 1fr 1fr;
+}
+.grid9 {
+ grid-template-columns: 1fr 1fr 1fr;
+ grid-template-rows: 1fr 1fr 1fr;
+}
+.imgItem {
+ position: relative;
+ aspect-ratio: 1/1;
+ border-radius: 8px;
overflow: hidden;
}
-
-.content-image {
+.img {
width: 100%;
height: 100%;
object-fit: cover;
}
-.like-info {
+// 操作人
+.operatorWrap {
display: flex;
align-items: center;
- gap: 8px;
- padding: 8px 12px;
- background: #f8f9fa;
- border-radius: 6px;
+ margin-top: 16px;
+ padding: 8px;
+ background: #f3f4f6;
+ border-radius: 8px;
}
-
-.operator-avatar {
- width: 32px;
- height: 32px;
- border-radius: 50%;
+.operatorAvatar {
+ width: 32px !important;
+ height: 32px !important;
+ margin-right: 8px;
flex-shrink: 0;
}
-
-.like-text {
+.operatorInfo {
font-size: 14px;
- color: #666;
- min-width: 0;
+ position: relative;
+ flex: 1;
+ position: relative;
}
-
-.operator-name {
- font-weight: 600;
- color: #333;
+.operatorName {
+ font-weight: 500;
+ max-width: 100%;
+ display: inline-block;
+ white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- white-space: nowrap;
- display: inline-block;
- max-width: 100%;
}
-
-.like-action {
- margin-left: 4px;
+.operatorAction {
+ color: #888;
+ margin-left: 8px;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ top: 2px;
}
-
-.loading {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- height: 60vh;
- gap: 16px;
-}
-
-.loading-text {
- color: #666;
- font-size: 14px;
-}
-
-.empty-state {
- text-align: center;
- padding: 60px 20px;
- color: #666;
-}
-
-.empty-icon {
- font-size: 48px;
- color: #d9d9d9;
- margin-bottom: 16px;
-}
-
-.empty-text {
- font-size: 16px;
- color: #999;
-}
-
-// 移动端适配
-@media (max-width: 768px) {
- .task-stats {
- flex-direction: column;
- gap: 12px;
- }
-
- .search-wrapper {
- flex-direction: column;
- gap: 12px;
- }
-
- .search-btn {
- width: 100%;
- }
-
- .user-info {
- max-width: 60%;
- }
-
- .content-images {
- &.multiple {
- grid-template-columns: repeat(2, 1fr);
- }
- }
-}
\ No newline at end of file
diff --git a/nkebao/src/router/module/traffic-pool.tsx b/nkebao/src/router/module/traffic-pool.tsx
index d0dcd70d..99872ab7 100644
--- a/nkebao/src/router/module/traffic-pool.tsx
+++ b/nkebao/src/router/module/traffic-pool.tsx
@@ -1,5 +1,5 @@
-import TrafficPool from "@/pages/traffic-pool/TrafficPool";
-import TrafficPoolDetail from "@/pages/traffic-pool/TrafficPoolDetail";
+import TrafficPool from "@/pages/traffic-pool/list/index";
+import TrafficPoolDetail from "@/pages/traffic-pool/detail/index";
const trafficPoolRoutes = [
{