# -*- coding: utf-8 -*- """运营端 → 培训子应用数据桥接(课程 / 活动 / 报名 / 测评)。 培训业务数据存于 app.training(独立 serverdata/data/opc.db);运营端 /admin/* 端点在此聚合读写,避免在平台应用重建一套课程/活动模型。 仅作适度封装(list / create / status / patch),状态与原 mock 语义保持一致; 创建统一生成 id(前缀 C- / E- / B- / T-),时间用 UTC ISO。 """ from __future__ import annotations import json from datetime import datetime, timezone from app.training import db as tdb def _now() -> str: return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") # ── 课程(courses 表)──────────────────────────────────────────────────── def list_courses(status: str | None = None) -> list[dict]: rows = tdb.list_all("courses", "created_at DESC") if status: return [r for r in rows if r.get("status") == status] return rows def create_course(data: dict) -> dict: row = dict(data) row["id"] = tdb.gen_id("C-") row.setdefault("created_at", _now()) row.setdefault("status", "draft") tdb.insert("courses", row) return tdb.fetch_by_id("courses", row["id"]) def set_course_status(course_id: str, status: str) -> dict | None: if tdb.fetch_by_id("courses", course_id) is None: return None tdb.update_row("courses", course_id, {"status": status}) return tdb.fetch_by_id("courses", course_id) def update_course(course_id: str, patch: dict) -> dict | None: if tdb.fetch_by_id("courses", course_id) is None: return None if patch: tdb.update_row("courses", course_id, patch) return tdb.fetch_by_id("courses", course_id) def delete_course(course_id: str) -> bool: if tdb.fetch_by_id("courses", course_id) is None: return False tdb.delete_row("courses", course_id) return True # ── 活动(events 表)───────────────────────────────────────────────────── def list_activities(status: str | None = None) -> list[dict]: rows = tdb.list_all("events", "start_at DESC") if status: return [r for r in rows if r.get("status") == status] return rows def create_activity(data: dict) -> dict: row = dict(data) row["id"] = tdb.gen_id("E-") row.setdefault("mode", "offline") row.setdefault("status", "open") row.setdefault("duration_min", 90) tdb.insert("events", row) return tdb.fetch_by_id("events", row["id"]) def set_activity_status(event_id: str, status: str) -> dict | None: if tdb.fetch_by_id("events", event_id) is None: return None tdb.update_row("events", event_id, {"status": status}) return tdb.fetch_by_id("events", event_id) def update_activity(event_id: str, patch: dict) -> dict | None: if tdb.fetch_by_id("events", event_id) is None: return None if patch: tdb.update_row("events", event_id, patch) return tdb.fetch_by_id("events", event_id) def delete_activity(event_id: str) -> bool: if tdb.fetch_by_id("events", event_id) is None: return False tdb.delete_row("events", event_id) return True # ── 报名(bookings 表)─────────────────────────────────────────────────── def list_bookings(status: str | None = None, audit_status: str | None = None) -> list[dict]: rows = tdb.list_all("bookings", "created_at DESC") if status: rows = [r for r in rows if r.get("status") == status] if audit_status: rows = [r for r in rows if r.get("audit_status") == audit_status] # 映射为运营端 Booking 视图 return [pack_booking(r) for r in rows] def pack_booking(r: dict) -> dict: return { "id": r.get("id"), "user_id": r.get("username"), "user_name": r.get("name"), "target_type": "event", "target_id": r.get("event_id"), "target_title": r.get("event_title"), "status": r.get("status"), "audit_status": r.get("audit_status"), "note": r.get("question"), "created_at": r.get("created_at"), } def update_booking(booking_id: str, patch: dict) -> dict | None: if tdb.fetch_by_id("bookings", booking_id) is None: return None allowed = {k: v for k, v in patch.items() if k in ("status", "audit_status", "note", "question")} if "note" in allowed: allowed["question"] = allowed.pop("note") if allowed: tdb.update_row("bookings", booking_id, allowed) return pack_booking(tdb.fetch_by_id("bookings", booking_id)) # ── 测评(tests 表:OPC 适配度测评记录)───────────────────────────────────── def list_tests() -> list[dict]: rows = tdb.list_all("tests", "created_at DESC") return [pack_test(r) for r in rows] def pack_test(r: dict) -> dict: return { "id": r.get("id"), "title": r.get("persona") or "OPC 适配度测评", "category": r.get("type_code"), "pass_score": 0, "question_count": 30, "status": "completed", "adapt_level": r.get("adapt_level"), "tracks": r.get("tracks"), "created_at": r.get("created_at"), } def pack_test_if_exists(test_id: str) -> dict | None: row = tdb.fetch_by_id("tests", test_id) return pack_test(row) if row else None def create_test(data: dict) -> dict: row = { "id": tdb.gen_id("T-"), "created_at": _now(), "username": "", "type_code": data.get("category", "opc"), "persona": data.get("title", "OPC 适配度测评"), "adapt_level": "", "tracks": data.get("tracks", ""), "version": "", } tdb.insert("tests", row) return pack_test(tdb.fetch_by_id("tests", row["id"])) def _parse_json(raw): if raw is None: return None if isinstance(raw, (dict, list)): return raw try: return json.loads(raw) except (TypeError, ValueError): return raw # ── 调研(survey_logs 表)───────────────────────────────────────────────── def list_surveys() -> list[dict]: rows = tdb.list_all("survey_logs", "created_at DESC") return [ { "id": r.get("id"), "username": r.get("username"), "source": r.get("source"), "answers": _parse_json(r.get("answers")), "created_at": r.get("created_at"), } for r in rows ] # ── 政策(policy_logs 表)───────────────────────────────────────────────── def list_policies() -> list[dict]: rows = tdb.list_all("policy_logs", "created_at DESC") return [ { "id": r.get("id"), "username": r.get("username"), "answers": _parse_json(r.get("answers")), "policies_count": r.get("policies_count"), "subsidies_count": r.get("subsidies_count"), "loans_count": r.get("loans_count"), "summary": r.get("summary"), "created_at": r.get("created_at"), } for r in rows ] # ── 流程(plan_logs 表)─────────────────────────────────────────────────── def list_plans() -> list[dict]: rows = tdb.list_all("plan_logs", "created_at DESC") return [ { "id": r.get("id"), "username": r.get("username"), "region": r.get("region"), "status": r.get("status"), "need_park": r.get("need_park"), "has_staff": r.get("has_staff"), "steps_count": r.get("steps_count"), "created_at": r.get("created_at"), } for r in rows ]