feat: 本次提交更新内容如下
接口对接成功
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import request from "@/api/request";
|
||||
|
||||
export function getTrafficPoolDetail(id: string): Promise<any> {
|
||||
return request("/v1/workbench/detail", { id }, "GET");
|
||||
export function getTrafficPoolDetail(wechatId: string): Promise<any> {
|
||||
return request("/v1/wechats/getWechatInfo", { wechatId }, "GET");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
.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: 8px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.packageTag {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
.rfmGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.rfmItem {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rfmValue {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.rfmLabel {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.interactionContent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.purchaseValue {
|
||||
color: #22c55e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tagsContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.userTag {
|
||||
font-size: 12px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.addTagButton {
|
||||
margin: 0 16px 16px;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
|
||||
:global(.antd-mobile-icon) {
|
||||
margin-right: 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;
|
||||
}
|
||||
|
||||
.tabContent {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.rfmGrid {
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.rfmValue {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.statsGrid {
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.statValue {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tagsContainer {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.addTagButton {
|
||||
margin: 0 12px 12px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
// 暗色模式支持
|
||||
@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;
|
||||
}
|
||||
|
||||
.infoCard :global(.adm-card-header) {
|
||||
color: #fff;
|
||||
border-bottom-color: #3a3a3a;
|
||||
}
|
||||
|
||||
.rfmLabel,
|
||||
.statLabel {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.emptyText {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
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 {
|
||||
UserOutlined,
|
||||
MessageOutlined,
|
||||
ShoppingOutlined,
|
||||
EyeOutlined,
|
||||
PlusOutlined,
|
||||
} 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 { Card, Button, Avatar, Tag, Spin } from "antd";
|
||||
|
||||
const tabList = [
|
||||
{ key: "base", label: "基本信息" },
|
||||
{ key: "journey", label: "用户旅程" },
|
||||
{ key: "tags", label: "用户标签" },
|
||||
];
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
const TrafficPoolDetail: React.FC = () => {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [user, setUser] = useState<TrafficPoolUserDetail | null>(null);
|
||||
const [activeTab, setActiveTab] = useState<"base" | "journey" | "tags">(
|
||||
"base"
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
@@ -28,270 +28,256 @@ const TrafficPoolDetail: React.FC = () => {
|
||||
.finally(() => setLoading(false));
|
||||
}, [id]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Layout>
|
||||
<div style={{ textAlign: "center", padding: "64px 0" }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
const getInteractionIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case "click":
|
||||
return <UserOutlined style={{ color: "#ff6b35" }} />;
|
||||
case "message":
|
||||
return <MessageOutlined style={{ color: "#3b82f6" }} />;
|
||||
case "purchase":
|
||||
return <ShoppingOutlined style={{ color: "#22c55e" }} />;
|
||||
case "view":
|
||||
return <EyeOutlined style={{ color: "#8b5cf6" }} />;
|
||||
default:
|
||||
return <UserOutlined />;
|
||||
}
|
||||
};
|
||||
|
||||
const getInteractionTitle = (type: string) => {
|
||||
switch (type) {
|
||||
case "click":
|
||||
return "点击行为";
|
||||
case "message":
|
||||
return "消息互动";
|
||||
case "purchase":
|
||||
return "购买行为";
|
||||
case "view":
|
||||
return "页面浏览";
|
||||
default:
|
||||
return "未知行为";
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = (status: string | number) => {
|
||||
if (status === "failed" || status === 0) return "添加失败";
|
||||
if (status === "added" || status === 1) return "添加成功";
|
||||
return "未添加";
|
||||
};
|
||||
|
||||
const getStatusColor = (status: string | number) => {
|
||||
if (status === "failed" || status === 0) return "danger";
|
||||
if (status === "added" || status === 1) return "success";
|
||||
return "default";
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<Layout>
|
||||
<div style={{ textAlign: "center", color: "#aaa", padding: "64px 0" }}>
|
||||
未找到该用户
|
||||
<Layout header={<NavCommon title="用户详情" />} loading={loading}>
|
||||
<div className={styles.emptyState}>
|
||||
<div className={styles.emptyText}>未找到该用户</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout
|
||||
header={
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
height: 48,
|
||||
borderBottom: "1px solid #eee",
|
||||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => navigate(-1)}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
< 返回
|
||||
</Button>
|
||||
<div style={{ fontWeight: 600, fontSize: 18 }}>用户详情</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div style={{ padding: 16 }}>
|
||||
{/* 顶部信息 */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 16,
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
<Avatar src={user.avatar} size={64} />
|
||||
<div>
|
||||
<div style={{ fontSize: 20, fontWeight: 600 }}>{user.nickname}</div>
|
||||
<div style={{ color: "#1677ff", fontSize: 14, margin: "4px 0" }}>
|
||||
{user.wechatId}
|
||||
<Layout header={<NavCommon title="用户详情" />} loading={loading}>
|
||||
<div className={styles.container}>
|
||||
{/* 用户基本信息 */}
|
||||
<Card className={styles.userCard}>
|
||||
<div className={styles.userInfo}>
|
||||
<Avatar
|
||||
src={user.avatar}
|
||||
className={styles.avatar}
|
||||
fallback={<UserOutlined />}
|
||||
/>
|
||||
<div className={styles.userDetails}>
|
||||
<div className={styles.nickname}>{user.nickname}</div>
|
||||
<div className={styles.wechatId}>{user.wechatId}</div>
|
||||
<div className={styles.tags}>
|
||||
{user.packages?.map((pkg) => (
|
||||
<Tag
|
||||
key={pkg}
|
||||
color="primary"
|
||||
fill="outline"
|
||||
className={styles.packageTag}
|
||||
>
|
||||
{pkg}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{user.packages &&
|
||||
user.packages.length > 0 &&
|
||||
user.packages.map((pkg) => (
|
||||
<Tag color="purple" key={pkg} style={{ marginRight: 4 }}>
|
||||
{pkg}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* Tab栏 */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 24,
|
||||
borderBottom: "1px solid #eee",
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
{tabList.map((tab) => (
|
||||
<div
|
||||
key={tab.key}
|
||||
style={{
|
||||
padding: "8px 0",
|
||||
fontWeight: 500,
|
||||
color: activeTab === tab.key ? "#1677ff" : "#888",
|
||||
borderBottom:
|
||||
activeTab === tab.key ? "2px solid #1677ff" : "none",
|
||||
cursor: "pointer",
|
||||
fontSize: 16,
|
||||
}}
|
||||
onClick={() => setActiveTab(tab.key as any)}
|
||||
>
|
||||
{tab.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Tab内容 */}
|
||||
{activeTab === "base" && (
|
||||
<>
|
||||
<Card style={{ marginBottom: 16 }} title="关键信息">
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 24 }}>
|
||||
<div>设备:{user.deviceName || "--"}</div>
|
||||
<div>微信号:{user.wechatAccountName || "--"}</div>
|
||||
<div>客服:{user.customerServiceName || "--"}</div>
|
||||
<div>添加时间:{user.addTime || "--"}</div>
|
||||
<div>最近互动:{user.lastInteraction || "--"}</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card style={{ marginBottom: 16 }} title="RFM评分">
|
||||
<div style={{ display: "flex", gap: 32 }}>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 20, fontWeight: 600, color: "#1677ff" }}
|
||||
>
|
||||
{user.rfmScore?.recency ?? "-"}
|
||||
<Tabs className={styles.tabs}>
|
||||
<Tabs.Tab title="基本信息" key="base">
|
||||
<div className={styles.tabContent}>
|
||||
{/* 关键信息 */}
|
||||
<Card title="关键信息" className={styles.infoCard}>
|
||||
<List>
|
||||
<List.Item extra={user.deviceName || "--"}>设备</List.Item>
|
||||
<List.Item extra={user.wechatAccountName || "--"}>
|
||||
微信号
|
||||
</List.Item>
|
||||
<List.Item extra={user.customerServiceName || "--"}>
|
||||
客服
|
||||
</List.Item>
|
||||
<List.Item extra={user.addTime || "--"}>添加时间</List.Item>
|
||||
<List.Item extra={user.lastInteraction || "--"}>
|
||||
最近互动
|
||||
</List.Item>
|
||||
</List>
|
||||
</Card>
|
||||
|
||||
{/* RFM评分 */}
|
||||
<Card title="RFM评分" className={styles.infoCard}>
|
||||
<div className={styles.rfmGrid}>
|
||||
<div className={styles.rfmItem}>
|
||||
<div
|
||||
className={styles.rfmValue}
|
||||
style={{ color: "#1677ff" }}
|
||||
>
|
||||
{user.rfmScore?.recency ?? "-"}
|
||||
</div>
|
||||
<div className={styles.rfmLabel}>最近性(R)</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>最近性(R)</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 20, fontWeight: 600, color: "#52c41a" }}
|
||||
>
|
||||
{user.rfmScore?.frequency ?? "-"}
|
||||
<div className={styles.rfmItem}>
|
||||
<div
|
||||
className={styles.rfmValue}
|
||||
style={{ color: "#52c41a" }}
|
||||
>
|
||||
{user.rfmScore?.frequency ?? "-"}
|
||||
</div>
|
||||
<div className={styles.rfmLabel}>频率(F)</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>频率(F)</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 20, fontWeight: 600, color: "#eb2f96" }}
|
||||
>
|
||||
{user.rfmScore?.monetary ?? "-"}
|
||||
<div className={styles.rfmItem}>
|
||||
<div
|
||||
className={styles.rfmValue}
|
||||
style={{ color: "#eb2f96" }}
|
||||
>
|
||||
{user.rfmScore?.monetary ?? "-"}
|
||||
</div>
|
||||
<div className={styles.rfmLabel}>金额(M)</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>金额(M)</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card style={{ marginBottom: 16 }} title="统计数据">
|
||||
<div style={{ display: "flex", gap: 32 }}>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 18, fontWeight: 600, color: "#52c41a" }}
|
||||
>
|
||||
¥{user.totalSpent ?? "-"}
|
||||
</Card>
|
||||
|
||||
{/* 统计数据 */}
|
||||
<Card title="统计数据" className={styles.infoCard}>
|
||||
<div className={styles.statsGrid}>
|
||||
<div className={styles.statItem}>
|
||||
<div
|
||||
className={styles.statValue}
|
||||
style={{ color: "#52c41a" }}
|
||||
>
|
||||
¥{user.totalSpent ?? "-"}
|
||||
</div>
|
||||
<div className={styles.statLabel}>总消费</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>总消费</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 18, fontWeight: 600, color: "#1677ff" }}
|
||||
>
|
||||
{user.interactionCount ?? "-"}
|
||||
<div className={styles.statItem}>
|
||||
<div
|
||||
className={styles.statValue}
|
||||
style={{ color: "#1677ff" }}
|
||||
>
|
||||
{user.interactionCount ?? "-"}
|
||||
</div>
|
||||
<div className={styles.statLabel}>互动次数</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>互动次数</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 18, fontWeight: 600, color: "#faad14" }}
|
||||
>
|
||||
{user.conversionRate ?? "-"}
|
||||
<div className={styles.statItem}>
|
||||
<div
|
||||
className={styles.statValue}
|
||||
style={{ color: "#faad14" }}
|
||||
>
|
||||
{user.conversionRate ?? "-"}
|
||||
</div>
|
||||
<div className={styles.statLabel}>转化率</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>转化率</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: 18, fontWeight: 600, color: "#ff4d4f" }}
|
||||
>
|
||||
{user.status === "failed"
|
||||
? "添加失败"
|
||||
: user.status === "added"
|
||||
? "添加成功"
|
||||
: "未添加"}
|
||||
<div className={styles.statItem}>
|
||||
<div
|
||||
className={styles.statValue}
|
||||
style={{ color: "#ff4d4f" }}
|
||||
>
|
||||
{getStatusText(user.status)}
|
||||
</div>
|
||||
<div className={styles.statLabel}>添加状态</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: "#888" }}>添加状态</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
{activeTab === "journey" && (
|
||||
<Card title="互动记录">
|
||||
{user.interactions && user.interactions.length > 0 ? (
|
||||
user.interactions.slice(0, 4).map((it) => (
|
||||
<div
|
||||
key={it.id}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
borderBottom: "1px solid #f0f0f0",
|
||||
padding: "12px 0",
|
||||
</Card>
|
||||
</div>
|
||||
</Tabs.Tab>
|
||||
|
||||
<Tabs.Tab title="用户旅程" key="journey">
|
||||
<div className={styles.tabContent}>
|
||||
<Card title="互动记录" className={styles.infoCard}>
|
||||
{user.interactions && user.interactions.length > 0 ? (
|
||||
<List>
|
||||
{user.interactions.slice(0, 4).map((interaction) => (
|
||||
<List.Item
|
||||
key={interaction.id}
|
||||
prefix={getInteractionIcon(interaction.type)}
|
||||
title={getInteractionTitle(interaction.type)}
|
||||
description={
|
||||
<div className={styles.interactionContent}>
|
||||
<span>{interaction.content}</span>
|
||||
{interaction.type === "purchase" &&
|
||||
interaction.value && (
|
||||
<span className={styles.purchaseValue}>
|
||||
¥{interaction.value}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
extra={interaction.timestamp}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
) : (
|
||||
<div className={styles.emptyState}>
|
||||
<div className={styles.emptyText}>暂无互动记录</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</Tabs.Tab>
|
||||
|
||||
<Tabs.Tab title="用户标签" key="tags">
|
||||
<div className={styles.tabContent}>
|
||||
<Card title="用户标签" className={styles.infoCard}>
|
||||
<div className={styles.tagsContainer}>
|
||||
{user.tags && user.tags.length > 0 ? (
|
||||
user.tags.map((tag) => (
|
||||
<Tag
|
||||
key={tag}
|
||||
color="primary"
|
||||
fill="outline"
|
||||
className={styles.userTag}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))
|
||||
) : (
|
||||
<div className={styles.emptyText}>暂无标签</div>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
block
|
||||
color="default"
|
||||
fill="outline"
|
||||
className={styles.addTagButton}
|
||||
onClick={() => {
|
||||
// TODO: 实现添加标签功能
|
||||
console.log("添加新标签");
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: 22 }}>
|
||||
{it.type === "click" && "📱"}
|
||||
{it.type === "message" && "💬"}
|
||||
{it.type === "purchase" && "💲"}
|
||||
{it.type === "view" && "👁️"}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ fontWeight: 500 }}>
|
||||
{it.type === "click" && "点击行为"}
|
||||
{it.type === "message" && "消息互动"}
|
||||
{it.type === "purchase" && "购买行为"}
|
||||
{it.type === "view" && "页面浏览"}
|
||||
</div>
|
||||
<div style={{ color: "#888", fontSize: 13 }}>
|
||||
{it.content}
|
||||
{it.type === "purchase" && it.value && (
|
||||
<span
|
||||
style={{
|
||||
color: "#52c41a",
|
||||
fontWeight: 600,
|
||||
marginLeft: 4,
|
||||
}}
|
||||
>
|
||||
¥{it.value}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: "#aaa",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{it.timestamp}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
color: "#aaa",
|
||||
textAlign: "center",
|
||||
padding: "24px 0",
|
||||
}}
|
||||
>
|
||||
暂无互动记录
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
{activeTab === "tags" && (
|
||||
<Card title="用户标签">
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
{user.tags && user.tags.length > 0 ? (
|
||||
user.tags.map((tag) => (
|
||||
<Tag
|
||||
key={tag}
|
||||
color="blue"
|
||||
style={{ marginRight: 8, marginBottom: 8 }}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))
|
||||
) : (
|
||||
<span style={{ color: "#aaa" }}>暂无标签</span>
|
||||
)}
|
||||
<PlusOutlined />
|
||||
添加新标签
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
<Button type="dashed" block>
|
||||
➕ 添加新标签
|
||||
</Button>
|
||||
</Card>
|
||||
)}
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -191,7 +191,9 @@ const TrafficPoolList: React.FC = () => {
|
||||
<div
|
||||
className={styles.card}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => navigate(`/traffic-pool/detail/${item.id}`)}
|
||||
onClick={() =>
|
||||
navigate(`/traffic-pool/detail/${item.sourceId}`)
|
||||
}
|
||||
>
|
||||
<div className={styles.cardContent}>
|
||||
<Checkbox
|
||||
|
||||
@@ -73,17 +73,6 @@ const Workspace: React.FC = () => {
|
||||
path: "/workspace/traffic-distribution",
|
||||
bgColor: "#e6f7ff",
|
||||
},
|
||||
{
|
||||
id: "ai-assistant",
|
||||
name: "AI对话助手",
|
||||
description: "智能回复,提高互动质量",
|
||||
icon: (
|
||||
<MessageOutlined className={styles.icon} style={{ color: "#1890ff" }} />
|
||||
),
|
||||
path: "/workspace/ai-assistant",
|
||||
bgColor: "#e6f7ff",
|
||||
isNew: true,
|
||||
},
|
||||
];
|
||||
|
||||
// AI智能助手
|
||||
@@ -176,7 +165,7 @@ const Workspace: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* AI智能助手 */}
|
||||
<div className={styles.section}>
|
||||
{/* <div className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>AI 智能助手</h2>
|
||||
<div className={styles.featuresGrid}>
|
||||
{aiFeatures.map((feature) => (
|
||||
@@ -205,7 +194,7 @@ const Workspace: React.FC = () => {
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user