feat(流量分发表单): 优化表单管理和数据获取逻辑

重构流量分发表单组件,使用Form管理字段并引入useWatch以简化状态管理。移除未使用的状态和函数,优化了获取详情数据的逻辑。同时,更新了API请求方法以符合RESTful标准,确保删除计划时使用DELETE请求。
This commit is contained in:
超级老白兔
2025-09-19 16:58:40 +08:00
parent f69659309d
commit ef839f65c1
2 changed files with 132 additions and 147 deletions

View File

@@ -1,15 +1,5 @@
import React, { useState, useEffect } from "react";
import {
Form,
Input,
Button,
Radio,
Slider,
TimePicker,
message,
Checkbox,
} from "antd";
import { SearchOutlined } from "@ant-design/icons";
import React, { useState, useEffect, useCallback } from "react";
import { Form, Input, Button, Radio, Slider, TimePicker, message } from "antd";
import { useNavigate, useParams } from "react-router-dom";
import style from "./index.module.scss";
import StepIndicator from "@/components/StepIndicator";
@@ -24,22 +14,10 @@ import {
updateTrafficDistribution,
createTrafficDistribution,
} from "./api";
import type {
TrafficDistributionDetail,
TrafficDistributionFormData,
} from "./data";
import type { TrafficDistributionFormData } from "./data";
import dayjs from "dayjs";
const scenarioList = [
{ label: "海报获客", value: "poster" },
{ label: "电话获客", value: "phone" },
{ label: "抖音获客", value: "douyin" },
{ label: "小红书获客", value: "xiaohongshu" },
{ label: "微信群获客", value: "weixinqun" },
{ label: "API获客", value: "api" },
{ label: "订单获客", value: "order" },
{ label: "付款码获客", value: "payment" },
];
// const scenarioList = [...];
const poolList = [
{
id: "pool-1",
@@ -73,10 +51,7 @@ const TrafficDistributionForm: React.FC = () => {
const [deviceGroupsOptions, setDeviceGroupsOptions] = useState<any[]>([]);
const [accountGroups, setAccountGroups] = useState<any[]>([]);
const [accountGroupsOptions, setAccountGroupsOptions] = useState<any[]>([]);
const [distributeType, setDistributeType] = useState(1);
const [maxPerDay, setMaxPerDay] = useState(50);
const [timeType, setTimeType] = useState(1);
const [timeRange, setTimeRange] = useState<any>(null);
// 使用 Form 管理字段,配合 useWatch 读取值
const [loading, setLoading] = useState(false);
const [detailLoading, setDetailLoading] = useState(false);
@@ -86,9 +61,12 @@ const TrafficDistributionForm: React.FC = () => {
"device" | "account"
>("device");
// 编辑时的详情数据
const [detailData, setDetailData] =
useState<TrafficDistributionDetail | null>(null);
// 编辑时的详情数据(不需要保存整份数据,仅回填表单与本地状态)
// 监听表单字段变化antd v5 推荐)
const maxPerDay = Form.useWatch("maxPerDay", form);
const timeType = Form.useWatch("timeType", form);
// const timeRange = Form.useWatch("timeRange", form);
// 生成默认名称
const generateDefaultName = () => {
@@ -98,20 +76,12 @@ const TrafficDistributionForm: React.FC = () => {
return `流量分发 ${dateStr} ${timeStr}`;
};
// 获取详情数据
useEffect(() => {
if (isEdit && id) {
fetchDetail();
}
}, [isEdit, id]);
const fetchDetail = async () => {
const fetchDetail = useCallback(async () => {
if (!id) return;
setDetailLoading(true);
try {
const detail = await getTrafficDistributionDetail(id);
setDetailData(detail);
// 回填表单数据
const config = detail.config;
@@ -122,11 +92,6 @@ const TrafficDistributionForm: React.FC = () => {
timeType: config.timeType,
});
// 设置状态
setDistributeType(config.distributeType);
setMaxPerDay(config.maxPerDay);
setTimeType(config.timeType);
// 设置账号组数据
setAccountGroups(config.accountGroups || []);
setAccountGroupsOptions(config.accountGroupsOptions || []);
@@ -147,7 +112,7 @@ const TrafficDistributionForm: React.FC = () => {
// 使用dayjs创建时间对象
const startTime = dayjs().hour(startHour).minute(startMinute).second(0);
const endTime = dayjs().hour(endHour).minute(endMinute).second(0);
setTimeRange([startTime, endTime]);
form.setFieldsValue({ timeRange: [startTime, endTime] });
}
// 设置流量池
@@ -158,9 +123,21 @@ const TrafficDistributionForm: React.FC = () => {
} finally {
setDetailLoading(false);
}
}, [id, form]);
// 获取详情数据
useEffect(() => {
if (isEdit && id) {
fetchDetail();
}
}, [isEdit, id, fetchDetail]);
const handleFinish = async () => {
form.submit();
};
const handleFinish = async (values?: any) => {
// 移除未使用的 handleFinish3
const handleFinish2 = async (values?: any) => {
setLoading(true);
try {
// 如果没有传递values参数从表单中获取
@@ -173,13 +150,17 @@ const TrafficDistributionForm: React.FC = () => {
source: "",
sourceIcon: "",
description: "",
distributeType: distributeType,
maxPerDay: maxPerDay,
timeType: timeType,
distributeType: formValues.distributeType,
maxPerDay: formValues.maxPerDay,
timeType: formValues.timeType,
startTime:
timeType === 2 && timeRange?.[0] ? timeRange[0].format("HH:mm") : "",
formValues.timeType === 2 && formValues.timeRange?.[0]
? formValues.timeRange[0].format("HH:mm")
: "",
endTime:
timeType === 2 && timeRange?.[1] ? timeRange[1].format("HH:mm") : "",
formValues.timeType === 2 && formValues.timeRange?.[1]
? formValues.timeRange[1].format("HH:mm")
: "",
deviceGroups: deviceGroups,
deviceGroupsOptions: deviceGroupsOptions,
accountGroups: accountGroups,
@@ -216,6 +197,17 @@ const TrafficDistributionForm: React.FC = () => {
.catch(() => {
// 验证失败,不进行下一步
});
} else if (current === 1) {
// 第二步:目标设置至少需要选择设备或客服之一
const hasDevice =
Array.isArray(selectedDevices) && selectedDevices.length > 0;
const hasAccount =
Array.isArray(selectedAccounts) && selectedAccounts.length > 0;
if (!hasDevice && !hasAccount) {
message.error("请至少选择一个设备或一个客服");
return;
}
setCurrent(cur => cur + 1);
} else {
setCurrent(cur => cur + 1);
}
@@ -225,6 +217,7 @@ const TrafficDistributionForm: React.FC = () => {
// 过滤流量池
const filteredPools = poolList.filter(pool => pool.name.includes(poolSearch));
// 移除未使用的输入同步函数
return (
<Layout
header={
@@ -262,104 +255,96 @@ const TrafficDistributionForm: React.FC = () => {
>
<div className={style.formPage}>
<div className={style.formBody}>
{current === 0 && (
<Form
form={form}
layout="vertical"
initialValues={{
name: isEdit ? "" : generateDefaultName(),
distributeType: 1,
maxPerDay: 50,
timeType: 1,
}}
disabled={detailLoading}
<Form
form={form}
layout="vertical"
initialValues={{
name: isEdit ? "" : generateDefaultName(),
distributeType: 1,
maxPerDay: 50,
timeType: 1,
}}
disabled={detailLoading}
onFinish={handleFinish2}
style={{ display: current === 0 ? "block" : "none" }}
>
<div className={style.sectionTitle}></div>
<Form.Item
label="计划名称"
name="name"
rules={[{ required: true, message: "请输入计划名称" }]}
>
<div className={style.sectionTitle}></div>
<Input placeholder="流量分发 20250724 1700" maxLength={30} />
</Form.Item>
<Form.Item label="分配方式" name="distributeType" required>
<Radio.Group className={style.radioGroup}>
<Radio value={1}>
<span className={style.radioDesc}>
()
</span>
</Radio>
<Radio value={2}>
<span className={style.radioDesc}>
()
</span>
</Radio>
<Radio value={3}>
<span className={style.radioDesc}>()</span>
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="分配限制" required>
<div className={style.sliderLabelWrap}>
<span></span>
<span className={style.sliderValue}>
{maxPerDay || 0} /
</span>
</div>
<Form.Item
label="计划名称"
name="name"
rules={[{ required: true, message: "请输入计划名称" }]}
name="maxPerDay"
noStyle
rules={[{ required: true, message: "请设置每日最大分配量" }]}
>
<Input placeholder="流量分发 20250724 1700" maxLength={30} />
<Slider min={1} max={100} className={style.slider} />
</Form.Item>
<Form.Item label="分配方式" name="distributeType" required>
<Radio.Group
value={distributeType}
onChange={e => setDistributeType(e.target.value)}
className={style.radioGroup}
>
<Radio value={1}>
<span className={style.radioDesc}>
()
</span>
</Radio>
<Radio value={2}>
<span className={style.radioDesc}>
()
</span>
</Radio>
<Radio value={3}>
<span className={style.radioDesc}>
()
</span>
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="分配限制" required>
<div className={style.sliderLabelWrap}>
<span></span>
<span className={style.sliderValue}>{maxPerDay} /</span>
</div>
<Slider
min={1}
max={100}
value={maxPerDay}
onChange={setMaxPerDay}
className={style.slider}
<div className={style.sliderDesc}></div>
</Form.Item>
<Form.Item label="时间限制" name="timeType" required>
<Radio.Group className={style.radioGroup}>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
</Radio.Group>
</Form.Item>
{timeType === 2 && (
<Form.Item
label=""
name="timeRange"
required
dependencies={["timeType"]}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
if (getFieldValue("timeType") === 1) {
return Promise.resolve();
}
if (value && value.length === 2) {
return Promise.resolve();
}
return Promise.reject(new Error("请选择开始和结束时间"));
},
}),
]}
>
<TimePicker.RangePicker
format="HH:mm"
style={{ width: "100%" }}
/>
<div className={style.sliderDesc}>
</div>
</Form.Item>
<Form.Item label="时间限制" name="timeType" required>
<Radio.Group
value={timeType}
onChange={e => setTimeType(e.target.value)}
className={style.radioGroup}
>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
</Radio.Group>
</Form.Item>
{timeType === 2 && (
<Form.Item label="" required>
<div className={style.timeRangeWrap}>
<div>
<span></span>
<TimePicker
format="HH:mm"
style={{ width: 120 }}
value={timeRange?.[0]}
onChange={v => setTimeRange([v, timeRange?.[1]])}
/>
</div>
<div>
<span></span>
<TimePicker
format="HH:mm"
style={{ width: 120 }}
value={timeRange?.[1]}
onChange={v => setTimeRange([timeRange?.[0], v])}
/>
</div>
</div>
</Form.Item>
)}
</Form>
)}
)}
</Form>
{current === 1 && (
<div>
<div className={style.sectionTitle}></div>

View File

@@ -24,7 +24,7 @@ export function toggleDistributionRuleStatus(
// 删除计划
export function deleteDistributionRule(id: number): Promise<any> {
return request("/v1/workbench/delete", { id }, "POST");
return request("/v1/workbench/delete", { id }, "DELETE");
}
// 获取流量分发规则详情