diff --git a/frontend/app/features/schedules/NodeInspector.tsx b/frontend/app/features/schedules/NodeInspector.tsx index dc0d0c5..9a61093 100644 --- a/frontend/app/features/schedules/NodeInspector.tsx +++ b/frontend/app/features/schedules/NodeInspector.tsx @@ -1,15 +1,7 @@ import { type ScheduleNode } from "../../services/api"; import Icon from "../../components/common/Icon"; import { shortHash } from "./utils"; - -type NodeForm = { - nodeName: string; - timeoutSeconds: string; - retryCount: string; - retryIntervalSec: string; - argumentsJson: string; - envRefsJson: string; -}; +import { PYTHON_VERSION_OPTIONS, type NodeForm } from "./state/schedulesStore"; export function NodeInspector({ node, @@ -88,18 +80,36 @@ export function NodeInspector({ /> - +
+ + +

运行参数

diff --git a/frontend/app/features/schedules/constants.ts b/frontend/app/features/schedules/constants.ts index a272801..1541b76 100644 --- a/frontend/app/features/schedules/constants.ts +++ b/frontend/app/features/schedules/constants.ts @@ -24,6 +24,7 @@ export const EMPTY_NODE_FORM = { retryIntervalSec: "5", argumentsJson: "{}", envRefsJson: "{}", + pythonVersion: "3.12" as "3.8" | "3.10" | "3.12", }; export const RUN_STATUS_LABELS: Record = { diff --git a/frontend/app/features/schedules/state/schedulesStore.ts b/frontend/app/features/schedules/state/schedulesStore.ts index c9870aa..d2adf39 100644 --- a/frontend/app/features/schedules/state/schedulesStore.ts +++ b/frontend/app/features/schedules/state/schedulesStore.ts @@ -33,6 +33,14 @@ export type ScheduleForm = { failurePolicy: "stop" | "continue"; }; +export type PythonVersion = "3.8" | "3.10" | "3.12"; + +export const PYTHON_VERSION_OPTIONS: readonly PythonVersion[] = [ + "3.8", + "3.10", + "3.12", +]; + export type NodeForm = { nodeName: string; timeoutSeconds: string; @@ -40,6 +48,7 @@ export type NodeForm = { retryIntervalSec: string; argumentsJson: string; envRefsJson: string; + pythonVersion: PythonVersion; }; export type NodePositionDraft = { @@ -77,6 +86,7 @@ export const EMPTY_NODE_FORM: NodeForm = { retryIntervalSec: "5", argumentsJson: "{}", envRefsJson: "{}", + pythonVersion: "3.12", }; // ---- Module-level non-reactive holders ---- @@ -124,6 +134,7 @@ function nodeToForm(node: ScheduleNode): NodeForm { retryIntervalSec: String(node.retry_interval_sec), argumentsJson: JSON.stringify(node.arguments_json ?? {}, null, 2), envRefsJson: JSON.stringify(node.env_refs_json ?? {}, null, 2), + pythonVersion: (node.python_version ?? "3.12") as PythonVersion, }; } @@ -855,6 +866,7 @@ export const useSchedulesStore = create((set, get) => { position_y: Math.max(20, Math.round(positionY)), arguments_json: {}, env_refs_json: {}, + python_version: "3.12", }), `${artifact.script_name} 已加入画布`, ); @@ -883,6 +895,9 @@ export const useSchedulesStore = create((set, get) => { if (!Number.isInteger(retryIntervalSec) || retryIntervalSec < 0) { throw new Error("重试间隔必须是非负整数"); } + if (!PYTHON_VERSION_OPTIONS.includes(nodeForm.pythonVersion)) { + throw new Error("Python 版本必须是 3.8 / 3.10 / 3.12"); + } const argumentsJson = parseObject(nodeForm.argumentsJson, "运行参数"); const rawEnv = parseObject(nodeForm.envRefsJson, "环境引用"); const envRefsJson = Object.fromEntries( @@ -907,6 +922,7 @@ export const useSchedulesStore = create((set, get) => { retry_interval_sec: retryIntervalSec, arguments_json: argumentsJson, env_refs_json: envRefsJson, + python_version: nodeForm.pythonVersion, }, ), "节点配置已保存", diff --git a/frontend/app/features/schedules/utils.ts b/frontend/app/features/schedules/utils.ts index befb897..7a2822b 100644 --- a/frontend/app/features/schedules/utils.ts +++ b/frontend/app/features/schedules/utils.ts @@ -6,6 +6,7 @@ import { type ScheduleRunSummary, } from "../../services/api"; import { EMPTY_SCHEDULE_FORM, EMPTY_NODE_FORM } from "./constants"; +import type { NodeForm } from "./state/schedulesStore"; export function formatTime(value: string | null): string { if (!value) return "尚未执行"; @@ -82,7 +83,7 @@ export function scheduleToForm(schedule: Schedule) { }; } -export function nodeToForm(node: ScheduleNode) { +export function nodeToForm(node: ScheduleNode): NodeForm { return { nodeName: node.node_name, timeoutSeconds: String(node.timeout_seconds), @@ -90,6 +91,7 @@ export function nodeToForm(node: ScheduleNode) { retryIntervalSec: String(node.retry_interval_sec), argumentsJson: JSON.stringify(node.arguments_json ?? {}, null, 2), envRefsJson: JSON.stringify(node.env_refs_json ?? {}, null, 2), + pythonVersion: node.python_version ?? "3.12", }; } diff --git a/frontend/app/services/api.ts b/frontend/app/services/api.ts index bef60ae..8e4601a 100644 --- a/frontend/app/services/api.ts +++ b/frontend/app/services/api.ts @@ -658,6 +658,8 @@ export type ScheduleArtifact = { created_at: string; }; +export type PythonVersion = "3.8" | "3.10" | "3.12"; + export type ScheduleNode = { node_id: string; schedule_id: string; @@ -671,6 +673,7 @@ export type ScheduleNode = { position_y: number; arguments_json: Record; env_refs_json: Record; + python_version: PythonVersion; created_at: string; updated_at: string; version: { @@ -1093,6 +1096,7 @@ export async function createScheduleNode( position_y?: number; arguments_json?: Record; env_refs_json?: Record; + python_version?: PythonVersion; }, ): Promise { return apiRequest( @@ -1117,6 +1121,7 @@ export async function updateScheduleNode( position_y?: number; arguments_json?: Record; env_refs_json?: Record; + python_version?: PythonVersion; }, ): Promise { return apiRequest(