From ed720c12188fa3f656e6b6c95564a4d648edaa4b Mon Sep 17 00:00:00 2001 From: tt-P607 <68868379+tt-P607@users.noreply.github.com> Date: Wed, 27 Aug 2025 23:13:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(monthly=5Fplan):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=9C=88=E5=BA=A6=E8=AE=A1=E5=88=92=E6=95=B0=E9=87=8F=E4=B8=8A?= =?UTF-8?q?=E9=99=90=E5=B9=B6=E8=87=AA=E5=8A=A8=E6=B8=85=E7=90=86=20style:?= =?UTF-8?q?=20=E4=BC=98=E5=8C=96=E6=9C=88=E5=BA=A6=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在数据库模块中新增物理删除月度计划的函数 `delete_plans_by_ids` - 在月度计划管理器中引入 `max_plans_per_month` 配置,用于限制每月计划数量 - 当检测到计划数量超出上限时,自动按创建时间删除最旧的计划以维持数量限制 - 优化了标记计划完成和删除计划时的日志记录,使其输出更详细的计划内容 - 调整了检查现有计划时的日志信息,使其更清晰 --- src/common/database/monthly_plan_db.py | 40 +++++++++++++++++++++++++- src/schedule/monthly_plan_manager.py | 22 ++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/common/database/monthly_plan_db.py b/src/common/database/monthly_plan_db.py index a65e6f547..01acf2d5a 100644 --- a/src/common/database/monthly_plan_db.py +++ b/src/common/database/monthly_plan_db.py @@ -80,16 +80,54 @@ def mark_plans_completed(plan_ids: List[int]): with get_db_session() as session: try: + plans_to_mark = session.query(MonthlyPlan).filter(MonthlyPlan.id.in_(plan_ids)).all() + if not plans_to_mark: + logger.info("没有需要标记为完成的月度计划。") + return + + plan_details = "\n".join([f" {i+1}. {plan.plan_text}" for i, plan in enumerate(plans_to_mark)]) + logger.info(f"以下 {len(plans_to_mark)} 条月度计划将被标记为已完成:\n{plan_details}") + session.query(MonthlyPlan).filter( MonthlyPlan.id.in_(plan_ids) ).update({"status": "completed"}, synchronize_session=False) session.commit() - logger.info(f"成功将 {len(plan_ids)} 条月度计划标记为已完成。") except Exception as e: logger.error(f"标记月度计划为完成时发生错误: {e}") session.rollback() raise +def delete_plans_by_ids(plan_ids: List[int]): + """ + 根据ID列表从数据库中物理删除月度计划。 + + :param plan_ids: 需要删除的计划ID列表。 + """ + if not plan_ids: + return + + with get_db_session() as session: + try: + # 先查询要删除的计划,用于日志记录 + plans_to_delete = session.query(MonthlyPlan).filter(MonthlyPlan.id.in_(plan_ids)).all() + if not plans_to_delete: + logger.info("没有找到需要删除的月度计划。") + return + + plan_details = "\n".join([f" {i+1}. {plan.plan_text}" for i, plan in enumerate(plans_to_delete)]) + logger.info(f"检测到月度计划超额,将删除以下 {len(plans_to_delete)} 条计划:\n{plan_details}") + + # 执行删除 + session.query(MonthlyPlan).filter( + MonthlyPlan.id.in_(plan_ids) + ).delete(synchronize_session=False) + session.commit() + + except Exception as e: + logger.error(f"删除月度计划时发生错误: {e}") + session.rollback() + raise + def soft_delete_plans(plan_ids: List[int]): """ 将指定ID的计划标记为软删除(兼容旧接口)。 diff --git a/src/schedule/monthly_plan_manager.py b/src/schedule/monthly_plan_manager.py index 2b7899d83..1e25cdf11 100644 --- a/src/schedule/monthly_plan_manager.py +++ b/src/schedule/monthly_plan_manager.py @@ -8,7 +8,9 @@ from src.common.database.monthly_plan_db import ( add_new_plans, get_archived_plans_for_month, archive_active_plans_for_month, - has_active_plans + has_active_plans, + get_active_plans_for_month, + delete_plans_by_ids ) from src.config.config import global_config, model_config from src.llm_models.utils_model import LLMRequest @@ -67,7 +69,23 @@ class MonthlyPlanManager: logger.info(f" {target_month} 没有任何有效的月度计划,将立即生成。") return await self.generate_monthly_plans(target_month) else: - # logger.info(f"{target_month} 已存在有效的月度计划,跳过生成。") + logger.info(f"{target_month} 已存在有效的月度计划。") + plans = get_active_plans_for_month(target_month) + + # 检查是否超出上限 + max_plans = global_config.monthly_plan_system.max_plans_per_month + if len(plans) > max_plans: + logger.warning(f"当前月度计划数量 ({len(plans)}) 超出上限 ({max_plans}),将自动删除多余的计划。") + # 按创建时间升序排序(旧的在前),然后删除超出上限的部分(新的) + plans_to_delete = sorted(plans, key=lambda p: p.created_at)[max_plans:] + delete_ids = [p.id for p in plans_to_delete] + delete_plans_by_ids(delete_ids) + # 重新获取计划列表 + plans = get_active_plans_for_month(target_month) + + if plans: + plan_texts = "\n".join([f" {i+1}. {plan.plan_text}" for i, plan in enumerate(plans)]) + logger.info(f"当前月度计划内容:\n{plan_texts}") return True # 已经有计划,也算成功 async def generate_monthly_plans(self, target_month: Optional[str] = None) -> bool: