chore: initialize tuhui repository
This commit is contained in:
138
backend/instant_dispatch.py
Normal file
138
backend/instant_dispatch.py
Normal file
@@ -0,0 +1,138 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user