支持创建周期验收项目并延迟首采

This commit is contained in:
2026-09-01 23:27:28 +08:00
parent 9b322cb6dd
commit b2fc2e01f4
3 changed files with 46 additions and 6 deletions

View File

@@ -996,17 +996,34 @@ def create_acceptance_task(data: dict[str, Any]) -> dict[str, Any]:
422,
)
name = str(data.get("name") or "").strip() or f"项目验收|{keywords[0] if keywords else '飞书资料'}"
schedule_requested = data.get("schedule_weekdays") not in (None, [], "")
schedule_weekdays = _normalize_schedule_weekdays(data.get("schedule_weekdays")) if schedule_requested else []
schedule_start = _normalize_schedule_time(data.get("schedule_start_time", "00:00"), "开始时间") if schedule_requested else "00:00"
schedule_end = _normalize_schedule_time(data.get("schedule_end_time", "23:59"), "结束时间") if schedule_requested else "23:59"
if schedule_requested and schedule_start > schedule_end:
raise TaskError("INVALID_SCHEDULE_RANGE", "开始时间不能晚于结束时间", 422)
defer_initial = data.get("defer_initial_collection") is True
initial_status = "completed" if defer_initial else "waiting"
initial_progress = 100 if defer_initial else 0
now = now_iso()
with connection() as conn:
public_id = _public_id()
cursor = conn.execute(
"""INSERT INTO acceptance_tasks
(public_task_id,name,acceptance_method,status,progress_percent,device_count,
created_by_id,created_by_name,created_at,updated_at,trigger_source,cookie_count)
VALUES (?,?,?,'waiting',0,?,?,?,?,?,?,?)""",
(public_id, name, method, device_count, str(data.get("created_by_id") or "local-dev"),
created_by_id,created_by_name,created_at,updated_at,trigger_source,cookie_count,
schedule_enabled,schedule_weekday,schedule_weekdays,schedule_start_time,
schedule_end_time,next_run_at,use_all_devices)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
(public_id, name, method, initial_status, initial_progress, device_count,
str(data.get("created_by_id") or "local-dev"),
str(data.get("created_by_name") or "本地开发用户"), now, now,
str(data.get("trigger_source") or "acceptance"), cookie_count),
str(data.get("trigger_source") or "acceptance"), cookie_count,
1 if schedule_requested else 0, schedule_weekdays[0] if schedule_weekdays else None,
json.dumps(schedule_weekdays) if schedule_weekdays else None,
schedule_start, schedule_end,
_next_weekly_run(schedule_weekdays, schedule_start) if schedule_weekdays else None,
1 if method in {"screenshot", "combined"} else 0),
)
task_id = cursor.lastrowid
conn.executemany(
@@ -1046,6 +1063,7 @@ def create_acceptance_task(data: dict[str, Any]) -> dict[str, Any]:
VALUES (?,?,?,?,'waiting',?,?)""",
[(task_id, index, url, _source_type(url), now, now) for index, url in enumerate(links)],
)
if not defer_initial:
threading.Thread(target=_fetch_sources, args=(public_id,), daemon=True, name=f"acceptance-{public_id}").start()
return get_acceptance_task(public_id)

View File

@@ -222,7 +222,11 @@
"description": "仅用于笔记收录。填写后仅使用该 Cookie;留空时使用 Cookie 池全部可用凭据。不会在任务详情中返回。"
},
"created_by_id": {"type": "string"},
"created_by_name": {"type": "string"}
"created_by_name": {"type": "string"},
"schedule_weekdays": {"type": "array", "items": {"type": "integer", "minimum": 1, "maximum": 7}},
"schedule_start_time": {"type": "string", "example": "20:00"},
"schedule_end_time": {"type": "string", "example": "22:00"},
"defer_initial_collection": {"type": "boolean", "description": "true 时只保存周期项目,不立即启动首批采集"}
}
}
},

View File

@@ -62,6 +62,24 @@ class AcceptanceCreationTest(unittest.TestCase):
self.assertEqual(task["keywords"], ["山姆特价"])
self.assertEqual(task["feishu_links"], [])
@patch("acceptance_service.threading.Thread", _ThreadWithoutStart)
@patch("acceptance_service.get_wen_resources")
def test_create_can_save_schedule_without_starting_initial_collection(self, resources):
resources.return_value = {"cookie_count": 2, "device_count": 3, "credential_ids": ["c1", "c2"]}
task = create_acceptance_task({
"acceptance_method": "combined", "keywords": ["山姆会员卡"],
"match_keywords": ["民生"], "schedule_weekdays": [1, 4],
"schedule_start_time": "20:00", "schedule_end_time": "22:00",
"defer_initial_collection": True,
})
self.assertEqual(task["status"], "completed")
self.assertEqual(task["cookie_count"], 2)
self.assertEqual(task["device_count"], 3)
self.assertEqual(task["schedule_weekdays"], [1, 4])
self.assertEqual(task["schedule_start_time"], "20:00")
self.assertIsNotNone(task["next_run_at"])
self.assertEqual(task["keyword_runs"], [])
@patch("acceptance_service.threading.Thread", _ThreadWithoutStart)
@patch("acceptance_service.get_wen_resources")
def test_active_acceptance_task_can_be_cancelled(self, resources):