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.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={
-
-
-
- }
- >
-
-
- );
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/list/api.ts b/Touchkebao/src/pages/mobile/mine/content/list/api.ts
deleted file mode 100644
index 51821b6f..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/list/api.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import request from "@/api/request";
-import {
- ContentLibrary,
- CreateContentLibraryParams,
- UpdateContentLibraryParams,
-} from "./data";
-
-// 获取内容库列表
-export function getContentLibraryList(params: {
- page?: number;
- limit?: number;
- keyword?: string;
- sourceType?: number;
-}): Promise {
- return request("/v1/content/library/list", params, "GET");
-}
-
-// 获取内容库详情
-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");
-}
-
-// 删除内容库
-export function deleteContentLibrary(id: string): Promise {
- return request("/v1/content/library/delete", { id }, "DELETE");
-}
-
-// 切换内容库状态
-export function toggleContentLibraryStatus(
- id: string,
- status: number,
-): Promise {
- return request("/v1/content/library/update-status", { id, status }, "POST");
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/list/data.ts b/Touchkebao/src/pages/mobile/mine/content/list/data.ts
deleted file mode 100644
index bb2c1d2c..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/list/data.ts
+++ /dev/null
@@ -1,66 +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 LibraryListResponse {
- list: ContentLibrary[];
- total: number;
-}
-
-// 创建内容库参数
-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/list/index.module.scss b/Touchkebao/src/pages/mobile/mine/content/list/index.module.scss
deleted file mode 100644
index 8fe90eeb..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/list/index.module.scss
+++ /dev/null
@@ -1,217 +0,0 @@
-.content-library-page {
- padding: 16px;
- background: #f5f5f5;
- min-height: 100vh;
-}
-
-.search-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 16px;
- background: white;
- padding: 12px;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.search-input-wrapper {
- position: relative;
- flex: 1;
-}
-
-.search-icon {
- position: absolute;
- left: 12px;
- top: 50%;
- transform: translateY(-50%);
- color: #999;
- z-index: 1;
-}
-
-.search-input {
- padding-left: 36px;
- border-radius: 20px;
- border: 1px solid #e0e0e0;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
-}
-
-.create-btn {
- border-radius: 20px;
- padding: 0 16px;
-}
-
-.spinning {
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-.tabs {
- flex: 1;
-}
-
-.library-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.loading {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 40px 0;
-}
-
-.empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 60px 20px;
- text-align: center;
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.empty-icon {
- font-size: 48px;
- margin-bottom: 16px;
- opacity: 0.6;
-}
-
-.empty-text {
- color: #999;
- margin-bottom: 20px;
- font-size: 14px;
-}
-
-.empty-btn {
- border-radius: 20px;
- padding: 0 20px;
-}
-
-.library-card {
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- border: none;
-
- &:hover {
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- }
-}
-
-.card-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 12px;
-}
-
-.library-info {
- display: flex;
- align-items: center;
- gap: 8px;
- flex: 1;
-}
-
-.library-name {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin: 0;
-}
-
-.status-tag {
- font-size: 12px;
- padding: 2px 8px;
- border-radius: 10px;
-}
-
-.menu-btn {
- background: none;
- border: none;
- padding: 4px;
- cursor: pointer;
- color: #999;
- border-radius: 4px;
-
- &:hover {
- background: #f5f5f5;
- color: #666;
- }
-}
-
-.menu-dropdown {
- position: absolute;
- right: 0;
- top: 100%;
- background: white;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- z-index: 1000;
- min-width: 120px;
- padding: 4px;
- margin-top: 4px;
-}
-
-.menu-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 12px;
- cursor: pointer;
- border-radius: 4px;
- font-size: 14px;
- color: #333;
- transition: background 0.2s;
-
- &:hover {
- background: #f5f5f5;
- }
-
- &.danger {
- color: #ff4d4f;
-
- &:hover {
- background: #fff2f0;
- }
- }
-}
-
-.card-content {
- display: flex;
- flex-direction: column;
- gap: 6px;
-}
-
-.info-row {
- display: flex;
- align-items: center;
- font-size: 13px;
-}
-
-.label {
- color: #999;
- min-width: 70px;
- margin-right: 8px;
-}
-
-.value {
- color: #333;
- flex: 1;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/list/index.tsx b/Touchkebao/src/pages/mobile/mine/content/list/index.tsx
deleted file mode 100644
index cd24f010..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/list/index.tsx
+++ /dev/null
@@ -1,314 +0,0 @@
-import React, { useState, useEffect, useCallback } from "react";
-import { useNavigate } from "react-router-dom";
-import {
- Button,
- Toast,
- SpinLoading,
- Dialog,
- Card,
- Avatar,
- Tag,
-} from "antd-mobile";
-import { Input } from "antd";
-import {
- PlusOutlined,
- SearchOutlined,
- ReloadOutlined,
- EyeOutlined,
- EditOutlined,
- DeleteOutlined,
- MoreOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import NavCommon from "@/components/NavCommon";
-import { getContentLibraryList, deleteContentLibrary } from "./api";
-import { ContentLibrary } from "./data";
-import style from "./index.module.scss";
-import { Tabs } from "antd-mobile";
-
-// 卡片菜单组件
-interface CardMenuProps {
- onView: () => void;
- onEdit: () => void;
- onDelete: () => void;
- onViewMaterials: () => void;
-}
-
-const CardMenu: React.FC = ({
- onView,
- onEdit,
- onDelete,
- onViewMaterials,
-}) => {
- const [open, setOpen] = useState(false);
- const menuRef = React.useRef(null);
-
- React.useEffect(() => {
- function handleClickOutside(event: MouseEvent) {
- if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
- setOpen(false);
- }
- }
- if (open) document.addEventListener("mousedown", handleClickOutside);
- return () => document.removeEventListener("mousedown", handleClickOutside);
- }, [open]);
-
- return (
-
-
- {open && (
-
-
{
- onEdit();
- setOpen(false);
- }}
- className={style["menu-item"]}
- >
-
- 编辑
-
-
{
- onDelete();
- setOpen(false);
- }}
- className={`${style["menu-item"]} ${style["danger"]}`}
- >
-
- 删除
-
-
{
- onViewMaterials();
- setOpen(false);
- }}
- className={style["menu-item"]}
- >
-
- 查看素材
-
-
- )}
-
- );
-};
-
-const ContentLibraryList: React.FC = () => {
- const navigate = useNavigate();
- const [libraries, setLibraries] = useState([]);
- const [searchQuery, setSearchQuery] = useState("");
- const [activeTab, setActiveTab] = useState("all");
- const [loading, setLoading] = useState(false);
-
- // 获取内容库列表
- const fetchLibraries = useCallback(async () => {
- setLoading(true);
- try {
- const response = await getContentLibraryList({
- page: 1,
- limit: 100,
- keyword: searchQuery,
- sourceType:
- activeTab !== "all" ? (activeTab === "friends" ? 1 : 2) : undefined,
- });
-
- setLibraries(response.list || []);
- } catch (error: any) {
- console.error("获取内容库列表失败:", error);
- } finally {
- setLoading(false);
- }
- }, [searchQuery, activeTab]);
-
- useEffect(() => {
- fetchLibraries();
- }, [fetchLibraries]);
-
- const handleCreateNew = () => {
- navigate("/mine/content/new");
- };
-
- const handleEdit = (id: string) => {
- navigate(`/mine/content/edit/${id}`);
- };
-
- const handleDelete = async (id: string) => {
- const result = await Dialog.confirm({
- content: "确定要删除这个内容库吗?",
- confirmText: "删除",
- cancelText: "取消",
- });
-
- if (result) {
- try {
- const response = await deleteContentLibrary(id);
- if (response.code === 200) {
- Toast.show({
- content: "删除成功",
- position: "top",
- });
- fetchLibraries();
- } else {
- Toast.show({
- content: response.msg || "删除失败",
- position: "top",
- });
- }
- } catch (error: any) {
- console.error("删除内容库失败:", error);
- Toast.show({
- content: error?.message || "请检查网络连接",
- position: "top",
- });
- }
- }
- };
-
- const handleViewMaterials = (id: string) => {
- navigate(`/mine/content/materials/${id}`);
- };
-
- const handleRefresh = () => {
- fetchLibraries();
- };
-
- const filteredLibraries = libraries.filter(
- library =>
- library.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
- library.creatorName?.toLowerCase().includes(searchQuery.toLowerCase()),
- );
-
- return (
-
- navigate("/mine")}
- right={
-
- }
- />
-
- {/* 搜索栏 */}
-
-
- setSearchQuery(e.target.value)}
- prefix={}
- allowClear
- size="large"
- />
-
-
-
-
- {/* 标签页 */}
-
-
-
-
-
-
-
- >
- }
- >
-
- {/* 内容库列表 */}
-
- {loading ? (
-
-
-
- ) : filteredLibraries.length === 0 ? (
-
-
📚
-
- 暂无内容库,快去新建一个吧!
-
-
-
- ) : (
- filteredLibraries.map(library => (
-
-
-
-
{library.name}
-
- {library.status === 1 ? "已启用" : "未启用"}
-
-
-
navigate(`/content/${library.id}`)}
- onEdit={() => handleEdit(library.id)}
- onDelete={() => handleDelete(library.id)}
- onViewMaterials={() => handleViewMaterials(library.id)}
- />
-
-
-
- 来源:
-
- {library.sourceType === 1 ? "微信好友" : "聊天群"}
-
-
-
- 创建人:
-
- {library.creatorName || "系统"}
-
-
-
- 内容数量:
-
- {library.itemCount || 0}
-
-
-
- 更新时间:
-
- {new Date(library.updateTime).toLocaleString("zh-CN", {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- })}
-
-
-
-
- ))
- )}
-
-
-
- );
-};
-
-export default ContentLibraryList;
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/form/api.ts b/Touchkebao/src/pages/mobile/mine/content/materials/form/api.ts
deleted file mode 100644
index c442c0a3..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/form/api.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import request from "@/api/request";
-
-// 获取素材详情
-export function getContentItemDetail(id: string) {
- return request("/v1/content/library/get-item-detail", { id }, "GET");
-}
-
-// 创建素材
-export function createContentItem(params: any) {
- return request("/v1/content/library/create-item", params, "POST");
-}
-
-// 更新素材
-export function updateContentItem(params: any) {
- return request(`/v1/content/library/update-item`, params, "POST");
-}
-// 获取内容库详情
-export function getContentLibraryDetail(id: string) {
- return request("/v1/content/library/detail", { id }, "GET");
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/form/data.ts b/Touchkebao/src/pages/mobile/mine/content/materials/form/data.ts
deleted file mode 100644
index 2ecaeb15..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/form/data.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-// 素材数据类型定义
-export interface ContentItem {
- id: number; // 修改为number类型
- libraryId: number; // 修改为number类型
- type?: string;
- contentType: number; // 0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序, 6=图文
- title: string;
- content: string;
- contentAi?: string;
- contentData?: any;
- snsId?: string | null;
- msgId?: string | null;
- wechatId?: string | null;
- friendId?: string | null;
- createMomentTime?: number;
- createTime: string;
- updateTime: string;
- coverImage?: string;
- resUrls?: string[];
- urls?: any[];
- location?: string | null;
- lat?: string;
- lng?: string;
- status?: number;
- isDel?: number;
- delTime?: number;
- wechatChatroomId?: string | null;
- senderNickname?: string;
- createMessageTime?: string | null;
- comment?: string;
- sendTime?: string; // 字符串格式的时间
- sendTimes?: number;
- contentTypeName?: string;
-}
-
-// 内容库类型
-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 CreateContentItemParams {
- libraryId: string;
- title: string;
- content: string;
- contentType: number;
- resUrls?: string[];
- urls?: string[];
- comment?: string;
- sendTime?: string;
-}
-
-// 更新素材参数
-export interface UpdateContentItemParams
- extends Partial {
- id: string;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/form/index.module.scss b/Touchkebao/src/pages/mobile/mine/content/materials/form/index.module.scss
deleted file mode 100644
index 89314dd7..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/form/index.module.scss
+++ /dev/null
@@ -1,160 +0,0 @@
-.form-page {
- padding: 16px;
- background: #f5f5f5;
- min-height: 100vh;
-}
-
-.loading {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 40px 0;
-}
-
-.form {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-
-.form-card {
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- border: none;
- padding: 16px;
-}
-
-.card-title {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin-bottom: 16px;
- padding-bottom: 8px;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.form-item {
- margin-bottom: 16px;
-}
-
-.form-label {
- display: block;
- font-size: 14px;
- font-weight: 500;
- color: #333;
- margin-bottom: 8px;
-
- .required {
- color: #ff4d4f;
- margin-right: 4px;
- }
-}
-
-.form-input {
- width: 100%;
- height: 40px;
- border-radius: 6px;
- border: 1px solid #d9d9d9;
- padding: 0 12px;
- font-size: 14px;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
-}
-
-.form-select {
- width: 100%;
- border-radius: 6px;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
-}
-
-.form-textarea {
- width: 100%;
- border-radius: 6px;
- border: 1px solid #d9d9d9;
- padding: 8px 12px;
- font-size: 14px;
- resize: vertical;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
-}
-
-.select-option {
- display: flex;
- align-items: center;
- gap: 8px;
-
- .anticon {
- font-size: 16px;
- color: #1677ff;
- }
-}
-
-.form-actions {
- display: flex;
- gap: 12px;
- padding: 16px;
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- margin-top: 16px;
-}
-
-.back-btn {
- flex: 1;
- border-radius: 6px;
- border: 1px solid #d9d9d9;
-
- &:hover {
- border-color: #1677ff;
- color: #1677ff;
- }
-}
-
-.submit-btn {
- flex: 1;
- border-radius: 6px;
-}
-
-// 覆盖 antd-mobile 的默认样式
-:global {
- .adm-form-item {
- margin-bottom: 16px;
- }
-
- .adm-form-item-label {
- font-size: 14px;
- color: #333;
- font-weight: 500;
- }
-
- .adm-input {
- border-radius: 6px;
- border: 1px solid #d9d9d9;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
- }
-
- .adm-select {
- border-radius: 6px;
- border: 1px solid #d9d9d9;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
- }
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/form/index.tsx b/Touchkebao/src/pages/mobile/mine/content/materials/form/index.tsx
deleted file mode 100644
index 23e628d6..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/form/index.tsx
+++ /dev/null
@@ -1,403 +0,0 @@
-import React, { useState, useEffect, useCallback } from "react";
-import { useNavigate, useParams } from "react-router-dom";
-import { Button, Toast, SpinLoading, Card } from "antd-mobile";
-import { Input, Select } from "antd";
-import {
- ArrowLeftOutlined,
- SaveOutlined,
- PictureOutlined,
- LinkOutlined,
- VideoCameraOutlined,
- FileTextOutlined,
- AppstoreOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import NavCommon from "@/components/NavCommon";
-import UploadComponent from "@/components/Upload/ImageUpload/ImageUpload";
-import VideoUpload from "@/components/Upload/VideoUpload";
-import {
- getContentItemDetail,
- createContentItem,
- updateContentItem,
-} from "./api";
-import style from "./index.module.scss";
-
-const { Option } = Select;
-const { TextArea } = Input;
-
-// 内容类型选项
-const contentTypeOptions = [
- { value: 1, label: "图片", icon: },
- { value: 2, label: "链接", icon: },
- { value: 3, label: "视频", icon: },
- { value: 4, label: "文本", icon: },
- { value: 5, label: "小程序", icon: },
-];
-
-const MaterialForm: React.FC = () => {
- const navigate = useNavigate();
- const { id: libraryId, materialId } = useParams<{
- id: string;
- materialId: string;
- }>();
- const [loading, setLoading] = useState(false);
- const [saving, setSaving] = useState(false);
-
- // 表单状态
- const [contentType, setContentType] = useState(4);
- const [title, setTitle] = useState("");
- const [content, setContent] = useState("");
- const [comment, setComment] = useState("");
- const [sendTime, setSendTime] = useState("");
- const [resUrls, setResUrls] = useState([]);
-
- // 链接相关状态
- const [linkDesc, setLinkDesc] = useState("");
- const [linkImage, setLinkImage] = useState("");
- const [linkUrl, setLinkUrl] = useState("");
-
- // 小程序相关状态
- const [appTitle, setAppTitle] = useState("");
- const [appId, setAppId] = useState("");
-
- const isEdit = !!materialId;
-
- // 获取素材详情
- const fetchMaterialDetail = useCallback(async () => {
- if (!materialId) return;
- setLoading(true);
- try {
- const response = await getContentItemDetail(materialId);
- // 填充表单数据
- setTitle(response.title || "");
- setContent(response.content || "");
- setContentType(response.contentType || 4);
- setComment(response.comment || "");
-
- // 处理时间格式 - sendTime是字符串格式,需要转换为datetime-local格式
- if (response.sendTime) {
- // 将 "2025-07-28 16:11:00" 转换为 "2025-07-28T16:11"
- const dateTime = new Date(response.sendTime);
- setSendTime(dateTime.toISOString().slice(0, 16));
- } else {
- setSendTime("");
- }
-
- setResUrls(response.resUrls || []);
-
- // 设置链接相关数据
- if (response.urls && response.urls.length > 0) {
- const firstUrl = response.urls[0];
- if (typeof firstUrl === "object" && firstUrl !== null) {
- setLinkDesc(firstUrl.desc || "");
- setLinkImage(firstUrl.image || "");
- setLinkUrl(firstUrl.url || "");
- }
- }
- } catch (error: unknown) {
- console.error("获取素材详情失败:", error);
- } finally {
- setLoading(false);
- }
- }, [materialId]);
-
- useEffect(() => {
- if (isEdit && materialId) {
- fetchMaterialDetail();
- }
- }, [isEdit, materialId, fetchMaterialDetail]);
-
- const handleSubmit = async () => {
- if (!libraryId) return;
-
- if (!content.trim()) {
- Toast.show({
- content: "请输入素材内容",
- position: "top",
- });
- return;
- }
-
- setSaving(true);
- try {
- // 构建urls数据
- let finalUrls: { desc: string; image: string; url: string }[] = [];
- if (contentType === 2 && linkUrl) {
- finalUrls = [
- {
- desc: linkDesc,
- image: linkImage,
- url: linkUrl,
- },
- ];
- }
-
- const params = {
- libraryId,
- title,
- content,
- contentType,
- comment,
- sendTime: sendTime || "",
- resUrls,
- urls: finalUrls,
- type: contentType,
- };
-
- if (isEdit) {
- await updateContentItem({
- id: materialId!,
- ...params,
- });
- } else {
- await createContentItem(params);
- }
-
- // 直接使用返回数据,无需判断code
- Toast.show({
- content: isEdit ? "更新成功" : "创建成功",
- position: "top",
- });
- navigate(`/mine/content/materials/${libraryId}`);
- } catch (error: unknown) {
- console.error("保存素材失败:", error);
- Toast.show({
- content: error instanceof Error ? error.message : "请检查网络连接",
- position: "top",
- });
- } finally {
- setSaving(false);
- }
- };
-
- const handleBack = () => {
- navigate(`/mine/content/materials/${libraryId}`);
- };
-
- if (loading) {
- return (
- }>
-
-
-
-
- );
- }
-
- return (
- }
- footer={
-
-
-
-
- }
- >
-
-
- {/* 基础信息 */}
-
- 基础信息
-
-
-
- setSendTime(e.target.value)}
- placeholder="请选择发布时间"
- className={style["form-input"]}
- />
-
-
-
-
-
-
-
-
- {/* 内容信息 */}
-
- 内容信息
-
-
-
-
-
- {/* 链接类型特有字段 */}
- {contentType === 2 && (
- <>
-
-
- setLinkDesc(e.target.value)}
- placeholder="请输入描述"
- className={style["form-input"]}
- />
-
-
-
-
- setLinkImage(urls[0] || "")}
- count={1}
- />
-
-
-
-
- setLinkUrl(e.target.value)}
- placeholder="请输入链接地址"
- className={style["form-input"]}
- />
-
- >
- )}
-
- {/* 视频类型特有字段 */}
- {contentType === 3 && (
-
-
- setResUrls([url])}
- />
-
- )}
-
-
- {/* 素材上传(仅图片类型和小程序类型) */}
- {[1, 5].includes(contentType) && (
-
-
- 素材上传 (当前类型: {contentType})
-
-
- {contentType === 1 && (
-
-
-
-
-
-
- 当前内容类型: {contentType}, 图片数量: {resUrls.length}
-
-
- )}
-
- {contentType === 5 && (
- <>
-
-
- setAppTitle(e.target.value)}
- placeholder="请输入小程序名称"
- className={style["form-input"]}
- />
-
-
-
-
- setAppId(e.target.value)}
- placeholder="请输入AppID"
- className={style["form-input"]}
- />
-
-
-
-
-
-
- >
- )}
-
- )}
-
- {/* 评论/备注 */}
-
- 评论/备注
-
-
-
-
-
-
-
-
- );
-};
-
-export default MaterialForm;
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/list/api.ts b/Touchkebao/src/pages/mobile/mine/content/materials/list/api.ts
deleted file mode 100644
index 6037391f..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/list/api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import request from "@/api/request";
-import {
- GetContentItemListParams,
- CreateContentItemParams,
- UpdateContentItemParams,
-} from "./data";
-
-// 获取素材列表
-export function getContentItemList(params: GetContentItemListParams) {
- return request("/v1/content/library/item-list", params, "GET");
-}
-
-// 获取素材详情
-export function getContentItemDetail(id: string) {
- return request("/v1/content/item/detail", { id }, "GET");
-}
-
-// 创建素材
-export function createContentItem(params: CreateContentItemParams) {
- return request("/v1/content/item/create", params, "POST");
-}
-
-// 更新素材
-export function updateContentItem(params: UpdateContentItemParams) {
- const { id, ...data } = params;
- return request(`/v1/content/item/update`, { id, ...data }, "POST");
-}
-
-// 删除素材
-export function deleteContentItem(id: string) {
- return request("/v1/content/library/delete-item", { id }, "DELETE");
-}
-
-// 获取内容库详情
-export function getContentLibraryDetail(id: string) {
- return request("/v1/content/library/detail", { id }, "GET");
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/list/data.ts b/Touchkebao/src/pages/mobile/mine/content/materials/list/data.ts
deleted file mode 100644
index b2bc51ab..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/list/data.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-// 素材数据类型定义
-export interface ContentItem {
- id: number;
- libraryId: number;
- type: string;
- contentType: number; // 0=未知, 1=图片, 2=链接, 3=视频, 4=文本, 5=小程序, 6=图文
- title: string;
- content: string;
- contentAi?: string | null;
- contentData?: string | null;
- snsId?: string | null;
- msgId?: string | null;
- wechatId?: string | null;
- friendId?: string | null;
- createMomentTime: number;
- createTime: string;
- updateTime: string;
- coverImage: string;
- resUrls: string[];
- urls: { desc: string; image: string; url: string }[];
- location?: string | null;
- lat: string;
- lng: string;
- status: number;
- isDel: number;
- delTime: number;
- wechatChatroomId?: string | null;
- senderNickname: string;
- createMessageTime?: string | null;
- comment: string;
- sendTime: number;
- sendTimes: number;
- contentTypeName: string;
-}
-
-// 内容库类型
-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 ItemListResponse {
- list: ContentItem[];
- total: number;
-}
-
-// 获取素材列表参数
-export interface GetContentItemListParams {
- libraryId: string;
- page?: number;
- limit?: number;
- keyword?: string;
-}
-
-// 创建素材参数
-export interface CreateContentItemParams {
- libraryId: string;
- title: string;
- content: string;
- contentType: number;
- resUrls?: string[];
- urls?: (string | { desc?: string; image?: string; url: string })[];
- comment?: string;
- sendTime?: string;
-}
-
-// 更新素材参数
-export interface UpdateContentItemParams
- extends Partial {
- id: string;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/list/index.module.scss b/Touchkebao/src/pages/mobile/mine/content/materials/list/index.module.scss
deleted file mode 100644
index 666b75ad..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/list/index.module.scss
+++ /dev/null
@@ -1,615 +0,0 @@
-.materials-page {
- padding: 16px;
-}
-
-.search-bar {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 16px;
- background: white;
- padding: 12px;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.search-input-wrapper {
- position: relative;
- flex: 1;
-}
-
-.search-icon {
- position: absolute;
- left: 12px;
- top: 50%;
- transform: translateY(-50%);
- color: #999;
- z-index: 1;
-}
-
-.search-input {
- padding-left: 36px;
- border-radius: 20px;
- border: 1px solid #e0e0e0;
-
- &:focus {
- border-color: #1677ff;
- box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
- }
-}
-
-.create-btn {
- border-radius: 20px;
- padding: 0 16px;
-}
-
-.spinning {
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-.materials-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.loading {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 40px 0;
-}
-
-.empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 60px 20px;
- text-align: center;
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-}
-
-.empty-icon {
- font-size: 48px;
- margin-bottom: 16px;
- opacity: 0.6;
-}
-
-.empty-text {
- color: #999;
- margin-bottom: 20px;
- font-size: 14px;
-}
-
-.empty-btn {
- border-radius: 20px;
- padding: 0 20px;
-}
-
-.material-card {
- background: white;
- border-radius: 8px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
- border: none;
-
- &:hover {
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- }
-}
-
-.card-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 16px;
-}
-
-.avatar-section {
- display: flex;
- align-items: center;
- gap: 12px;
- flex: 1;
-}
-
-.avatar {
- width: 48px;
- height: 48px;
- border-radius: 50%;
- background: #e6f7ff;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.avatar-icon {
- font-size: 24px;
- color: #1677ff;
-}
-
-.header-info {
- display: flex;
- flex-direction: column;
- gap: 4px;
-}
-
-.creator-name {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- line-height: 1.2;
-}
-
-.material-id {
- background: #e6f7ff;
- color: #1677ff;
- font-size: 12px;
- font-weight: 600;
- border-radius: 12px;
- padding: 2px 8px;
- display: inline-block;
-}
-
-.material-title {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin-bottom: 12px;
- line-height: 1.4;
-}
-
-.content-icon {
- font-size: 16px;
- color: #1677ff;
-}
-
-.type-tag {
- font-size: 12px;
- padding: 2px 8px;
- border-radius: 10px;
-}
-
-.menu-btn {
- background: none;
- border: none;
- padding: 4px;
- cursor: pointer;
- color: #999;
- border-radius: 4px;
-
- &:hover {
- background: #f5f5f5;
- color: #666;
- }
-}
-
-.menu-dropdown {
- position: absolute;
- right: 0;
- top: 100%;
- background: white;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- z-index: 1000;
- min-width: 120px;
- padding: 4px;
- margin-top: 4px;
-}
-
-.menu-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 12px;
- cursor: pointer;
- border-radius: 4px;
- font-size: 14px;
- color: #333;
- transition: background 0.2s;
-
- &:hover {
- background: #f5f5f5;
- }
-
- &.danger {
- color: #ff4d4f;
-
- &:hover {
- background: #fff2f0;
- }
- }
-}
-
-.link-preview {
- display: flex;
- align-items: flex-start;
- gap: 12px;
- padding: 12px;
- background: #f8f9fa;
- border-radius: 8px;
- margin-bottom: 16px;
- border: 1px solid #e9ecef;
- cursor: pointer;
- transition: all 0.2s ease;
-
- &:hover {
- background: #e9ecef;
- border-color: #1677ff;
- }
-}
-
-.link-icon {
- width: 40px;
- height: 40px;
- border-radius: 8px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- overflow: hidden;
-
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
-}
-
-.link-content {
- flex: 1;
- min-width: 0;
-}
-
-.link-title {
- font-size: 14px;
- font-weight: 500;
- color: #333;
- margin-bottom: 4px;
- line-height: 1.3;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.link-url {
- font-size: 12px;
- color: #666;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.action-buttons {
- display: flex;
- margin-top: 16px;
- justify-content: space-between;
-}
-.action-btn-group {
- display: flex;
- gap: 8px;
-}
-
-.action-btn {
- border-radius: 6px;
- font-size: 16px;
- padding: 6px 12px;
- border: 1px solid #d9d9d9;
- background: white;
- color: #333;
-
- &:hover {
- border-color: #1677ff;
- color: #1677ff;
- }
-}
-
-.delete-btn {
- border-radius: 6px;
- font-size: 16px;
- padding: 6px 12px;
- background: #ff4d4f;
- border-color: #ff4d4f;
- color: white;
-
- &:hover {
- background: #ff7875;
- border-color: #ff7875;
- }
-}
-
-.pagination-wrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 16px;
- background: white;
- border-top: 1px solid #f0f0f0;
-}
-
-// 内容类型标签样式
-.content-type-tag {
- display: inline-flex;
- align-items: center;
- padding: 4px 8px;
- border-radius: 12px;
- font-size: 12px;
- font-weight: 500;
- border: 1px solid currentColor;
-}
-
-// 图片类型预览样式
-.material-image-preview {
- margin: 12px 0;
-
- .image-grid {
- display: grid;
- gap: 8px;
- width: 100%;
-
- // 1张图片:宽度拉伸,高度自适应
- &.single {
- grid-template-columns: 1fr;
-
- img {
- width: 100%;
- height: auto;
- object-fit: cover;
- border-radius: 8px;
- }
- }
-
- // 2张图片:左右并列
- &.double {
- grid-template-columns: 1fr 1fr;
-
- img {
- width: 100%;
- height: 120px;
- object-fit: cover;
- border-radius: 8px;
- }
- }
-
- // 3张图片:三张并列
- &.triple {
- grid-template-columns: 1fr 1fr 1fr;
-
- img {
- width: 100%;
- height: 100px;
- object-fit: cover;
- border-radius: 8px;
- }
- }
-
- // 4张图片:2x2网格布局
- &.quad {
- grid-template-columns: repeat(2, 1fr);
-
- img {
- width: 100%;
- height: 140px;
- object-fit: cover;
- border-radius: 8px;
- }
- }
-
- // 5张及以上:网格布局
- &.grid {
- grid-template-columns: repeat(3, 1fr);
-
- img {
- width: 100%;
- height: 100px;
- object-fit: cover;
- border-radius: 8px;
- }
-
- .image-more {
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f5f5f5;
- border-radius: 8px;
- color: #666;
- font-size: 12px;
- font-weight: 500;
- height: 100px;
- }
- }
- }
-
- .no-image {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 80px;
- background: #f5f5f5;
- border-radius: 8px;
- color: #999;
- font-size: 14px;
- }
-}
-
-// 链接类型预览样式
-.material-link-preview {
- margin: 12px 0;
-
- .link-card {
- display: flex;
- background: #e9f8ff;
- border-radius: 8px;
- padding: 12px;
- cursor: pointer;
- transition: all 0.2s;
- border: 1px solid #cde6ff;
- &:hover {
- background: #cde6ff;
- }
-
- .link-image {
- width: 60px;
- height: 60px;
- margin-right: 12px;
- flex-shrink: 0;
-
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: 6px;
- }
- }
-
- .link-content {
- flex: 1;
- min-width: 0;
-
- .link-title {
- font-weight: 500;
- margin-bottom: 4px;
- color: #333;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .link-url {
- font-size: 12px;
- color: #666;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- }
-}
-
-// 视频类型预览样式
-.material-video-preview {
- margin: 12px 0;
-
- .video-thumbnail {
- video {
- width: 100%;
- max-height: 200px;
- border-radius: 8px;
- }
- }
-
- .no-video {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 120px;
- background: #f5f5f5;
- border-radius: 8px;
- color: #999;
- font-size: 14px;
- }
-}
-
-// 文本类型预览样式
-.material-text-preview {
- margin: 12px 0;
-
- .text-content {
- background: #f8f9fa;
- padding: 12px;
- border-radius: 8px;
- line-height: 1.6;
- color: #333;
- font-size: 14px;
- }
-}
-
-// 小程序类型预览样式
-.material-miniprogram-preview {
- margin: 12px 0;
-
- .miniprogram-card {
- display: flex;
- background: #f8f9fa;
- border-radius: 8px;
- padding: 12px;
- width: 100%;
-
- img {
- width: 60px;
- height: 60px;
- border-radius: 8px;
- margin-right: 12px;
- flex-shrink: 0;
- object-fit: cover;
- }
-
- .miniprogram-info {
- flex: 1;
- min-width: 0;
-
- .miniprogram-title {
- font-weight: 500;
- color: #333;
- margin-bottom: 4px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- }
-}
-
-// 图文类型预览样式
-.material-article-preview {
- margin: 12px 0;
-
- .article-image {
- margin-bottom: 12px;
-
- img {
- width: 100%;
- height: 120px;
- object-fit: cover;
- border-radius: 8px;
- }
- }
-
- .article-content {
- .article-title {
- font-weight: 500;
- color: #333;
- margin-bottom: 8px;
- font-size: 16px;
- }
-
- .article-text {
- color: #666;
- line-height: 1.6;
- font-size: 14px;
- }
- }
-}
-
-// 默认预览样式
-.material-default-preview {
- margin: 12px 0;
-
- .default-content {
- background: #f8f9fa;
- padding: 12px;
- border-radius: 8px;
- color: #333;
- line-height: 1.6;
- }
-}
diff --git a/Touchkebao/src/pages/mobile/mine/content/materials/list/index.tsx b/Touchkebao/src/pages/mobile/mine/content/materials/list/index.tsx
deleted file mode 100644
index db963f0b..00000000
--- a/Touchkebao/src/pages/mobile/mine/content/materials/list/index.tsx
+++ /dev/null
@@ -1,409 +0,0 @@
-import React, { useState, useEffect, useCallback } from "react";
-import { useNavigate, useParams } from "react-router-dom";
-import { Toast, SpinLoading, Dialog, Card } from "antd-mobile";
-import { Input, Pagination, Button } from "antd";
-import {
- PlusOutlined,
- SearchOutlined,
- ReloadOutlined,
- EditOutlined,
- DeleteOutlined,
- UserOutlined,
- BarChartOutlined,
- PictureOutlined,
- LinkOutlined,
- VideoCameraOutlined,
- FileTextOutlined,
- AppstoreOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import NavCommon from "@/components/NavCommon";
-import { getContentItemList, deleteContentItem } from "./api";
-import { ContentItem } from "./data";
-import style from "./index.module.scss";
-
-// 内容类型配置
-const contentTypeConfig = {
- 1: { label: "图片", icon: PictureOutlined, color: "#52c41a" },
- 2: { label: "链接", icon: LinkOutlined, color: "#1890ff" },
- 3: { label: "视频", icon: VideoCameraOutlined, color: "#722ed1" },
- 4: { label: "文本", icon: FileTextOutlined, color: "#fa8c16" },
- 5: { label: "小程序", icon: AppstoreOutlined, color: "#eb2f96" },
- 6: { label: "图文", icon: PictureOutlined, color: "#13c2c2" },
-};
-
-const MaterialsList: React.FC = () => {
- const navigate = useNavigate();
- const { id } = useParams<{ id: string }>();
- const [materials, setMaterials] = useState([]);
- const [searchQuery, setSearchQuery] = useState("");
- const [loading, setLoading] = useState(false);
- const [currentPage, setCurrentPage] = useState(1);
- const [total, setTotal] = useState(0);
- const pageSize = 20;
-
- // 获取素材列表
- const fetchMaterials = useCallback(async () => {
- if (!id) return;
- setLoading(true);
- try {
- const response = await getContentItemList({
- libraryId: id,
- page: currentPage,
- limit: pageSize,
- keyword: searchQuery,
- });
-
- setMaterials(response.list || []);
- setTotal(response.total || 0);
- } catch (error: unknown) {
- console.error("获取素材列表失败:", error);
- Toast.show({
- content: error instanceof Error ? error.message : "请检查网络连接",
- position: "top",
- });
- } finally {
- setLoading(false);
- }
- }, [id, currentPage, searchQuery]);
-
- useEffect(() => {
- fetchMaterials();
- }, [fetchMaterials]);
-
- const handleCreateNew = () => {
- navigate(`/mine/content/materials/new/${id}`);
- };
-
- const handleEdit = (materialId: number) => {
- navigate(`/mine/content/materials/edit/${id}/${materialId}`);
- };
-
- const handleDelete = async (materialId: number) => {
- const result = await Dialog.confirm({
- content: "确定要删除这个素材吗?",
- confirmText: "删除",
- cancelText: "取消",
- });
-
- if (result) {
- try {
- await deleteContentItem(materialId.toString());
- Toast.show({
- content: "删除成功",
- position: "top",
- });
- fetchMaterials();
- } catch (error: unknown) {
- console.error("删除素材失败:", error);
- Toast.show({
- content: error instanceof Error ? error.message : "请检查网络连接",
- position: "top",
- });
- }
- }
- };
-
- const handleView = (materialId: number) => {
- // 可以跳转到素材详情页面或显示弹窗
- console.log("查看素材:", materialId);
- };
-
- const handleRefresh = () => {
- fetchMaterials();
- };
-
- const handlePageChange = (page: number) => {
- setCurrentPage(page);
- };
-
- // 渲染内容类型标签
- const renderContentTypeTag = (contentType: number) => {
- const config =
- contentTypeConfig[contentType as keyof typeof contentTypeConfig];
- if (!config) return null;
-
- const IconComponent = config.icon;
- return (
-
-
- {config.label}
-
- );
- };
-
- // 渲染素材内容预览
- const renderContentPreview = (material: ContentItem) => {
- const { contentType, content, resUrls, urls, coverImage } = material;
-
- switch (contentType) {
- case 1: // 图片
- return (
-
- {resUrls && resUrls.length > 0 ? (
-
- {resUrls.slice(0, 9).map((url, index) => (
-

- ))}
- {resUrls.length > 9 && (
-
- +{resUrls.length - 9}
-
- )}
-
- ) : coverImage ? (
-
-

-
- ) : (
-
暂无图片
- )}
-
- );
-
- case 2: // 链接
- return (
-
- {urls && urls.length > 0 && (
-
{
- window.open(urls[0].url, "_blank");
- }}
- >
- {urls[0].image && (
-
-

-
- )}
-
-
- {urls[0].desc || "链接"}
-
-
{urls[0].url}
-
-
- )}
-
- );
-
- case 3: // 视频
- return (
-
- {resUrls && resUrls.length > 0 ? (
-
-
-
- ) : (
-
暂无视频
- )}
-
- );
-
- case 4: // 文本
- return (
-
-
- {content.length > 100
- ? `${content.substring(0, 100)}...`
- : content}
-
-
- );
-
- case 5: // 小程序
- return (
-
- {resUrls && resUrls.length > 0 && (
-
-

-
-
- {material.title || "小程序"}
-
-
-
- )}
-
- );
-
- case 6: // 图文
- return (
-
- {coverImage && (
-
-

-
- )}
-
-
- {material.title || "图文内容"}
-
-
- {content.length > 80
- ? `${content.substring(0, 80)}...`
- : content}
-
-
-
- );
-
- default:
- return (
-
- );
- }
- };
-
- return (
-
- navigate("/mine/content")}
- right={
-
- }
- />
- {/* 搜索栏 */}
-
-
- setSearchQuery(e.target.value)}
- prefix={}
- allowClear
- size="large"
- />
-
-
}
- size="large"
- >
-
- >
- }
- footer={
-
- }
- loading={loading}
- >
-
- {/* 素材列表 */}
-
- {loading ? (
-
-
-
- ) : materials.length === 0 ? (
-
-
📄
-
- 暂无素材,快去新建一个吧!
-
-
-
- ) : (
- <>
- {materials.map(material => (
-
- {/* 顶部信息 */}
-
-
-
-
-
-
-
- {material.senderNickname || "系统创建"}
-
-
- ID: {material.id}
-
-
-
- {renderContentTypeTag(material.contentType)}
-
- {/* 标题 */}
- {material.contentType != 4 && (
-
- {material.content}
-
- )}
- {/* 内容预览 */}
- {renderContentPreview(material)}
-
- {/* 操作按钮区 */}
-
-
-
-
-
-
-
-
- ))}
- >
- )}
-
-
-
- );
-};
-
-export default MaterialsList;
diff --git a/Touchkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx b/Touchkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx
deleted file mode 100644
index 71398a96..00000000
--- a/Touchkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx
+++ /dev/null
@@ -1,392 +0,0 @@
-import React, { useEffect, useState, useCallback, useRef } from "react";
-import { useParams, useNavigate } from "react-router-dom";
-import {
- NavBar,
- Tabs,
- Switch,
- Toast,
- SpinLoading,
- Button,
- Avatar,
-} from "antd-mobile";
-import { SettingOutlined, RedoOutlined, UserOutlined } from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import {
- fetchDeviceDetail,
- fetchDeviceRelatedAccounts,
- fetchDeviceHandleLogs,
- updateDeviceTaskConfig,
-} from "./api";
-import type { Device, WechatAccount, HandleLog } from "@/types/device";
-import NavCommon from "@/components/NavCommon";
-const DeviceDetail: React.FC = () => {
- const { id } = useParams<{ id: string }>();
- const navigate = useNavigate();
- const [loading, setLoading] = useState(true);
- const [device, setDevice] = useState(null);
- const [tab, setTab] = useState("info");
- const [accounts, setAccounts] = useState([]);
- const [accountsLoading, setAccountsLoading] = useState(false);
- const [logs, setLogs] = useState([]);
- const [logsLoading, setLogsLoading] = useState(false);
- const [featureSaving, setFeatureSaving] = useState<{ [k: string]: boolean }>(
- {},
- );
-
- // 获取设备详情
- const loadDetail = useCallback(async () => {
- if (!id) return;
- setLoading(true);
- try {
- const res = await fetchDeviceDetail(id);
- setDevice(res);
- } catch (e: any) {
- Toast.show({ content: e.message || "获取设备详情失败", position: "top" });
- } finally {
- setLoading(false);
- }
- }, [id]);
-
- // 获取关联账号
- const loadAccounts = useCallback(async () => {
- if (!id) return;
- setAccountsLoading(true);
- try {
- const res = await fetchDeviceRelatedAccounts(id);
- setAccounts(Array.isArray(res.accounts) ? res.accounts : []);
- } catch (e: any) {
- Toast.show({ content: e.message || "获取关联账号失败", position: "top" });
- } finally {
- setAccountsLoading(false);
- }
- }, [id]);
-
- // 获取操作日志
- const loadLogs = useCallback(async () => {
- if (!id) return;
- setLogsLoading(true);
- try {
- const res = await fetchDeviceHandleLogs(id, 1, 20);
- setLogs(Array.isArray(res.list) ? res.list : []);
- } catch (e: any) {
- Toast.show({ content: e.message || "获取操作日志失败", position: "top" });
- } finally {
- setLogsLoading(false);
- }
- }, [id]);
-
- useEffect(() => {
- loadDetail();
- // eslint-disable-next-line
- }, [id]);
-
- useEffect(() => {
- if (tab === "accounts") loadAccounts();
- if (tab === "logs") loadLogs();
- // eslint-disable-next-line
- }, [tab]);
-
- // 功能开关
- const handleFeatureChange = async (
- feature: keyof Device["features"],
- checked: boolean,
- ) => {
- if (!id) return;
- setFeatureSaving(prev => ({ ...prev, [feature]: true }));
- try {
- await updateDeviceTaskConfig({ deviceId: id, [feature]: checked });
- setDevice(prev =>
- prev
- ? {
- ...prev,
- features: { ...prev.features, [feature]: checked },
- }
- : prev,
- );
- Toast.show({
- content: `${getFeatureName(feature)}已${checked ? "开启" : "关闭"}`,
- });
- } catch (e: any) {
- Toast.show({ content: e.message || "设置失败", position: "top" });
- } finally {
- setFeatureSaving(prev => ({ ...prev, [feature]: false }));
- }
- };
-
- const getFeatureName = (feature: string) => {
- const map: Record = {
- autoAddFriend: "自动加好友",
- autoReply: "自动回复",
- momentsSync: "朋友圈同步",
- aiChat: "AI会话",
- };
- return map[feature] || feature;
- };
-
- return (
-
-
-
- {/* 基本信息卡片 */}
- {device && (
-
-
- {device.memo || "未命名设备"}
-
-
- IMEI: {device.imei}
-
-
- 微信号: {device.wechatId || "未绑定"}
-
-
- 好友数: {device.totalFriend ?? "-"}
-
-
- {device.status === "online" || device.alive === 1
- ? "在线"
- : "离线"}
-
-
- )}
- >
- }
- loading={loading}
- >
- {!device ? (
-
- ) : (
-
- {/* 标签页 */}
-
-
-
-
-
- {/* 功能开关 */}
- {tab === "info" && (
-
- {["autoAddFriend", "autoReply", "momentsSync", "aiChat"].map(
- (f, index) => (
-
-
-
- handleFeatureChange(
- f as keyof Device["features"],
- checked,
- )
- }
- />
-
- ),
- )}
-
- )}
- {/* 关联账号 */}
- {tab === "accounts" && (
-
- {accountsLoading ? (
-
-
-
- ) : accounts.length === 0 ? (
-
- 暂无关联微信账号
-
- ) : (
-
- {accounts.map((acc, index) => (
-
{
- navigate(`/wechat-accounts/detail/${acc.wechatId}`);
- }}
- >
-
-
-
- }
- />
-
-
{acc.nickname}
-
- 微信号: {acc.wechatId}
-
-
- 好友数: {acc.totalFriend}
-
-
- 最后活跃: {acc.lastActive}
-
-
-
- {acc.wechatAliveText}
-
-
- ))}
-
- )}
-
-
-
-
- )}
- {/* 操作日志 */}
- {tab === "logs" && (
-
- {logsLoading ? (
-
-
-
- ) : logs.length === 0 ? (
-
- 暂无操作日志
-
- ) : (
-
- {logs.map((log, index) => (
-
-
{log.content}
-
- 操作人: {log.username} · {log.createTime}
-
-
- ))}
-
- )}
-
-
-
-
- )}
-
- )}
-
- );
-};
-
-export default DeviceDetail;
diff --git a/Touchkebao/src/pages/mobile/mine/devices/api.ts b/Touchkebao/src/pages/mobile/mine/devices/api.ts
deleted file mode 100644
index c8e91198..00000000
--- a/Touchkebao/src/pages/mobile/mine/devices/api.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import request from "@/api/request";
-
-// 获取设备列表
-export const fetchDeviceList = (params: {
- page?: number;
- limit?: number;
- keyword?: string;
-}) => request("/v1/devices", params, "GET");
-
-// 获取设备详情
-export const fetchDeviceDetail = (id: string | number) =>
- request(`/v1/devices/${id}`);
-
-// 获取设备关联微信账号
-export const fetchDeviceRelatedAccounts = (id: string | number) =>
- request(`/v1/wechats/related-device/${id}`);
-
-// 获取设备操作日志
-export const fetchDeviceHandleLogs = (
- id: string | number,
- page = 1,
- limit = 10,
-) => request(`/v1/devices/${id}/handle-logs`, { page, limit }, "GET");
-
-// 更新设备任务配置
-export const updateDeviceTaskConfig = (config: {
- deviceId: string | number;
- autoAddFriend?: boolean;
- autoReply?: boolean;
- momentsSync?: boolean;
- aiChat?: boolean;
-}) => request("/v1/devices/task-config", config, "POST");
-
-// 删除设备
-export const deleteDevice = (id: number) =>
- request(`/v1/devices/${id}`, undefined, "DELETE");
-
-// 获取设备二维码
-export const fetchDeviceQRCode = (accountId: string) =>
- request("/v1/api/device/add", { accountId }, "POST");
-
-// 通过IMEI添加设备
-export const addDeviceByImei = (imei: string, name: string) =>
- request("/v1/api/device/add-by-imei", { imei, name }, "POST");
diff --git a/Touchkebao/src/pages/mobile/mine/devices/index.module.scss b/Touchkebao/src/pages/mobile/mine/devices/index.module.scss
deleted file mode 100644
index dad90af4..00000000
--- a/Touchkebao/src/pages/mobile/mine/devices/index.module.scss
+++ /dev/null
@@ -1,173 +0,0 @@
-.deviceList {
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.deviceCard {
- background: #fff;
- border-radius: 12px;
- padding: 12px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- transition: all 0.2s ease;
- position: relative;
- overflow: hidden;
-
- &:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
- }
-
- &.selected {
- border: 2px solid #1677ff;
- }
-
- &:not(.selected) {
- border: 1px solid #f5f5f5;
- }
-}
-
-.headerRow {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 8px;
-}
-
-.checkboxContainer {
- flex-shrink: 0;
-}
-
-.imeiText {
- font-size: 13px;
- color: #666;
- font-family: monospace;
- flex: 1;
-}
-
-.mainContent {
- display: flex;
- align-items: center;
- gap: 12px;
- cursor: pointer;
- border-radius: 8px;
- transition: background-color 0.2s ease;
-
- &:hover {
- background-color: #f8f9fa;
- }
-}
-
-.avatar {
- width: 64px;
- height: 64px;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- display: flex;
- align-items: center;
- justify-content: center;
- overflow: hidden;
- box-shadow: 0 2px 8px rgba(102, 126, 234, 0.25);
- flex-shrink: 0;
- border-radius: 6px;
-
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
-
- .avatarText {
- font-size: 18px;
- color: #fff;
- font-weight: 700;
- text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
- }
-}
-
-.deviceInfo {
- flex: 1;
- min-width: 0;
-}
-
-.deviceHeader {
- display: flex;
- align-items: center;
- gap: 6px;
- margin-bottom: 6px;
-}
-
-.deviceName {
- margin: 0;
- font-size: 16px;
- font-weight: 600;
- color: #1a1a1a;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.statusBadge {
- font-size: 11px;
- padding: 1px 6px;
- border-radius: 8px;
- font-weight: 500;
-
- &.online {
- color: #52c41a;
- background: #f6ffed;
- border: 1px solid #b7eb8f;
- }
-
- &.offline {
- color: #ff4d4f;
- background: #fff2f0;
- border: 1px solid #ffccc7;
- }
-}
-
-.infoList {
- display: flex;
- flex-direction: column;
- gap: 4px;
-}
-
-.infoItem {
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.infoLabel {
- font-size: 13px;
- color: #666;
- min-width: 50px;
-}
-
-.infoValue {
- font-size: 13px;
- color: #333;
-
- &.friendCount {
- font-weight: 500;
- }
-}
-
-.arrowIcon {
- color: #999;
- font-size: 14px;
- margin-left: auto;
- transition: transform 0.2s ease;
-}
-
-.mainContent:hover .arrowIcon {
- transform: translateX(3px);
- color: #1677ff;
-}
-
-.paginationContainer {
- padding: 16px;
- background: #fff;
- border-top: 1px solid #f0f0f0;
- display: flex;
- justify-content: center;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/devices/index.tsx b/Touchkebao/src/pages/mobile/mine/devices/index.tsx
deleted file mode 100644
index 62fe17f2..00000000
--- a/Touchkebao/src/pages/mobile/mine/devices/index.tsx
+++ /dev/null
@@ -1,442 +0,0 @@
-import React, { useEffect, useRef, useState, useCallback } from "react";
-import { Popup, Tabs, Toast, SpinLoading } from "antd-mobile";
-import { Button, Input, Pagination, Checkbox } from "antd";
-import { useNavigate } from "react-router-dom";
-import { AddOutline, DeleteOutline } from "antd-mobile-icons";
-import {
- ReloadOutlined,
- SearchOutlined,
- QrcodeOutlined,
- RightOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import {
- fetchDeviceList,
- fetchDeviceQRCode,
- addDeviceByImei,
- deleteDevice,
-} from "./api";
-import type { Device } from "@/types/device";
-import { comfirm } from "@/utils/common";
-import { useUserStore } from "@/store/module/user";
-import NavCommon from "@/components/NavCommon";
-import styles from "./index.module.scss";
-
-const Devices: React.FC = () => {
- // 设备列表相关
- const [devices, setDevices] = useState([]);
- const [loading, setLoading] = useState(false);
- const [search, setSearch] = useState("");
- const [status, setStatus] = useState<"all" | "online" | "offline">("all");
- const [page, setPage] = useState(1);
- const [hasMore, setHasMore] = useState(true);
- const [total, setTotal] = useState(0);
- const [selected, setSelected] = useState<(string | number)[]>([]);
- const observerRef = useRef(null);
- const [usePagination, setUsePagination] = useState(true); // 新增:是否使用分页
-
- // 添加设备弹窗
- const [addVisible, setAddVisible] = useState(false);
- const [addTab, setAddTab] = useState("scan");
- const [qrLoading, setQrLoading] = useState(false);
- const [qrCode, setQrCode] = useState(null);
- const [imei, setImei] = useState("");
- const [name, setName] = useState("");
- const [addLoading, setAddLoading] = useState(false);
-
- // 删除弹窗
- const [delVisible, setDelVisible] = useState(false);
- const [delLoading, setDelLoading] = useState(false);
-
- const navigate = useNavigate();
- const { user } = useUserStore();
- // 加载设备列表
- const loadDevices = useCallback(
- async (reset = false) => {
- if (loading) return;
- setLoading(true);
- try {
- const params: any = { page: reset ? 1 : page, limit: 20 };
- if (search) params.keyword = search;
- const res = await fetchDeviceList(params);
- const list = Array.isArray(res.list) ? res.list : [];
- setDevices(prev => (reset ? list : [...prev, ...list]));
- setTotal(res.total || 0);
- setHasMore(list.length === 20);
- if (reset) setPage(1);
- } catch (e) {
- Toast.show({ content: "获取设备列表失败", position: "top" });
- setHasMore(false); // 请求失败后不再继续请求
- } finally {
- setLoading(false);
- }
- },
- [loading, search, page],
- );
-
- // 首次加载和搜索
- useEffect(() => {
- loadDevices(true);
- // eslint-disable-next-line
- }, [search]);
-
- // 无限滚动
- useEffect(() => {
- if (!hasMore || loading) return;
- const observer = new window.IntersectionObserver(
- entries => {
- if (entries[0].isIntersecting && hasMore && !loading) {
- setPage(p => p + 1);
- }
- },
- { threshold: 0.5 },
- );
- if (observerRef.current) observer.observe(observerRef.current);
- return () => observer.disconnect();
- }, [hasMore, loading]);
-
- // 分页加载
- useEffect(() => {
- if (page === 1) return;
- loadDevices();
- // eslint-disable-next-line
- }, [page]);
-
- // 状态筛选
- const filtered = devices.filter(d => {
- if (status === "all") return true;
- if (status === "online") return d.status === "online" || d.alive === 1;
- if (status === "offline") return d.status === "offline" || d.alive === 0;
- return true;
- });
-
- // 获取二维码
- const handleGetQr = async () => {
- setQrLoading(true);
- setQrCode(null);
- try {
- const accountId = user.s2_accountId;
- if (!accountId) throw new Error("未获取到用户信息");
- const res = await fetchDeviceQRCode(accountId);
- setQrCode(res.qrCode);
- } catch (e: any) {
- Toast.show({ content: e.message || "获取二维码失败", position: "top" });
- } finally {
- setQrLoading(false);
- }
- };
-
- const addDevice = async () => {
- await handleGetQr();
- setAddVisible(true);
- };
-
- // 手动添加设备
- const handleAddDevice = async () => {
- if (!imei.trim() || !name.trim()) {
- Toast.show({ content: "请填写完整信息", position: "top" });
- return;
- }
- setAddLoading(true);
- try {
- await addDeviceByImei(imei, name);
- Toast.show({ content: "添加成功", position: "top" });
- setAddVisible(false);
- setImei("");
- setName("");
- loadDevices(true);
- } catch (e: any) {
- Toast.show({ content: e.message || "添加失败", position: "top" });
- } finally {
- setAddLoading(false);
- }
- };
-
- // 删除设备
- const handleDelete = async () => {
- setDelLoading(true);
- try {
- for (const id of selected) {
- await deleteDevice(Number(id));
- }
- Toast.show({ content: `删除成功`, position: "top" });
- setSelected([]);
- loadDevices(true);
- } catch (e: any) {
- if (e) Toast.show({ content: e.message || "删除失败", position: "top" });
- } finally {
- setDelLoading(false);
- }
- };
-
- // 删除按钮点击
- const handleDeleteClick = async () => {
- try {
- await comfirm(
- `将删除${selected.length}个设备,删除后本设备配置的计划任务操作也将失效。确认删除?`,
- { title: "确认删除", confirmText: "确认删除", cancelText: "取消" },
- );
- handleDelete();
- } catch {
- // 用户取消,无需处理
- }
- };
-
- // 跳转详情
- const goDetail = (id: string | number) => {
- navigate(`/mine/devices/${id}`);
- };
-
- // 分页切换
- const handlePageChange = (p: number) => {
- setPage(p);
- loadDevices(true);
- };
-
- return (
-
- addDevice()}>
-
- 添加设备
-
- }
- />
-
- {/* 搜索栏 */}
-
- setSearch(e.target.value)}
- prefix={}
- allowClear
- style={{ flex: 1 }}
- />
-
-
- {/* 筛选和删除 */}
-
-
setStatus(k as any)}
- style={{ flex: 1 }}
- >
-
-
-
-
-
- }
- disabled={selected.length === 0}
- onClick={handleDeleteClick}
- >
- 删除
-
-
-
-
- >
- }
- footer={
-
- }
- loading={loading && devices.length === 0}
- >
-
- {/* 设备列表 */}
-
- {filtered.map(device => (
-
- {/* 顶部行:选择框和IMEI */}
-
-
- {
- e.stopPropagation();
- setSelected(prev =>
- e.target.checked
- ? [...prev, device.id!]
- : prev.filter(id => id !== device.id),
- );
- }}
- onClick={e => e.stopPropagation()}
- />
-
-
- IMEI: {device.imei?.toUpperCase()}
-
-
-
- {/* 主要内容区域:头像和详细信息 */}
-
- {/* 头像 */}
-
- {device.avatar ? (
-

- ) : (
-
- {(device.memo || device.wechatId || "设")[0]}
-
- )}
-
-
- {/* 设备信息 */}
-
-
-
- {device.memo || "未命名设备"}
-
-
- {device.status === "online" || device.alive === 1
- ? "在线"
- : "离线"}
-
-
-
-
-
- 微信号:
-
- {device.wechatId || "未绑定"}
-
-
-
- 好友数:
-
- {device.totalFriend ?? "-"}
-
-
-
-
-
- {/* 箭头图标 */}
-
goDetail(device.id!)}
- />
-
-
- ))}
-
- {/* 无限滚动提示(仅在不分页时显示) */}
- {!usePagination && (
-
- {loading && }
- {!hasMore && devices.length > 0 && "没有更多设备了"}
- {!hasMore && devices.length === 0 && "暂无设备"}
-
- )}
-
-
- {/* 添加设备弹窗 */}
- setAddVisible(false)}
- bodyStyle={{
- borderTopLeftRadius: 16,
- borderTopRightRadius: 16,
- minHeight: 320,
- }}
- >
-
-
-
-
- {addTab === "scan" && (
-
-
}
- >
- 获取二维码
-
- {qrCode && (
-
-

-
- 请用手机扫码添加设备
-
-
- )}
-
- )}
- {addTab === "manual" && (
-
- setName(e.target.value)}
- allowClear
- />
- setImei(e.target.value)}
- allowClear
- />
-
-
- )}
-
-
-
- );
-};
-
-export default Devices;
diff --git a/Touchkebao/src/pages/mobile/mine/main/api.ts b/Touchkebao/src/pages/mobile/mine/main/api.ts
deleted file mode 100644
index e5a76cb8..00000000
--- a/Touchkebao/src/pages/mobile/mine/main/api.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import request from "@/api/request";
-// 首页仪表盘总览
-export function getDashboard() {
- return request("/v1/dashboard", {}, "GET");
-}
-// 用户信息统计
-export function getUserInfoStats() {
- return request("/v1/dashboard/userInfoStats", {}, "GET");
-}
diff --git a/Touchkebao/src/pages/mobile/mine/main/index.module.scss b/Touchkebao/src/pages/mobile/mine/main/index.module.scss
deleted file mode 100644
index 138d96f3..00000000
--- a/Touchkebao/src/pages/mobile/mine/main/index.module.scss
+++ /dev/null
@@ -1,210 +0,0 @@
-.mine-page {
- padding: 12px;
-}
-
-.user-card {
- border-radius: 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- margin: 16px 0 12px 0;
- padding: 0 0 0 0;
-}
-
-.user-info-row {
- display: flex;
- align-items: center;
- padding: 20px 24px 16px 24px;
-}
-
-.user-avatar {
- width: 56px;
- height: 56px;
- border-radius: 50%;
- background: #666;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 28px;
- font-weight: 700;
- color: #1890ff;
- margin-right: 18px;
- overflow: hidden;
-}
-.avatar-placeholder {
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 28px;
- font-weight: 700;
- color: #1890ff;
- background: #e6f7ff;
- border-radius: 50%;
-}
-
-.user-main-info {
- flex: 1;
- min-width: 0;
- position: relative;
-}
-
-.user-main-row {
- display: flex;
- align-items: center;
- gap: 8px;
- flex-wrap: wrap;
-}
-.user-name {
- font-size: 20px;
- font-weight: 700;
- color: #222;
- margin-right: 2px;
-}
-.role-badge {
- background: #fa8c16;
- color: #fff;
- font-size: 13px;
- font-weight: 500;
- border-radius: 12px;
- padding: 2px 10px;
- margin-right: 8px;
-}
-.balance-label {
- color: #666;
- font-size: 15px;
- margin-right: 2px;
-}
-.balance-value {
- color: #16b364;
- font-size: 20px;
- font-weight: 700;
- margin-right: 4px;
-}
-.recharge-btn {
- margin-right: 8px;
- padding: 0 14px;
- font-size: 14px;
- height: 28px;
- line-height: 28px;
- border-radius: 8px;
-}
-
-.icon-setting {
- font-size: 26px;
- color: #666;
- position: absolute;
- right: 0px;
- top: 0px;
-}
-
-.icon-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 32px;
- height: 32px;
- border-radius: 50%;
- background: none;
- font-size: 20px;
- color: #666;
- cursor: pointer;
- margin-left: 2px;
-}
-.last-login {
- color: #888;
- font-size: 13px;
- margin-top: 6px;
- margin-left: 2px;
-}
-
-.menu-card {
- margin-bottom: 16px;
- border-radius: 12px;
-
- :global(.adm-list-body) {
- border: none;
- }
-
- :global(.adm-card-body) {
- padding: 14px 0 0 0;
- }
- :global(.adm-list-body-inner) {
- margin-top: 0px;
- }
- :global(.adm-list-item) {
- padding: 0px;
- :global(.adm-list-item-content) {
- border: 1px solid #f0f0f0;
- margin-bottom: 12px;
- padding: 0 12px;
- border-radius: 12px;
- }
-
- :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-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;
- background: #666;
- }
-
- .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;
- }
- }
- }
-}
diff --git a/Touchkebao/src/pages/mobile/mine/main/index.tsx b/Touchkebao/src/pages/mobile/mine/main/index.tsx
deleted file mode 100644
index 66450792..00000000
--- a/Touchkebao/src/pages/mobile/mine/main/index.tsx
+++ /dev/null
@@ -1,232 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { useNavigate } from "react-router-dom";
-import { Card, List, Button } from "antd-mobile";
-import {
- PhoneOutlined,
- MessageOutlined,
- DatabaseOutlined,
- FolderOpenOutlined,
- SettingOutlined,
-} from "@ant-design/icons";
-import MeauMobile from "@/components/MeauMobile/MeauMoible";
-import Layout from "@/components/Layout/Layout";
-import style from "./index.module.scss";
-import { useUserStore } from "@/store/module/user";
-import { getDashboard, getUserInfoStats } from "./api";
-import NavCommon from "@/components/NavCommon";
-const Mine: React.FC = () => {
- const navigate = useNavigate();
- const { user } = useUserStore();
- const [stats, setStats] = useState({
- devices: 12,
- wechat: 25,
- traffic: 8,
- content: 156,
- balance: 0,
- });
- const [userInfoStats, setUserInfoStats] = useState({
- contentLibraryNum: 0,
- deviceNum: 0,
- userNum: 0,
- wechatNum: 0,
- });
-
- // 用户信息
- const currentUserInfo = {
- name: user?.username || "-",
- email: user?.account || "-",
- role: user?.isAdmin === 1 ? "管理员" : "普通用户",
- lastLogin: user?.lastLoginTime
- ? new Date(user.lastLoginTime * 1000).toLocaleString()
- : "-",
- avatar: user?.avatar || "",
- };
-
- // 功能模块数据
- const functionModules = [
- {
- id: "devices",
- title: "设备管理",
- description: "管理您的设备和微信账号",
- icon: ,
- count: userInfoStats.deviceNum,
- path: "/mine/devices",
- bgColor: "#e6f7ff",
- iconColor: "#1890ff",
- },
- {
- id: "wechat",
- title: "微信号管理",
- description: "管理微信账号和好友",
- icon: ,
- count: userInfoStats.wechatNum,
- path: "/wechat-accounts",
- bgColor: "#f6ffed",
- iconColor: "#52c41a",
- },
- {
- id: "traffic",
- title: "流量池",
- description: "管理用户流量池和分组",
- icon: ,
- count: userInfoStats.userNum,
- path: "/mine/traffic-pool",
- bgColor: "#f9f0ff",
- iconColor: "#722ed1",
- },
- {
- id: "content",
- title: "内容库",
- description: "管理营销内容和素材",
- icon: ,
- count: userInfoStats.contentLibraryNum,
- path: "/mine/content",
- bgColor: "#fff7e6",
- iconColor: "#fa8c16",
- },
- {
- id: "ckb",
- title: "触客宝",
- description: "触客宝",
- icon: ,
- count: 0,
- path: "/ckbox/weChat",
- bgColor: "#fff7e6",
- iconColor: "#fa8c16",
- },
- ];
-
- // 加载统计数据
- const loadStats = async () => {
- try {
- const res = await getDashboard();
- setStats({
- devices: res.deviceNum,
- wechat: res.wechatNum,
- traffic: 999,
- content: 999,
- balance: res.balance || 0,
- });
- const res2 = await getUserInfoStats();
- setUserInfoStats(res2);
- } catch (error) {
- console.error("加载统计数据失败:", error);
- }
- };
-
- useEffect(() => {
- loadStats();
- }, []);
-
- const handleFunctionClick = (path: string) => {
- navigate(path);
- };
-
- // 渲染功能模块图标
- const renderModuleIcon = (module: any) => (
-
- {module.icon}
-
- );
-
- return (
- }
- footer={}
- >
-
- {/* 用户信息卡片(严格按图片风格) */}
-
-
- {/* 头像 */}
-
- {currentUserInfo.avatar ? (
-

- ) : (
-
卡
- )}
-
- {/* 右侧内容 */}
-
-
-
- {currentUserInfo.name}
-
-
- {currentUserInfo.role}
-
-
-
-
-
-
-
- 余额:
-
- ¥{Number(stats.balance || 0).toFixed(2)}
-
-
-
-
- 最近登录:{currentUserInfo.lastLogin}
-
-
navigate("/settings")}
- />
-
-
-
-
- {/* 我的功能 */}
-
-
- {functionModules.map(module => (
-
- {module.count}
-
- }
- arrow
- onClick={() => handleFunctionClick(module.path)}
- />
- ))}
-
-
-
-
- );
-};
-
-export default Mine;
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/index/index.module.scss b/Touchkebao/src/pages/mobile/mine/recharge/index/index.module.scss
deleted file mode 100644
index c7e3615a..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/index/index.module.scss
+++ /dev/null
@@ -1,440 +0,0 @@
-.recharge-page {
-}
-
-.record-btn {
- color: var(--primary-color);
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- padding: 4px 8px;
- border-radius: 4px;
- transition: background-color 0.2s ease;
-
- &:hover {
- background-color: rgba(24, 142, 238, 0.1);
- }
-
- &:active {
- background-color: rgba(24, 142, 238, 0.2);
- }
-}
-
-.recharge-tabs {
- :global(.adm-tabs-header) {
- background: #fff;
- border-bottom: 1px solid #f0f0f0;
- position: sticky;
- top: 0;
- z-index: 10;
- }
-
- :global(.adm-tabs-tab) {
- font-size: 16px;
- font-weight: 500;
- }
-
- :global(.adm-tabs-tab-active) {
- color: var(--primary-color);
- }
-
- :global(.adm-tabs-tab-line) {
- background: var(--primary-color);
- }
-}
-
-.tab-content {
-}
-
-.balance-card {
- margin-bottom: 16px;
- background: #f6ffed;
- border: 1px solid #b7eb8f;
- border-radius: 12px;
- padding: 18px 0 18px 0;
- display: flex;
- align-items: center;
- .balance-content {
- display: flex;
- color: #16b364;
- padding-left: 30px;
- }
- .wallet-icon {
- color: #16b364;
- font-size: 30px;
- flex-shrink: 0;
- }
- .balance-info {
- margin-left: 15px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
- .balance-label {
- font-size: 14px;
- font-weight: normal;
- color: #666;
- margin-bottom: 2px;
- }
- .balance-amount {
- font-size: 24px;
- font-weight: 700;
- color: #16b364;
- line-height: 1.1;
- }
-}
-
-.quick-card {
- margin-bottom: 16px;
- .quick-list {
- display: flex;
- flex-wrap: wrap;
- gap: 6px;
- justify-content: flex-start;
- margin-bottom: 8px;
- }
-}
-
-.desc-card {
- margin: 16px 0px;
- background: #fffbe6;
- border: 1px solid #ffe58f;
-}
-
-.warn-card {
- margin: 16px 0;
- background: #fff2e8;
- border: 1px solid #ffbb96;
-}
-
-.quick-title {
- font-weight: 500;
- margin-bottom: 8px;
- font-size: 16px;
-}
-.quick-list {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- justify-content: flex-start;
- margin-bottom: 8px;
-}
-.quick-btn {
- min-width: 80px;
- margin: 4px 0;
- font-size: 16px;
- border-radius: 8px;
-}
-.quick-btn-active {
- @extend .quick-btn;
- font-weight: 600;
-}
-.recharge-main-btn {
- margin-top: 16px;
- font-size: 18px;
- border-radius: 8px;
-}
-.desc-title {
- font-weight: 500;
- margin-bottom: 8px;
- font-size: 16px;
-}
-.desc-text {
- color: #666;
- font-size: 14px;
-}
-.warn-content {
- display: flex;
- align-items: center;
- gap: 8px;
- color: #faad14;
- font-size: 14px;
-}
-.warn-icon {
- font-size: 30px;
- color: #faad14;
- flex-shrink: 0;
-}
-.warn-info {
- display: flex;
- flex-direction: column;
-}
-.warn-title {
- font-weight: 600;
- font-size: 15px;
-}
-.warn-text {
- color: #faad14;
- font-size: 14px;
-}
-
-// AI服务样式
-.ai-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 8px;
-}
-
-.ai-title {
- display: flex;
- align-items: center;
- font-size: 20px;
- font-weight: 700;
- color: #222;
-}
-
-.ai-icon {
- font-size: 24px;
- color: var(--primary-color);
- margin-right: 8px;
-}
-
-.ai-tag {
- background: #ff6b35;
- color: #fff;
- font-size: 12px;
- padding: 4px 8px;
- border-radius: 12px;
- font-weight: 500;
-}
-
-.ai-description {
- color: #666;
- font-size: 14px;
- margin-bottom: 20px;
-}
-
-.ai-services {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-
-.ai-service-card {
- border-radius: 12px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-}
-
-.service-header {
- margin-bottom: 12px;
-}
-
-.service-info {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.service-icon {
- font-size: 24px;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f0f0f0;
- border-radius: 8px;
-}
-
-.service-details {
- flex: 1;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.service-name {
- font-size: 16px;
- font-weight: 600;
- color: #222;
-}
-
-.service-price {
- font-size: 16px;
- font-weight: 700;
- color: #ff4d4f;
-}
-
-.service-description {
- color: #666;
- font-size: 14px;
- margin-bottom: 12px;
- line-height: 1.5;
-}
-
-.service-features {
- margin-bottom: 16px;
-}
-
-.feature-item {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 6px;
- font-size: 14px;
- color: #333;
-}
-
-.feature-check {
- color: #52c41a;
- font-weight: bold;
- font-size: 16px;
-}
-
-.usage-progress {
- margin-top: 12px;
-}
-
-.usage-label {
- font-size: 14px;
- color: #666;
- margin-bottom: 8px;
-}
-
-.progress-bar {
- width: 100%;
- height: 6px;
- background: #f0f0f0;
- border-radius: 3px;
- overflow: hidden;
- margin-bottom: 6px;
-}
-
-.progress-fill {
- height: 100%;
- background: var(--primary-color);
- border-radius: 3px;
- transition: width 0.3s ease;
-}
-
-.usage-text {
- font-size: 12px;
- color: #999;
- text-align: right;
-}
-
-// 版本套餐样式
-.version-header {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 8px;
- font-size: 20px;
- font-weight: 700;
- color: #222;
-}
-
-.version-icon {
- font-size: 24px;
- color: #722ed1;
-}
-
-.version-description {
- color: #666;
- font-size: 14px;
- margin-bottom: 20px;
-}
-
-.version-packages {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-
-.version-card {
- border-radius: 12px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- position: relative;
-}
-
-.package-header {
- margin-bottom: 12px;
-}
-
-.package-info {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.package-icon {
- font-size: 24px;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f0f0f0;
- border-radius: 8px;
-}
-
-.package-details {
- flex: 1;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.package-name {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 16px;
- font-weight: 600;
- color: #222;
-}
-
-.package-tag {
- font-size: 12px;
- padding: 2px 8px;
- border-radius: 10px;
- font-weight: 500;
-}
-
-.tag-blue {
- background: #e6f7ff;
- color: #1890ff;
-}
-
-.tag-green {
- background: #f6ffed;
- color: #52c41a;
-}
-
-.package-price {
- font-size: 18px;
- font-weight: 700;
- color: var(--primary-color);
-}
-
-.package-description {
- color: #666;
- font-size: 14px;
- margin-bottom: 12px;
- line-height: 1.5;
-}
-
-.package-features {
- margin-bottom: 16px;
-}
-
-.features-title {
- font-size: 14px;
- font-weight: 600;
- color: #333;
- margin-bottom: 8px;
-}
-
-.package-status {
- text-align: center;
- color: #52c41a;
- font-size: 14px;
- font-weight: 500;
- margin-bottom: 12px;
-}
-
-.upgrade-btn {
- border-radius: 8px;
- font-size: 16px;
- font-weight: 600;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/index/index.tsx b/Touchkebao/src/pages/mobile/mine/recharge/index/index.tsx
deleted file mode 100644
index 9507b73c..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/index/index.tsx
+++ /dev/null
@@ -1,371 +0,0 @@
-import React, { useState } from "react";
-import { useNavigate } from "react-router-dom";
-import { Card, Button, Toast, Tabs } from "antd-mobile";
-import { useUserStore } from "@/store/module/user";
-import style from "./index.module.scss";
-import {
- WalletOutlined,
- WarningOutlined,
- ClockCircleOutlined,
- RobotOutlined,
- CrownOutlined,
-} from "@ant-design/icons";
-import NavCommon from "@/components/NavCommon";
-import Layout from "@/components/Layout/Layout";
-
-const quickAmounts = [50, 100, 200, 500, 1000];
-
-// AI服务套餐数据
-const aiServicePackages = [
- {
- id: 1,
- name: "入门套餐",
- tag: "推荐",
- tagColor: "blue",
- description: "适合个人用户体验AI服务",
- usage: "可使用AI服务约110次",
- price: 100,
- originalPrice: 110,
- gift: 10,
- actualAmount: 110,
- },
- {
- id: 2,
- name: "标准套餐",
- tag: "热门",
- tagColor: "green",
- description: "适合小团队日常使用",
- usage: "可使用AI服务约580次",
- price: 500,
- originalPrice: 580,
- gift: 80,
- actualAmount: 580,
- },
-];
-
-// AI服务列表数据
-const aiServices = [
- {
- id: 1,
- name: "添加好友及打招呼",
- icon: "💬",
- price: 1,
- description: "AI智能添加好友并发送个性化打招呼消息",
- features: ["智能筛选目标用户", "发送个性化打招呼消息", "自动记录添加结果"],
- usage: { current: 15, total: 450 },
- },
- {
- id: 2,
- name: "小室AI内容生产",
- icon: "⚡",
- price: 1,
- description: "AI智能创建朋友圈内容,智能配文与朋友圈内容",
- features: ["智能生成朋友圈文案", "AI配文智能文案", "内容智能排版优化"],
- usage: { current: 28, total: 680 },
- },
- {
- id: 3,
- name: "智能分发服务",
- icon: "📤",
- price: 1,
- description: "AI智能分发内容到多个平台",
- features: ["多平台智能分发", "内容智能优化", "分发效果分析"],
- usage: { current: 12, total: 300 },
- },
-];
-
-// 版本套餐数据
-const versionPackages = [
- {
- id: 1,
- name: "普通版本",
- icon: "📦",
- price: "免费",
- description: "充值即可使用,包含基础AI功能",
- features: ["基础AI服务", "标准客服支持", "基础数据统计"],
- status: "当前使用中",
- buttonText: null,
- tagColor: undefined,
- },
- {
- id: 2,
- name: "标准版本",
- icon: "👑",
- price: "¥98/月",
- tag: "推荐",
- tagColor: "blue",
- description: "适合中小企业,AI功能更丰富",
- features: ["高级AI服务", "优先客服支持", "详细数据分析", "API接口访问"],
- status: null,
- buttonText: "立即升级",
- },
- {
- id: 3,
- name: "企业版本",
- icon: "🏢",
- price: "¥1980/月",
- description: "适合大型企业,提供专属服务",
- features: [
- "专属AI服务",
- "24小时专属客服",
- "高级数据分析",
- "API接口访问",
- "专属技术支持",
- ],
- status: null,
- buttonText: "立即升级",
- tagColor: undefined,
- },
-];
-
-const Recharge: React.FC = () => {
- const navigate = useNavigate();
- const { user } = useUserStore();
- // 假设余额从后端接口获取,实际可用props或store传递
- const [balance, setBalance] = useState(0);
- const [selected, setSelected] = useState(null);
- const [loading, setLoading] = useState(false);
- const [activeTab, setActiveTab] = useState("account");
-
- // 充值操作
- const handleRecharge = async () => {
- if (!selected) {
- Toast.show({ content: "请选择充值金额", position: "top" });
- return;
- }
- setLoading(true);
- setTimeout(() => {
- setBalance(b => b + selected);
- Toast.show({ content: `充值成功,已到账¥${selected}` });
- setLoading(false);
- }, 1200);
- };
-
- // 渲染账户充值tab内容
- const renderAccountRecharge = () => (
-
-
-
-
-
-
当前余额
-
- ¥{balance.toFixed(2)}
-
-
-
-
-
- 快捷充值
-
- {quickAmounts.map(amt => (
-
- ))}
-
-
-
-
- 服务消耗
-
- 使用以下服务将从余额中扣除相应费用。
-
-
- {balance < 10 && (
-
-
-
-
-
余额不足提醒
-
- 当前余额较低,建议及时充值以免影响服务使用
-
-
-
-
- )}
-
- );
-
- // 渲染AI服务tab内容
- const renderAiServices = () => (
-
-
-
-
- AI智能服务收费
-
-
统一按次收费
-
-
- 三项核心AI服务,按使用次数收费,每次1元
-
-
-
- {aiServices.map(service => (
-
-
-
-
{service.icon}
-
-
{service.name}
-
- ¥{service.price}/次
-
-
-
-
-
- {service.description}
-
-
- {service.features.map((feature, index) => (
-
- ✓
- {feature}
-
- ))}
-
-
-
今日使用进度
-
-
- {service.usage.current} / {service.usage.total}
-
-
-
- ))}
-
-
- );
-
- // 渲染版本套餐tab内容
- const renderVersionPackages = () => (
-
-
-
- 存客宝版本套餐
-
-
- 选择适合的版本,享受不同级别的AI服务
-
-
-
- {versionPackages.map(pkg => (
-
-
-
-
{pkg.icon}
-
-
- {pkg.name}
- {pkg.tag && (
-
- {pkg.tag}
-
- )}
-
-
{pkg.price}
-
-
-
-
- {pkg.description}
-
-
-
包含功能:
- {pkg.features.map((feature, index) => (
-
- ✓
- {feature}
-
- ))}
-
- {pkg.status && (
- {pkg.status}
- )}
- {pkg.buttonText && (
-
- )}
-
- ))}
-
-
- );
-
- return (
- navigate("/recharge/order")}
- >
-
- 记录
-
- }
- />
- }
- >
-
-
-
- {renderAccountRecharge()}
-
-
- {renderAiServices()}
-
-
- {renderVersionPackages()}
-
-
-
-
- );
-};
-
-export default Recharge;
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/order/api.ts b/Touchkebao/src/pages/mobile/mine/recharge/order/api.ts
deleted file mode 100644
index 11d4573e..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/order/api.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-import {
- RechargeOrdersResponse,
- RechargeOrderDetail,
- RechargeOrderParams,
-} from "./data";
-
-// 模拟数据
-const mockOrders = [
- {
- id: "1",
- orderNo: "RC20241201001",
- amount: 100.0,
- paymentMethod: "wechat",
- status: "success" as const,
- createTime: "2024-12-01T10:30:00Z",
- payTime: "2024-12-01T10:32:15Z",
- description: "账户充值",
- balance: 150.0,
- },
- {
- id: "2",
- orderNo: "RC20241201002",
- amount: 200.0,
- paymentMethod: "alipay",
- status: "pending" as const,
- createTime: "2024-12-01T14:20:00Z",
- description: "账户充值",
- balance: 350.0,
- },
- {
- id: "3",
- orderNo: "RC20241130001",
- amount: 50.0,
- paymentMethod: "bank",
- status: "success" as const,
- createTime: "2024-11-30T09:15:00Z",
- payTime: "2024-11-30T09:18:30Z",
- description: "账户充值",
- balance: 50.0,
- },
- {
- id: "4",
- orderNo: "RC20241129001",
- amount: 300.0,
- paymentMethod: "wechat",
- status: "failed" as const,
- createTime: "2024-11-29T16:45:00Z",
- description: "账户充值",
- },
- {
- id: "5",
- orderNo: "RC20241128001",
- amount: 150.0,
- paymentMethod: "alipay",
- status: "cancelled" as const,
- createTime: "2024-11-28T11:20:00Z",
- description: "账户充值",
- },
- {
- id: "6",
- orderNo: "RC20241127001",
- amount: 80.0,
- paymentMethod: "wechat",
- status: "success" as const,
- createTime: "2024-11-27T13:10:00Z",
- payTime: "2024-11-27T13:12:45Z",
- description: "账户充值",
- balance: 80.0,
- },
- {
- id: "7",
- orderNo: "RC20241126001",
- amount: 120.0,
- paymentMethod: "bank",
- status: "success" as const,
- createTime: "2024-11-26T08:30:00Z",
- payTime: "2024-11-26T08:33:20Z",
- description: "账户充值",
- balance: 120.0,
- },
- {
- id: "8",
- orderNo: "RC20241125001",
- amount: 250.0,
- paymentMethod: "alipay",
- status: "pending" as const,
- createTime: "2024-11-25T15:45:00Z",
- description: "账户充值",
- balance: 370.0,
- },
-];
-
-// 模拟延迟
-const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
-
-// 获取充值记录列表
-export async function getRechargeOrders(
- params: RechargeOrderParams,
-): Promise {
- await delay(800); // 模拟网络延迟
-
- let filteredOrders = [...mockOrders];
-
- // 状态筛选
- if (params.status && params.status !== "all") {
- filteredOrders = filteredOrders.filter(
- order => order.status === params.status,
- );
- }
-
- // 时间筛选
- if (params.startTime) {
- filteredOrders = filteredOrders.filter(
- order => new Date(order.createTime) >= new Date(params.startTime!),
- );
- }
- if (params.endTime) {
- filteredOrders = filteredOrders.filter(
- order => new Date(order.createTime) <= new Date(params.endTime!),
- );
- }
-
- // 分页
- const startIndex = (params.page - 1) * params.limit;
- const endIndex = startIndex + params.limit;
- const paginatedOrders = filteredOrders.slice(startIndex, endIndex);
-
- return {
- list: paginatedOrders,
- total: filteredOrders.length,
- page: params.page,
- limit: params.limit,
- };
-}
-
-// 获取充值记录详情
-export async function getRechargeOrderDetail(
- id: string,
-): Promise {
- await delay(500);
-
- const order = mockOrders.find(o => o.id === id);
- if (!order) {
- throw new Error("订单不存在");
- }
-
- return {
- ...order,
- paymentChannel:
- order.paymentMethod === "wechat"
- ? "微信支付"
- : order.paymentMethod === "alipay"
- ? "支付宝"
- : "银行转账",
- transactionId: `TX${order.orderNo}`,
- };
-}
-
-// 取消充值订单
-export async function cancelRechargeOrder(id: string): Promise {
- await delay(1000);
-
- const orderIndex = mockOrders.findIndex(o => o.id === id);
- if (orderIndex === -1) {
- throw new Error("订单不存在");
- }
-
- if (mockOrders[orderIndex].status !== "pending") {
- throw new Error("只能取消处理中的订单");
- }
-
- // 模拟更新订单状态
- (mockOrders[orderIndex] as any).status = "cancelled";
-}
-
-// 申请退款
-export async function refundRechargeOrder(
- id: string,
- reason: string,
-): Promise {
- await delay(1200);
-
- const orderIndex = mockOrders.findIndex(o => o.id === id);
- if (orderIndex === -1) {
- throw new Error("订单不存在");
- }
-
- if (mockOrders[orderIndex].status !== "success") {
- throw new Error("只能对成功的订单申请退款");
- }
-
- // 模拟添加退款信息
- const order = mockOrders[orderIndex];
- (order as any).refundAmount = order.amount;
- (order as any).refundTime = new Date().toISOString();
- (order as any).refundReason = reason;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/order/data.ts b/Touchkebao/src/pages/mobile/mine/recharge/order/data.ts
deleted file mode 100644
index 95b9a0e9..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/order/data.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// 充值记录类型定义
-export interface RechargeOrder {
- id: string;
- orderNo: string;
- amount: number;
- paymentMethod: string;
- status: "success" | "pending" | "failed" | "cancelled";
- createTime: string;
- payTime?: string;
- description?: string;
- remark?: string;
- operator?: string;
- balance?: number;
-}
-
-// API响应类型
-export interface RechargeOrdersResponse {
- list: RechargeOrder[];
- total: number;
- page: number;
- limit: number;
-}
-
-// 充值记录详情
-export interface RechargeOrderDetail extends RechargeOrder {
- paymentChannel?: string;
- transactionId?: string;
- refundAmount?: number;
- refundTime?: string;
- refundReason?: string;
-}
-
-// 查询参数
-export interface RechargeOrderParams {
- page: number;
- limit: number;
- status?: string;
- startTime?: string;
- endTime?: string;
-}
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/order/index.module.scss b/Touchkebao/src/pages/mobile/mine/recharge/order/index.module.scss
deleted file mode 100644
index 64031e92..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/order/index.module.scss
+++ /dev/null
@@ -1,242 +0,0 @@
-.recharge-orders-page {
- padding: 16px;
- background: #f5f5f5;
- min-height: 100vh;
-
- .orders-list {
- .order-card {
- margin-bottom: 12px;
- border-radius: 12px;
- background: #fff;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- overflow: hidden;
-
- .order-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 16px;
- border-bottom: 1px solid #f0f0f0;
-
- .order-info {
- flex: 1;
-
- .order-no {
- font-size: 14px;
- color: #333;
- font-weight: 500;
- margin-bottom: 4px;
- }
-
- .order-time {
- font-size: 12px;
- color: #999;
- display: flex;
- align-items: center;
- gap: 4px;
- }
- }
-
- .order-amount {
- text-align: right;
-
- .amount-text {
- font-size: 18px;
- font-weight: 600;
- color: #52c41a;
- margin-bottom: 4px;
- }
-
- .status-tag {
- font-size: 12px;
- padding: 2px 8px;
- border-radius: 10px;
- }
- }
- }
-
- .order-details {
- padding: 12px 16px;
-
- .detail-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8px;
- font-size: 14px;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .label {
- color: #666;
- }
-
- .value {
- color: #333;
- font-weight: 500;
- }
- }
-
- .payment-method {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 8px;
-
- .method-icon {
- width: 20px;
- height: 20px;
- border-radius: 4px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 12px;
- color: #fff;
- }
-
- .method-text {
- font-size: 14px;
- color: #333;
- }
- }
-
- .balance-info {
- background: #f8f9fa;
- padding: 8px 12px;
- border-radius: 6px;
- font-size: 12px;
- color: #666;
- margin-top: 8px;
- }
- }
-
- .order-actions {
- padding: 12px 16px;
- border-top: 1px solid #f0f0f0;
- display: flex;
- gap: 8px;
-
- .action-btn {
- flex: 1;
- height: 32px;
- border-radius: 6px;
- font-size: 12px;
- border: none;
- cursor: pointer;
- transition: all 0.2s;
-
- &.primary {
- background: #1677ff;
- color: #fff;
-
- &:hover {
- background: #0958d9;
- }
- }
-
- &.secondary {
- background: #f5f5f5;
- color: #666;
- border: 1px solid #d9d9d9;
-
- &:hover {
- background: #e6e6e6;
- }
- }
-
- &.danger {
- background: #ff4d4f;
- color: #fff;
-
- &:hover {
- background: #cf1322;
- }
- }
- }
- }
- }
- }
-
- .empty-state {
- padding: 60px 20px;
- text-align: center;
-
- .empty-icon {
- font-size: 48px;
- color: #d9d9d9;
- margin-bottom: 16px;
- }
-
- .empty-text {
- font-size: 14px;
- color: #999;
- }
- }
-
- .loading-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 40px 20px;
-
- .loading-text {
- margin-top: 12px;
- font-size: 14px;
- color: #666;
- }
- }
-
- .load-more {
- text-align: center;
- padding: 16px;
- color: #1677ff;
- font-size: 14px;
- cursor: pointer;
- background: #fff;
- border-radius: 8px;
- margin-top: 12px;
-
- &:hover {
- background: #f0f8ff;
- }
- }
-
- .filter-bar {
- background: #fff;
- border-radius: 12px;
- padding: 16px;
- margin-bottom: 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-
- .filter-tabs {
- display: flex;
- gap: 8px;
-
- .filter-tab {
- flex: 1;
- height: 32px;
- border-radius: 16px;
- font-size: 12px;
- border: 1px solid #d9d9d9;
- background: #fff;
- color: #666;
- cursor: pointer;
- transition: all 0.2s;
-
- &.active {
- background: #1677ff;
- color: #fff;
- border-color: #1677ff;
- }
-
- &:hover:not(.active) {
- border-color: #1677ff;
- color: #1677ff;
- }
- }
- }
- }
-}
diff --git a/Touchkebao/src/pages/mobile/mine/recharge/order/index.tsx b/Touchkebao/src/pages/mobile/mine/recharge/order/index.tsx
deleted file mode 100644
index 7e5260e6..00000000
--- a/Touchkebao/src/pages/mobile/mine/recharge/order/index.tsx
+++ /dev/null
@@ -1,344 +0,0 @@
-import React, { useState, useEffect, useCallback } from "react";
-import { useNavigate } from "react-router-dom";
-import { Card, SpinLoading, Empty, Toast, Dialog } from "antd-mobile";
-import {
- WalletOutlined,
- ClockCircleOutlined,
- WechatOutlined,
- AlipayCircleOutlined,
- BankOutlined,
-} from "@ant-design/icons";
-import NavCommon from "@/components/NavCommon";
-import Layout from "@/components/Layout/Layout";
-import {
- getRechargeOrders,
- cancelRechargeOrder,
- refundRechargeOrder,
-} from "./api";
-import { RechargeOrder } from "./data";
-import style from "./index.module.scss";
-
-const RechargeOrders: React.FC = () => {
- const navigate = useNavigate();
- const [orders, setOrders] = useState([]);
- const [loading, setLoading] = useState(true);
- const [hasMore, setHasMore] = useState(true);
- const [page, setPage] = useState(1);
- const [statusFilter, setStatusFilter] = useState("all");
-
- const loadOrders = async (reset = false) => {
- setLoading(true);
- try {
- const currentPage = reset ? 1 : page;
- const params = {
- page: currentPage,
- limit: 20,
- ...(statusFilter !== "all" && { status: statusFilter }),
- };
-
- const response = await getRechargeOrders(params);
- const newOrders = response.list || [];
- setOrders(prev => (reset ? newOrders : [...prev, ...newOrders]));
- setHasMore(newOrders.length === 20);
- if (reset) setPage(1);
- else setPage(currentPage + 1);
- } catch (error) {
- console.error("加载充值记录失败:", error);
- Toast.show({ content: "加载失败,请重试", position: "top" });
- } finally {
- setLoading(false);
- }
- };
-
- // 初始化加载
- useEffect(() => {
- loadOrders(true);
- }, []);
-
- // 筛选条件变化时重新加载
- const handleFilterChange = (newStatus: string) => {
- setStatusFilter(newStatus);
- setPage(1);
- setOrders([]);
- loadOrders(true);
- };
-
- const getStatusText = (status: string) => {
- switch (status) {
- case "success":
- return "充值成功";
- case "pending":
- return "处理中";
- case "failed":
- return "充值失败";
- case "cancelled":
- return "已取消";
- default:
- return "未知状态";
- }
- };
-
- const getStatusColor = (status: string) => {
- switch (status) {
- case "success":
- return "#52c41a";
- case "pending":
- return "#faad14";
- case "failed":
- return "#ff4d4f";
- case "cancelled":
- return "#999";
- default:
- return "#666";
- }
- };
-
- const getPaymentMethodIcon = (method: string) => {
- switch (method.toLowerCase()) {
- case "wechat":
- return ;
- case "alipay":
- return ;
- case "bank":
- return ;
- default:
- return ;
- }
- };
-
- const getPaymentMethodColor = (method: string) => {
- switch (method.toLowerCase()) {
- case "wechat":
- return "#07c160";
- case "alipay":
- return "#1677ff";
- case "bank":
- return "#722ed1";
- default:
- return "#666";
- }
- };
-
- const formatTime = (timeStr: string) => {
- const date = new Date(timeStr);
- const now = new Date();
- const diff = now.getTime() - date.getTime();
- const days = Math.floor(diff / (1000 * 60 * 60 * 24));
-
- if (days === 0) {
- return date.toLocaleTimeString("zh-CN", {
- hour: "2-digit",
- minute: "2-digit",
- });
- } else if (days === 1) {
- return (
- "昨天 " +
- date.toLocaleTimeString("zh-CN", {
- hour: "2-digit",
- minute: "2-digit",
- })
- );
- } else if (days < 7) {
- return `${days}天前`;
- } else {
- return date.toLocaleDateString("zh-CN");
- }
- };
-
- const handleCancelOrder = async (orderId: string) => {
- const result = await Dialog.confirm({
- content: "确定要取消这个充值订单吗?",
- confirmText: "确定取消",
- cancelText: "再想想",
- });
-
- if (result) {
- try {
- await cancelRechargeOrder(orderId);
- Toast.show({ content: "订单已取消", position: "top" });
- loadOrders(true);
- } catch (error) {
- console.error("取消订单失败:", error);
- Toast.show({ content: "取消失败,请重试", position: "top" });
- }
- }
- };
-
- const handleRefundOrder = async (orderId: string) => {
- const result = await Dialog.confirm({
- content: "确定要申请退款吗?退款将在1-3个工作日内处理。",
- confirmText: "申请退款",
- cancelText: "取消",
- });
-
- if (result) {
- try {
- await refundRechargeOrder(orderId, "用户主动申请退款");
- Toast.show({ content: "退款申请已提交", position: "top" });
- loadOrders(true);
- } catch (error) {
- console.error("申请退款失败:", error);
- Toast.show({ content: "申请失败,请重试", position: "top" });
- }
- }
- };
-
- const renderOrderItem = (order: RechargeOrder) => (
-
-
-
-
订单号:{order.orderNo}
-
-
- {formatTime(order.createTime)}
-
-
-
-
- ¥{order.amount.toFixed(2)}
-
-
- {getStatusText(order.status)}
-
-
-
-
-
-
-
- {getPaymentMethodIcon(order.paymentMethod)}
-
-
{order.paymentMethod}
-
-
- {order.description && (
-
- 备注
- {order.description}
-
- )}
-
- {order.payTime && (
-
- 支付时间
- {formatTime(order.payTime)}
-
- )}
-
- {order.balance !== undefined && (
-
- 充值后余额: ¥{order.balance.toFixed(2)}
-
- )}
-
-
- {order.status === "pending" && (
-
-
-
- )}
-
- {order.status === "success" && (
-
-
-
-
- )}
-
- {order.status === "failed" && (
-
-
-
- )}
-
- );
-
- const filterTabs = [
- { key: "all", label: "全部" },
- { key: "success", label: "成功" },
- { key: "pending", label: "处理中" },
- { key: "failed", label: "失败" },
- { key: "cancelled", label: "已取消" },
- ];
-
- return (
- }
- loading={loading && page === 1}
- >
-
-
-
- {filterTabs.map(tab => (
-
- ))}
-
-
-
- {orders.length === 0 && !loading ? (
-
}
- />
- ) : (
-
- {orders.map(renderOrderItem)}
- {loading && page > 1 && (
-
- )}
- {!loading && hasMore && (
-
loadOrders()}>
- 加载更多
-
- )}
-
- )}
-
-
- );
-};
-
-export default RechargeOrders;
diff --git a/Touchkebao/src/pages/mobile/mine/setting/About.tsx b/Touchkebao/src/pages/mobile/mine/setting/About.tsx
deleted file mode 100644
index 432d15aa..00000000
--- a/Touchkebao/src/pages/mobile/mine/setting/About.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import React from "react";
-import { useNavigate } from "react-router-dom";
-import { NavBar, Card } from "antd-mobile";
-import {
- InfoCircleOutlined,
- MailOutlined,
- PhoneOutlined,
- GlobalOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import style from "./index.module.scss";
-import NavCommon from "@/components/NavCommon";
-const About: React.FC = () => {
- const navigate = useNavigate();
-
- // 应用信息
- const appInfo = {
- name: "存客宝管理系统",
- version: "1.0.0",
- buildNumber: "20241201",
- description: "专业的存客宝管理平台,提供设备管理、自动营销、数据分析等功能",
- };
-
- // 功能特性
- const features = [
- {
- title: "设备管理",
- description: "统一管理微信设备和账号,实时监控设备状态",
- },
- {
- title: "自动营销",
- description: "智能点赞、群发推送、朋友圈同步等自动化营销功能",
- },
- {
- title: "流量池管理",
- description: "高效管理用户流量池,精准分组和标签管理",
- },
- {
- title: "内容库",
- description: "丰富的营销内容库,支持多种媒体格式",
- },
- {
- title: "数据分析",
- description: "详细的数据统计和分析,助力营销决策",
- },
- ];
-
- // 联系信息
- const contractInfo = [
- {
- id: "email",
- title: "邮箱支持",
- value: "support@example.com",
- icon: ,
- action: () => {
- // 复制邮箱到剪贴板
- navigator.clipboard.writeText("support@example.com");
- },
- },
- {
- id: "phone",
- title: "客服热线",
- value: "400-123-4567",
- icon: ,
- action: () => {
- // 拨打电话
- window.location.href = "tel:400-123-4567";
- },
- },
- {
- id: "website",
- title: "官方网站",
- value: "www.example.com",
- icon: ,
- action: () => {
- // 打开网站
- window.open("https://www.example.com", "_blank");
- },
- },
- ];
-
- return (
- }>
-
- {/* 应用信息卡片 */}
-
-
-
-
-

-
-
-
-
{appInfo.name}
-
版本 {appInfo.version}
-
- Build {appInfo.buildNumber}
-
-
-
- {appInfo.description}
-
-
- {/* 功能特性 */}
-
- 功能特性
-
- {features.map((feature, index) => (
-
-
-
-
{feature.title}
-
- {feature.description}
-
-
-
- ))}
-
-
-
- {/* 联系信息 */}
- {/*
- 联系我们
-
- {contractInfo.map(item => (
- }
- onClick={item.action}
- arrow
- />
- ))}
-
- */}
-
- {/* 版权信息 */}
-
-
© 2024 存客宝管理系统
-
保留所有权利
-
-
-
- );
-};
-
-export default About;
diff --git a/Touchkebao/src/pages/mobile/mine/setting/Privacy.tsx b/Touchkebao/src/pages/mobile/mine/setting/Privacy.tsx
deleted file mode 100644
index 4a3ea570..00000000
--- a/Touchkebao/src/pages/mobile/mine/setting/Privacy.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import React from "react";
-import { Card } from "antd-mobile";
-import Layout from "@/components/Layout/Layout";
-import style from "./index.module.scss";
-import NavCommon from "@/components/NavCommon";
-
-const Privacy: React.FC = () => {
- return (
- }>
-
-
-
-
用户隐私协议
-
更新时间:2025年8月1日
-
-
- 1. 信息收集
- 我们收集的信息包括:
-
- - 账户信息:用户名、手机号、邮箱等注册信息
- - 设备信息:设备型号、操作系统版本、设备标识符
- - 使用数据:应用使用情况、功能访问记录
- - 微信相关:微信账号信息、好友数据(经您授权)
-
-
-
-
- 2. 信息使用
- 我们使用收集的信息用于:
-
- - 提供和改进服务功能
- - 个性化用户体验
- - 安全防护和风险控制
- - 客户支持和问题解决
- - 合规性要求和法律义务
-
-
-
-
- 3. 信息共享
- 我们不会向第三方出售、交易或转让您的个人信息,除非:
-
- - 获得您的明确同意
- - 法律法规要求
- - 保护用户和公众的安全
- - 与授权合作伙伴共享必要信息
-
-
-
-
- 4. 数据安全
- 我们采取多种安全措施保护您的信息:
-
- - 数据加密传输和存储
- - 访问控制和身份验证
- - 定期安全审计和更新
- - 员工保密培训
-
-
-
-
- 5. 您的权利
- 您享有以下权利:
-
- - 访问和查看您的个人信息
- - 更正或更新不准确的信息
- - 删除您的账户和相关数据
- - 撤回同意和限制处理
- - 数据可携带性
-
-
-
-
- 6. 数据保留
- 我们仅在必要期间保留您的信息:
-
- - 账户活跃期间持续保留
- - 法律法规要求的保留期
- - 业务运营必要的保留期
- - 您主动删除后及时清除
-
-
-
-
- 7. 儿童隐私
-
- 我们的服务不面向13岁以下儿童。如果发现收集了儿童信息,我们将立即删除。
-
-
-
-
- 8. 国际传输
-
- 您的信息可能在中国境内或境外处理。我们将确保适当的保护措施。
-
-
-
-
- 9. 协议更新
-
- 我们可能会更新本隐私协议。重大变更将通过应用内通知或邮件告知您。
-
-
-
-
- 10. 联系我们
- 如果您对本隐私协议有任何疑问,请联系我们:
-
- - 邮箱:privacy@example.com
- - 电话:400-123-4567
- - 地址:北京市朝阳区xxx大厦
-
-
-
-
-
-
-
-
- );
-};
-
-export default Privacy;
diff --git a/Touchkebao/src/pages/mobile/mine/setting/README.md b/Touchkebao/src/pages/mobile/mine/setting/README.md
deleted file mode 100644
index c8a454b6..00000000
--- a/Touchkebao/src/pages/mobile/mine/setting/README.md
+++ /dev/null
@@ -1,188 +0,0 @@
-# 设置功能说明
-
-## 概述
-
-设置功能为存客宝管理系统提供了完整的用户配置管理,包括账户设置、通知设置、应用设置等多个模块。
-
-## 功能模块
-
-### 1. 主设置页面 (`index.tsx`)
-
-**功能特性:**
-
-- 用户信息展示
-- 分组设置项管理
-- 设置状态持久化
-
-**主要组件:**
-
-- 用户信息卡片:显示头像、昵称、账号、角色
-- 设置分组:账户设置、通知设置、应用设置、其他
-- 版本信息:显示应用版本和版权信息
-
-### 2. 安全设置页面 (`SecuritySetting.tsx`)
-
-**功能特性:**
-
-- 密码修改
-- 手机号绑定
-- 登录设备管理
-- 安全建议
-
-**主要功能:**
-
-- 修改密码:支持旧密码验证和新密码确认
-- 绑定手机号:提高账号安全性
-- 设备管理:查看和管理已登录设备
-- 安全提醒:提供账号安全建议
-
-### 3. 关于页面 (`About.tsx`)
-
-**功能特性:**
-
-- 应用信息展示
-- 功能特性介绍
-- 联系方式
-- 法律信息
-
-**主要内容:**
-
-- 应用版本信息
-- 功能介绍:设备管理、自动营销、流量池管理等
-- 联系方式:邮箱、电话、官网
-- 法律文档:隐私政策、用户协议、开源许可
-
-## 设置管理
-
-### 设置Store (`settings.ts`)
-
-**功能特性:**
-
-- 全局设置状态管理
-- 设置持久化存储
-- 设置工具函数
-
-**支持的设置项:**
-
-#### 通知设置
-
-- `pushNotification`: 推送通知开关
-- `emailNotification`: 邮件通知开关
-- `soundNotification`: 声音提醒开关
-
-#### 应用设置
-
-- `autoLogin`: 自动登录开关
-- `language`: 语言设置
-- `timezone`: 时区设置
-
-#### 隐私设置
-
-- `analyticsEnabled`: 数据分析开关
-- `crashReportEnabled`: 崩溃报告开关
-
-#### 功能设置
-
-- `autoSave`: 自动保存开关
-- `showTutorial`: 教程显示开关
-
-### 工具函数
-
-```typescript
-// 获取设置值
-const value = getSetting("pushNotification");
-
-// 设置值
-setSetting("autoLogin", true);
-```
-
-## 样式设计
-
-### 设计原则
-
-- 移动端优先设计
-- 统一的视觉风格
-- 良好的用户体验
-
-### 样式特性
-
-- 响应式布局
-- 卡片式设计
-- 圆角边框
-- 阴影效果
-- 渐变背景
-
-## 路由配置
-
-```typescript
-// 设置相关路由
-{
- path: "/settings",
- element: ,
- auth: true,
-},
-{
- path: "/security",
- element: ,
- auth: true,
-},
-{
- path: "/about",
- element: ,
- auth: true,
-}
-```
-
-## 使用示例
-
-### 基本使用
-
-```typescript
-import { useSettingsStore } from '@/store/module/settings';
-
-const MyComponent = () => {
- const { settings, updateSetting } = useSettingsStore();
-
- const handleToggleNotification = () => {
- updateSetting('pushNotification', !settings.pushNotification);
- };
-
- return (
-
- );
-};
-```
-
-## 扩展功能
-
-### 添加新设置项
-
-1. 在 `AppSettings` 接口中添加新字段
-2. 在 `defaultSettings` 中设置默认值
-3. 在设置页面中添加对应的UI组件
-4. 在样式文件中添加相应的样式
-
-### 添加新设置页面
-
-1. 创建新的页面组件
-2. 在路由配置中添加路由
-3. 在主设置页面中添加导航链接
-4. 添加相应的样式
-
-## 注意事项
-
-1. **数据持久化**:所有设置都会自动保存到本地存储
-2. **权限控制**:某些设置可能需要管理员权限
-3. **兼容性**:确保在不同设备和浏览器上的兼容性
-4. **性能优化**:避免频繁的设置更新影响性能
-
-## 未来规划
-
-- [ ] 多语言支持
-- [ ] 设置导入导出
-- [ ] 云端同步设置
-- [ ] 设置备份恢复
-- [ ] 高级设置选项
diff --git a/Touchkebao/src/pages/mobile/mine/setting/SecuritySetting.tsx b/Touchkebao/src/pages/mobile/mine/setting/SecuritySetting.tsx
deleted file mode 100644
index 9ae89537..00000000
--- a/Touchkebao/src/pages/mobile/mine/setting/SecuritySetting.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-import React, { useState } from "react";
-import { useNavigate } from "react-router-dom";
-import { NavBar, List, Dialog, Toast, Card, Input } from "antd-mobile";
-import {
- LockOutlined,
- MobileOutlined,
- SafetyOutlined,
- RightOutlined,
-} from "@ant-design/icons";
-import Layout from "@/components/Layout/Layout";
-import { useUserStore } from "@/store/module/user";
-import style from "./index.module.scss";
-import NavCommon from "@/components/NavCommon";
-const SecuritySetting: React.FC = () => {
- const navigate = useNavigate();
- const { user } = useUserStore();
- const [showPasswordDialog, setShowPasswordDialog] = useState(false);
- const [passwordForm, setPasswordForm] = useState({
- oldPassword: "",
- newPassword: "",
- confirmPassword: "",
- });
-
- // 修改密码
- const handleChangePassword = async () => {
- const { oldPassword, newPassword, confirmPassword } = passwordForm;
-
- if (!oldPassword || !newPassword || !confirmPassword) {
- Toast.show({ content: "请填写完整信息", position: "top" });
- return;
- }
-
- if (newPassword !== confirmPassword) {
- Toast.show({ content: "两次输入的新密码不一致", position: "top" });
- return;
- }
-
- if (newPassword.length < 6) {
- Toast.show({ content: "新密码长度不能少于6位", position: "top" });
- return;
- }
-
- try {
- // TODO: 调用修改密码API
- Toast.show({ content: "密码修改成功", position: "top" });
- setShowPasswordDialog(false);
- setPasswordForm({
- oldPassword: "",
- newPassword: "",
- confirmPassword: "",
- });
- } catch (error: any) {
- Toast.show({ content: error.message || "密码修改失败", position: "top" });
- }
- };
-
- // 绑定手机号
- const handleBindPhone = () => {
- Toast.show({ content: "功能开发中", position: "top" });
- };
-
- // 登录设备管理
- const handleDeviceManagement = () => {
- Toast.show({ content: "功能开发中", position: "top" });
- };
-
- // 安全设置项
- const securityItems = [
- {
- id: "password",
- title: "修改密码",
- description: "定期更换密码,保护账号安全",
- icon: ,
- onClick: () => setShowPasswordDialog(true),
- },
- {
- id: "phone",
- title: "绑定手机号",
- description: user?.phone
- ? `已绑定:${user.phone}`
- : "绑定手机号,提高账号安全性",
- icon: ,
- onClick: handleBindPhone,
- },
- {
- id: "devices",
- title: "登录设备管理",
- description: "查看和管理已登录的设备",
- icon: ,
- onClick: handleDeviceManagement,
- },
- ];
-
- return (
- }>
-
- {/* 安全提示卡片 */}
-
-
-
-
-
账号安全提醒
-
- 建议定期更换密码,开启双重验证,保护您的账号安全
-
-
-
-
-
- {/* 安全设置列表 */}
-
- 安全设置
-
- {securityItems.map(item => (
-
- ))}
-
-
-
- {/* 安全建议 */}
-
- 安全建议
-
-
- •
- 使用强密码,包含字母、数字和特殊字符
-
-
- •
- 定期更换密码,建议每3个月更换一次
-
-
- •
- 不要在公共场所登录账号
-
-
- •
- 及时清理不常用的登录设备
-
-
-
-
-
- {/* 修改密码对话框 */}
-