From aad2d055b7983438b09d2d619fcf5ff2358bfa24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=B0=B8=E5=B9=B3?= Date: Fri, 4 Jul 2025 14:24:20 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E9=9D=99=E6=80=81=E5=81=9A?= =?UTF-8?q?=E5=AE=8C=E4=BA=86=EF=BC=8C=E5=85=88=E5=AD=98=E4=B8=80=E6=B3=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nkebao/src/App.tsx | 6 + nkebao/src/pages/plans/PlanDetail.tsx | 239 +++++++++++++++ nkebao/src/pages/plans/Plans.tsx | 192 +++++++++++- nkebao/src/pages/scenarios/NewPlan.tsx | 180 +++++++++++ nkebao/src/pages/scenarios/ScenarioDetail.tsx | 284 ++++++++++++++++++ nkebao/src/pages/scenarios/Scenarios.tsx | 214 ++++++++++++- 6 files changed, 1111 insertions(+), 4 deletions(-) create mode 100644 nkebao/src/pages/plans/PlanDetail.tsx create mode 100644 nkebao/src/pages/scenarios/NewPlan.tsx create mode 100644 nkebao/src/pages/scenarios/ScenarioDetail.tsx diff --git a/nkebao/src/App.tsx b/nkebao/src/App.tsx index 80c21cce..a9fafab2 100644 --- a/nkebao/src/App.tsx +++ b/nkebao/src/App.tsx @@ -14,8 +14,11 @@ import MomentsSyncDetail from './pages/workspace/moments-sync/Detail'; import TrafficDistribution from './pages/workspace/traffic-distribution/TrafficDistribution'; import TrafficDistributionDetail from './pages/workspace/traffic-distribution/Detail'; import Scenarios from './pages/scenarios/Scenarios'; +import NewPlan from './pages/scenarios/NewPlan'; +import ScenarioDetail from './pages/scenarios/ScenarioDetail'; import Profile from './pages/profile/Profile'; import Plans from './pages/plans/Plans'; +import PlanDetail from './pages/plans/PlanDetail'; import Orders from './pages/orders/Orders'; import TrafficPool from './pages/traffic-pool/TrafficPool'; import ContactImport from './pages/contact-import/ContactImport'; @@ -39,8 +42,11 @@ function App() { } /> } /> } /> + } /> + } /> } /> } /> + } /> } /> } /> } /> diff --git a/nkebao/src/pages/plans/PlanDetail.tsx b/nkebao/src/pages/plans/PlanDetail.tsx new file mode 100644 index 00000000..902ba18e --- /dev/null +++ b/nkebao/src/pages/plans/PlanDetail.tsx @@ -0,0 +1,239 @@ +import React, { useEffect, useState } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { ArrowLeft, Users, TrendingUp, Calendar, Settings, Play, Pause, Edit } from 'lucide-react'; + +interface PlanData { + id: string; + name: string; + status: 'active' | 'paused' | 'completed'; + createdAt: string; + totalCustomers: number; + todayCustomers: number; + growth: string; + description?: string; + scenario: string; +} + +export default function PlanDetail() { + const { planId } = useParams<{ planId: string }>(); + const navigate = useNavigate(); + const [plan, setPlan] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + + useEffect(() => { + const fetchPlanData = async () => { + setLoading(true); + try { + // 模拟API调用 + const mockPlan: PlanData = { + id: planId || '', + name: '春季营销计划', + status: 'active', + createdAt: '2024-03-15', + totalCustomers: 456, + todayCustomers: 23, + growth: '+8.2%', + description: '针对春季市场的营销推广计划,通过多种渠道获取潜在客户', + scenario: 'douyin', + }; + + setPlan(mockPlan); + } catch (error) { + setError('获取计划数据失败'); + console.error('获取计划数据失败:', error); + } finally { + setLoading(false); + } + }; + + fetchPlanData(); + }, [planId]); + + const handleStatusChange = async (newStatus: 'active' | 'paused') => { + if (!plan) return; + + try { + // 这里可以调用实际的API + // await fetch(`/api/plans/${plan.id}/status`, { + // method: 'PATCH', + // headers: { 'Content-Type': 'application/json' }, + // body: JSON.stringify({ status: newStatus }), + // }); + + setPlan({ ...plan, status: newStatus }); + } catch (error) { + console.error('更新计划状态失败:', error); + alert('更新失败,请重试'); + } + }; + + if (loading) { + return ( +
+
+
加载中...
+
+
+ ); + } + + if (error || !plan) { + return ( +
+
{error || '计划不存在'}
+
+ ); + } + + return ( +
+
+
+
+ +

{plan.name}

+
+
+ + +
+
+
+ +
+ {/* 计划描述 */} + {plan.description && ( +
+

{plan.description}

+
+ )} + + {/* 数据统计 */} +
+
+
+
+

总获客数

+

{plan.totalCustomers}

+
+ +
+
+ + {plan.growth} +
+
+ +
+
+
+

今日获客

+

{plan.todayCustomers}

+
+ +
+
+ 创建于 {plan.createdAt} +
+
+
+ + {/* 状态控制 */} +
+

计划状态

+
+
+ + {plan.status === 'active' ? '进行中' : plan.status === 'paused' ? '已暂停' : '已完成'} + +
+
+ {plan.status === 'active' ? ( + + ) : plan.status === 'paused' ? ( + + ) : null} +
+
+
+ + {/* 功能区域 */} +
+
navigate(`/plans/${plan.id}/customers`)}> +
+ +
+

客户管理

+

查看和管理获客客户

+
+
+
+ +
navigate(`/plans/${plan.id}/analytics`)}> +
+ +
+

数据分析

+

查看获客数据统计

+
+
+
+ +
navigate(`/plans/${plan.id}/content`)}> +
+ +
+

内容管理

+

管理营销内容

+
+
+
+ +
navigate(`/plans/${plan.id}/settings`)}> +
+ +
+

