From dd2f58dc784980f21917caf17a527438bd40fb88 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: Thu, 11 Sep 2025 17:20:15 +0800 Subject: [PATCH] =?UTF-8?q?refactor(profile):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=E4=B8=BA?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E8=B5=84=E6=96=99=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将用户设置功能从/mine/setting迁移到/profile路径 删除不再使用的mine模块相关代码 更新路由配置以指向新的个人资料页面 --- .../src/components/WebSocketExample.tsx | 251 ------ .../UserSetting.tsx => Profile/Profile.tsx} | 0 .../mobile/{mine/setting => Profile}/api.ts | 0 .../setting => Profile}/index.module.scss | 0 Touchkebao/src/pages/mobile/home/api.ts | 31 - .../src/pages/mobile/home/index.module.scss | 356 --------- Touchkebao/src/pages/mobile/home/index.tsx | 262 ------- .../src/pages/mobile/mine/content/form/api.ts | 26 - .../pages/mobile/mine/content/form/data.ts | 61 -- .../mine/content/form/index.module.scss | 140 ---- .../pages/mobile/mine/content/form/index.tsx | 372 --------- .../src/pages/mobile/mine/content/list/api.ts | 49 -- .../pages/mobile/mine/content/list/data.ts | 66 -- .../mine/content/list/index.module.scss | 217 ----- .../pages/mobile/mine/content/list/index.tsx | 314 -------- .../mobile/mine/content/materials/form/api.ts | 20 - .../mine/content/materials/form/data.ts | 93 --- .../content/materials/form/index.module.scss | 160 ---- .../mine/content/materials/form/index.tsx | 403 ---------- .../mobile/mine/content/materials/list/api.ts | 37 - .../mine/content/materials/list/data.ts | 106 --- .../content/materials/list/index.module.scss | 615 --------------- .../mine/content/materials/list/index.tsx | 409 ---------- .../mobile/mine/devices/DeviceDetail.tsx | 392 ---------- .../src/pages/mobile/mine/devices/api.ts | 44 -- .../mobile/mine/devices/index.module.scss | 173 ---- .../src/pages/mobile/mine/devices/index.tsx | 442 ----------- Touchkebao/src/pages/mobile/mine/main/api.ts | 9 - .../pages/mobile/mine/main/index.module.scss | 210 ----- .../src/pages/mobile/mine/main/index.tsx | 232 ------ .../mine/recharge/index/index.module.scss | 440 ----------- .../mobile/mine/recharge/index/index.tsx | 371 --------- .../pages/mobile/mine/recharge/order/api.ts | 197 ----- .../pages/mobile/mine/recharge/order/data.ts | 40 - .../mine/recharge/order/index.module.scss | 242 ------ .../mobile/mine/recharge/order/index.tsx | 344 -------- .../src/pages/mobile/mine/setting/About.tsx | 152 ---- .../src/pages/mobile/mine/setting/Privacy.tsx | 125 --- .../src/pages/mobile/mine/setting/README.md | 188 ----- .../mobile/mine/setting/SecuritySetting.tsx | 224 ------ .../src/pages/mobile/mine/setting/index.tsx | 306 -------- .../mobile/mine/traffic-pool/detail/api.ts | 25 - .../mobile/mine/traffic-pool/detail/data.ts | 108 --- .../traffic-pool/detail/index.module.scss | 432 ---------- .../mobile/mine/traffic-pool/detail/index.tsx | 709 ----------------- .../mine/traffic-pool/list/BatchAddModal.tsx | 57 -- .../traffic-pool/list/DataAnalysisPanel.tsx | 84 -- .../mine/traffic-pool/list/FilterModal.tsx | 169 ---- .../mobile/mine/traffic-pool/list/api.ts | 18 - .../mobile/mine/traffic-pool/list/data.ts | 51 -- .../mine/traffic-pool/list/dataAnyx.tsx | 182 ----- .../mine/traffic-pool/list/index.module.scss | 65 -- .../mobile/mine/traffic-pool/list/index.tsx | 260 ------ .../mobile/mine/wechat-accounts/detail/api.ts | 29 - .../mine/wechat-accounts/detail/data.ts | 54 -- .../wechat-accounts/detail/detail.module.scss | 740 ------------------ .../mine/wechat-accounts/detail/index.tsx | 557 ------------- .../mobile/mine/wechat-accounts/list/api.ts | 31 - .../wechat-accounts/list/index.module.scss | 171 ---- .../mine/wechat-accounts/list/index.tsx | 250 ------ Touchkebao/src/router/module/common.tsx | 7 - Touchkebao/src/router/module/mine.tsx | 96 --- Touchkebao/src/router/module/mobile.tsx | 4 +- 63 files changed, 2 insertions(+), 12216 deletions(-) delete mode 100644 Touchkebao/src/components/WebSocketExample.tsx rename Touchkebao/src/pages/mobile/{mine/setting/UserSetting.tsx => Profile/Profile.tsx} (100%) rename Touchkebao/src/pages/mobile/{mine/setting => Profile}/api.ts (100%) rename Touchkebao/src/pages/mobile/{mine/setting => Profile}/index.module.scss (100%) delete mode 100644 Touchkebao/src/pages/mobile/home/api.ts delete mode 100644 Touchkebao/src/pages/mobile/home/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/home/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/content/form/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/form/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/form/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/content/form/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/content/list/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/list/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/list/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/content/list/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/form/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/form/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/form/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/form/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/list/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/list/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/list/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/content/materials/list/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/devices/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/devices/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/devices/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/main/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/main/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/main/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/index/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/index/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/order/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/order/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/order/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/recharge/order/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/setting/About.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/setting/Privacy.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/setting/README.md delete mode 100644 Touchkebao/src/pages/mobile/mine/setting/SecuritySetting.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/setting/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/BatchAddModal.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/DataAnalysisPanel.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/FilterModal.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/detail/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/detail/data.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/detail/detail.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/detail/index.tsx delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/list/api.ts delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/list/index.module.scss delete mode 100644 Touchkebao/src/pages/mobile/mine/wechat-accounts/list/index.tsx delete mode 100644 Touchkebao/src/router/module/mine.tsx diff --git a/Touchkebao/src/components/WebSocketExample.tsx b/Touchkebao/src/components/WebSocketExample.tsx deleted file mode 100644 index e8816e5b..00000000 --- a/Touchkebao/src/components/WebSocketExample.tsx +++ /dev/null @@ -1,251 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { Button, Card, List, Badge, Toast } from "antd-mobile"; -import { - useWebSocketStore, - WebSocketStatus, - WebSocketMessage, -} from "@/store/module/websocket/websocket"; - -/** - * WebSocket使用示例组件 - * 展示如何使用WebSocket store进行消息收发 - */ -const WebSocketExample: React.FC = () => { - const [messageInput, setMessageInput] = useState(""); - - // 使用WebSocket store - const { - status, - messages, - unreadCount, - connect, - disconnect, - sendMessage, - sendCommand, - clearMessages, - markAsRead, - reconnect, - } = useWebSocketStore(); - - // 连接状态显示 - const getStatusText = () => { - switch (status) { - case WebSocketStatus.DISCONNECTED: - return "未连接"; - case WebSocketStatus.CONNECTING: - return "连接中..."; - case WebSocketStatus.CONNECTED: - return "已连接"; - case WebSocketStatus.RECONNECTING: - return "重连中..."; - case WebSocketStatus.ERROR: - return "连接错误"; - default: - return "未知状态"; - } - }; - - // 获取状态颜色 - const getStatusColor = () => { - switch (status) { - case WebSocketStatus.CONNECTED: - return "success"; - case WebSocketStatus.CONNECTING: - case WebSocketStatus.RECONNECTING: - return "warning"; - case WebSocketStatus.ERROR: - return "danger"; - default: - return "default"; - } - }; - - // 发送消息 - const handleSendMessage = () => { - if (!messageInput.trim()) { - Toast.show({ content: "请输入消息内容", position: "top" }); - return; - } - - sendMessage({ - type: "chat", - content: { - text: messageInput, - timestamp: Date.now(), - }, - sender: "user", - receiver: "all", - }); - - setMessageInput(""); - }; - - // 发送命令 - const handleSendCommand = (cmdType: string) => { - sendCommand(cmdType, { - data: "示例数据", - timestamp: Date.now(), - }); - }; - - // 格式化时间 - const formatTime = (timestamp: number) => { - return new Date(timestamp).toLocaleTimeString(); - }; - - return ( -
- -
- -
- - {getStatusText()} -
- -
- - - - - -
- - - 0 ? `(${unreadCount} 条未读)` : ""}`} - extra={ -
- - -
- } - style={{ marginTop: "16px" }} - > - - {messages.length === 0 ? ( - 暂无消息 - ) : ( - messages.map((message: WebSocketMessage) => ( - -
- {formatTime(message.timestamp)} - {message.type} -
-
- {typeof message.content === "string" - ? message.content - : JSON.stringify(message.content, null, 2)} -
-
- )) - )} -
-
- - -
- setMessageInput(e.target.value)} - placeholder="输入消息内容" - style={{ - flex: 1, - padding: "8px 12px", - border: "1px solid #d9d9d9", - borderRadius: "4px", - fontSize: "14px", - }} - onKeyPress={e => e.key === "Enter" && handleSendMessage()} - /> - -
- -
- - - - - -
-
- - -
-

1. 点击"连接"按钮建立WebSocket连接

-

2. 连接成功后可以发送消息和命令

-

3. 收到的消息会显示在消息列表中

-

4. 页面刷新后会自动重连(如果之前是连接状态)

-

5. 支持自动重连和错误处理

-
-
-
- ); -}; - -export default WebSocketExample; diff --git a/Touchkebao/src/pages/mobile/mine/setting/UserSetting.tsx b/Touchkebao/src/pages/mobile/Profile/Profile.tsx similarity index 100% rename from Touchkebao/src/pages/mobile/mine/setting/UserSetting.tsx rename to Touchkebao/src/pages/mobile/Profile/Profile.tsx diff --git a/Touchkebao/src/pages/mobile/mine/setting/api.ts b/Touchkebao/src/pages/mobile/Profile/api.ts similarity index 100% rename from Touchkebao/src/pages/mobile/mine/setting/api.ts rename to Touchkebao/src/pages/mobile/Profile/api.ts diff --git a/Touchkebao/src/pages/mobile/mine/setting/index.module.scss b/Touchkebao/src/pages/mobile/Profile/index.module.scss similarity index 100% rename from Touchkebao/src/pages/mobile/mine/setting/index.module.scss rename to Touchkebao/src/pages/mobile/Profile/index.module.scss diff --git a/Touchkebao/src/pages/mobile/home/api.ts b/Touchkebao/src/pages/mobile/home/api.ts deleted file mode 100644 index 7b528180..00000000 --- a/Touchkebao/src/pages/mobile/home/api.ts +++ /dev/null @@ -1,31 +0,0 @@ -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"); -} - -// 今日数据统计 -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/Touchkebao/src/pages/mobile/home/index.module.scss b/Touchkebao/src/pages/mobile/home/index.module.scss deleted file mode 100644 index 9c8acd09..00000000 --- a/Touchkebao/src/pages/mobile/home/index.module.scss +++ /dev/null @@ -1,356 +0,0 @@ -.home-page { - padding: 12px; -} - -.content-wrapper { - display: flex; - flex-direction: column; - gap: 12px; -} - -// 导航栏样式 -.nav-title { - display: flex; - width: 100%; - justify-content: center; -} - -.nav-text { - color: var(--primary-color); - font-weight: 700; - font-size: 18px; - text-shadow: 0 2px 4px rgba(24, 142, 238, 0.2); -} - -.nav-right { - display: flex; - align-items: center; - gap: 8px; -} - -.error-tip { - font-size: 12px; - color: #f97316; - background: #fef3c7; - padding: 4px 8px; - border-radius: 4px; - margin-right: 8px; -} - -.nav-button { - padding: 8px; - border-radius: 50%; - border: none; - background: transparent; - cursor: pointer; - transition: background-color 0.2s; - - &:hover { - background: #f3f4f6; - } -} - -// 统计卡片网格 -.stats-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 12px; -} - -.stat-card { - background: white; - border-radius: 8px; - padding: 12px; - display: flex; - flex-direction: column; - gap: 8px; - cursor: pointer; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - transition: all 0.3s ease; - - &:hover { - transform: translateY(-1px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); - } -} - -.stat-label { - font-size: 14px; - color: #333; - line-height: 1.2; - font-weight: bold; -} - -.stat-value { - font-size: 20px; - font-weight: 700; - color: #3b82f6; - line-height: 1.2; - display: flex; - align-items: center; - justify-content: space-between; -} - -.progress-bar { - height: 4px; - background: #e5e7eb; - border-radius: 2px; - margin-top: 8px; - overflow: hidden; -} - -.progress-fill { - height: 100%; - background: #3b82f6; - border-radius: 2px; - transition: width 0.3s ease; -} - -// Loading状态样式 -.stat-card { - .stat-label:empty::before { - content: ""; - display: block; - width: 60px; - height: 12px; - background: #f0f0f0; - border-radius: 2px; - animation: pulse 1.5s ease-in-out infinite; - } - - .stat-value { - span:empty::before { - content: ""; - display: block; - width: 40px; - height: 20px; - background: #f0f0f0; - border-radius: 2px; - animation: pulse 1.5s ease-in-out infinite; - } - - div:empty::before { - content: ""; - display: block; - width: 20px; - height: 20px; - background: #f0f0f0; - border-radius: 4px; - animation: pulse 1.5s ease-in-out infinite; - } - } -} - -@keyframes pulse { - 0%, - 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } -} - -// 通用区域样式 -.section { - background: white; - border-radius: 12px; - padding: 16px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - transition: all 0.3s ease; - - &:hover { - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - } -} - -.section-header { - margin-bottom: 12px; -} - -.section-title { - font-size: 14px; - font-weight: 600; - color: #333; - position: relative; - padding-left: 8px; - - &::before { - content: ""; - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - width: 3px; - height: 14px; - background: var(--primary-gradient); - border-radius: 2px; - } -} - -// 场景统计网格 -.scene-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 8px; -} - -.scene-item { - text-align: center; - padding: 8px 4px; -} - -.scene-icon { - width: 36px; - height: 36px; - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - margin: 0 auto 6px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - overflow: hidden; -} - -.scene-image { - width: 100%; - height: 100%; - object-fit: cover; - border-radius: 8px; -} - -.scene-value { - font-size: 16px; - font-weight: 700; - color: #333; - margin-bottom: 2px; - line-height: 1.2; -} - -.scene-label { - font-size: 10px; - color: #666; - line-height: 1.2; -} - -// 今日数据网格 -.today-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 12px; -} - -.today-item { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background: #f8fafc; - border-radius: 8px; - transition: all 0.3s ease; - cursor: pointer; - - &:hover { - background: #f1f5f9; - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - } -} - -.today-icon { - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - background: white; - border-radius: 50%; - flex-shrink: 0; -} - -.today-value { - font-size: 18px; - font-weight: 700; - color: #333; - line-height: 1.2; -} - -.today-label { - font-size: 12px; - color: #666; - line-height: 1.2; -} - -// 图表容器 -.chart-container { - width: 100%; - min-height: 160px; - border-radius: 8px; - background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); - padding: 12px; -} - -// 响应式设计 -@media (max-width: 375px) { - .home-page { - padding: 8px; - } - - .stats-grid { - gap: 6px; - margin-bottom: 12px; - } - - .stat-card { - padding: 10px 6px; - } - - .stat-icon { - width: 28px; - height: 28px; - } - - .stat-value { - font-size: 16px; - } - - .stat-label { - font-size: 10px; - } - - .section { - padding: 12px; - margin-bottom: 8px; - } - - .scene-grid, - .today-grid { - gap: 6px; - } - - .scene-icon { - width: 32px; - height: 32px; - } - - .scene-value { - font-size: 14px; - } - - .scene-label { - font-size: 9px; - } - - .today-value { - font-size: 12px; - } - - .today-label { - font-size: 9px; - } - - .chart-container { - min-height: 140px; - padding: 8px; - } -} diff --git a/Touchkebao/src/pages/mobile/home/index.tsx b/Touchkebao/src/pages/mobile/home/index.tsx deleted file mode 100644 index 9f4a65b6..00000000 --- a/Touchkebao/src/pages/mobile/home/index.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import NavCommon from "@/components/NavCommon"; -import { - MobileOutlined, - MessageOutlined, - TeamOutlined, - RiseOutlined, - LineChartOutlined, -} from "@ant-design/icons"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; -import Layout from "@/components/Layout/Layout"; -import LineChart from "@/components/LineChart"; -import { - getPlanStats, - getSevenDayStats, - getTodayStats, - getDashboard, -} from "./api"; -import style from "./index.module.scss"; -import UpdateNotification from "@/components/UpdateNotification"; - -interface DashboardData { - deviceNum?: number; - wechatNum?: number; - aliveWechatNum?: number; -} - -interface SevenDayStatsData { - date?: string[]; - allNum?: number[]; -} - -const Home: React.FC = () => { - const navigate = useNavigate(); - const [sceneStats, setSceneStats] = useState([]); - const [todayStats, setTodayStats] = useState([]); - const [dashboard, setDashboard] = useState({}); - const [sevenDayStats, setSevenDayStats] = useState({}); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - const fetchData = async () => { - try { - setIsLoading(true); - - // 并行请求多个接口 - const [dashboardResult, planStatsResult, sevenDayResult, todayResult] = - await Promise.allSettled([ - getDashboard(), - getPlanStats({ num: 4 }), - getSevenDayStats(), - getTodayStats(), - ]); - - // 处理仪表板数据 - if (dashboardResult.status === "fulfilled") { - setDashboard(dashboardResult.value); - } else { - console.warn("仪表板API失败:", dashboardResult.reason); - } - - // 处理计划统计数据 - if (planStatsResult.status === "fulfilled") { - setSceneStats(planStatsResult.value); - } else { - console.warn("计划统计API失败:", planStatsResult.reason); - } - - // 处理七天统计数据 - if (sevenDayResult.status === "fulfilled") { - setSevenDayStats(sevenDayResult.value); - } else { - console.warn("七天统计API失败:", sevenDayResult.reason); - } - - // 处理今日统计数据 - if (todayResult.status === "fulfilled") { - const todayStatsData = [ - { - label: "同步朋友圈", - value: todayResult.value?.momentsNum || 0, - icon: ( - - ), - color: "#8b5cf6", - path: "/workspace/moments-sync", - }, - { - label: "群发任务", - value: todayResult.value?.groupPushNum || 0, - icon: , - color: "#f97316", - path: "/workspace/group-push", - }, - { - label: "获客转化率", - value: todayResult.value?.passRate || "0%", - icon: , - color: "#22c55e", - path: "/scenarios", - }, - { - label: "系统活跃度", - value: todayResult.value?.sysActive || "0%", - icon: ( - - ), - color: "#3b82f6", - path: "/workspace", - }, - ]; - setTodayStats(todayStatsData); - } else { - console.warn("今日统计API失败:", todayResult.reason); - } - } catch (error) { - console.error("获取数据失败:", error); - } finally { - setIsLoading(false); - } - }; - - fetchData(); - }, []); - - const handleDevicesClick = () => { - navigate("/mine/devices"); - }; - - const handleWechatClick = () => { - navigate("/wechat-accounts"); - }; - - const handleAliveWechatClick = () => { - navigate("/wechat-accounts?wechatStatus=1"); - }; - - return ( - } title="存客宝" />} - footer={} - loading={isLoading} - > -
-
- {/* 统计卡片 */} -
-
-
设备数量
-
- {dashboard.deviceNum || 42} - -
-
-
-
微信号数量
-
- {dashboard.wechatNum || 42} - -
-
-
-
在线微信号
-
- {dashboard.aliveWechatNum || 35} - -
-
-
0 - ? ((dashboard.aliveWechatNum || 0) / - (dashboard.wechatNum || 1)) * - 100 - : 0 - }%`, - }} - >
-
-
-
- - {/* 场景获客统计 */} -
-
-

