Files
junhong_cmp_fiber/internal/service/personal_customer/service.go
huang 4507de577b 代码质量改进:修复架构违规、完善文档注释和清理冗余代码
- 修复 health.go handler 直接操作响应的架构违规问题
- 为 model 字段添加 GORM comment 标签(account_role、base、role_permission)
- 为 handler、service、store 包添加包级文档注释
- 清理 customer service 和 personal_customer handler 中注释掉的代码

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 16:28:48 +08:00

239 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package personal_customer 提供个人客户管理的业务逻辑服务
// 包含个人客户注册、登录、微信绑定、短信验证等功能
package personal_customer
import (
"context"
"fmt"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/service/verification"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/auth"
"go.uber.org/zap"
"gorm.io/gorm"
)
// Service 个人客户服务
type Service struct {
store *postgres.PersonalCustomerStore
phoneStore *postgres.PersonalCustomerPhoneStore
verificationService *verification.Service
jwtManager *auth.JWTManager
logger *zap.Logger
}
// NewService 创建个人客户服务实例
func NewService(
store *postgres.PersonalCustomerStore,
phoneStore *postgres.PersonalCustomerPhoneStore,
verificationService *verification.Service,
jwtManager *auth.JWTManager,
logger *zap.Logger,
) *Service {
return &Service{
store: store,
phoneStore: phoneStore,
verificationService: verificationService,
jwtManager: jwtManager,
logger: logger,
}
}
// SendVerificationCode 发送验证码
func (s *Service) SendVerificationCode(ctx context.Context, phone string) error {
return s.verificationService.SendCode(ctx, phone)
}
// VerifyCode 验证验证码
func (s *Service) VerifyCode(ctx context.Context, phone string, code string) error {
return s.verificationService.VerifyCode(ctx, phone, code)
}
// LoginByPhone 通过手机号登录
// 如果手机号不存在,自动创建新的个人客户
// 注意:此方法是临时实现,完整的登录流程应该是先微信授权,再绑定手机号
func (s *Service) LoginByPhone(ctx context.Context, phone string, code string) (string, *model.PersonalCustomer, error) {
// 验证验证码
if err := s.verificationService.VerifyCode(ctx, phone, code); err != nil {
s.logger.Warn("验证码验证失败",
zap.String("phone", phone),
zap.Error(err),
)
return "", nil, fmt.Errorf("验证码验证失败: %w", err)
}
// 查找或创建个人客户
customer, err := s.store.GetByPhone(ctx, phone)
if err != nil {
if err == gorm.ErrRecordNotFound {
// 客户不存在,创建新客户
// 注意:临时实现,使用空的微信信息(正式应该先微信授权)
customer = &model.PersonalCustomer{
WxOpenID: "", // 临时为空,后续需绑定微信
WxUnionID: "", // 临时为空,后续需绑定微信
Status: 1, // 默认启用
}
if err := s.store.Create(ctx, customer); err != nil {
s.logger.Error("创建个人客户失败",
zap.String("phone", phone),
zap.Error(err),
)
return "", nil, fmt.Errorf("创建个人客户失败: %w", err)
}
// 创建手机号绑定记录
// TODO: 这里需要通过 PersonalCustomerPhoneStore 来创建
// 暂时跳过,等待 PersonalCustomerPhoneStore 实现
s.logger.Info("创建新个人客户",
zap.Uint("customer_id", customer.ID),
zap.String("phone", phone),
)
} else {
s.logger.Error("查询个人客户失败",
zap.String("phone", phone),
zap.Error(err),
)
return "", nil, fmt.Errorf("查询个人客户失败: %w", err)
}
}
// 检查客户状态
if customer.Status == 0 {
s.logger.Warn("个人客户已被禁用",
zap.Uint("customer_id", customer.ID),
zap.String("phone", phone),
)
return "", nil, fmt.Errorf("账号已被禁用")
}
// 生成 Token临时传递 phone后续应该从 Token 中移除 phone 字段)
token, err := s.jwtManager.GeneratePersonalCustomerToken(customer.ID, phone)
if err != nil {
s.logger.Error("生成 Token 失败",
zap.Uint("customer_id", customer.ID),
zap.String("phone", phone),
zap.Error(err),
)
return "", nil, fmt.Errorf("生成 Token 失败: %w", err)
}
s.logger.Info("个人客户登录成功",
zap.Uint("customer_id", customer.ID),
zap.String("phone", phone),
)
return token, customer, nil
}
// BindWechat 绑定微信信息
func (s *Service) BindWechat(ctx context.Context, customerID uint, wxOpenID, wxUnionID string) error {
// 获取客户
customer, err := s.store.GetByID(ctx, customerID)
if err != nil {
s.logger.Error("查询个人客户失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return fmt.Errorf("查询个人客户失败: %w", err)
}
// 更新微信信息
customer.WxOpenID = wxOpenID
customer.WxUnionID = wxUnionID
if err := s.store.Update(ctx, customer); err != nil {
s.logger.Error("更新微信信息失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return fmt.Errorf("更新微信信息失败: %w", err)
}
s.logger.Info("绑定微信信息成功",
zap.Uint("customer_id", customerID),
zap.String("wx_open_id", wxOpenID),
)
return nil
}
// UpdateProfile 更新个人资料
func (s *Service) UpdateProfile(ctx context.Context, customerID uint, nickname, avatarURL string) error {
customer, err := s.store.GetByID(ctx, customerID)
if err != nil {
s.logger.Error("查询个人客户失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return fmt.Errorf("查询个人客户失败: %w", err)
}
// 更新资料
if nickname != "" {
customer.Nickname = nickname
}
if avatarURL != "" {
customer.AvatarURL = avatarURL
}
if err := s.store.Update(ctx, customer); err != nil {
s.logger.Error("更新个人资料失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return fmt.Errorf("更新个人资料失败: %w", err)
}
s.logger.Info("更新个人资料成功",
zap.Uint("customer_id", customerID),
)
return nil
}
// GetProfile 获取个人资料
func (s *Service) GetProfile(ctx context.Context, customerID uint) (*model.PersonalCustomer, error) {
customer, err := s.store.GetByID(ctx, customerID)
if err != nil {
s.logger.Error("查询个人客户失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return nil, fmt.Errorf("查询个人客户失败: %w", err)
}
return customer, nil
}
// GetProfileWithPhone 获取个人资料(包含主手机号)
func (s *Service) GetProfileWithPhone(ctx context.Context, customerID uint) (*model.PersonalCustomer, string, error) {
// 获取客户信息
customer, err := s.store.GetByID(ctx, customerID)
if err != nil {
s.logger.Error("查询个人客户失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
return nil, "", fmt.Errorf("查询个人客户失败: %w", err)
}
// 获取主手机号
phone := ""
primaryPhone, err := s.phoneStore.GetPrimaryPhone(ctx, customerID)
if err != nil {
if err != gorm.ErrRecordNotFound {
s.logger.Error("查询主手机号失败",
zap.Uint("customer_id", customerID),
zap.Error(err),
)
// 不返回错误,继续返回客户信息(手机号为空)
}
} else {
phone = primaryPhone.Phone
}
return customer, phone, nil
}