fix: add /docs redirect middleware to forward docs paths to configured docs_link
This commit is contained in:
parent
9f47782442
commit
6a880c08ba
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/QuantumNous/new-api/common"
|
"github.com/QuantumNous/new-api/common"
|
||||||
"github.com/QuantumNous/new-api/middleware"
|
"github.com/QuantumNous/new-api/middleware"
|
||||||
|
"github.com/QuantumNous/new-api/setting/operation_setting"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
@ -18,6 +19,32 @@ func SetRouter(router *gin.Engine, buildFS embed.FS, indexPage []byte) {
|
||||||
SetDashboardRouter(router)
|
SetDashboardRouter(router)
|
||||||
SetRelayRouter(router)
|
SetRelayRouter(router)
|
||||||
SetVideoRouter(router)
|
SetVideoRouter(router)
|
||||||
|
|
||||||
|
// 文档重定向:拦截 /docs 和 /{lang}/docs 路径,转发到配置的 docs_link
|
||||||
|
router.Use(func(c *gin.Context) {
|
||||||
|
path := c.Request.URL.Path
|
||||||
|
var prefix string
|
||||||
|
if path == "/docs" || strings.HasPrefix(path, "/docs/") {
|
||||||
|
prefix = "/docs"
|
||||||
|
} else {
|
||||||
|
for _, lp := range []string{"/zh/docs", "/en/docs", "/ja/docs"} {
|
||||||
|
if path == lp || strings.HasPrefix(path, lp+"/") {
|
||||||
|
prefix = lp
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prefix == "" {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
docsLink := operation_setting.GetGeneralSetting().DocsLink
|
||||||
|
subPath := strings.TrimPrefix(path, prefix)
|
||||||
|
target := strings.TrimRight(docsLink, "/") + subPath
|
||||||
|
c.Redirect(http.StatusFound, target)
|
||||||
|
c.Abort()
|
||||||
|
})
|
||||||
|
|
||||||
frontendBaseUrl := os.Getenv("FRONTEND_BASE_URL")
|
frontendBaseUrl := os.Getenv("FRONTEND_BASE_URL")
|
||||||
if common.IsMasterNode && frontendBaseUrl != "" {
|
if common.IsMasterNode && frontendBaseUrl != "" {
|
||||||
frontendBaseUrl = ""
|
frontendBaseUrl = ""
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
For commercial licensing, please contact support@quantumnous.com
|
For commercial licensing, please contact support@quantumnous.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Copy, Check, Code, Terminal, FileCode, Box, Grid3X3, Play, Trophy, PieChart, BookOpen, Search, Sun, Moon, Monitor, Languages } from 'lucide-react';
|
import { Copy, Check, Code, Terminal, FileCode, Box, Grid3X3, Play, Trophy, PieChart, BookOpen, Search, Sun, Moon, Monitor, Languages } from 'lucide-react';
|
||||||
import { mapWebLanguageToDocsLocale } from '../../helpers/docsLink';
|
|
||||||
|
|
||||||
|
|
||||||
/* ==================================================================
|
/* ==================================================================
|
||||||
|
|
@ -140,7 +139,7 @@ function HomeLanguageSelector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function HeroSection() {
|
function HeroSection() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const copyCmd = useCallback(() => {
|
const copyCmd = useCallback(() => {
|
||||||
|
|
@ -148,12 +147,6 @@ function HeroSection() {
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => setCopied(false), 1500);
|
setTimeout(() => setCopied(false), 1500);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const docsUrl = useMemo(() => {
|
|
||||||
const locale = mapWebLanguageToDocsLocale(i18n.language);
|
|
||||||
return `/${locale}/docs`;
|
|
||||||
}, [i18n.language]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative bg-black text-white overflow-hidden">
|
<section className="relative bg-black text-white overflow-hidden">
|
||||||
<div className="absolute inset-0 pointer-events-none opacity-[0.04]" style={{ backgroundImage: "radial-gradient(circle, white 1px, transparent 1px)", backgroundSize: "24px 24px" }} />
|
<div className="absolute inset-0 pointer-events-none opacity-[0.04]" style={{ backgroundImage: "radial-gradient(circle, white 1px, transparent 1px)", backgroundSize: "24px 24px" }} />
|
||||||
|
|
@ -169,11 +162,11 @@ function HeroSection() {
|
||||||
{[
|
{[
|
||||||
{ key: "model", label: "模型", icon: <Box size={16} />, to: "/pricing" },
|
{ key: "model", label: "模型", icon: <Box size={16} />, to: "/pricing" },
|
||||||
{ key: "benchmark", label: "评测", icon: <Trophy size={16} />, to: "/benchmarks" },
|
{ key: "benchmark", label: "评测", icon: <Trophy size={16} />, to: "/benchmarks" },
|
||||||
{ key: "docs", label: "文档", icon: <BookOpen size={16} />, to: docsUrl, external: true },
|
{ key: "docs", label: "文档", icon: <BookOpen size={16} />, to: "/docs", isDocs: true },
|
||||||
{ key: "console", label: "控制台", icon: <Grid3X3 size={16} />, to: "/console" },
|
{ key: "console", label: "控制台", icon: <Grid3X3 size={16} />, to: "/console" },
|
||||||
].map((item) => {
|
].map((item) => {
|
||||||
const linkClass = "inline-flex items-center gap-1.5 px-3 py-1.5 text-[14px] rounded-md transition-colors duration-150 text-white/60 hover:text-white";
|
const linkClass = "inline-flex items-center gap-1.5 px-3 py-1.5 text-[14px] rounded-md transition-colors duration-150 text-white/60 hover:text-white";
|
||||||
if (item.external) {
|
if (item.isDocs) {
|
||||||
return <a key={item.key} href={item.to} className={linkClass}>{item.icon}<span className="hidden sm:inline">{t(item.label)}</span></a>;
|
return <a key={item.key} href={item.to} className={linkClass}>{item.icon}<span className="hidden sm:inline">{t(item.label)}</span></a>;
|
||||||
}
|
}
|
||||||
return <Link key={item.key} to={item.to} className={linkClass}>{item.icon}<span className="hidden sm:inline">{t(item.label)}</span></Link>;
|
return <Link key={item.key} to={item.to} className={linkClass}>{item.icon}<span className="hidden sm:inline">{t(item.label)}</span></Link>;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue