feat: 本次提交更新内容如下

存一波
This commit is contained in:
笔记本里的永平
2025-07-19 14:17:05 +08:00
parent b128410346
commit 4af615889b
8 changed files with 6879 additions and 336 deletions

6402
nkebao/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.6.1",
"antd": "^5.13.1", "antd": "^5.13.1",
"antd-mobile": "^5.39.1", "antd-mobile": "^5.39.1",
"axios": "^1.6.7", "axios": "^1.6.7",

View File

@@ -3,9 +3,9 @@ import { NavBar } from "antd-mobile";
import { import {
AppOutline, AppOutline,
UserOutline, UserOutline,
LoopOutline,
TravelOutline,
ClockCircleOutline, ClockCircleOutline,
SendOutline,
StarOutline,
} from "antd-mobile-icons"; } from "antd-mobile-icons";
import MeauMobile from "@/components/MeauMobile/MeauMoible"; import MeauMobile from "@/components/MeauMobile/MeauMoible";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
@@ -38,19 +38,21 @@ const Home: React.FC = () => {
{ {
label: "同步朋友圈", label: "同步朋友圈",
value: res.momentsNum, value: res.momentsNum,
icon: <LoopOutline style={{ fontSize: 16, color: "#ff6b35" }} />, icon: (
<ClockCircleOutline style={{ fontSize: 16, color: "#ff6b35" }} />
),
color: "#ff6b35", color: "#ff6b35",
}, },
{ {
label: "群发任务", label: "群发任务",
value: res.groupPushNum, value: res.groupPushNum,
icon: <TravelOutline style={{ fontSize: 16, color: "#ffd700" }} />, icon: <SendOutline style={{ fontSize: 16, color: "#ffd700" }} />,
color: "#ffd700", color: "#ffd700",
}, },
{ {
label: "获客转化率", label: "获客转化率",
value: res.passRate, value: res.passRate,
icon: <LoopOutline style={{ fontSize: 16, color: "#4caf50" }} />, icon: <StarOutline style={{ fontSize: 16, color: "#4caf50" }} />,
color: "#4caf50", color: "#4caf50",
}, },
{ {

View File

@@ -1,71 +1,150 @@
.home-page { .mine-page {
padding: 12px; padding: 16px;
background: #f5f5f5; background-color: #f5f5f5;
min-height: 100vh;
} }
.home-cards { .user-card {
display: flex; margin-bottom: 16px;
gap: 12px; border-radius: 12px;
margin-bottom: 12px; overflow: hidden;
> :global(.adm-card) {
flex: 1; :global(.adm-card-body) {
padding: 20px;
} }
} }
.home-section { .user-info {
margin-bottom: 12px;
background: #fff;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
}
.home-section-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
padding-left: 16px;
}
.home-scene-stats {
display: flex; display: flex;
justify-content: space-between; align-items: center;
margin: 0 8px 8px 8px; gap: 16px;
}
.home-scene-item {
flex: 1;
text-align: center;
}
.home-scene-icon {
margin: 0 auto 4px auto;
}
.home-scene-value {
font-size: 18px;
font-weight: bold;
color: #1677ff;
}
.home-scene-label {
font-size: 12px;
color: #888;
} }
.home-today-item { .user-avatar {
text-align: center; width: 60px;
padding: 8px 0; height: 60px;
background: #f7f8fa; border-radius: 50%;
border-radius: 8px; overflow: hidden;
} border: 2px solid var(--primary-color);
.home-today-value {
font-size: 18px;
font-weight: bold;
color: #1677ff;
}
.home-today-label {
font-size: 12px;
color: #888;
}
.home-chart { img {
margin-top: 8px;
width: 100%; width: 100%;
min-height: 100px; height: 100%;
object-fit: cover;
}
}
.user-details {
flex: 1;
}
.user-name {
font-size: 18px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.user-level {
font-size: 14px;
color: var(--primary-color);
margin-bottom: 4px;
}
.user-points {
font-size: 12px;
color: #666;
}
.menu-card {
margin-bottom: 16px;
border-radius: 12px;
overflow: hidden;
:global(.adm-card-body) {
padding: 0;
}
:global(.adm-list-item) {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
:global(.adm-list-item-content) {
padding: 0;
}
:global(.adm-list-item-content-prefix) {
margin-right: 12px;
color: var(--primary-color);
font-size: 20px;
}
:global(.adm-list-item-content-main) {
flex: 1;
}
:global(.adm-list-item-title) {
font-size: 16px;
color: #333;
margin-bottom: 4px;
}
:global(.adm-list-item-description) {
font-size: 12px;
color: #666;
}
:global(.adm-list-item-content-arrow) {
color: #ccc;
}
}
}
.logout-section {
padding: 0 16px;
}
.logout-btn {
border-radius: 8px;
height: 48px;
font-size: 16px;
font-weight: 500;
}
// 响应式设计
@media (max-width: 375px) {
.mine-page {
padding: 12px;
}
.user-info {
gap: 12px;
}
.user-avatar {
width: 50px;
height: 50px;
}
.user-name {
font-size: 16px;
}
.menu-card {
:global(.adm-list-item) {
padding: 12px;
:global(.adm-list-item-content-prefix) {
font-size: 18px;
}
:global(.adm-list-item-title) {
font-size: 14px;
}
}
}
} }

View File

@@ -1,132 +1,143 @@
import React, { useState } from "react"; import React from "react";
import { Card, NavBar, TabBar, Grid } from "antd-mobile"; import { Card, NavBar, List, Button } from "antd-mobile";
import { import {
AppOutline,
UserOutline, UserOutline,
PieOutline, // 替换 BarChartOutline AppOutline,
ShopbagOutline,
BellOutline, BellOutline,
HeartOutline,
StarOutline,
MessageOutline,
SendOutline,
MailOutline,
} from "antd-mobile-icons"; } from "antd-mobile-icons";
import MeauMobile from "@/components/MeauMobile/MeauMoible"; import MeauMobile from "@/components/MeauMobile/MeauMoible";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
import style from "./index.module.scss"; import style from "./index.module.scss";
const sceneStats = [
{
label: "公众号获客",
value: 234,
icon: <ShopbagOutline style={{ fontSize: 28, color: "#4caf50" }} />,
},
{
label: "海报获客",
value: 167,
icon: <AppOutline style={{ fontSize: 28, color: "#ff9800" }} />,
},
{
label: "抖音获客",
value: 156,
icon: <PieOutline style={{ fontSize: 28, color: "#2196f3" }} />,
},
{
label: "小红书获客",
value: 89,
icon: <UserOutline style={{ fontSize: 28, color: "#e91e63" }} />,
},
];
const todayStats = [ const Mine: React.FC = () => {
{ label: "朋友圈同步", value: 12 }, const userInfo = {
{ label: "群发任务", value: 8 }, name: "张三",
{ label: "获客转化", value: "85%" }, avatar: "https://via.placeholder.com/60",
{ label: "系统活跃度", value: "98%" }, level: "VIP会员",
]; points: 1280,
};
const menuItems = [
{
icon: <UserOutline />,
title: "个人资料",
subtitle: "修改个人信息",
path: "/profile",
},
{
icon: <AppOutline />,
title: "系统设置",
subtitle: "应用设置与偏好",
path: "/settings",
},
{
icon: <BellOutline />,
title: "消息通知",
subtitle: "通知设置",
path: "/notifications",
},
{
icon: <HeartOutline />,
title: "我的收藏",
subtitle: "收藏的内容",
path: "/favorites",
},
{
icon: <StarOutline />,
title: "我的评价",
subtitle: "查看评价记录",
path: "/reviews",
},
{
icon: <MessageOutline />,
title: "意见反馈",
subtitle: "问题反馈与建议",
path: "/feedback",
},
{
icon: <SendOutline />,
title: "联系客服",
subtitle: "在线客服",
path: "/customer-service",
},
{
icon: <MailOutline />,
title: "关于我们",
subtitle: "版本信息",
path: "/about",
},
];
const Home: React.FC = () => {
return ( return (
<Layout <Layout
header={ header={
<NavBar back={null} style={{ background: "#fff" }}> <NavBar back={null} style={{ background: "#fff" }}>
<span style={{ color: "#1677ff", fontWeight: 700 }}></span> <div style={{ color: "var(--primary-color)", fontWeight: 600 }}>
</div>
</NavBar> </NavBar>
} }
footer={<MeauMobile />} footer={<MeauMobile />}
> >
<div className={style["home-page"]}> <div className={style["mine-page"]}>
{/* 统计卡片 */} {/* 用户信息卡片 */}
<div className={style["home-cards"]}> <Card className={style["user-card"]}>
<Card className={style["home-card"]}> <div className={style["user-info"]}>
<div className={style["home-card-title"]}></div> <div className={style["user-avatar"]}>
<div className={style["home-card-value"]}>0</div> <img src={userInfo.avatar} alt="头像" />
</Card> </div>
<Card className={style["home-card"]}> <div className={style["user-details"]}>
<div className={style["home-card-title"]}></div> <div className={style["user-name"]}>{userInfo.name}</div>
<div className={style["home-card-value"]}>0</div> <div className={style["user-level"]}>{userInfo.level}</div>
</Card> <div className={style["user-points"]}>
<Card className={style["home-card"]}> : {userInfo.points}
<div className={style["home-card-title"]}>线</div>
<div className={style["home-card-value"]}>0</div>
</Card>
</div> </div>
{/* 场景获客统计 */}
<Card className={style["home-section"]}>
<div className={style["home-section-title"]}></div>
<div className={style["home-scene-stats"]}>
{sceneStats.map((item) => (
<div key={item.label} className={style["home-scene-item"]}>
<div className={style["home-scene-icon"]}>{item.icon}</div>
<div className={style["home-scene-value"]}>{item.value}</div>
<div className={style["home-scene-label"]}>{item.label}</div>
</div> </div>
))}
</div> </div>
</Card> </Card>
{/* 今日数据 */} {/* 菜单列表 */}
<Card className={style["home-section"]}> <Card className={style["menu-card"]}>
<div className={style["home-section-title"]}></div> <List>
<Grid columns={2} gap={12}> {menuItems.map((item, index) => (
{todayStats.map((item) => ( <List.Item
<Grid.Item key={item.label}> key={index}
<div className={style["home-today-item"]}> prefix={item.icon}
<div className={style["home-today-value"]}>{item.value}</div> title={item.title}
<div className={style["home-today-label"]}>{item.label}</div> description={item.subtitle}
</div> arrow
</Grid.Item> onClick={() => {
))} // 这里可以添加导航逻辑
</Grid> console.log(`点击了: ${item.title}`);
</Card> }}
{/* 每日获客趋势(静态图表占位) */}
<Card className={style["home-section"]}>
<div className={style["home-section-title"]}></div>
<div className={style["home-chart"]}>
<svg width="100%" height="120">
<polyline
fill="none"
stroke="#1677ff"
strokeWidth="3"
points="10,100 40,80 70,60 100,50 130,40 160,60 190,80"
/> />
{/* x轴文字 */} ))}
{["周一", "周二", "周三", "周四", "周五", "周六", "周日"].map( </List>
(d, i) => (
<text
key={d}
x={10 + i * 30}
y={115}
fontSize="12"
textAnchor="middle"
>
{d}
</text>
)
)}
</svg>
</div>
</Card> </Card>
{/* 退出登录按钮 */}
<div className={style["logout-section"]}>
<Button
block
color="danger"
fill="outline"
className={style["logout-btn"]}
onClick={() => {
// 这里可以添加退出登录逻辑
console.log("退出登录");
}}
>
退
</Button>
</div>
</div> </div>
</Layout> </Layout>
); );
}; };
export default Home; export default Mine;

View File

@@ -31,9 +31,9 @@
// 页面容器 // 页面容器
.scene-page { .scene-page {
padding: 12px; background: #f5f6fa;
background: #f5f5f5; min-height: 100vh;
min-height: calc(100vh - 100px); padding: 0 0 60px 0;
} }
// 错误提示 // 错误提示
@@ -142,109 +142,89 @@
} }
} }
.scenarios-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
padding: 16px;
}
.scenario-card { .scenario-card {
background: #fff; background: #fff;
border-radius: 12px; border-radius: 16px;
padding: 16px 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.06);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); transition: box-shadow 0.2s, transform 0.2s;
border: 1px solid #f0f0f0; cursor: pointer;
transition: all 0.2s ease; overflow: hidden;
display: flex;
justify-content: space-between;
align-items: center;
min-height: 78px;
&:hover { &:hover {
box-shadow: 0 4px 16px rgba(24, 142, 238, 0.12); box-shadow: 0 6px 16px rgba(0,0,0,0.12);
border-color: var(--primary-color-light); transform: translateY(-2px) scale(1.02);
} }
} }
.scenario-left { .card-inner {
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
gap: 16px; padding: 18px 10px 14px 10px;
flex: 1;
} }
.scenario-icon { .card-img-wrap {
width: 52px; margin-bottom: 8px;
height: 52px; }
background: linear-gradient(135deg, #f0f8ff 0%, #e6f7ff 100%); .card-img-bg {
border-radius: 12px; width: 48px;
height: 48px;
background: #f0f2f5;
border-radius: 50%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border: 1px solid rgba(24, 142, 238, 0.1);
flex-shrink: 0;
} }
.card-img {
.scenario-image {
width: 32px; width: 32px;
height: 32px; height: 32px;
object-fit: contain; object-fit: contain;
border-radius: 8px;
} }
.scenario-info { .card-title {
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
min-width: 0;
}
.scenario-name {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #1a1a1a; color: #1677ff;
line-height: 1.3; text-align: center;
white-space: nowrap; margin-bottom: 2px;
overflow: hidden;
text-overflow: ellipsis;
} }
.scenario-stats { .card-desc {
font-size: 12px;
color: #888;
text-align: center;
margin-bottom: 6px;
line-height: 1.4;
min-height: 32px;
max-height: 32px;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.card-stats {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
gap: 10px;
margin-top: 4px;
} }
.card-count {
.stat-text {
font-size: 13px; font-size: 13px;
color: #666; color: #666;
font-weight: 500;
} }
.card-growth {
.scenario-right { font-size: 12px;
display: flex; color: #52c41a;
flex-direction: column;
align-items: flex-end;
gap: 8px;
flex-shrink: 0;
}
.scenario-status {
display: flex;
justify-content: flex-end;
}
.status-tag {
font-size: 11px;
padding: 3px 8px;
border-radius: 10px;
font-weight: 500;
}
.scenario-growth {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 3px;
font-size: 16px;
font-weight: 700;
}
.growth-icon {
font-size: 14px;
} }
// 空状态 // 空状态
@@ -317,3 +297,35 @@
font-size: 13px; font-size: 13px;
} }
} }
@media (max-width: 500px) {
.scenarios-grid {
gap: 10px;
padding: 10px;
}
.card-inner {
padding: 12px 4px 10px 4px;
}
.card-img-bg {
width: 40px;
height: 40px;
}
.card-img {
width: 26px;
height: 26px;
}
.card-title {
font-size: 15px;
}
.card-desc {
font-size: 11px;
min-height: 24px;
max-height: 24px;
}
.card-count {
font-size: 12px;
}
.card-growth {
font-size: 11px;
}
}

