248 lines
6.3 KiB
Go
248 lines
6.3 KiB
Go
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
|
||
}
|