This commit is contained in:
sjk
2026-01-10 21:46:50 +08:00
parent 3b66018271
commit 213229953b
14 changed files with 1499 additions and 282 deletions

View File

@@ -781,6 +781,31 @@ func (ctrl *EmployeeController) SaveQRCodeLogin(c *gin.Context) {
common.SuccessWithMessage(c, "绑定成功", nil)
}
// SaveLogin 保存验证码登录的绑定信息
func (ctrl *EmployeeController) SaveLogin(c *gin.Context) {
var req struct {
EmployeeID int `json:"employee_id" binding:"required"`
CookiesFull []interface{} `json:"cookies_full"`
StorageState map[string]interface{} `json:"storage_state"`
StorageStatePath string `json:"storage_state_path"`
UserInfo map[string]interface{} `json:"user_info"` // 新增: 用户信息
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 调用service层保存
err := ctrl.service.SaveLogin(req.EmployeeID, req.CookiesFull, req.StorageState, req.StorageStatePath, req.UserInfo)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "绑定成功", nil)
}
// StartQRCodeLogin 启动扫码登录转发到Python服务
func (ctrl *EmployeeController) StartQRCodeLogin(c *gin.Context) {
employeeID := c.GetInt("employee_id")

View File

@@ -130,6 +130,8 @@ func SetupRouter(r *gin.Engine) {
// 保存扫码登录的绑定信息
xhs.POST("/save-qrcode-login", xhsCtrl.SaveQRCodeLogin)
// 保存验证码登录的绑定信息
xhs.POST("/save-login", xhsCtrl.SaveLogin)
}
}
}

View File

@@ -2341,6 +2341,151 @@ func (s *EmployeeService) SaveQRCodeLogin(employeeID int, cookiesFull []interfac
return nil
}
// SaveLogin 保存验证码登录的信息
func (s *EmployeeService) SaveLogin(employeeID int, cookiesFull []interface{}, storageState map[string]interface{}, storageStatePath string, userInfo map[string]interface{}) error {
ctx := context.Background()
// 查询用户信息
var employee models.User
if err := database.DB.First(&employee, employeeID).Error; err != nil {
return fmt.Errorf("获取用户信息失败: %w", err)
}
// 优先使用 storage_state如果没有则降级使用 cookies_full
var loginStateJSON string
if len(storageState) > 0 {
// 新版:使用 Playwright 的 storage_state
storageStateBytes, err := json.Marshal(storageState)
if err == nil {
loginStateJSON = string(storageStateBytes)
log.Printf("验证码登录 - 用户%d - StorageState长度: %d", employeeID, len(loginStateJSON))
} else {
log.Printf("验证码登录 - 用户%d - 序列化storage_state失败: %v", employeeID, err)
}
} else if len(cookiesFull) > 0 {
// 降级:使用旧版本的 cookies_full
log.Printf("验证码登录 - 用户%d - 警告: 未找到storage_state降级使用cookies", employeeID)
cookiesBytes, err := json.Marshal(cookiesFull)
if err == nil {
loginStateJSON = string(cookiesBytes)
log.Printf("验证码登录 - 用户%d - Cookie长度: %d", employeeID, len(loginStateJSON))
}
}
if loginStateJSON == "" {
log.Printf("验证码登录 - 用户%d - 错误: 未能获取到任何登录数据", employeeID)
return errors.New("登录成功但未能获取到登录数据,请重试")
}
// 从 userInfo 提取小红书账号信息
xhsNickname := "小红书用户" // 默认值
xhsPhone := "" // red_id
xhsUserId := "" // user_id
if len(userInfo) > 0 {
// 优先使用 nickname
if nickname, ok := userInfo["nickname"].(string); ok && nickname != "" {
xhsNickname = nickname
}
// 提取 red_id 作为 xhs_phone
if redID, ok := userInfo["red_id"].(string); ok && redID != "" {
xhsPhone = redID
}
// 提取 user_id
if userID, ok := userInfo["user_id"].(string); ok && userID != "" {
xhsUserId = userID
}
log.Printf("验证码登录 - 用户%d - 提取的用户信息: nickname=%s, red_id=%s, user_id=%s", employeeID, xhsNickname, xhsPhone, xhsUserId)
} else {
log.Printf("验证码登录 - 用户%d - 警告: userInfo为空使用默认值", employeeID)
}
now := time.Now()
// 开启事务
tx := database.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 创建或更新 ai_authors 表的小红书账号记录
log.Printf("验证码登录 - 用户%d - 开始创建或更新作者记录", employeeID)
author := models.Author{
EnterpriseID: employee.EnterpriseID,
CreatedUserID: employeeID,
Phone: employee.Phone,
AuthorName: xhsNickname,
XHSCookie: loginStateJSON,
XHSPhone: xhsPhone,
XHSAccount: xhsNickname,
BoundAt: &now,
Channel: 1, // 1=小红书
Status: "active",
}
// 查询是否已存在记录
var existingAuthor models.Author
err := database.DB.Where("created_user_id = ? AND enterprise_id = ? AND channel = 1",
employeeID, employee.EnterpriseID).First(&existingAuthor).Error
if err == gorm.ErrRecordNotFound {
// 创建新记录
if err := tx.Create(&author).Error; err != nil {
tx.Rollback()
log.Printf("验证码登录 - 用户%d - 创建作者记录失败: %v", employeeID, err)
return fmt.Errorf("创建作者记录失败: %w", err)
}
log.Printf("验证码登录 - 用户%d - 创建作者记录成功", employeeID)
} else {
// 更新现有记录
if err := tx.Model(&models.Author{}).Where(
"created_user_id = ? AND enterprise_id = ? AND channel = 1",
employeeID, employee.EnterpriseID,
).Updates(map[string]interface{}{
"author_name": xhsNickname,
"xhs_cookie": loginStateJSON,
"xhs_phone": xhsPhone,
"xhs_account": xhsNickname,
"bound_at": &now,
"status": "active",
"phone": employee.Phone,
}).Error; err != nil {
tx.Rollback()
log.Printf("验证码登录 - 用户%d - 更新作者记录失败: %v", employeeID, err)
return fmt.Errorf("更新作者记录失败: %w", err)
}
log.Printf("验证码登录 - 用户%d - 更新作者记录成功", employeeID)
}
// 更新 ai_users 表的绑定标识
if err := tx.Model(&employee).Update("is_bound_xhs", 1).Error; err != nil {
tx.Rollback()
log.Printf("验证码登录 - 用户%d - 更新用户绑定标识失败: %v", employeeID, err)
return fmt.Errorf("更新用户绑定标识失败: %w", err)
}
log.Printf("验证码登录 - 用户%d - 数据库更新成功", employeeID)
// 提交事务
if err := tx.Commit().Error; err != nil {
log.Printf("验证码登录 - 用户%d - 事务提交失败: %v", employeeID, err)
return fmt.Errorf("提交事务失败: %w", err)
}
// 清除相关缓存
cacheService := NewCacheService()
if err := cacheService.ClearUserRelatedCache(ctx, employeeID); err != nil {
log.Printf("清除缓存失败: %v", err)
}
log.Printf("验证码登录 - 用户%d - 绑定成功", employeeID)
return nil
}
// StartQRCodeLogin 启动扫码登录转发到Python服务
func (s *EmployeeService) StartQRCodeLogin(employeeID int) (map[string]interface{}, error) {
log.Printf("[启动扫码登录] 用户ID: %d", employeeID)