Files
server-core/app/api/routers/rbac_opc.py
T
Pine c99662cfec feat: 业务层 services 抽取完成(工作台/用户管理)
- DashboardService:OPC 工作台聚合(统计/进行中任务/智能体建议/月度收入/消息)
- UserAdminService:建号+默认身份联动、角色分配提权防护(action:role.grant_perm 仅超管)
- rbac_opc dashboard / rbac_admin create_user+set_role 接线
- services 层覆盖全部核心业务域,路由全瘦身
2026-08-24 09:35:08 +08:00

235 lines
7.7 KiB
Python

# -*- coding: utf-8 -*-
"""OPC 超级个体端端点(工作台聚合数据)。
所有数据均由服务端(SQLite 演示库)提供,前端不落地任何演示数据。
当前角色要求 opc_member;后续各页面端点在此扩展。
"""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from ..dependencies import get_db
from ...rbac import require_roles, write_audit
from ...infrastructure.repositories import Database, new_id, utcnow_iso
from ...infrastructure.models import FinanceRecord
router = APIRouter(prefix="/opc", tags=["opc"])
@router.get("/dashboard", summary="OPC 工作台总览")
async def opc_dashboard(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
"""返回当前 OPC 用户的工作台聚合数据(统计/进行中任务/智能体建议/月度收入/最新消息)。"""
from ...services.dashboard_service import DashboardService
return await DashboardService(db).opc_dashboard(user["id"])
# ── OPC 子页面(全部由服务端提供标准数据)─────────────────────────────────
@router.get("/agent", summary="OPC 智能体助手")
async def opc_agent(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
agents = await db.agents.get_by_user(user["id"], port=user.get("port") or "opc")
default = next((a for a in agents if a.get("id", "").startswith("pine_agents_official_001")), None)
return {
"agent": {
"name": (default or {}).get("name", "小云"),
"desc": (default or {}).get("description", "您的智能体助手,可处理创业、政策、财税等事务"),
"port": user.get("port") or "opc",
},
"quick_actions": [
{"title": "查询政策", "desc": "为您匹配最新创业政策"},
{"title": "发布能力", "desc": "快速发布您的服务能力"},
{"title": "财务助手", "desc": "查看收入与支出"},
],
"chat_path": "/chat",
}
@router.get("/tasks", summary="任务广场(已发布平台任务)")
async def opc_task_square(
db: Database = Depends(get_db),
_u: dict = Depends(require_roles("opc_member")),
):
return {"items": await db.tasks.list(status="published")}
@router.get("/my-tasks", summary="我的任务看板")
async def opc_my_tasks(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
return {"items": await db.opc_tasks.list_by_user(user["id"])}
@router.get("/services", summary="服务市场(在营服务商)")
async def opc_services(
db: Database = Depends(get_db),
_u: dict = Depends(require_roles("opc_member")),
):
return {"items": await db.providers.list(status="active")}
@router.get("/policy", summary="政策列表(已发布政策)")
async def opc_policy(
db: Database = Depends(get_db),
_u: dict = Depends(require_roles("opc_member")),
):
return {"items": await db.content.list(ctype="policy", status="published")}
@router.get("/finance", summary="财务流水")
async def opc_finance(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
uid = user["id"]
return {
"records": await db.finance.list_by_user(uid),
"total_income": await db.finance.total_income(uid),
}
@router.get("/messages", summary="站内消息")
async def opc_messages(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
return {"items": await db.messages.list_by_user(user["id"])}
@router.get("/profile", summary="个人资料")
async def opc_profile(
db: Database = Depends(get_db),
user: dict = Depends(require_roles("opc_member")),
):
profile = await db.users.to_profile(user)
profile["opc_profile"] = await db.opc_profiles.get(user["id"])
return profile
class BidRequest(BaseModel):
quote: int = 0
plan: str = ""
@router.post("/tasks/{task_id}/grab", summary="OPC 抢单")
async def opc_grab(
task_id: str,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_roles("opc_member")),
):
from ...services.task_service import TaskService
updated = await TaskService(db).grab(task_id, actor)
await write_audit(db, action="task.grab", resource="task", resource_id=task_id,
detail=actor.get("username"), user=actor, request=request)
return updated
@router.post("/tasks/{task_id}/bid", summary="OPC 投标")
async def opc_bid(
task_id: str,
req: BidRequest,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_roles("opc_member")),
):
from ...services.task_service import TaskService
bid = await TaskService(db).bid(task_id, actor, req.quote, req.plan)
await write_audit(db, action="task.bid", resource="bid", resource_id=bid["id"],
user=actor, request=request)
return bid
@router.post("/tasks/{task_id}/deliver", summary="OPC 交付")
async def opc_deliver(
task_id: str,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_roles("opc_member")),
):
from ...services.task_service import TaskService
updated = await TaskService(db).deliver(task_id, actor)
await write_audit(db, action="task.deliver", resource="task", resource_id=task_id,
user=actor, request=request)
return updated
class ProfileUpdate(BaseModel):
nickname: str | None = None
account: str | None = None
company: str | None = None
room: str | None = None
skills: list[str] = []
credit_score: int | None = None
@router.put("/profile", summary="OPC 基础资料编辑")
async def opc_update_profile(
req: ProfileUpdate,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_roles("opc_member")),
):
profile_updates = {k: v for k, v in req.model_dump(exclude_none=True).items()
if k in ("nickname", "account", "company", "room")}
if profile_updates:
await db.users.update_profile(actor["id"], profile_updates)
if req.credit_score is not None:
await db.opc_profiles.upsert(actor["id"], req.credit_score)
await write_audit(db, action="profile.update", resource="user", resource_id=actor["id"],
user=actor, request=request)
fresh_user = await db.users.get_by_id(actor["id"])
return await opc_profile(db, fresh_user)
class FinanceRecordCreate(BaseModel):
category: str = "income" # income | expense
amount: int
date: str = ""
note: str = ""
@router.post("/finance/record", summary="OPC 记一笔收支")
async def opc_add_finance(
req: FinanceRecordCreate,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_roles("opc_member")),
):
from ...services.finance_service import FinanceService
record = await FinanceService(db).add_record(
user_id=actor["id"], category=req.category, amount=req.amount,
date=req.date or utcnow_iso()[:10], note=req.note,
)
await write_audit(db, action="finance.add", resource="finance", resource_id=record["id"],
user=actor, request=request)
return record
@router.get("/tax", summary="OPC 税务申报")
async def opc_tax(
db: Database = Depends(get_db),
_u: dict = Depends(require_roles("opc_member")),
):
return await db.portal_pages.get("opc", "tax") or {"items": []}
@router.get("/affairs", summary="OPC 工商/政务办事")
async def opc_affairs(
db: Database = Depends(get_db),
_u: dict = Depends(require_roles("opc_member")),
):
return await db.portal_pages.get("opc", "affairs") or {"items": []}