diff --git a/controller/console_migrate.go b/controller/console_migrate.go new file mode 100644 index 00000000..937fa2ee --- /dev/null +++ b/controller/console_migrate.go @@ -0,0 +1,88 @@ +// 用于迁移检测的旧键,该文件下个版本会删除 + +package controller + +import ( + "encoding/json" + "net/http" + "one-api/common" + "one-api/model" + "github.com/gin-gonic/gin" +) + +// MigrateConsoleSetting 迁移旧的控制台相关配置到 console_setting.* +func MigrateConsoleSetting(c *gin.Context) { + // 读取全部 option + opts, err := model.AllOption() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()}) + return + } + // 建立 map + valMap := map[string]string{} + for _, o := range opts { + valMap[o.Key] = o.Value + } + + // 处理 APIInfo + if v := valMap["ApiInfo"]; v != "" { + var arr []map[string]interface{} + if err := json.Unmarshal([]byte(v), &arr); err == nil { + if len(arr) > 50 { + arr = arr[:50] + } + bytes, _ := json.Marshal(arr) + model.UpdateOption("console_setting.api_info", string(bytes)) + } + model.UpdateOption("ApiInfo", "") + } + // Announcements 直接搬 + if v := valMap["Announcements"]; v != "" { + model.UpdateOption("console_setting.announcements", v) + model.UpdateOption("Announcements", "") + } + // FAQ 转换 + if v := valMap["FAQ"]; v != "" { + var arr []map[string]interface{} + if err := json.Unmarshal([]byte(v), &arr); err == nil { + out := []map[string]interface{}{} + for _, item := range arr { + q, _ := item["question"].(string) + if q == "" { + q, _ = item["title"].(string) + } + a, _ := item["answer"].(string) + if a == "" { + a, _ = item["content"].(string) + } + if q != "" && a != "" { + out = append(out, map[string]interface{}{"question": q, "answer": a}) + } + } + if len(out) > 50 { + out = out[:50] + } + bytes, _ := json.Marshal(out) + model.UpdateOption("console_setting.faq", string(bytes)) + } + model.UpdateOption("FAQ", "") + } + // Uptime + if v := valMap["UptimeKumaUrl"]; v != "" { + model.UpdateOption("console_setting.uptime_kuma_url", v) + model.UpdateOption("UptimeKumaUrl", "") + } + if v := valMap["UptimeKumaSlug"]; v != "" { + model.UpdateOption("console_setting.uptime_kuma_slug", v) + model.UpdateOption("UptimeKumaSlug", "") + } + + // 删除旧键记录 + oldKeys := []string{"ApiInfo", "Announcements", "FAQ", "UptimeKumaUrl", "UptimeKumaSlug"} + model.DB.Where("key IN ?", oldKeys).Delete(&model.Option{}) + + // 重新加载 OptionMap + model.InitOptionMap() + common.SysLog("console setting migrated") + c.JSON(http.StatusOK, gin.H{"success": true, "message": "migrated"}) +} \ No newline at end of file diff --git a/router/api-router.go b/router/api-router.go index 851e9193..45930246 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -81,6 +81,7 @@ func SetApiRouter(router *gin.Engine) { optionRoute.GET("/", controller.GetOptions) optionRoute.PUT("/", controller.UpdateOption) optionRoute.POST("/rest_model_ratio", controller.ResetModelRatio) + optionRoute.POST("/migrate_console_setting", controller.MigrateConsoleSetting) // 用于迁移检测的旧键,下个版本会删除 } channelRoute := apiRouter.Group("/channel") channelRoute.Use(middleware.AdminAuth()) diff --git a/web/src/components/settings/DashboardSetting.js b/web/src/components/settings/DashboardSetting.js index f52add07..7021c7ca 100644 --- a/web/src/components/settings/DashboardSetting.js +++ b/web/src/components/settings/DashboardSetting.js @@ -1,6 +1,6 @@ -import React, { useEffect, useState } from 'react'; -import { Card, Spin } from '@douyinfe/semi-ui'; -import { API, showError } from '../../helpers'; +import React, { useEffect, useState, useMemo } from 'react'; +import { Card, Spin, Button, Modal } from '@douyinfe/semi-ui'; +import { API, showError, showSuccess } from '../../helpers'; import SettingsAPIInfo from '../../pages/Setting/Dashboard/SettingsAPIInfo.js'; import SettingsAnnouncements from '../../pages/Setting/Dashboard/SettingsAnnouncements.js'; import SettingsFAQ from '../../pages/Setting/Dashboard/SettingsFAQ.js'; @@ -13,9 +13,17 @@ const DashboardSetting = () => { 'console_setting.faq': '', 'console_setting.uptime_kuma_url': '', 'console_setting.uptime_kuma_slug': '', + + // 用于迁移检测的旧键,下个版本会删除 + ApiInfo: '', + Announcements: '', + FAQ: '', + UptimeKumaUrl: '', + UptimeKumaSlug: '', }); let [loading, setLoading] = useState(false); + const [showMigrateModal, setShowMigrateModal] = useState(false); // 下个版本会删除 const getOptions = async () => { const res = await API.get('/api/option/'); @@ -49,9 +57,52 @@ const DashboardSetting = () => { onRefresh(); }, []); + // 用于迁移检测的旧键,下个版本会删除 + const hasLegacyData = useMemo(() => { + const legacyKeys = ['ApiInfo', 'Announcements', 'FAQ', 'UptimeKumaUrl', 'UptimeKumaSlug']; + return legacyKeys.some(k => inputs[k]); + }, [inputs]); + + useEffect(() => { + if (hasLegacyData) { + setShowMigrateModal(true); + } + }, [hasLegacyData]); + + const handleMigrate = async () => { + try { + setLoading(true); + await API.post('/api/option/migrate_console_setting'); + showSuccess('旧配置迁移完成'); + await onRefresh(); + setShowMigrateModal(false); + } catch (err) { + console.error(err); + showError('迁移失败: ' + (err.message || '未知错误')); + } finally { + setLoading(false); + } + }; + return ( <> + {/* 用于迁移检测的旧键模态框,下个版本会删除 */} + setShowMigrateModal(false)} + confirmLoading={loading} + okText="确认迁移" + cancelText="取消" + > +

检测到旧版本的配置数据,是否要迁移到新的配置格式?

+

+ 注意:迁移过程中会自动处理数据格式转换,迁移完成后旧配置将被清除,请在迁移前在数据库中备份好旧配置。 +

+
+ {/* API信息管理 */}