diff --git a/nkebao/src/pages/workspace/auto-group/AutoGroup.tsx b/nkebao/src/pages/workspace/auto-group/AutoGroup.tsx index 58c8acd4..b3ee7157 100644 --- a/nkebao/src/pages/workspace/auto-group/AutoGroup.tsx +++ b/nkebao/src/pages/workspace/auto-group/AutoGroup.tsx @@ -57,6 +57,59 @@ interface GroupTask { groupDescription: string; } +// CardMenu组件,参考AutoLike实现 +function CardMenu({ onView, onEdit, onCopy, onDelete }: { onView: () => void; onEdit: () => void; onCopy: () => void; onDelete: () => void; }) { + const [open, setOpen] = React.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 && ( +
+
{ onView(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}> + 查看 +
+
{ onEdit(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}> + 编辑 +
+
{ onCopy(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}> + 复制 +
+
{ onDelete(); setOpen(false); }} style={{ padding: 8, cursor: "pointer", display: "flex", alignItems: "center", borderRadius: 6, fontSize: 14, gap: 6, color: "#e53e3e", transition: "background .2s" }} onMouseOver={e => (e.currentTarget as HTMLDivElement).style.background="#f5f5f5"} onMouseOut={e => (e.currentTarget as HTMLDivElement).style.background=""}> + 删除 +
+
+ )} +
+ ); +} + export default function AutoGroup() { const navigate = useNavigate(); const { toast } = useToast(); @@ -260,31 +313,12 @@ export default function AutoGroup() { onCheckedChange={() => toggleTaskStatus(task.id)} disabled={task.status === 'completed'} /> - - - - - - handleView(task.id)}> - - 查看 - - handleEdit(task.id)}> - - 编辑 - - handleCopy(task.id)}> - - 复制 - - handleDelete(task.id)}> - - 删除 - - - + handleView(task.id)} + onEdit={() => handleEdit(task.id)} + onCopy={() => handleCopy(task.id)} + onDelete={() => handleDelete(task.id)} + /> diff --git a/nkebao/src/pages/workspace/auto-group/Detail.tsx b/nkebao/src/pages/workspace/auto-group/Detail.tsx index 3c6750a0..621cfada 100644 --- a/nkebao/src/pages/workspace/auto-group/Detail.tsx +++ b/nkebao/src/pages/workspace/auto-group/Detail.tsx @@ -1,7 +1,414 @@ -import React from 'react'; -import { useParams } from 'react-router-dom'; +import { useState, useEffect } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { + ChevronLeft, + Search, + Filter, + RefreshCw, + AlertCircle, + CheckCircle2, + Users, +} from 'lucide-react'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Badge } from '@/components/ui/badge'; +import { Progress } from '@/components/ui/progress'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import Layout from '@/components/Layout'; +import PageHeader from '@/components/PageHeader'; +import { useToast } from '@/components/ui/toast'; +import '@/components/Layout.css'; + +// 群组成员接口 +interface GroupMember { + id: string; + nickname: string; + wechatId: string; + tags: string[]; +} + +// 群组接口 +interface Group { + id: string; + members: GroupMember[]; +} + +// 建群任务详情接口 +interface GroupTaskDetail { + id: string; + name: string; + status: 'preparing' | 'creating' | 'completed' | 'paused'; + totalGroups: number; + currentGroupIndex: number; + groups: Group[]; + createTime: string; + lastUpdateTime: string; + creator: string; + deviceCount: number; + targetFriends: number; + groupSize: { min: number; max: number }; + timeRange: { start: string; end: string }; + targetTags: string[]; + groupNameTemplate: string; + groupDescription: string; +} + +// 群组预览组件 +function GroupPreview({ + groupIndex, + members, + isCreating, + isCompleted, + onRetry +}: { + groupIndex: number; + members: GroupMember[]; + isCreating: boolean; + isCompleted: boolean; + onRetry?: () => void; +}) { + const [expanded, setExpanded] = useState(false); + const targetSize = 38; // 微信群人数固定为38人 + + return ( + + +
+ + 群 {groupIndex + 1} + + {isCompleted ? "已完成" : isCreating ? "创建中" : "等待中"} + + +
+ + {members.length}/{targetSize} +
+
+
+ + {isCreating && !isCompleted && ( +
+ +
+ )} + + {expanded ? ( +
+
+ {members.map((member) => ( +
+ {member.nickname} + {member.tags.length > 0 && ( + + {member.tags[0]} + + )} +
+ ))} +
+ +
+ ) : ( + + )} + + {!isCompleted && members.length < targetSize && ( +
+ + 群人数不足{targetSize}人 + {onRetry && ( + + )} +
+ )} + + {isCompleted && ( +
+ + 群创建完成 +
+ )} +
+
+ ); +} + +// 建群进度组件 +function GroupCreationProgress({ + taskDetail, + onComplete +}: { + taskDetail: GroupTaskDetail; + onComplete: () => void; +}) { + const [groups, setGroups] = useState(taskDetail.groups); + const [currentGroupIndex, setCurrentGroupIndex] = useState(taskDetail.currentGroupIndex); + const [status, setStatus] = useState<'preparing' | 'creating' | 'completed'>(taskDetail.status as any); + const [error, setError] = useState(null); + + useEffect(() => { + // 模拟建群进度更新 + if (status === 'creating' && currentGroupIndex < groups.length) { + const timer = setTimeout(() => { + if (currentGroupIndex === groups.length - 1) { + setStatus('completed'); + onComplete(); + } else { + setCurrentGroupIndex((prev) => prev + 1); + } + }, 3000); + return () => clearTimeout(timer); + } + }, [status, currentGroupIndex, groups.length, onComplete]); + + const handleRetryGroup = (groupIndex: number) => { + // 模拟重试逻辑 + setGroups((prev) => + prev.map((group, index) => { + if (index === groupIndex) { + return { + ...group, + members: [ + ...group.members, + { + id: `retry-member-${Date.now()}`, + nickname: `补充用户${group.members.length + 1}`, + wechatId: `wx_retry_${Date.now()}`, + tags: ['新加入'], + }, + ], + }; + } + return group; + }), + ); + }; + + return ( +
+ + +
+ + 建群进度 + + {status === "preparing" ? "准备中" : status === "creating" ? "创建中" : "已完成"} + + +
+ {currentGroupIndex + 1}/{groups.length}组 +
+
+
+ + + +
+ + {error && ( + + + {error} + + )} + + +
+ {groups.map((group, index) => ( + handleRetryGroup(index)} + /> + ))} +
+
+ + {status === "completed" && ( + + + 所有群组已创建完成 + + )} +
+ ); +} export default function AutoGroupDetail() { - const { id } = useParams(); - return
分组详情页,当前ID: {id}
; + const { id } = useParams<{ id: string }>(); + const navigate = useNavigate(); + const { toast } = useToast(); + const [loading, setLoading] = useState(true); + const [taskDetail, setTaskDetail] = useState(null); + + // 模拟获取任务详情 + useEffect(() => { + const fetchTaskDetail = async () => { + setLoading(true); + try { + // 模拟API调用 + await new Promise(resolve => setTimeout(resolve, 1000)); + + // 模拟数据 + const mockTaskDetail: GroupTaskDetail = { + id: id || '1', + name: 'VIP客户建群', + status: 'creating', + totalGroups: 5, + currentGroupIndex: 2, + groups: Array.from({ length: 5 }).map((_, index) => ({ + id: `group-${index}`, + members: Array.from({ length: Math.floor(Math.random() * 10) + 30 }).map((_, mIndex) => ({ + id: `member-${index}-${mIndex}`, + nickname: `用户${mIndex + 1}`, + wechatId: `wx_${mIndex}`, + tags: [`标签${(mIndex % 3) + 1}`], + })), + })), + createTime: '2024-11-20 19:04:14', + lastUpdateTime: '2025-02-06 13:12:35', + creator: 'admin', + deviceCount: 2, + targetFriends: 156, + groupSize: { min: 20, max: 50 }, + timeRange: { start: '09:00', end: '21:00' }, + targetTags: ['VIP客户', '高价值'], + groupNameTemplate: 'VIP客户交流群{序号}', + groupDescription: 'VIP客户专属交流群,提供优质服务', + }; + + setTaskDetail(mockTaskDetail); + } catch (error) { + console.error('获取任务详情失败:', error); + toast({ + title: '获取任务详情失败', + description: '请稍后重试', + variant: 'destructive', + }); + } finally { + setLoading(false); + } + }; + + if (id) { + fetchTaskDetail(); + } + }, [id, toast]); + + const handleComplete = () => { + toast({ + title: '建群完成', + description: '所有群组已创建完成', + }); + }; + + if (loading) { + return ( + + } + > +
+
+
+
+
+
加载中...
+
+
+
+
+
+ ); + } + + if (!taskDetail) { + return ( + + } + > +
+
+ + +

任务不存在

+

请检查任务ID是否正确

+ +
+
+
+
+ ); + } + + return ( + + } + > +
+
+ {/* 任务基本信息 */} + +
+
+

基本信息

+
+
任务名称:{taskDetail.name}
+
创建时间:{taskDetail.createTime}
+
创建人:{taskDetail.creator}
+
执行设备:{taskDetail.deviceCount} 个
+
+
+
+

建群配置

+
+
群组规模:{taskDetail.groupSize.min}-{taskDetail.groupSize.max} 人
+
执行时间:{taskDetail.timeRange.start} - {taskDetail.timeRange.end}
+
目标标签:{taskDetail.targetTags.join(', ')}
+
群名称模板:{taskDetail.groupNameTemplate}
+
+
+
+
+ + {/* 建群进度 */} + +
+
+
+ ); } \ No newline at end of file