Files
ai_wht_wechat/go_backend/controller/employee_controller.go

889 lines
24 KiB
Go
Raw Normal View History

2025-12-19 22:36:48 +08:00
package controller
import (
"ai_xhs/common"
2026-01-06 19:36:42 +08:00
"ai_xhs/database"
"ai_xhs/models"
2025-12-19 22:36:48 +08:00
"ai_xhs/service"
2026-01-06 19:36:42 +08:00
"ai_xhs/utils"
"bytes"
"context"
"encoding/base64"
"fmt"
2026-01-07 22:55:12 +08:00
"net/http"
2025-12-19 22:36:48 +08:00
"strconv"
2026-01-06 19:36:42 +08:00
"strings"
"time"
2025-12-19 22:36:48 +08:00
"github.com/gin-gonic/gin"
)
2025-12-20 01:05:46 +08:00
2025-12-19 22:36:48 +08:00
type EmployeeController struct {
service *service.EmployeeService
}
func NewEmployeeController() *EmployeeController {
return &EmployeeController{
service: &service.EmployeeService{},
}
}
// SendXHSCode 发送小红书验证码
func (ctrl *EmployeeController) SendXHSCode(c *gin.Context) {
var req struct {
XHSPhone string `json:"xhs_phone" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误:手机号不能为空")
return
}
2026-01-06 19:36:42 +08:00
// 获取当前登录用户ID
employeeID := c.GetInt("employee_id")
2026-01-09 23:27:52 +08:00
data, err := ctrl.service.SendXHSCode(req.XHSPhone, employeeID)
2025-12-19 22:36:48 +08:00
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
2026-01-09 23:27:52 +08:00
// 检查是否需要扫码验证
if needCaptcha, ok := data["need_captcha"].(bool); ok && needCaptcha {
// 发送验证码时触发风控,返回二维码
common.SuccessWithMessage(c, "需要扫码验证", data)
return
}
common.SuccessWithMessage(c, "验证码已发送请在小红书APP中查看", data)
2025-12-19 22:36:48 +08:00
}
// GetProfile 获取员工个人信息
func (ctrl *EmployeeController) GetProfile(c *gin.Context) {
employeeID := c.GetInt("employee_id")
employee, err := ctrl.service.GetProfile(employeeID)
if err != nil {
common.Error(c, common.CodeNotFound, "员工不存在")
return
}
// 获取用户显示名称(优先使用真实姓名,其次用户名)
displayName := employee.RealName
if displayName == "" {
displayName = employee.Username
}
data := map[string]interface{}{
"id": employee.ID,
"name": displayName,
"username": employee.Username,
"real_name": employee.RealName,
2026-01-06 19:36:42 +08:00
"nickname": employee.Nickname,
"email": employee.Email,
2025-12-19 22:36:48 +08:00
"phone": employee.Phone,
"role": employee.Role,
"enterprise_id": employee.EnterpriseID,
"enterprise_name": employee.Enterprise.Name,
2026-01-06 19:36:42 +08:00
"avatar": employee.Icon,
2025-12-19 22:36:48 +08:00
"is_bound_xhs": employee.IsBoundXHS,
}
2026-01-06 19:36:42 +08:00
// 如果已绑定,从 ai_authors 表获取小红书账号信息(根据 created_user_id 查询)
if employee.IsBoundXHS == 1 {
var author models.Author
err := database.DB.Where(
"created_user_id = ? AND enterprise_id = ? AND channel = 1 AND status = 'active'",
employeeID, employee.EnterpriseID,
).First(&author).Error
if err == nil {
data["xhs_account"] = author.XHSAccount
data["xhs_phone"] = author.XHSPhone
data["has_xhs_cookie"] = author.XHSCookie != ""
if author.BoundAt != nil {
data["bound_at"] = author.BoundAt.Format("2006-01-02 15:04:05")
}
} else {
// 没有找到author记录返回默认值
data["xhs_account"] = ""
data["xhs_phone"] = ""
data["has_xhs_cookie"] = false
}
} else {
data["xhs_account"] = ""
data["xhs_phone"] = ""
data["has_xhs_cookie"] = false
2025-12-19 22:36:48 +08:00
}
common.Success(c, data)
}
2026-01-06 19:36:42 +08:00
// UpdateProfile 更新个人资料(昵称、邮箱、头像)
func (ctrl *EmployeeController) UpdateProfile(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
Nickname *string `json:"nickname"`
Email *string `json:"email"`
Avatar *string `json:"avatar"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
if req.Nickname == nil && req.Email == nil && req.Avatar == nil {
common.Error(c, common.CodeInvalidParams, "没有可更新的字段")
return
}
// 简单校验邮箱格式
if req.Email != nil && *req.Email != "" {
if !strings.Contains(*req.Email, "@") {
common.Error(c, common.CodeInvalidParams, "邮箱格式不正确")
return
}
}
if err := ctrl.service.UpdateProfile(employeeID, req.Nickname, req.Email, req.Avatar); err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "更新成功", nil)
}
// UploadAvatar 上传头像
func (ctrl *EmployeeController) UploadAvatar(c *gin.Context) {
employeeID := c.GetInt("employee_id")
// 获取上传的文件
file, err := c.FormFile("file")
if err != nil {
common.Error(c, common.CodeInvalidParams, "请选择要上传的图片")
return
}
// 校验文件类型
contentType := file.Header.Get("Content-Type")
if !strings.HasPrefix(contentType, "image/") {
common.Error(c, common.CodeInvalidParams, "只能上传图片文件")
return
}
// 校验文件大小5MB
if file.Size > 5*1024*1024 {
common.Error(c, common.CodeInvalidParams, "图片大小不能超过5MB")
return
}
// 打开文件
src, err := file.Open()
if err != nil {
common.Error(c, common.CodeInternalError, "打开文件失败")
return
}
defer src.Close()
// 读取文件内容
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(src)
if err != nil {
common.Error(c, common.CodeInternalError, "读取文件失败")
return
}
// 上传到 OSS
fileExt := ".jpg"
if strings.Contains(contentType, "png") {
fileExt = ".png"
} else if strings.Contains(contentType, "webp") {
fileExt = ".webp"
}
fileName := fmt.Sprintf("avatar_%d_%d%s", employeeID, time.Now().Unix(), fileExt)
ossURL, err := utils.UploadToOSS(bytes.NewReader(buf.Bytes()), fileName)
if err != nil {
common.Error(c, common.CodeInternalError, fmt.Sprintf("上传失败: %s", err.Error()))
return
}
// 更新数据库
if err := ctrl.service.UpdateProfile(employeeID, nil, nil, &ossURL); err != nil {
common.Error(c, common.CodeInternalError, "更新头像失败")
return
}
common.Success(c, map[string]interface{}{
"url": ossURL,
})
}
// BindXHS 绑定小红书账号(异步处理)
2025-12-19 22:36:48 +08:00
func (ctrl *EmployeeController) BindXHS(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
2026-01-07 22:55:12 +08:00
XHSPhone string `json:"xhs_phone" binding:"required"`
Code string `json:"code" binding:"required"`
SessionID string `json:"session_id"` // 发送验证码时返回的session_id用于复用浏览器
2025-12-19 22:36:48 +08:00
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
2026-01-07 22:55:12 +08:00
_, err := ctrl.service.BindXHS(employeeID, req.XHSPhone, req.Code, req.SessionID)
2025-12-19 22:36:48 +08:00
if err != nil {
common.Error(c, common.CodeBindXHSFailed, err.Error())
return
}
2026-01-06 19:36:42 +08:00
// 立即返回成功,告知前端正在处理
common.SuccessWithMessage(c, "正在验证登录,请稍候...", map[string]interface{}{
"status": "processing",
2025-12-19 22:36:48 +08:00
})
}
2026-01-06 19:36:42 +08:00
// GetBindXHSStatus 获取小红书绑定状态
func (ctrl *EmployeeController) GetBindXHSStatus(c *gin.Context) {
employeeID := c.GetInt("employee_id")
status, err := ctrl.service.GetBindXHSStatus(employeeID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.Success(c, status)
}
2025-12-19 22:36:48 +08:00
// UnbindXHS 解绑小红书账号
func (ctrl *EmployeeController) UnbindXHS(c *gin.Context) {
employeeID := c.GetInt("employee_id")
if err := ctrl.service.UnbindXHS(employeeID); err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "解绑成功", nil)
}
// GetAvailableCopies 获取可领取文案列表
func (ctrl *EmployeeController) GetAvailableCopies(c *gin.Context) {
employeeID := c.GetInt("employee_id")
productID, err := strconv.Atoi(c.Query("product_id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "产品ID参数错误")
return
}
data, err := ctrl.service.GetAvailableCopies(employeeID, productID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.Success(c, data)
}
// ClaimCopy 领取文案
func (ctrl *EmployeeController) ClaimCopy(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
CopyID int `json:"copy_id" binding:"required"`
ProductID int `json:"product_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
data, err := ctrl.service.ClaimCopy(employeeID, req.CopyID, req.ProductID)
if err != nil {
common.Error(c, common.CodeAlreadyClaimed, err.Error())
return
}
common.SuccessWithMessage(c, "领取成功", data)
}
// ClaimRandomCopy 随机领取文案
func (ctrl *EmployeeController) ClaimRandomCopy(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
ProductID int `json:"product_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
data, err := ctrl.service.ClaimRandomCopy(employeeID, req.ProductID)
if err != nil {
common.Error(c, common.CodeCopyNotAvailable, err.Error())
return
}
common.SuccessWithMessage(c, "领取成功", data)
}
// Publish 发布内容
func (ctrl *EmployeeController) Publish(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req service.PublishRequest
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
recordID, err := ctrl.service.Publish(employeeID, req)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "发布成功", map[string]interface{}{
"record_id": recordID,
})
}
// GetMyPublishRecords 获取我的发布记录
func (ctrl *EmployeeController) GetMyPublishRecords(c *gin.Context) {
employeeID := c.GetInt("employee_id")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
data, err := ctrl.service.GetMyPublishRecords(employeeID, page, pageSize)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.Success(c, data)
}
// GetPublishRecordDetail 获取发布记录详情
func (ctrl *EmployeeController) GetPublishRecordDetail(c *gin.Context) {
employeeID := c.GetInt("employee_id")
recordID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "记录ID参数错误")
return
}
data, err := ctrl.service.GetPublishRecordDetail(employeeID, recordID)
if err != nil {
common.Error(c, common.CodeNotFound, err.Error())
return
}
common.Success(c, data)
}
// CheckXHSStatus 检查小红书绑定与Cookie状态
func (ctrl *EmployeeController) CheckXHSStatus(c *gin.Context) {
employeeID := c.GetInt("employee_id")
status, err := ctrl.service.CheckXHSStatus(employeeID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.Success(c, status)
}
// GetProducts 获取产品列表
func (ctrl *EmployeeController) GetProducts(c *gin.Context) {
2026-01-06 19:36:42 +08:00
employeeID := c.GetInt("employee_id")
if employeeID == 0 {
common.Error(c, common.CodeUnauthorized, "未登录或token无效")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
data, hasMore, err := ctrl.service.GetProducts(employeeID, page, pageSize)
2025-12-19 22:36:48 +08:00
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.Success(c, map[string]interface{}{
2026-01-06 19:36:42 +08:00
"list": data,
"has_more": hasMore,
2025-12-19 22:36:48 +08:00
})
}
2025-12-20 01:05:46 +08:00
// UpdateArticleStatus 更新文案状态(通过/拒绝)
func (ctrl *EmployeeController) UpdateArticleStatus(c *gin.Context) {
employeeID := c.GetInt("employee_id")
articleID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "文案ID参数错误")
return
}
var req struct {
Status string `json:"status" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 验证status值
if req.Status != "approved" && req.Status != "rejected" {
common.Error(c, common.CodeInvalidParams, "status只能为approved或rejected")
return
}
err = ctrl.service.UpdateArticleStatus(employeeID, articleID, req.Status)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
message := "已通过"
if req.Status == "rejected" {
message = "已拒绝"
}
common.SuccessWithMessage(c, message, nil)
}
2026-01-06 19:36:42 +08:00
// UpdateArticleContent 更新文案内容(标题、正文)
func (ctrl *EmployeeController) UpdateArticleContent(c *gin.Context) {
employeeID := c.GetInt("employee_id")
articleID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "文案ID参数错误")
return
}
var req struct {
Title string `json:"title" binding:"required"`
Content string `json:"content" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 验证标题和内容字数
if len([]rune(req.Title)) > 20 {
common.Error(c, common.CodeInvalidParams, "标题最多20字")
return
}
if len([]rune(req.Content)) > 1000 {
common.Error(c, common.CodeInvalidParams, "内容最多1000字")
return
}
err = ctrl.service.UpdateArticleContent(employeeID, articleID, req.Title, req.Content)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "更新成功", nil)
}
// UpdatePublishRecord 编辑发布记录(修改标题、内容、图片、标签)
func (ctrl *EmployeeController) UpdatePublishRecord(c *gin.Context) {
employeeID := c.GetInt("employee_id")
recordID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "记录ID参数错误")
return
}
var req service.UpdatePublishRecordRequest
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 验证标题和内容字数
if req.Title != nil && len([]rune(*req.Title)) > 20 {
common.Error(c, common.CodeInvalidParams, "标题最多20字")
return
}
if req.Content != nil && len([]rune(*req.Content)) > 1000 {
common.Error(c, common.CodeInvalidParams, "内容最多1000字")
return
}
if err := ctrl.service.UpdatePublishRecord(employeeID, recordID, req); err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "更新成功", nil)
}
// RepublishRecord 重新发布种草内容
func (ctrl *EmployeeController) RepublishRecord(c *gin.Context) {
employeeID := c.GetInt("employee_id")
recordID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "记录ID参数错误")
return
}
publishLink, err := ctrl.service.RepublishRecord(employeeID, recordID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "重新发布成功", map[string]interface{}{
"publish_link": publishLink,
})
}
// AddArticleImage 添加文案图片
func (ctrl *EmployeeController) AddArticleImage(c *gin.Context) {
employeeID := c.GetInt("employee_id")
articleID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "文案ID参数错误")
return
}
var req struct {
ImageURL string `json:"image_url" binding:"required"`
ImageThumbURL string `json:"image_thumb_url"`
KeywordsName string `json:"keywords_name"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 如果没有缩略图,使用原图
if req.ImageThumbURL == "" {
req.ImageThumbURL = req.ImageURL
}
image, err := ctrl.service.AddArticleImage(employeeID, articleID, req.ImageURL, req.ImageThumbURL, req.KeywordsName)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "添加成功", image)
}
// DeleteArticleImage 删除文案图片
func (ctrl *EmployeeController) DeleteArticleImage(c *gin.Context) {
employeeID := c.GetInt("employee_id")
imageID, err := strconv.Atoi(c.Param("imageId"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "图片ID参数错误")
return
}
err = ctrl.service.DeleteArticleImage(employeeID, imageID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "删除成功", nil)
}
// UpdateArticleImagesOrder 更新文案图片排序
func (ctrl *EmployeeController) UpdateArticleImagesOrder(c *gin.Context) {
employeeID := c.GetInt("employee_id")
articleID, err := strconv.Atoi(c.Param("id"))
if err != nil {
common.Error(c, common.CodeInvalidParams, "文案ID参数错误")
return
}
var req struct {
ImageOrders []map[string]int `json:"image_orders" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
err = ctrl.service.UpdateArticleImagesOrder(employeeID, articleID, req.ImageOrders)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "更新成功", nil)
}
// UploadImage 上传图片支持base64和multipart/form-data
func (ctrl *EmployeeController) UploadImage(c *gin.Context) {
// 尝试从表单获取文件
file, header, err := c.Request.FormFile("file")
if err == nil {
// 处理文件上传
defer file.Close()
// 验证文件类型
contentType := header.Header.Get("Content-Type")
if !strings.HasPrefix(contentType, "image/") {
common.Error(c, common.CodeInvalidParams, "只支持图片文件")
return
}
// 上传到OSS
imageURL, err := utils.UploadToOSS(file, header.Filename)
if err != nil {
common.Error(c, common.CodeInternalError, fmt.Sprintf("上传失败: %v", err))
return
}
common.SuccessWithMessage(c, "上传成功", map[string]interface{}{
"image_url": imageURL,
"image_thumb_url": imageURL, // 简化处理,缩略图与原图相同
})
return
}
// 尝试介ase64获取
var req struct {
Base64 string `json:"base64" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "请上传文件或base64数据")
return
}
// 解析base64
var imageData []byte
if strings.Contains(req.Base64, "base64,") {
// 移除data:image/xxx;base64,前缀
parts := strings.Split(req.Base64, "base64,")
if len(parts) != 2 {
common.Error(c, common.CodeInvalidParams, "base64格式错误")
return
}
imageData, err = base64.StdEncoding.DecodeString(parts[1])
} else {
imageData, err = base64.StdEncoding.DecodeString(req.Base64)
}
if err != nil {
common.Error(c, common.CodeInvalidParams, "base64解码失败")
return
}
// 上传到OSS
reader := bytes.NewReader(imageData)
imageURL, err := utils.UploadToOSS(reader, "image.jpg")
if err != nil {
common.Error(c, common.CodeInternalError, fmt.Sprintf("上传失败: %v", err))
return
}
common.SuccessWithMessage(c, "上传成功", map[string]interface{}{
"image_url": imageURL,
"image_thumb_url": imageURL,
})
}
// RevokeUserToken 禁用用户撤销Token
func (ctrl *EmployeeController) RevokeUserToken(c *gin.Context) {
// 只有管理员可以禁用用户
employeeID := c.GetInt("employee_id")
// 获取当前用户信息,检查是否为管理员
var currentUser models.User
if err := database.DB.Where("id = ?", employeeID).First(&currentUser).Error; err != nil {
common.Error(c, common.CodeUnauthorized, "用户不存在")
return
}
if currentUser.Role != "admin" {
common.Error(c, common.CodeUnauthorized, "无权操作,只有管理员可以禁用用户")
return
}
var req struct {
TargetUserID int `json:"target_user_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误需要提供目标用户ID")
return
}
// 不能禁用自己
if req.TargetUserID == employeeID {
common.Error(c, common.CodeInvalidParams, "不能禁用自己")
return
}
// 检查目标用户是否存在
var targetUser models.User
if err := database.DB.Where("id = ?", req.TargetUserID).First(&targetUser).Error; err != nil {
common.Error(c, common.CodeNotFound, "目标用户不存在")
return
}
// 撤销该用户的Token
ctx := context.Background()
if err := utils.RevokeToken(ctx, req.TargetUserID); err != nil {
common.Error(c, common.CodeInternalError, fmt.Sprintf("禁用失败: %v", err))
return
}
common.SuccessWithMessage(c, fmt.Sprintf("已禁用用户 %s (手机号: %s),该用户需要重新登录", targetUser.Username, targetUser.Phone), nil)
}
2026-01-07 22:55:12 +08:00
// SaveQRCodeLogin 保存扫码登录的绑定信息
// 由Python后端调用不需要认证
func (ctrl *EmployeeController) SaveQRCodeLogin(c *gin.Context) {
var req struct {
EmployeeID int `json:"employee_id" binding:"required"`
CookiesFull []interface{} `json:"cookies_full"`
UserInfo map[string]interface{} `json:"user_info"`
LoginState map[string]interface{} `json:"login_state"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
// 调用service层直接保存与验证码登录相同的逻辑
err := ctrl.service.SaveQRCodeLogin(req.EmployeeID, req.CookiesFull, req.UserInfo, req.LoginState)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
common.SuccessWithMessage(c, "绑定成功", nil)
}
2026-01-10 21:46:50 +08:00
// 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)
}
2026-01-07 22:55:12 +08:00
// StartQRCodeLogin 启动扫码登录转发到Python服务
func (ctrl *EmployeeController) StartQRCodeLogin(c *gin.Context) {
employeeID := c.GetInt("employee_id")
data, err := ctrl.service.StartQRCodeLogin(employeeID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
// 直接返回Python的响应格式保持code=0
c.JSON(http.StatusOK, data)
}
// GetQRCodeStatus 获取扫码状态转发到Python服务
func (ctrl *EmployeeController) GetQRCodeStatus(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
SessionID string `json:"session_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
data, err := ctrl.service.GetQRCodeStatus(employeeID, req.SessionID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
// 直接返回Python的响应格式保持code=0或code=2
c.JSON(http.StatusOK, data)
}
// RefreshQRCode 刷新二维码转发到Python服务
func (ctrl *EmployeeController) RefreshQRCode(c *gin.Context) {
employeeID := c.GetInt("employee_id")
var req struct {
SessionID string `json:"session_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
data, err := ctrl.service.RefreshQRCode(employeeID, req.SessionID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
// 直接返回Python的响应格式保持code=0或code=3
c.JSON(http.StatusOK, data)
}
// CancelQRCodeLogin 取消扫码登录,释放浏览器资源
func (ctrl *EmployeeController) CancelQRCodeLogin(c *gin.Context) {
var req struct {
SessionID string `json:"session_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
common.Error(c, common.CodeInvalidParams, "参数错误")
return
}
data, err := ctrl.service.CancelQRCodeLogin(req.SessionID)
if err != nil {
common.Error(c, common.CodeInternalError, err.Error())
return
}
// 直接返回Python的响应格式
c.JSON(http.StatusOK, data)
}