控制器中间件授权改造完成

This commit is contained in:
GeekMaster
2025-08-26 14:22:14 +08:00
parent 728de61bd6
commit b6d81890cf
23 changed files with 168 additions and 334 deletions

View File

@@ -103,6 +103,7 @@ func AdminAuthMiddleware(secretKey string, redis *redis.Client) gin.HandlerFunc
c.Abort()
return
}
c.Set(types.AdminUserID, claims["user_id"])
}
}

View File

@@ -54,11 +54,11 @@ func (h *ManagerHandler) RegisterRoutes() {
// 公开接口,不需要授权
group.POST("login", h.Login)
group.GET("logout", h.Logout)
group.GET("session", h.Session)
// 需要管理员授权的接口
group.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))
{
group.GET("session", h.Session)
group.GET("list", h.List)
group.POST("save", h.Save)
group.POST("enable", h.Enable)
@@ -157,16 +157,15 @@ func (h *ManagerHandler) Logout(c *gin.Context) {
// Session 会话检测
func (h *ManagerHandler) Session(c *gin.Context) {
id := h.GetLoginUserId(c)
key := fmt.Sprintf("admin/%d", id)
if _, err := h.redis.Get(context.Background(), key).Result(); err != nil {
resp.NotAuth(c)
id := h.GetAdminId(c)
if id == 0 {
resp.NotAuth(c, "当前用户已退出登录")
return
}
var manager model.AdminUser
res := h.DB.Where("id", id).First(&manager)
if res.Error != nil {
resp.NotAuth(c)
err := h.DB.Where("id", id).First(&manager).Error
if err != nil {
resp.NotAuth(c, "当前用户已退出登录")
return
}

View File

@@ -33,7 +33,7 @@ func NewApiKeyHandler(app *core.AppServer, db *gorm.DB) *ApiKeyHandler {
// RegisterRoutes 注册路由
func (h *ApiKeyHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/admin/apiKey/")
group := h.App.Engine.Group("/api/admin/apikey/")
// 需要管理员授权的接口
group.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))

View File

@@ -33,7 +33,7 @@ func NewChatAppHandler(app *core.AppServer, db *gorm.DB) *ChatAppHandler {
// RegisterRoutes 注册路由
func (h *ChatAppHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/admin/app/")
group := h.App.Engine.Group("/api/admin/role/")
// 需要管理员授权的接口
group.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))

View File

@@ -44,12 +44,12 @@ func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB,
// RegisterRoutes 注册路由
func (h *ConfigHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/admin/config/")
group.GET("get", h.Get)
// 需要管理员授权的接口
group.Use(middleware.AdminAuthMiddleware(h.App.Config.AdminSession.SecretKey, h.App.Redis))
{
group.POST("update", h.Update)
group.GET("get", h.Get)
group.POST("active", h.Active)
group.POST("test", h.Test)
group.GET("license", h.GetLicense)

View File

@@ -15,9 +15,10 @@ import (
logger2 "geekai/logger"
"geekai/store/model"
"geekai/utils"
"gorm.io/gorm"
"strings"
"gorm.io/gorm"
"github.com/gin-gonic/gin"
)
@@ -69,6 +70,14 @@ func (h *BaseHandler) GetLoginUserId(c *gin.Context) uint {
return uint(utils.IntValue(utils.InterfaceToString(userId), 0))
}
func (h *BaseHandler) GetAdminId(c *gin.Context) uint {
userId, ok := c.Get(types.AdminUserID)
if !ok {
return 0
}
return uint(utils.IntValue(utils.InterfaceToString(userId), 0))
}
func (h *BaseHandler) IsLogin(c *gin.Context) bool {
return h.GetLoginUserId(c) > 0
}

View File

@@ -9,7 +9,6 @@ package handler
import (
"geekai/core"
"geekai/core/middleware"
"geekai/core/types"
"geekai/service"
"geekai/utils/resp"
@@ -33,14 +32,11 @@ func NewCaptchaHandler(app *core.AppServer, s *service.CaptchaService, sysConfig
func (h *CaptchaHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/captcha/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("get", h.Get)
group.POST("check", h.Check)
group.GET("slide/get", h.SlideGet)
group.POST("slide/check", h.SlideCheck)
}
// 需授权的接口
group.GET("get", h.Get)
group.POST("check", h.Check)
group.GET("slide/get", h.SlideGet)
group.POST("slide/check", h.SlideCheck)
}
func (h *CaptchaHandler) Get(c *gin.Context) {

View File

@@ -30,7 +30,7 @@ func NewChatRoleHandler(app *core.AppServer, db *gorm.DB) *ChatRoleHandler {
// RegisterRoutes 注册路由
func (h *ChatRoleHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/role/")
group := h.App.Engine.Group("/api/app/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))

View File

@@ -9,7 +9,6 @@ package handler
import (
"geekai/core"
"geekai/core/middleware"
"geekai/service"
"geekai/store/model"
"geekai/utils"
@@ -32,12 +31,9 @@ func NewConfigHandler(app *core.AppServer, db *gorm.DB, licenseService *service.
func (h *ConfigHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/config/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("get", h.Get)
group.GET("license", h.License)
}
// 需授权的接口
group.GET("get", h.Get)
group.GET("license", h.License)
}
// Get 获取指定的系统配置

View File

@@ -58,6 +58,7 @@ func NewFunctionHandler(
// RegisterRoutes 注册路由
func (h *FunctionHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/function/")
group.GET("list", h.List)
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
@@ -66,7 +67,6 @@ func (h *FunctionHandler) RegisterRoutes() {
group.POST("zaobao", h.ZaoBao)
group.POST("dalle3", h.Dall3)
group.POST("websearch", h.WebSearch)
group.GET("list", h.List)
}
}

View File

@@ -9,7 +9,6 @@ package handler
import (
"geekai/core"
"geekai/core/middleware"
"geekai/store/model"
"geekai/store/vo"
"geekai/utils"
@@ -30,12 +29,7 @@ func NewMenuHandler(app *core.AppServer, db *gorm.DB) *MenuHandler {
// RegisterRoutes 注册路由
func (h *MenuHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/menu/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("list", h.List)
}
group.GET("list", h.List)
}
// List 数据列表

View File

@@ -35,12 +35,12 @@ func NewNetHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManage
// RegisterRoutes 注册路由
func (h *NetHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/upload/")
group := h.App.Engine.Group("/api/upload")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.POST("upload", h.Upload)
group.POST("", h.Upload)
group.POST("list", h.List)
group.GET("remove", h.Remove)
}

View File

@@ -12,7 +12,7 @@ import (
"errors"
"fmt"
"geekai/core"
"geekai/core/midware"
"geekai/core/middleware"
"geekai/core/types"
"geekai/service"
"geekai/service/payment"
@@ -81,7 +81,7 @@ func (h *PaymentHandler) RegisterRoutes() {
rg.POST("notify/wechat", h.WechatPayNotify)
// 需要用户登录的接口
rg.Use(midware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
rg.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
rg.POST("create", h.Pay)
}

View File

@@ -9,7 +9,6 @@ package handler
import (
"geekai/core"
"geekai/core/middleware"
"geekai/core/types"
"geekai/service"
"geekai/service/sms"
@@ -48,12 +47,8 @@ func NewSmsHandler(
// RegisterRoutes 注册路由
func (h *SmsHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/sms/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.POST("code", h.SendCode)
}
// 无需授权的接口
group.POST("code", h.SendCode)
}
// SendCode 发送验证码

View File

@@ -68,12 +68,12 @@ func (h *UserHandler) RegisterRoutes() {
group.POST("login", h.Login)
group.POST("resetPass", h.ResetPass)
group.GET("clogin", h.CLogin)
group.GET("logout", h.Logout)
group.GET("clogin/callback", h.CLoginCallback)
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("logout", h.Logout)
group.GET("session", h.Session)
group.GET("profile", h.Profile)
group.POST("profile/update", h.ProfileUpdate)

View File

@@ -112,12 +112,6 @@ func main() {
return xdbFS
}),
// 数据修复
fx.Provide(service.NewDataFixService),
fx.Invoke(func(s *core.AppServer, dfs *service.DataFixService) {
dfs.FixData()
}),
// 创建 Ip2Region 查询对象
fx.Provide(func() (*xdb.Searcher, error) {
file, err := xdbFS.Open("res/ip2region.xdb")
@@ -151,11 +145,9 @@ func main() {
fx.Provide(handler.NewJimengHandler),
fx.Provide(service.NewConfigService),
fx.Provide(service.NewConfigMigrationService),
fx.Invoke(func(migrationService *service.ConfigMigrationService, config *types.AppConfig, redisClient *redis.Client) {
if err := migrationService.MigrateFromConfig(config); err != nil {
logger.Errorf("配置迁移失败: %v", err)
}
fx.Provide(service.NewMigrationService),
fx.Invoke(func(migrationService *service.MigrationService) {
migrationService.StartMigrate()
}),
// 管理后台控制器

View File

@@ -1,66 +0,0 @@
package service
import (
"geekai/store/model"
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
)
type DataFixService struct {
db *gorm.DB
redis *redis.Client
}
func NewDataFixService(db *gorm.DB, redis *redis.Client) *DataFixService {
return &DataFixService{db: db, redis: redis}
}
func (s *DataFixService) FixData() {
s.FixColumn()
}
// 字段修正
func (s *DataFixService) FixColumn() {
// 订单字段整理
if s.db.Migrator().HasColumn(&model.Order{}, "pay_type") {
s.db.Migrator().RenameColumn(&model.Order{}, "pay_type", "channel")
}
if !s.db.Migrator().HasColumn(&model.Order{}, "check") {
s.db.Migrator().AddColumn(&model.Order{}, "checked")
}
// 重命名 config 表字段
if s.db.Migrator().HasColumn(&model.Config{}, "config_json") {
s.db.Migrator().RenameColumn(&model.Config{}, "config_json", "value")
}
if s.db.Migrator().HasColumn(&model.Config{}, "marker") {
s.db.Migrator().RenameColumn(&model.Config{}, "marker", "name")
}
if s.db.Migrator().HasIndex(&model.Config{}, "idx_chatgpt_configs_key") {
s.db.Migrator().DropIndex(&model.Config{}, "idx_chatgpt_configs_key")
}
if s.db.Migrator().HasIndex(&model.Config{}, "marker") {
s.db.Migrator().DropIndex(&model.Config{}, "marker")
}
// 手动删除字段
if s.db.Migrator().HasColumn(&model.Order{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.Order{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.ChatItem{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.ChatItem{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.ChatMessage{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.ChatMessage{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.User{}, "chat_config") {
s.db.Migrator().DropColumn(&model.User{}, "chat_config")
}
if s.db.Migrator().HasColumn(&model.ChatModel{}, "category") {
s.db.Migrator().DropColumn(&model.ChatModel{}, "category")
}
if s.db.Migrator().HasColumn(&model.ChatModel{}, "description") {
s.db.Migrator().DropColumn(&model.ChatModel{}, "description")
}
}

View File

@@ -10,37 +10,35 @@ package service
import (
"errors"
"fmt"
"geekai/core"
"geekai/core/types"
"geekai/store"
"geekai/store/model"
"geekai/utils"
"strings"
"time"
"github.com/imroc/req/v3"
"github.com/shirou/gopsutil/host"
"gorm.io/gorm"
)
type LicenseService struct {
levelDB *store.LevelDB
license *types.License
urlWhiteList []string
machineId string
db *gorm.DB
}
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) *LicenseService {
var license types.License
func NewLicenseService(sysConfig *types.SystemConfig, db *gorm.DB) *LicenseService {
var machineId string
err := levelDB.Get(types.LicenseKey, &license)
logger.Infof("License: %+v", server.SysConfig)
info, err := host.Info()
if err == nil {
machineId = info.HostID
}
logger.Infof("License: %+v", license)
logger.Infof("License: %+v", sysConfig.License)
return &LicenseService{
levelDB: levelDB,
license: &license,
license: &sysConfig.License,
machineId: machineId,
db: db,
}
}
@@ -88,10 +86,13 @@ func (s *LicenseService) ActiveLicense(license string, machineId string) error {
ExpiredAt: res.Data.ExpiredAt,
IsActive: true,
}
err = s.levelDB.Put(types.LicenseKey, s.license)
// 保存 License 到数据库
err = s.db.Model(&model.Config{}).Where("name = ?", types.ConfigKeyLicense).UpdateColumn("value", utils.JsonEncode(s.license)).Error
if err != nil {
return fmt.Errorf("保存许可证书失败:%v", err)
return fmt.Errorf("保存 License 到数据库失败: %v", err)
}
return nil
}
@@ -173,6 +174,13 @@ func (s *LicenseService) fetchUrlWhiteList() ([]string, error) {
// GetLicense 获取许可信息
func (s *LicenseService) GetLicense() *types.License {
if s.license == nil {
var config model.Config
s.db.Model(&model.Config{}).Where("name = ?", types.ConfigKeyLicense).First(&config)
if config.Value != "" {
utils.JsonDecode(config.Value, &s.license)
}
}
return s.license
}

View File

@@ -11,6 +11,7 @@ import (
"context"
"encoding/json"
"geekai/core/types"
"geekai/store"
"geekai/store/model"
"github.com/go-redis/redis/v8"
@@ -24,27 +25,103 @@ const (
MigrationCompleted = "completed"
)
// ConfigMigrationService 配置迁移服务
type ConfigMigrationService struct {
// MigrationService 配置迁移服务
type MigrationService struct {
db *gorm.DB
redisClient *redis.Client
appConfig *types.AppConfig
levelDB *store.LevelDB
}
func NewConfigMigrationService(db *gorm.DB, redisClient *redis.Client) *ConfigMigrationService {
return &ConfigMigrationService{
func NewMigrationService(db *gorm.DB, redisClient *redis.Client, appConfig *types.AppConfig, levelDB *store.LevelDB) *MigrationService {
return &MigrationService{
db: db,
redisClient: redisClient,
appConfig: appConfig,
levelDB: levelDB,
}
}
// MigrateFromConfig 从 config.toml 迁移配置到数据库(仅首次启动时执行)
func (s *ConfigMigrationService) MigrateFromConfig(config *types.AppConfig) error {
// 检查是否已经迁移过
if s.isMigrationCompleted() {
logger.Info("配置迁移已完成,跳过迁移")
return nil
func (s *MigrationService) StartMigrate() {
go func() {
s.MigrateConfig(s.appConfig)
s.TableMigration()
s.MigrateLicense()
}()
}
// 迁移 License
func (s *MigrationService) MigrateLicense() {
key := "migrate:license"
if s.redisClient.Get(context.Background(), key).Val() == "1" {
logger.Info("License 已迁移,跳过迁移")
return
}
logger.Info("开始迁移 License...")
var license types.License
err := s.levelDB.Get(types.LicenseKey, &license)
if err != nil {
logger.Errorf("迁移 License 失败: %v", err)
return
}
logger.Infof("迁移 License: %+v", license)
if err := s.saveConfig(types.ConfigKeyLicense, license); err != nil {
logger.Errorf("迁移 License 失败: %v", err)
return
}
logger.Info("迁移 License 完成")
s.redisClient.Set(context.Background(), key, "1", 0)
}
// 数据表迁移
func (s *MigrationService) TableMigration() {
// 订单字段整理
if s.db.Migrator().HasColumn(&model.Order{}, "pay_type") {
s.db.Migrator().RenameColumn(&model.Order{}, "pay_type", "channel")
}
if !s.db.Migrator().HasColumn(&model.Order{}, "checked") {
s.db.Migrator().AddColumn(&model.Order{}, "checked")
}
// 重命名 config 表字段
if s.db.Migrator().HasColumn(&model.Config{}, "config_json") {
s.db.Migrator().RenameColumn(&model.Config{}, "config_json", "value")
}
if s.db.Migrator().HasColumn(&model.Config{}, "marker") {
s.db.Migrator().RenameColumn(&model.Config{}, "marker", "name")
}
if s.db.Migrator().HasIndex(&model.Config{}, "idx_chatgpt_configs_key") {
s.db.Migrator().DropIndex(&model.Config{}, "idx_chatgpt_configs_key")
}
if s.db.Migrator().HasIndex(&model.Config{}, "marker") {
s.db.Migrator().DropIndex(&model.Config{}, "marker")
}
// 手动删除字段
if s.db.Migrator().HasColumn(&model.Order{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.Order{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.ChatItem{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.ChatItem{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.ChatMessage{}, "deleted_at") {
s.db.Migrator().DropColumn(&model.ChatMessage{}, "deleted_at")
}
if s.db.Migrator().HasColumn(&model.User{}, "chat_config") {
s.db.Migrator().DropColumn(&model.User{}, "chat_config")
}
if s.db.Migrator().HasColumn(&model.ChatModel{}, "category") {
s.db.Migrator().DropColumn(&model.ChatModel{}, "category")
}
if s.db.Migrator().HasColumn(&model.ChatModel{}, "description") {
s.db.Migrator().DropColumn(&model.ChatModel{}, "description")
}
}
// 迁移配置数据
func (s *MigrationService) MigrateConfig(config *types.AppConfig) error {
logger.Info("开始迁移配置到数据库...")
// 迁移支付配置
@@ -65,36 +142,12 @@ func (s *ConfigMigrationService) MigrateFromConfig(config *types.AppConfig) erro
return err
}
// 标记迁移完成
if err := s.markMigrationCompleted(); err != nil {
logger.Errorf("标记迁移完成失败: %v", err)
return err
}
logger.Info("配置迁移完成")
return nil
}
// 检查是否已经迁移完成
func (s *ConfigMigrationService) isMigrationCompleted() bool {
ctx := context.Background()
status, err := s.redisClient.Get(ctx, MigrationStatusKey).Result()
if err != nil {
// Redis中没有找到标志说明未迁移过
return false
}
return status == MigrationCompleted
}
// 标记迁移完成
func (s *ConfigMigrationService) markMigrationCompleted() error {
ctx := context.Background()
// 设置迁移完成标志,永不过期
return s.redisClient.Set(ctx, MigrationStatusKey, MigrationCompleted, 0).Err()
}
// 迁移支付配置
func (s *ConfigMigrationService) migratePaymentConfig(config *types.AppConfig) error {
func (s *MigrationService) migratePaymentConfig(config *types.AppConfig) error {
paymentConfig := types.PaymentConfig{
Alipay: config.AlipayConfig,
@@ -109,7 +162,7 @@ func (s *ConfigMigrationService) migratePaymentConfig(config *types.AppConfig) e
}
// 迁移存储配置
func (s *ConfigMigrationService) migrateStorageConfig(config *types.AppConfig) error {
func (s *MigrationService) migrateStorageConfig(config *types.AppConfig) error {
ossConfig := types.OSSConfig{
Active: config.OSS.Active,
@@ -122,7 +175,7 @@ func (s *ConfigMigrationService) migrateStorageConfig(config *types.AppConfig) e
}
// 迁移通信配置
func (s *ConfigMigrationService) migrateCommunicationConfig(config *types.AppConfig) error {
func (s *MigrationService) migrateCommunicationConfig(config *types.AppConfig) error {
// SMTP配置
smtpConfig := map[string]any{
"use_tls": config.SmtpConfig.UseTls,
@@ -156,7 +209,7 @@ func (s *ConfigMigrationService) migrateCommunicationConfig(config *types.AppCon
}
// 保存配置到数据库
func (s *ConfigMigrationService) saveConfig(key string, config any) error {
func (s *MigrationService) saveConfig(key string, config any) error {
// 检查是否已存在
var existingConfig model.Config
if err := s.db.Where("name", key).First(&existingConfig).Error; err == nil {

View File

@@ -34,6 +34,7 @@
<button
class="w-full h-12 rounded-xl text-base font-medium text-white bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg active:translate-y-0 shadow-md"
@click="submitLogin"
type="button"
>
{{ loading ? '登录中...' : '登 录' }}
</button>
@@ -210,6 +211,7 @@
<button
class="w-full h-12 rounded-xl text-base font-medium text-white bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg active:translate-y-0 shadow-md"
@click="submitRegister"
type="button"
>
{{ loading ? '注册中...' : '注 册' }}
</button>

View File

@@ -1,133 +0,0 @@
/**
* 设备检测工具函数
* 用于判断当前设备类型支持PC端和移动端的智能识别
*/
/**
* 检测设备类型
* @returns {string} 'mobile' | 'desktop'
*/
export const detectDevice = () => {
const userAgent = navigator.userAgent.toLowerCase()
// 移动设备关键词检测
const mobileKeywords = [
'mobile',
'android',
'iphone',
'ipad',
'phone',
'blackberry',
'opera mini',
'windows phone',
'iemobile',
]
// 平板设备关键词检测
const tabletKeywords = ['tablet', 'ipad', 'playbook', 'silk', 'kindle']
// 检查是否为移动设备
const isMobile = mobileKeywords.some((keyword) => userAgent.includes(keyword))
// 检查是否为平板设备
const isTablet = tabletKeywords.some((keyword) => userAgent.includes(keyword))
// 检查屏幕尺寸
const screenWidth = window.innerWidth
const screenHeight = window.innerHeight
// 移动设备判断逻辑
if (isMobile || isTablet || screenWidth <= 768) {
return 'mobile'
}
return 'desktop'
}
/**
* 检测是否为移动设备
* @returns {boolean}
*/
export const isMobileDevice = () => {
return detectDevice() === 'mobile'
}
/**
* 检测是否为桌面设备
* @returns {boolean}
*/
export const isDesktopDevice = () => {
return detectDevice() === 'desktop'
}
/**
* 获取设备跳转路径
* @param {string} deviceType - 设备类型
* @param {string} defaultPath - 默认路径
* @returns {string} 跳转路径
*/
export const getDeviceRedirectPath = (deviceType, defaultPath = '/') => {
if (deviceType === 'mobile') {
return '/mobile'
}
return defaultPath
}
/**
* 根据当前设备获取跳转路径
* @param {string} defaultPath - 默认路径
* @returns {string} 跳转路径
*/
export const getCurrentDeviceRedirectPath = (defaultPath = '/') => {
const deviceType = detectDevice()
return getDeviceRedirectPath(deviceType, defaultPath)
}
/**
* 检测屏幕尺寸
* @returns {object} { width, height, isSmall, isMedium, isLarge }
*/
export const getScreenInfo = () => {
const width = window.innerWidth
const height = window.innerHeight
return {
width,
height,
isSmall: width <= 768,
isMedium: width > 768 && width <= 1024,
isLarge: width > 1024,
}
}
/**
* 检测浏览器类型
* @returns {string} 浏览器类型
*/
export const detectBrowser = () => {
const userAgent = navigator.userAgent.toLowerCase()
if (userAgent.includes('chrome')) return 'chrome'
if (userAgent.includes('firefox')) return 'firefox'
if (userAgent.includes('safari') && !userAgent.includes('chrome')) return 'safari'
if (userAgent.includes('edge')) return 'edge'
if (userAgent.includes('opera')) return 'opera'
return 'unknown'
}
/**
* 检测操作系统
* @returns {string} 操作系统类型
*/
export const detectOS = () => {
const userAgent = navigator.userAgent.toLowerCase()
if (userAgent.includes('windows')) return 'windows'
if (userAgent.includes('mac')) return 'macos'
if (userAgent.includes('linux')) return 'linux'
if (userAgent.includes('android')) return 'android'
if (userAgent.includes('ios')) return 'ios'
return 'unknown'
}

View File

@@ -30,12 +30,7 @@
</div>
<div class="login-content">
<login-dialog
:show="true"
@hide="handleLoginHide"
@success="handleLoginSuccess"
ref="loginDialogRef"
/>
<login-dialog :show="true" @success="handleLoginSuccess" ref="loginDialogRef" />
</div>
</div>
</div>
@@ -45,7 +40,7 @@
<script setup>
import LoginDialog from '@/components/LoginDialog.vue'
import { setUserToken } from '@/store/session'
import { getCurrentDeviceRedirectPath } from '@/utils/device'
import { isMobile } from '@/utils/libs'
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -58,16 +53,13 @@ if (token) {
router.push('/chat')
}
// 处理登录弹窗隐藏
const handleLoginHide = () => {
const redirectPath = getCurrentDeviceRedirectPath()
router.push(redirectPath)
}
// 处理登录成功
const handleLoginSuccess = () => {
const redirectPath = getCurrentDeviceRedirectPath()
router.push(redirectPath)
if (isMobile()) {
router.push('/mobile')
} else {
router.push('/chat')
}
}
onMounted(() => {

View File

@@ -34,7 +34,6 @@
:show="true"
active="register"
:inviteCode="inviteCode"
@hide="handleRegisterHide"
@success="handleRegisterSuccess"
ref="loginDialogRef"
/>
@@ -46,7 +45,7 @@
<script setup>
import LoginDialog from '@/components/LoginDialog.vue'
import { getCurrentDeviceRedirectPath } from '@/utils/device'
import { isMobile } from '@/utils/libs'
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -54,16 +53,13 @@ const router = useRouter()
const loginDialogRef = ref(null)
const inviteCode = ref(router.currentRoute.value.query.invite_code || '')
// 处理注册弹窗隐藏
const handleRegisterHide = () => {
const redirectPath = getCurrentDeviceRedirectPath()
router.push(redirectPath)
}
// 处理注册成功
const handleRegisterSuccess = () => {
const redirectPath = getCurrentDeviceRedirectPath()
router.push(redirectPath)
if (isMobile()) {
router.push('/mobile')
} else {
router.push('/chat')
}
}
onMounted(() => {