View File

@@ -1,7 +1,8 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { NavBar, Button, SpinLoading, Toast, Tag } from "antd-mobile"; import { NavBar, Button, Toast, SpinLoading } from "antd-mobile";
import { AddOutline, UserAddOutline } from "antd-mobile-icons"; import { AddOutline } from "antd-mobile-icons";
import { RiseOutlined } from "@ant-design/icons";
import MeauMobile from "@/components/MeauMobile/MeauMoible"; import MeauMobile from "@/components/MeauMobile/MeauMoible";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
import { getScenarios } from "./api"; import { getScenarios } from "./api";
@@ -11,11 +12,23 @@ interface Scenario {
id: string; id: string;
name: string; name: string;
image: string; image: string;
description?: string;
count: number; count: number;
growth: string; growth: string;
status: number; status: number;
} }
const scenarioDescriptions: Record<string, string> = {
douyin: "通过抖音平台进行精准获客",
xiaohongshu: "利用小红书平台进行内容营销获客",
gongzhonghao: "通过微信公众号进行获客",
haibao: "通过海报分享进行获客",
phone: "通过电话营销进行获客",
weixinqun: "通过微信群进行获客",
payment: "通过付款码进行获客",
api: "通过API接口进行获客",
};
const Scene: React.FC = () => { const Scene: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [scenarios, setScenarios] = useState<Scenario[]>([]); const [scenarios, setScenarios] = useState<Scenario[]>([]);
@@ -26,25 +39,23 @@ const Scene: React.FC = () => {
const fetchScenarios = async () => { const fetchScenarios = async () => {
setLoading(true); setLoading(true);
setError(""); setError("");
try { try {
const response = await getScenarios({ page: 1, limit: 20 }); const response = await getScenarios({ page: 1, limit: 20 });
// 转换API数据为前端需要的格式
const transformedScenarios: Scenario[] = response.map((item: any) => ({ const transformedScenarios: Scenario[] = response.map((item: any) => ({
id: item.id.toString(), id: item.id.toString(),
name: item.name, name: item.name,
image: image:
item.image || item.image ||
"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-api.png", "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-api.png",
count: item.count, // 模拟今日数据 description:
growth: item.growth, // 模拟增长率 scenarioDescriptions[item.name?.toLowerCase()] ||
"通过该平台进行获客",
count: item.count,
growth: item.growth,
status: item.status, status: item.status,
})); }));
setScenarios(transformedScenarios); setScenarios(transformedScenarios);
} catch (error) { } catch (error) {
console.error("获取场景数据失败:", error);
setError("获取场景数据失败,请稍后重试"); setError("获取场景数据失败,请稍后重试");
Toast.show({ Toast.show({
content: "获取场景数据失败,请稍后重试", content: "获取场景数据失败,请稍后重试",
@@ -54,7 +65,6 @@ const Scene: React.FC = () => {
setLoading(false); setLoading(false);
} }
}; };
fetchScenarios(); fetchScenarios();
}, []); }, []);
@@ -68,12 +78,61 @@ const Scene: React.FC = () => {
navigate("/scenarios/new"); navigate("/scenarios/new");
}; };
const getGrowthColor = (growth: string) => { if (loading) {
const value = parseFloat(growth.replace(/[+%]/g, "")); return (
if (value > 10) return "#52c41a"; <Layout
if (value > 5) return "#faad14"; header={
return "#ff4d4f"; <NavBar back={null} style={{ background: "#fff" }}>
}; <div className={style["nav-title"]}></div>
<Button
size="small"
color="primary"
onClick={handleNewPlan}
className={style["new-plan-btn"]}
style={{ marginLeft: "auto" }}
>
<AddOutline />
</Button>
</NavBar>
}
footer={<MeauMobile />}
>
<div className={style["loading"]}>
<SpinLoading color="primary" style={{ fontSize: 32 }} />
<div className={style["loading-text"]}>...</div>
</div>
</Layout>
);
}
if (error && scenarios.length === 0) {
return (
<Layout
header={
<NavBar back={null} style={{ background: "#fff" }}>
<div className={style["nav-title"]}></div>
<Button
size="small"
color="primary"
onClick={handleNewPlan}
className={style["new-plan-btn"]}
style={{ marginLeft: "auto" }}
>
<AddOutline />
</Button>
</NavBar>
}
footer={<MeauMobile />}
>
<div className={style["error"]}>
<div className={style["error-text"]}>{error}</div>
<Button color="primary" onClick={() => window.location.reload()}>
</Button>
</div>
</Layout>
);
}
return ( return (
<Layout <Layout
@@ -88,94 +147,58 @@ const Scene: React.FC = () => {
color="primary" color="primary"
onClick={handleNewPlan} onClick={handleNewPlan}
className={style["new-plan-btn"]} className={style["new-plan-btn"]}
style={{ marginLeft: "auto" }}
> >
<AddOutline /> <AddOutline />
<span className={style["nav-right"]}></span>
</Button> </Button>
} }
/> ></NavBar>
} }
footer={<MeauMobile />} footer={<MeauMobile />}
> >
<div className={style["scene-page"]}> <div className={style["scene-page"]}>
<div className={style["scene-header"]}> <div className={style["scenarios-grid"]}>
<div className={style["header-title"]}>
<UserAddOutline className={style["header-icon"]} />
<span></span>
</div>
<div className={style["header-subtitle"]}>
</div>
</div>
<div className={style["scenarios-list"]}>
{scenarios.map((scenario) => ( {scenarios.map((scenario) => (
<div <div
key={scenario.id} key={scenario.id}
className={style["scenario-item"]} className={style["scenario-card"]}
onClick={() => handleScenarioClick(scenario.id, scenario.name)} onClick={() => handleScenarioClick(scenario.id, scenario.name)}
> >
<div className={style["scenario-card"]}> <div className={style["card-inner"]}>
<div className={style["scenario-left"]}> <div className={style["card-img-wrap"]}>
<div className={style["scenario-icon"]}> <div className={style["card-img-bg"]}>
<img <img
src={scenario.image} src={scenario.image}
alt={scenario.name} alt={scenario.name}
className={style["scenario-image"]} className={style["card-img"]}
onError={(e) => { onError={(e) => {
e.currentTarget.src = e.currentTarget.src =
"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-api.png"; "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-api.png";
}} }}
/> />
</div> </div>
<div className={style["scenario-info"]}>
<div className={style["scenario-name"]}>
{scenario.name}
</div> </div>
<div className={style["scenario-stats"]}> <div className={style["card-title"]}>{scenario.name}</div>
<span className={style["stat-text"]}> {scenario.description && (
: {scenario.count} <div className={style["card-desc"]}>
{scenario.description}
</div>
)}
<div className={style["card-stats"]}>
<span className={style["card-count"]}>
: {scenario.count}
</span> </span>
</div> <span className={style["card-growth"]}>
</div> <RiseOutlined
</div> style={{ fontSize: 14, color: "#52c41a", marginRight: 2 }}
/>
<div className={style["scenario-right"]}>
<div className={style["scenario-status"]}>
<Tag
color={scenario.status === 1 ? "success" : "default"}
fill="outline"
className={style["status-tag"]}
>
{scenario.status === 1 ? "活跃" : "暂停"}
</Tag>
</div>
<div
className={style["scenario-growth"]}
style={{ color: getGrowthColor(scenario.growth) }}
>
{scenario.growth} {scenario.growth}
</div> </span>
</div> </div>
</div> </div>
</div> </div>
))} ))}
</div> </div>
{scenarios.length === 0 && !loading && (
<div className={style["empty-state"]}>
<div className={style["empty-icon"]}>📊</div>
<div className={style["empty-text"]}></div>
<Button
color="primary"
size="small"
onClick={handleNewPlan}
className={style["empty-action"]}
>
</Button>
</div>
)}
</div> </div>
</Layout> </Layout>
); );

