diff --git a/db/scripts/init.sql b/db/scripts/init.sql index 8e79966..e58e00d 100644 --- a/db/scripts/init.sql +++ b/db/scripts/init.sql @@ -117,3 +117,28 @@ CREATE TABLE IF NOT EXISTS message_archive.tasks ) comment '机器人定时任务表'; + + +-- 修改签到表,添加必要字段 +ALTER TABLE t_sign_record ADD COLUMN last_continuous_days INT DEFAULT 0 COMMENT '历史最长连续签到天数'; +ALTER TABLE t_sign_record ADD COLUMN total_sign_days INT DEFAULT 0 COMMENT '总签到天数'; +ALTER TABLE t_sign_record ADD COLUMN last_sign_date DATETIME NULL COMMENT '上一次签到日期'; +ALTER TABLE t_sign_record ADD COLUMN streak_start_sign_date DATETIME NULL COMMENT '连续签到第一天日期'; +-- 添加断签前连签天数字段 +ALTER TABLE t_sign_record ADD COLUMN previous_streak INT DEFAULT 0 COMMENT '断签前的连签天数'; + + +-- 创建签到历史记录表 +CREATE TABLE IF NOT EXISTS message_archive.t_sign_history ( + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '历史记录ID', + wx_id VARCHAR(100) NOT NULL COMMENT '用户微信ID', + group_id VARCHAR(100) NOT NULL COMMENT '群聊ID', + sign_date DATE NOT NULL COMMENT '签到日期', + sign_time DATETIME NOT NULL COMMENT '签到时间', + is_makeup TINYINT(1) DEFAULT 0 COMMENT '是否为补签', + points_earned INT DEFAULT 0 COMMENT '获得的积分', + streak_count INT DEFAULT 1 COMMENT '当时的连签天数', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间', + INDEX idx_user_group (wx_id, group_id), + INDEX idx_sign_date (sign_date) +) COMMENT '用户签到历史记录表'; \ No newline at end of file diff --git a/db/sign_in.py b/db/sign_in.py index e43a717..4ae355e 100644 --- a/db/sign_in.py +++ b/db/sign_in.py @@ -109,3 +109,20 @@ class SignInDB(BaseDBOperator): wx_id, group_id ) self.execute_update(sql, params) + + def update_sign_record_with_previous_streak(self, wx_id: str, group_id: str, wx_nick_name: str, + points_to_add: int, sign_time: datetime, streak: int, + last_sign_date: datetime, previous_streak: int) -> bool: + """更新签到记录,包括上次签到日期和断签前连签天数""" + sql = """ + UPDATE t_sign_record + SET wx_nick_name = %s, points = points + %s, + sign_stat = %s, signin_streak = %s, + last_sign_date = %s, previous_streak = %s, update_time = %s + WHERE wx_id = %s AND group_id = %s + """ + params = (wx_nick_name, points_to_add, + sign_time, streak, + last_sign_date, previous_streak, datetime.now(), + wx_id, group_id) + return self.execute_update(sql, params) diff --git a/plugins/message_sign/main.py b/plugins/message_sign/main.py index 13fb107..a1bfcaf 100644 --- a/plugins/message_sign/main.py +++ b/plugins/message_sign/main.py @@ -244,6 +244,9 @@ class MessageSignPlugin(MessagePluginInterface): (roomid if roomid else sender), sender) return False, "已签到" + # 在_handle_sign_in方法中,修改断签处理逻辑 + # 找到约在第247行的代码块 + streak = 0 streak_broken = False old_streak = 1 @@ -259,8 +262,11 @@ class MessageSignPlugin(MessagePluginInterface): old_streak = streak streak_broken = False else: + # 断签时,保存之前的连签天数 streak = 1 streak_broken = True + # 保存断签前的连签天数,用于后续补签恢复 + previous_streak = user_record['signin_streak'] else: streak = 1 @@ -273,12 +279,23 @@ class MessageSignPlugin(MessagePluginInterface): if user_record: # 保存上次签到时间 last_sign_date = user_record.get('sign_stat') - self.sign_in_db.update_sign_record_with_last_date( - sender, roomid, wx_nick_name, - points_to_add, - current_time, streak, - last_sign_date # 保存上次签到时间 - ) + + # 如果断签,保存断签前的连签天数 + if streak_broken and user_record['signin_streak'] > 1: + self.sign_in_db.update_sign_record_with_previous_streak( + sender, roomid, wx_nick_name, + points_to_add, + current_time, streak, + last_sign_date, # 保存上次签到时间 + user_record['signin_streak'] # 保存断签前的连签天数 + ) + else: + self.sign_in_db.update_sign_record_with_last_date( + sender, roomid, wx_nick_name, + points_to_add, + current_time, streak, + last_sign_date # 保存上次签到时间 + ) else: self.sign_in_db.create_sign_record_with_last_date( sender, roomid, wx_nick_name, @@ -334,23 +351,26 @@ class MessageSignPlugin(MessagePluginInterface): total_points = base_points + extra_points return min(total_points, self.max_point) + # 修改_handle_makeup_sign方法,实现连签恢复功能 + def _handle_makeup_sign(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]: """处理补签请求""" sender = message.get("sender") roomid = message.get("roomid", "") all_contacts = message.get("all_contacts", {}) - + try: # 获取当前时间,带有时区信息 current_time = datetime.now(tz=pytz.timezone(self.timezone)) + today_date = current_time.date() today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0) yesterday = today_start - timedelta(days=1) day_before_yesterday = today_start - timedelta(days=2) - + # 获取用户的签到记录 user_record = self.get_user_record(sender, roomid) wx_nick_name = all_contacts.get(sender, sender) - + # 检查用户是否有签到记录 if not user_record: self.message_util.send_text_msg( @@ -358,25 +378,25 @@ class MessageSignPlugin(MessagePluginInterface): (roomid if roomid else sender), sender ) return True, "无签到记录" - + # 获取上次签到时间并规范化到零点 last_sign_date = None if user_record.get('last_sign_date'): last_sign_date = user_record['last_sign_date'].replace(hour=0, minute=0, second=0, microsecond=0) elif user_record.get('sign_stat'): last_sign_date = user_record['sign_stat'].replace(hour=0, minute=0, second=0, microsecond=0) - + # 确保时区一致 if isinstance(last_sign_date, datetime) and last_sign_date.tzinfo is None: last_sign_date = pytz.timezone(self.timezone).localize(last_sign_date) - + # 获取当前签到状态并规范化到零点 sign_stat = None if user_record.get('sign_stat'): sign_stat = user_record['sign_stat'].replace(hour=0, minute=0, second=0, microsecond=0) if sign_stat.tzinfo is None: sign_stat = pytz.timezone(self.timezone).localize(sign_stat) - + # 检查是否已经签到今天 if sign_stat and sign_stat >= today_start: # 今天已经签到,检查是否需要补签昨天 @@ -400,7 +420,7 @@ class MessageSignPlugin(MessagePluginInterface): (roomid if roomid else sender), sender ) return True, "不符合补签条件" - + if last_sign_date >= yesterday: self.LOG.info(f"昨天已签到,last_sign_date: {last_sign_date}") self.message_util.send_text_msg( @@ -408,67 +428,95 @@ class MessageSignPlugin(MessagePluginInterface): (roomid if roomid else sender), sender ) return True, "无需补签" - + # 检查用户积分是否足够 from db.points_db import PointsDBOperator, PointSource points_db = PointsDBOperator(self.db_manager) user_points = points_db.get_user_points(sender, roomid) - + if not user_points or user_points["total_points"] < self.makeup_cost: self.message_util.send_text_msg( f"❌ 积分不足!补签需要 {self.makeup_cost} 积分,您当前只有 {user_points.get('total_points', 0)} 积分。", (roomid if roomid else sender), sender ) return True, "积分不足" - + # 扣除积分 deduct_success, deduct_result = points_db.deduct_points( sender, roomid, self.makeup_cost, PointSource.PLUGIN, "签到补签消费" ) - + if not deduct_success: self.message_util.send_text_msg( f"❌ 扣除积分失败:{deduct_result.get('error', '未知错误')}", (roomid if roomid else sender), sender ) return True, "扣除积分失败" - - # 获取原连签天数 + + # 获取原连签天数和断签前连签天数 original_streak = user_record['signin_streak'] - + previous_streak = user_record.get('previous_streak', 0) + + # 计算新的连签天数 + new_streak = original_streak + + # 如果今天已签到且有断签前记录,恢复连签 + if sign_stat and sign_stat >= today_start and previous_streak > 0: + # 恢复连签:断签前连签天数 + 1 (今天已签到) + new_streak = previous_streak + 1 + self.LOG.info(f"恢复连签: {previous_streak} + 1 = {new_streak}") + # 如果今天未签到且有断签前记录,也可以恢复连签 + elif previous_streak > 0: + # 恢复连签:断签前连签天数 + new_streak = previous_streak + self.LOG.info(f"恢复连签: {previous_streak}") + # 如果没有断签前记录,则连签天数+1 + else: + new_streak = original_streak + 1 + self.LOG.info(f"普通补签: {original_streak} + 1 = {new_streak}") + # 更新签到记录 yesterday_time = yesterday.replace(hour=current_time.hour, minute=current_time.minute, second=current_time.second) - + # 如果今天已经签到,则更新last_sign_date为昨天,保持sign_stat不变 if sign_stat and sign_stat >= today_start: - self.sign_in_db.update_makeup_sign( + self.sign_in_db.update_makeup_sign_with_streak_recovery( sender, roomid, wx_nick_name, 0, # 补签不增加积分 - sign_stat, original_streak + 1, - yesterday_time # 设置last_sign_date为昨天 + sign_stat, new_streak, + yesterday_time, # 设置last_sign_date为昨天 + 0 # 清除previous_streak,因为已经恢复了 ) else: # 如果今天没签到,则更新sign_stat为昨天,last_sign_date为上次签到时间 - self.sign_in_db.update_sign_record_with_last_date( + self.sign_in_db.update_sign_record_with_streak_recovery( sender, roomid, wx_nick_name, 0, # 补签不增加积分 - yesterday_time, original_streak + 1, - last_sign_date # 保留原来的last_sign_date + yesterday_time, new_streak, + last_sign_date, # 保留原来的last_sign_date + 0 # 清除previous_streak,因为已经恢复了 ) - + # 发送成功消息 + success_message = f"✅ 补签成功!\n💰 消费 {self.makeup_cost} 积分\n" + + # 如果恢复了连签,显示恢复信息 + if new_streak > original_streak + 1: + success_message += f"🎉 恢复连签!连续签到天数:{new_streak}\n" + else: + success_message += f"🔄 连续签到天数:{new_streak}\n" + + success_message += f"💰 当前积分:{user_points['total_points'] - self.makeup_cost}" + self.message_util.send_text_msg( - f"✅ 补签成功!\n" - f"💰 消费 {self.makeup_cost} 积分\n" - f"🔄 连续签到天数:{original_streak + 1}\n" - f"💰 当前积分:{user_points['total_points'] - self.makeup_cost}", + success_message, (roomid if roomid else sender), sender ) - + return True, "补签成功" - + except Exception as e: self.LOG.error(f"处理补签请求出错: {e}") self.message_util.send_text_msg(