Files
server-core/app/api/routers/rbac_opc.py
T
Pine 413bd29390 feat: 业务层 services 抽取(财务/结算/补贴)
- FinanceService:opc_add_finance 直写 ORM 改为走 Repository.create(修复四层依赖违规)
- SettlementService:结算佣金(5%)/电子合同幂等/争议联动/投资撮合评分
- SubsidyService:政务三级审批状态机(区县→市→省→发放)
- rbac_ecosystem/rbac_government/rbac_opc 接线,路由瘦身
2026-08-24 01:54:04 +08:00

277 lines
9.1 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 用户的工作台聚合数据(统计/进行中任务/智能体建议/月度收入/最新消息)。"""
uid = user["id"]
profile = await db.opc_profiles.get(uid)
task_counts = await db.opc_tasks.counts(uid)
opc_tasks = await db.opc_tasks.list_by_user(uid)
# 进行中任务:进行中/紧急优先,取前 3 条
active_tasks = [
t for t in opc_tasks if t["status"] in ("in_progress", "urgent")
][:3]
# 智能体建议(由服务端依据真实数据生成)
policy_count = len(
[c for c in await db.content.list(ctype="policy", status="published")]
)
agent_tips = [
{
"title": "政策匹配提醒",
"desc": f"{policy_count} 项新政策与您高度匹配",
"type": "policy",
},
{
"title": "报税截止提醒",
"desc": "本月报税截止 7月31日",
"type": "tax",
},
{
"title": "技能提升推荐",
"desc": "推荐参加 UI 设计研修班",
"type": "skill",
},
]
return {
"stats": {
"inProgressTasks": task_counts["in_progress"],
"completedTasks": task_counts["completed"],
"totalEarnings": await db.finance.total_income(uid),
"creditScore": (profile or {}).get("credit_score", 80),
},
"activeTasks": active_tasks,
"agentTips": agent_tips,
"monthlyIncome": await db.finance.monthly_income(uid),
"recentMessages": await db.messages.recent(uid, limit=4),
}
# ── 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": []}