2025-12-19 22:36:48 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"ai_xhs/config"
|
|
|
|
|
|
"ai_xhs/database"
|
|
|
|
|
|
"ai_xhs/models"
|
|
|
|
|
|
"ai_xhs/utils"
|
|
|
|
|
|
"bytes"
|
2026-01-06 19:36:42 +08:00
|
|
|
|
"context"
|
2025-12-19 22:36:48 +08:00
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"io"
|
|
|
|
|
|
"log"
|
|
|
|
|
|
"net/http"
|
2025-12-20 01:05:46 +08:00
|
|
|
|
|
|
|
|
|
|
"gorm.io/gorm"
|
2025-12-19 22:36:48 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type AuthService struct{}
|
|
|
|
|
|
|
|
|
|
|
|
func NewAuthService() *AuthService {
|
|
|
|
|
|
return &AuthService{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 微信手机号响应
|
|
|
|
|
|
type WxPhoneResponse struct {
|
|
|
|
|
|
PhoneInfo struct {
|
|
|
|
|
|
PhoneNumber string `json:"phoneNumber"`
|
|
|
|
|
|
PurePhoneNumber string `json:"purePhoneNumber"`
|
|
|
|
|
|
CountryCode string `json:"countryCode"`
|
|
|
|
|
|
} `json:"phone_info"`
|
|
|
|
|
|
ErrCode int `json:"errcode"`
|
|
|
|
|
|
ErrMsg string `json:"errmsg"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 微信登录响应
|
|
|
|
|
|
type WxLoginResponse struct {
|
|
|
|
|
|
OpenID string `json:"openid"`
|
|
|
|
|
|
SessionKey string `json:"session_key"`
|
|
|
|
|
|
UnionID string `json:"unionid"`
|
|
|
|
|
|
ErrCode int `json:"errcode"`
|
|
|
|
|
|
ErrMsg string `json:"errmsg"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// WechatLogin 微信小程序登录
|
|
|
|
|
|
func (s *AuthService) WechatLogin(code string, phone string, phoneCode string) (string, *models.User, error) {
|
|
|
|
|
|
// 1. 调用微信API验证code
|
|
|
|
|
|
// 注意:需要在配置文件中添加小程序的AppID和AppSecret
|
|
|
|
|
|
appID := config.AppConfig.Wechat.AppID
|
|
|
|
|
|
appSecret := config.AppConfig.Wechat.AppSecret
|
|
|
|
|
|
|
|
|
|
|
|
// 调试日志:打印配置信息
|
|
|
|
|
|
log.Printf("[微信登录] AppID: %s, AppSecret: %s (长度:%d)", appID, appSecret, len(appSecret))
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有配置微信AppID,使用手机号登录逻辑
|
|
|
|
|
|
if appID == "" || appSecret == "" {
|
|
|
|
|
|
if phone == "" {
|
|
|
|
|
|
// 没有配置微信且没有手机号,使用默认员工ID=1
|
|
|
|
|
|
return s.loginByEmployeeID(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 使用手机号登录
|
|
|
|
|
|
return s.PhoneLogin(phone)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用微信API
|
|
|
|
|
|
url := fmt.Sprintf(
|
|
|
|
|
|
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
|
|
|
|
|
|
appID, appSecret, code,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 调试日志:打印请求URL(隐藏密钥)
|
|
|
|
|
|
log.Printf("[微信登录] 请求URL: https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=***&js_code=%s&grant_type=authorization_code", appID, code)
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("调用微信API失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("读取响应失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调试日志:打印微信返回的原始响应
|
|
|
|
|
|
log.Printf("[微信登录] 微信API响应: %s", string(body))
|
|
|
|
|
|
|
|
|
|
|
|
var wxResp WxLoginResponse
|
|
|
|
|
|
if err := json.Unmarshal(body, &wxResp); err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("解析响应失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if wxResp.ErrCode != 0 {
|
|
|
|
|
|
return "", nil, fmt.Errorf("微信登录失败: %s", wxResp.ErrMsg)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1.5 如果有 phoneCode,调用微信API获取手机号
|
|
|
|
|
|
if phoneCode != "" {
|
|
|
|
|
|
accessTokenURL := fmt.Sprintf(
|
|
|
|
|
|
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
|
|
|
|
|
|
appID, appSecret,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取 access_token
|
|
|
|
|
|
accessTokenResp, err := http.Get(accessTokenURL)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Printf("获取access_token失败: %v", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
defer accessTokenResp.Body.Close()
|
|
|
|
|
|
accessTokenBody, _ := io.ReadAll(accessTokenResp.Body)
|
|
|
|
|
|
|
|
|
|
|
|
var tokenResult struct {
|
|
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
|
|
ErrCode int `json:"errcode"`
|
|
|
|
|
|
ErrMsg string `json:"errmsg"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := json.Unmarshal(accessTokenBody, &tokenResult); err == nil && tokenResult.AccessToken != "" {
|
|
|
|
|
|
// 获取手机号
|
|
|
|
|
|
phoneURL := fmt.Sprintf(
|
|
|
|
|
|
"https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s",
|
|
|
|
|
|
tokenResult.AccessToken,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
phoneReqBody := map[string]string{"code": phoneCode}
|
|
|
|
|
|
phoneReqJSON, _ := json.Marshal(phoneReqBody)
|
|
|
|
|
|
|
|
|
|
|
|
phoneResp, err := http.Post(phoneURL, "application/json", bytes.NewBuffer(phoneReqJSON))
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
defer phoneResp.Body.Close()
|
|
|
|
|
|
phoneBody, _ := io.ReadAll(phoneResp.Body)
|
|
|
|
|
|
|
|
|
|
|
|
var phoneResult WxPhoneResponse
|
|
|
|
|
|
if err := json.Unmarshal(phoneBody, &phoneResult); err == nil && phoneResult.ErrCode == 0 {
|
|
|
|
|
|
// 获取手机号成功,覆盖 phone 参数
|
|
|
|
|
|
phone = phoneResult.PhoneInfo.PurePhoneNumber
|
|
|
|
|
|
log.Printf("[微信登录] 获取手机号成功: %s", phone)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log.Printf("[微信登录] 获取手机号失败: %s", string(phoneBody))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 01:05:46 +08:00
|
|
|
|
// 2. 根据手机号查找用户(手机号必填)
|
|
|
|
|
|
if phone == "" {
|
|
|
|
|
|
return "", nil, errors.New("请提供手机号")
|
|
|
|
|
|
}
|
2025-12-19 22:36:48 +08:00
|
|
|
|
|
2025-12-20 01:05:46 +08:00
|
|
|
|
var employee models.User
|
|
|
|
|
|
// 通过手机号查找员工
|
|
|
|
|
|
result := database.DB.Where("phone = ? AND status = ?", phone, "active").First(&employee)
|
2025-12-19 22:36:48 +08:00
|
|
|
|
if result.Error != nil {
|
2025-12-20 01:05:46 +08:00
|
|
|
|
// 手机号不存在,不允许登录
|
|
|
|
|
|
return "", nil, errors.New("手机号不存在,请联系管理员添加")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 检查微信绑定信息
|
|
|
|
|
|
// 如果该用户已绑定微信信息,必须与当前登录的微信信息一致(单设备登录)
|
|
|
|
|
|
if employee.WechatOpenID != nil && *employee.WechatOpenID != "" {
|
|
|
|
|
|
// 已绑定微信,检查是否一致
|
|
|
|
|
|
if *employee.WechatOpenID != wxResp.OpenID {
|
|
|
|
|
|
return "", nil, errors.New("该账号已在其他设备登录,请使用原设备登录或联系管理员")
|
2025-12-19 22:36:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 01:05:46 +08:00
|
|
|
|
// 如果有UnionID,也需要检查一致性
|
|
|
|
|
|
if employee.WechatUnionID != nil && *employee.WechatUnionID != "" && wxResp.UnionID != "" {
|
|
|
|
|
|
if *employee.WechatUnionID != wxResp.UnionID {
|
|
|
|
|
|
return "", nil, errors.New("微信账号信息不匹配,请使用原设备登录")
|
|
|
|
|
|
}
|
2025-12-19 22:36:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 01:05:46 +08:00
|
|
|
|
log.Printf("[微信登录] 用户 %s (ID:%d) 微信验证通过", employee.Phone, employee.ID)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 微信信息为空,说明是新用户首次登录,保存微信信息
|
|
|
|
|
|
log.Printf("[微信登录] 新用户首次登录,绑定微信信息: OpenID=%s, UnionID=%s", wxResp.OpenID, wxResp.UnionID)
|
|
|
|
|
|
|
2025-12-19 22:36:48 +08:00
|
|
|
|
employee.WechatOpenID = &wxResp.OpenID
|
|
|
|
|
|
if wxResp.UnionID != "" {
|
|
|
|
|
|
employee.WechatUnionID = &wxResp.UnionID
|
|
|
|
|
|
}
|
2025-12-20 01:05:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 使用事务保存微信绑定信息并创建作者记录
|
|
|
|
|
|
err := database.DB.Transaction(func(tx *gorm.DB) error {
|
|
|
|
|
|
// 1. 保存微信绑定信息
|
|
|
|
|
|
if err := tx.Save(&employee).Error; err != nil {
|
|
|
|
|
|
return fmt.Errorf("保存微信绑定信息失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-06 19:36:42 +08:00
|
|
|
|
// 2. 检查是否已存在作者记录(通过 created_user_id 和企业ID)
|
2025-12-20 01:05:46 +08:00
|
|
|
|
var existingAuthor models.Author
|
2026-01-06 19:36:42 +08:00
|
|
|
|
result := tx.Where("created_user_id = ? AND enterprise_id = ?", employee.ID, employee.EnterpriseID).First(&existingAuthor)
|
2025-12-20 01:05:46 +08:00
|
|
|
|
|
|
|
|
|
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
|
|
|
|
|
// 作者记录不存在,创建新记录
|
|
|
|
|
|
author := models.Author{
|
|
|
|
|
|
EnterpriseID: employee.EnterpriseID,
|
|
|
|
|
|
CreatedUserID: employee.ID,
|
|
|
|
|
|
Phone: employee.Phone,
|
|
|
|
|
|
AuthorName: employee.RealName,
|
|
|
|
|
|
Department: employee.Department,
|
|
|
|
|
|
Status: "active",
|
2026-01-06 19:36:42 +08:00
|
|
|
|
Channel: 1, // 1=小红书(默认渠道)
|
2025-12-20 01:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果真实姓名为空,使用用户名
|
|
|
|
|
|
if author.AuthorName == "" {
|
|
|
|
|
|
author.AuthorName = employee.Username
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := tx.Create(&author).Error; err != nil {
|
|
|
|
|
|
return fmt.Errorf("创建作者记录失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-06 19:36:42 +08:00
|
|
|
|
log.Printf("[微信登录] 创建作者记录成功: ID=%d, Name=%s, Channel=1(小红书)", author.ID, author.AuthorName)
|
2025-12-20 01:05:46 +08:00
|
|
|
|
} else if result.Error != nil {
|
|
|
|
|
|
// 其他数据库错误
|
|
|
|
|
|
return fmt.Errorf("检查作者记录失败: %v", result.Error)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log.Printf("[微信登录] 作者记录已存在: ID=%d", existingAuthor.ID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.Printf("[微信登录] 用户 %s (ID:%d) 微信绑定成功", employee.Phone, employee.ID)
|
2025-12-19 22:36:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 01:05:46 +08:00
|
|
|
|
// 4. 生成JWT token
|
2025-12-19 22:36:48 +08:00
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-06 19:36:42 +08:00
|
|
|
|
// 5. 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[微信登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
// 不阻断登录流程,但记录错误
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log.Printf("[微信登录] 用户%d token已存入Redis", employee.ID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 22:36:48 +08:00
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PhoneLogin 手机号登录(用于测试或无微信配置时)
|
|
|
|
|
|
func (s *AuthService) PhoneLogin(phone string) (string, *models.User, error) {
|
|
|
|
|
|
var employee models.User
|
|
|
|
|
|
|
|
|
|
|
|
// 查找员工
|
|
|
|
|
|
result := database.DB.Where("phone = ? AND status = ?", phone, "active").First(&employee)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
return "", nil, errors.New("员工不存在或已被禁用")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成token
|
|
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-06 19:36:42 +08:00
|
|
|
|
// 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[手机号登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 22:36:48 +08:00
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// loginByEmployeeID 通过员工ID登录(内部方法)
|
|
|
|
|
|
func (s *AuthService) loginByEmployeeID(employeeID int) (string, *models.User, error) {
|
|
|
|
|
|
var employee models.User
|
|
|
|
|
|
|
|
|
|
|
|
result := database.DB.Where("id = ? AND status = ?", employeeID, "active").First(&employee)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
return "", nil, errors.New("员工不存在或已被禁用")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成token
|
|
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-06 19:36:42 +08:00
|
|
|
|
// 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[ID登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PhonePasswordLogin 手机号密码登录
|
|
|
|
|
|
func (s *AuthService) PhonePasswordLogin(phone string, password string) (string, *models.User, error) {
|
|
|
|
|
|
if phone == "" || password == "" {
|
|
|
|
|
|
return "", nil, errors.New("手机号和密码不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var employee models.User
|
|
|
|
|
|
|
|
|
|
|
|
// 查找员工
|
|
|
|
|
|
result := database.DB.Where("phone = ? AND status = ?", phone, "active").First(&employee)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
return "", nil, errors.New("手机号或密码错误")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证密码
|
|
|
|
|
|
if !utils.VerifyPassword(password, employee.Password) {
|
|
|
|
|
|
return "", nil, errors.New("手机号或密码错误")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成token
|
|
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[密码登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckPhoneExists 检查手机号是否存在于user表中
|
|
|
|
|
|
func (s *AuthService) CheckPhoneExists(phone string) error {
|
|
|
|
|
|
var count int64
|
|
|
|
|
|
result := database.DB.Model(&models.User{}).Where("phone = ? AND status = ?", phone, "active").Count(&count)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
return fmt.Errorf("查询用户信息失败: %v", result.Error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if count == 0 {
|
|
|
|
|
|
return errors.New("手机号未注册,请联系管理员添加")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// XHSPhoneCodeLogin 小红书手机号验证码登录
|
|
|
|
|
|
func (s *AuthService) XHSPhoneCodeLogin(phone string, code string) (string, *models.User, error) {
|
|
|
|
|
|
if phone == "" || code == "" {
|
|
|
|
|
|
return "", nil, errors.New("手机号和验证码不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用短信服务验证验证码
|
|
|
|
|
|
smsService := GetSmsService()
|
|
|
|
|
|
if err := smsService.VerifyCode(phone, code); err != nil {
|
|
|
|
|
|
return "", nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var employee models.User
|
|
|
|
|
|
|
|
|
|
|
|
// 查找员工
|
|
|
|
|
|
result := database.DB.Where("phone = ? AND status = ?", phone, "active").First(&employee)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
// 用户不存在,不允许登录
|
|
|
|
|
|
return "", nil, errors.New("手机号未注册,请联系管理员添加")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成token
|
|
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[验证码登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// createNewUserFromPhone 从手机号创建新用户
|
|
|
|
|
|
func (s *AuthService) createNewUserFromPhone(phone string) (string, *models.User, error) {
|
|
|
|
|
|
// 使用事务创建用户和作者记录
|
|
|
|
|
|
var employee models.User
|
|
|
|
|
|
|
|
|
|
|
|
err := database.DB.Transaction(func(tx *gorm.DB) error {
|
|
|
|
|
|
// 1. 创建用户记录
|
|
|
|
|
|
employee = models.User{
|
|
|
|
|
|
Phone: phone,
|
|
|
|
|
|
Username: phone, // 默认用户名为手机号
|
|
|
|
|
|
Role: "user",
|
|
|
|
|
|
Status: "active",
|
|
|
|
|
|
EnterpriseID: 1, // 默认企业ID,可根据实际调整
|
|
|
|
|
|
EnterpriseName: "默认企业", // 默认企业名称
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := tx.Create(&employee).Error; err != nil {
|
|
|
|
|
|
return fmt.Errorf("创建用户失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 创建作者记录
|
|
|
|
|
|
author := models.Author{
|
|
|
|
|
|
EnterpriseID: employee.EnterpriseID,
|
|
|
|
|
|
CreatedUserID: employee.ID,
|
|
|
|
|
|
Phone: employee.Phone,
|
|
|
|
|
|
AuthorName: employee.Username,
|
|
|
|
|
|
Department: "",
|
|
|
|
|
|
Status: "active",
|
|
|
|
|
|
Channel: 1, // 1=小红书
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := tx.Create(&author).Error; err != nil {
|
|
|
|
|
|
return fmt.Errorf("创建作者记录失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.Printf("[手机号登录] 创建新用户成功: Phone=%s, UserID=%d, AuthorID=%d", phone, employee.ID, author.ID)
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成token
|
|
|
|
|
|
token, err := utils.GenerateToken(employee.ID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return "", nil, fmt.Errorf("生成token失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将token存入Redis
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
if err := utils.StoreTokenInRedis(ctx, employee.ID, token); err != nil {
|
|
|
|
|
|
log.Printf("[新用户登录] 存储token到Redis失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 22:36:48 +08:00
|
|
|
|
return token, &employee, nil
|
|
|
|
|
|
}
|