diff --git a/entity/friend.go b/entity/friend.go index 96ee1ac..884c27d 100644 --- a/entity/friend.go +++ b/entity/friend.go @@ -20,6 +20,7 @@ type Friend struct { EnableWelcome bool `json:"enableWelcome" gorm:"type:tinyint(1) default 0 not null"` // 是否启用迎新 EnableSummary bool `json:"enableSummary" gorm:"type:tinyint(1) default 0 not null"` // 是否启用总结 EnableNews bool `json:"enableNews" gorm:"type:tinyint(1) default 0 not null"` // 是否启用新闻 + ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的) IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常 } diff --git a/service/friend.go b/service/friend.go index e3e6cf3..948cbbb 100644 --- a/service/friend.go +++ b/service/friend.go @@ -77,6 +77,15 @@ func GetAllEnableNews() (records []entity.Friend, err error) { return } +// GetAllEnableClearGroup +// @description: 获取所有需要清理成员的群组 +// @return records +// @return err +func GetAllEnableClearGroup() (records []entity.Friend, err error) { + err = client.MySQL.Where("clear_members != 0").Where("is_ok IS TRUE").Find(&records).Error + return +} + // CheckIsEnableCommand // @description: 检查用户是否启用了指令 // @param userId diff --git a/tasks/cleargroupuser/cleargroupuser.go b/tasks/cleargroupuser/cleargroupuser.go new file mode 100644 index 0000000..c236b4c --- /dev/null +++ b/tasks/cleargroupuser/cleargroupuser.go @@ -0,0 +1,68 @@ +package cleargroupuser + +import ( + "fmt" + "go-wechat/client" + "go-wechat/entity" + "go-wechat/service" + "go-wechat/utils" + "log" + "strings" +) + +// ClearGroupUser +// @description: 清理群成员 +func ClearGroupUser() { + groups, err := service.GetAllEnableNews() + if err != nil { + log.Printf("获取启用了聊天排行榜的群组失败, 错误信息: %v", err) + return + } + + for _, group := range groups { + // 获取需要清理的群成员Id + members := getNeedDeleteMembers(group.Wxid, group.ClearMember) + memberCount := len(members) + log.Printf("群[%s(%s)]需要清理的成员数量: %d", group.Nickname, group.Wxid, memberCount) + if memberCount < 1 { + continue + } + var memberMap = make(map[string]string) + var deleteIds = make([]string, 0) + for _, member := range members { + deleteIds = append(deleteIds, member.Wxid) + // 昵称为空,取id后4位 + if member.Nickname == "" { + member.Nickname = "无名氏_" + member.Wxid[len(member.Wxid)-4:] + } + memberMap[member.Nickname] = member.LastActive.Format("2006-01-02 15:04:05") + } + // 调用接口 + utils.DeleteGroupMember(group.Wxid, strings.Join(deleteIds, ","), 0) + // 发送通知到群里 + ms := make([]string, 0) + for k, v := range memberMap { + ms = append(ms, fmt.Sprintf("%s: %s", k, v)) + } + msg := fmt.Sprintf("#清理群成员#\n\n很遗憾地通知各位,就在刚刚,有%d名群友引活跃度不够暂时离开了我们,希望还健在的群友引以为戒、保持活跃!\n\n活跃信息: \n%s", + memberCount, strings.Join(ms, "\n")) + utils.SendMessage(group.Wxid, "", msg, 0) + } +} + +// getNeedDeleteMembers +// @description: 获取需要删除的群成员 +// @param groupId 群Id +// @param days 需要清理的未活跃的天数 +// @return members +func getNeedDeleteMembers(groupId string, days int) (members []entity.GroupUser) { + err := client.MySQL.Model(&entity.GroupUser{}).Where("group_id = ?", groupId). + Where("is_member IS TRUE"). + Where("DATEDIFF( NOW(), last_active ) >= ?", days). + Order("last_active DESC"). + Find(&members).Error + if err != nil { + log.Printf("获取需要清理的群成员失败, 错误信息: %v", err) + } + return +} diff --git a/tasks/friends/friends.go b/tasks/friends/friends.go index 8be344a..d47ea35 100644 --- a/tasks/friends/friends.go +++ b/tasks/friends/friends.go @@ -75,6 +75,7 @@ func Sync() { EnableSummary: config.Conf.System.DefaultRule.Summary, EnableWelcome: config.Conf.System.DefaultRule.Welcome, EnableNews: config.Conf.System.DefaultRule.News, + ClearMember: 0, LastActive: time.Now().Local(), }).Error if err != nil { diff --git a/tasks/tasks.go b/tasks/tasks.go index 4ff0724..9627c01 100644 --- a/tasks/tasks.go +++ b/tasks/tasks.go @@ -3,6 +3,7 @@ package tasks import ( "github.com/go-co-op/gocron" "go-wechat/config" + "go-wechat/tasks/cleargroupuser" "go-wechat/tasks/friends" "go-wechat/tasks/news" "go-wechat/tasks/summary" @@ -56,6 +57,9 @@ func InitTasks() { _, _ = s.Cron(config.Conf.Task.News.Cron).Do(news.DailyNews) } + // 每天0点检查一次处理清理群成员 + _, _ = s.Cron("0 0 * * *").Do(cleargroupuser.ClearGroupUser) + // 开启定时任务 s.StartAsync() log.Println("定时任务初始化成功") diff --git a/tasks/watergroup/utils.go b/tasks/watergroup/utils.go index 510653b..0f48e3d 100644 --- a/tasks/watergroup/utils.go +++ b/tasks/watergroup/utils.go @@ -32,7 +32,7 @@ func getRankData(groupId, date string) (rank []rankUser, err error) { case "week": tx.Where("YEARWEEK(date_format(tm.create_at, '%Y-%m-%d')) = YEARWEEK(now()) - 1") case "month": - tx.Where("PERIOD_DIFF(date_format(now(), '%Y%m'), date_format(create_at, '%Y%m')) = 1") + tx.Where("PERIOD_DIFF(date_format(now(), '%Y%m'), date_format(tm.create_at, '%Y%m')) = 1") case "year": tx.Where("YEAR(tm.create_at) = YEAR(NOW()) - 1") } diff --git a/utils/send.go b/utils/send.go index 9ac1498..7c4e1ed 100644 --- a/utils/send.go +++ b/utils/send.go @@ -121,3 +121,34 @@ func SendEmotion(toId, emotionHash string, retryCount int) { } log.Printf("发送表情包消息结果: %s", resp.String()) } + +// DeleteGroupMember +// @description: 删除群成员 +// @param chatRoomId 群Id +// @param memberIds 成员id,用','分隔 +func DeleteGroupMember(chatRoomId, memberIds string, retryCount int) { + if retryCount > 5 { + log.Printf("重试五次失败,停止发送") + return + } + + // 组装参数 + param := map[string]any{ + "chatRoomId": chatRoomId, // 群Id + "memberIds": memberIds, // 成员id + } + pbs, _ := json.Marshal(param) + + res := resty.New() + resp, err := res.R(). + SetHeader("Content-Type", "application/json;chartset=utf-8"). + SetBody(string(pbs)). + Post(config.Conf.Wechat.GetURL("/api/delMemberFromChatRoom")) + if err != nil { + log.Printf("删除群成员失败: %s", err.Error()) + // 休眠五秒后重新发送 + time.Sleep(5 * time.Second) + SendImage(chatRoomId, memberIds, retryCount+1) + } + log.Printf("删除群成员结果: %s", resp.String()) +} diff --git a/views/group.html b/views/group.html index d508132..efd4f8b 100644 --- a/views/group.html +++ b/views/group.html @@ -50,6 +50,9 @@ 指令 + + 末位淘汰(天) + 操作 @@ -107,6 +110,9 @@ {{ template "command" . }} + + {{ .ClearMember }} + diff --git a/vo/friend.go b/vo/friend.go index da0da93..dbca7af 100644 --- a/vo/friend.go +++ b/vo/friend.go @@ -20,6 +20,7 @@ type FriendItem struct { EnableCommand bool // 是否启用指令 EnableSummary bool // 是否启用总结 EnableNews bool // 是否启用新闻 + ClearMember int // 清理成员配置(多少天未活跃的) IsOk bool // 是否还在通讯库(群聊是要还在群里也算) }