139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
from fastapi import FastAPI, HTTPException, Header
|
|
import sqlite3
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
import requests
|
|
import time
|
|
|
|
app = FastAPI(title="即时派单 API")
|
|
|
|
API_KEY = "tuhui_dispatch_key_2026"
|
|
DESIGNER_DB_PATH = Path("/root/tuhui/backend/designer_status.db")
|
|
DISPATCH_DB_PATH = Path("/root/tuhui/backend/dispatch.db")
|
|
WECHAT_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=cc88bdef-a13f-4d7e-bdb6-ee51b68b8205"
|
|
|
|
@app.get("/health")
|
|
def health():
|
|
return {"status": "ok", "timestamp": datetime.now().isoformat()}
|
|
|
|
@app.get("/online")
|
|
def get_online_designers(x_api_key: str = Header(None)):
|
|
"""查询当前在线设计师"""
|
|
if x_api_key != API_KEY:
|
|
raise HTTPException(status_code=401, detail="Invalid API Key")
|
|
|
|
conn = sqlite3.connect(str(DESIGNER_DB_PATH), timeout=30)
|
|
conn.row_factory = sqlite3.Row
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("SELECT real_name, last_seen FROM designer_status WHERE status='online' ORDER BY last_seen DESC")
|
|
designers = [row["real_name"] for row in cursor.fetchall()]
|
|
|
|
conn.close()
|
|
|
|
return {
|
|
"count": len(designers),
|
|
"online": designers,
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
@app.get("/assign")
|
|
def assign_task(x_api_key: str = Header(None)):
|
|
"""
|
|
即时派单接口 - 轮询均匀分配版
|
|
1. 查询在线设计师
|
|
2. 统计每个设计师的已分配任务数
|
|
3. 选择任务最少的(轮询)
|
|
4. 发送企业微信通知
|
|
5. 返回派单结果
|
|
"""
|
|
if x_api_key != API_KEY:
|
|
raise HTTPException(status_code=401, detail="Invalid API Key")
|
|
|
|
try:
|
|
# 1. 查询在线设计师
|
|
conn = sqlite3.connect(str(DESIGNER_DB_PATH), timeout=30)
|
|
dispatch_conn = sqlite3.connect(str(DISPATCH_DB_PATH), timeout=30)
|
|
conn.row_factory = sqlite3.Row
|
|
cursor = conn.cursor()
|
|
dispatch_cursor = dispatch_conn.cursor()
|
|
|
|
cursor.execute("""
|
|
SELECT real_name FROM designer_status
|
|
WHERE status = 'online'
|
|
ORDER BY last_seen DESC
|
|
""")
|
|
online_designers = [row["real_name"] for row in cursor.fetchall()]
|
|
|
|
if not online_designers:
|
|
conn.close()
|
|
dispatch_conn.close()
|
|
raise HTTPException(status_code=400, detail="暂无在线设计师")
|
|
|
|
# 2. 统计每个在线设计师的已分配任务数(今天)
|
|
designer_workload = {}
|
|
for designer in online_designers:
|
|
dispatch_cursor.execute('''
|
|
SELECT COUNT(*) as count FROM dispatch_tasks
|
|
WHERE assigned_to = ?
|
|
AND date(assigned_at) = date('now')
|
|
''', (designer,))
|
|
count = dispatch_cursor.fetchone()[0]
|
|
designer_workload[designer] = count
|
|
|
|
# 3. 选择任务最少的(轮询均匀分配)
|
|
selected_designer = min(designer_workload, key=designer_workload.get)
|
|
min_tasks = designer_workload[selected_designer]
|
|
|
|
# 4. 创建任务
|
|
task_id = f"task_{int(datetime.now().timestamp())}"
|
|
|
|
dispatch_cursor.execute('''
|
|
INSERT INTO dispatch_tasks (id, task_name, task_description, task_type, priority, status, assigned_to, assigned_at)
|
|
VALUES (?, ?, ?, ?, ?, 'assigned', ?, ?)
|
|
''', (task_id, "临时任务", "即时分配", "design", 1, selected_designer, datetime.now()))
|
|
|
|
dispatch_conn.commit()
|
|
|
|
# 5. 发送企业微信通知
|
|
message = f"""📋 新任务分配
|
|
|
|
👤 设计师:{selected_designer}
|
|
📊 今日已分配:{min_tasks + 1} 个任务
|
|
📝 任务:临时任务
|
|
⏰ 时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
|
|
|
请及时处理!"""
|
|
|
|
try:
|
|
requests.post(WECHAT_WEBHOOK, json={
|
|
"msgtype": "markdown",
|
|
"markdown": {"content": message}
|
|
}, timeout=10)
|
|
notification_sent = True
|
|
except:
|
|
notification_sent = False
|
|
|
|
conn.close()
|
|
dispatch_conn.close()
|
|
|
|
return {
|
|
"success": True,
|
|
"task_id": task_id,
|
|
"assigned_to": selected_designer,
|
|
"workload": designer_workload,
|
|
"online_count": len(online_designers),
|
|
"notification_sent": notification_sent,
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
|
|
except sqlite3.OperationalError as e:
|
|
if "locked" in str(e):
|
|
time.sleep(0.5) # 等待 0.5 秒重试
|
|
return assign_task(x_api_key)
|
|
raise
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
uvicorn.run(app, host="0.0.0.0", port=8006)
|