package wecom import ( "context" "strings" "time" "gorm.io/gorm" "gorm.io/gorm/clause" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // MemberRepository 持久化企业微信应用可见成员快照。 type MemberRepository struct { db *gorm.DB } // NewMemberRepository 创建企业微信成员快照 Repository。 func NewMemberRepository(db *gorm.DB) *MemberRepository { return &MemberRepository{db: db} } // ReplaceVisible 原子替换指定应用当前可见成员,历史不可见成员仅标记为不可见。 func (r *MemberRepository) ReplaceVisible(ctx context.Context, applicationID uint, members []model.WeComMember, syncedAt time.Time) error { if r == nil || r.db == nil { return errors.New(errors.CodeDatabaseError, "企业微信成员存储未配置") } err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Model(&model.WeComMember{}).Where("application_id = ?", applicationID). Updates(map[string]any{"visible": false, "updated_at": syncedAt}).Error; err != nil { return err } if len(members) == 0 { return nil } return tx.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "application_id"}, {Name: "userid"}}, DoUpdates: clause.Assignments(map[string]any{ "corp_id": gorm.Expr("EXCLUDED.corp_id"), "name": gorm.Expr("EXCLUDED.name"), "department_ids": gorm.Expr("EXCLUDED.department_ids"), "visible": true, "synced_at": gorm.Expr("EXCLUDED.synced_at"), "updated_at": syncedAt, }), }).CreateInBatches(&members, constants.WeComMemberSyncBatchSize).Error }) if err != nil { return errors.Wrap(errors.CodeDatabaseError, err, "同步企业微信可见成员失败") } return nil } // ListVisible 分页查询指定应用当前可见成员。 func (r *MemberRepository) ListVisible(ctx context.Context, applicationID uint, page, pageSize int, keyword string) ([]model.WeComMember, int64, error) { query := r.db.WithContext(ctx).Model(&model.WeComMember{}). Joins("JOIN tb_wecom_application ON tb_wecom_application.id = tb_wecom_member.application_id AND tb_wecom_application.deleted_at IS NULL AND tb_wecom_application.status = ?", constants.StatusEnabled). Where("tb_wecom_member.application_id = ? AND tb_wecom_member.visible = ?", applicationID, true) keyword = strings.TrimSpace(keyword) if keyword != "" { query = query.Where("tb_wecom_member.name ILIKE ? OR tb_wecom_member.userid ILIKE ?", "%"+keyword+"%", "%"+keyword+"%") } var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "统计企业微信可见成员失败") } var members []model.WeComMember if err := query.Select("tb_wecom_member.*").Order("tb_wecom_member.name ASC, tb_wecom_member.userid ASC"). Offset((page - 1) * pageSize).Limit(pageSize).Find(&members).Error; err != nil { return nil, 0, errors.Wrap(errors.CodeDatabaseError, err, "查询企业微信可见成员失败") } return members, total, nil } // GetVisible 查询可用于账号绑定的应用可见成员。 func (r *MemberRepository) GetVisible(ctx context.Context, applicationID uint, userID string) (*model.WeComMember, error) { var member model.WeComMember if err := r.db.WithContext(ctx).Model(&model.WeComMember{}). Select("tb_wecom_member.*"). Joins("JOIN tb_wecom_application ON tb_wecom_application.id = tb_wecom_member.application_id AND tb_wecom_application.deleted_at IS NULL AND tb_wecom_application.status = ?", constants.StatusEnabled). Where("tb_wecom_member.application_id = ? AND tb_wecom_member.userid = ? AND tb_wecom_member.visible = ?", applicationID, strings.ToLower(strings.TrimSpace(userID)), true). First(&member).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.New(errors.CodeInvalidParam, "所选成员不在企业微信应用可见范围内") } return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询企业微信可见成员失败") } return &member, nil }