feat(ECR-011): 昵称、首页贴士与档案 Self 唯一/合盘交叉校验
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

每账号仅一条 self(migration 40902);合盘只选 TA;账号昵称可改;首页穿衣/颜色/养生贴士。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-12 22:05:00 +08:00
co-authored by Cursor
parent 5ceb3ce749
commit 13860bf1ef
67 changed files with 1936 additions and 275 deletions
+36 -8
View File
@@ -12,6 +12,7 @@ import (
"github.com/jackc/pgx/v5"
"golang.org/x/crypto/bcrypt"
nickgen "github.com/yuxingu/digital-psychology/apps/api/internal/nickname"
"github.com/yuxingu/digital-psychology/apps/api/internal/repository"
)
@@ -46,12 +47,12 @@ func (s *Service) Login(ctx context.Context, userID uuid.UUID, deviceKey, phone,
}
// OpenLogin: any phone+password accepted; persist account; issue session.
func (s *Service) OpenLogin(ctx context.Context, deviceUserID uuid.UUID, deviceKey, phone, password, nickname string) (*SessionResult, error) {
func (s *Service) OpenLogin(ctx context.Context, deviceUserID uuid.UUID, deviceKey, phone, password, nickIn string) (*SessionResult, error) {
phone = strings.TrimSpace(phone)
if phone == "" {
return nil, errors.New("请填写手机号")
}
nickname = strings.TrimSpace(nickname)
nickIn = nickgen.Normalize(nickIn)
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
@@ -65,8 +66,12 @@ func (s *Service) OpenLogin(ctx context.Context, deviceUserID uuid.UUID, deviceK
_ = s.Repo.BindDevice(ctx, deviceKey, acc.ID)
}
nick := acc.Nickname
if nickname != "" {
nick = nickname
if nickIn != "" {
nick = nickIn
_ = s.Repo.UpdateNickname(ctx, acc.ID, nick)
} else if nick == "" {
nick = nickgen.Random()
_ = s.Repo.UpdateNickname(ctx, acc.ID, nick)
}
return s.issue(ctx, acc.ID, acc.Phone, nick)
}
@@ -74,15 +79,19 @@ func (s *Service) OpenLogin(ctx context.Context, deviceUserID uuid.UUID, deviceK
return nil, err
}
// New phone: prefer upgrading anonymous device user.
nick := nickIn
if nick == "" {
nick = nickgen.Random()
}
cur, curErr := s.Repo.GetAccount(ctx, deviceUserID)
uid := deviceUserID
if curErr == nil && cur.Phone == "" {
if err := s.Repo.RegisterOnUser(ctx, deviceUserID, phone, hashStr, nickname); err != nil {
if err := s.Repo.RegisterOnUser(ctx, deviceUserID, phone, hashStr, nick); err != nil {
return nil, errors.New("登录失败,请重试")
}
} else {
uid, err = s.Repo.CreateUserWithPhone(ctx, phone, hashStr, nickname)
uid, err = s.Repo.CreateUserWithPhone(ctx, phone, hashStr, nick)
if err != nil {
return nil, errors.New("登录失败,请重试")
}
@@ -90,7 +99,26 @@ func (s *Service) OpenLogin(ctx context.Context, deviceUserID uuid.UUID, deviceK
if deviceKey != "" {
_ = s.Repo.BindDevice(ctx, deviceKey, uid)
}
return s.issue(ctx, uid, phone, nickname)
return s.issue(ctx, uid, phone, nick)
}
// UpdateNickname changes account display nickname (116 chars).
func (s *Service) UpdateNickname(ctx context.Context, userID uuid.UUID, nick string) (*Me, error) {
nick = nickgen.Normalize(nick)
if nick == "" {
return nil, errors.New("请填写昵称")
}
if err := s.Repo.UpdateNickname(ctx, userID, nick); err != nil {
return nil, err
}
acc, err := s.Repo.GetAccount(ctx, userID)
if err != nil {
return nil, err
}
if acc.Phone == "" {
return nil, errors.New("未登录")
}
return &Me{ID: acc.ID.String(), Phone: maskPhone(acc.Phone), Nickname: acc.Nickname}, nil
}
// Logout revokes the current bearer session and unbinds the device from the account