diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx index 255842e4..e83332ad 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx @@ -1,6 +1,5 @@ -import React, { useState } from "react"; -import { Input, Button, Card, Switch } from "antd"; -import { MinusOutlined, PlusOutlined } from "@ant-design/icons"; +import React, { useImperativeHandle, forwardRef } from "react"; +import { Input, Button, Card, Switch, Form, InputNumber } from "antd"; interface BasicSettingsProps { defaultValues?: { @@ -18,194 +17,199 @@ interface BasicSettingsProps { loading?: boolean; } -const BasicSettings: React.FC = ({ - defaultValues = { - name: "", - pushTimeStart: "06:00", - pushTimeEnd: "23:59", - dailyPushCount: 20, - pushOrder: "latest", - isLoopPush: false, - isImmediatePush: false, - isEnabled: false, - }, - onNext, - onSave, - loading = false, -}) => { - const [values, setValues] = useState(defaultValues); +export interface BasicSettingsRef { + validate: () => Promise; + getValues: () => any; +} - const handleChange = (field: string, value: any) => { - setValues(prev => ({ ...prev, [field]: value })); - }; +const BasicSettings = forwardRef( + ( + { + defaultValues = { + name: "", + pushTimeStart: "06:00", + pushTimeEnd: "23:59", + dailyPushCount: 20, + pushOrder: "latest", + isLoopPush: false, + isImmediatePush: false, + isEnabled: false, + }, + }, + ref, + ) => { + const [form] = Form.useForm(); - const handleCountChange = (increment: boolean) => { - setValues(prev => ({ - ...prev, - dailyPushCount: increment - ? prev.dailyPushCount + 1 - : Math.max(1, prev.dailyPushCount - 1), + // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + validate: async () => { + try { + await form.validateFields(); + return true; + } catch (error) { + console.log("BasicSettings 表单验证失败:", error); + return false; + } + }, + getValues: () => { + return form.getFieldsValue(); + }, })); - }; - return ( -
- -
- {/* 任务名称 */} -
- *任务名称: - handleChange("name", e.target.value)} - placeholder="请输入任务名称" - style={{ marginTop: 4 }} - /> -
- {/* 允许推送的时间段 */} -
- 允许推送的时间段: -
- handleChange("pushTimeStart", e.target.value)} - style={{ width: 120 }} - /> - - handleChange("pushTimeEnd", e.target.value)} - style={{ width: 120 }} - /> -
-
- {/* 每日推送 */} -
- 每日推送: -
+ +
{ + // 可以在这里处理表单值变化 + }} + > + {/* 任务名称 */} + -
-
- {/* 推送顺序 */} -
- 推送顺序: -
- - -
-
- {/* 是否循环推送 */} -
- 是否循环推送: - handleChange("isLoopPush", checked)} - disabled={loading} - /> -
- {/* 是否立即推送 */} -
- 是否立即推送: - handleChange("isImmediatePush", checked)} - disabled={loading} - /> -
- {values.isImmediatePush && ( -
+ + {/* 推送顺序 */} + - 如果启用,系统会把内容库里所有的内容按顺序推送到指定的社群 -
- )} - {/* 是否启用 */} -
- 是否启用: - handleChange("isEnabled", checked)} - disabled={loading} - /> -
-
-
-
- ); -}; +
+ + +
+ + + {/* 是否循环推送 */} + + + + + {/* 是否立即推送 */} + + + + + {/* 是否启用 */} + + + + + {/* 立即推送提示 */} + + {() => { + const isImmediatePush = form.getFieldValue("isImmediatePush"); + return isImmediatePush ? ( +
+ 如果启用,系统会把内容库里所有的内容按顺序推送到指定的社群 +
+ ) : null; + }} +
+ + + + ); + }, +); + +BasicSettings.displayName = "BasicSettings"; export default BasicSettings; diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx index 1c6f7634..e96c6e14 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx @@ -1,4 +1,5 @@ -import React, { useState } from "react"; +import React, { useImperativeHandle, forwardRef } from "react"; +import { Form, Card } from "antd"; import ContentLibrarySelection from "@/components/ContentLibrarySelection"; interface ContentLibrary { @@ -19,60 +20,116 @@ interface ContentSelectorProps { loading?: boolean; } -const ContentSelector: React.FC = ({ - selectedLibraries, - onLibrariesChange, - onPrevious, - onNext, - onSave, - loading = false, -}) => { - // 将 ContentLibrary[] 转换为 string[] 用于 ContentLibrarySelection - const selectedLibraryIds = selectedLibraries.map(lib => lib.id); +export interface ContentSelectorRef { + validate: () => Promise; + getValues: () => any; +} - // 处理选择变化 - const handleLibrariesChange = (libraryIds: string[]) => { - // 这里需要根据选中的ID重新构建ContentLibrary对象 - // 由于ContentLibrarySelection只返回ID,我们需要从原始数据中获取完整信息 - // 暂时使用简化的处理方式 - const newSelectedLibraries = libraryIds.map(id => ({ - id, - name: `内容库 ${id}`, // 这里应该从API获取完整信息 - targets: [], // 这里应该从API获取完整信息 +const ContentSelector = forwardRef( + ( + { + selectedLibraries, + onLibrariesChange, + onPrevious, + onNext, + onSave, + loading = false, + }, + ref, + ) => { + const [form] = Form.useForm(); + + // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + validate: async () => { + try { + await form.validateFields(); + return true; + } catch (error) { + console.log("ContentSelector 表单验证失败:", error); + return false; + } + }, + getValues: () => { + return form.getFieldsValue(); + }, })); - onLibrariesChange(newSelectedLibraries); - }; - // 处理选择详情变化 - const handleSelectDetail = (libraries: any[]) => { - // 将API返回的数据转换为ContentLibrary格式 - const convertedLibraries = libraries.map(lib => ({ - id: lib.id, - name: lib.name, - targets: [], // 这里需要根据实际情况获取targets数据 - })); - onLibrariesChange(convertedLibraries); - }; + // 将 ContentLibrary[] 转换为 string[] 用于 ContentLibrarySelection + const selectedLibraryIds = selectedLibraries.map(lib => lib.id); - return ( -
-
-
- 选择内容库: -
- + // 处理选择变化 + const handleLibrariesChange = (libraryIds: string[]) => { + // 这里需要根据选中的ID重新构建ContentLibrary对象 + // 由于ContentLibrarySelection只返回ID,我们需要从原始数据中获取完整信息 + // 暂时使用简化的处理方式 + const newSelectedLibraries = libraryIds.map(id => ({ + id, + name: `内容库 ${id}`, // 这里应该从API获取完整信息 + targets: [], // 这里应该从API获取完整信息 + })); + onLibrariesChange(newSelectedLibraries); + form.setFieldValue("contentLibraries", libraryIds); + }; + + // 处理选择详情变化 + const handleSelectDetail = (libraries: any[]) => { + // 将API返回的数据转换为ContentLibrary格式 + const convertedLibraries = libraries.map(lib => ({ + id: lib.id, + name: lib.name, + targets: [], // 这里需要根据实际情况获取targets数据 + })); + onLibrariesChange(convertedLibraries); + form.setFieldValue( + "contentLibraries", + libraries.map(lib => lib.id), + ); + }; + + return ( +
+ +
+
+

+ 选择内容库 +

+

+ 请选择要推送的内容库 +

+
+ + + + +
+
-
- ); -}; + ); + }, +); + +ContentSelector.displayName = "ContentSelector"; export default ContentSelector; diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx index b77cecaf..f744295e 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx @@ -1,59 +1,95 @@ -import React, { useState } from "react"; +import React, { useImperativeHandle, forwardRef } from "react"; +import { Form, Card } from "antd"; import GroupSelection from "@/components/GroupSelection"; import { GroupSelectionItem } from "@/components/GroupSelection/data"; interface GroupSelectorProps { - selectedGroups: string[]; - onGroupsChange: (groups: string[]) => void; + selectedGroups: GroupSelectionItem[]; onPrevious: () => void; - onNext: () => void; - onSave: () => void; - loading?: boolean; + onNext: (data: { + wechatGroups: string[]; + wechatGroupsOptions: GroupSelectionItem[]; + }) => void; } -const GroupSelector: React.FC = ({ - selectedGroups, - onGroupsChange, - onPrevious, - onNext, - onSave, - loading = false, -}) => { - // 将string[]转换为GroupSelectionItem[] - const selectedGroupItems: GroupSelectionItem[] = selectedGroups.map(id => ({ - id, - name: `群组 ${id}`, - avatar: "", - chatroomId: id, - })); +export interface GroupSelectorRef { + validate: () => Promise; + getValues: () => any; +} - const handleGroupSelect = (groupItems: GroupSelectionItem[]) => { - // 将GroupSelectionItem[]转换回string[] - const groupIds = groupItems.map(item => item.id); - onGroupsChange(groupIds); - }; +const GroupSelector = forwardRef( + ({ selectedGroups, onNext }, ref) => { + const [form] = Form.useForm(); - return ( -
-
-

- 选择推送群组 -

-

- 请选择要推送消息的微信群组 -

-
+ // 暴露方法给父组件 + useImperativeHandle(ref, () => ({ + validate: async () => { + try { + form.setFieldsValue({ + wechatGroups: selectedGroups.map(item => item.id), + }); + await form.validateFields(); + return true; + } catch (error) { + console.log("GroupSelector 表单验证失败:", error); + return false; + } + }, + getValues: () => { + return form.getFieldsValue(); + }, + })); - -
- ); -}; + // 群组选择 + const handleGroupSelect = (wechatGroupsOptions: GroupSelectionItem[]) => { + const wechatGroups = wechatGroupsOptions.map(item => item.id); + form.setFieldValue("wechatGroups", wechatGroups); + onNext({ wechatGroups, wechatGroupsOptions }); + }; + + return ( + +
+
+

