- 拆分应用工厂、业务服务与路由,保留原有 HTTP/SSE 和存储入口 - 分离页面资源,重排客服工作台并完善响应式导航、草稿和附件交互 - 整理维护脚本、请求示例和贡献指南,移除启动脚本中的密钥配置 - 上传文件改为仅本地保留,补充隔离的后端与前端回归验证 验证:46 项 Python 测试通过,含 14 个已有子测试;12 个 Node 前端场景通过。
76 lines
2.7 KiB
Python
76 lines
2.7 KiB
Python
"""Feedback, reporting, login, orders and offline tickets."""
|
|
|
|
from datetime import datetime
|
|
|
|
from .db import connect, now_str
|
|
|
|
|
|
def feedback(data):
|
|
"""收集 👍/👎 反馈,存到 feedback 表"""
|
|
conn = connect()
|
|
conn.execute('INSERT INTO feedback(question, answer, vote, ctime) VALUES (?,?,?,?)', (str(data.get('question', ''))[:500], str(data.get('answer', ''))[:2000], str(data.get('vote', '')), now_str()))
|
|
conn.commit()
|
|
conn.close()
|
|
return {'ok': True}
|
|
|
|
|
|
def admin_stats():
|
|
conn = connect()
|
|
total_conv = conn.execute('SELECT COUNT(*) FROM chat_history').fetchone()[0]
|
|
total_msg = conn.execute('SELECT COUNT(*) FROM messages').fetchone()[0]
|
|
good = conn.execute('SELECT COUNT(*) FROM feedback WHERE vote=1').fetchone()[0]
|
|
bad = conn.execute('SELECT COUNT(*) FROM feedback WHERE vote=-1').fetchone()[0]
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
today_conv = conn.execute('SELECT COUNT(*) FROM chat_history WHERE date(ctime)=date(?)', (today,)).fetchone()[0]
|
|
conn.close()
|
|
return {'total_conv': total_conv, 'total_msg': total_msg, 'good': good, 'bad': bad, 'today_conv': today_conv}
|
|
|
|
|
|
def my_orders(phone):
|
|
if not phone:
|
|
return {'orders': []}
|
|
conn = connect()
|
|
rows = conn.execute('SELECT track_no, status, created FROM orders WHERE phone=? ORDER BY id DESC', (phone,)).fetchall()
|
|
conn.close()
|
|
return {'orders': [{'track_no': r[0], 'status': r[1], 'created': r[2]} for r in rows]}
|
|
|
|
|
|
def add_ticket(data):
|
|
conn = connect()
|
|
conn.execute('INSERT INTO tickets(content, phone, ctime, status) VALUES(?,?,?,?)', (data.get('content', ''), data.get('phone', ''), datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'pending'))
|
|
conn.commit()
|
|
conn.close()
|
|
return {'ok': True}
|
|
|
|
|
|
def list_tickets():
|
|
conn = connect()
|
|
rows = conn.execute("SELECT id, content, phone, ctime FROM tickets WHERE status='pending' ORDER BY id DESC").fetchall()
|
|
conn.close()
|
|
return [{'id': r[0], 'content': r[1], 'phone': r[2], 'ctime': r[3]} for r in rows]
|
|
|
|
|
|
def admin_login(data):
|
|
u = data.get('username', '')
|
|
p = data.get('password', '')
|
|
conn = connect()
|
|
row = conn.execute('SELECT name FROM agents WHERE username=? AND password=?', (u, p)).fetchone()
|
|
conn.close()
|
|
if row:
|
|
return {'ok': True, 'name': row[0]}
|
|
return ({'ok': False}, 401)
|
|
|
|
|
|
def export_chat():
|
|
conn = connect()
|
|
rows = conn.execute('SELECT h.title, m.role, m.content, m.ctime FROM messages m JOIN chat_history h ON m.conv_id=h.id ORDER BY m.id').fetchall()
|
|
conn.close()
|
|
import csv
|
|
import io
|
|
buf = io.StringIO()
|
|
w = csv.writer(buf)
|
|
w.writerow(['标题', '角色', '内容', '时间'])
|
|
for r in rows:
|
|
w.writerow([r[0], r[1], r[2] or '', r[3]])
|
|
return buf.getvalue()
|