2026-05-16 08:12:42 +08:00

248 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package resource
import (
"context"
"strings"
"hyapp-admin-server/internal/appctx"
"hyapp-admin-server/internal/model"
)
const (
grantSourceAdmin = "admin"
grantSourceManagerCenter = "manager_center"
)
type adminOperator struct {
UserID uint
Username string
Name string
}
type managerOperator struct {
UserID int64
DisplayUserID string
Username string
Avatar string
}
func (h *Handler) enrichGrantTargets(ctx context.Context, grants []grantDTO) error {
ids := collectGrantTargetIDs(grants)
if len(ids) == 0 {
return nil
}
users := make(map[int64]grantUserDTO, len(ids))
if h.userDB != nil {
var err error
users, err = h.queryGrantTargetUsers(ctx, ids)
if err != nil {
return err
}
}
applyGrantTargetUsers(grants, users)
return nil
}
func (h *Handler) queryGrantTargetUsers(ctx context.Context, ids []int64) (map[int64]grantUserDTO, error) {
out := make(map[int64]grantUserDTO, len(ids))
if len(ids) == 0 || h.userDB == nil {
return out, nil
}
args := append([]any{appctx.FromContext(ctx)}, int64Args(ids)...)
rows, err := h.userDB.QueryContext(ctx, `
SELECT user_id,
current_display_user_id,
COALESCE(username, ''),
COALESCE(avatar, '')
FROM users
WHERE app_code = ? AND user_id IN (`+placeholders(len(ids))+`)
`, args...)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var user grantUserDTO
if err := rows.Scan(&user.UserID, &user.DisplayUserID, &user.Username, &user.Avatar); err != nil {
return nil, err
}
out[user.UserID] = user
}
return out, rows.Err()
}
func applyGrantTargetUsers(grants []grantDTO, users map[int64]grantUserDTO) {
for index := range grants {
targetUserID := grants[index].TargetUserID
if targetUserID <= 0 {
continue
}
if user, ok := users[targetUserID]; ok {
grants[index].TargetUser = &user
continue
}
grants[index].TargetUser = &grantUserDTO{UserID: targetUserID}
}
}
func (h *Handler) enrichGrantOperators(ctx context.Context, grants []grantDTO) error {
// operator_user_id 在 wallet 发放事实里只保存稳定 ID后台列表按来源补展示资料避免把 admin 用户和 app 用户混成同一张表。
adminIDs, managerIDs := collectGrantOperatorIDs(grants)
admins, err := h.queryAdminOperators(adminIDs)
if err != nil {
return err
}
managers, err := h.queryManagerOperators(ctx, managerIDs)
if err != nil {
return err
}
applyGrantOperators(grants, admins, managers)
return nil
}
func (h *Handler) queryAdminOperators(ids []uint) (map[uint]adminOperator, error) {
out := make(map[uint]adminOperator, len(ids))
if len(ids) == 0 || h.store == nil {
return out, nil
}
users, err := h.store.UsersByIDs(ids)
if err != nil {
return nil, err
}
for id, user := range users {
out[id] = adminOperatorFromModel(user)
}
return out, nil
}
func (h *Handler) queryManagerOperators(ctx context.Context, ids []int64) (map[int64]managerOperator, error) {
out := make(map[int64]managerOperator, len(ids))
if len(ids) == 0 || h.userDB == nil {
return out, nil
}
// 经理中心发放人是 app 用户,只读 user-service 的用户库投影;资源发放事实仍然以 wallet-service 返回为准。
args := append([]any{appctx.FromContext(ctx)}, int64Args(ids)...)
rows, err := h.userDB.QueryContext(ctx, `
SELECT user_id,
current_display_user_id,
COALESCE(username, ''),
COALESCE(avatar, '')
FROM users
WHERE app_code = ? AND user_id IN (`+placeholders(len(ids))+`)
`, args...)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var operator managerOperator
if err := rows.Scan(&operator.UserID, &operator.DisplayUserID, &operator.Username, &operator.Avatar); err != nil {
return nil, err
}
out[operator.UserID] = operator
}
return out, rows.Err()
}
func applyGrantOperators(grants []grantDTO, admins map[uint]adminOperator, managers map[int64]managerOperator) {
for index := range grants {
source := normalizeGrantSource(grants[index].GrantSource)
operatorID := grants[index].OperatorUserID
if operatorID <= 0 {
continue
}
// 即使资料缺失也返回 source + user_id前端仍能展示可追溯的操作人线索。
operator := &operatorDTO{
Source: source,
UserID: operatorID,
}
switch source {
case grantSourceAdmin:
if admin, ok := admins[uint(operatorID)]; ok {
operator.Username = admin.Username
operator.Name = admin.Name
}
case grantSourceManagerCenter:
if manager, ok := managers[operatorID]; ok {
operator.DisplayUserID = manager.DisplayUserID
operator.Username = manager.Username
operator.Avatar = manager.Avatar
}
}
grants[index].Operator = operator
}
}
func collectGrantOperatorIDs(grants []grantDTO) ([]uint, []int64) {
adminSet := make(map[uint]struct{})
managerSet := make(map[int64]struct{})
for _, grant := range grants {
if grant.OperatorUserID <= 0 {
continue
}
switch normalizeGrantSource(grant.GrantSource) {
case grantSourceAdmin:
adminSet[uint(grant.OperatorUserID)] = struct{}{}
case grantSourceManagerCenter:
managerSet[grant.OperatorUserID] = struct{}{}
}
}
adminIDs := make([]uint, 0, len(adminSet))
for id := range adminSet {
adminIDs = append(adminIDs, id)
}
managerIDs := make([]int64, 0, len(managerSet))
for id := range managerSet {
managerIDs = append(managerIDs, id)
}
return adminIDs, managerIDs
}
func collectGrantTargetIDs(grants []grantDTO) []int64 {
targetSet := make(map[int64]struct{})
for _, grant := range grants {
if grant.TargetUserID <= 0 {
continue
}
targetSet[grant.TargetUserID] = struct{}{}
}
targetIDs := make([]int64, 0, len(targetSet))
for id := range targetSet {
targetIDs = append(targetIDs, id)
}
return targetIDs
}
func adminOperatorFromModel(user model.User) adminOperator {
return adminOperator{
UserID: user.ID,
Username: user.Username,
Name: user.Name,
}
}
func normalizeGrantSource(source string) string {
return strings.ToLower(strings.TrimSpace(source))
}
func placeholders(count int) string {
if count <= 0 {
return ""
}
items := make([]string, count)
for index := range items {
items[index] = "?"
}
return strings.Join(items, ",")
}
func int64Args(values []int64) []any {
args := make([]any, 0, len(values))
for _, value := range values {
args = append(args, value)
}
return args
}