计划设置

+

配置计划参数

+
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/nkebao/src/pages/plans/Plans.tsx b/nkebao/src/pages/plans/Plans.tsx index 195ab943..525d85ec 100644 --- a/nkebao/src/pages/plans/Plans.tsx +++ b/nkebao/src/pages/plans/Plans.tsx @@ -1,5 +1,193 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Plus, Users, TrendingUp, Calendar } from 'lucide-react'; + +interface Plan { + id: string; + name: string; + status: 'active' | 'paused' | 'completed'; + createdAt: string; + totalCustomers: number; + todayCustomers: number; + growth: string; + scenario: string; +} export default function Plans() { - return
套餐页
; + const navigate = useNavigate(); + const [plans, setPlans] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(''); + + useEffect(() => { + const fetchPlans = async () => { + setLoading(true); + try { + // 模拟API调用 + const mockPlans: Plan[] = [ + { + id: '1', + name: '春季营销计划', + status: 'active', + createdAt: '2024-03-15', + totalCustomers: 456, + todayCustomers: 23, + growth: '+8.2%', + scenario: 'douyin', + }, + { + id: '2', + name: '新品推广计划', + status: 'active', + createdAt: '2024-03-10', + totalCustomers: 234, + todayCustomers: 15, + growth: '+5.1%', + scenario: 'xiaohongshu', + }, + { + id: '3', + name: '节日活动计划', + status: 'paused', + createdAt: '2024-02-28', + totalCustomers: 789, + todayCustomers: 0, + growth: '+0%', + scenario: 'gongzhonghao', + }, + ]; + + setPlans(mockPlans); + } catch (error) { + setError('获取计划数据失败'); + console.error('获取计划数据失败:', error); + } finally { + setLoading(false); + } + }; + + fetchPlans(); + }, []); + + const getStatusColor = (status: string) => { + switch (status) { + case 'active': + return 'text-green-600 bg-green-50'; + case 'paused': + return 'text-yellow-600 bg-yellow-50'; + case 'completed': + return 'text-gray-600 bg-gray-50'; + default: + return 'text-gray-600 bg-gray-50'; + } + }; + + const getStatusText = (status: string) => { + switch (status) { + case 'active': + return '进行中'; + case 'paused': + return '已暂停'; + case 'completed': + return '已完成'; + default: + return '未知'; + } + }; + + if (loading) { + return ( +
+
+
+

获客计划

+
+
+
+
加载中...
+
+
+ ); + } + + if (error) { + return ( +
+
+
+

获客计划

+
+
+
{error}
+
+ ); + } + + return ( +
+
+
+

获客计划

+ +
+
+ +
+ {plans.length === 0 ? ( +
+

暂无获客计划

+ +
+ ) : ( +
+ {plans.map((plan) => ( +
navigate(`/plans/${plan.id}`)} + > +
+
+
+

{plan.name}

+ + {getStatusText(plan.status)} + +
+
+ + 创建于 {plan.createdAt} +
+
+ +
+
+ 总获客: + {plan.totalCustomers} +
+
+ 今日: + {plan.todayCustomers} + ({plan.growth}) +
+
+
+
+ ))} +
+ )} +
+
+ ); } \ No newline at end of file diff --git a/nkebao/src/pages/scenarios/NewPlan.tsx b/nkebao/src/pages/scenarios/NewPlan.tsx new file mode 100644 index 00000000..d305a694 --- /dev/null +++ b/nkebao/src/pages/scenarios/NewPlan.tsx @@ -0,0 +1,180 @@ +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { ArrowLeft, Check } from 'lucide-react'; + +interface ScenarioOption { + id: string; + name: string; + icon: string; + description: string; + image: string; +} + +const scenarioOptions: ScenarioOption[] = [ + { + id: "douyin", + name: "抖音获客", + icon: "🎵", + description: "通过抖音平台进行精准获客", + image: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-QR8ManuDplYTySUJsY4mymiZkDYnQ9.png", + }, + { + id: "xiaohongshu", + name: "小红书获客", + icon: "📖", + description: "利用小红书平台进行内容营销获客", + image: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-yvnMxpoBUzcvEkr8DfvHgPHEo1kmQ3.png", + }, + { + id: "gongzhonghao", + name: "公众号获客", + icon: "📱", + description: "通过微信公众号进行获客", + image: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-Gsg0CMf5tsZb41mioszdjqU1WmsRxW.png", + }, + { + id: "haibao", + name: "海报获客", + icon: "🖼️", + description: "通过海报分享进行获客", + image: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-x92XJgXy4MI7moNYlA1EAes2FqDxMH.png", + }, +]; + +export default function NewPlan() { + const navigate = useNavigate(); + const [selectedScenario, setSelectedScenario] = useState(''); + const [planName, setPlanName] = useState(''); + const [description, setDescription] = useState(''); + const [loading, setLoading] = useState(false); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!selectedScenario || !planName.trim()) { + alert('请选择场景并填写计划名称'); + return; + } + + setLoading(true); + try { + // 这里可以调用实际的API + // const response = await fetch('/api/plans', { + // method: 'POST', + // headers: { 'Content-Type': 'application/json' }, + // body: JSON.stringify({ + // scenarioId: selectedScenario, + // name: planName, + // description: description, + // }), + // }); + + // 模拟API调用 + await new Promise(resolve => setTimeout(resolve, 1000)); + + // 跳转到计划详情页 + navigate(`/scenarios/${selectedScenario}?plan=${encodeURIComponent(planName)}`); + } catch (error) { + console.error('创建计划失败:', error); + alert('创建计划失败,请重试'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+ +

新建计划

+
+
+ +
+
+ {/* 场景选择 */} +
+

选择获客场景

+
+ {scenarioOptions.map((scenario) => ( +
setSelectedScenario(scenario.id)} + > + {selectedScenario === scenario.id && ( +
+ +
+ )} +
+ {scenario.name} +

{scenario.name}

+

{scenario.description}

+
+
+ ))} +
+
+ + {/* 计划信息 */} +
+

计划信息

+ +
+ + setPlanName(e.target.value)} + placeholder="请输入计划名称" + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + required + /> +
+ +
+ +