From d8c59f43c2b2b426da9fcf173298410c692b7f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AC=94=E8=AE=B0=E6=9C=AC=E9=87=8C=E7=9A=84=E6=B0=B8?= =?UTF-8?q?=E5=B9=B3?= Date: Fri, 18 Jul 2025 12:03:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9C=AC=E6=AC=A1=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=86=85=E5=AE=B9=E5=A6=82=E4=B8=8B=20?= =?UTF-8?q?=E6=90=9E=E7=99=BB=E5=BD=95=E6=8B=A6=E6=88=AA=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nkebao/package.json | 2 + nkebao/src/App.tsx | 3 - .../src/{com => components}/Layout/Layout.tsx | 40 ++-- .../Layout/layout.module.scss | 0 nkebao/src/components/LineChart.tsx | 53 +++++ .../src/components/MeauMobile/MeauMoible.tsx | 81 ++++++++ nkebao/src/pages/home/api.ts | 21 +- nkebao/src/pages/home/index.module.scss | 70 +++++++ nkebao/src/pages/home/index.scss | 35 ---- nkebao/src/pages/home/index.tsx | 186 ++++++++++++------ nkebao/src/pages/login/login.module.scss | 0 nkebao/src/pages/login/login.tsx | 74 +++++++ nkebao/src/pages/mine/api.ts | 14 ++ nkebao/src/pages/mine/index.module.scss | 71 +++++++ nkebao/src/pages/mine/index.tsx | 132 +++++++++++++ nkebao/src/pages/scene/api.ts | 14 ++ nkebao/src/pages/scene/index.module.scss | 71 +++++++ nkebao/src/pages/scene/index.tsx | 132 +++++++++++++ nkebao/src/pages/work/api.ts | 14 ++ nkebao/src/pages/work/index.module.scss | 71 +++++++ nkebao/src/pages/work/index.tsx | 132 +++++++++++++ nkebao/src/router/module/home.tsx | 28 +-- package.json | 5 + yarn.lock | 23 +++ 24 files changed, 1136 insertions(+), 136 deletions(-) rename nkebao/src/{com => components}/Layout/Layout.tsx (73%) rename nkebao/src/{com => components}/Layout/layout.module.scss (100%) create mode 100644 nkebao/src/components/LineChart.tsx create mode 100644 nkebao/src/components/MeauMobile/MeauMoible.tsx create mode 100644 nkebao/src/pages/home/index.module.scss delete mode 100644 nkebao/src/pages/home/index.scss create mode 100644 nkebao/src/pages/login/login.module.scss create mode 100644 nkebao/src/pages/login/login.tsx create mode 100644 nkebao/src/pages/mine/api.ts create mode 100644 nkebao/src/pages/mine/index.module.scss create mode 100644 nkebao/src/pages/mine/index.tsx create mode 100644 nkebao/src/pages/scene/api.ts create mode 100644 nkebao/src/pages/scene/index.module.scss create mode 100644 nkebao/src/pages/scene/index.tsx create mode 100644 nkebao/src/pages/work/api.ts create mode 100644 nkebao/src/pages/work/index.module.scss create mode 100644 nkebao/src/pages/work/index.tsx create mode 100644 package.json create mode 100644 yarn.lock diff --git a/nkebao/package.json b/nkebao/package.json index f9f4ac6e..8d148544 100644 --- a/nkebao/package.json +++ b/nkebao/package.json @@ -6,6 +6,8 @@ "antd": "^5.13.1", "antd-mobile": "^5.39.1", "axios": "^1.6.7", + "echarts": "^5.6.0", + "echarts-for-react": "^3.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.20.0", diff --git a/nkebao/src/App.tsx b/nkebao/src/App.tsx index 40792893..9138ddb5 100644 --- a/nkebao/src/App.tsx +++ b/nkebao/src/App.tsx @@ -1,8 +1,5 @@ import React from "react"; import AppRouter from "@/router"; -import { Button } from "antd"; -import { Button as MobileButton } from "antd-mobile"; - function App() { return ( <> diff --git a/nkebao/src/com/Layout/Layout.tsx b/nkebao/src/components/Layout/Layout.tsx similarity index 73% rename from nkebao/src/com/Layout/Layout.tsx rename to nkebao/src/components/Layout/Layout.tsx index 40580895..2cef351d 100644 --- a/nkebao/src/com/Layout/Layout.tsx +++ b/nkebao/src/components/Layout/Layout.tsx @@ -1,20 +1,20 @@ -import React from "react"; -import "layout.module.scss"; -interface LayoutProps { - loading?: boolean; - children?: React.ReactNode; - header?: React.ReactNode; - footer?: React.ReactNode; -} - -const Layout: React.FC = ({ children, header, footer }) => { - return ( -
- {header &&
{header}
} -
{children}
- {footer &&
{footer}
} -
- ); -}; - -export default Layout; +import React from "react"; +import styles from "./layout.module.scss"; +interface LayoutProps { + loading?: boolean; + children?: React.ReactNode; + header?: React.ReactNode; + footer?: React.ReactNode; +} + +const Layout: React.FC = ({ children, header, footer }) => { + return ( +
+ {header &&
{header}
} +
{children}
+ {footer &&
{footer}
} +
+ ); +}; + +export default Layout; diff --git a/nkebao/src/com/Layout/layout.module.scss b/nkebao/src/components/Layout/layout.module.scss similarity index 100% rename from nkebao/src/com/Layout/layout.module.scss rename to nkebao/src/components/Layout/layout.module.scss diff --git a/nkebao/src/components/LineChart.tsx b/nkebao/src/components/LineChart.tsx new file mode 100644 index 00000000..7bd9db0d --- /dev/null +++ b/nkebao/src/components/LineChart.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import ReactECharts from "echarts-for-react"; + +interface LineChartProps { + title?: string; + xData: string[]; + yData: number[]; + height?: number | string; +} + +const LineChart: React.FC = ({ + title = "", + xData, + yData, + height = 200, +}) => { + const option = { + title: { + text: title, + left: "center", + textStyle: { fontSize: 16 }, + }, + tooltip: { trigger: "axis" }, + xAxis: { + type: "category", + data: xData, + boundaryGap: false, + }, + yAxis: { + type: "value", + boundaryGap: ["10%", "10%"], // 上下留白 + min: (value: any) => value.min - 10, // 下方多留一点空间 + max: (value: any) => value.max + 10, // 上方多留一点空间 + minInterval: 1, + axisLabel: { margin: 12 }, + }, + series: [ + { + data: yData, + type: "line", + smooth: true, + symbol: "circle", + lineStyle: { color: "#1677ff" }, + itemStyle: { color: "#1677ff" }, + }, + ], + grid: { left: 40, right: 24, top: 40, bottom: 32 }, + }; + + return ; +}; + +export default LineChart; diff --git a/nkebao/src/components/MeauMobile/MeauMoible.tsx b/nkebao/src/components/MeauMobile/MeauMoible.tsx new file mode 100644 index 00000000..4fe432f8 --- /dev/null +++ b/nkebao/src/components/MeauMobile/MeauMoible.tsx @@ -0,0 +1,81 @@ +import React, { useState, useEffect } from "react"; +import { TabBar } from "antd-mobile"; +import { + AppOutline, + ShopbagOutline, + PieOutline, + UserOutline, +} from "antd-mobile-icons"; +import { useLocation, useNavigate } from "react-router-dom"; + +const tabs = [ + { + key: "home", + title: "首页", + icon: , + path: "/", + }, + { + key: "scene", + title: "场景获客", + icon: , + path: "/scene", + }, + { + key: "work", + title: "工作台", + icon: , + path: "/work", + }, + { + key: "mine", + title: "我的", + icon: , + path: "/mine", + }, +]; + +// 需要展示菜单的路由白名单(可根据实际业务调整) +const menuPaths = ["/", "/scene", "/work", "/mine"]; + +const MeauMobile: React.FC = () => { + const location = useLocation(); + const navigate = useNavigate(); + const [activeKey, setActiveKey] = useState("home"); + + // 根据当前路由自动设置 activeKey,支持嵌套路由 + useEffect(() => { + const found = tabs.find((tab) => + tab.path === "/" + ? location.pathname === "/" + : location.pathname.startsWith(tab.path) + ); + if (found) setActiveKey(found.key); + }, [location.pathname]); + + // 判断当前路由是否需要展示菜单 + const showMenu = menuPaths.some((path) => + path === "/" + ? location.pathname === "/" + : location.pathname.startsWith(path) + ); + if (!showMenu) return null; + + return ( + { + setActiveKey(key); + const tab = tabs.find((t) => t.key === key); + if (tab && tab.path) navigate(tab.path); + }} + > + {tabs.map((item) => ( + + ))} + + ); +}; + +export default MeauMobile; diff --git a/nkebao/src/pages/home/api.ts b/nkebao/src/pages/home/api.ts index 53514714..25016d2d 100644 --- a/nkebao/src/pages/home/api.ts +++ b/nkebao/src/pages/home/api.ts @@ -10,5 +10,22 @@ export function getWechatStats() { return request('/v1/dashboard/wechat-stats', {}, 'GET'); } -// 你可以根据需要继续添加其他接口 -// 例如:场景获客统计、今日数据统计等 +// 今日数据统计 +export function getTodayStats() { + return request('/v1/dashboard/today-stats', {}, 'GET'); +} + +// 首页仪表盘总览 +export function getDashboard() { + return request('/v1/dashboard', {}, 'GET'); +} + +// 获客场景统计 +export function getPlanStats(params:any) { + return request('/v1/dashboard/plan-stats', params, 'GET'); +} + +// 近七天统计 +export function getSevenDayStats() { + return request('/v1/dashboard/sevenDay-stats', {}, 'GET'); +} diff --git a/nkebao/src/pages/home/index.module.scss b/nkebao/src/pages/home/index.module.scss new file mode 100644 index 00000000..e2c392aa --- /dev/null +++ b/nkebao/src/pages/home/index.module.scss @@ -0,0 +1,70 @@ +.home-page { + padding: 12px; + background: #f5f5f5; +} + +.home-cards { + display: flex; + gap: 12px; + margin-bottom: 12px; + > :global(.adm-card) { + flex: 1; + } +} + +.home-section { + 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; +} + +.home-scene-stats { + display: flex; + justify-content: space-between; + margin: 0 8px 8px 8px; +} +.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 { + text-align: center; + padding: 8px 0; + background: #f7f8fa; + border-radius: 8px; +} +.home-today-value { + font-size: 18px; + font-weight: bold; + color: #1677ff; +} +.home-today-label { + font-size: 12px; + color: #888; +} + +.home-chart { + margin-top: 8px; + width: 100%; + min-height: 100px; +} \ No newline at end of file diff --git a/nkebao/src/pages/home/index.scss b/nkebao/src/pages/home/index.scss deleted file mode 100644 index d8def7fd..00000000 --- a/nkebao/src/pages/home/index.scss +++ /dev/null @@ -1,35 +0,0 @@ -.home-page { - padding: 16px; - background: #f5f5f5; - min-height: 100vh; - .home-title { - font-size: 22px; - font-weight: bold; - margin-bottom: 16px; - color: #1677ff; - text-align: center; - } - .home-cards { - display: flex; - gap: 16px; - flex-direction: column; - .home-card { - .home-card-value { - font-size: 28px; - font-weight: bold; - color: #1677ff; - margin-bottom: 8px; - } - .home-card-desc { - font-size: 14px; - color: #888; - } - } - } - .home-loading { - margin-top: 24px; - text-align: center; - color: #999; - font-size: 16px; - } -} \ No newline at end of file diff --git a/nkebao/src/pages/home/index.tsx b/nkebao/src/pages/home/index.tsx index e96bd934..f63752b6 100644 --- a/nkebao/src/pages/home/index.tsx +++ b/nkebao/src/pages/home/index.tsx @@ -1,65 +1,121 @@ -import React, { useEffect, useState } from "react"; -import { Card, Toast } from "antd-mobile"; -import { getDeviceStats, getWechatStats } from "./api"; -import Layout from "@/com/Layout/Layout"; -import "./index.scss"; - -const Home: React.FC = () => { - const [stats, setStats] = useState({ - totalDevices: 0, - onlineDevices: 0, - totalWechatAccounts: 0, - onlineWechatAccounts: 0, - }); - const [loading, setLoading] = useState(true); - - useEffect(() => { - const fetchStats = async () => { - setLoading(true); - try { - const [device, wechat] = await Promise.all([ - getDeviceStats(), - getWechatStats(), - ]); - setStats({ - totalDevices: device.total || 0, - onlineDevices: device.online || 0, - totalWechatAccounts: wechat.total || 0, - onlineWechatAccounts: wechat.active || 0, - }); - } catch (err: any) { - Toast.show({ - content: err?.message || "数据加载失败", - position: "top", - }); - } finally { - setLoading(false); - } - }; - fetchStats(); - }, []); - - return ( - 首页 Home} - footer={
底部内容
} // 如有底部内容可加 - > -
- -
{stats.totalDevices}
-
在线设备:{stats.onlineDevices}
-
- -
{stats.totalWechatAccounts}
-
- 在线微信号:{stats.onlineWechatAccounts} -
-
-
- {loading &&
加载中...
} -
- ); -}; - -export default Home; +import React, { useEffect, useState } from "react"; +import { Card, NavBar, TabBar, Grid } from "antd-mobile"; +import { + AppOutline, + UserOutline, + PieOutline, // 替换 BarChartOutline + ShopbagOutline, +} from "antd-mobile-icons"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import Layout from "@/components/Layout/Layout"; +import style from "./index.module.scss"; +import LineChart from "@/components/LineChart"; +import { getPlanStats } from "./api"; + +const sceneStats = [ + { + label: "公众号获客", + value: 234, + icon: , + }, + { + label: "海报获客", + value: 167, + icon: , + }, + { + label: "抖音获客", + value: 156, + icon: , + }, + { + label: "小红书获客", + value: 89, + icon: , + }, +]; + +const todayStats = [ + { label: "朋友圈同步", value: 12 }, + { label: "群发任务", value: 8 }, + { label: "获客转化", value: "85%" }, + { label: "系统活跃度", value: "98%" }, +]; + +const Home: React.FC = () => { + useEffect(() => { + getPlanStats({ num: 4 }).then((res: any) => { + console.log(res); + }); + }, []); + + return ( + + 存客宝 + + } + footer={} + > +
+ {/* 统计卡片 */} +
+ +
设备数量
+
0
+
+ +
微信号数量
+
0
+
+ +
在线微信号
+
0
+
+
+ + {/* 场景获客统计 */} + +
场景获客统计
+
+ {sceneStats.map((item) => ( +
+
{item.icon}
+
{item.value}
+
{item.label}
+
+ ))} +
+
+ + {/* 今日数据 */} + +
今日数据
+ + {todayStats.map((item) => ( + +
+
{item.value}
+
{item.label}
+
+
+ ))} +
+
+ + {/* 每日获客趋势(静态图表占位) */} + +
每日获客趋势
+
+ +
+
+
+
+ ); +}; +export default Home; diff --git a/nkebao/src/pages/login/login.module.scss b/nkebao/src/pages/login/login.module.scss new file mode 100644 index 00000000..e69de29b diff --git a/nkebao/src/pages/login/login.tsx b/nkebao/src/pages/login/login.tsx new file mode 100644 index 00000000..a9a93068 --- /dev/null +++ b/nkebao/src/pages/login/login.tsx @@ -0,0 +1,74 @@ +import React, { useState } from "react"; +import { Form, Input, Button, Toast } from "antd-mobile"; +import { EyeInvisibleOutline, EyeOutline } from "antd-mobile-icons"; +import request from "@/api/request"; +import style from "./login.module.scss"; + +const Login: React.FC = () => { + const [loading, setLoading] = useState(false); + const [visible, setVisible] = useState(false); + + const onFinish = async (values: any) => { + setLoading(true); + try { + // 假设接口为 /api/login,实际请根据后端接口调整 + const res = await request("/api/login", values, "POST"); + // 登录成功后保存 token + localStorage.setItem("token", res.token); + Toast.show({ content: "登录成功", position: "top" }); + // 跳转首页或其他页面 + window.location.href = "/"; + } catch (err: any) { + Toast.show({ content: err?.message || "登录失败", position: "top" }); + } finally { + setLoading(false); + } + }; + + return ( +
+
账号登录
+
+ 登录 + + } + > + + + + + setVisible((v) => !v)}> + {visible ? : } +
+ } + /> + + + + ); +}; + +export default Login; diff --git a/nkebao/src/pages/mine/api.ts b/nkebao/src/pages/mine/api.ts new file mode 100644 index 00000000..53514714 --- /dev/null +++ b/nkebao/src/pages/mine/api.ts @@ -0,0 +1,14 @@ +import request from '@/api/request'; + +// 设备统计 +export function getDeviceStats() { + return request('/v1/dashboard/device-stats', {}, 'GET'); +} + +// 微信号统计 +export function getWechatStats() { + return request('/v1/dashboard/wechat-stats', {}, 'GET'); +} + +// 你可以根据需要继续添加其他接口 +// 例如:场景获客统计、今日数据统计等 diff --git a/nkebao/src/pages/mine/index.module.scss b/nkebao/src/pages/mine/index.module.scss new file mode 100644 index 00000000..53304f69 --- /dev/null +++ b/nkebao/src/pages/mine/index.module.scss @@ -0,0 +1,71 @@ +.home-page { + padding: 12px; + background: #f5f5f5; +} + +.home-cards { + display: flex; + gap: 12px; + margin-bottom: 12px; + > :global(.adm-card) { + flex: 1; + } +} + +.home-section { + 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; + justify-content: space-between; + margin: 0 8px 8px 8px; +} +.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 { + text-align: center; + padding: 8px 0; + background: #f7f8fa; + border-radius: 8px; +} +.home-today-value { + font-size: 18px; + font-weight: bold; + color: #1677ff; +} +.home-today-label { + font-size: 12px; + color: #888; +} + +.home-chart { + margin-top: 8px; + width: 100%; + min-height: 100px; +} \ No newline at end of file diff --git a/nkebao/src/pages/mine/index.tsx b/nkebao/src/pages/mine/index.tsx new file mode 100644 index 00000000..dc673c00 --- /dev/null +++ b/nkebao/src/pages/mine/index.tsx @@ -0,0 +1,132 @@ +import React, { useState } from "react"; +import { Card, NavBar, TabBar, Grid } from "antd-mobile"; +import { + AppOutline, + UserOutline, + PieOutline, // 替换 BarChartOutline + ShopbagOutline, + BellOutline, +} from "antd-mobile-icons"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import Layout from "@/components/Layout/Layout"; +import style from "./index.module.scss"; +const sceneStats = [ + { + label: "公众号获客", + value: 234, + icon: , + }, + { + label: "海报获客", + value: 167, + icon: , + }, + { + label: "抖音获客", + value: 156, + icon: , + }, + { + label: "小红书获客", + value: 89, + icon: , + }, +]; + +const todayStats = [ + { label: "朋友圈同步", value: 12 }, + { label: "群发任务", value: 8 }, + { label: "获客转化", value: "85%" }, + { label: "系统活跃度", value: "98%" }, +]; + +const Home: React.FC = () => { + return ( + + 存客宝 + + } + footer={} + > +
+ {/* 统计卡片 */} +
+ +
设备数量
+
0
+
+ +
微信号数量
+
0
+
+ +
在线微信号
+
0
+
+
+ + {/* 场景获客统计 */} + +
场景获客统计
+
+ {sceneStats.map((item) => ( +
+
{item.icon}
+
{item.value}
+
{item.label}
+
+ ))} +
+
+ + {/* 今日数据 */} + +
今日数据
+ + {todayStats.map((item) => ( + +
+
{item.value}
+
{item.label}
+
+
+ ))} +
+
+ + {/* 每日获客趋势(静态图表占位) */} + +
每日获客趋势
+
+ + + {/* x轴文字 */} + {["周一", "周二", "周三", "周四", "周五", "周六", "周日"].map( + (d, i) => ( + + {d} + + ) + )} + +
+
+
+
+ ); +}; + +export default Home; diff --git a/nkebao/src/pages/scene/api.ts b/nkebao/src/pages/scene/api.ts new file mode 100644 index 00000000..53514714 --- /dev/null +++ b/nkebao/src/pages/scene/api.ts @@ -0,0 +1,14 @@ +import request from '@/api/request'; + +// 设备统计 +export function getDeviceStats() { + return request('/v1/dashboard/device-stats', {}, 'GET'); +} + +// 微信号统计 +export function getWechatStats() { + return request('/v1/dashboard/wechat-stats', {}, 'GET'); +} + +// 你可以根据需要继续添加其他接口 +// 例如:场景获客统计、今日数据统计等 diff --git a/nkebao/src/pages/scene/index.module.scss b/nkebao/src/pages/scene/index.module.scss new file mode 100644 index 00000000..53304f69 --- /dev/null +++ b/nkebao/src/pages/scene/index.module.scss @@ -0,0 +1,71 @@ +.home-page { + padding: 12px; + background: #f5f5f5; +} + +.home-cards { + display: flex; + gap: 12px; + margin-bottom: 12px; + > :global(.adm-card) { + flex: 1; + } +} + +.home-section { + 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; + justify-content: space-between; + margin: 0 8px 8px 8px; +} +.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 { + text-align: center; + padding: 8px 0; + background: #f7f8fa; + border-radius: 8px; +} +.home-today-value { + font-size: 18px; + font-weight: bold; + color: #1677ff; +} +.home-today-label { + font-size: 12px; + color: #888; +} + +.home-chart { + margin-top: 8px; + width: 100%; + min-height: 100px; +} \ No newline at end of file diff --git a/nkebao/src/pages/scene/index.tsx b/nkebao/src/pages/scene/index.tsx new file mode 100644 index 00000000..dc673c00 --- /dev/null +++ b/nkebao/src/pages/scene/index.tsx @@ -0,0 +1,132 @@ +import React, { useState } from "react"; +import { Card, NavBar, TabBar, Grid } from "antd-mobile"; +import { + AppOutline, + UserOutline, + PieOutline, // 替换 BarChartOutline + ShopbagOutline, + BellOutline, +} from "antd-mobile-icons"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import Layout from "@/components/Layout/Layout"; +import style from "./index.module.scss"; +const sceneStats = [ + { + label: "公众号获客", + value: 234, + icon: , + }, + { + label: "海报获客", + value: 167, + icon: , + }, + { + label: "抖音获客", + value: 156, + icon: , + }, + { + label: "小红书获客", + value: 89, + icon: , + }, +]; + +const todayStats = [ + { label: "朋友圈同步", value: 12 }, + { label: "群发任务", value: 8 }, + { label: "获客转化", value: "85%" }, + { label: "系统活跃度", value: "98%" }, +]; + +const Home: React.FC = () => { + return ( + + 存客宝 + + } + footer={} + > +
+ {/* 统计卡片 */} +
+ +
设备数量
+
0
+
+ +
微信号数量
+
0
+
+ +
在线微信号
+
0
+
+
+ + {/* 场景获客统计 */} + +
场景获客统计
+
+ {sceneStats.map((item) => ( +
+
{item.icon}
+
{item.value}
+
{item.label}
+
+ ))} +
+
+ + {/* 今日数据 */} + +
今日数据
+ + {todayStats.map((item) => ( + +
+
{item.value}
+
{item.label}
+
+
+ ))} +
+
+ + {/* 每日获客趋势(静态图表占位) */} + +
每日获客趋势
+
+ + + {/* x轴文字 */} + {["周一", "周二", "周三", "周四", "周五", "周六", "周日"].map( + (d, i) => ( + + {d} + + ) + )} + +
+
+
+
+ ); +}; + +export default Home; diff --git a/nkebao/src/pages/work/api.ts b/nkebao/src/pages/work/api.ts new file mode 100644 index 00000000..53514714 --- /dev/null +++ b/nkebao/src/pages/work/api.ts @@ -0,0 +1,14 @@ +import request from '@/api/request'; + +// 设备统计 +export function getDeviceStats() { + return request('/v1/dashboard/device-stats', {}, 'GET'); +} + +// 微信号统计 +export function getWechatStats() { + return request('/v1/dashboard/wechat-stats', {}, 'GET'); +} + +// 你可以根据需要继续添加其他接口 +// 例如:场景获客统计、今日数据统计等 diff --git a/nkebao/src/pages/work/index.module.scss b/nkebao/src/pages/work/index.module.scss new file mode 100644 index 00000000..53304f69 --- /dev/null +++ b/nkebao/src/pages/work/index.module.scss @@ -0,0 +1,71 @@ +.home-page { + padding: 12px; + background: #f5f5f5; +} + +.home-cards { + display: flex; + gap: 12px; + margin-bottom: 12px; + > :global(.adm-card) { + flex: 1; + } +} + +.home-section { + 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; + justify-content: space-between; + margin: 0 8px 8px 8px; +} +.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 { + text-align: center; + padding: 8px 0; + background: #f7f8fa; + border-radius: 8px; +} +.home-today-value { + font-size: 18px; + font-weight: bold; + color: #1677ff; +} +.home-today-label { + font-size: 12px; + color: #888; +} + +.home-chart { + margin-top: 8px; + width: 100%; + min-height: 100px; +} \ No newline at end of file diff --git a/nkebao/src/pages/work/index.tsx b/nkebao/src/pages/work/index.tsx new file mode 100644 index 00000000..dc673c00 --- /dev/null +++ b/nkebao/src/pages/work/index.tsx @@ -0,0 +1,132 @@ +import React, { useState } from "react"; +import { Card, NavBar, TabBar, Grid } from "antd-mobile"; +import { + AppOutline, + UserOutline, + PieOutline, // 替换 BarChartOutline + ShopbagOutline, + BellOutline, +} from "antd-mobile-icons"; +import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import Layout from "@/components/Layout/Layout"; +import style from "./index.module.scss"; +const sceneStats = [ + { + label: "公众号获客", + value: 234, + icon: , + }, + { + label: "海报获客", + value: 167, + icon: , + }, + { + label: "抖音获客", + value: 156, + icon: , + }, + { + label: "小红书获客", + value: 89, + icon: , + }, +]; + +const todayStats = [ + { label: "朋友圈同步", value: 12 }, + { label: "群发任务", value: 8 }, + { label: "获客转化", value: "85%" }, + { label: "系统活跃度", value: "98%" }, +]; + +const Home: React.FC = () => { + return ( + + 存客宝 + + } + footer={} + > +
+ {/* 统计卡片 */} +
+ +
设备数量
+
0
+
+ +
微信号数量
+
0
+
+ +
在线微信号
+
0
+
+
+ + {/* 场景获客统计 */} + +
场景获客统计
+
+ {sceneStats.map((item) => ( +
+
{item.icon}
+
{item.value}
+
{item.label}
+
+ ))} +
+
+ + {/* 今日数据 */} + +
今日数据
+ + {todayStats.map((item) => ( + +
+
{item.value}
+
{item.label}
+
+
+ ))} +
+
+ + {/* 每日获客趋势(静态图表占位) */} + +
每日获客趋势
+
+ + + {/* x轴文字 */} + {["周一", "周二", "周三", "周四", "周五", "周六", "周日"].map( + (d, i) => ( + + {d} + + ) + )} + +
+
+
+
+ ); +}; + +export default Home; diff --git a/nkebao/src/router/module/home.tsx b/nkebao/src/router/module/home.tsx index 840b36dc..17a08aa0 100644 --- a/nkebao/src/router/module/home.tsx +++ b/nkebao/src/router/module/home.tsx @@ -1,11 +1,17 @@ -import Home from "@/pages/home/index"; - -const homeRoutes = [ - { - path: "/", - element: , - auth: false, // 不需要权限 - }, -]; - -export default homeRoutes; +import Home from "@/pages/home/index"; +import Login from "@/pages/login/login"; + +const homeRoutes = [ + { + path: "/", + element: , + auth: false, // 不需要权限 + }, + { + path: "/login", + element: , + auth: false, // 不需要权限 + }, +]; + +export default homeRoutes; diff --git a/package.json b/package.json new file mode 100644 index 00000000..f73eb4d6 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "echarts": "^5.6.0" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..aab17ca2 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,23 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +echarts@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6" + integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA== + dependencies: + tslib "2.3.0" + zrender "5.6.1" + +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +zrender@5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b" + integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag== + dependencies: + tslib "2.3.0"