feat(自动建群表单): 优化表单加载状态和输入组件样式

- 添加数据加载状态控制,编辑模式显示加载中提示
- 重构数字输入组件样式,使用antd的InputNumber组件
- 将StepIndicator移动到header区域优化布局
- 重命名defaultValues为initialValues以更准确表达用途
This commit is contained in:
超级老白兔
2025-08-20 15:45:55 +08:00
parent fcc4805220
commit 1d93368eb0
2 changed files with 185 additions and 133 deletions

View File

@@ -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;

View File

@@ -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>
);
};