Files
qiji/backend/app/api/mini_business_logs.py
T
v6ole 17a0218b32 feat: 商机跟单新增跟进记录子表(后端+API模块)
- 新增 mini_business_logs 表(business_id/log_date/method/content/created_by)
- MiniBusiness 模型添加 logs relationship(cascade delete)
- 5个端点: GET列表/POST新增/PUT编辑/DELETE删除
- 跟进方式: 电话/微信/上门/邮件/其他
- lifespan 自动建表+索引

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-12 18:51:04 +08:00

144 lines
4.8 KiB
Python

"""MiniBusinessLog CRUD API — follow-up log entries for mini business opportunities."""
import uuid
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.middleware.auth import get_current_user, require_any_role
from app.models.mini_business import MiniBusiness
from app.models.mini_business_log import MiniBusinessLog
from app.models.user import User
from app.schemas.mini_business_log import (
MiniBusinessLogCreate, MiniBusinessLogUpdate, MiniBusinessLogOut,
)
router = APIRouter(prefix="/mini-business", tags=["MiniBusiness Logs"])
async def _get_log(db: AsyncSession, log_id: str) -> MiniBusinessLog:
result = await db.execute(select(MiniBusinessLog).where(MiniBusinessLog.id == log_id))
log = result.scalar_one_or_none()
if not log:
raise HTTPException(status_code=404, detail="跟进记录不存在")
return log
@router.get("/{business_id}/logs")
async def list_logs(
business_id: str,
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""List follow-up logs for a mini business, newest first."""
# Verify business exists and user has access
mb = await db.get(MiniBusiness, business_id)
if not mb:
raise HTTPException(status_code=404, detail="商机不存在")
if current_user["role"] == "manager" and str(mb.manager_id) != current_user["user_id"]:
raise HTTPException(status_code=403, detail="Access denied")
result = await db.execute(
select(MiniBusinessLog)
.where(MiniBusinessLog.business_id == business_id)
.order_by(MiniBusinessLog.log_date.desc(), MiniBusinessLog.created_at.desc())
)
logs = result.scalars().all()
# Resolve creator names
user_ids = {log.created_by for log in logs}
users = (await db.execute(select(User).where(User.id.in_(user_ids)))).scalars().all()
user_map = {u.id: u.name for u in users}
return [
{
"id": log.id,
"business_id": log.business_id,
"log_date": str(log.log_date),
"method": log.method,
"content": log.content,
"created_by": log.created_by,
"created_by_name": user_map.get(log.created_by, ""),
"created_at": str(log.created_at) if log.created_at else None,
}
for log in logs
]
@router.post("/{business_id}/logs")
async def create_log(
business_id: str,
data: MiniBusinessLogCreate,
current_user: dict = Depends(require_any_role),
db: AsyncSession = Depends(get_db),
):
"""Add a follow-up log entry."""
mb = await db.get(MiniBusiness, business_id)
if not mb:
raise HTTPException(status_code=404, detail="商机不存在")
if current_user["role"] == "manager" and str(mb.manager_id) != current_user["user_id"]:
raise HTTPException(status_code=403, detail="Access denied")
log = MiniBusinessLog(
business_id=uuid.UUID(business_id),
log_date=data.log_date,
method=data.method,
content=data.content,
created_by=uuid.UUID(current_user["user_id"]),
)
db.add(log)
await db.commit()
await db.refresh(log)
creator = await db.get(User, log.created_by)
return {
"id": log.id,
"business_id": log.business_id,
"log_date": str(log.log_date),
"method": log.method,
"content": log.content,
"created_by": log.created_by,
"created_by_name": creator.name if creator else "",
"created_at": str(log.created_at) if log.created_at else None,
}
@router.put("/logs/{log_id}")
async def update_log(
log_id: str,
data: MiniBusinessLogUpdate,
current_user: dict = Depends(require_any_role),
db: AsyncSession = Depends(get_db),
):
"""Update a follow-up log entry."""
log = await _get_log(db, log_id)
# Managers can only edit their own logs; directors/leaders can edit any
if current_user["role"] == "manager" and str(log.created_by) != current_user["user_id"]:
raise HTTPException(status_code=403, detail="Access denied")
update_data = data.model_dump(exclude_unset=True)
for k, v in update_data.items():
setattr(log, k, v)
await db.commit()
await db.refresh(log)
return {"id": log.id, "log_date": str(log.log_date), "method": log.method, "content": log.content}
@router.delete("/logs/{log_id}")
async def delete_log(
log_id: str,
current_user: dict = Depends(require_any_role),
db: AsyncSession = Depends(get_db),
):
"""Delete a follow-up log entry."""
log = await _get_log(db, log_id)
if current_user["role"] == "manager" and str(log.created_by) != current_user["user_id"]:
raise HTTPException(status_code=403, detail="Access denied")
await db.delete(log)
await db.commit()
return {"status": "deleted"}