# -*- coding: utf-8 -*- """各业务端口工作台与子页面端点(企业/载体/服务商/政务)。 列表类页面数据全部由服务端(portal_pages 表)提供;企业发布任务写入 tasks 表。 OPC 端工作台在 ``rbac_opc.py`` 中(按用户聚合)。 """ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from ..dependencies import get_db from ..schemas.portals import EnterpriseTaskCreate, TaskReviewRequest, ReferralCreate from ...rbac import require_roles, write_audit from ...infrastructure.repositories import Database router = APIRouter(tags=["portals"]) # 端口 -> 允许的角色 _PORT_ROLE = { "enterprise": "enterprise", "carrier": "carrier", "provider": "provider", "government": "government", } def _dashboard(port: str): role = _PORT_ROLE.get(port) if role is None: raise HTTPException(status_code=404, detail="Unknown port") async def handler( db: Database = Depends(get_db), _u: dict = Depends(require_roles(role)), ): payload = await db.portal_dashboards.get(port) if payload is None: raise HTTPException(status_code=404, detail="Dashboard not found") return payload return handler def _page(port: str, page: str): role = _PORT_ROLE.get(port) if role is None: raise HTTPException(status_code=404, detail="Unknown port") async def handler( db: Database = Depends(get_db), _u: dict = Depends(require_roles(role)), ): payload = await db.portal_pages.get(port, page) if payload is None: raise HTTPException(status_code=404, detail="Page data not found") payload.setdefault("port", port) payload.setdefault("page", page) return payload return handler router.get("/enterprise/dashboard", summary="企业端工作台")(_dashboard("enterprise")) router.get("/carrier/dashboard", summary="载体/园区端工作台")(_dashboard("carrier")) router.get("/provider/dashboard", summary="服务商端工作台")(_dashboard("provider")) router.get("/government/dashboard", summary="政务端工作台")(_dashboard("government")) # ── 子页面(列表/数据均由服务端提供)────────────────────────────────────── router.get("/enterprise/talents", summary="企业·人才搜索")(_page("enterprise", "talents")) router.get("/carrier/opc", summary="载体·OPC 管理")(_page("carrier", "opc")) router.get("/carrier/services", summary="载体·服务管理")(_page("carrier", "services")) router.get("/provider/orders", summary="服务商·订单管理")(_page("provider", "orders")) router.get("/provider/services", summary="服务商·服务管理")(_page("provider", "services")) router.get("/government/policies", summary="政务·政策管理")(_page("government", "policies")) # ── 企业·任务(发布任务/我的任务)───────────────────────────────────────── @router.get("/enterprise/tasks", summary="企业·我的任务列表") async def enterprise_tasks( db: Database = Depends(get_db), _u: dict = Depends(require_roles("enterprise")), ): return {"items": await db.tasks.list(status="published")} @router.post("/enterprise/tasks", summary="企业·发布任务") async def enterprise_create_task( req: EnterpriseTaskCreate, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_roles("enterprise")), ): task = await db.tasks.create({**req.model_dump(exclude_none=True), "status": "pending"}) await write_audit(db, action="task.publish", resource="task", resource_id=task["id"], detail=task["title"], user=actor, request=request) return task @router.post("/enterprise/tasks/{task_id}/submit", summary="企业·提交审核并发布") async def enterprise_submit_task( task_id: str, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_roles("enterprise")), ): task = await db.tasks.set_status(task_id, "published") if task is None: raise HTTPException(status_code=404, detail="Task not found") await write_audit(db, action="task.submit", resource="task", resource_id=task_id, user=actor, request=request) return task @router.get("/enterprise/tasks/{task_id}/bids", summary="企业·查看竞标") async def enterprise_list_bids( task_id: str, db: Database = Depends(get_db), _u: dict = Depends(require_roles("enterprise")), ): return {"items": await db.bids.list_for_task(task_id)} @router.post("/enterprise/tasks/{task_id}/bids/{bid_id}/win", summary="企业·评标中标") async def enterprise_win_bid( task_id: str, bid_id: str, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_roles("enterprise")), ): bid = await db.bids.set_status(bid_id, "win") if bid is None: raise HTTPException(status_code=404, detail="Bid not found") await db.tasks.set_status(task_id, "in_progress") await write_audit(db, action="bid.win", resource="bid", resource_id=bid_id, detail=f"task={task_id} winner={bid['opc_name']}", user=actor, request=request) return bid @router.post("/enterprise/tasks/{task_id}/review", summary="企业·验收任务") async def enterprise_review_task( task_id: str, req: TaskReviewRequest, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_roles("enterprise")), ): task = await db.tasks.get(task_id) if task is None: raise HTTPException(status_code=404, detail="Task not found") new_status = "completed" if req.action == "accept" else "in_progress" updated = await db.tasks.set_status(task_id, new_status) await write_audit(db, action="task.review", resource="task", resource_id=task_id, detail=req.action, user=actor, request=request) return updated # ── 载体·服务商引荐(三方绑定:载体引荐服务商→服务园区内 OPC)───────────── @router.get("/carrier/referrals", summary="载体·引荐记录") async def carrier_referrals( db: Database = Depends(get_db), user: dict = Depends(require_roles("carrier")), ): return {"items": await db.referrals.list_for(user.get("org_id"))} @router.post("/carrier/referrals", summary="载体·引荐服务商给园区内 OPC") async def carrier_create_referral( req: ReferralCreate, request: Request, db: Database = Depends(get_db), actor: dict = Depends(require_roles("carrier")), ): referral = await db.referrals.create({ **req.model_dump(exclude_none=True), "carrier_id": actor.get("org_id") or actor["id"], }) await write_audit(db, action="referral.create", resource="referral", resource_id=referral["id"], detail=f"{referral['provider_name']}->{referral['opc_name']}", user=actor, request=request) return referral