feat(dev): 本地开发工具集 v0.5.6-dev-tooling
包含本地 dev 链路完整跑通的工具集(不进生产): backend: - dev_auth.py: /api/dev/login Mock 企微 OAuth(/dev/* 路由) - messages.py: dev 模式短路企微推送,避免 invalid corpid 噪音 - main.py: dev 模式启动时建 5 条 demo conversation,让前端有数据可测 frontend: - PortalSelect.vue: dev 模式 enterRole 跳完整 URL(5173/5174/5175 端口),生产仍走相对路径 infrastructure: - docker-compose.dev.yml: dev compose(包含 backend/postgres/redis) scripts(Windows PowerShell): - dev-frontend-install.ps1: 一次性装 4 个前端依赖 - dev-frontend-start.ps1: 后台起 4 个前端 dev server - dev-check-schema-drift.ps1: 对比 SQLAlchemy 模型 vs Postgres schema,漂移 exit 1 docs: - CURRENT-FOCUS.md: 项目状态看板(每次 session 维护)
This commit is contained in:
+165
-1
@@ -12,12 +12,13 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy import select, text
|
||||
|
||||
# 导入配置(读取环境变量)
|
||||
from app.config import settings
|
||||
@@ -179,6 +180,7 @@ async def _init_default_data():
|
||||
3. quick_reply_templates — 快速回复模板
|
||||
4. approval_links — 审批流程链接
|
||||
5. software_downloads — 软件下载入口
|
||||
6. (dev 模式)demo_conversations — 演示用会话,让前端有数据可发
|
||||
|
||||
只在表为空时插入,避免重复插入。
|
||||
"""
|
||||
@@ -188,6 +190,7 @@ async def _init_default_data():
|
||||
from app.models.quick_reply_template import QuickReplyTemplate
|
||||
from app.models.approval_link import ApprovalLink
|
||||
from app.models.software_download import SoftwareDownload
|
||||
from app.config import settings
|
||||
|
||||
async_session_factory = _get_session_factory()
|
||||
async with async_session_factory() as db:
|
||||
@@ -207,6 +210,11 @@ async def _init_default_data():
|
||||
# 5. 初始化软件下载入口
|
||||
await _init_software_downloads(db, SoftwareDownload)
|
||||
|
||||
# 6. (dev 模式)初始化 demo 会话,让前端有数据可发
|
||||
# 真因:之前没建,前端硬编码的 conv-001 调 POST /messages 返 "会话不存在" 3003
|
||||
if getattr(settings, 'dev_mode', False) or os.getenv('DEV_MODE', '').lower() == 'true':
|
||||
await _init_demo_conversations(db)
|
||||
|
||||
await db.commit()
|
||||
logger.info("默认数据初始化完成")
|
||||
|
||||
@@ -215,6 +223,162 @@ async def _init_default_data():
|
||||
logger.error(f"默认数据初始化失败: {e}")
|
||||
|
||||
|
||||
async def _init_demo_conversations(db):
|
||||
"""(dev 模式专用)建 5 条 demo 会话,让前端有数据可测。
|
||||
|
||||
涵盖各种状态:
|
||||
- ai_handling: AI 正在处理(2 条,不同员工)
|
||||
- queued: 等坐席接手
|
||||
- serving: 坐席服务中
|
||||
- resolved: 已结单
|
||||
|
||||
只在 conversations 表为空时建,避免重复。
|
||||
"""
|
||||
from app.models.conversation import Conversation
|
||||
|
||||
existing = (await db.execute(select(Conversation).limit(1))).scalar_one_or_none()
|
||||
if existing:
|
||||
logger.info("demo 会话已存在,跳过")
|
||||
return
|
||||
|
||||
import uuid as _uuid
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
demo_convs = [
|
||||
{
|
||||
"id": "conv-001",
|
||||
"corp_id": "wwa8c87970b2011f41",
|
||||
"employee_id": "dev-user-001",
|
||||
"employee_name": "张三(普通员工)",
|
||||
"department": "财务部",
|
||||
"position": "会计",
|
||||
"level": "P5",
|
||||
"status": "ai_handling",
|
||||
"is_vip": False,
|
||||
"is_pinned": False,
|
||||
"is_todo": False,
|
||||
"urgency_score": 30,
|
||||
"tags": ["财务", "IT"],
|
||||
"assigned_agent_id": None,
|
||||
"collaborating_agent_ids": [],
|
||||
"participants": [],
|
||||
"ai_substantive_reply_count": 0,
|
||||
"impact_scope": 1,
|
||||
"is_blocking": False,
|
||||
"emotion_state": "normal",
|
||||
"dify_conversation_id": None,
|
||||
"last_message_at": now - timedelta(minutes=2),
|
||||
"last_message_summary": "想问下 VPN 怎么连",
|
||||
},
|
||||
{
|
||||
"id": "conv-002",
|
||||
"corp_id": "wwa8c87970b2011f41",
|
||||
"employee_id": "dev-user-001",
|
||||
"employee_name": "张三(普通员工)",
|
||||
"department": "财务部",
|
||||
"position": "会计",
|
||||
"level": "P5",
|
||||
"status": "queued",
|
||||
"is_vip": False,
|
||||
"is_pinned": True,
|
||||
"is_todo": True,
|
||||
"urgency_score": 70,
|
||||
"tags": ["紧急", "VPN"],
|
||||
"assigned_agent_id": None,
|
||||
"collaborating_agent_ids": [],
|
||||
"participants": [],
|
||||
"ai_substantive_reply_count": 2,
|
||||
"impact_scope": 3,
|
||||
"is_blocking": True,
|
||||
"emotion_state": "worried",
|
||||
"dify_conversation_id": "dify-conv-002",
|
||||
"last_message_at": now - timedelta(minutes=5),
|
||||
"last_message_summary": "VPN 连不上,影响工作",
|
||||
},
|
||||
{
|
||||
"id": "conv-003",
|
||||
"corp_id": "wwa8c87970b2011f41",
|
||||
"employee_id": "dev-multi-001",
|
||||
"employee_name": "周八(多角色测试)",
|
||||
"department": "测试部",
|
||||
"position": "测试工程师",
|
||||
"level": "P6",
|
||||
"status": "serving",
|
||||
"is_vip": True,
|
||||
"is_pinned": False,
|
||||
"is_todo": False,
|
||||
"urgency_score": 50,
|
||||
"tags": ["软件安装"],
|
||||
"assigned_agent_id": "dev-agent-001",
|
||||
"collaborating_agent_ids": [],
|
||||
"participants": [],
|
||||
"ai_substantive_reply_count": 1,
|
||||
"impact_scope": 1,
|
||||
"is_blocking": False,
|
||||
"emotion_state": "normal",
|
||||
"dify_conversation_id": "dify-conv-003",
|
||||
"last_message_at": now - timedelta(minutes=10),
|
||||
"last_message_summary": "需要装 WPS 专业版",
|
||||
},
|
||||
{
|
||||
"id": "conv-004",
|
||||
"corp_id": "wwa8c87970b2011f41",
|
||||
"employee_id": "dev-supervisor-001",
|
||||
"employee_name": "王五(部门主管)",
|
||||
"department": "信息技术部",
|
||||
"position": "主管",
|
||||
"level": "M3",
|
||||
"status": "serving",
|
||||
"is_vip": True,
|
||||
"is_pinned": True,
|
||||
"is_todo": False,
|
||||
"urgency_score": 80,
|
||||
"tags": ["系统升级"],
|
||||
"assigned_agent_id": "dev-agent-001",
|
||||
"collaborating_agent_ids": ["dev-admin-001"],
|
||||
"participants": [],
|
||||
"ai_substantive_reply_count": 3,
|
||||
"impact_scope": 50,
|
||||
"is_blocking": True,
|
||||
"emotion_state": "urgent",
|
||||
"dify_conversation_id": "dify-conv-004",
|
||||
"last_message_at": now - timedelta(minutes=15),
|
||||
"last_message_summary": "ERP 系统升级咨询",
|
||||
},
|
||||
{
|
||||
"id": "conv-005",
|
||||
"corp_id": "wwa8c87970b2011f41",
|
||||
"employee_id": "dev-security-001",
|
||||
"employee_name": "赵六(安全团队)",
|
||||
"department": "信息安全部",
|
||||
"position": "安全工程师",
|
||||
"level": "P7",
|
||||
"status": "resolved",
|
||||
"is_vip": False,
|
||||
"is_pinned": False,
|
||||
"is_todo": False,
|
||||
"urgency_score": 20,
|
||||
"tags": ["安全"],
|
||||
"assigned_agent_id": "dev-agent-001",
|
||||
"collaborating_agent_ids": [],
|
||||
"participants": [],
|
||||
"ai_substantive_reply_count": 5,
|
||||
"impact_scope": 1,
|
||||
"is_blocking": False,
|
||||
"emotion_state": "normal",
|
||||
"dify_conversation_id": "dify-conv-005",
|
||||
"last_message_at": now - timedelta(hours=2),
|
||||
"last_message_summary": "已处理:密码策略咨询",
|
||||
},
|
||||
]
|
||||
|
||||
for data in demo_convs:
|
||||
db.add(Conversation(**data))
|
||||
|
||||
logger.info(f"已初始化 {len(demo_convs)} 条 demo 会话(仅 dev 模式)")
|
||||
|
||||
|
||||
async def _init_system_configs(db, SystemConfig):
|
||||
"""初始化系统配置项。"""
|
||||
from sqlalchemy import select, func
|
||||
|
||||
Reference in New Issue
Block a user