feat(自动建群): 添加内容库选择功能并重构表单为分步式

添加内容库选择组件及相关类型定义
重构自动建群表单为分步式操作流程
新增基础设置、设备选择和内容选择三个步骤组件
完善表单验证逻辑和步骤导航功能
This commit is contained in:
超级老白兔
2025-08-20 15:07:17 +08:00
parent d93165bfac
commit fcc4805220
5 changed files with 694 additions and 222 deletions

View File

@@ -0,0 +1,291 @@
import React, { useImperativeHandle, forwardRef } from "react";
import { Input, Button, Card, Switch, Form, InputNumber } from "antd";
import { TextArea } from "antd-mobile";
interface BasicSettingsProps {
defaultValues?: {
name: string;
startTime: string;
endTime: string;
groupSizeMin: number;
groupSizeMax: number;
maxGroupsPerDay: number;
groupNameTemplate: string;
groupDescription: string;
status: number;
};
}
export interface BasicSettingsRef {
validate: () => Promise<boolean>;
getValues: () => any;
}
const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
({
defaultValues = {
name: "",
startTime: "06:00",
endTime: "23:59",
groupSizeMin: 20,
groupSizeMax: 50,
maxGroupsPerDay: 10,
groupNameTemplate: "",
groupDescription: "",
status: 1,
},
}, ref) => {
const [form] = Form.useForm();
// 暴露方法给父组件
useImperativeHandle(ref, () => ({
validate: async () => {
try {
await form.validateFields();
return true;
} catch (error) {
console.log("BasicSettings 表单验证失败:", error);
return false;
}
},
getValues: () => {
return form.getFieldsValue();
},
}));
return (
<div style={{ marginBottom: 24 }}>
<Card>
<Form
form={form}
layout="vertical"
initialValues={defaultValues}
onValuesChange={(changedValues, allValues) => {
// 可以在这里处理表单值变化
}}
>
{/* 任务名称 */}
<Form.Item
label="任务名称"
name="name"
rules={[
{ required: true, message: "请输入任务名称" },
{ min: 2, max: 50, message: "任务名称长度在2-50个字符之间" },
]}
>
<Input placeholder="请输入任务名称" />
</Form.Item>
{/* 允许建群的时间段 */}
<Form.Item label="允许建群的时间段">
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
<Form.Item
name="startTime"
noStyle
rules={[{ required: true, message: "请选择开始时间" }]}
>
<Input type="time" style={{ width: 120 }} />
</Form.Item>
<span style={{ color: "#888" }}></span>
<Form.Item
name="endTime"
noStyle
rules={[{ required: true, message: "请选择结束时间" }]}
>
<Input type="time" style={{ width: 120 }} />
</Form.Item>
</div>
</Form.Item>
{/* 每日最大建群数 */}
<Form.Item
label="每日最大建群数"
name="maxGroupsPerDay"
rules={[
{ required: true, message: "请输入每日最大建群数" },
{
type: "number",
min: 1,
max: 100,
message: "每日最大建群数在1-100之间",
},
]}
>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("maxGroupsPerDay") || 1;
const newValue = Math.max(1, currentValue - 1);
form.setFieldValue("maxGroupsPerDay", newValue);
}}
>
-
</Button>
<InputNumber
min={1}
max={100}
placeholder="请输入最大建群数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("maxGroupsPerDay") || 1;
const newValue = Math.min(100, currentValue + 1);
form.setFieldValue("maxGroupsPerDay", newValue);
}}
>
+
</Button>
</div>
</Form.Item>
{/* 群组最小人数 */}
<Form.Item
label="群组最小人数"
name="groupSizeMin"
rules={[
{ required: true, message: "请输入群组最小人数" },
{
type: "number",
min: 1,
max: 500,
message: "群组最小人数在1-500之间",
},
]}
>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("groupSizeMin") || 1;
const maxValue = form.getFieldValue("groupSizeMax") || 500;
const newValue = Math.max(1, currentValue - 1);
form.setFieldValue("groupSizeMin", Math.min(newValue, maxValue));
}}
>
-
</Button>
<InputNumber
min={1}
max={500}
placeholder="请输入最小人数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("groupSizeMin") || 1;
const newValue = Math.min(500, currentValue + 1);
form.setFieldValue("groupSizeMin", newValue);
}}
>
+
</Button>
</div>
</Form.Item>
{/* 群组最大人数 */}
<Form.Item
label="群组最大人数"
name="groupSizeMax"
rules={[
{ required: true, message: "请输入群组最大人数" },
{
type: "number",
min: 1,
max: 500,
message: "群组最大人数在1-500之间",
},
]}
>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("groupSizeMax") || 1;
const newValue = Math.max(1, currentValue - 1);
form.setFieldValue("groupSizeMax", newValue);
}}
>
-
</Button>
<InputNumber
min={1}
max={500}
placeholder="请输入最大人数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const currentValue = form.getFieldValue("groupSizeMax") || 1;
const minValue = form.getFieldValue("groupSizeMin") || 1;
const newValue = Math.min(500, currentValue + 1);
form.setFieldValue("groupSizeMax", Math.max(newValue, minValue));
}}
>
+
</Button>
</div>
</Form.Item>
{/* 群名称模板 */}
<Form.Item
label="群名称模板"
name="groupNameTemplate"
rules={[
{ required: true, message: "请输入群名称模板" },
{ min: 2, max: 100, message: "群名称模板长度在2-100个字符之间" },
]}
>
<Input placeholder="请输入群名称模板" />
</Form.Item>
{/* 群描述 */}
<Form.Item
label="群描述"
name="groupDescription"
rules={[{ max: 200, message: "群描述不能超过200个字符" }]}
>
<TextArea
placeholder="请输入群描述"
rows={3}
maxLength={200}
showCount
/>
</Form.Item>
{/* 是否启用 */}
<Form.Item
label="是否启用"
name="status"
valuePropName="checked"
getValueFromEvent={(checked) => checked ? 1 : 0}
getValueProps={(value) => ({ checked: value === 1 })}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<span></span>
<Switch />
</div>
</Form.Item>
</Form>
</Card>
</div>
);
},
);
BasicSettings.displayName = "BasicSettings";
export default BasicSettings;

