🎨 优化登录逻辑,添加设备ID和名称生成,更新二维码状态处理
All checks were successful
BuildImage / build-image (push) Successful in 2m3s
All checks were successful
BuildImage / build-image (push) Successful in 2m3s
This commit is contained in:
parent
37b766368f
commit
2f6b3fac01
@ -19,9 +19,9 @@ docker:
|
||||
imageName: "lxh01/xybotv2:latest"
|
||||
network: "bridge"
|
||||
redis:
|
||||
host: "localhost"
|
||||
password: "password"
|
||||
db: 0
|
||||
host: "10.0.0.31"
|
||||
password: "pGhQKwj7DE7FbFL1"
|
||||
db: 2
|
||||
|
||||
auth:
|
||||
secretKey: "dev-secret-key"
|
||||
|
1
go.mod
1
go.mod
@ -14,6 +14,7 @@ require (
|
||||
gorm.io/driver/postgres v1.5.11
|
||||
gorm.io/driver/sqlite v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
gorm.io/plugin/soft_delete v1.2.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
8
go.sum
8
go.sum
@ -64,6 +64,8 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
@ -81,6 +83,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
@ -243,10 +246,15 @@ gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=
|
||||
gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
|
||||
gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
|
||||
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
gorm.io/plugin/soft_delete v1.2.1 h1:qx9D/c4Xu6w5KT8LviX8DgLcB9hkKl6JC9f44Tj7cGU=
|
||||
gorm.io/plugin/soft_delete v1.2.1/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
|
@ -44,7 +44,13 @@ type CheckUuidResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
Status int `json:"Status"`
|
||||
Uuid string `json:"uuid"`
|
||||
Status int `json:"status"` // 状态
|
||||
PushLoginUrlExpiredTime int `json:"pushLoginUrlexpiredTime"` // 推送登录url过期时间
|
||||
ExpiredTime int `json:"expiredTime"` // 过期时间(秒)
|
||||
HeadImgUrl string `json:"headImgUrl"` // 头像
|
||||
NickName string `json:"nickName"` // 昵称
|
||||
AcctSectResp map[string]any `json:"acctSectResp"` // 账号信息-登录成功之后才有
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
@ -149,7 +155,7 @@ func GetQRCode(ctx context.Context, containerID string, containerHost string) (*
|
||||
}
|
||||
|
||||
// CheckUuid 检查二维码状态
|
||||
func CheckUuid(ctx context.Context, containerID string, uuid string, containerHost string) (*CheckUuidResponse, error) {
|
||||
func CheckUuid(ctx context.Context, uuid string, containerHost string) (*CheckUuidResponse, error) {
|
||||
client := newHTTPClient()
|
||||
|
||||
url := fmt.Sprintf("http://%s/CheckUuid", containerHost)
|
||||
|
@ -2,6 +2,10 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"gitee.ltd/lxh/wechat-robot/internal/config"
|
||||
"github.com/gofiber/fiber/v2/log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@ -33,8 +37,8 @@ func CheckQRCodeStatus(c *fiber.Ctx) error {
|
||||
// 获取机器人实例
|
||||
db := model.GetDB()
|
||||
var robot model.Robot
|
||||
if err := db.First(&robot, id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if err = db.First(&robot, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "机器人不存在",
|
||||
@ -51,7 +55,7 @@ func CheckQRCodeStatus(c *fiber.Ctx) error {
|
||||
defer cancel()
|
||||
|
||||
// 调用CheckUuid API检查二维码状态,传递容器访问地址
|
||||
response, err := docker.CheckUuid(ctx, robot.ContainerID, uuid, robot.ContainerHost)
|
||||
response, err := docker.CheckUuid(ctx, uuid, robot.ContainerHost)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"success": false,
|
||||
@ -59,8 +63,23 @@ func CheckQRCodeStatus(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
if cfg, _ := config.Load(); cfg.Server.Env == "development" {
|
||||
bs, _ := json.Marshal(response)
|
||||
log.Debugf("扫码返回结果: %s", bs)
|
||||
}
|
||||
|
||||
// 如果返回status=1,表示已扫码,暂存一下昵称和头像
|
||||
if response.Data.Status == 1 {
|
||||
robot.Nickname = response.Data.NickName
|
||||
robot.Avatar = response.Data.HeadImgUrl
|
||||
db.Save(&robot)
|
||||
}
|
||||
|
||||
// 如果检测到已登录,更新机器人状态
|
||||
if response.Success && response.Data.Status == 2 {
|
||||
if response.Success && response.Data.AcctSectResp != nil {
|
||||
response.Data.Status = 99
|
||||
robot.WechatID = response.Data.AcctSectResp["userName"].(string)
|
||||
|
||||
// 开启自动心跳,传递容器访问地址
|
||||
if robot.WechatID != "" {
|
||||
_, _ = docker.AutoHeartbeatStart(ctx, robot.ContainerID, robot.WechatID, robot.ContainerHost)
|
||||
@ -74,8 +93,9 @@ func CheckQRCodeStatus(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": response.Success,
|
||||
"status": response.Data.Status,
|
||||
"message": response.Message,
|
||||
"success": response.Success,
|
||||
"status": response.Data.Status,
|
||||
"message": response.Message,
|
||||
"userInfo": response.Data.AcctSectResp,
|
||||
})
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -79,9 +80,9 @@ func CreateRobot(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
db := model.GetDB()
|
||||
if err := db.Create(&robot).Error; err != nil {
|
||||
if err = db.Create(&robot).Error; err != nil {
|
||||
// 如果数据库创建失败,尝试删除容器
|
||||
docker.RemoveContainer(ctx, containerID, true)
|
||||
_ = docker.RemoveContainer(ctx, containerID, true)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "保存机器人信息失败: "+err.Error())
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ func DeleteRobot(c *fiber.Ctx) error {
|
||||
var robot model.Robot
|
||||
db := model.GetDB()
|
||||
|
||||
if err := db.First(&robot, id).Error; err != nil {
|
||||
if err = db.First(&robot, id).Error; err != nil {
|
||||
// 针对API请求返回JSON
|
||||
if strings.HasPrefix(c.Get("Accept"), "application/json") || c.Method() == "DELETE" {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
@ -141,7 +142,7 @@ func DeleteRobot(c *fiber.Ctx) error {
|
||||
"message": "机器人不存在",
|
||||
})
|
||||
}
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
||||
@ -152,14 +153,14 @@ func DeleteRobot(c *fiber.Ctx) error {
|
||||
defer cancel()
|
||||
|
||||
if robot.Status == model.RobotStatusOnline {
|
||||
if err := docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
||||
if err = docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
||||
log.Printf("登出机器人失败: %v", err)
|
||||
// 继续删除流程,不因登出失败而中断
|
||||
}
|
||||
}
|
||||
|
||||
// 删除容器
|
||||
if err := docker.RemoveContainer(ctx, robot.ContainerID, true); err != nil {
|
||||
if err = docker.RemoveContainer(ctx, robot.ContainerID, true); err != nil {
|
||||
log.Printf("删除容器失败: %v", err)
|
||||
// 继续删除流程,不因容器删除失败而中断
|
||||
}
|
||||
@ -169,7 +170,7 @@ func DeleteRobot(c *fiber.Ctx) error {
|
||||
monitor.RemoveRobot(robot.ContainerID)
|
||||
|
||||
// 删除数据库记录
|
||||
if err := db.Delete(&robot).Error; err != nil {
|
||||
if err = db.Delete(&robot).Error; err != nil {
|
||||
// 针对API请求返回JSON
|
||||
if strings.HasPrefix(c.Get("Accept"), "application/json") || c.Method() == "DELETE" {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
@ -201,13 +202,16 @@ func RobotLogin(c *fiber.Ctx) error {
|
||||
|
||||
var robot model.Robot
|
||||
db := model.GetDB()
|
||||
|
||||
if err := db.First(&robot, id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if err = db.First(&robot, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
||||
}
|
||||
// 处理一下设备信息
|
||||
if robot.CheckDevice() {
|
||||
db.Save(&robot)
|
||||
}
|
||||
|
||||
// 获取登录二维码
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
@ -219,12 +223,6 @@ func RobotLogin(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "获取登录二维码失败: "+err.Error())
|
||||
}
|
||||
|
||||
// 保存二维码相关信息到数据库
|
||||
robot.QRCodePath = qrcodeResp.Data.QRCodeBase64
|
||||
if err := db.Save(&robot).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "保存二维码信息失败")
|
||||
}
|
||||
|
||||
// 渲染登录页面,包含二维码和UUID(用于后续状态检查)
|
||||
return c.Render("robot/login", fiber.Map{
|
||||
"Title": "微信登录",
|
||||
@ -245,8 +243,8 @@ func RobotLogout(c *fiber.Ctx) error {
|
||||
var robot model.Robot
|
||||
db := model.GetDB()
|
||||
|
||||
if err := db.First(&robot, id).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
if err = db.First(&robot, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
||||
@ -258,20 +256,19 @@ func RobotLogout(c *fiber.Ctx) error {
|
||||
|
||||
// 使用新的LogOut API接口,传递容器访问地址
|
||||
if robot.WechatID != "" {
|
||||
if _, err := docker.LogOut(ctx, robot.ContainerID, robot.WechatID, robot.ContainerHost); err != nil {
|
||||
if _, err = docker.LogOut(ctx, robot.ContainerID, robot.WechatID, robot.ContainerHost); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "登出微信失败: "+err.Error())
|
||||
}
|
||||
} else {
|
||||
// 如果没有WechatID,使用原来的方法
|
||||
if err := docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
||||
if err = docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "登出微信失败: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 更新机器人状态
|
||||
robot.Status = model.RobotStatusOffline
|
||||
robot.QRCodePath = ""
|
||||
if err := db.Save(&robot).Error; err != nil {
|
||||
if err = db.Save(&robot).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "更新状态失败")
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,14 @@ package model
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/plugin/soft_delete"
|
||||
)
|
||||
|
||||
// BaseModel 是所有模型的基础结构
|
||||
type BaseModel struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt int64 `json:"-" gorm:"index:deleted; default:0"`
|
||||
IsDel soft_delete.DeletedAt `json:"-" gorm:"softDelete:flag,DeletedAtField:DeletedAt; index:deleted; default:0; type:tinyint(1)"`
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gitee.ltd/lxh/wechat-robot/internal/utils"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@ -18,15 +19,16 @@ const (
|
||||
// Robot 表示微信机器人实例
|
||||
type Robot struct {
|
||||
BaseModel
|
||||
ContainerID string `gorm:"column:container_id;uniqueIndex:idx_container_id,length:64" json:"container_id"`
|
||||
ContainerID string `gorm:"column:container_id;index:deleted,unique,length:64" json:"container_id"`
|
||||
ShortContainerID string `gorm:"column:short_container_id;index" json:"short_container_id"` // 容器ID的前12位
|
||||
ContainerHost string `gorm:"column:container_host" json:"container_host"` // 容器访问地址,格式为ip:port
|
||||
WechatID string `gorm:"column:wechat_id;index:idx_wechat_id,length:64" json:"wechat_id"`
|
||||
DeviceId string `gorm:"column:device_id;index:deleted,unique;" json:"deviceId"` // 设备Id
|
||||
DeviceName string `gorm:"column:device_name" json:"deviceName"` // 设备名称
|
||||
WechatID string `gorm:"column:wechat_id;index:deleted,unique,length:64" json:"wechat_id"`
|
||||
Nickname string `gorm:"column:nickname" json:"nickname"`
|
||||
Avatar string `gorm:"column:avatar" json:"avatar"`
|
||||
Status RobotStatus `gorm:"column:status;default:'offline'" json:"status"`
|
||||
LastLoginAt *time.Time `gorm:"column:last_login_at" json:"last_login_at"`
|
||||
QRCodePath string `gorm:"column:qrcode_path" json:"qrcode_path"` // 二维码路径,用于登录
|
||||
ErrorMessage string `gorm:"column:error_message" json:"error_message"`
|
||||
}
|
||||
|
||||
@ -68,3 +70,22 @@ func (r *Robot) BeforeDelete(tx *gorm.DB) error {
|
||||
// 在删除机器人之前,可以处理相关依赖
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckDevice
|
||||
// @description: 检查设备信息
|
||||
// @receiver r
|
||||
// @return bool 是否重新处理过,如果是,就返回true
|
||||
func (r *Robot) CheckDevice() (flag bool) {
|
||||
// 如果是空的,就获取环境变量配置的值,如果还是空的,就生成一个新的
|
||||
if r.DeviceId == "" {
|
||||
r.DeviceId = utils.GetDeviceId()
|
||||
flag = true
|
||||
}
|
||||
|
||||
// 如果是空的,就获取环境变量配置的值,如果还是空的,就生成一个新的
|
||||
if r.DeviceName == "" {
|
||||
r.DeviceName = utils.GetDeviceName()
|
||||
flag = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
66
internal/utils/device.go
Normal file
66
internal/utils/device.go
Normal file
@ -0,0 +1,66 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetDeviceId
|
||||
// @description: 生成设备ID
|
||||
// @return deviceId 设备ID
|
||||
func GetDeviceId() (deviceId string) {
|
||||
// 创建一个有种子的随机数生成器
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
// 定义可能的字母
|
||||
letters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
// 初始化字符串构建器
|
||||
var sb strings.Builder
|
||||
// 生成15个随机字母
|
||||
for i := 0; i < 15; i++ {
|
||||
sb.WriteByte(letters[r.Intn(len(letters))])
|
||||
}
|
||||
// 计算MD5哈希
|
||||
hash := md5.Sum([]byte(sb.String()))
|
||||
hashString := hex.EncodeToString(hash[:])
|
||||
|
||||
// 返回49加上MD5哈希的第3个字符开始的部分
|
||||
return "49" + hashString[2:]
|
||||
}
|
||||
|
||||
// GetDeviceName
|
||||
// @description: 生成设备名称
|
||||
// @return deviceName 设备名称
|
||||
func GetDeviceName() (deviceName string) {
|
||||
firstNames := []string{
|
||||
"Oliver", "Emma", "Liam", "Ava", "Noah", "Sophia", "Elijah", "Isabella",
|
||||
"James", "Mia", "William", "Amelia", "Benjamin", "Harper", "Lucas", "Evelyn",
|
||||
"Henry", "Abigail", "Alexander", "Ella", "Jackson", "Scarlett", "Sebastian",
|
||||
"Grace", "Aiden", "Chloe", "Matthew", "Zoey", "Samuel", "Lily", "David",
|
||||
"Aria", "Joseph", "Riley", "Carter", "Nora", "Owen", "Luna", "Daniel",
|
||||
"Sofia", "Gabriel", "Ellie", "Matthew", "Avery", "Isaac", "Mila", "Leo",
|
||||
"Julian", "Layla",
|
||||
}
|
||||
|
||||
lastNames := []string{
|
||||
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
|
||||
"Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson",
|
||||
"Thomas", "Taylor", "Moore", "Jackson", "Martin", "Lee", "Perez", "Thompson",
|
||||
"White", "Harris", "Sanchez", "Clark", "Ramirez", "Lewis", "Robinson", "Walker",
|
||||
"Young", "Allen", "King", "Wright", "Scott", "Torres", "Nguyen", "Hill",
|
||||
"Flores", "Green", "Adams", "Nelson", "Baker", "Hall", "Rivera", "Campbell",
|
||||
"Mitchell", "Carter", "Roberts", "Gomez", "Phillips", "Evans",
|
||||
}
|
||||
|
||||
// 使用随机数生成器
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// 随机选择名字和姓氏
|
||||
firstName := firstNames[r.Intn(len(firstNames))]
|
||||
lastName := lastNames[r.Intn(len(lastNames))]
|
||||
|
||||
// 返回组合后的字符串
|
||||
return firstName + " " + lastName + "'s Pad"
|
||||
}
|
@ -13,12 +13,12 @@
|
||||
<h2 class="text-lg font-medium text-gray-800">{{.Robot.Nickname}}</h2>
|
||||
<p class="text-sm text-gray-600 mt-1">请使用微信扫描二维码登录</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="p-6 flex flex-col items-center">
|
||||
<div class="border border-gray-200 rounded-lg p-3 mb-6 bg-white">
|
||||
<img src="{{.QRCode}}" alt="Login QR Code" class="w-64 h-64">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="qrcode-status" class="text-center mb-4">
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800">
|
||||
<span class="relative flex h-3 w-3 mr-2">
|
||||
@ -28,15 +28,15 @@
|
||||
等待扫描
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<p class="text-sm text-gray-500 mb-4 text-center">
|
||||
请打开微信,使用"扫一扫"功能扫描上方二维码登录
|
||||
</p>
|
||||
|
||||
|
||||
<div id="timer" class="text-sm text-gray-500 mb-5">
|
||||
二维码有效期: <span id="countdown">120</span>秒
|
||||
</div>
|
||||
|
||||
|
||||
<div class="w-full flex justify-between">
|
||||
<a href="/admin/robots/{{.Robot.ID}}" class="py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition-colors">
|
||||
取消
|
||||
@ -47,7 +47,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p class="text-center text-sm text-gray-500 mt-6">
|
||||
<i class="fas fa-info-circle mr-1"></i> 请确保手机与电脑在同一网络环境
|
||||
</p>
|
||||
@ -59,30 +59,30 @@
|
||||
const timer = document.getElementById('timer');
|
||||
const countdown = document.getElementById('countdown');
|
||||
const refreshQrcode = document.getElementById('refresh-qrcode');
|
||||
|
||||
|
||||
let secondsLeft = 120;
|
||||
let statusCheckInterval;
|
||||
|
||||
|
||||
// 开始倒计时
|
||||
const countdownTimer = setInterval(() => {
|
||||
secondsLeft--;
|
||||
countdown.textContent = secondsLeft;
|
||||
|
||||
|
||||
if (secondsLeft <= 0) {
|
||||
clearInterval(countdownTimer);
|
||||
clearInterval(statusCheckInterval);
|
||||
|
||||
|
||||
qrcodeStatus.innerHTML = `
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800">
|
||||
<i class="fas fa-times-circle mr-1"></i>
|
||||
二维码已过期
|
||||
</span>
|
||||
`;
|
||||
|
||||
|
||||
refreshQrcode.classList.remove('hidden');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
|
||||
// 检查扫码状态
|
||||
function checkQRCodeStatus() {
|
||||
fetch(`/admin/robots/{{.Robot.ID}}/check-qrcode?uuid={{.UUID}}`)
|
||||
@ -110,17 +110,17 @@
|
||||
已扫描,等待确认
|
||||
</span>
|
||||
`;
|
||||
} else if (data.status === 2) {
|
||||
} else if (data.status === 99 && data.userInfo && Object.keys(data.userInfo).length > 0) {
|
||||
qrcodeStatus.innerHTML = `
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-green-100 text-green-800">
|
||||
<i class="fas fa-check-circle mr-1"></i>
|
||||
登录成功
|
||||
</span>
|
||||
`;
|
||||
|
||||
|
||||
clearInterval(countdownTimer);
|
||||
clearInterval(statusCheckInterval);
|
||||
|
||||
|
||||
// 重定向到机器人详情页
|
||||
setTimeout(() => {
|
||||
window.location.href = `/admin/robots/{{.Robot.ID}}`;
|
||||
@ -134,10 +134,10 @@
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 每3秒检查一次扫码状态
|
||||
statusCheckInterval = setInterval(checkQRCodeStatus, 3000);
|
||||
|
||||
|
||||
// 立即执行一次检查
|
||||
checkQRCodeStatus();
|
||||
});
|
||||
|
@ -1,6 +0,0 @@
|
||||
# 数据库迁移
|
||||
|
||||
此目录包含数据库迁移文件:
|
||||
- 表结构创建
|
||||
- 数据初始化
|
||||
- 架构升级脚本
|
@ -1,7 +0,0 @@
|
||||
# 静态资源
|
||||
|
||||
此目录包含Web应用的静态资源:
|
||||
- CSS样式
|
||||
- JavaScript文件
|
||||
- 图片资源
|
||||
- 字体文件
|
Loading…
x
Reference in New Issue
Block a user