From dce691037166f309deca321e6f3241e372567069 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: Tue, 29 Jul 2025 19:08:50 +0800 Subject: [PATCH] =?UTF-8?q?FEAT=20=3D>=20=E6=9C=AC=E6=AC=A1=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=A1=B9=E7=9B=AE=E4=B8=BA=EF=BC=9A=20=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nkebao/.env.development | 5 +- .../mobile/mine/traffic-pool/detail/api.ts | 24 +- .../mobile/mine/traffic-pool/detail/data.ts | 66 +- .../traffic-pool/detail/index.module.scss | 711 +++++++++++------- .../mobile/mine/traffic-pool/detail/index.tsx | 662 +++++++++++----- .../mobile/mine/traffic-pool/list/index.tsx | 2 +- nkebao/src/router/module/mine.tsx | 2 +- nkebao/tsconfig.json | 48 +- 8 files changed, 1018 insertions(+), 502 deletions(-) diff --git a/nkebao/.env.development b/nkebao/.env.development index 3b39062c..616d7ebb 100644 --- a/nkebao/.env.development +++ b/nkebao/.env.development @@ -1,6 +1,5 @@ # 基础环境变量示例 -VITE_API_BASE_URL=http://www.yishi.com -# VITE_API_BASE_URL=https://ckbapi.quwanzhi.com +# VITE_API_BASE_URL=http://www.yishi.com +VITE_API_BASE_URL=https://ckbapi.quwanzhi.com VITE_APP_TITLE=Nkebao Base - diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts b/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts index 84574235..0bbaec1f 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts @@ -1,5 +1,27 @@ import request from "@/api/request"; +import type { TrafficPoolUserDetail, UserJourneyResponse } from "./data"; -export function getTrafficPoolDetail(wechatId: string): Promise { +export function getTrafficPoolDetail( + wechatId: string +): Promise { return request("/v1/wechats/getWechatInfo", { wechatId }, "GET"); } + +// 获取用户旅程记录 +export function getUserJourney(params: { + page: number; + pageSize: number; + userId: string; +}): Promise { + return request("/v1/traffic/pool/getUserJourney", params, "GET"); +} + +// 获取用户标签 +export function getUserTags(userId: string): Promise { + return request("/v1/user/tags", { userId }, "GET"); +} + +// 添加用户标签 +export function addUserTag(userId: string, tagData: any): Promise { + return request("/v1/user/tags", { userId, ...tagData }, "POST"); +} diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts b/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts index fb149007..1e274f63 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts @@ -1,4 +1,4 @@ -// 用户详情类型 +// 用户详情类型 - 基于实际API返回数据 export interface TrafficPoolUserDetail { userInfo: { wechatId: string; @@ -44,3 +44,67 @@ export interface TrafficPoolUserDetail { reason: string; }>; } + +// 用户旅程记录类型 +export interface UserJourneyRecord { + id: number; + type: number; // 0-浏览, 2-提交订单, 3-注册 + trafficPoolId: number; + remark: string; + count: number; + createTime: string; + updateTime: string; +} + +// 用户旅程响应类型 +export interface UserJourneyResponse { + list: UserJourneyRecord[]; + total: number; +} + +// 扩展的用户详情类型 - 用于前端展示 +export interface ExtendedUserDetail extends TrafficPoolUserDetail { + // 前端计算或模拟的数据 + rfmScore?: { + recency: number; + frequency: number; + monetary: number; + totalScore: number; + }; + trafficPools?: { + currentPool: string; + availablePools: string[]; + }; + userJourney?: InteractionRecord[]; + userTags?: UserTag[]; + valueTags?: ValueTag[]; +} + +// 用户标签 +export interface UserTag { + id: string; + name: string; + color: string; + icon?: string; + type: "user" | "value"; +} + +// 价值标签 +export interface ValueTag { + id: string; + name: string; + color: string; + icon?: string; + rfmScore: number; + valueLevel: string; +} + +// 互动记录 +export interface InteractionRecord { + id: string; + type: "click" | "view" | "purchase"; + action: string; + description: string; + timestamp: string; + icon: string; +} diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss index a3833543..60165acb 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss @@ -1,291 +1,420 @@ -.container { - padding: 12px; - background: #f5f5f5; - min-height: 100vh; -} - -.userCard { - margin-bottom: 12px; - border-radius: 12px; - overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); -} - -.userInfo { - display: flex; - align-items: center; - gap: 16px; - padding: 16px; -} - -.avatar { - width: 64px; - height: 64px; - border-radius: 50%; - flex-shrink: 0; -} - -.userDetails { - flex: 1; - min-width: 0; -} - -.nickname { - font-size: 18px; - font-weight: 600; - color: #333; - margin-bottom: 4px; - line-height: 1.2; -} - -.wechatId { - font-size: 14px; - color: #1677ff; - margin-bottom: 4px; - line-height: 1.2; -} - -.alias { - font-size: 12px; - color: #666; - margin-bottom: 8px; - line-height: 1.2; -} - -.tags { - display: flex; - flex-wrap: wrap; - gap: 6px; -} - -.genderTag { - font-size: 12px; - padding: 2px 8px; - border-radius: 12px; -} - -.weightTag { - font-size: 12px; - padding: 2px 8px; - border-radius: 12px; -} - -.tabs { - background: transparent; - - :global(.adm-tabs-header) { - background: white; - border-radius: 12px 12px 0 0; - margin-bottom: 0; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - } - - :global(.adm-tabs-tab) { - font-size: 14px; - font-weight: 500; - } - - :global(.adm-tabs-tab-active) { - color: #1677ff; - } - - :global(.adm-tabs-tab-line) { - background: #1677ff; - } - - :global(.adm-tabs-content) { - background: white; - border-radius: 0 0 12px 12px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - } -} - -.tabContent { - padding: 16px; -} - -.infoCard { - margin-bottom: 12px; - border-radius: 8px; - overflow: hidden; - - &:last-child { - margin-bottom: 0; - } - - :global(.adm-card-header) { - padding: 12px 16px; - border-bottom: 1px solid #f0f0f0; - font-size: 14px; - font-weight: 600; - color: #333; - } - - :global(.adm-card-body) { - padding: 0; - } -} - -.statsGrid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 16px; - padding: 16px; -} - -.statItem { - text-align: center; -} - -.statValue { - font-size: 18px; - font-weight: 700; - line-height: 1.2; - margin-bottom: 4px; -} - -.statLabel { - font-size: 12px; - color: #666; - line-height: 1.2; -} - -.restrictionTitle { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - font-size: 14px; - font-weight: 500; - color: #333; - line-height: 1.4; -} - -.restrictionLevel { - font-size: 10px; - padding: 2px 6px; - border-radius: 8px; - flex-shrink: 0; -} - -.restrictionContent { - display: flex; - flex-direction: column; - gap: 4px; - font-size: 12px; - color: #666; - line-height: 1.4; - margin-top: 4px; -} - -.emptyState { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 48px 16px; - text-align: center; -} - -.emptyText { - color: #999; - font-size: 14px; - line-height: 1.4; -} - -// 响应式设计 -@media (max-width: 375px) { - .container { - padding: 8px; - } - - .userInfo { - padding: 12px; - gap: 12px; - } - - .avatar { - width: 56px; - height: 56px; - } - - .nickname { - font-size: 16px; - } - - .wechatId { - font-size: 13px; - } - - .alias { - font-size: 11px; - } - - .tabContent { - padding: 12px; - } - - .statsGrid { - gap: 12px; - padding: 12px; - } - - .statValue { - font-size: 16px; - } - - .restrictionTitle { - font-size: 13px; - } - - .restrictionContent { - font-size: 11px; - } -} - -// 暗色模式支持 -@media (prefers-color-scheme: dark) { - .container { - background: #1a1a1a; - } - - .userCard, - .tabs :global(.adm-tabs-header), - .tabs :global(.adm-tabs-content) { - background: #2a2a2a; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); - } - - .nickname { - color: #fff; - } - - .wechatId { - color: #4a9eff; - } - - .alias { - color: #999; - } - - .infoCard :global(.adm-card-header) { - color: #fff; - border-bottom-color: #3a3a3a; - } - - .statLabel { - color: #999; - } - - .restrictionTitle { - color: #fff; - } - - .restrictionContent { - color: #999; - } - - .emptyText { - color: #666; - } -} +.container { + padding: 0; + background: #f5f5f5; + min-height: 100vh; +} + +// 头部样式 +.header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px; + background: #fff; + border-bottom: 1px solid #f0f0f0; + + .title { + font-size: 18px; + font-weight: 600; + color: #333; + } + + .closeBtn { + padding: 8px; + border: none; + background: transparent; + color: #999; + font-size: 16px; + } +} + +// 用户卡片 +.userCard { + margin: 16px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + .userInfo { + display: flex; + align-items: flex-start; + gap: 16px; + } + + .avatar { + width: 60px; + height: 60px; + border-radius: 50%; + flex-shrink: 0; + } + + .userDetails { + flex: 1; + min-width: 0; + } + + .nickname { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 4px; + } + + .wechatId { + font-size: 14px; + color: #666; + margin-bottom: 8px; + } + + .tags { + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .userTag { + font-size: 12px; + padding: 4px 8px; + border-radius: 12px; + } +} + +// 标签导航 +.tabNav { + display: flex; + background: #fff; + margin: 0 16px; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + + .tabItem { + flex: 1; + padding: 12px 16px; + text-align: center; + font-size: 14px; + color: #666; + cursor: pointer; + transition: all 0.3s ease; + border-bottom: 2px solid transparent; + + &.active { + color: var(--primary-color); + border-bottom-color: var(--primary-color); + background: rgba(24, 142, 238, 0.05); + } + + &:hover { + background: rgba(24, 142, 238, 0.05); + } + } +} + +// 内容区域 +.content { + padding: 16px; +} + +.tabContent { + display: flex; + flex-direction: column; + gap: 16px; +} + +// 信息卡片 +.infoCard { + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; + + :global(.adm-card-header) { + padding: 16px; + border-bottom: 1px solid #f0f0f0; + font-weight: 600; + color: #333; + } + + :global(.adm-card-body) { + padding: 0; + } +} + +// RFM评分网格 +.rfmGrid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; + padding: 16px; +} + +.rfmItem { + text-align: center; + padding: 12px; + background: #f8f9fa; + border-radius: 8px; +} + +.rfmLabel { + font-size: 12px; + color: #666; + margin-bottom: 4px; +} + +.rfmValue { + font-size: 18px; + font-weight: 600; +} + +// 流量池区域 +.poolSection { + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.currentPool, +.availablePools { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.poolLabel { + font-size: 14px; + color: #666; + white-space: nowrap; +} + +// 统计数据网格 +.statsGrid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; + padding: 16px; +} + +.statItem { + text-align: center; + padding: 12px; + background: #f8f9fa; + border-radius: 8px; +} + +.statValue { + font-size: 18px; + font-weight: 600; + margin-bottom: 4px; +} + +.statLabel { + font-size: 12px; + color: #666; +} + +// 用户旅程 +.journeyItem { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 12px; + color: #666; + margin-top: 4px; +} + +.timestamp { + color: #999; +} + +// 加载状态 +.loadingContainer { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 16px; + text-align: center; +} + +.loadingText { + font-size: 14px; + color: #999; + margin-top: 8px; +} + +.loadingMore { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 16px; + color: #666; + font-size: 14px; +} + +.loadMoreBtn { + display: flex; + justify-content: center; + padding: 16px; +} + +// 标签区域 +.tagsSection { + padding: 16px; + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.valueTagsSection { + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.tagItem { + font-size: 12px; + padding: 6px 12px; + border-radius: 16px; +} + +.valueTagContainer { + display: flex; + flex-direction: column; + gap: 8px; +} + +.valueTagRow { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.rfmScoreText { + font-size: 12px; + color: #666; + white-space: nowrap; +} + +.valueLevelLabel { + font-size: 12px; + color: #666; + white-space: nowrap; +} + +.valueTagItem { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #f0f0f0; + + &:last-child { + border-bottom: none; + } +} + +.valueInfo { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: #666; +} + +// 添加标签按钮 +.addTagBtn { + margin-top: 16px; + border-radius: 8px; + height: 48px; + font-size: 16px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +} + +// 空状态 +.emptyState { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60px 16px; + text-align: center; +} + +.emptyIcon { + margin-bottom: 16px; + opacity: 0.6; +} + +.emptyText { + font-size: 16px; + color: #666; + margin-bottom: 8px; + font-weight: 500; +} + +.emptyDesc { + font-size: 14px; + color: #999; + line-height: 1.4; +} + +// 限制记录样式 +.restrictionTitle { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-size: 14px; + font-weight: 500; + color: #333; + line-height: 1.4; +} + +.restrictionLevel { + font-size: 10px; + padding: 2px 6px; + border-radius: 8px; + flex-shrink: 0; +} + +.restrictionContent { + display: flex; + flex-direction: column; + gap: 4px; + font-size: 12px; + color: #666; + line-height: 1.4; + margin-top: 4px; +} + +// 响应式设计 +@media (max-width: 375px) { + .rfmGrid, + .statsGrid { + grid-template-columns: 1fr; + } + + .userInfo { + flex-direction: column; + text-align: center; + } + + .avatar { + align-self: center; + } + + .restrictionTitle { + font-size: 13px; + } + + .restrictionContent { + font-size: 11px; + } +} diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx index c10a74ef..afe795fa 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx @@ -1,33 +1,191 @@ import React, { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import { Card, Button, Avatar, Tag, Tabs, List, Badge } from "antd-mobile"; +import { + Card, + Button, + Avatar, + Tag, + Tabs, + List, + Badge, + SpinLoading, +} from "antd-mobile"; import { UserOutlined, - MessageOutlined, - TeamOutlined, - ClockCircleOutlined, - ExclamationCircleOutlined, + CrownOutlined, PlusOutlined, + CloseOutlined, + EyeOutlined, + DollarOutlined, + MobileOutlined, + TagOutlined, + FileTextOutlined, + UserAddOutlined, } from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; import NavCommon from "@/components/NavCommon"; -import { getTrafficPoolDetail } from "./api"; -import type { TrafficPoolUserDetail } from "./data"; +import { getTrafficPoolDetail, getUserJourney } from "./api"; +import type { + TrafficPoolUserDetail, + ExtendedUserDetail, + InteractionRecord, + UserJourneyRecord, +} from "./data"; import styles from "./index.module.scss"; const TrafficPoolDetail: React.FC = () => { - const { id } = useParams(); + const { wxid, userId } = useParams(); const navigate = useNavigate(); const [loading, setLoading] = useState(true); - const [user, setUser] = useState(null); + const [user, setUser] = useState(null); + const [activeTab, setActiveTab] = useState("basic"); + + // 用户旅程相关状态 + const [journeyLoading, setJourneyLoading] = useState(false); + const [journeyList, setJourneyList] = useState([]); + const [journeyPage, setJourneyPage] = useState(1); + const [journeyTotal, setJourneyTotal] = useState(0); + const pageSize = 10; useEffect(() => { - if (!id) return; + if (!wxid) return; setLoading(true); - getTrafficPoolDetail(id as string) - .then((res) => setUser(res)) + getTrafficPoolDetail(wxid as string) + .then(res => { + // 将API数据转换为扩展的用户详情数据 + const extendedUser: ExtendedUserDetail = { + ...res, + // 模拟RFM评分数据 + rfmScore: { + recency: 5, + frequency: 5, + monetary: 5, + totalScore: 15, + }, + // 模拟流量池数据 + trafficPools: { + currentPool: "新用户池", + availablePools: ["高价值客户池", "活跃用户池"], + }, + // 模拟用户标签数据 + userTags: [ + { id: "1", name: "近期活跃", color: "success", type: "user" }, + { id: "2", name: "高频互动", color: "primary", type: "user" }, + { id: "3", name: "高消费", color: "warning", type: "user" }, + { id: "4", name: "老客户", color: "danger", type: "user" }, + ], + // 模拟价值标签数据 + valueTags: [ + { + id: "1", + name: "重要保持客户", + color: "primary", + icon: "crown", + rfmScore: 14, + valueLevel: "高价值", + }, + ], + }; + setUser(extendedUser); + }) .finally(() => setLoading(false)); - }, [id]); + }, [wxid]); + + // 获取用户旅程数据 + const fetchUserJourney = async (page: number = 1) => { + if (!userId) return; + + setJourneyLoading(true); + try { + const response = await getUserJourney({ + page, + pageSize, + userId: userId, + }); + + if (page === 1) { + setJourneyList(response.list); + } else { + setJourneyList(prev => [...prev, ...response.list]); + } + setJourneyTotal(response.total); + setJourneyPage(page); + } catch (error) { + console.error("获取用户旅程失败:", error); + } finally { + setJourneyLoading(false); + } + }; + + // 标签切换处理 + const handleTabChange = (tab: string) => { + setActiveTab(tab); + if (tab === "journey" && journeyList.length === 0) { + fetchUserJourney(1); + } + }; + + const handleClose = () => { + navigate(-1); + }; + + const getJourneyTypeIcon = (type: number) => { + switch (type) { + case 0: // 浏览 + return ; + case 2: // 提交订单 + return ; + case 3: // 注册 + return ; + default: + return ; + } + }; + + const getJourneyTypeText = (type: number) => { + switch (type) { + case 0: + return "浏览行为"; + case 2: + return "提交订单"; + case 3: + return "注册行为"; + default: + return "其他行为"; + } + }; + + const formatDateTime = (dateTime: string) => { + try { + const date = new Date(dateTime); + return date.toLocaleString("zh-CN", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }); + } catch (error) { + return dateTime; + } + }; + + const getActionIcon = (type: string) => { + switch (type) { + case "click": + return ; + case "view": + return ; + case "purchase": + return ; + default: + return ; + } + }; + + const formatCurrency = (amount: number) => { + return `¥${amount.toLocaleString()}`; + }; const getGenderText = (gender: number) => { switch (gender) { @@ -87,16 +245,6 @@ const TrafficPoolDetail: React.FC = () => { } }; - const formatAccountAge = (dateString: string) => { - if (!dateString) return "--"; - try { - const date = new Date(dateString); - return date.toLocaleDateString("zh-CN"); - } catch (error) { - return dateString; - } - }; - if (!user) { return ( } loading={loading}> @@ -108,8 +256,21 @@ const TrafficPoolDetail: React.FC = () => { } return ( - } loading={loading}> +
+ {/* 头部 */} +
+
用户详情
+ +
+ {/* 用户基本信息 */}
@@ -121,54 +282,167 @@ const TrafficPoolDetail: React.FC = () => {
{user.userInfo.nickname}
{user.userInfo.wechatId}
-
别名:{user.userInfo.alias}
- - {getGenderText(user.userInfo.gender)} + + + 重要价值客户 + + + 优先添加 - {user.userInfo.weight && ( - - 权重: {user.userInfo.weight} - - )}
- {/* Tab内容 */} - - + {/* 导航标签 */} +
+
handleTabChange("basic")} + > + 基本信息 +
+
handleTabChange("journey")} + > + 用户旅程 +
+
handleTabChange("tags")} + > + 用户标签 +
+
+ + {/* 内容区域 */} +
+ {activeTab === "basic" && (
- {/* 账户信息 */} - + {/* 关联信息 */} + - - 注册时间 - - - 今日添加 - - - 总消息数 - - - 今日消息 - + 设备 + 微信号 + 客服 + 添加时间 + 最近互动 + {/* RFM评分 */} + {user.rfmScore && ( + +
+
+
最近性(R)
+
+ {user.rfmScore.recency} +
+
+
+
频率(F)
+
+ {user.rfmScore.frequency} +
+
+
+
金额(M)
+
+ {user.rfmScore.monetary} +
+
+
+
总分
+
+ {user.rfmScore.totalScore}/15 +
+
+
+
+ )} + + {/* 流量池 */} + {user.trafficPools && ( + +
+
+ 当前池: + + {user.trafficPools.currentPool} + +
+
+ 可选池: + {user.trafficPools.availablePools.map((pool, index) => ( + + {pool} + + ))} +
+
+
+ )} + + {/* 统计数据 */} + +
+
+
+ ¥9561 +
+
总消费
+
+
+
+ 6 +
+
互动次数
+
+
+
+ 3% +
+
转化率
+
+
+
+ 未添加 +
+
添加状态
+
+
+
+ {/* 好友统计 */}
@@ -205,126 +479,16 @@ const TrafficPoolDetail: React.FC = () => {
未知性别
-
-
- {user.userInfo.friendShip.groupNumber} -
-
群聊数量
-
- {/* 活跃度统计 */} - -
-
-
- {user.userInfo.activity.totalMsgCount} -
-
总消息数
-
-
-
- {user.userInfo.activity.sevenDayMsgCount} -
-
7天消息
-
-
-
- {user.userInfo.activity.thirtyDayMsgCount} -
-
30天消息
-
-
-
- {user.userInfo.activity.yesterdayMsgCount} -
-
昨日消息
-
-
-
- - {/* 账户权重 */} - -
-
-
- {user.accountWeight.ageWeight} -
-
年龄权重
-
-
-
- {user.accountWeight.activityWeigth} -
-
活跃权重
-
-
-
- {user.accountWeight.restrictWeight} -
-
限制权重
-
-
-
- {user.accountWeight.realNameWeight} -
-
实名权重
-
-
-
- {user.accountWeight.scope} -
-
综合评分
-
-
-
-
- - - -
+ {/* 限制记录 */} {user.restrictions && user.restrictions.length > 0 ? ( - {user.restrictions.map((restriction) => ( + {user.restrictions.map(restriction => ( - } title={
{restriction.reason || "未知原因"} @@ -354,23 +518,161 @@ const TrafficPoolDetail: React.FC = () => { ) : (
+
+ +
暂无限制记录
+
+ 该用户没有任何限制记录 +
)}
- + )} - + {activeTab === "journey" && (
- -
-
暂无操作记录
-
+ + {journeyLoading && journeyList.length === 0 ? ( +
+ +
加载中...
+
+ ) : journeyList.length === 0 ? ( +
+
+ +
+
暂无互动记录
+
+ 该用户还没有任何互动行为 +
+
+ ) : ( + + {journeyList.map(record => ( + + {record.remark} + + {formatDateTime(record.createTime)} + +
+ } + /> + ))} + {journeyLoading && journeyList.length > 0 && ( +
+ + 加载更多... +
+ )} + {!journeyLoading && journeyList.length < journeyTotal && ( +
+ +
+ )} +
+ )}
-
- + )} + + {activeTab === "tags" && ( +
+ {/* 用户标签 */} + + {user.userTags && user.userTags.length > 0 ? ( +
+ {user.userTags.map(tag => ( + + {tag.name} + + ))} +
+ ) : ( +
+
+ +
+
暂无用户标签
+
该用户还没有任何标签
+
+ )} +
+ + {/* 价值标签 */} + + {user.valueTags && user.valueTags.length > 0 ? ( +
+ {user.valueTags.map(tag => ( +
+
+ + {tag.icon === "crown" && } + {tag.name} + + + RFM总分: {tag.rfmScore}/15 + +
+
+ + 价值等级: + + + {tag.valueLevel} + +
+
+ ))} +
+ ) : ( +
+
+ +
+
暂无价值标签
+
+ 该用户还没有任何价值标签 +
+
+ )} +
+ + {/* 添加新标签按钮 */} + +
+ )} +
); diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx b/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx index a802394d..7e000524 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx @@ -192,7 +192,7 @@ const TrafficPoolList: React.FC = () => { className={styles.card} style={{ cursor: "pointer" }} onClick={() => - navigate(`/traffic-pool/detail/${item.sourceId}`) + navigate(`/traffic-pool/detail/${item.sourceId}/${item.id}`) } >
diff --git a/nkebao/src/router/module/mine.tsx b/nkebao/src/router/module/mine.tsx index 7a190068..46e852e8 100644 --- a/nkebao/src/router/module/mine.tsx +++ b/nkebao/src/router/module/mine.tsx @@ -29,7 +29,7 @@ const routes = [ auth: true, }, { - path: "/traffic-pool/detail/:id", + path: "/traffic-pool/detail/:wxid/:userId", element: , auth: true, }, diff --git a/nkebao/tsconfig.json b/nkebao/tsconfig.json index d5830e18..9d100420 100644 --- a/nkebao/tsconfig.json +++ b/nkebao/tsconfig.json @@ -1,24 +1,24 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": false, - "noImplicitAny": false, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "baseUrl": "./", - "paths": { - "@/*": ["src/*"] - } - }, - "include": ["src"] -} +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": false, + "noImplicitAny": false, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src"] +}