from __future__ import annotations import json from flask import g, jsonify, request from sqlalchemy import text from app import db from app.api.system import bp from app.core.system.permissions import READ_GOVERNANCE, require_permissions from app.core.workbench.registry import DEFAULT_LAYOUT, WIDGET_REGISTRY, validate_layout from app.models.result import failed, success @bp.route("/workbench/registry", methods=["GET"]) @require_permissions(READ_GOVERNANCE) def workbench_registry(): return jsonify(success(WIDGET_REGISTRY)) @bp.route("/workbench/layout", methods=["GET"]) @require_permissions(READ_GOVERNANCE) def get_workbench_layout(): row = db.session.execute(text("SELECT layout_version, widgets FROM public.workbench_layouts WHERE user_id = CAST(:id AS uuid)"), {"id": g.current_user["id"]}).one_or_none() data = {"version": row[0], "widgets": row[1]} if row else {"version": 0, "widgets": DEFAULT_LAYOUT} return jsonify(success(data)) @bp.route("/workbench/layout", methods=["PUT"]) @require_permissions(READ_GOVERNANCE) def put_workbench_layout(): body = request.get_json(silent=True) or {} try: widgets = validate_layout(body.get("widgets")) expected = int(request.headers.get("If-Match", body.get("version", 0))) except (ValueError, TypeError) as exc: return jsonify(failed(str(exc), code=400)), 400 current = db.session.execute(text("SELECT layout_version FROM public.workbench_layouts WHERE user_id = CAST(:id AS uuid) FOR UPDATE"), {"id": g.current_user["id"]}).scalar_one_or_none() if (current or 0) != expected: db.session.rollback() return jsonify(failed("布局已被其他会话修改", code=409, data={"current_version": current or 0})), 409 new_version = expected + 1 db.session.execute(text("INSERT INTO public.workbench_layouts (user_id, layout_version, widgets) VALUES (CAST(:id AS uuid), :version, CAST(:widgets AS jsonb)) ON CONFLICT (user_id) DO UPDATE SET layout_version = EXCLUDED.layout_version, widgets = EXCLUDED.widgets, updated_at = CURRENT_TIMESTAMP"), {"id": g.current_user["id"], "version": new_version, "widgets": json.dumps(widgets)}) db.session.commit() return jsonify(success({"version": new_version, "widgets": widgets}))