feat: 系统设置新增通报时间配置 + 亮灯表30天滚动窗口 + 相关人员文案统一 + 周报数据补全
- 亮灯表从自然月改为30天滚动窗口(30/60天阈值),解决月底覆盖断崖 - 系统设置新增「定时通报时间」选择器,支局长可配置每日企微通报时刻 - 新增 SystemConfig 键值表 + scheduler_manager APScheduler 运行时重调度 - 拜访记录/导入模板/弹窗表单统一「同访人员」→「相关人员」 - 仪表盘周报数据补全:companion_names_resolved、visitor_name/phone 等字段 - 新增 weekly_report_template.xlsx 模板文件 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+23
-22
@@ -1,27 +1,14 @@
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from sqlalchemy import select
|
||||
from app.config import settings
|
||||
from app.database import engine, Base, async_session
|
||||
from app.api import router as api_router
|
||||
from app.api import auth, users, customers, visits, work_plans, mini_business, key_visits
|
||||
from app.api import dashboard, upload, export, import_data, wecom, daily_notes, ai_summary
|
||||
from app.services.scheduler import check_daily_reporting, check_overdue_plans
|
||||
|
||||
_scheduler = AsyncIOScheduler()
|
||||
|
||||
|
||||
async def _scheduled_check():
|
||||
"""Wrapper for APScheduler: create a fresh session and run the daily check."""
|
||||
async with async_session() as db:
|
||||
await check_daily_reporting(db)
|
||||
|
||||
|
||||
async def _scheduled_overdue_check():
|
||||
"""Check for overdue plans and remind managers (9:00 AM)."""
|
||||
async with async_session() as db:
|
||||
await check_overdue_plans(db)
|
||||
from app.api import dashboard, upload, export, import_data, wecom, daily_notes, ai_summary, system_config
|
||||
from app.models.system_config import SystemConfig
|
||||
from app.services.scheduler_manager import start_scheduler, shutdown_scheduler
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@@ -58,16 +45,29 @@ async def lifespan(app: FastAPI):
|
||||
await conn.run_sync(lambda c: c.exec_driver_sql(
|
||||
"ALTER TABLE visits ADD COLUMN IF NOT EXISTS companion_names TEXT[] DEFAULT '{}'"
|
||||
))
|
||||
# system_config table for v0.5
|
||||
await conn.run_sync(lambda c: c.exec_driver_sql(
|
||||
"CREATE TABLE IF NOT EXISTS system_config (key VARCHAR(64) PRIMARY KEY, value TEXT DEFAULT '')"
|
||||
))
|
||||
|
||||
# Start daily reporting scheduler (17:30 CST = 09:30 UTC)
|
||||
_scheduler.add_job(_scheduled_check, "cron", hour=17, minute=30, id="daily_check")
|
||||
_scheduler.add_job(_scheduled_overdue_check, "cron", hour=9, minute=0, id="overdue_check")
|
||||
_scheduler.start()
|
||||
# Read notification_time from DB (or use default 17:30)
|
||||
notification_hour, notification_minute = 17, 30
|
||||
async with async_session() as db:
|
||||
row = await db.get(SystemConfig, "notification_time")
|
||||
if row and row.value:
|
||||
try:
|
||||
parts = row.value.strip().split(":")
|
||||
notification_hour, notification_minute = int(parts[0]), int(parts[1])
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
|
||||
# Start daily reporting scheduler
|
||||
start_scheduler(notification_hour, notification_minute)
|
||||
|
||||
yield
|
||||
|
||||
# Shutdown
|
||||
_scheduler.shutdown(wait=False)
|
||||
shutdown_scheduler()
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ app.include_router(import_data.router, prefix="/api")
|
||||
app.include_router(wecom.router, prefix="/api")
|
||||
app.include_router(daily_notes.router, prefix="/api")
|
||||
app.include_router(ai_summary.router, prefix="/api")
|
||||
app.include_router(system_config.router, prefix="/api")
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
|
||||
Reference in New Issue
Block a user