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(