+ 选择推送群组 +

+

+ 请选择要推送消息的微信群组 +

+
+ + + + +
+
+ ); + }, +); + +GroupSelector.displayName = "GroupSelector"; export default GroupSelector; diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/index.data.ts b/nkebao/src/pages/mobile/workspace/group-push/form/index.data.ts index 1604aef2..8d7e81a3 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/index.data.ts +++ b/nkebao/src/pages/mobile/workspace/group-push/form/index.data.ts @@ -27,6 +27,7 @@ export interface FormData { isLoopPush: boolean; isImmediatePush: boolean; isEnabled: boolean; - groups: WechatGroup[]; contentLibraries: ContentLibrary[]; + wechatGroups: string[]; + [key: string]: any; } diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/index.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/index.tsx index 71d3b2ae..158574b6 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/index.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/index.tsx @@ -1,14 +1,17 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { Button } from "antd"; import { createGroupPushTask } from "./index.api"; import Layout from "@/components/Layout/Layout"; import StepIndicator from "@/components/StepIndicator"; -import BasicSettings from "./components/BasicSettings"; -import GroupSelector from "./components/GroupSelector"; -import ContentSelector from "./components/ContentSelector"; +import BasicSettings, { BasicSettingsRef } from "./components/BasicSettings"; +import GroupSelector, { GroupSelectorRef } from "./components/GroupSelector"; +import ContentSelector, { + ContentSelectorRef, +} from "./components/ContentSelector"; import type { ContentLibrary, FormData } from "./index.data"; import NavCommon from "@/components/NavCommon"; +import { GroupSelectionItem } from "@/components/GroupSelection/data"; const steps = [ { id: 1, title: "步骤 1", subtitle: "基础设置" }, { id: 2, title: "步骤 2", subtitle: "选择社群" }, @@ -21,6 +24,9 @@ const NewGroupPush: React.FC = () => { const navigate = useNavigate(); const [currentStep, setCurrentStep] = useState(1); const [loading, setLoading] = useState(false); + const [wechatGroupsOptions, setWechatGroupsOptions] = useState< + GroupSelectionItem[] + >([]); const [formData, setFormData] = useState({ name: "", pushTimeStart: "06:00", @@ -30,11 +36,16 @@ const NewGroupPush: React.FC = () => { isLoopPush: false, isImmediatePush: false, isEnabled: false, - groups: [], + wechatGroups: [], contentLibraries: [], }); const [isEditMode, setIsEditMode] = useState(false); + // 创建子组件的ref + const basicSettingsRef = useRef(null); + const groupSelectorRef = useRef(null); + const contentSelectorRef = useRef(null); + useEffect(() => { if (!id) return; setIsEditMode(true); @@ -44,19 +55,16 @@ const NewGroupPush: React.FC = () => { setFormData(prev => ({ ...prev, ...values })); }; - const handleGroupsChange = (groups: string[]) => { - // 将string[]转换为WechatGroup[] - const convertedGroups = groups.map(id => ({ - id, - name: `群组 ${id}`, - avatar: "", - serviceAccount: { - id: "", - name: "", - avatar: "", - }, + //群组选择 + const handleGroupsChange = (data: { + wechatGroups: string[]; + wechatGroupsOptions: GroupSelectionItem[]; + }) => { + setFormData(prev => ({ + ...prev, + wechatGroups: data.wechatGroups, })); - setFormData(prev => ({ ...prev, groups: convertedGroups })); + setWechatGroupsOptions(data.wechatGroupsOptions); }; const handleLibrariesChange = (contentLibraries: ContentLibrary[]) => { @@ -119,64 +127,66 @@ const NewGroupPush: React.FC = () => { } }; - const handleNext = () => { + const handleNext = async () => { if (currentStep < 4) { - setCurrentStep(currentStep + 1); - } - }; + try { + let isValid = false; - const canGoNext = () => { - switch (currentStep) { - case 1: { - return formData.name.trim() !== ""; + switch (currentStep) { + case 1: + // 调用 BasicSettings 的表单校验 + isValid = (await basicSettingsRef.current?.validate()) || false; + if (isValid) { + const values = basicSettingsRef.current?.getValues(); + if (values) { + handleBasicSettingsChange(values); + } + setCurrentStep(2); + } + break; + + case 2: + // 调用 GroupSelector 的表单校验 + isValid = (await groupSelectorRef.current?.validate()) || false; + if (isValid) { + setCurrentStep(3); + } + break; + + case 3: + // 调用 ContentSelector 的表单校验 + isValid = (await contentSelectorRef.current?.validate()) || false; + if (isValid) { + setCurrentStep(4); + } + break; + + default: + setCurrentStep(currentStep + 1); + } + } catch (error) { + console.log("表单验证失败:", error); } - case 2: { - // 选择社群:检查是否选择了群组 - const groupsValid = - formData.groups.length > 0 && formData.groups.length <= 50; // 添加上限检查 - return groupsValid; - } - case 3: { - // 选择内容库:检查是否选择了内容库 - const librariesValid = - formData.contentLibraries.length > 0 && - formData.contentLibraries.length <= 20; // 添加上限检查 - return librariesValid; - } - case 4: { - // 京东联盟:可以进入下一步(保存) - // 这里可以添加京东联盟相关的验证逻辑 - return true; - } - default: - return false; } }; const renderFooter = () => { - if (currentStep === 4) { - return ( -
- - -
- ); - } - return (
{currentStep > 1 && ( - )} - + {currentStep === 4 ? ( + + ) : ( + + )}
); }; @@ -186,11 +196,14 @@ const NewGroupPush: React.FC = () => { header={} footer={renderFooter()} > -
- -
+
+
+ +
+
{currentStep === 1 && ( { )} {currentStep === 2 && ( g.id)} - onGroupsChange={handleGroupsChange} + ref={groupSelectorRef} + selectedGroups={wechatGroupsOptions} onPrevious={() => setCurrentStep(1)} - onNext={() => setCurrentStep(3)} - onSave={handleSave} - loading={loading} + onNext={handleGroupsChange} /> )} {currentStep === 3 && ( setCurrentStep(2)}