diff --git a/nkebao/src/pages/workspace/auto-like/new/api.ts b/nkebao/src/pages/workspace/auto-like/new/api.ts new file mode 100644 index 00000000..6ca2944c --- /dev/null +++ b/nkebao/src/pages/workspace/auto-like/new/api.ts @@ -0,0 +1,21 @@ +import request from "@/api/request"; +import { + CreateLikeTaskData, + UpdateLikeTaskData, + LikeTask, +} from "@/types/auto-like"; + +// 获取自动点赞任务详情 +export function fetchAutoLikeTaskDetail(id: string): Promise { + return request("/v1/workbench/detail", { id }, "GET"); +} + +// 创建自动点赞任务 +export function createAutoLikeTask(data: CreateLikeTaskData): Promise { + return request("/v1/workbench/create", { ...data, type: 1 }, "POST"); +} + +// 更新自动点赞任务 +export function updateAutoLikeTask(data: UpdateLikeTaskData): Promise { + return request("/v1/workbench/update", { ...data, type: 1 }, "POST"); +} diff --git a/nkebao/src/pages/workspace/auto-like/new/index.tsx b/nkebao/src/pages/workspace/auto-like/new/index.tsx index bd6c9d5e..24fa60e1 100644 --- a/nkebao/src/pages/workspace/auto-like/new/index.tsx +++ b/nkebao/src/pages/workspace/auto-like/new/index.tsx @@ -1,36 +1,16 @@ import React, { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { - NavBar, - Button, - Toast, - SpinLoading, - Form, - Input, - Switch, - Stepper, - Card, - Tag, -} from "antd-mobile"; -import { Input as AntInput, TimePicker, Select } from "antd"; import { PlusOutlined, MinusOutlined, - CheckOutlined, - TagOutlined, - ClockCircleOutlined, - LikeOutlined, - UserOutlined, - SettingOutlined, + ArrowLeftOutlined, } from "@ant-design/icons"; - -import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; +import { Button, Input, Switch, message, Spin } from "antd"; import { createAutoLikeTask, updateAutoLikeTask, fetchAutoLikeTaskDetail, -} from "@/api/autoLike"; +} from "./api"; import { CreateLikeTaskData, UpdateLikeTaskData, @@ -38,7 +18,12 @@ import { } from "@/types/auto-like"; import style from "./new.module.scss"; -const { Option } = Select; +const contentTypeLabels: Record = { + text: "文字", + image: "图片", + video: "视频", + link: "链接", +}; const NewAutoLike: React.FC = () => { const navigate = useNavigate(); @@ -48,7 +33,6 @@ const NewAutoLike: React.FC = () => { const [isSubmitting, setIsSubmitting] = useState(false); const [isLoading, setIsLoading] = useState(isEditMode); const [autoEnabled, setAutoEnabled] = useState(false); - const [formData, setFormData] = useState({ name: "", interval: 5, @@ -64,21 +48,18 @@ const NewAutoLike: React.FC = () => { friendTags: "", }); - // 如果是编辑模式,获取任务详情 useEffect(() => { if (isEditMode && id) { fetchTaskDetail(); } }, [id, isEditMode]); - // 获取任务详情 const fetchTaskDetail = async () => { + setIsLoading(true); try { const taskDetail = await fetchAutoLikeTaskDetail(id!); if (taskDetail) { - const taskAny = taskDetail as any; - const config = taskAny.config || taskAny; - + const config = (taskDetail as any).config || taskDetail; setFormData({ name: taskDetail.name || "", interval: config.likeInterval || config.interval || 5, @@ -93,15 +74,14 @@ const NewAutoLike: React.FC = () => { enableFriendTags: config.enableFriendTags || false, friendTags: config.friendTags || "", }); - - const status = taskAny.status; - setAutoEnabled(status === 1 || status === "running"); + setAutoEnabled( + (taskDetail as any).status === 1 || + (taskDetail as any).status === "running" + ); } } catch (error) { - Toast.show({ - content: "获取任务详情失败", - position: "top", - }); + message.error("获取任务详情失败"); + navigate("/workspace/auto-like"); } finally { setIsLoading(false); } @@ -111,326 +91,246 @@ const NewAutoLike: React.FC = () => { setFormData((prev) => ({ ...prev, ...data })); }; - const handleNext = () => { - if (currentStep < 3) { - setCurrentStep(currentStep + 1); - } - }; - - const handlePrev = () => { - if (currentStep > 1) { - setCurrentStep(currentStep - 1); - } - }; + const handleNext = () => setCurrentStep((prev) => Math.min(prev + 1, 3)); + const handlePrev = () => setCurrentStep((prev) => Math.max(prev - 1, 1)); const handleComplete = async () => { if (!formData.name.trim()) { - Toast.show({ - content: "请输入任务名称", - position: "top", - }); + message.warning("请输入任务名称"); return; } - - if (formData.devices.length === 0) { - Toast.show({ - content: "请选择执行设备", - position: "top", - }); + if (!formData.devices || formData.devices.length === 0) { + message.warning("请选择执行设备"); return; } - setIsSubmitting(true); try { if (isEditMode && id) { - const updateData: UpdateLikeTaskData = { - ...formData, - id, - }; - await updateAutoLikeTask(updateData); - Toast.show({ - content: "更新成功", - position: "top", - }); + await updateAutoLikeTask({ ...formData, id }); + message.success("更新成功"); } else { await createAutoLikeTask(formData); - Toast.show({ - content: "创建成功", - position: "top", - }); + message.success("创建成功"); } navigate("/workspace/auto-like"); } catch (error) { - Toast.show({ - content: isEditMode ? "更新失败" : "创建失败", - position: "top", - }); + message.error(isEditMode ? "更新失败" : "创建失败"); } finally { setIsSubmitting(false); } }; - const handleContentTypeChange = (type: ContentType) => { - const newTypes = formData.contentTypes.includes(type) - ? formData.contentTypes.filter((t) => t !== type) - : [...formData.contentTypes, type]; - handleUpdateFormData({ contentTypes: newTypes }); - }; + // 顶部导航栏 + const renderNavBar = () => ( +
+
+ ); - const renderStepIndicator = () => ( -
-
-
= 1 ? style["active"] : ""}`} - > -
1
-
基础设置
+ // 步骤1:基础设置 + const renderBasicSettings = () => ( +
+
+ + handleUpdateFormData({ name: e.target.value })} + className={style["form-input"]} + /> +
+
+ +
+
-
= 2 ? style["active"] : ""}`} - > -
2
-
设备选择
+
+
+ +
+
-
= 3 ? style["active"] : ""}`} - > -
3
-
好友设置
+
+
+ +
+ + handleUpdateFormData({ startTime: e.target.value }) + } + className={style["time-input"]} + /> + + handleUpdateFormData({ endTime: e.target.value })} + className={style["time-input"]} + />
+
+ +
+ {(["text", "image", "video", "link"] as ContentType[]).map((type) => ( + { + const newTypes = formData.contentTypes.includes(type) + ? formData.contentTypes.filter((t) => t !== type) + : [...formData.contentTypes, type]; + handleUpdateFormData({ contentTypes: newTypes }); + }} + > + {contentTypeLabels[type]} + + ))} +
+
+
+ + +
+
+ +
); - const renderBasicSettings = () => ( -
- -
- - handleUpdateFormData({ name: value })} - className={style["form-input"]} - /> -
- -
- -
- - - {formData.interval} 秒 - - -
-
- -
- -
- - - {formData.maxLikes} 次 - - -
-
- -
- -
- handleUpdateFormData({ startTime: value })} - className={style["time-input"]} - /> - - handleUpdateFormData({ endTime: value })} - className={style["time-input"]} - /> -
-
- -
- -
- {(["text", "image", "video", "link"] as ContentType[]).map( - (type) => ( - handleContentTypeChange(type)} - className={style["content-type-tag"]} - > - {type === "text" && "文字"} - {type === "image" && "图片"} - {type === "video" && "视频"} - {type === "link" && "链接"} - - ) - )} -
-
- -
- - -
-
-
- ); - + // 步骤2:设备选择(占位) const renderDeviceSelection = () => ( -
- -
- -
设备选择功能开发中...
-
- 当前已选择 {formData.devices.length} 个设备 -
+
+
+ [设备选择组件占位] +
设备选择功能开发中...
+
+ 当前已选择 {formData.devices?.length || 0} 个设备
- +
+
+ + +
); + // 步骤3:好友设置(占位) const renderFriendSettings = () => ( -
- -
- -
好友设置功能开发中...
-
- 当前已选择 {formData.friends.length} 个好友 -
+
+
+ [好友选择组件占位] +
好友设置功能开发中...
+
+ 当前已选择 {formData.friends?.length || 0} 个好友
- +
+
+ + +
); - if (isLoading) { - return ( - window.history.back()} - left={ -
- {isEditMode ? "编辑任务" : "新建任务"} -
- } - /> - } - footer={} - > -
- -
加载中...
-
-
- ); - } - return ( - window.history.back()} - left={ -
- {isEditMode ? "编辑任务" : "新建任务"} +
+ {renderNavBar()} +
+ {/* 步骤器保留新项目的 */} + {/* 你可以在这里插入新项目的步骤器组件 */} +
+ {currentStep === 1 && renderBasicSettings()} + {currentStep === 2 && renderDeviceSelection()} + {currentStep === 3 && renderFriendSettings()} + {isLoading && ( +
+
- } - /> - } - footer={} - > -
- {renderStepIndicator()} - - {currentStep === 1 && renderBasicSettings()} - {currentStep === 2 && renderDeviceSelection()} - {currentStep === 3 && renderFriendSettings()} - -
- {currentStep > 1 && ( - - )} - - {currentStep < 3 ? ( - - ) : ( - )}
- +
); }; diff --git a/nkebao/src/pages/workspace/auto-like/new/new.module.scss b/nkebao/src/pages/workspace/auto-like/new/new.module.scss index 5b25188e..adb3aa67 100644 --- a/nkebao/src/pages/workspace/auto-like/new/new.module.scss +++ b/nkebao/src/pages/workspace/auto-like/new/new.module.scss @@ -1,144 +1,118 @@ -.new-page { - background: #f5f5f5; +.new-page-bg { min-height: 100vh; - padding-bottom: 80px; + background: #f8f9fa; } -.step-indicator { - background: white; - padding: 20px 16px; - border-bottom: 1px solid #f0f0f0; -} - -.step-list { +.nav-bar { display: flex; - justify-content: space-between; align-items: center; - position: relative; - - &::before { - content: ''; - position: absolute; - top: 20px; - left: 20px; - right: 20px; - height: 2px; - background: #e5e5e5; - z-index: 1; - } + height: 56px; + background: #fff; + box-shadow: 0 1px 0 #f0f0f0; + padding: 0 24px; + position: sticky; + top: 0; + z-index: 10; } -.step-item { - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; - position: relative; - z-index: 2; - - &.active { - .step-number { - background: #1890ff; - color: white; - border-color: #1890ff; - } - - .step-label { - color: #1890ff; - font-weight: 600; - } - } -} - -.step-number { - width: 40px; - height: 40px; - border-radius: 50%; - background: white; - border: 2px solid #e5e5e5; +.nav-back-btn { + border: none; + background: none; + font-size: 20px; + color: #222; + margin-right: 8px; + box-shadow: none; + padding: 0; + min-width: 32px; + min-height: 32px; display: flex; align-items: center; justify-content: center; - font-size: 16px; +} + +.nav-title { + font-size: 18px; font-weight: 600; - color: #999; - transition: all 0.3s; + color: #222; + margin-left: 4px; } -.step-label { - font-size: 12px; - color: #666; - text-align: center; - transition: all 0.3s; -} - -.step-content { - padding: 16px; +.new-page-center { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 32px; } .form-card { - background: white; - border-radius: 8px; - padding: 20px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + background: #fff; + border-radius: 18px; + box-shadow: 0 2px 16px rgba(0,0,0,0.06); + padding: 36px 32px 32px 32px; + min-width: 340px; + max-width: 420px; + width: 100%; +} + +.form-section { + width: 100%; } .form-item { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } + margin-bottom: 28px; + display: flex; + flex-direction: column; } .form-label { - display: block; - font-size: 14px; - font-weight: 600; + font-size: 15px; + font-weight: 500; color: #333; margin-bottom: 8px; } .form-input { - width: 100%; - height: 40px; - border: 1px solid #d9d9d9; - border-radius: 6px; - padding: 0 12px; - font-size: 14px; - - &:focus { - border-color: #1890ff; - box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); - outline: none; - } + border-radius: 10px !important; + height: 44px; + font-size: 15px; + padding-left: 14px; + background: #f8f9fa; + border: 1px solid #e5e6eb; + transition: border 0.2s; } -.stepper-wrapper { +.form-input:focus { + border-color: #1890ff; + background: #fff; +} + +.stepper-group { display: flex; align-items: center; gap: 12px; } .stepper-btn { - width: 32px; - height: 32px; - padding: 0; - border-radius: 6px; + border-radius: 8px !important; + width: 36px; + height: 36px; + font-size: 18px; + background: #f5f6fa; + border: 1px solid #e5e6eb; + color: #222; display: flex; align-items: center; justify-content: center; - border: 1px solid #d9d9d9; - background: white; - - &:hover { - border-color: #1890ff; - color: #1890ff; - } + transition: border 0.2s; +} + +.stepper-btn:hover { + border-color: #1890ff; + color: #1890ff; } .stepper-value { - font-size: 14px; + font-size: 15px; font-weight: 600; color: #333; min-width: 60px; @@ -148,65 +122,108 @@ .time-range { display: flex; align-items: center; - gap: 12px; + gap: 10px; } .time-input { - flex: 1; - height: 40px; - border: 1px solid #d9d9d9; - border-radius: 6px; - padding: 0 12px; - font-size: 14px; - - &:focus { - border-color: #1890ff; - box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); - outline: none; - } + border-radius: 10px !important; + height: 44px; + font-size: 15px; + padding-left: 14px; + background: #f8f9fa; + border: 1px solid #e5e6eb; + width: 120px; } .time-separator { - font-size: 14px; - color: #666; + font-size: 15px; + color: #888; font-weight: 500; } .content-types { display: flex; + gap: 10px; flex-wrap: wrap; - gap: 8px; } .content-type-tag { + border-radius: 8px; + background: #f5f6fa; + color: #666; + font-size: 14px; + padding: 6px 18px; cursor: pointer; + border: 1px solid #e5e6eb; transition: all 0.2s; - - &:hover { - transform: translateY(-1px); - } } -.form-switch { - margin-left: auto; +.content-type-tag-active { + border-radius: 8px; + background: #e6f4ff; + color: #1890ff; + font-size: 14px; + padding: 6px 18px; + cursor: pointer; + border: 1px solid #1890ff; + font-weight: 600; + transition: all 0.2s; +} + +.form-actions { + display: flex; + gap: 16px; + margin-top: 12px; +} + +.main-btn { + border-radius: 10px !important; + height: 44px; + font-size: 16px; + font-weight: 600; + background: #1890ff; + border: none; + box-shadow: 0 2px 8px rgba(24,144,255,0.08); + transition: background 0.2s; +} + +.main-btn:hover { + background: #1677ff; +} + +.secondary-btn { + border-radius: 10px !important; + height: 44px; + font-size: 16px; + font-weight: 600; + background: #fff; + border: 1.5px solid #e5e6eb; + color: #222; + transition: border 0.2s; +} + +.secondary-btn:hover { + border-color: #1890ff; + color: #1890ff; } .placeholder-content { text-align: center; - padding: 40px 20px; - color: #666; + color: #888; + padding: 40px 0 24px 0; } .placeholder-icon { - font-size: 48px; + font-size: 32px; color: #d9d9d9; - margin-bottom: 16px; + margin-bottom: 12px; + display: block; } .placeholder-text { font-size: 16px; - margin-bottom: 8px; color: #333; + margin-bottom: 6px; } .placeholder-subtext { @@ -214,88 +231,20 @@ color: #999; } -.step-actions { - position: fixed; - bottom: 0; - left: 0; - right: 0; - background: white; - padding: 16px; - border-top: 1px solid #f0f0f0; - display: flex; - gap: 12px; - z-index: 10; -} - -.prev-btn { - flex: 1; - height: 44px; - border-radius: 8px; - font-size: 16px; - font-weight: 500; -} - -.next-btn, -.complete-btn { - flex: 1; - height: 44px; - border-radius: 8px; - font-size: 16px; - font-weight: 500; -} - .loading { display: flex; - flex-direction: column; align-items: center; justify-content: center; - height: 60vh; - gap: 16px; + min-height: 120px; } -.loading-text { - color: #666; - font-size: 14px; -} - -// 移动端适配 -@media (max-width: 768px) { - .step-list { - &::before { - left: 15px; - right: 15px; - } - } - - .step-number { - width: 36px; - height: 36px; - font-size: 14px; - } - - .step-label { - font-size: 11px; - } - +@media (max-width: 600px) { .form-card { - padding: 16px; + min-width: 0; + max-width: 100vw; + padding: 18px 6px 18px 6px; } - - .stepper-wrapper { - gap: 8px; - } - - .stepper-btn { - width: 28px; - height: 28px; - } - - .time-range { - flex-direction: column; - gap: 8px; - } - - .content-types { - gap: 6px; + .new-page-center { + margin-top: 12px; } } \ No newline at end of file