feat: 支持 uv 从 pyproject/requirements 创建虚拟环境

- 工作目录探测新增 pyproject.toml / requirements*.txt 扫描、uv 可用性与 can_create
- 新增 POST /api/v1/python/venv/create:已有虚拟环境优先复用;pyproject 走 uv sync,requirements 走 uv venv + uv pip install,并使用默认 PyPI 镜像
- 编辑器在缺少虚拟环境且具备依赖文件时显示「用 uv 创建环境」;没有 uv 或没有依赖文件时明确报错
- 解释器字段改为可选,留空由服务端默认 python.exe 并使用虚拟环境;Python 任务缺少虚拟环境/依赖文件时运行直接失败,不再回退系统解释器
- 补后端探测/创建测试、前端入口测试与 README
This commit is contained in:
2026-11-03 22:57:17 +08:00
parent 29fc579275
commit 8e6b3b92b9
14 changed files with 759 additions and 70 deletions
+16
View File
@@ -28,6 +28,7 @@ pub async fn create(pool: &SqlitePool, mut request: CreateTaskRequest) -> ApiRes
request.name = request.name.trim().to_owned();
request.cron = request.cron.trim().to_owned();
request.timezone = request.timezone.trim().to_owned();
normalize_action(&mut request.action);
validate_task_id(&request.id)?;
validate_common(
@@ -57,6 +58,7 @@ pub async fn update(
request.name = request.name.trim().to_owned();
request.cron = request.cron.trim().to_owned();
request.timezone = request.timezone.trim().to_owned();
normalize_action(&mut request.action);
validate_common(
&request.name,
@@ -180,6 +182,20 @@ fn validate_common(
Ok(())
}
fn normalize_action(action: &mut TaskAction) {
if let TaskAction::Script {
venv, interpreter, ..
} = action
{
if interpreter.trim().is_empty() {
*interpreter = "python.exe".to_owned();
}
if venv.as_deref().is_some_and(|value| value.trim().is_empty()) {
*venv = None;
}
}
}
fn validate_action(action: &TaskAction) -> ApiResult<()> {
match action {
TaskAction::Script {