feat(自动建群表单): 优化表单加载状态和输入组件样式
- 添加数据加载状态控制,编辑模式显示加载中提示 - 重构数字输入组件样式,使用antd的InputNumber组件 - 将StepIndicator移动到header区域优化布局 - 重命名defaultValues为initialValues以更准确表达用途
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import React, { useImperativeHandle, forwardRef } from "react";
|
||||
import { Input, Button, Card, Switch, Form, InputNumber } from "antd";
|
||||
import { TextArea } from "antd-mobile";
|
||||
import React, { useImperativeHandle, forwardRef, useEffect } from "react";
|
||||
import { Button, Card, Switch, Form, InputNumber } from "antd";
|
||||
import { Input } from "antd";
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
interface BasicSettingsProps {
|
||||
defaultValues?: {
|
||||
initialValues?: {
|
||||
name: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
@@ -22,21 +24,29 @@ export interface BasicSettingsRef {
|
||||
}
|
||||
|
||||
const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
({
|
||||
defaultValues = {
|
||||
name: "",
|
||||
startTime: "06:00",
|
||||
endTime: "23:59",
|
||||
groupSizeMin: 20,
|
||||
groupSizeMax: 50,
|
||||
maxGroupsPerDay: 10,
|
||||
groupNameTemplate: "",
|
||||
groupDescription: "",
|
||||
status: 1,
|
||||
(
|
||||
{
|
||||
initialValues = {
|
||||
name: "",
|
||||
startTime: "06:00",
|
||||
endTime: "23:59",
|
||||
groupSizeMin: 20,
|
||||
groupSizeMax: 50,
|
||||
maxGroupsPerDay: 10,
|
||||
groupNameTemplate: "",
|
||||
groupDescription: "",
|
||||
status: 1,
|
||||
},
|
||||
},
|
||||
}, ref) => {
|
||||
ref,
|
||||
) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 当initialValues变化时,重新设置表单值
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(initialValues);
|
||||
}, [form, initialValues]);
|
||||
|
||||
// 暴露方法给父组件
|
||||
useImperativeHandle(ref, () => ({
|
||||
validate: async () => {
|
||||
@@ -59,7 +69,7 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={defaultValues}
|
||||
key={JSON.stringify(initialValues)}
|
||||
onValuesChange={(changedValues, allValues) => {
|
||||
// 可以在这里处理表单值变化
|
||||
}}
|
||||
@@ -104,42 +114,53 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
rules={[
|
||||
{ required: true, message: "请输入每日最大建群数" },
|
||||
{
|
||||
type: "number",
|
||||
min: 1,
|
||||
max: 100,
|
||||
message: "每日最大建群数在1-100之间",
|
||||
validator: (_, value) => {
|
||||
const numValue = Number(value);
|
||||
if (value && (numValue < 1 || numValue > 100)) {
|
||||
return Promise.reject(
|
||||
new Error("每日最大建群数在1-100之间"),
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<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>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={100}
|
||||
placeholder="请输入最大建群数"
|
||||
step={1}
|
||||
style={{ width: "100%" }}
|
||||
value={form.getFieldValue("maxGroupsPerDay")}
|
||||
onChange={value => form.setFieldValue("maxGroupsPerDay", value)}
|
||||
addonBefore={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("maxGroupsPerDay") || 1;
|
||||
const newValue = Math.max(1, currentValue - 1);
|
||||
form.setFieldValue("maxGroupsPerDay", newValue);
|
||||
}}
|
||||
>
|
||||
-
|
||||
</Button>
|
||||
}
|
||||
addonAfter={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("maxGroupsPerDay") || 1;
|
||||
const newValue = Math.min(100, currentValue + 1);
|
||||
form.setFieldValue("maxGroupsPerDay", newValue);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* 群组最小人数 */}
|
||||
@@ -149,43 +170,53 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
rules={[
|
||||
{ required: true, message: "请输入群组最小人数" },
|
||||
{
|
||||
type: "number",
|
||||
min: 1,
|
||||
max: 500,
|
||||
message: "群组最小人数在1-500之间",
|
||||
validator: (_, value) => {
|
||||
const numValue = Number(value);
|
||||
if (value && (numValue < 1 || numValue > 500)) {
|
||||
return Promise.reject(
|
||||
new Error("群组最小人数在1-500之间"),
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<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>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={500}
|
||||
placeholder="请输入最小人数"
|
||||
step={1}
|
||||
style={{ width: "100%" }}
|
||||
value={form.getFieldValue("groupSizeMin")}
|
||||
onChange={value => form.setFieldValue("groupSizeMin", value)}
|
||||
addonBefore={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("groupSizeMin") || 1;
|
||||
const newValue = Math.max(1, currentValue - 1);
|
||||
form.setFieldValue("groupSizeMin", newValue);
|
||||
}}
|
||||
>
|
||||
-
|
||||
</Button>
|
||||
}
|
||||
addonAfter={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("groupSizeMin") || 1;
|
||||
const newValue = Math.min(500, currentValue + 1);
|
||||
form.setFieldValue("groupSizeMin", newValue);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* 群组最大人数 */}
|
||||
@@ -195,43 +226,53 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
rules={[
|
||||
{ required: true, message: "请输入群组最大人数" },
|
||||
{
|
||||
type: "number",
|
||||
min: 1,
|
||||
max: 500,
|
||||
message: "群组最大人数在1-500之间",
|
||||
validator: (_, value) => {
|
||||
const numValue = Number(value);
|
||||
if (value && (numValue < 1 || numValue > 500)) {
|
||||
return Promise.reject(
|
||||
new Error("群组最大人数在1-500之间"),
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<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>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={500}
|
||||
placeholder="请输入最大人数"
|
||||
step={1}
|
||||
style={{ width: "100%" }}
|
||||
value={form.getFieldValue("groupSizeMax")}
|
||||
onChange={value => form.setFieldValue("groupSizeMax", value)}
|
||||
addonBefore={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("groupSizeMax") || 1;
|
||||
const newValue = Math.max(1, currentValue - 1);
|
||||
form.setFieldValue("groupSizeMax", newValue);
|
||||
}}
|
||||
>
|
||||
-
|
||||
</Button>
|
||||
}
|
||||
addonAfter={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => {
|
||||
const currentValue =
|
||||
form.getFieldValue("groupSizeMax") || 1;
|
||||
const newValue = Math.min(500, currentValue + 1);
|
||||
form.setFieldValue("groupSizeMax", newValue);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* 群名称模板 */}
|
||||
@@ -240,7 +281,11 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
name="groupNameTemplate"
|
||||
rules={[
|
||||
{ required: true, message: "请输入群名称模板" },
|
||||
{ min: 2, max: 100, message: "群名称模板长度在2-100个字符之间" },
|
||||
{
|
||||
min: 2,
|
||||
max: 100,
|
||||
message: "群名称模板长度在2-100个字符之间",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入群名称模板" />
|
||||
@@ -265,8 +310,8 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
label="是否启用"
|
||||
name="status"
|
||||
valuePropName="checked"
|
||||
getValueFromEvent={(checked) => checked ? 1 : 0}
|
||||
getValueProps={(value) => ({ checked: value === 1 })}
|
||||
getValueFromEvent={checked => (checked ? 1 : 0)}
|
||||
getValueProps={value => ({ checked: value === 1 })}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
@@ -288,4 +333,4 @@ const BasicSettings = forwardRef<BasicSettingsRef, BasicSettingsProps>(
|
||||
|
||||
BasicSettings.displayName = "BasicSettings";
|
||||
|
||||
export default BasicSettings;
|
||||
export default BasicSettings;
|
||||
|
||||
@@ -45,6 +45,7 @@ const AutoGroupForm: React.FC = () => {
|
||||
const isEdit = Boolean(id);
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataLoaded, setDataLoaded] = useState(!isEdit); // 非编辑模式直接标记为已加载
|
||||
const [formData, setFormData] = useState<AutoGroupFormData>(defaultForm);
|
||||
const [deviceGroupsOptions, setDeviceGroupsOptions] = useState<
|
||||
DeviceSelectionItem[]
|
||||
@@ -83,6 +84,7 @@ const AutoGroupForm: React.FC = () => {
|
||||
setFormData(updatedForm);
|
||||
setDeviceGroupsOptions(res.config.deveiceGroupsOptions || []);
|
||||
setContentGroupsOptions(res.config.contentGroupsOptions || []);
|
||||
setDataLoaded(true); // 标记数据已加载
|
||||
});
|
||||
}, [id]);
|
||||
|
||||
@@ -190,12 +192,19 @@ const AutoGroupForm: React.FC = () => {
|
||||
};
|
||||
|
||||
const renderCurrentStep = () => {
|
||||
// 编辑模式下,等待数据加载完成后再渲染
|
||||
if (isEdit && !dataLoaded) {
|
||||
return (
|
||||
<div style={{ textAlign: "center", padding: "50px" }}>加载中...</div>
|
||||
);
|
||||
}
|
||||
|
||||
switch (currentStep) {
|
||||
case 1:
|
||||
return (
|
||||
<BasicSettings
|
||||
ref={basicSettingsRef}
|
||||
defaultValues={{
|
||||
initialValues={{
|
||||
name: formData.name,
|
||||
startTime: formData.startTime,
|
||||
endTime: formData.endTime,
|
||||
@@ -258,19 +267,17 @@ const AutoGroupForm: React.FC = () => {
|
||||
return (
|
||||
<Layout
|
||||
header={
|
||||
<NavCommon
|
||||
title={isEdit ? "编辑建群任务" : "新建建群任务"}
|
||||
backFn={() => navigate(-1)}
|
||||
/>
|
||||
<>
|
||||
<NavCommon
|
||||
title={isEdit ? "编辑建群任务" : "新建建群任务"}
|
||||
backFn={() => navigate(-1)}
|
||||
/>
|
||||
<StepIndicator currentStep={currentStep} steps={steps} />
|
||||
</>
|
||||
}
|
||||
footer={renderFooter()}
|
||||
>
|
||||
<div style={{ padding: 12 }}>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<StepIndicator currentStep={currentStep} steps={steps} />
|
||||
</div>
|
||||
<div>{renderCurrentStep()}</div>
|
||||
</div>
|
||||
<div style={{ padding: 12 }}>{renderCurrentStep()}</div>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user