add: 打手初始化接口

This commit is contained in:
zetaloop
2026-04-04 03:35:36 +08:00
parent 85ce6a45c5
commit 32d58ef462
12 changed files with 224 additions and 21 deletions
+3
View File
@@ -16,3 +16,6 @@ Prometheus:
PlayerRpcConf: PlayerRpcConf:
Endpoints: Endpoints:
- player-rpc:8080 - player-rpc:8080
UsercenterRpcConf:
Endpoints:
- user-rpc:8080
+1
View File
@@ -11,4 +11,5 @@ import (
type Config struct { type Config struct {
rest.RestConf rest.RestConf
PlayerRpcConf zrpc.RpcClientConf PlayerRpcConf zrpc.RpcClientConf
UsercenterRpcConf zrpc.RpcClientConf
} }
@@ -0,0 +1,38 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package player
import (
"errors"
"juwan-backend/common/utils/responses"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"juwan-backend/app/player/api/internal/logic/player"
"juwan-backend/app/player/api/internal/svc"
"juwan-backend/app/player/api/internal/types"
)
// 初始化当前用户的打手资料
func InitPlayerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.EmptyResp
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := player.NewInitPlayerLogic(r.Context(), svcCtx)
resp, err := l.InitPlayer(&req)
if err != nil {
if errors.Is(err, player.ErrPlayerNotEligible) {
httpx.ErrorCtx(r.Context(), w, responses.NewErrorResp(http.StatusForbidden, err))
return
}
httpx.ErrorCtx(r.Context(), w, err)
} else {
httpx.OkJsonCtx(r.Context(), w, resp)
}
}
}
@@ -51,6 +51,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes( server.AddRoutes(
[]rest.Route{ []rest.Route{
{
// 初始化当前用户的打手资料
Method: http.MethodPost,
Path: "/players/me",
Handler: player.InitPlayerHandler(serverCtx),
},
{ {
// 更新接单状态 // 更新接单状态
Method: http.MethodPut, Method: http.MethodPut,
@@ -0,0 +1,128 @@
// Code scaffolded by goctl. Safe to edit.
// goctl 1.9.2
package player
import (
"context"
"encoding/json"
"errors"
"slices"
"strconv"
"time"
"juwan-backend/app/player/api/internal/svc"
"juwan-backend/app/player/api/internal/types"
"juwan-backend/app/player/rpc/playerservice"
"juwan-backend/app/users/rpc/usercenter"
"juwan-backend/common/utils/contextj"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/status"
)
var ErrPlayerNotEligible = errors.New("player role not verified")
type InitPlayerLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// 初始化当前用户的打手资料
func NewInitPlayerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InitPlayerLogic {
return &InitPlayerLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *InitPlayerLogic) InitPlayer(req *types.EmptyResp) (resp *types.PlayerProfile, err error) {
userID, err := contextj.UserIDFrom(l.ctx)
if err != nil {
return nil, err
}
userResp, err := l.svcCtx.UserRpc.GetUsersById(l.ctx, &usercenter.GetUsersByIdReq{Id: userID})
if err != nil {
return nil, err
}
if userResp.GetUsers() == nil {
return nil, ErrPlayerNotEligible
}
if !slices.Contains(userResp.GetUsers().VerifiedRoles, "player") {
return nil, ErrPlayerNotEligible
}
verificationStatus := map[string]string{}
if userResp.GetUsers().VerificationStatus != "" {
_ = json.Unmarshal([]byte(userResp.GetUsers().VerificationStatus), &verificationStatus)
}
playerReq := &playerservice.SearchPlayersReq{UserId: &userID}
playerResp, err := l.svcCtx.PlayerRpc.GetPlayerByUserId(l.ctx, playerReq)
if err != nil {
st, _ := status.FromError(err)
if st.Code().String() != "NotFound" {
logx.Errorf("InitPlayerLogic.GetPlayerByUserId err: %v", err)
return nil, errors.New("get player failed")
}
_, err = l.svcCtx.PlayerRpc.AddPlayers(l.ctx, &playerservice.AddPlayersReq{
UserId: userID,
Status: "offline",
Rating: 5,
Gender: 1,
})
if err != nil {
logx.Errorf("InitPlayerLogic.AddPlayers err: %v", err)
return nil, errors.New("create player failed")
}
playerResp, err = l.svcCtx.PlayerRpc.GetPlayerByUserId(l.ctx, playerReq)
if err != nil {
logx.Errorf("InitPlayerLogic.GetPlayerByUserId after create err: %v", err)
return nil, errors.New("get player failed")
}
}
player := playerResp.GetPlayers()
if player == nil {
return nil, errors.New("player not found")
}
games := make([]string, 0, len(player.Games))
for _, gameID := range player.Games {
games = append(games, strconv.FormatInt(gameID, 10))
}
resp = &types.PlayerProfile{
Id: player.Id,
User: types.UserProfile{
Id: strconv.FormatInt(userResp.GetUsers().Id, 10),
Username: userResp.GetUsers().Username,
Nickname: userResp.GetUsers().Nickname,
Avatar: userResp.GetUsers().Avatar,
Role: userResp.GetUsers().CurrentRole,
VerifiedRoles: append([]string{}, userResp.GetUsers().VerifiedRoles...),
Phone: userResp.GetUsers().Phone,
Bio: userResp.GetUsers().Bio,
CreatedAt: time.Unix(userResp.GetUsers().CreatedAt, 0).Format(time.DateTime),
},
Rating: player.Rating,
TotalOrders: player.TotalOrders,
Status: player.Status,
Games: games,
Services: []types.PlayerService{},
Gender: player.Gender,
Tags: append([]string{}, player.Tags...),
}
resp.User.VerificationStatus = verificationStatus
if player.ShopId != 0 {
resp.ShopId = strconv.FormatInt(player.ShopId, 10)
}
return resp, nil
}
@@ -6,6 +6,7 @@ package svc
import ( import (
"juwan-backend/app/player/api/internal/config" "juwan-backend/app/player/api/internal/config"
"juwan-backend/app/player/rpc/playerservice" "juwan-backend/app/player/rpc/playerservice"
"juwan-backend/app/users/rpc/usercenter"
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
) )
@@ -13,11 +14,13 @@ import (
type ServiceContext struct { type ServiceContext struct {
Config config.Config Config config.Config
PlayerRpc playerservice.PlayerService PlayerRpc playerservice.PlayerService
UserRpc usercenter.Usercenter
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
PlayerRpc: playerservice.NewPlayerService(zrpc.MustNewClient(c.PlayerRpcConf)), PlayerRpc: playerservice.NewPlayerService(zrpc.MustNewClient(c.PlayerRpcConf)),
UserRpc: usercenter.NewUsercenter(zrpc.MustNewClient(c.UsercenterRpcConf)),
} }
} }
@@ -33,18 +33,28 @@ func (l *AddPlayersLogic) AddPlayers(in *pb.AddPlayersReq) (*pb.AddPlayersResp,
logx.Errorf("addPlayerServices err:%v", err) logx.Errorf("addPlayerServices err:%v", err)
return nil, errors.New("create player service id failed") return nil, errors.New("create player service id failed")
} }
_, err = l.svcCtx.PlayerModelRW.Players.Create(). creator := l.svcCtx.PlayerModelRW.Players.Create().
SetID(idResp.Id). SetID(idResp.Id).
SetUserID(in.UserId). SetUserID(in.UserId).
SetStatus(in.Status). SetStatus(in.Status).
SetRating(decimal.NewFromFloat(in.Rating)). SetRating(decimal.NewFromFloat(in.Rating)).
SetTotalOrders(int(in.TotalOrders)). SetGender(in.Gender != 0)
SetCompletedOrders(int(in.CompletedOrders)). if in.TotalOrders != 0 {
SetShopID(in.ShopId). creator.SetTotalOrders(int(in.TotalOrders))
SetTags(in.Tags). }
SetGender(in.Gender != 0). if in.CompletedOrders != 0 {
SetGames(in.Games). creator.SetCompletedOrders(int(in.CompletedOrders))
Save(l.ctx) }
if in.ShopId != 0 {
creator.SetShopID(in.ShopId)
}
if len(in.GetTags()) > 0 {
creator.SetTags(in.GetTags())
}
if len(in.GetGames()) > 0 {
creator.SetGames(in.GetGames())
}
_, err = creator.Save(l.ctx)
if err != nil { if err != nil {
logx.Errorf("addPlayerServices err:%v", err) logx.Errorf("addPlayerServices err:%v", err)
return nil, errors.New("add player service failed") return nil, errors.New("add player service failed")
@@ -3,12 +3,15 @@ package logic
import ( import (
"context" "context"
"errors" "errors"
"juwan-backend/app/player/rpc/internal/models"
"juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/models/players"
"juwan-backend/app/player/rpc/internal/svc" "juwan-backend/app/player/rpc/internal/svc"
"juwan-backend/app/player/rpc/pb" "juwan-backend/app/player/rpc/pb"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
type GetPlayerByUserIdLogic struct { type GetPlayerByUserIdLogic struct {
@@ -32,6 +35,9 @@ func (l *GetPlayerByUserIdLogic) GetPlayerByUserId(in *pb.SearchPlayersReq) (*pb
player, err := l.svcCtx.PlayerModelRO.Players.Query().Where(players.UserIDEQ(in.GetUserId())).First(l.ctx) player, err := l.svcCtx.PlayerModelRO.Players.Query().Where(players.UserIDEQ(in.GetUserId())).First(l.ctx)
if err != nil { if err != nil {
if models.IsNotFound(err) {
return nil, status.Error(codes.NotFound, "player not found")
}
logx.WithContext(l.ctx).Errorf("GetPlayerByUserIdLogic err: %v", err) logx.WithContext(l.ctx).Errorf("GetPlayerByUserIdLogic err: %v", err)
return nil, errors.New("get player by user id failed") return nil, errors.New("get player by user id failed")
} }
@@ -40,6 +46,7 @@ func (l *GetPlayerByUserIdLogic) GetPlayerByUserId(in *pb.SearchPlayersReq) (*pb
Id: player.ID, Id: player.ID,
UserId: player.UserID, UserId: player.UserID,
Status: player.Status, Status: player.Status,
Gender: player.Gender,
Rating: player.Rating.InexactFloat64(), Rating: player.Rating.InexactFloat64(),
TotalOrders: int64(player.TotalOrders), TotalOrders: int64(player.TotalOrders),
CompletedOrders: int64(player.CompletedOrders), CompletedOrders: int64(player.CompletedOrders),
+5 -7
View File
@@ -3,9 +3,9 @@
package models package models
import ( import (
"encoding/json"
"fmt" "fmt"
"juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/models/players"
"juwan-backend/pkg/types"
"strings" "strings"
"time" "time"
@@ -51,7 +51,7 @@ func (*Players) scanValues(columns []string) ([]any, error) {
for i := range columns { for i := range columns {
switch columns[i] { switch columns[i] {
case players.FieldTags: case players.FieldTags:
values[i] = new([]byte) values[i] = new(types.TextArray)
case players.FieldRating: case players.FieldRating:
values[i] = new(decimal.Decimal) values[i] = new(decimal.Decimal)
case players.FieldGames: case players.FieldGames:
@@ -129,12 +129,10 @@ func (_m *Players) assignValues(columns []string, values []any) error {
*_m.ShopID = value.Int64 *_m.ShopID = value.Int64
} }
case players.FieldTags: case players.FieldTags:
if value, ok := values[i].(*[]byte); !ok { if value, ok := values[i].(*types.TextArray); !ok {
return fmt.Errorf("unexpected type %T for field tags", values[i]) return fmt.Errorf("unexpected type %T for field tags", values[i])
} else if value != nil && len(*value) > 0 { } else if value != nil {
if err := json.Unmarshal(*value, &_m.Tags); err != nil { _m.Tags = append([]string{}, value.Elements...)
return fmt.Errorf("unmarshal field tags: %w", err)
}
} }
case players.FieldGames: case players.FieldGames:
if value, ok := values[i].(*pq.Int64Array); !ok { if value, ok := values[i].(*pq.Int64Array); !ok {
@@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/models/players"
"juwan-backend/pkg/types"
"time" "time"
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
@@ -314,7 +315,8 @@ func (_c *PlayersCreate) createSpec() (*Players, *sqlgraph.CreateSpec) {
_node.ShopID = &value _node.ShopID = &value
} }
if value, ok := _c.mutation.Tags(); ok { if value, ok := _c.mutation.Tags(); ok {
_spec.SetField(players.FieldTags, field.TypeJSON, value) tags := types.TextArray{Elements: append([]string{}, value...), Valid: true}
_spec.SetField(players.FieldTags, field.TypeOther, tags)
_node.Tags = value _node.Tags = value
} }
if value, ok := _c.mutation.Games(); ok { if value, ok := _c.mutation.Games(); ok {
@@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/models/players"
"juwan-backend/app/player/rpc/internal/models/predicate" "juwan-backend/app/player/rpc/internal/models/predicate"
"juwan-backend/pkg/types"
"time" "time"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
@@ -326,7 +327,8 @@ func (_u *PlayersUpdate) sqlSave(ctx context.Context) (_node int, err error) {
_spec.ClearField(players.FieldShopID, field.TypeInt64) _spec.ClearField(players.FieldShopID, field.TypeInt64)
} }
if value, ok := _u.mutation.Tags(); ok { if value, ok := _u.mutation.Tags(); ok {
_spec.SetField(players.FieldTags, field.TypeJSON, value) tags := types.TextArray{Elements: append([]string{}, value...), Valid: true}
_spec.SetField(players.FieldTags, field.TypeOther, tags)
} }
if value, ok := _u.mutation.AppendedTags(); ok { if value, ok := _u.mutation.AppendedTags(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) { _spec.AddModifier(func(u *sql.UpdateBuilder) {
@@ -334,7 +336,7 @@ func (_u *PlayersUpdate) sqlSave(ctx context.Context) (_node int, err error) {
}) })
} }
if _u.mutation.TagsCleared() { if _u.mutation.TagsCleared() {
_spec.ClearField(players.FieldTags, field.TypeJSON) _spec.ClearField(players.FieldTags, field.TypeOther)
} }
if value, ok := _u.mutation.Games(); ok { if value, ok := _u.mutation.Games(); ok {
_spec.SetField(players.FieldGames, field.TypeOther, value) _spec.SetField(players.FieldGames, field.TypeOther, value)
@@ -690,7 +692,8 @@ func (_u *PlayersUpdateOne) sqlSave(ctx context.Context) (_node *Players, err er
_spec.ClearField(players.FieldShopID, field.TypeInt64) _spec.ClearField(players.FieldShopID, field.TypeInt64)
} }
if value, ok := _u.mutation.Tags(); ok { if value, ok := _u.mutation.Tags(); ok {
_spec.SetField(players.FieldTags, field.TypeJSON, value) tags := types.TextArray{Elements: append([]string{}, value...), Valid: true}
_spec.SetField(players.FieldTags, field.TypeOther, tags)
} }
if value, ok := _u.mutation.AppendedTags(); ok { if value, ok := _u.mutation.AppendedTags(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) { _spec.AddModifier(func(u *sql.UpdateBuilder) {
@@ -698,7 +701,7 @@ func (_u *PlayersUpdateOne) sqlSave(ctx context.Context) (_node *Players, err er
}) })
} }
if _u.mutation.TagsCleared() { if _u.mutation.TagsCleared() {
_spec.ClearField(players.FieldTags, field.TypeJSON) _spec.ClearField(players.FieldTags, field.TypeOther)
} }
if value, ok := _u.mutation.Games(); ok { if value, ok := _u.mutation.Games(); ok {
_spec.SetField(players.FieldGames, field.TypeOther, value) _spec.SetField(players.FieldGames, field.TypeOther, value)
+4
View File
@@ -123,6 +123,10 @@ type (
group: player group: player
) )
service player-api { service player-api {
@doc "初始化当前用户的打手资料"
@handler InitPlayer
post /players/me (EmptyResp) returns (PlayerProfile)
@doc "更新接单状态" @doc "更新接单状态"
@handler UpdatePlayerStatus @handler UpdatePlayerStatus
put /players/me/status (UpdatePlayerStatusReq) returns (EmptyResp) put /players/me/status (UpdatePlayerStatusReq) returns (EmptyResp)