FEAT => 本次更新项目为:

选择社群构建完成
This commit is contained in:
超级老白兔
2025-08-07 17:43:20 +08:00
parent 67c76d8b04
commit 504e8ff9b6
5 changed files with 463 additions and 353 deletions

View File

@@ -1,6 +1,5 @@
import React, { useState } from "react"; import React, { useImperativeHandle, forwardRef } from "react";
import { Input, Button, Card, Switch } from "antd"; import { Input, Button, Card, Switch, Form, InputNumber } from "antd";
import { MinusOutlined, PlusOutlined } from "@ant-design/icons";
interface BasicSettingsProps { interface BasicSettingsProps {
defaultValues?: { defaultValues?: {
@@ -18,194 +17,199 @@ interface BasicSettingsProps {
loading?: boolean; loading?: boolean;
} }
const BasicSettings: React.FC<BasicSettingsProps> = ({ export interface BasicSettingsRef {
defaultValues = { validate: () => Promise<boolean>;
name: "", getValues: () => any;
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);
const handleChange = (field: string, value: any) => { const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
setValues(prev => ({ ...prev, [field]: value })); (
}; {
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 => ({ useImperativeHandle(ref, () => ({
...prev, validate: async () => {
dailyPushCount: increment try {
? prev.dailyPushCount + 1 await form.validateFields();
: Math.max(1, prev.dailyPushCount - 1), return true;
} catch (error) {
console.log("BasicSettings 表单验证失败:", error);
return false;
}
},
getValues: () => {
return form.getFieldsValue();
},
})); }));
};
return ( return (
<div style={{ marginBottom: 24 }}> <div style={{ marginBottom: 24 }}>
<Card> <Card>
<div> <Form
{/* 任务名称 */} form={form}
<div style={{ marginBottom: 16 }}> layout="vertical"
<span style={{ color: "red", marginRight: 4 }}>*</span>: initialValues={defaultValues}
<Input onValuesChange={(changedValues, allValues) => {
value={values.name} // 可以在这里处理表单值变化
onChange={e => handleChange("name", e.target.value)} }}
placeholder="请输入任务名称" >
style={{ marginTop: 4 }} {/* 任务名称 */}
/> <Form.Item
</div> label="任务名称"
{/* 允许推送的时间段 */} name="name"
<div style={{ marginBottom: 16 }}> rules={[
<span>:</span> { required: true, message: "请输入任务名称" },
<div style={{ display: "flex", gap: 8, marginTop: 4 }}> { min: 2, max: 50, message: "任务名称长度在2-50个字符之间" },
<Input ]}
type="time"
value={values.pushTimeStart}
onChange={e => handleChange("pushTimeStart", e.target.value)}
style={{ width: 120 }}
/>
<span style={{ color: "#888" }}></span>
<Input
type="time"
value={values.pushTimeEnd}
onChange={e => handleChange("pushTimeEnd", e.target.value)}
style={{ width: 120 }}
/>
</div>
</div>
{/* 每日推送 */}
<div style={{ marginBottom: 16 }}>
<span>:</span>
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
marginTop: 4,
}}
> >
<Button <Input placeholder="请输入任务名称" />
icon={<MinusOutlined />} </Form.Item>
onClick={() => handleCountChange(false)}
disabled={loading} {/* 允许推送的时间段 */}
/> <Form.Item label="允许推送的时间段">
<Input <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
type="number" <Form.Item
value={values.dailyPushCount} name="pushTimeStart"
onChange={e => noStyle
handleChange( rules={[{ required: true, message: "请选择开始时间" }]}
"dailyPushCount", >
Number.parseInt(e.target.value) || 1, <Input type="time" style={{ width: 120 }} />
) </Form.Item>
} <span style={{ color: "#888" }}></span>
style={{ width: 80, textAlign: "center" }} <Form.Item
name="pushTimeEnd"
noStyle
rules={[{ required: true, message: "请选择结束时间" }]}
>
<Input type="time" style={{ width: 120 }} />
</Form.Item>
</div>
</Form.Item>
{/* 每日推送 */}
<Form.Item
label="每日推送"
name="dailyPushCount"
rules={[
{ required: true, message: "请输入每日推送数量" },
{
type: "number",
min: 1,
max: 100,
message: "每日推送数量在1-100之间",
},
]}
>
<InputNumber
min={1} min={1}
disabled={loading} max={100}
style={{ width: 120 }}
addonAfter="条内容"
/> />
<Button </Form.Item>
icon={<PlusOutlined />}
onClick={() => handleCountChange(true)} {/* 推送顺序 */}
disabled={loading} <Form.Item
/> label="推送顺序"
<span style={{ color: "#888" }}></span> name="pushOrder"
</div> rules={[{ required: true, message: "请选择推送顺序" }]}
</div>
{/* 推送顺序 */}
<div style={{ marginBottom: 16 }}>
<span>:</span>
<div style={{ display: "flex" }}>
<Button
type={values.pushOrder === "earliest" ? "primary" : "default"}
onClick={() => handleChange("pushOrder", "earliest")}
disabled={loading}
style={{ borderRadius: "6px 0 0 6px" }}
>
</Button>
<Button
type={values.pushOrder === "latest" ? "primary" : "default"}
onClick={() => handleChange("pushOrder", "latest")}
disabled={loading}
style={{ borderRadius: "0 6px 6px 0", marginLeft: -1 }}
>
</Button>
</div>
</div>
{/* 是否循环推送 */}
<div
style={{
marginBottom: 16,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<span>:</span>
<Switch
checked={values.isLoopPush}
onChange={checked => handleChange("isLoopPush", checked)}
disabled={loading}
/>
</div>
{/* 是否立即推送 */}
<div
style={{
marginBottom: 16,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<span>:</span>
<Switch
checked={values.isImmediatePush}
onChange={checked => handleChange("isImmediatePush", checked)}
disabled={loading}
/>
</div>
{values.isImmediatePush && (
<div
style={{
background: "#fffbe6",
border: "1px solid #ffe58f",
borderRadius: 4,
padding: 8,
color: "#ad8b00",
marginBottom: 16,
}}
> >
<div style={{ display: "flex" }}>
</div> <Button
)} type="default"
{/* 是否启用 */} style={{ borderRadius: "6px 0 0 6px" }}
<div onClick={() => form.setFieldValue("pushOrder", "earliest")}
style={{ className={
marginBottom: 16, form.getFieldValue("pushOrder") === "earliest"
display: "flex", ? "ant-btn-primary"
alignItems: "center", : ""
justifyContent: "space-between", }
}} >
>
<span>:</span> </Button>
<Switch <Button
checked={values.isEnabled} type="default"
onChange={checked => handleChange("isEnabled", checked)} style={{ borderRadius: "0 6px 6px 0", marginLeft: -1 }}
disabled={loading} onClick={() => form.setFieldValue("pushOrder", "latest")}
/> className={
</div> form.getFieldValue("pushOrder") === "latest"
</div> ? "ant-btn-primary"
</Card> : ""
</div> }
); >
};
</Button>
</div>
</Form.Item>
{/* 是否循环推送 */}
<Form.Item
label="是否循环推送"
name="isLoopPush"
valuePropName="checked"
>
<Switch />
</Form.Item>
{/* 是否立即推送 */}
<Form.Item
label="是否立即推送"
name="isImmediatePush"
valuePropName="checked"
>
<Switch />
</Form.Item>
{/* 是否启用 */}
<Form.Item
label="是否启用"
name="isEnabled"
valuePropName="checked"
>
<Switch />
</Form.Item>
{/* 立即推送提示 */}
<Form.Item noStyle shouldUpdate>
{() => {
const isImmediatePush = form.getFieldValue("isImmediatePush");
return isImmediatePush ? (
<div
style={{
background: "#fffbe6",
border: "1px solid #ffe58f",
borderRadius: 4,
padding: 8,
color: "#ad8b00",
marginBottom: 16,
}}
>
</div>
) : null;
}}
</Form.Item>
</Form>
</Card>
</div>
);
},
);
BasicSettings.displayName = "BasicSettings";
export default BasicSettings; export default BasicSettings;

View File

@@ -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"; import ContentLibrarySelection from "@/components/ContentLibrarySelection";
interface ContentLibrary { interface ContentLibrary {
@@ -19,60 +20,116 @@ interface ContentSelectorProps {
loading?: boolean; loading?: boolean;
} }
const ContentSelector: React.FC<ContentSelectorProps> = ({ export interface ContentSelectorRef {
selectedLibraries, validate: () => Promise<boolean>;
onLibrariesChange, getValues: () => any;
onPrevious, }
onNext,
onSave,
loading = false,
}) => {
// 将 ContentLibrary[] 转换为 string[] 用于 ContentLibrarySelection
const selectedLibraryIds = selectedLibraries.map(lib => lib.id);
// 处理选择变化 const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
const handleLibrariesChange = (libraryIds: string[]) => { (
// 这里需要根据选中的ID重新构建ContentLibrary对象 {
// 由于ContentLibrarySelection只返回ID我们需要从原始数据中获取完整信息 selectedLibraries,
// 暂时使用简化的处理方式 onLibrariesChange,
const newSelectedLibraries = libraryIds.map(id => ({ onPrevious,
id, onNext,
name: `内容库 ${id}`, // 这里应该从API获取完整信息 onSave,
targets: [], // 这里应该从API获取完整信息 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);
};
// 处理选择详情变化 // 将 ContentLibrary[] 转换为 string[] 用于 ContentLibrarySelection
const handleSelectDetail = (libraries: any[]) => { const selectedLibraryIds = selectedLibraries.map(lib => lib.id);
// 将API返回的数据转换为ContentLibrary格式
const convertedLibraries = libraries.map(lib => ({
id: lib.id,
name: lib.name,
targets: [], // 这里需要根据实际情况获取targets数据
}));
onLibrariesChange(convertedLibraries);
};
return ( // 处理选择变化
<div style={{ marginBottom: 24 }}> const handleLibrariesChange = (libraryIds: string[]) => {
<div> // 这里需要根据选中的ID重新构建ContentLibrary对象
<div style={{ marginBottom: 16 }}> // 由于ContentLibrarySelection只返回ID我们需要从原始数据中获取完整信息
<span>:</span> // 暂时使用简化的处理方式
</div> const newSelectedLibraries = libraryIds.map(id => ({
<ContentLibrarySelection id,
selectedLibraries={selectedLibraryIds} name: `内容库 ${id}`, // 这里应该从API获取完整信息
onSelect={handleLibrariesChange} targets: [], // 这里应该从API获取完整信息
onSelectDetail={handleSelectDetail} }));
placeholder="选择内容库" onLibrariesChange(newSelectedLibraries);
showInput={true} form.setFieldValue("contentLibraries", libraryIds);
showSelectedList={true} };
readonly={loading}
selectedListMaxHeight={320} // 处理选择详情变化
/> 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 (
<div style={{ marginBottom: 24 }}>
<Card>
<Form
form={form}
layout="vertical"
initialValues={{ contentLibraries: selectedLibraryIds }}
>
<div style={{ marginBottom: 16 }}>
<h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>
</h2>
<p style={{ margin: "8px 0 0 0", color: "#666", fontSize: 14 }}>
</p>
</div>
<Form.Item
name="contentLibraries"
rules={[
{ required: true, message: "请选择至少一个内容库" },
{ type: "array", min: 1, message: "请选择至少一个内容库" },
{ type: "array", max: 20, message: "最多只能选择20个内容库" },
]}
>
<ContentLibrarySelection
selectedLibraries={selectedLibraryIds}
onSelect={handleLibrariesChange}
onSelectDetail={handleSelectDetail}
placeholder="选择内容库"
showInput={true}
showSelectedList={true}
readonly={loading}
selectedListMaxHeight={320}
/>
</Form.Item>
</Form>
</Card>
</div> </div>
</div> );
); },
}; );
ContentSelector.displayName = "ContentSelector";
export default ContentSelector; export default ContentSelector;

View File

@@ -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 GroupSelection from "@/components/GroupSelection";
import { GroupSelectionItem } from "@/components/GroupSelection/data"; import { GroupSelectionItem } from "@/components/GroupSelection/data";
interface GroupSelectorProps { interface GroupSelectorProps {
selectedGroups: string[]; selectedGroups: GroupSelectionItem[];
onGroupsChange: (groups: string[]) => void;
onPrevious: () => void; onPrevious: () => void;
onNext: () => void; onNext: (data: {
onSave: () => void; wechatGroups: string[];
loading?: boolean; wechatGroupsOptions: GroupSelectionItem[];
}) => void;
} }
const GroupSelector: React.FC<GroupSelectorProps> = ({ export interface GroupSelectorRef {
selectedGroups, validate: () => Promise<boolean>;
onGroupsChange, getValues: () => any;
onPrevious, }
onNext,
onSave,
loading = false,
}) => {
// 将string[]转换为GroupSelectionItem[]
const selectedGroupItems: GroupSelectionItem[] = selectedGroups.map(id => ({
id,
name: `群组 ${id}`,
avatar: "",
chatroomId: id,
}));
const handleGroupSelect = (groupItems: GroupSelectionItem[]) => { const GroupSelector = forwardRef<GroupSelectorRef, GroupSelectorProps>(
// 将GroupSelectionItem[]转换回string[] ({ selectedGroups, onNext }, ref) => {
const groupIds = groupItems.map(item => item.id); const [form] = Form.useForm();
onGroupsChange(groupIds);
};
return ( // 暴露方法给父组件
<div style={{ padding: 20 }}> useImperativeHandle(ref, () => ({
<div style={{ marginBottom: 20 }}> validate: async () => {
<h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}> try {
form.setFieldsValue({
</h2> wechatGroups: selectedGroups.map(item => item.id),
<p style={{ margin: "8px 0 0 0", color: "#666", fontSize: 14 }}> });
await form.validateFields();
</p> return true;
</div> } catch (error) {
console.log("GroupSelector 表单验证失败:", error);
return false;
}
},
getValues: () => {
return form.getFieldsValue();
},
}));
<GroupSelection // 群组选择
selectedGroups={selectedGroupItems} const handleGroupSelect = (wechatGroupsOptions: GroupSelectionItem[]) => {
onSelect={handleGroupSelect} const wechatGroups = wechatGroupsOptions.map(item => item.id);
placeholder="选择要推送的群组" form.setFieldValue("wechatGroups", wechatGroups);
readonly={false} onNext({ wechatGroups, wechatGroupsOptions });
showSelectedList={true} };
selectedListMaxHeight={300}
/> return (
</div> <Card>
); <Form
}; form={form}
layout="vertical"
initialValues={{ groups: selectedGroups }}
>
<div style={{ marginBottom: 20 }}>
<h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>
</h2>
<p style={{ margin: "8px 0 0 0", color: "#666", fontSize: 14 }}>
</p>
</div>
<Form.Item
name="wechatGroups"
rules={[
{
required: true,
type: "array",
min: 1,
message: "请选择至少一个群组",
},
{ type: "array", max: 50, message: "最多只能选择50个群组" },
]}
>
<GroupSelection
selectedGroups={selectedGroups}
onSelect={handleGroupSelect}
placeholder="选择要推送的群组"
readonly={false}
showSelectedList={true}
selectedListMaxHeight={300}
/>
</Form.Item>
</Form>
</Card>
);
},
);
GroupSelector.displayName = "GroupSelector";
export default GroupSelector; export default GroupSelector;

View File

@@ -27,6 +27,7 @@ export interface FormData {
isLoopPush: boolean; isLoopPush: boolean;
isImmediatePush: boolean; isImmediatePush: boolean;
isEnabled: boolean; isEnabled: boolean;
groups: WechatGroup[];
contentLibraries: ContentLibrary[]; contentLibraries: ContentLibrary[];
wechatGroups: string[];
[key: string]: any;
} }

View File

@@ -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 { useNavigate, useParams } from "react-router-dom";
import { Button } from "antd"; import { Button } from "antd";
import { createGroupPushTask } from "./index.api"; import { createGroupPushTask } from "./index.api";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
import StepIndicator from "@/components/StepIndicator"; import StepIndicator from "@/components/StepIndicator";
import BasicSettings from "./components/BasicSettings"; import BasicSettings, { BasicSettingsRef } from "./components/BasicSettings";
import GroupSelector from "./components/GroupSelector"; import GroupSelector, { GroupSelectorRef } from "./components/GroupSelector";
import ContentSelector from "./components/ContentSelector"; import ContentSelector, {
ContentSelectorRef,
} from "./components/ContentSelector";
import type { ContentLibrary, FormData } from "./index.data"; import type { ContentLibrary, FormData } from "./index.data";
import NavCommon from "@/components/NavCommon"; import NavCommon from "@/components/NavCommon";
import { GroupSelectionItem } from "@/components/GroupSelection/data";
const steps = [ const steps = [
{ id: 1, title: "步骤 1", subtitle: "基础设置" }, { id: 1, title: "步骤 1", subtitle: "基础设置" },
{ id: 2, title: "步骤 2", subtitle: "选择社群" }, { id: 2, title: "步骤 2", subtitle: "选择社群" },
@@ -21,6 +24,9 @@ const NewGroupPush: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [currentStep, setCurrentStep] = useState(1); const [currentStep, setCurrentStep] = useState(1);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [wechatGroupsOptions, setWechatGroupsOptions] = useState<
GroupSelectionItem[]
>([]);
const [formData, setFormData] = useState<FormData>({ const [formData, setFormData] = useState<FormData>({
name: "", name: "",
pushTimeStart: "06:00", pushTimeStart: "06:00",
@@ -30,11 +36,16 @@ const NewGroupPush: React.FC = () => {
isLoopPush: false, isLoopPush: false,
isImmediatePush: false, isImmediatePush: false,
isEnabled: false, isEnabled: false,
groups: [], wechatGroups: [],
contentLibraries: [], contentLibraries: [],
}); });
const [isEditMode, setIsEditMode] = useState(false); const [isEditMode, setIsEditMode] = useState(false);
// 创建子组件的ref
const basicSettingsRef = useRef<BasicSettingsRef>(null);
const groupSelectorRef = useRef<GroupSelectorRef>(null);
const contentSelectorRef = useRef<ContentSelectorRef>(null);
useEffect(() => { useEffect(() => {
if (!id) return; if (!id) return;
setIsEditMode(true); setIsEditMode(true);
@@ -44,19 +55,16 @@ const NewGroupPush: React.FC = () => {
setFormData(prev => ({ ...prev, ...values })); setFormData(prev => ({ ...prev, ...values }));
}; };
const handleGroupsChange = (groups: string[]) => { //群组选择
// 将string[]转换为WechatGroup[] const handleGroupsChange = (data: {
const convertedGroups = groups.map(id => ({ wechatGroups: string[];
id, wechatGroupsOptions: GroupSelectionItem[];
name: `群组 ${id}`, }) => {
avatar: "", setFormData(prev => ({
serviceAccount: { ...prev,
id: "", wechatGroups: data.wechatGroups,
name: "",
avatar: "",
},
})); }));
setFormData(prev => ({ ...prev, groups: convertedGroups })); setWechatGroupsOptions(data.wechatGroupsOptions);
}; };
const handleLibrariesChange = (contentLibraries: ContentLibrary[]) => { const handleLibrariesChange = (contentLibraries: ContentLibrary[]) => {
@@ -119,64 +127,66 @@ const NewGroupPush: React.FC = () => {
} }
}; };
const handleNext = () => { const handleNext = async () => {
if (currentStep < 4) { if (currentStep < 4) {
setCurrentStep(currentStep + 1); try {
} let isValid = false;
};
const canGoNext = () => { switch (currentStep) {
switch (currentStep) { case 1:
case 1: { // 调用 BasicSettings 的表单校验
return formData.name.trim() !== ""; 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 = () => { const renderFooter = () => {
if (currentStep === 4) {
return (
<div className="footer-btn-group">
<Button size="large" onClick={handlePrevious}>
</Button>
<Button type="primary" size="large" onClick={handleSave}>
</Button>
</div>
);
}
return ( return (
<div className="footer-btn-group"> <div className="footer-btn-group">
{currentStep > 1 && ( {currentStep > 1 && (
<Button size="large" type="primary" onClick={handlePrevious}> <Button size="large" onClick={handlePrevious}>
</Button> </Button>
)} )}
<Button size="large" type="primary" onClick={handleNext}> {currentStep === 4 ? (
<Button size="large" type="primary" onClick={handleSave}>
</Button>
</Button>
) : (
<Button size="large" type="primary" onClick={handleNext}>
</Button>
)}
</div> </div>
); );
}; };
@@ -186,11 +196,14 @@ const NewGroupPush: React.FC = () => {
header={<NavCommon title={isEditMode ? "编辑任务" : "新建任务"} />} header={<NavCommon title={isEditMode ? "编辑任务" : "新建任务"} />}
footer={renderFooter()} footer={renderFooter()}
> >
<div style={{ maxWidth: 600, margin: "0 auto", padding: 16 }}> <div style={{ padding: 12 }}>
<StepIndicator currentStep={currentStep} steps={steps} /> <div style={{ marginBottom: 12 }}>
<div style={{ marginTop: 32 }}> <StepIndicator currentStep={currentStep} steps={steps} />
</div>
<div>
{currentStep === 1 && ( {currentStep === 1 && (
<BasicSettings <BasicSettings
ref={basicSettingsRef}
defaultValues={{ defaultValues={{
name: formData.name, name: formData.name,
pushTimeStart: formData.pushTimeStart, pushTimeStart: formData.pushTimeStart,
@@ -208,16 +221,15 @@ const NewGroupPush: React.FC = () => {
)} )}
{currentStep === 2 && ( {currentStep === 2 && (
<GroupSelector <GroupSelector
selectedGroups={formData.groups.map(g => g.id)} ref={groupSelectorRef}
onGroupsChange={handleGroupsChange} selectedGroups={wechatGroupsOptions}
onPrevious={() => setCurrentStep(1)} onPrevious={() => setCurrentStep(1)}
onNext={() => setCurrentStep(3)} onNext={handleGroupsChange}
onSave={handleSave}
loading={loading}
/> />
)} )}
{currentStep === 3 && ( {currentStep === 3 && (
<ContentSelector <ContentSelector
ref={contentSelectorRef}
selectedLibraries={formData.contentLibraries} selectedLibraries={formData.contentLibraries}
onLibrariesChange={handleLibrariesChange} onLibrariesChange={handleLibrariesChange}
onPrevious={() => setCurrentStep(2)} onPrevious={() => setCurrentStep(2)}