package model import ( "context" "time" "spark-server/internal/module/group/entity" "spark-server/internal/pkg/errs" ) // GroupMember maps table group_members. type GroupMember struct { ID int64 `gorm:"column:id;primaryKey;autoIncrement;comment:行 id,表内自增,仅内部用;业务唯一键是 (group_id, user_id)"` GroupID int64 `gorm:"column:group_id;comment:群号,groups.id"` UserID int64 `gorm:"column:user_id;comment:成员 user_id"` Role int `gorm:"column:role;comment:1=群主 2=管理员 3=普通成员"` Nickname string `gorm:"column:nickname;comment:群内昵称,空则用用户昵称"` Remark string `gorm:"column:remark;comment:成员对该群的备注,仅自己可见"` SpeakMuted int `gorm:"column:speak_muted;comment:0=未禁言 1=被单独禁言"` JoinedAt time.Time `gorm:"column:joined_at;comment:入群时间"` } func (GroupMember) TableName() string { return "group_members" } func (r *GroupMember) entity() *entity.Member { if r == nil { return nil } m := &entity.Member{ GroupID: r.GroupID, UserID: r.UserID, Role: entity.Role(r.Role), Nickname: r.Nickname, Remark: r.Remark, JoinedAtMS: r.JoinedAt.UnixMilli(), } m.SpeakMuted = r.SpeakMuted != 0 return m } func memberRow(m *entity.Member) *GroupMember { row := &GroupMember{ GroupID: m.GroupID, UserID: m.UserID, Role: int(m.Role), Nickname: m.Nickname, Remark: m.Remark, JoinedAt: msTime(m.JoinedAtMS), } if m.SpeakMuted { row.SpeakMuted = 1 } if row.Role == 0 { row.Role = int(entity.RoleMember) } return row } func (m *Repo) GetMember(ctx context.Context, groupID, userID int64) (*entity.Member, error) { if groupID <= 0 || userID <= 0 { return nil, errs.ErrInvalidArgument } db, err := m.session(ctx) if err != nil { return nil, err } var row GroupMember if err := db.Where("group_id = ? AND user_id = ?", groupID, userID).Take(&row).Error; err != nil { return nil, mapDBErr(err) } return row.entity(), nil } func (m *Repo) ListMembers(ctx context.Context, groupID int64, limit int) ([]*entity.Member, error) { if groupID <= 0 { return nil, errs.ErrInvalidArgument } db, err := m.session(ctx) if err != nil { return nil, err } limit = entity.ClampMemberLimit(limit) var rows []GroupMember err = db.Where("group_id = ?", groupID).Order("role ASC, joined_at ASC").Limit(limit).Find(&rows).Error if err != nil { return nil, mapDBErr(err) } out := make([]*entity.Member, 0, len(rows)) for i := range rows { out = append(out, rows[i].entity()) } return out, nil } func (m *Repo) ListMemberIDs(ctx context.Context, groupID int64) ([]int64, error) { if groupID <= 0 { return nil, errs.ErrInvalidArgument } db, err := m.session(ctx) if err != nil { return nil, err } var ids []int64 err = db.Model(&GroupMember{}).Where("group_id = ?", groupID).Order("joined_at ASC").Pluck("user_id", &ids).Error if err != nil { return nil, mapDBErr(err) } return ids, nil } func (m *Repo) UpdateMember(ctx context.Context, mem *entity.Member) error { if mem == nil || mem.GroupID <= 0 || mem.UserID <= 0 { return errs.ErrInvalidArgument } db, err := m.session(ctx) if err != nil { return err } res := db.Model(&GroupMember{}).Where("group_id = ? AND user_id = ?", mem.GroupID, mem.UserID).Updates(map[string]any{ "role": mem.Role, "nickname": mem.Nickname, "remark": mem.Remark, "speak_muted": boolInt(mem.SpeakMuted), }) if res.Error != nil { return mapDBErr(res.Error) } if res.RowsAffected == 0 { return errs.ErrNotFound } return nil }