场景获客统计

-
-
- {sceneStats.map(scenario => ( -
- navigate( - `/scenarios/list/${scenario.id}/${encodeURIComponent( - scenario.name, - )}`, - ) - } - > -
- {scenario.name} -
-
{scenario.allNum}
-
{scenario.name}
-
- ))} -
-
- - {/* 今日数据统计 */} -
-
-

今日数据

-
-
- {todayStats.map((stat, index) => ( -
stat.path && navigate(stat.path)} - > -
{stat.icon}
-
-
{stat.value}
-
{stat.label}
-
-
- ))} -
-
- - {/* 趋势图表 - 保持原有实现 */} -
-
- 获客趋势 -
-
- -
-
-
-
- -
- ); -}; - -export default Home; diff --git a/Touchkebao/src/pages/mobile/mine/content/form/api.ts b/Touchkebao/src/pages/mobile/mine/content/form/api.ts deleted file mode 100644 index bc136d88..00000000 --- a/Touchkebao/src/pages/mobile/mine/content/form/api.ts +++ /dev/null @@ -1,26 +0,0 @@ -import request from "@/api/request"; -import { - ContentLibrary, - CreateContentLibraryParams, - UpdateContentLibraryParams, -} from "./data"; - -// 获取内容库详情 -export function getContentLibraryDetail(id: string): Promise { - return request("/v1/content/library/detail", { id }, "GET"); -} - -// 创建内容库 -export function createContentLibrary( - params: CreateContentLibraryParams, -): Promise { - return request("/v1/content/library/create", params, "POST"); -} - -// 更新内容库 -export function updateContentLibrary( - params: UpdateContentLibraryParams, -): Promise { - const { id, ...data } = params; - return request(`/v1/content/library/update`, { id, ...data }, "POST"); -} diff --git a/Touchkebao/src/pages/mobile/mine/content/form/data.ts b/Touchkebao/src/pages/mobile/mine/content/form/data.ts deleted file mode 100644 index 3f3f3425..00000000 --- a/Touchkebao/src/pages/mobile/mine/content/form/data.ts +++ /dev/null @@ -1,61 +0,0 @@ -// 内容库表单数据类型定义 -export interface ContentLibrary { - id: string; - name: string; - sourceType: number; // 1=微信好友, 2=聊天群 - creatorName?: string; - updateTime: string; - status: number; // 0=未启用, 1=已启用 - itemCount?: number; - createTime: string; - sourceFriends?: string[]; - sourceGroups?: string[]; - keywordInclude?: string[]; - keywordExclude?: string[]; - aiPrompt?: string; - timeEnabled?: number; - timeStart?: string; - timeEnd?: string; - selectedFriends?: any[]; - selectedGroups?: any[]; - selectedGroupMembers?: WechatGroupMember[]; -} - -// 微信群成员 -export interface WechatGroupMember { - id: string; - nickname: string; - wechatId: string; - avatar: string; - gender?: "male" | "female"; - role?: "owner" | "admin" | "member"; - joinTime?: string; -} - -// API 响应类型 -export interface ApiResponse { - code: number; - msg: string; - data: T; -} - -// 创建内容库参数 -export interface CreateContentLibraryParams { - name: string; - sourceType: number; - sourceFriends?: string[]; - sourceGroups?: string[]; - keywordInclude?: string[]; - keywordExclude?: string[]; - aiPrompt?: string; - timeEnabled?: number; - timeStart?: string; - timeEnd?: string; -} - -// 更新内容库参数 -export interface UpdateContentLibraryParams - extends Partial { - id: string; - status?: number; -} diff --git a/Touchkebao/src/pages/mobile/mine/content/form/index.module.scss b/Touchkebao/src/pages/mobile/mine/content/form/index.module.scss deleted file mode 100644 index b2f49942..00000000 --- a/Touchkebao/src/pages/mobile/mine/content/form/index.module.scss +++ /dev/null @@ -1,140 +0,0 @@ -.form-page { - background: #f7f8fa; - padding: 16px; -} - -.form-main { - max-width: 420px; - margin: 0 auto; - padding: 16px 0 0 0; -} - -.form-section { - margin-bottom: 18px; -} - -.form-card { - border-radius: 16px; - box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06); - padding: 24px 18px 18px 18px; - background: #fff; -} - -.form-label { - font-weight: 600; - font-size: 16px; - color: #222; - display: block; - margin-bottom: 6px; -} - -.section-title { - font-size: 16px; - font-weight: 700; - color: #222; - margin-top: 28px; - margin-bottom: 12px; - letter-spacing: 0.5px; -} - -.section-block { - padding: 12px 0 8px 0; - border-bottom: 1px solid #f0f0f0; - margin-bottom: 8px; -} - -.tabs-bar { - .adm-tabs-header { - background: #f7f8fa; - border-radius: 8px; - margin-bottom: 8px; - } - .adm-tabs-tab { - font-size: 15px; - font-weight: 500; - padding: 8px 0; - } -} - -.collapse { - margin-top: 12px; - .adm-collapse-panel-content { - padding-bottom: 8px; - background: #f8fafc; - border-radius: 10px; - padding: 18px 14px 10px 14px; - margin-top: 2px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03); - } - .form-section { - margin-bottom: 22px; - } - .form-label { - font-size: 15px; - font-weight: 500; - margin-bottom: 4px; - color: #333; - } - .adm-input { - min-height: 42px; - font-size: 15px; - border-radius: 7px; - margin-bottom: 2px; - } -} - -.ai-row, -.section-block { - display: flex; - align-items: center; - gap: 12px; -} - -.ai-desc { - color: #888; - font-size: 13px; - flex: 1; -} - -.date-row, -.section-block { - display: flex; - gap: 12px; - align-items: center; -} - -.adm-input { - min-height: 44px; - font-size: 15px; - border-radius: 8px; -} - -.submit-btn { - margin-top: 32px; - height: 48px !important; - border-radius: 10px !important; - font-size: 17px; - font-weight: 600; - letter-spacing: 1px; -} - -@media (max-width: 600px) { - .form-main { - max-width: 100vw; - padding: 0; - } - .form-card { - border-radius: 0; - box-shadow: none; - padding: 16px 6px 12px 6px; - } - .section-title { - font-size: 15px; - margin-top: 22px; - margin-bottom: 8px; - } - .submit-btn { - height: 44px !important; - font-size: 15px; - } -} diff --git a/Touchkebao/src/pages/mobile/mine/content/form/index.tsx b/Touchkebao/src/pages/mobile/mine/content/form/index.tsx deleted file mode 100644 index 2aed0816..00000000 --- a/Touchkebao/src/pages/mobile/mine/content/form/index.tsx +++ /dev/null @@ -1,372 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { Input as AntdInput, Switch } from "antd"; -import { Button, Collapse, Toast, DatePicker, Tabs } from "antd-mobile"; -import NavCommon from "@/components/NavCommon"; -import FriendSelection from "@/components/FriendSelection"; -import GroupSelection from "@/components/GroupSelection"; -import Layout from "@/components/Layout/Layout"; -import style from "./index.module.scss"; -import request from "@/api/request"; -import { getContentLibraryDetail, updateContentLibrary } from "./api"; -import { GroupSelectionItem } from "@/components/GroupSelection/data"; -import { FriendSelectionItem } from "@/components/FriendSelection/data"; - -const { TextArea } = AntdInput; - -function formatDate(date: Date | null) { - if (!date) return ""; - // 格式化为 YYYY-MM-DD - const y = date.getFullYear(); - const m = (date.getMonth() + 1).toString().padStart(2, "0"); - const d = date.getDate().toString().padStart(2, "0"); - return `${y}-${m}-${d}`; -} - -export default function ContentForm() { - const navigate = useNavigate(); - const { id } = useParams<{ id?: string }>(); - const isEdit = !!id; - const [sourceType, setSourceType] = useState<"friends" | "groups">("friends"); - const [name, setName] = useState(""); - const [friendsGroups, setSelectedFriends] = useState([]); - const [friendsGroupsOptions, setSelectedFriendsOptions] = useState< - FriendSelectionItem[] - >([]); - const [selectedGroups, setSelectedGroups] = useState([]); - const [selectedGroupsOptions, setSelectedGroupsOptions] = useState< - GroupSelectionItem[] - >([]); - const [useAI, setUseAI] = useState(false); - const [aiPrompt, setAIPrompt] = useState(""); - const [enabled, setEnabled] = useState(true); - const [dateRange, setDateRange] = useState<[Date | null, Date | null]>([ - null, - null, - ]); - const [showStartPicker, setShowStartPicker] = useState(false); - const [showEndPicker, setShowEndPicker] = useState(false); - const [keywordsInclude, setKeywordsInclude] = useState(""); - const [keywordsExclude, setKeywordsExclude] = useState(""); - const [catchType, setCatchType] = useState([ - "text", - "image", - "video", - ]); - const [submitting, setSubmitting] = useState(false); - const [loading, setLoading] = useState(false); - - // 编辑模式下拉详情并回填 - useEffect(() => { - if (isEdit && id) { - setLoading(true); - getContentLibraryDetail(id) - .then(data => { - setName(data.name || ""); - setSourceType(data.sourceType === 1 ? "friends" : "groups"); - setSelectedFriends(data.sourceFriends || []); - setSelectedGroups(data.selectedGroups || []); - setSelectedGroupsOptions(data.selectedGroupsOptions || []); - setSelectedFriendsOptions(data.friendsGroupsOptions || []); - setKeywordsInclude((data.keywordInclude || []).join(",")); - setKeywordsExclude((data.keywordExclude || []).join(",")); - setCatchType(data.catchType || ["text", "image", "video"]); - setAIPrompt(data.aiPrompt || ""); - setUseAI(!!data.aiPrompt); - setEnabled(data.status === 1); - // 时间范围 - const start = data.timeStart || data.startTime; - const end = data.timeEnd || data.endTime; - setDateRange([ - start ? new Date(start) : null, - end ? new Date(end) : null, - ]); - }) - .catch(e => { - Toast.show({ - content: e?.message || "获取详情失败", - position: "top", - }); - }) - .finally(() => setLoading(false)); - } - }, [isEdit, id]); - - const handleSubmit = async (e?: React.FormEvent) => { - if (e) e.preventDefault(); - if (!name.trim()) { - Toast.show({ content: "请输入内容库名称", position: "top" }); - return; - } - setSubmitting(true); - try { - const payload = { - name, - sourceType: sourceType === "friends" ? 1 : 2, - friendsGroups: friendsGroups, - wechatGroups: selectedGroups, - groupMembers: {}, - keywordInclude: keywordsInclude - .split(/,|,|\n|\s+/) - .map(s => s.trim()) - .filter(Boolean), - keywordExclude: keywordsExclude - .split(/,|,|\n|\s+/) - .map(s => s.trim()) - .filter(Boolean), - catchType, - aiPrompt, - timeEnabled: dateRange[0] || dateRange[1] ? 1 : 0, - startTime: dateRange[0] ? formatDate(dateRange[0]) : "", - endTime: dateRange[1] ? formatDate(dateRange[1]) : "", - status: enabled ? 1 : 0, - }; - if (isEdit && id) { - await updateContentLibrary({ id, ...payload }); - Toast.show({ content: "保存成功", position: "top" }); - } else { - await request("/v1/content/library/create", payload, "POST"); - Toast.show({ content: "创建成功", position: "top" }); - } - navigate("/mine/content"); - } catch (e: any) { - Toast.show({ - content: e?.message || (isEdit ? "保存失败" : "创建失败"), - position: "top", - }); - } finally { - setSubmitting(false); - } - }; - - const handleGroupsChange = (groups: GroupSelectionItem[]) => { - setSelectedGroups(groups.map(g => g.id.toString())); - setSelectedGroupsOptions(groups); - }; - - const handleFriendsChange = (friends: FriendSelectionItem[]) => { - setSelectedFriends(friends.map(f => f.id.toString())); - setSelectedFriendsOptions(friends); - }; - - return ( - } - footer={ -
- -
- } - > -
-
e.preventDefault()} - autoComplete="off" - > -
- - setName(e.target.value)} - className={style["input"]} - /> -
- -
数据来源配置
-
- setSourceType(key as "friends" | "groups")} - className={style["tabs-bar"]} - > - - - - - - - -
- - - 关键词设置} - > -
- -