package userclient import ( "context" userv1 "hyapp.local/api/proto/user/v1" ) type PrettyDisplayIDPool struct { AppCode string `json:"app_code"` PoolID string `json:"pool_id"` Name string `json:"name"` LevelTrack string `json:"level_track"` MinLevel int32 `json:"min_level"` MaxLevel int32 `json:"max_level"` RuleType string `json:"rule_type"` RuleConfigJSON string `json:"rule_config_json"` Status string `json:"status"` SortOrder int32 `json:"sort_order"` CreatedByAdminID int64 `json:"created_by_admin_id,string"` UpdatedByAdminID int64 `json:"updated_by_admin_id,string"` CreatedAtMs int64 `json:"created_at_ms"` UpdatedAtMs int64 `json:"updated_at_ms"` } type PrettyDisplayID struct { AppCode string `json:"app_code"` PrettyID string `json:"pretty_id"` PoolID string `json:"pool_id"` Source string `json:"source"` DisplayUserID string `json:"display_user_id"` Status string `json:"status"` AssignedUserID int64 `json:"assigned_user_id,string"` AssignedLeaseID string `json:"assigned_lease_id"` AssignedAtMs int64 `json:"assigned_at_ms"` ReleasedAtMs int64 `json:"released_at_ms"` ReleaseReason string `json:"release_reason"` GeneratedBatchID string `json:"generated_batch_id"` CreatedByAdminID int64 `json:"created_by_admin_id,string"` CreatedAtMs int64 `json:"created_at_ms"` UpdatedAtMs int64 `json:"updated_at_ms"` Pool *PrettyDisplayIDPool `json:"pool,omitempty"` } type PrettyDisplayIDGenerationBatch struct { AppCode string `json:"app_code"` BatchID string `json:"batch_id"` PoolID string `json:"pool_id"` RuleType string `json:"rule_type"` RuleConfigJSON string `json:"rule_config_json"` RequestedCount int32 `json:"requested_count"` GeneratedCount int32 `json:"generated_count"` SkippedConflictCount int32 `json:"skipped_conflict_count"` Status string `json:"status"` OperatorAdminID int64 `json:"operator_admin_id,string"` RequestID string `json:"request_id"` CreatedAtMs int64 `json:"created_at_ms"` UpdatedAtMs int64 `json:"updated_at_ms"` } type ListPrettyDisplayIDPoolsRequest struct { RequestID string Caller string Status string LevelTrack string Page int32 PageSize int32 } type PrettyDisplayIDPoolRequest struct { RequestID string Caller string PoolID string Name string LevelTrack string MinLevel int32 MaxLevel int32 RuleType string RuleConfigJSON string Status string SortOrder int32 OperatorAdminID int64 } type GeneratePrettyDisplayIDsRequest struct { RequestID string Caller string PoolID string RuleType string RuleConfigJSON string Count int32 OperatorAdminID int64 } type ListPrettyDisplayIDsRequest struct { RequestID string Caller string PoolID string Source string Status string Keyword string AssignedUserID int64 Page int32 PageSize int32 } type SetPrettyDisplayIDStatusRequest struct { RequestID string Caller string PrettyID string Status string Reason string OperatorAdminID int64 } type AdminGrantPrettyDisplayIDRequest struct { RequestID string Caller string TargetUserID int64 DisplayUserID string DurationMs int64 Reason string OperatorAdminID int64 } type AdminGrantPrettyDisplayIDResult struct { Identity *UserIdentity `json:"identity"` PrettyID string `json:"pretty_id"` LeaseID string `json:"lease_id"` } // 以下方法只做 admin-server 到 user-service 的传输适配:HTTP 层 DTO 保持 snake_case,gRPC 层字段按 proto 命名传递。 func (c *GRPCClient) ListPrettyDisplayIDPools(ctx context.Context, req ListPrettyDisplayIDPoolsRequest) ([]*PrettyDisplayIDPool, int64, error) { resp, err := c.prettyClient.ListPrettyDisplayIDPools(ctx, &userv1.ListPrettyDisplayIDPoolsRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), Status: req.Status, LevelTrack: req.LevelTrack, Page: req.Page, PageSize: req.PageSize, }) if err != nil { return nil, 0, err } items := make([]*PrettyDisplayIDPool, 0, len(resp.GetItems())) for _, item := range resp.GetItems() { items = append(items, fromProtoPrettyDisplayIDPool(item)) } return items, resp.GetTotal(), nil } func (c *GRPCClient) CreatePrettyDisplayIDPool(ctx context.Context, req PrettyDisplayIDPoolRequest) (*PrettyDisplayIDPool, error) { resp, err := c.prettyClient.CreatePrettyDisplayIDPool(ctx, &userv1.CreatePrettyDisplayIDPoolRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), Name: req.Name, LevelTrack: req.LevelTrack, MinLevel: req.MinLevel, MaxLevel: req.MaxLevel, RuleType: req.RuleType, RuleConfigJson: req.RuleConfigJSON, Status: req.Status, SortOrder: req.SortOrder, OperatorAdminId: req.OperatorAdminID, }) if err != nil { return nil, err } return fromProtoPrettyDisplayIDPool(resp.GetPool()), nil } func (c *GRPCClient) UpdatePrettyDisplayIDPool(ctx context.Context, req PrettyDisplayIDPoolRequest) (*PrettyDisplayIDPool, error) { resp, err := c.prettyClient.UpdatePrettyDisplayIDPool(ctx, &userv1.UpdatePrettyDisplayIDPoolRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), PoolId: req.PoolID, Name: req.Name, LevelTrack: req.LevelTrack, MinLevel: req.MinLevel, MaxLevel: req.MaxLevel, RuleType: req.RuleType, RuleConfigJson: req.RuleConfigJSON, Status: req.Status, SortOrder: req.SortOrder, OperatorAdminId: req.OperatorAdminID, }) if err != nil { return nil, err } return fromProtoPrettyDisplayIDPool(resp.GetPool()), nil } func (c *GRPCClient) GeneratePrettyDisplayIDs(ctx context.Context, req GeneratePrettyDisplayIDsRequest) (*PrettyDisplayIDGenerationBatch, error) { // 批量生成的冲突过滤、规则默认值和批次落库都在 user-service,这里不复制业务判断。 resp, err := c.prettyClient.GeneratePrettyDisplayIDs(ctx, &userv1.GeneratePrettyDisplayIDsRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), PoolId: req.PoolID, RuleType: req.RuleType, RuleConfigJson: req.RuleConfigJSON, Count: req.Count, OperatorAdminId: req.OperatorAdminID, }) if err != nil { return nil, err } return fromProtoPrettyDisplayIDGenerationBatch(resp.GetBatch()), nil } func (c *GRPCClient) ListPrettyDisplayIDs(ctx context.Context, req ListPrettyDisplayIDsRequest) ([]*PrettyDisplayID, int64, error) { resp, err := c.prettyClient.ListPrettyDisplayIDs(ctx, &userv1.ListPrettyDisplayIDsRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), PoolId: req.PoolID, Source: req.Source, Status: req.Status, Keyword: req.Keyword, AssignedUserId: req.AssignedUserID, Page: req.Page, PageSize: req.PageSize, }) if err != nil { return nil, 0, err } items := make([]*PrettyDisplayID, 0, len(resp.GetItems())) for _, item := range resp.GetItems() { items = append(items, fromProtoPrettyDisplayID(item)) } return items, resp.GetTotal(), nil } func (c *GRPCClient) SetPrettyDisplayIDStatus(ctx context.Context, req SetPrettyDisplayIDStatusRequest) (*PrettyDisplayID, error) { resp, err := c.prettyClient.SetPrettyDisplayIDStatus(ctx, &userv1.SetPrettyDisplayIDStatusRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), PrettyId: req.PrettyID, Status: req.Status, OperatorAdminId: req.OperatorAdminID, Reason: req.Reason, }) if err != nil { return nil, err } return fromProtoPrettyDisplayID(resp.GetItem()), nil } func (c *GRPCClient) AdminGrantPrettyDisplayID(ctx context.Context, req AdminGrantPrettyDisplayIDRequest) (*AdminGrantPrettyDisplayIDResult, error) { // 后台发放返回当前用户身份快照,admin-server 原样转给前端,方便页面确认最终展示号。 resp, err := c.prettyClient.AdminGrantPrettyDisplayID(ctx, &userv1.AdminGrantPrettyDisplayIDRequest{ Meta: requestMeta(ctx, req.RequestID, req.Caller), TargetUserId: req.TargetUserID, DisplayUserId: req.DisplayUserID, DurationMs: req.DurationMs, Reason: req.Reason, OperatorAdminId: req.OperatorAdminID, }) if err != nil { return nil, err } return &AdminGrantPrettyDisplayIDResult{ Identity: fromProtoUserIdentity(resp.GetIdentity()), PrettyID: resp.GetPrettyId(), LeaseID: resp.GetLeaseId(), }, nil } func fromProtoPrettyDisplayIDPool(pool *userv1.PrettyDisplayIDPool) *PrettyDisplayIDPool { if pool == nil { return nil } // 转换层保留 int64 的 string JSON tag,避免后台前端在大 ID 上丢精度。 return &PrettyDisplayIDPool{ AppCode: pool.GetAppCode(), PoolID: pool.GetPoolId(), Name: pool.GetName(), LevelTrack: pool.GetLevelTrack(), MinLevel: pool.GetMinLevel(), MaxLevel: pool.GetMaxLevel(), RuleType: pool.GetRuleType(), RuleConfigJSON: pool.GetRuleConfigJson(), Status: pool.GetStatus(), SortOrder: pool.GetSortOrder(), CreatedByAdminID: pool.GetCreatedByAdminId(), UpdatedByAdminID: pool.GetUpdatedByAdminId(), CreatedAtMs: pool.GetCreatedAtMs(), UpdatedAtMs: pool.GetUpdatedAtMs(), } } func fromProtoPrettyDisplayID(item *userv1.PrettyDisplayID) *PrettyDisplayID { if item == nil { return nil } // pool 可能为空:后台发放的自由靓号没有池归属,列表展示时仍要返回靓号本体。 return &PrettyDisplayID{ AppCode: item.GetAppCode(), PrettyID: item.GetPrettyId(), PoolID: item.GetPoolId(), Source: item.GetSource(), DisplayUserID: item.GetDisplayUserId(), Status: item.GetStatus(), AssignedUserID: item.GetAssignedUserId(), AssignedLeaseID: item.GetAssignedLeaseId(), AssignedAtMs: item.GetAssignedAtMs(), ReleasedAtMs: item.GetReleasedAtMs(), ReleaseReason: item.GetReleaseReason(), GeneratedBatchID: item.GetGeneratedBatchId(), CreatedByAdminID: item.GetCreatedByAdminId(), CreatedAtMs: item.GetCreatedAtMs(), UpdatedAtMs: item.GetUpdatedAtMs(), Pool: fromProtoPrettyDisplayIDPool(item.GetPool()), } } func fromProtoPrettyDisplayIDGenerationBatch(batch *userv1.PrettyDisplayIDGenerationBatch) *PrettyDisplayIDGenerationBatch { if batch == nil { return nil } return &PrettyDisplayIDGenerationBatch{ AppCode: batch.GetAppCode(), BatchID: batch.GetBatchId(), PoolID: batch.GetPoolId(), RuleType: batch.GetRuleType(), RuleConfigJSON: batch.GetRuleConfigJson(), RequestedCount: batch.GetRequestedCount(), GeneratedCount: batch.GetGeneratedCount(), SkippedConflictCount: batch.GetSkippedConflictCount(), Status: batch.GetStatus(), OperatorAdminID: batch.GetOperatorAdminId(), RequestID: batch.GetRequestId(), CreatedAtMs: batch.GetCreatedAtMs(), UpdatedAtMs: batch.GetUpdatedAtMs(), } }