微信小程序页面迁移校验之前 P5任务处理之前
This commit is contained in:
102
apps/backend/app/routers/member_retention_clue.py
Normal file
102
apps/backend/app/routers/member_retention_clue.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
维客线索路由。
|
||||
|
||||
- POST /api/retention-clue — 提交维客线索(UPSERT)
|
||||
- GET /api/retention-clue/{member_id} — 查询某会员的全部维客线索
|
||||
- DELETE /api/retention-clue/{clue_id} — 删除单条线索
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
|
||||
from app.database import get_connection
|
||||
from app.schemas.member_retention_clue import RetentionClueSubmit, RetentionClueOut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["维客线索"])
|
||||
|
||||
|
||||
@router.post("/retention-clue")
|
||||
async def submit_retention_clue(body: RetentionClueSubmit):
|
||||
"""
|
||||
提交维客线索(INSERT)。
|
||||
|
||||
同一会员可有多条不同大类的线索。
|
||||
"""
|
||||
sql = """
|
||||
INSERT INTO member_retention_clue
|
||||
(member_id, category, summary, detail,
|
||||
recorded_by_assistant_id, recorded_by_name, site_id, source)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
"""
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, (
|
||||
body.member_id,
|
||||
body.category.value,
|
||||
body.summary,
|
||||
body.detail,
|
||||
body.recorded_by_assistant_id,
|
||||
body.recorded_by_name,
|
||||
body.site_id,
|
||||
body.source.value,
|
||||
))
|
||||
row = cur.fetchone()
|
||||
conn.commit()
|
||||
return {"status": "ok", "id": row[0] if row else None}
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
logger.exception("维客线索写入失败: member_id=%s", body.member_id)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="线索提交失败,请稍后重试",
|
||||
)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@router.get("/retention-clue/{member_id}", response_model=list[RetentionClueOut])
|
||||
async def get_retention_clues(member_id: int, site_id: int):
|
||||
"""查询某会员的全部维客线索,按录入时间倒序。"""
|
||||
sql = """
|
||||
SELECT id, member_id, category, summary, detail,
|
||||
recorded_by_assistant_id, recorded_by_name, recorded_at, site_id, source
|
||||
FROM member_retention_clue
|
||||
WHERE member_id = %s AND site_id = %s
|
||||
ORDER BY recorded_at DESC
|
||||
"""
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, (member_id, site_id))
|
||||
rows = cur.fetchall()
|
||||
cols = [d[0] for d in cur.description]
|
||||
return [dict(zip(cols, r)) for r in rows]
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@router.delete("/retention-clue/{clue_id}")
|
||||
async def delete_retention_clue(clue_id: int):
|
||||
"""删除单条维客线索。"""
|
||||
sql = "DELETE FROM member_retention_clue WHERE id = %s"
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, (clue_id,))
|
||||
if cur.rowcount == 0:
|
||||
raise HTTPException(status_code=404, detail="线索不存在")
|
||||
conn.commit()
|
||||
return {"status": "ok"}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
logger.exception("维客线索删除失败: id=%s", clue_id)
|
||||
raise HTTPException(status_code=500, detail="删除失败")
|
||||
finally:
|
||||
conn.close()
|
||||
Reference in New Issue
Block a user