View File

@@ -0,0 +1,95 @@
import React, { useImperativeHandle, forwardRef } from "react";
import { Form, Card } from "antd";
import ContentSelection from "@/components/ContentSelection";
import { ContentItem } from "@/components/ContentSelection/data";
interface ContentSelectorProps {
selectedContent: ContentItem[];
onNext: (data: {
contentGroups: string[];
contentGroupsOptions: ContentItem[];
}) => void;
}
export interface ContentSelectorRef {
validate: () => Promise<boolean>;
getValues: () => any;
}
const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
({ selectedContent, onNext }, 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();
},
}));
// 处理选择变化
const handleContentChange = (contentGroupsOptions: ContentItem[]) => {
const contentGroups = contentGroupsOptions.map(c => c.id.toString());
form.setFieldValue("contentGroups", contentGroups);
onNext({
contentGroups,
contentGroupsOptions,
});
};
return (
<div style={{ marginBottom: 24 }}>
<Card>
<Form
form={form}
layout="vertical"
initialValues={{
contentGroups: selectedContent.map(c => c.id.toString()),
}}
>
<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="contentGroups"
rules={[
{ required: true, message: "请选择至少一个内容库" },
{ type: "array", min: 1, message: "请选择至少一个内容库" },
{ type: "array", max: 20, message: "最多只能选择20个内容库" },
]}
>
<ContentSelection
selectedOptions={selectedContent}
onSelect={handleContentChange}
placeholder="选择内容库"
showInput={true}
showSelectedList={true}
readonly={false}
selectedListMaxHeight={320}
/>
</Form.Item>
</Form>
</Card>
</div>
);
},
);
ContentSelector.displayName = "ContentSelector";
export default ContentSelector;

