package logic import ( "context" "errors" "fmt" plantModel "sundynix-micro-go/app/plant/model" "sundynix-micro-go/app/plant/rpc/internal/svc" "sundynix-micro-go/app/plant/rpc/plant" sysPb "sundynix-micro-go/app/system/rpc/system" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type FindOrCreateUserByOpenIdLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger } func NewFindOrCreateUserByOpenIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FindOrCreateUserByOpenIdLogic { return &FindOrCreateUserByOpenIdLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx), } } func (l *FindOrCreateUserByOpenIdLogic) FindOrCreateUserByOpenId(in *plant.FindOrCreateUserByOpenIdReq) (*plant.PlantUserProfile, error) { if in.OpenId == "" { return nil, fmt.Errorf("openid 不能为空") } // 1. 根据 mini_open_id 查询植物用户扩展表 var profile plantModel.UserProfile err := l.svcCtx.DB.Where("mini_open_id = ?", in.OpenId).First(&profile).Error if err == nil { // 1.1 用户已存在:如果 session_key 发生变化则进行更新 if in.SessionKey != "" && (in.SessionKey != profile.SessionKey || in.UnionId != profile.UnionID || in.SaOpenId != profile.SaOpenID) { l.svcCtx.DB.Model(&profile).Updates(map[string]interface{}{ "session_key": in.SessionKey, "union_id": in.UnionId, "sa_open_id": in.SaOpenId, }) } return profileToProto(&profile), nil } // 2. 用户不存在:分步创建(先 System RPC 创建基础用户,再本地创建扩展用户) if !errors.Is(err, gorm.ErrRecordNotFound) { l.Errorf("[FindOrCreateUserByOpenId] 查询扩展表失败: openid=%s, err=%v", in.OpenId, err) return nil, fmt.Errorf("系统繁忙,请稍后再试") } // 2.1 调用 System RPC 创建基础用户(遵守服务边界,不直接写 system 表) createResp, err := l.svcCtx.SystemRpc.CreateUser(l.ctx, &sysPb.CreateUserReq{ ClientId: in.ClientId, NickName: "园艺新手", }) if err != nil { l.Errorf("[FindOrCreateUserByOpenId] 调用 System RPC 创建基础用户失败: err=%v", err) return nil, fmt.Errorf("注册用户失败") } userId := createResp.User.Id l.Infof("[FindOrCreateUserByOpenId] ✅ System 基础用户创建成功: userId=%s", userId) // 2.2 自动匹配初始等级 ID (获取首个等级,一般是 Level 1) var firstLevel plantModel.LevelConfig levelErr := l.svcCtx.DB.Order("level asc").First(&firstLevel).Error levelID := "" if levelErr == nil { levelID = firstLevel.ID } // 2.3 本地事务创建应用专属扩展表 profile = plantModel.UserProfile{ UserID: userId, MiniOpenID: in.OpenId, SessionKey: in.SessionKey, UnionID: in.UnionId, SaOpenID: in.SaOpenId, NickName: "园艺新手", LevelID: levelID, CurrentSunlight: 0, TotalSunlight: 0, } if err = l.svcCtx.DB.Create(&profile).Error; err != nil { l.Errorf("[FindOrCreateUserByOpenId] 创建用户扩展表失败: err=%v", err) // 2.4 补偿回滚:删除已创建的 System 基础用户,避免孤儿记录 _, delErr := l.svcCtx.SystemRpc.DeleteUser(l.ctx, &sysPb.DeleteUserReq{ Ids: []string{userId}, }) if delErr != nil { l.Errorf("[FindOrCreateUserByOpenId] ⚠️ 补偿删除基础用户失败: userId=%s, err=%v", userId, delErr) // 即使补偿失败也返回原始错误,孤儿记录可通过后台定期清理 } else { l.Infof("[FindOrCreateUserByOpenId] 补偿删除基础用户成功: userId=%s", userId) } return nil, fmt.Errorf("注册应用扩展失败") } l.Infof("[FindOrCreateUserByOpenId] ✅ 成功创建游客账户: userId=%s, openid=%s", userId, in.OpenId) return profileToProto(&profile), nil } // profileToProto 将 model 转为 proto 响应 func profileToProto(p *plantModel.UserProfile) *plant.PlantUserProfile { return &plant.PlantUserProfile{ Id: p.ID, UserId: p.UserID, NickName: p.NickName, AvatarId: p.AvatarID, LevelId: p.LevelID, CurrentSunlight: p.CurrentSunlight, TotalSunlight: p.TotalSunlight, PlantCount: p.PlantCount, CareCount: p.CareCount, PostCount: p.PostCount, WaterCount: p.WaterCount, FertilizeCount: p.FertilizeCount, RepotCount: p.RepotCount, PruneCount: p.PruneCount, PhotoCount: p.PhotoCount, MiniOpenId: p.MiniOpenID, SessionKey: p.SessionKey, UnionId: p.UnionID, SaOpenId: p.SaOpenID, } }