feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ from app.middleware.response_wrapper import (
|
||||
http_exception_handler,
|
||||
unhandled_exception_handler,
|
||||
)
|
||||
from app.trace.middleware import TraceMiddleware
|
||||
|
||||
from app import config
|
||||
# CHANGE 2026-02-19 | 新增 xcx_test 路由(MVP 验证)+ wx_callback 路由(微信消息推送)
|
||||
@@ -29,9 +30,16 @@ from app import config
|
||||
# CHANGE 2026-03-18 | 新增 xcx_customers 路由(CUST-1 客户详情、CUST-2 客户服务记录)
|
||||
# CHANGE 2026-03-19 | 新增 xcx_coaches 路由(COACH-1 助教详情)
|
||||
# CHANGE 2026-03-19 | 新增 xcx_board / xcx_config 路由(RNS1.3 三看板 + 技能类型配置)
|
||||
from app.routers import auth, execution, schedules, tasks, env_config, db_viewer, etl_status, xcx_test, wx_callback, member_retention_clue, ops_panel, xcx_auth, admin_applications, business_day, xcx_tasks, xcx_notes, xcx_chat, xcx_ai_cache, xcx_performance, xcx_customers, xcx_coaches, xcx_board, xcx_config
|
||||
# CHANGE 2026-03-22 | 新增 admin_registry 路由(NS4.1 注册体系:租户/店铺/简写ID 管理)
|
||||
# CHANGE 2026-03-23 | 新增 admin_ai 路由(P15 AI 监控后台:Dashboard/调度/调用/缓存/预算/批量/告警)
|
||||
# CHANGE 2026-03-24 | 新增 admin_dev_trace 路由(dev-trace-log: 开发调试日志管理 API)
|
||||
# CHANGE 2026-03-23 | 新增 trigger_jobs 路由(定时任务管理页面 API)
|
||||
# CHANGE 2026-03-24 | P18 任务引擎运营看板:新增 admin_task_engine 路由
|
||||
# CHANGE 2026-03-29 | DWS_TASK_ENGINE:新增 internal_events 路由(按 job_name 执行任务)
|
||||
from app.routers import auth, execution, schedules, tasks, env_config, db_viewer, etl_status, xcx_test, wx_callback, member_retention_clue, ops_panel, xcx_auth, xcx_avatar, admin_applications, business_day, xcx_tasks, xcx_notes, xcx_chat, xcx_ai_cache, xcx_performance, xcx_customers, xcx_coaches, xcx_board, xcx_config, tenant_auth, tenant_users, tenant_excel, tenant_clues, tenant_site_admins, admin_tenant_admins, admin_registry, internal_ai, admin_ai, admin_dev_trace, trigger_jobs, admin_task_engine, admin_db_health, admin_triggers, internal_events
|
||||
from app.services.scheduler import scheduler
|
||||
from app.services.task_queue import task_queue
|
||||
from app.services.task_executor import task_executor
|
||||
from app.ws.logs import ws_router
|
||||
|
||||
|
||||
@@ -56,40 +64,76 @@ async def lifespan(app: FastAPI):
|
||||
)
|
||||
print(_banner, flush=True)
|
||||
|
||||
# CHANGE 2026-03-22 | 启动时清理本机僵尸任务(上次非正常关闭遗留的 running 记录)
|
||||
task_executor.recover_stale()
|
||||
|
||||
# 启动
|
||||
task_queue.start()
|
||||
scheduler.start()
|
||||
|
||||
# CHANGE 2026-02-27 | 注册触发器 job handler(核心业务模块)
|
||||
# CHANGE 2026-03-24 | dev-trace-log: 用 trace_job 包装 job handler,追踪后台任务执行
|
||||
from app.services.trigger_scheduler import register_job
|
||||
from app.services import task_generator, task_expiry, recall_detector, note_reclassifier
|
||||
from app.trace.job_wrapper import trace_job
|
||||
|
||||
register_job("task_generator", lambda **_kw: task_generator.run())
|
||||
register_job("task_expiry_check", lambda **_kw: task_expiry.run())
|
||||
register_job("recall_completion_check", recall_detector.run)
|
||||
register_job("note_reclassify_backfill", note_reclassifier.run)
|
||||
register_job("task_generator", trace_job("task_generator")(lambda **_kw: task_generator.run()))
|
||||
register_job("task_expiry_check", trace_job("task_expiry_check")(lambda **_kw: task_expiry.run()))
|
||||
register_job("recall_completion_check", trace_job("recall_completion_check")(recall_detector.run))
|
||||
register_job("note_reclassify_backfill", trace_job("note_reclassify_backfill")(note_reclassifier.run))
|
||||
|
||||
# CHANGE 2026-03-23 | 启动时检查定时任务是否今天执行过,打印提示
|
||||
from app.services.trigger_scheduler import check_startup_jobs
|
||||
try:
|
||||
pending_jobs = check_startup_jobs()
|
||||
if pending_jobs:
|
||||
_lines = ["╔══ 定时任务提醒 ══════════════════════════════════════╗"]
|
||||
for j in pending_jobs:
|
||||
_lines.append(f"║ ⚠ {j['description']}({j['job_name']})— {j['last_run_at']}")
|
||||
_lines.append("║ → 请在管理后台「定时任务」页面手动执行")
|
||||
_lines.append("╚══════════════════════════════════════════════════════╝")
|
||||
print("\n".join(_lines), flush=True)
|
||||
else:
|
||||
print("✓ 所有定时任务今天已执行过", flush=True)
|
||||
except Exception:
|
||||
import logging as _log
|
||||
_log.getLogger(__name__).warning("启动检查定时任务失败", exc_info=True)
|
||||
|
||||
# CHANGE 2026-03-10 | 注册 AI 事件处理器(消费/备注/任务分配 → AI 调用链)
|
||||
# CHANGE 2026-03-22 | P14 迁移:BailianClient → DashScopeClient + AIConfig + 防护层
|
||||
try:
|
||||
import os
|
||||
_api_key = os.environ.get("BAILIAN_API_KEY", "")
|
||||
_base_url = os.environ.get("BAILIAN_BASE_URL", "")
|
||||
_model = os.environ.get("BAILIAN_MODEL", "qwen-plus")
|
||||
if _api_key and _base_url:
|
||||
from app.ai.bailian_client import BailianClient
|
||||
from app.ai.cache_service import AICacheService
|
||||
from app.ai.conversation_service import ConversationService
|
||||
from app.ai.dispatcher import AIDispatcher, register_ai_handlers
|
||||
from app.ai.config import AIConfig
|
||||
from app.ai.dashscope_client import DashScopeClient
|
||||
from app.ai.cache_service import AICacheService
|
||||
from app.ai.conversation_service import ConversationService
|
||||
from app.ai.circuit_breaker import CircuitBreaker
|
||||
from app.ai.rate_limiter import RateLimiter
|
||||
from app.ai.budget_tracker import BudgetTracker
|
||||
from app.ai.run_log_service import AIRunLogService
|
||||
from app.ai.dispatcher import AIDispatcher, register_ai_handlers
|
||||
from app.database import get_connection
|
||||
|
||||
_bailian = BailianClient(api_key=_api_key, base_url=_base_url, model=_model)
|
||||
_dispatcher = AIDispatcher(_bailian, AICacheService(), ConversationService())
|
||||
register_ai_handlers(_dispatcher)
|
||||
_ai_config = AIConfig.from_env()
|
||||
_client = DashScopeClient(api_key=_ai_config.api_key, workspace_id=_ai_config.workspace_id)
|
||||
_run_log_svc = AIRunLogService(get_conn=get_connection)
|
||||
_dispatcher = AIDispatcher(
|
||||
client=_client,
|
||||
cache_svc=AICacheService(),
|
||||
conv_svc=ConversationService(),
|
||||
circuit_breaker=CircuitBreaker(),
|
||||
rate_limiter=RateLimiter(),
|
||||
budget_tracker=BudgetTracker(usage_provider=_run_log_svc),
|
||||
run_log_svc=_run_log_svc,
|
||||
config=_ai_config,
|
||||
)
|
||||
register_ai_handlers(_dispatcher)
|
||||
except Exception:
|
||||
import logging as _log
|
||||
_log.getLogger(__name__).warning("AI 事件处理器注册失败,AI 功能不可用", exc_info=True)
|
||||
|
||||
yield
|
||||
# 关闭
|
||||
# CHANGE 2026-03-22 | 优雅关闭:先终止所有运行中的子进程(3s 超时),再停调度和队列
|
||||
await task_executor.shutdown(timeout=3.0)
|
||||
await scheduler.stop()
|
||||
await task_queue.stop()
|
||||
|
||||
@@ -117,6 +161,10 @@ app.add_middleware(
|
||||
# CHANGE 2026-03-16 | RNS1.0 T0-1: 全局响应包装 + 异常处理器
|
||||
app.add_middleware(ResponseWrapperMiddleware)
|
||||
|
||||
# ---- 全链路追踪中间件(最后添加 = 最先执行 = 最外层) ----
|
||||
# CHANGE 2026-03-24 | dev-trace-log: TraceMiddleware 包裹所有中间件,仅拦截 /api/xcx/ 路由
|
||||
app.add_middleware(TraceMiddleware)
|
||||
|
||||
# ---- 全局异常处理器 ----
|
||||
app.add_exception_handler(StarletteHTTPException, http_exception_handler)
|
||||
app.add_exception_handler(Exception, unhandled_exception_handler)
|
||||
@@ -135,6 +183,7 @@ app.include_router(wx_callback.router)
|
||||
app.include_router(member_retention_clue.router)
|
||||
app.include_router(ops_panel.router)
|
||||
app.include_router(xcx_auth.router)
|
||||
app.include_router(xcx_avatar.router)
|
||||
app.include_router(admin_applications.router)
|
||||
app.include_router(business_day.router)
|
||||
app.include_router(xcx_tasks.router)
|
||||
@@ -146,6 +195,21 @@ app.include_router(xcx_customers.router)
|
||||
app.include_router(xcx_coaches.router)
|
||||
app.include_router(xcx_board.router)
|
||||
app.include_router(xcx_config.router)
|
||||
app.include_router(tenant_auth.router)
|
||||
app.include_router(tenant_users.router)
|
||||
app.include_router(tenant_excel.router)
|
||||
app.include_router(tenant_clues.router)
|
||||
app.include_router(tenant_site_admins.router)
|
||||
app.include_router(admin_tenant_admins.router)
|
||||
app.include_router(admin_registry.router)
|
||||
app.include_router(internal_ai.router)
|
||||
app.include_router(internal_events.router)
|
||||
app.include_router(admin_ai.router)
|
||||
app.include_router(admin_dev_trace.router)
|
||||
app.include_router(trigger_jobs.router)
|
||||
app.include_router(admin_task_engine.router)
|
||||
app.include_router(admin_db_health.router)
|
||||
app.include_router(admin_triggers.router)
|
||||
|
||||
|
||||
@app.get("/health", tags=["系统"])
|
||||
|
||||
Reference in New Issue
Block a user