View File

@@ -0,0 +1,95 @@
import React, { useImperativeHandle, forwardRef } from "react";
import { Form, Card } from "antd";
import DeviceSelection from "@/components/DeviceSelection";
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
interface DeviceSelectorProps {
selectedDevices: DeviceSelectionItem[];
onNext: (data: {
deveiceGroups: string[];
deveiceGroupsOptions: DeviceSelectionItem[];
}) => void;
}
export interface DeviceSelectorRef {
validate: () => Promise<boolean>;
getValues: () => any;
}
const DeviceSelector = forwardRef<DeviceSelectorRef, DeviceSelectorProps>(
({ selectedDevices, onNext }, ref) => {
const [form] = Form.useForm();
// 暴露方法给父组件
useImperativeHandle(ref, () => ({
validate: async () => {
try {
await form.validateFields();
return true;
} catch (error) {
console.log("DeviceSelector 表单验证失败:", error);
return false;
}
},
getValues: () => {
return form.getFieldsValue();
},
}));
// 设备选择
const handleDeviceSelect = (
deveiceGroupsOptions: DeviceSelectionItem[],
) => {
const deveiceGroups = deveiceGroupsOptions.map(item => item.id);
form.setFieldValue("deveiceGroups", deveiceGroups);
// 通知父组件数据变化
onNext({
deveiceGroups: deveiceGroups.map(id => String(id)),
deveiceGroupsOptions,
});
};
return (
<Card>
<Form
form={form}
layout="vertical"
initialValues={{
deveiceGroups: selectedDevices.map(item => item.id),
}}
>
<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="deveiceGroups"
rules={[
{
required: true,
type: "array",
min: 1,
message: "请选择至少一个设备组",
},
{ type: "array", max: 20, message: "最多只能选择20个设备组" },
]}
>
<DeviceSelection
selectedOptions={selectedDevices}
onSelect={handleDeviceSelect}
/>
</Form.Item>
</Form>
</Card>
);
},
);
DeviceSelector.displayName = "DeviceSelector";
export default DeviceSelector;

View File

