package model import ( "context" "fmt" "qnc-server/common/globalkey" "github.com/Masterminds/squirrel" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlx" ) var _ AgentModel = (*customAgentModel)(nil) type ( // AgentModel is an interface to be customized, add more methods here, // and implement the added methods in customAgentModel. AgentModel interface { agentModel // UpdateInTransaction 在事务中更新刚插入的记录,避免 UpdateWithVersion 中的 FindOne 缓存问题 UpdateInTransaction(ctx context.Context, session sqlx.Session, data *Agent) error // CountSubordinatesByTeamLeaderIds 按团队首领 id 统计未删除的直属代理数量(team_leader_id = 传入 id) CountSubordinatesByTeamLeaderIds(ctx context.Context, leaderIds []string) (map[string]int64, error) } customAgentModel struct { *defaultAgentModel } ) // NewAgentModel returns a model for the database table. func NewAgentModel(conn sqlx.SqlConn, c cache.CacheConf) AgentModel { return &customAgentModel{ defaultAgentModel: newAgentModel(conn, c), } } // UpdateInTransaction 在事务中更新刚插入的记录,避免 UpdateWithVersion 中的 FindOne 缓存问题 // 注意:此方法假设记录刚插入,version 为 0,更新后 version 为 1 func (m *customAgentModel) UpdateInTransaction(ctx context.Context, session sqlx.Session, data *Agent) error { if session == nil { return errors.New("session is required for UpdateInTransaction") } // 直接执行 SQL UPDATE,避免 FindOne 的缓存问题 // 字段顺序:user_id, level, region, mobile, wechat_id, team_leader_id, delete_time, del_state, version query := fmt.Sprintf("update %s set `user_id`=?, `level`=?, `region`=?, `mobile`=?, `wechat_id`=?, `team_leader_id`=?, `delete_time`=?, `del_state`=?, `version`=? where `id`=? and `version`=?", m.table) // 确保 version 从 0 增加到 1 oldVersion := data.Version data.Version = oldVersion + 1 result, err := session.ExecCtx(ctx, query, data.UserId, data.Level, data.Region, data.Mobile, data.WechatId, data.TeamLeaderId, data.DeleteTime, data.DelState, data.Version, data.Id, oldVersion) if err != nil { return errors.Wrapf(err, "UpdateInTransaction failed") } rowsAffected, err := result.RowsAffected() if err != nil { return errors.Wrapf(err, "UpdateInTransaction failed to get rows affected") } if rowsAffected == 0 { return errors.Wrapf(ErrNoRowsUpdate, "UpdateInTransaction: no rows updated, version may not match") } return nil } type teamLeaderSubCountRow struct { TeamLeaderId string `db:"team_leader_id"` Cnt int64 `db:"cnt"` } func (m *customAgentModel) CountSubordinatesByTeamLeaderIds(ctx context.Context, leaderIds []string) (map[string]int64, error) { out := make(map[string]int64) if len(leaderIds) == 0 { return out, nil } // 不含「自己挂在自己名下」的记录,否则首领会在自己的下级列表里且下级数量虚高 qb := squirrel.Select("team_leader_id", "COUNT(*) AS cnt"). From(m.table). Where(squirrel.Eq{"del_state": globalkey.DelStateNo}). Where(squirrel.Eq{"team_leader_id": leaderIds}). Where("`id` <> `team_leader_id`"). GroupBy("team_leader_id") query, args, err := qb.ToSql() if err != nil { return nil, err } var rows []teamLeaderSubCountRow if err := m.QueryRowsNoCacheCtx(ctx, &rows, query, args...); err != nil { return nil, err } for _, r := range rows { if r.TeamLeaderId != "" { out[r.TeamLeaderId] = r.Cnt } } return out, nil }