diff --git a/nkebao/src/pages/mobile/content/form/index.tsx b/nkebao/src/pages/mobile/content/form/index.tsx index 1eb91a06..d51e646d 100644 --- a/nkebao/src/pages/mobile/content/form/index.tsx +++ b/nkebao/src/pages/mobile/content/form/index.tsx @@ -202,7 +202,7 @@ export default function ContentForm() { diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx index b26279fd..fa2d5863 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx @@ -438,7 +438,7 @@ const BasicSettings: React.FC = ({
选择群聊
onChange({ ...formData, groupSelected: groups }) } diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx index ee2fdc8a..e70a9def 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx @@ -450,7 +450,7 @@ const MessageSettings: React.FC = ({ {message.type === "group" && (
handleUpdateMessage(dayIndex, messageIndex, { groupIds: groupIds, diff --git a/nkebao/src/pages/mobile/workspace/auto-like/new/NewAutoLike.tsx b/nkebao/src/pages/mobile/workspace/auto-like/new/NewAutoLike.tsx deleted file mode 100644 index 8aeab900..00000000 --- a/nkebao/src/pages/mobile/workspace/auto-like/new/NewAutoLike.tsx +++ /dev/null @@ -1,594 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { - ChevronLeft, - Plus, - Minus, - Check, - X, - Tag as TagIcon, -} from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; -import { - createAutoLikeTask, - updateAutoLikeTask, - fetchAutoLikeTaskDetail, -} from "@/api/autoLike"; -import { ContentType } from "@/types/auto-like"; -import { useToast } from "@/components/ui/toast"; -import Layout from "@/components/Layout"; -import DeviceSelection from "@/components/DeviceSelection"; -import FriendSelection from "@/components/FriendSelection"; - -// 修改CreateLikeTaskData接口,确保friends字段不是可选的 -interface CreateLikeTaskDataLocal { - name: string; - interval: number; - maxLikes: number; - startTime: string; - endTime: string; - contentTypes: ContentType[]; - devices: string[]; - friends: string[]; - friendMaxLikes: number; - friendTags: string; - enableFriendTags: boolean; - targetTags: string[]; -} - -export default function NewAutoLike() { - const navigate = useNavigate(); - const { id } = useParams<{ id: string }>(); - const isEditMode = !!id; - const { toast } = useToast(); - const [currentStep, setCurrentStep] = useState(1); - const [isSubmitting, setIsSubmitting] = useState(false); - const [isLoading, setIsLoading] = useState(isEditMode); - const [formData, setFormData] = useState({ - name: "", - interval: 5, - maxLikes: 200, - startTime: "08:00", - endTime: "22:00", - contentTypes: ["text", "image", "video"], - devices: [], - friends: [], // 确保初始化为空数组而不是undefined - targetTags: [], - friendMaxLikes: 10, - enableFriendTags: false, - friendTags: "", - }); - // 新增自动开启的独立状态 - const [autoEnabled, setAutoEnabled] = useState(false); - - // 如果是编辑模式,获取任务详情 - useEffect(() => { - if (isEditMode && id) { - fetchTaskDetail(); - } - }, [id, isEditMode]); - - // 获取任务详情 - const fetchTaskDetail = async () => { - try { - const taskDetail = await fetchAutoLikeTaskDetail(id!); - console.log("Task detail response:", taskDetail); // 添加日志用于调试 - - if (taskDetail) { - // 使用类型断言处理可能的字段名称差异 - const taskAny = taskDetail as any; - // 处理可能的嵌套结构 - const config = taskAny.config || taskAny; - - setFormData({ - name: taskDetail.name || "", - interval: config.likeInterval || config.interval || 5, - maxLikes: config.maxLikesPerDay || config.maxLikes || 200, - startTime: config.timeRange?.start || config.startTime || "08:00", - endTime: config.timeRange?.end || config.endTime || "22:00", - contentTypes: config.contentTypes || ["text", "image", "video"], - devices: config.devices || [], - friends: config.friends || [], - targetTags: config.targetTags || [], - friendMaxLikes: config.friendMaxLikes || 10, - enableFriendTags: config.enableFriendTags || false, - friendTags: config.friendTags || "", - }); - - // 处理状态字段,使用双等号允许类型自动转换 - const status = taskAny.status; - setAutoEnabled(status === 1 || status === "running"); - } else { - toast({ - title: "获取任务详情失败", - description: "无法找到该任务", - variant: "destructive", - }); - navigate("/workspace/auto-like"); - } - } catch (error) { - console.error("获取任务详情出错:", error); // 添加错误日志 - toast({ - title: "获取任务详情失败", - description: "请检查网络连接后重试", - variant: "destructive", - }); - navigate("/workspace/auto-like"); - } finally { - setIsLoading(false); - } - }; - - const handleUpdateFormData = (data: Partial) => { - setFormData(prev => ({ ...prev, ...data })); - }; - - const handleNext = () => { - setCurrentStep(prev => Math.min(prev + 1, 3)); - // 滚动到顶部 - const mainElement = document.querySelector("main"); - if (mainElement) { - mainElement.scrollTo({ top: 0, behavior: "smooth" }); - } - }; - - const handlePrev = () => { - setCurrentStep(prev => Math.max(prev - 1, 1)); - // 滚动到顶部 - const mainElement = document.querySelector("main"); - if (mainElement) { - mainElement.scrollTo({ top: 0, behavior: "smooth" }); - } - }; - - const handleComplete = async () => { - if (isSubmitting) return; - setIsSubmitting(true); - try { - // 转换为API需要的格式 - const apiFormData = { - ...formData, - // 如果API需要其他转换,可以在这里添加 - }; - - let response; - if (isEditMode) { - // 编辑模式,调用更新API - response = await updateAutoLikeTask({ - ...apiFormData, - id: id!, - }); - } else { - // 新建模式,调用创建API - response = await createAutoLikeTask(apiFormData); - } - - if (response.code === 200) { - toast({ - title: isEditMode ? "更新成功" : "创建成功", - description: isEditMode - ? "自动点赞任务已更新" - : "自动点赞任务已创建并开始执行", - }); - navigate("/workspace/auto-like"); - } else { - toast({ - title: isEditMode ? "更新失败" : "创建失败", - description: response.msg || "请稍后重试", - variant: "destructive", - }); - } - } catch (error) { - toast({ - title: isEditMode ? "更新失败" : "创建失败", - description: "请检查网络连接后重试", - variant: "destructive", - }); - } finally { - setIsSubmitting(false); - } - }; - - const header = ( -
-
- -

- {isEditMode ? "编辑自动点赞" : "新建自动点赞"} -

-
- -
- ); - - if (isLoading) { - return ( - -
-
-
-

加载中...

-
-
-
- ); - } - - return ( - -
-
-
- {currentStep === 1 && ( - - )} - - {currentStep === 2 && ( -
- handleUpdateFormData({ devices })} - placeholder="选择设备" - /> - -
- - -
-
- )} - - {currentStep === 3 && ( -
- handleUpdateFormData({ friends })} - deviceIds={formData.devices} - placeholder="选择微信好友" - /> - -
- - -
-
- )} -
-
-
-
- ); -} - -// 步骤指示器组件 -interface StepIndicatorProps { - currentStep: number; -} - -function StepIndicator({ currentStep }: StepIndicatorProps) { - const steps = [ - { title: "基础设置", description: "设置点赞规则" }, - { title: "设备选择", description: "选择执行设备" }, - { title: "人群选择", description: "选择目标人群" }, - ]; - - return ( -
-
-
- {steps.map((step, index) => ( -
-
- {index < currentStep ? ( - - ) : ( - index + 1 - )} -
-
-
- {step.title} -
-
- {step.description} -
-
-
- ))} -
-
-
-
-
-
- ); -} - -// 基础设置组件 -interface BasicSettingsProps { - formData: CreateLikeTaskDataLocal; - onChange: (data: Partial) => void; - onNext: () => void; - autoEnabled: boolean; - setAutoEnabled: (v: boolean) => void; -} - -function BasicSettings({ - formData, - onChange, - onNext, - autoEnabled, - setAutoEnabled, -}: BasicSettingsProps) { - const handleContentTypeChange = (type: ContentType) => { - const currentTypes = [...formData.contentTypes]; - if (currentTypes.includes(type)) { - onChange({ contentTypes: currentTypes.filter(t => t !== type) }); - } else { - onChange({ contentTypes: [...currentTypes, type] }); - } - }; - - const incrementInterval = () => { - onChange({ interval: Math.min(formData.interval + 5, 60) }); - }; - - const decrementInterval = () => { - onChange({ interval: Math.max(formData.interval - 5, 5) }); - }; - - const incrementMaxLikes = () => { - onChange({ maxLikes: Math.min(formData.maxLikes + 10, 500) }); - }; - - const decrementMaxLikes = () => { - onChange({ maxLikes: Math.max(formData.maxLikes - 10, 10) }); - }; - - return ( -
-
- - onChange({ name: e.target.value })} - className="h-12 rounded-xl border-gray-200" - /> -
- -
- -
- -
- - onChange({ interval: Number.parseInt(e.target.value) || 5 }) - } - className="h-12 rounded-none border-x-0 border-gray-200 text-center" - /> -
- 秒 -
-
- -
-