@@ -1,21 +1,34 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { Form, Toast, TextArea } from "antd-mobile";
import { Input, InputNumber, Button, Switch } from "antd";
import { Toast } from "antd-mobile";
import { Button } from "antd";
import Layout from "@/components/Layout/Layout";
import style from "./index.module.scss";
import { createAutoGroup, updateAutoGroup, getAutoGroupDetail } from "./api";
import { AutoGroupFormData } from "./types";
import DeviceSelection from "@/components/DeviceSelection/index";
import { AutoGroupFormData, StepItem } from "./types";
import StepIndicator from "@/components/StepIndicator";
import BasicSettings, { BasicSettingsRef } from "./components/BasicSettings";
import DeviceSelector, { DeviceSelectorRef } from "./components/DeviceSelector";
import ContentSelector, {
ContentSelectorRef,
} from "./components/ContentSelector";
import NavCommon from "@/components/NavCommon/index";
import dayjs from "dayjs";
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
import { ContentItem } from "@/components/ContentSelection/data";
const steps: StepItem[] = [
{ id: 1, title: "步骤 1", subtitle: "基础设置" },
{ id: 2, title: "步骤 2", subtitle: "选择设备" },
{ id: 3, title: "步骤 3", subtitle: "选择内容库" },
];
const defaultForm: AutoGroupFormData = {
name: "",
type: 4,
deveiceGroups: [], // 设备组
deveiceGroupsOptions: [], // 设备组选项
contentGroups: [], // 内容库
contentGroupsOptions: [], // 内容库选项
startTime: dayjs().format("HH:mm"), // 开始时间 (HH:mm)
endTime: dayjs().add(1, "hour").format("HH:mm"), // 结束时间 (HH:mm)
groupSizeMin: 20, // 群组最小人数
@@ -30,17 +43,32 @@ const AutoGroupForm: React.FC = () => {
const navigate = useNavigate();
const { id } = useParams();
const isEdit = Boolean(id);
const [form, setForm] = useState<AutoGroupFormData>(defaultForm);
const [currentStep, setCurrentStep] = useState(1);
const [loading, setLoading] = useState(false);
const [formData, setFormData] = useState<AutoGroupFormData>(defaultForm);
const [deviceGroupsOptions, setDeviceGroupsOptions] = useState<
DeviceSelectionItem[]
>([]);
const [contentGroupsOptions, setContentGroupsOptions] = useState<
ContentItem[]
>([]);
// 创建子组件的ref
const basicSettingsRef = useRef<BasicSettingsRef>(null);
const deviceSelectorRef = useRef<DeviceSelectorRef>(null);
const contentSelectorRef = useRef<ContentSelectorRef>(null);
useEffect(() => {
if (!id) return;
// 这里应请求详情接口回填表单演示用mock
getAutoGroupDetail(id).then(res => {
setForm({
const updatedForm = {
...defaultForm,
name: res.name,
deveiceGroups: res.config.deveiceGroups || [],
deveiceGroupsOptions: res.config.deveiceGroupsOptions || [],
contentGroups: res.config.contentGroups || [],
contentGroupsOptions: res.config.contentGroupsOptions || [],
startTime: res.config.startTime,
endTime: res.config.endTime,
groupSizeMin: res.config.groupSizeMin,
@@ -51,19 +79,65 @@ const AutoGroupForm: React.FC = () => {
status: res.status,
type: res.type,
id: res.id,
});
console.log(form);
};
setFormData(updatedForm);
setDeviceGroupsOptions(res.config.deveiceGroupsOptions || []);
setContentGroupsOptions(res.config.contentGroupsOptions || []);
});
}, [id]);
const handleSubmit = async () => {
const handleBasicSettingsChange = (values: Partial<AutoGroupFormData>) => {
setFormData(prev => ({ ...prev, ...values }));
};
// 设备组选择
const handleDevicesChange = (data: {
deveiceGroups: string[];
deveiceGroupsOptions: DeviceSelectionItem[];
}) => {
setFormData(prev => ({
...prev,
deveiceGroups: data.deveiceGroups,
}));
setDeviceGroupsOptions(data.deveiceGroupsOptions);
};
// 内容库选择
const handleContentChange = (data: {
contentGroups: string[];
contentGroupsOptions: ContentItem[];
}) => {
setFormData(prev => ({ ...prev, contentGroups: data.contentGroups }));
setContentGroupsOptions(data.contentGroupsOptions);
};
const handleSave = async () => {
if (!formData.name.trim()) {
Toast.show({ content: "请输入任务名称" });
return;
}
if (formData.deveiceGroups.length === 0) {
Toast.show({ content: "请选择至少一个设备组" });
return;
}
if (formData.contentGroups.length === 0) {
Toast.show({ content: "请选择至少一个内容库" });
return;
}
setLoading(true);
try {
const submitData = {
...formData,
deveiceGroupsOptions: deviceGroupsOptions,
contentGroupsOptions: contentGroupsOptions,
};
if (isEdit) {
await updateAutoGroup(form);
await updateAutoGroup(submitData);
Toast.show({ content: "编辑成功" });
} else {
await createAutoGroup(form);
await createAutoGroup(submitData);
Toast.show({ content: "创建成功" });
}
navigate("/workspace/auto-group");
@@ -74,17 +148,113 @@ const AutoGroupForm: React.FC = () => {
}
};
const setTaskName = (val: string) => {
setForm((f: any) => ({ ...f, name: val }));
const handlePrevious = () => {
if (currentStep > 1) {
setCurrentStep(currentStep - 1);
}
};
const setDeviceGroups = (val: DeviceSelectionItem[]) => {
console.log(val);
setForm((f: any) => ({
...f,
deveiceGroups: val.map(item => item.id),
deveiceGroupsOptions: val,
}));
const handleNext = async () => {
if (currentStep < 3) {
try {
let isValid = false;
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:
// 调用 DeviceSelector 的表单校验
isValid = (await deviceSelectorRef.current?.validate()) || false;
if (isValid) {
setCurrentStep(3);
}
break;
default:
setCurrentStep(currentStep + 1);
}
} catch (error) {
console.log("表单验证失败:", error);
}
}
};
const renderCurrentStep = () => {
switch (currentStep) {
case 1:
return (
<BasicSettings
ref={basicSettingsRef}
defaultValues={{
name: formData.name,
startTime: formData.startTime,
endTime: formData.endTime,
groupSizeMin: formData.groupSizeMin,
groupSizeMax: formData.groupSizeMax,
maxGroupsPerDay: formData.maxGroupsPerDay,
groupNameTemplate: formData.groupNameTemplate,
groupDescription: formData.groupDescription,
status: formData.status,
}}
/>
);
case 2:
return (
<DeviceSelector
ref={deviceSelectorRef}
selectedDevices={deviceGroupsOptions}
onNext={handleDevicesChange}
/>
);
case 3:
return (
<ContentSelector
ref={contentSelectorRef}
selectedContent={contentGroupsOptions}
onNext={handleContentChange}
/>
);
default:
return null;
}
};
const renderFooter = () => {
return (
<div className="footer-btn-group">
{currentStep > 1 && (
<Button size="large" onClick={handlePrevious}>
</Button>
)}
{currentStep === 3 ? (
<Button
size="large"
type="primary"
loading={loading}
onClick={handleSave}
>
{isEdit ? "保存修改" : "创建任务"}
</Button>
) : (
<Button size="large" type="primary" onClick={handleNext}>
</Button>
)}
</div>
);
};
return (
<Layout
header={
@@ -93,207 +263,13 @@ const AutoGroupForm: React.FC = () => {
backFn={() => navigate(-1)}
/>
}
footer={renderFooter()}
>
<div className={style.autoGroupForm}>
<Form
layout="vertical"
footer={
<Button
block
type="primary"
loading={loading}
onClick={handleSubmit}
>
{isEdit ? "保存修改" : "创建任务"}
</Button>
}
>
<Form.Item label="任务名称" required>
<Input
value={form.name}
onChange={val => setTaskName(val.target.value)}
placeholder="请输入任务名称"
/>
</Form.Item>
<Form.Item label="设备组" required>
<DeviceSelection
selectedOptions={form.deveiceGroupsOptions}
onSelect={setDeviceGroups}
/>
</Form.Item>
<Form.Item label="每日最大建群数" name="maxGroupsPerDay" required>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.max(1, (form.maxGroupsPerDay || 1) - 1);
setForm((f: any) => ({ ...f, maxGroupsPerDay: newValue }));
}}
>
-
</Button>
<InputNumber
min={1}
max={100}
value={form.maxGroupsPerDay}
onChange={val =>
setForm((f: any) => ({ ...f, maxGroupsPerDay: val || 1 }))
}
placeholder="请输入最大建群数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.min(
100,
(form.maxGroupsPerDay || 1) + 1,
);
setForm((f: any) => ({ ...f, maxGroupsPerDay: newValue }));
}}
>
+
</Button>
</div>
</Form.Item>
<Form.Item label="开始时间" required>
<Input
type="time"
style={{ width: 120 }}
value={form.startTime || ""}
onChange={e => {
setForm((f: any) => ({ ...f, startTime: e.target.value }));
}}
/>
</Form.Item>
<Form.Item label="结束时间" required>
<Input
type="time"
style={{ width: 120 }}
value={form.endTime || ""}
onChange={e => {
setForm((f: any) => ({ ...f, endTime: e.target.value }));
}}
/>
</Form.Item>
<Form.Item label="群组最小人数" name="groupSizeMin" required>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.max(1, (form.groupSizeMin || 1) - 1);
setForm((f: any) => ({ ...f, groupSizeMin: newValue }));
}}
>
-
</Button>
<InputNumber
min={1}
max={500}
value={form.groupSizeMin}
onChange={val => {
const newValue = val || 1;
setForm((f: any) => ({
...f,
groupSizeMin: Math.min(newValue, f.groupSizeMax),
}));
}}
placeholder="请输入最小人数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.min(500, (form.groupSizeMin || 1) + 1);
setForm((f: any) => ({ ...f, groupSizeMin: newValue }));
}}
>
+
</Button>
</div>
</Form.Item>
<Form.Item label="群组最大人数" name="groupSizeMax" required>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.max(1, (form.groupSizeMax || 1) - 1);
setForm((f: any) => ({ ...f, groupSizeMax: newValue }));
}}
>
-
</Button>
<InputNumber
min={1}
max={500}
value={form.groupSizeMax}
onChange={val => {
const newValue = val || 1;
setForm((f: any) => ({
...f,
groupSizeMax: Math.max(newValue, f.groupSizeMin),
}));
}}
placeholder="请输入最大人数"
step={1}
style={{ flex: 1 }}
/>
<Button
htmlType="button"
onClick={() => {
const newValue = Math.min(500, (form.groupSizeMax || 1) + 1);
setForm((f: any) => ({ ...f, groupSizeMax: newValue }));
}}
>
+
</Button>
</div>
</Form.Item>
<Form.Item label="群名称模板" required>
<Input
value={form.groupNameTemplate}
onChange={val =>
setForm((f: any) => ({
...f,
groupNameTemplate: val.target.value,
}))
}
placeholder="请输入群名称模板"
/>
</Form.Item>
<Form.Item label="群描述" name="groupDescription">
<TextArea
value={form.groupDescription}
onChange={val =>
setForm((f: any) => ({ ...f, groupDescription: val }))
}
placeholder="请输入群描述"
rows={3}
maxLength={100}
showCount
/>
</Form.Item>
<Form.Item label="是否开启" name="status">
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<span></span>
<Switch
checked={form.status === 1}
onChange={checked =>
setForm((f: any) => ({ ...f, status: checked ? 1 : 0 }))
}
/>
</div>
</Form.Item>
</Form>
<div style={{ padding: 12 }}>
<div style={{ marginBottom: 12 }}>
<StepIndicator currentStep={currentStep} steps={steps} />
</div>
<div>{renderCurrentStep()}</div>
</div>
</Layout>
);