View File

@@ -1,15 +1,14 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Card, NavBar, Badge, Progress } from "antd-mobile"; import { Card, NavBar, Badge } from "antd-mobile";
import { import {
ThumbsUpOutline, LikeOutline,
MessageOutline, MessageOutline,
SendOutline, SendOutline,
TeamOutline, TeamOutline,
ShareOutline, LinkOutline,
AppOutline, AppOutline,
BarChartOutline, PieOutline,
LineChartOutline,
ClockCircleOutline, ClockCircleOutline,
} from "antd-mobile-icons"; } from "antd-mobile-icons";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
@@ -33,7 +32,7 @@ const Workspace: React.FC = () => {
name: "自动点赞", name: "自动点赞",
description: "智能自动点赞互动", description: "智能自动点赞互动",
icon: ( icon: (
<ThumbsUpOutline className={styles.icon} style={{ color: "#ff4d4f" }} /> <LikeOutline className={styles.icon} style={{ color: "#ff4d4f" }} />
), ),
path: "/workspace/auto-like", path: "/workspace/auto-like",
bgColor: "#fff2f0", bgColor: "#fff2f0",
@@ -77,7 +76,7 @@ const Workspace: React.FC = () => {
name: "流量分发", name: "流量分发",
description: "管理流量分发和分配", description: "管理流量分发和分配",
icon: ( icon: (
<ShareOutline className={styles.icon} style={{ color: "#1890ff" }} /> <LinkOutline className={styles.icon} style={{ color: "#1890ff" }} />
), ),
path: "/workspace/traffic-distribution", path: "/workspace/traffic-distribution",
bgColor: "#e6f7ff", bgColor: "#e6f7ff",
@@ -101,9 +100,7 @@ const Workspace: React.FC = () => {
id: "ai-analyzer", id: "ai-analyzer",
name: "AI数据分析", name: "AI数据分析",
description: "智能分析客户行为特征", description: "智能分析客户行为特征",
icon: ( icon: <PieOutline className={styles.icon} style={{ color: "#531dab" }} />,
<BarChartOutline className={styles.icon} style={{ color: "#531dab" }} />
),
path: "/workspace/ai-analyzer", path: "/workspace/ai-analyzer",
bgColor: "#f0f0ff", bgColor: "#f0f0ff",
isNew: true, isNew: true,
@@ -121,17 +118,17 @@ const Workspace: React.FC = () => {
id: "ai-forecast", id: "ai-forecast",
name: "AI销售预测", name: "AI销售预测",
description: "智能预测销售趋势", description: "智能预测销售趋势",
icon: ( icon: <PieOutline className={styles.icon} style={{ color: "#d48806" }} />,
<LineChartOutline
className={styles.icon}
style={{ color: "#d48806" }}
/>
),
path: "/workspace/ai-forecast", path: "/workspace/ai-forecast",
bgColor: "#fffbe6", bgColor: "#fffbe6",
}, },
]; ];
// 进度条宽度
const progressPercent = Math.round(
(taskStats.inProgress / taskStats.total) * 100
);
return ( return (
<Layout <Layout
header={ header={
@@ -149,10 +146,26 @@ const Workspace: React.FC = () => {
<Card className={styles.statsCard}> <Card className={styles.statsCard}>
<div className={styles.statsTitle}></div> <div className={styles.statsTitle}></div>
<div className={styles.statsValue}>{taskStats.total}</div> <div className={styles.statsValue}>{taskStats.total}</div>
<Progress <div className={styles.progress}>
percent={(taskStats.inProgress / taskStats.total) * 100} <div
className={styles.progress} style={{
width: progressPercent + "%",
height: 6,
background: "var(--primary-color)",
borderRadius: 4,
transition: "width 0.3s",
}}
/> />
<div
style={{
width: 100 - progressPercent + "%",
height: 6,
background: "#f0f0f0",
borderRadius: 4,
display: "inline-block",
}}
/>
</div>
<div className={styles.statsSubtitle}> <div className={styles.statsSubtitle}>
: {taskStats.inProgress} / : {taskStats.completed} : {taskStats.inProgress} / : {taskStats.completed}
</div> </div>