设置两次点赞之间的最小时间间隔

-
- -
- -
- -
- - onChange({ maxLikes: Number.parseInt(e.target.value) || 10 }) - } - className="h-12 rounded-none border-x-0 border-gray-200 text-center" - /> -
- 次/天 -
-
- -
-

设置每天最多点赞的次数

-
- -
- -
-
- onChange({ startTime: e.target.value })} - className="h-12 rounded-xl border-gray-200" - /> -
-
- onChange({ endTime: e.target.value })} - className="h-12 rounded-xl border-gray-200" - /> -
-
-

设置每天可以点赞的时间段

-
- -
- -
- {[ - { id: "text" as ContentType, label: "文字" }, - { id: "image" as ContentType, label: "图片" }, - { id: "video" as ContentType, label: "视频" }, - ].map(type => ( -
handleContentTypeChange(type.id)} - > - {type.label} -
- ))} -
-

选择要点赞的内容类型

-
- -
-
- - onChange({ enableFriendTags: checked })} - /> -
- {formData.enableFriendTags && ( - <> -
- - onChange({ friendTags: e.target.value })} - className="h-12 rounded-xl border-gray-200" - /> -

只给有此标签的好友点赞

-
- - )} -
- -
- - -
- - -
- ); -} diff --git a/nkebao/src/pages/mobile/workspace/auto-like/new/data.ts b/nkebao/src/pages/mobile/workspace/auto-like/new/data.ts new file mode 100644 index 00000000..32201f84 --- /dev/null +++ b/nkebao/src/pages/mobile/workspace/auto-like/new/data.ts @@ -0,0 +1,125 @@ +import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; +import { FriendSelectionItem } from "@/components/FriendSelection/data"; + +// 自动点赞任务状态 +export type LikeTaskStatus = 1 | 2; // 1: 开启, 2: 关闭 + +// 内容类型 +export type ContentType = "text" | "image" | "video" | "link"; + +// 设备信息 +export interface Device { + id: string; + name: string; + status: "online" | "offline"; + lastActive: string; +} + +// 好友信息 +export interface Friend { + id: string; + nickname: string; + wechatId: string; + avatar: string; + tags: string[]; + region: string; + source: string; +} + +// 点赞记录 +export interface LikeRecord { + id: string; + workbenchId: string; + momentsId: string; + snsId: string; + wechatAccountId: string; + wechatFriendId: string; + likeTime: string; + content: string; + resUrls: string[]; + momentTime: string; + userName: string; + operatorName: string; + operatorAvatar: string; + friendName: string; + friendAvatar: string; +} + +// 自动点赞任务 +export interface LikeTask { + id: string; + name: string; + status: LikeTaskStatus; + deviceCount: number; + targetGroup: string; + likeCount: number; + lastLikeTime: string; + createTime: string; + creator: string; + likeInterval: number; + maxLikesPerDay: number; + timeRange: { start: string; end: string }; + contentTypes: ContentType[]; + targetTags: string[]; + devices: string[]; + friends: string[]; + friendMaxLikes: number; + friendTags: string; + enableFriendTags: boolean; + todayLikeCount: number; + totalLikeCount: number; + updateTime: string; +} + +// 创建任务数据 +export interface CreateLikeTaskData { + name: string; + interval: number; + maxLikes: number; + startTime: string; + endTime: string; + contentTypes: ContentType[]; + deveiceGroups: string[]; + deveiceGroupsOptions: DeviceSelectionItem[]; + friendsGroups: string[]; + friendsGroupsOptions: FriendSelectionItem[]; + friendMaxLikes: number; + friendTags?: string; + enableFriendTags: boolean; + targetTags: string[]; + [key: string]: any; +} + +// 更新任务数据 +export interface UpdateLikeTaskData extends CreateLikeTaskData { + id: string; +} + +// 任务配置 +export interface TaskConfig { + interval: number; + maxLikes: number; + startTime: string; + endTime: string; + contentTypes: ContentType[]; + devices: string[]; + friends: string[]; + friendMaxLikes: number; + friendTags: string; + enableFriendTags: boolean; +} + +// API响应类型 +export interface ApiResponse { + code: number; + msg: string; + data: T; +} + +// 分页响应类型 +export interface PaginatedResponse { + list: T[]; + total: number; + page: number; + limit: number; +} diff --git a/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx b/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx index 97873365..b7bc9ba4 100644 --- a/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx +++ b/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx @@ -12,17 +12,14 @@ import { updateAutoLikeTask, fetchAutoLikeTaskDetail, } from "./api"; -import { - CreateLikeTaskData, - ContentType, -} from "@/pages/workspace/auto-like/record/data"; +import { CreateLikeTaskData, ContentType } from "./data"; import style from "./new.module.scss"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; const contentTypeLabels: Record = { text: "文字", image: "图片", video: "视频", + link: "链接", }; const steps = [ @@ -46,8 +43,10 @@ const NewAutoLike: React.FC = () => { startTime: "08:00", endTime: "22:00", contentTypes: ["text", "image", "video"], - devices: [], - friends: [], + deveiceGroups: [], + deveiceGroupsOptions: [], + friendsGroups: [], + friendsGroupsOptions: [], targetTags: [], friendMaxLikes: 10, enableFriendTags: false, @@ -55,10 +54,10 @@ const NewAutoLike: React.FC = () => { }); useEffect(() => { - if (isEditMode && id) { + if (id) { fetchTaskDetail(); } - }, [id, isEditMode]); + }, [id]); const fetchTaskDetail = async () => { setIsLoading(true); @@ -73,8 +72,10 @@ const NewAutoLike: React.FC = () => { startTime: config.timeRange?.start || config.startTime || "08:00", endTime: config.timeRange?.end || config.endTime || "22:00", contentTypes: config.contentTypes || ["text", "image", "video"], - devices: config.devices || [], - friends: config.friends || [], + deveiceGroups: config.deveicegroups || [], + deveiceGroupsOptions: config.deveiceGroupsOptions || [], + friendsGroups: config.friendsgroups || [], + friendsGroupsOptions: config.friendsGroupsOptions || [], targetTags: config.targetTags || [], friendMaxLikes: config.friendMaxLikes || 10, enableFriendTags: config.enableFriendTags || false, @@ -120,13 +121,13 @@ const NewAutoLike: React.FC = () => { message.warning("请输入任务名称"); return; } - if (!formData.devices || formData.devices.length === 0) { + if (!formData.deveicegroups || formData.deveicegroups.length === 0) { message.warning("请选择执行设备"); return; } setIsSubmitting(true); try { - if (isEditMode && id) { + if (isEditMode) { await updateAutoLikeTask({ ...formData, id }); message.success("更新成功"); } else { @@ -328,7 +329,7 @@ const NewAutoLike: React.FC = () => {
handleUpdateFormData({ devices })} showInput={true} showSelectedList={true} @@ -347,7 +348,7 @@ const NewAutoLike: React.FC = () => { onClick={handleNext} className={style.nextBtn} size="large" - disabled={formData.devices.length === 0} + disabled={formData.deveicegroups.length === 0} > 下一步 @@ -359,9 +360,14 @@ const NewAutoLike: React.FC = () => {
handleUpdateFormData({ friends })} - deviceIds={formData.devices} + selectedOptions={formData.friendsGroupsOptions || []} + onSelect={friends => + handleUpdateFormData({ + friendsGroups: friends.map(f => String(f.id)), + friendsGroupsOptions: friends, + }) + } + deviceIds={formData.deveiceGroups} />
diff --git a/nkebao/src/pages/mobile/workspace/auto-like/record/AutoLikeDetail.tsx b/nkebao/src/pages/mobile/workspace/auto-like/record/AutoLikeDetail.tsx deleted file mode 100644 index 38b651d5..00000000 --- a/nkebao/src/pages/mobile/workspace/auto-like/record/AutoLikeDetail.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useParams } from "react-router-dom"; -import { ThumbsUp, RefreshCw, Search } from "lucide-react"; -import { Card } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Badge } from "@/components/ui/badge"; -import { Input } from "@/components/ui/input"; -import { Avatar } from "@/components/ui/avatar"; -import { Skeleton } from "@/components/ui/skeleton"; -import { Separator } from "@/components/ui/separator"; -import Layout from "@/components/Layout"; -import PageHeader from "@/components/PageHeader"; -import { useToast } from "@/components/ui/toast"; -import "@/components/Layout.css"; -import { fetchLikeRecords, LikeRecord } from "@/api/autoLike"; - -// 格式化日期 -const formatDate = (dateString: string) => { - try { - const date = new Date(dateString); - return date.toLocaleString("zh-CN", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - }); - } catch (error) { - return dateString; - } -}; - -export default function AutoLikeDetail() { - const { id } = useParams<{ id: string }>(); - const { toast } = useToast(); - const [records, setRecords] = useState([]); - const [recordsLoading, setRecordsLoading] = useState(false); - const [searchTerm, setSearchTerm] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const [total, setTotal] = useState(0); - const pageSize = 10; - - useEffect(() => { - if (!id) return; - setRecordsLoading(true); - fetchLikeRecords(id, 1, pageSize) - .then(response => { - setRecords(response.list || []); - setTotal(response.total || 0); - setCurrentPage(1); - }) - .catch(() => { - toast({ - title: "获取点赞记录失败", - description: "请稍后重试", - variant: "destructive", - }); - }) - .finally(() => setRecordsLoading(false)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [id]); - - const handleSearch = () => { - setCurrentPage(1); - fetchLikeRecords(id!, 1, pageSize, searchTerm) - .then(response => { - setRecords(response.list || []); - setTotal(response.total || 0); - setCurrentPage(1); - }) - .catch(() => { - toast({ - title: "获取点赞记录失败", - description: "请稍后重试", - variant: "destructive", - }); - }); - }; - - const handleRefresh = () => { - fetchLikeRecords(id!, currentPage, pageSize, searchTerm) - .then(response => { - setRecords(response.list || []); - setTotal(response.total || 0); - }) - .catch(() => { - toast({ - title: "获取点赞记录失败", - description: "请稍后重试", - variant: "destructive", - }); - }); - }; - - const handlePageChange = (newPage: number) => { - fetchLikeRecords(id!, newPage, pageSize, searchTerm) - .then(response => { - setRecords(response.list || []); - setTotal(response.total || 0); - setCurrentPage(newPage); - }) - .catch(() => { - toast({ - title: "获取点赞记录失败", - description: "请稍后重试", - variant: "destructive", - }); - }); - }; - - return ( - - -
-
- - setSearchTerm(e.target.value)} - onKeyDown={e => e.key === "Enter" && handleSearch()} - /> -
- -
- - } - footer={ - <> - {records.length > 0 && total > pageSize && ( -
- - - 第 {currentPage} 页,共 {Math.ceil(total / pageSize)} 页 - - -
- )} - - } - > -
-
- {recordsLoading ? ( -
- {Array.from({ length: 3 }).map((_, index) => ( - -
- -
- - -
-
- -
- - -
- - -
-
-
- ))} -
- ) : records.length === 0 ? ( -
- -

暂无点赞记录

-
- ) : ( - <> - {records.map(record => ( -
-
-
- - {record.friendName} - -
-
- {record.friendName} -
-
内容发布者
-
-
- - {formatDate(record.momentTime || record.likeTime)} - -
- -
- {record.content && ( -

- {record.content} -

- )} - {Array.isArray(record.resUrls) && - record.resUrls.length > 0 && ( -
- {record.resUrls - .slice(0, 9) - .map((image: string, idx: number) => ( -
- {`内容图片 -
- ))} -
- )} -
-
- - {record.operatorName} - -
- - {record.operatorName} - - 点赞了这条内容 -
-
-
- ))} - - )} -
-
-
- ); -}