微信小程序页面迁移校验之前 P5任务处理之前

This commit is contained in:
Neo
2026-03-09 01:19:21 +08:00
parent 263bf96035
commit 6e20987d2f
1112 changed files with 153824 additions and 219694 deletions

View File

@@ -25,6 +25,12 @@ import {
Tooltip,
Segmented,
Spin,
Modal,
Form,
Select,
TimePicker,
Descriptions,
Tag,
} from "antd";
import {
SendOutlined,
@@ -35,16 +41,20 @@ import {
SyncOutlined,
ShopOutlined,
ApiOutlined,
ScheduleOutlined,
} from "@ant-design/icons";
import { useNavigate } from "react-router-dom";
import TaskSelector from "../components/TaskSelector";
import { validateTaskConfig, fetchFlows } from "../api/tasks";
import type { FlowDef, ProcessingModeDef } from "../api/tasks";
import { submitToQueue, executeDirectly } from "../api/execution";
import { createSchedule } from "../api/schedules";
import { useAuthStore } from "../store/authStore";
import BusinessDayHint from "../components/BusinessDayHint";
import type { RadioChangeEvent } from "antd";
import type { Dayjs } from "dayjs";
import type { TaskConfig as TaskConfigType } from "../types";
import dayjs from "dayjs";
import type { TaskConfig as TaskConfigType, ScheduleConfig } from "../types";
const { Title, Text } = Typography;
const { TextArea } = Input;
@@ -224,6 +234,12 @@ const TaskConfig: React.FC = () => {
const [forceFull, setForceFull] = useState(false);
const [useLocalJson, setUseLocalJson] = useState(false);
/* ---------- Pipeline 调优 ---------- */
const [pipelineWorkers, setPipelineWorkers] = useState<number | null>(null);
const [pipelineBatchSize, setPipelineBatchSize] = useState<number | null>(null);
const [pipelineRateMin, setPipelineRateMin] = useState<number | null>(null);
const [pipelineRateMax, setPipelineRateMax] = useState<number | null>(null);
/* ---------- CLI 预览 ---------- */
const [cliCommand, setCliCommand] = useState<string>("");
const [cliEdited, setCliEdited] = useState(false);
@@ -232,6 +248,12 @@ const TaskConfig: React.FC = () => {
/* ---------- 提交状态 ---------- */
const [submitting, setSubmitting] = useState(false);
/* ---------- 调度任务弹窗 ---------- */
const [scheduleModalOpen, setScheduleModalOpen] = useState(false);
const [scheduleSubmitting, setScheduleSubmitting] = useState(false);
const [scheduleType, setScheduleType] = useState<string>("daily");
const [scheduleForm] = Form.useForm();
/* ---------- 派生状态 ---------- */
const layers = flowDefs[flow]?.layers ?? [];
const showVerifyOption = processingMode === "verify_only";
@@ -262,6 +284,10 @@ const TaskConfig: React.FC = () => {
/* CHANGE [2026-02-19] intent: DWD 表正向勾选,选中=装载 */
dwd_only_tables: layers.includes("DWD") ? (selectedDwdTables.length > 0 ? selectedDwdTables : null) : null,
force_full: forceFull,
pipeline_workers: pipelineWorkers,
pipeline_batch_size: pipelineBatchSize,
pipeline_rate_min: pipelineRateMin,
pipeline_rate_max: pipelineRateMax,
extra_args: {},
};
};
@@ -288,7 +314,8 @@ const TaskConfig: React.FC = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [flow, processingMode, fetchBeforeVerify, windowMode, lookbackHours, overlapSeconds,
windowStart, windowEnd, windowSplitDays, selectedTasks, selectedDwdTables,
dryRun, forceFull, useLocalJson, selectedConnectorStores]);
dryRun, forceFull, useLocalJson, selectedConnectorStores,
pipelineWorkers, pipelineBatchSize, pipelineRateMin, pipelineRateMax]);
/* ---------- 事件处理 ---------- */
const handleFlowChange = (e: RadioChangeEvent) => setFlow(e.target.value);
@@ -321,6 +348,67 @@ const TaskConfig: React.FC = () => {
}
};
/* ---------- 调度任务弹窗 ---------- */
const handleOpenScheduleModal = () => {
scheduleForm.resetFields();
scheduleForm.setFieldsValue({
schedule_config: {
schedule_type: "daily",
interval_value: 1,
interval_unit: "hours",
daily_time: dayjs("04:00", "HH:mm"),
weekly_days: [1],
weekly_time: dayjs("04:00", "HH:mm"),
cron_expression: "0 4 * * *",
},
});
setScheduleType("daily");
setScheduleModalOpen(true);
};
const handleScheduleSubmit = async () => {
try {
const values = await scheduleForm.validateFields();
setScheduleSubmitting(true);
const cfg = { ...values.schedule_config };
if (cfg.daily_time && typeof cfg.daily_time !== "string") {
cfg.daily_time = cfg.daily_time.format("HH:mm");
}
if (cfg.weekly_time && typeof cfg.weekly_time !== "string") {
cfg.weekly_time = cfg.weekly_time.format("HH:mm");
}
const scheduleConfig: ScheduleConfig = {
schedule_type: cfg.schedule_type ?? "daily",
interval_value: cfg.interval_value ?? 1,
interval_unit: cfg.interval_unit ?? "hours",
daily_time: cfg.daily_time ?? "04:00",
weekly_days: cfg.weekly_days ?? [1],
weekly_time: cfg.weekly_time ?? "04:00",
cron_expression: cfg.cron_expression ?? "0 4 * * *",
enabled: true,
start_date: null,
end_date: null,
};
const taskConfig = buildTaskConfig();
await createSchedule({
name: values.name,
task_codes: taskConfig.tasks,
task_config: taskConfig,
schedule_config: scheduleConfig,
run_immediately: !!values.run_immediately,
});
message.success("调度任务已创建");
setScheduleModalOpen(false);
} catch {
// 表单验证失败
} finally {
setScheduleSubmitting(false);
}
};
/* ---------- 样式常量 ---------- */
const cardStyle = { marginBottom: 12 };
const sectionTitleStyle: React.CSSProperties = {
@@ -464,6 +552,7 @@ const TaskConfig: React.FC = () => {
</Col>
</Row>
) : (
<>
<Row gutter={16}>
<Col span={12}>
<Text style={sectionTitleStyle}></Text>
@@ -481,6 +570,10 @@ const TaskConfig: React.FC = () => {
/>
</Col>
</Row>
<div style={{ marginTop: 4 }}>
<BusinessDayHint />
</div>
</>
)}
<div style={{ marginTop: 12 }}>
@@ -526,6 +619,65 @@ const TaskConfig: React.FC = () => {
</div>
</Col>
</Row>
{/* Pipeline 调优参数 */}
<div style={{ marginTop: 12, borderTop: "1px solid #f0f0f0", paddingTop: 12 }}>
<Text type="secondary" style={{ fontSize: 12, marginBottom: 8, display: "block" }}>
Pipeline 使
</Text>
<Row gutter={[24, 8]}>
<Col span={6}>
<Text style={{ fontSize: 12 }}> workers</Text>
<InputNumber
size="small"
min={1}
max={32}
placeholder="默认 3"
value={pipelineWorkers}
onChange={(v) => setPipelineWorkers(v)}
style={{ width: "100%" }}
/>
</Col>
<Col span={6}>
<Text style={{ fontSize: 12 }}></Text>
<InputNumber
size="small"
min={1}
max={10000}
placeholder="默认 200"
value={pipelineBatchSize}
onChange={(v) => setPipelineBatchSize(v)}
style={{ width: "100%" }}
/>
</Col>
<Col span={6}>
<Text style={{ fontSize: 12 }}>()</Text>
<InputNumber
size="small"
min={0}
max={60}
step={0.1}
placeholder="默认 1.0"
value={pipelineRateMin}
onChange={(v) => setPipelineRateMin(v)}
style={{ width: "100%" }}
/>
</Col>
<Col span={6}>
<Text style={{ fontSize: 12 }}>()</Text>
<InputNumber
size="small"
min={0}
max={60}
step={0.1}
placeholder="默认 3.0"
value={pipelineRateMax}
onChange={(v) => setPipelineRateMax(v)}
style={{ width: "100%" }}
/>
</Col>
</Row>
</div>
</Card>
{/* ---- 任务选择(含 DWD 表过滤) ---- */}
@@ -587,26 +739,142 @@ const TaskConfig: React.FC = () => {
{/* ---- 操作按钮 ---- */}
<Card size="small" style={{ marginBottom: 24 }}>
<Space size="middle">
<Button
type="primary"
size="large"
icon={<SendOutlined />}
loading={submitting}
onClick={handleSubmitToQueue}
>
</Button>
<div style={{ display: "flex", alignItems: "center" }}>
<Space size="middle">
<Button
type="primary"
size="large"
icon={<SendOutlined />}
loading={submitting}
onClick={handleSubmitToQueue}
>
</Button>
<Button
size="large"
icon={<ScheduleOutlined />}
onClick={handleOpenScheduleModal}
>
</Button>
</Space>
<div style={{ flex: 1 }} />
<Button
size="large"
icon={<ThunderboltOutlined />}
loading={submitting}
onClick={handleExecuteDirectly}
>
</Button>
</Space>
</div>
</Card>
{/* ---- 调度任务创建 Modal ---- */}
<Modal
title="添加到调度任务"
open={scheduleModalOpen}
onOk={handleScheduleSubmit}
onCancel={() => setScheduleModalOpen(false)}
confirmLoading={scheduleSubmitting}
destroyOnClose
width={560}
>
{/* 当前配置摘要(只读) */}
<Descriptions
column={1}
bordered
size="small"
style={{ marginBottom: 16 }}
title="当前任务配置(只读)"
>
<Descriptions.Item label="任务">
{selectedTasks.length > 0
? selectedTasks.map((t) => <Tag key={t}>{t}</Tag>)
: <Text type="secondary"></Text>}
</Descriptions.Item>
<Descriptions.Item label="Flow">
<Tag>{flow}</Tag>
</Descriptions.Item>
<Descriptions.Item label="处理模式">{processingMode}</Descriptions.Item>
<Descriptions.Item label="时间窗口">
{windowMode === "lookback"
? `回溯 ${lookbackHours} 小时`
: `${windowStart?.format("YYYY-MM-DD") ?? "?"} ~ ${windowEnd?.format("YYYY-MM-DD") ?? "?"}`}
</Descriptions.Item>
</Descriptions>
<Form form={scheduleForm} layout="vertical" preserve={false}>
<Form.Item
name="name"
label="调度任务名称"
rules={[{ required: true, message: "请输入调度任务名称" }]}
>
<Input placeholder="例如:每日全量同步" />
</Form.Item>
<Form.Item
name={["schedule_config", "schedule_type"]}
label="调度类型"
rules={[{ required: true }]}
>
<Select
options={[
{ label: "一次性", value: "once" },
{ label: "固定间隔", value: "interval" },
{ label: "每日", value: "daily" },
{ label: "每周", value: "weekly" },
{ label: "Cron", value: "cron" },
]}
onChange={(v: string) => setScheduleType(v)}
/>
</Form.Item>
{scheduleType === "interval" && (
<Space>
<Form.Item name={["schedule_config", "interval_value"]} noStyle rules={[{ required: true }]}>
<InputNumber min={1} placeholder="间隔值" />
</Form.Item>
<Form.Item name={["schedule_config", "interval_unit"]} noStyle rules={[{ required: true }]}>
<Select style={{ width: 100 }} options={[
{ label: "分钟", value: "minutes" },
{ label: "小时", value: "hours" },
{ label: "天", value: "days" },
]} />
</Form.Item>
</Space>
)}
{scheduleType === "daily" && (
<Form.Item name={["schedule_config", "daily_time"]} label="执行时间" rules={[{ required: true }]}>
<TimePicker format="HH:mm" />
</Form.Item>
)}
{scheduleType === "weekly" && (
<>
<Form.Item name={["schedule_config", "weekly_days"]} label="星期" rules={[{ required: true }]}>
<Checkbox.Group options={[
{ label: "周一", value: 1 }, { label: "周二", value: 2 },
{ label: "周三", value: 3 }, { label: "周四", value: 4 },
{ label: "周五", value: 5 }, { label: "周六", value: 6 },
{ label: "周日", value: 0 },
]} />
</Form.Item>
<Form.Item name={["schedule_config", "weekly_time"]} label="执行时间" rules={[{ required: true }]}>
<TimePicker format="HH:mm" />
</Form.Item>
</>
)}
{scheduleType === "cron" && (
<Form.Item name={["schedule_config", "cron_expression"]} label="Cron 表达式" rules={[{ required: true }]}>
<Input placeholder="0 4 * * *" />
</Form.Item>
)}
<Form.Item name="run_immediately" valuePropName="checked" style={{ marginBottom: 0 }}>
<Checkbox></Checkbox>
</Form.Item>
</Form>
</Modal>
</div>
);
};