View File

@@ -1,4 +1,6 @@
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
import { ContentItem } from "@/components/ContentSelection/data";
// 自动建群表单数据类型定义
export interface AutoGroupFormData {
id?: string; // 任务ID
@@ -6,6 +8,8 @@ export interface AutoGroupFormData {
name: string; // 任务名称
deveiceGroups: string[]; // 设备组
deveiceGroupsOptions: DeviceSelectionItem[]; // 设备组选项
contentGroups: string[]; // 内容库
contentGroupsOptions: ContentItem[]; // 内容库选项
startTime: string; // 开始时间 (YYYY-MM-DD HH:mm:ss)
endTime: string; // 结束时间 (YYYY-MM-DD HH:mm:ss)
groupSizeMin: number; // 群组最小人数
@@ -17,6 +21,13 @@ export interface AutoGroupFormData {
[key: string]: any;
}
// 步骤定义
export interface StepItem {
id: number;
title: string;
subtitle: string;
}
// 表单验证规则
export const formValidationRules = {
name: [
@@ -27,6 +38,10 @@ export const formValidationRules = {
{ required: true, message: "请选择设备组" },
{ type: "array", min: 1, message: "至少选择一个设备组" },
],
contentGroups: [
{ required: true, message: "请选择内容库" },
{ type: "array", min: 1, message: "至少选择一个内容库" },
],
startTime: [{ required: true, message: "请选择开始时间" }],
endTime: [{ required: true, message: "请选择结束时间" }],
groupSizeMin: [