feat: 添加中国节假日感知定时功能
- 新增 chinese_holidays 表,通过 timor.tech API 同步节假日数据 - 修正 holiday 字段解读:holiday=true → 休息日,holiday=false → 调休工作日 - 工作日 8:00-22:00 每小时爬取,周末/节假日/夜间自动跳过 - 新增 /api/v1/holidays/sync 和 /api/v1/holidays/today 接口 - 企微菜单新增「同步节假日」按钮,支持手动触发同步
This commit is contained in:
+83
-2
@@ -1,7 +1,11 @@
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from app.config import settings
|
||||
from app.wechat.crypto import WXBizMsgCrypt
|
||||
from app.wechat.client import WeChatClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WeChatMessageHandler:
|
||||
@@ -11,6 +15,7 @@ class WeChatMessageHandler:
|
||||
sEncodingAESKey=settings.wechat_encoding_aes_key,
|
||||
sReceiveId=settings.wechat_corp_id,
|
||||
)
|
||||
self.client = WeChatClient()
|
||||
|
||||
def verify_url(
|
||||
self, msg_signature: str, timestamp: str, nonce: str, echostr: str
|
||||
@@ -48,10 +53,86 @@ class WeChatMessageHandler:
|
||||
return encrypted
|
||||
return None
|
||||
|
||||
def handle_event(
|
||||
async def handle_event(
|
||||
self, event: str, event_key: str | None, from_user: str
|
||||
) -> str | None:
|
||||
if event != "click" or not event_key:
|
||||
return None
|
||||
|
||||
if event_key == "today_stats":
|
||||
return await self._handle_today_stats(from_user)
|
||||
elif event_key == "trigger_crawl":
|
||||
return await self._handle_trigger_crawl(from_user)
|
||||
elif event_key == "sync_holidays":
|
||||
return await self._handle_sync_holidays(from_user)
|
||||
return None
|
||||
|
||||
def handle_text(self, content: str, from_user: str) -> str | None:
|
||||
async def handle_text(self, content: str, from_user: str) -> str | None:
|
||||
return None
|
||||
|
||||
async def _handle_today_stats(self, from_user: str) -> str | None:
|
||||
from app.api.deps import get_db
|
||||
|
||||
try:
|
||||
async for db in get_db():
|
||||
from sqlalchemy import func, select
|
||||
from app.models.announcement import Announcement
|
||||
|
||||
total_result = await db.execute(
|
||||
select(func.count()).select_from(Announcement)
|
||||
)
|
||||
total = total_result.scalar() or 0
|
||||
|
||||
today_result = await db.execute(
|
||||
select(func.count()).where(
|
||||
func.date(Announcement.publish_date) == func.current_date()
|
||||
).select_from(Announcement)
|
||||
)
|
||||
today = today_result.scalar() or 0
|
||||
|
||||
text = f"今日新增: {today} 条\n累计公告: {total} 条"
|
||||
await self.client.send_text(text, from_user)
|
||||
except Exception as e:
|
||||
logger.error(f"查询统计失败: {e}")
|
||||
await self.client.send_text("查询失败,请稍后再试", from_user)
|
||||
|
||||
async def _handle_trigger_crawl(self, from_user: str) -> str | None:
|
||||
from app.api.deps import get_crawl_service
|
||||
|
||||
await self.client.send_text("开始爬取,请稍候...", from_user)
|
||||
|
||||
try:
|
||||
service = get_crawl_service()
|
||||
results = await service.run_all()
|
||||
total = sum(r.total_count for r in results)
|
||||
stored = sum(
|
||||
r.pipeline_result.stored for r in results
|
||||
if r.pipeline_result
|
||||
)
|
||||
notified = sum(
|
||||
r.pipeline_result.notified for r in results
|
||||
if r.pipeline_result
|
||||
)
|
||||
errors = [r.error_message for r in results if not r.success]
|
||||
msg = f"爬取完成\n抓取: {total} 条\n新增: {stored} 条\n推送: {notified} 条"
|
||||
if errors:
|
||||
msg += f"\n异常: {errors[0][:50]}"
|
||||
await self.client.send_text(msg, from_user)
|
||||
except Exception as e:
|
||||
logger.error(f"手动爬取失败: {e}")
|
||||
await self.client.send_text(f"爬取失败: {e}", from_user)
|
||||
|
||||
async def _handle_sync_holidays(self, from_user: str) -> str | None:
|
||||
from app.services.holiday_service import now_in_china, sync_holidays
|
||||
from app.api.deps import get_db
|
||||
|
||||
try:
|
||||
async for db in get_db():
|
||||
year = now_in_china().year
|
||||
count = await sync_holidays(db, year)
|
||||
await self.client.send_text(
|
||||
f"已同步 {year} 年节假日\n共 {count} 条记录", from_user,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"同步节假日失败: {e}")
|
||||
await self.client.send_text(f"同步失败: {e}", from_user)
|
||||
|
||||
Reference in New Issue
Block a user