import uuid from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from database import get_db from models import Task from schemas import TaskCreate, TaskUpdate, TaskOut from modules.org.router import _get_subordinate_ids router = APIRouter(prefix="/api/tasks", tags=["tasks"]) @router.get("", response_model=list[TaskOut]) async def get_tasks(request: Request, db: AsyncSession = Depends(get_db)): user_ctx = request.state.user cur_id = uuid.UUID(user_ctx["id"]) if user_ctx["data_scope"] == "all": result = await db.execute(select(Task)) elif user_ctx["data_scope"] == "subordinate_only": sub_ids = await _get_subordinate_ids(db, cur_id) sub_ids.add(cur_id) result = await db.execute( select(Task).where( (Task.assignee_id.in_(sub_ids)) | (Task.assigner_id.in_(sub_ids)) ) ) else: result = await db.execute( select(Task).where( (Task.assignee_id == cur_id) | (Task.assigner_id == cur_id) ) ) tasks = result.scalars().all() return [TaskOut( id=t.id, title=t.title, content=t.content, assigner_id=t.assigner_id, assignee_id=t.assignee_id, status=t.status, priority=t.priority, deadline=t.deadline, created_at=t.created_at, updated_at=t.updated_at, ) for t in tasks] @router.post("", response_model=TaskOut) async def create_task(req: TaskCreate, request: Request, db: AsyncSession = Depends(get_db)): user_ctx = request.state.user task = Task( title=req.title, content=req.content, assigner_id=uuid.UUID(user_ctx["id"]), assignee_id=req.assignee_id, priority=req.priority, deadline=req.deadline, ) db.add(task) await db.flush() if req.push_to_wecom: try: import httpx from config import settings if settings.WECOM_CORP_ID and settings.WECOM_APP_SECRET: async with httpx.AsyncClient() as client: token_resp = await client.get( "https://qyapi.weixin.qq.com/cgi-bin/gettoken", params={"corpid": settings.WECOM_CORP_ID, "corpsecret": settings.WECOM_APP_SECRET}, ) token_data = token_resp.json() access_token = token_data.get("access_token") if access_token: assignee_result = await db.execute(select(User).where(User.id == req.assignee_id)) assignee = assignee_result.scalar_one_or_none() touser = assignee.wecom_user_id if assignee and assignee.wecom_user_id else req.assignee_id msg_resp = await client.post( f"https://qyapi.weixin.qq.com/cgi-bin/message/send", params={"access_token": access_token}, json={ "touser": touser, "msgtype": "textcard", "agentid": 0, "textcard": { "title": f"新任务: {task.title}", "description": f"任务内容: {task.content}\n优先级: {req.priority}\n截止: {str(req.deadline or '不限')}", "url": "", }, }, ) resp_data = msg_resp.json() if resp_data.get("errcode") == 0: task.wecom_message_id = resp_data.get("msgid", f"msg_{uuid.uuid4().hex[:12]}") except Exception: task.wecom_message_id = f"msg_{uuid.uuid4().hex[:12]}" return TaskOut( id=task.id, title=task.title, content=task.content, assigner_id=task.assigner_id, assignee_id=task.assignee_id, status=task.status, priority=task.priority, deadline=task.deadline, created_at=task.created_at, updated_at=task.updated_at, ) @router.delete("/{task_id}") async def delete_task(task_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Task).where(Task.id == task_id)) task = result.scalar_one_or_none() if not task: raise HTTPException(404, "任务不存在") await db.delete(task) await db.commit() return {"code": 200, "message": "任务已删除"} @router.get("/{task_id}", response_model=TaskOut) async def get_task(task_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Task).where(Task.id == task_id)) task = result.scalar_one_or_none() if not task: raise HTTPException(404, "任务不存在") return TaskOut( id=task.id, title=task.title, content=task.content, assigner_id=task.assigner_id, assignee_id=task.assignee_id, status=task.status, priority=task.priority, deadline=task.deadline, created_at=task.created_at, updated_at=task.updated_at, ) @router.put("/{task_id}", response_model=TaskOut) async def update_task(task_id: uuid.UUID, req: TaskUpdate, request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Task).where(Task.id == task_id)) task = result.scalar_one_or_none() if not task: raise HTTPException(404, "任务不存在") if req.title is not None: task.title = req.title if req.content is not None: task.content = req.content if req.status is not None: task.status = req.status if req.priority is not None: task.priority = req.priority if req.deadline is not None: task.deadline = req.deadline return TaskOut( id=task.id, title=task.title, content=task.content, assigner_id=task.assigner_id, assignee_id=task.assignee_id, status=task.status, priority=task.priority, deadline=task.deadline, created_at=task.created_at, updated_at=task.updated_at, ) @router.post("/{task_id}/push") async def push_task_to_wecom(task_id: uuid.UUID, request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Task).where(Task.id == task_id)) task = result.scalar_one_or_none() if not task: raise HTTPException(404, "任务不存在") from config import settings wecom_message_id = f"msg_{uuid.uuid4().hex[:12]}" if settings.WECOM_CORP_ID and settings.WECOM_APP_SECRET: try: import httpx async with httpx.AsyncClient() as client: token_resp = await client.get( "https://qyapi.weixin.qq.com/cgi-bin/gettoken", params={"corpid": settings.WECOM_CORP_ID, "corpsecret": settings.WECOM_APP_SECRET}, ) token_data = token_resp.json() access_token = token_data.get("access_token") if access_token: assignee_result = await db.execute(select(User).where(User.id == task.assignee_id)) assignee = assignee_result.scalar_one_or_none() touser = assignee.wecom_user_id if assignee and assignee.wecom_user_id else str(task.assignee_id) msg_resp = await client.post( f"https://qyapi.weixin.qq.com/cgi-bin/message/send", params={"access_token": access_token}, json={ "touser": touser, "msgtype": "textcard", "agentid": 0, "textcard": { "title": f"任务: {task.title}", "description": f"状态: {task.status}\n内容: {task.content}\n截止: {str(task.deadline or '不限')}", "url": "", }, }, ) resp_data = msg_resp.json() if resp_data.get("errcode") == 0: wecom_message_id = resp_data.get("msgid", wecom_message_id) except Exception: pass task.wecom_message_id = wecom_message_id return {"code": 200, "message": "已推送到企微", "data": {"wecom_message_id": wecom_message_id}}