feat: dynamic URL (#3444)
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run

This commit is contained in:
shaohuzhang1 2025-07-01 15:43:00 +08:00 committed by GitHub
parent 9b89e8f75c
commit 2ad5883aef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 106 additions and 45 deletions

View File

@ -102,11 +102,15 @@ class Config(dict):
return self.get('LOG_LEVEL', 'DEBUG')
def get_sandbox_python_package_paths(self):
return self.get('SANDBOX_PYTHON_PACKAGE_PATHS', '/opt/py3/lib/python3.11/site-packages,/opt/maxkb-app/sandbox/python-packages,/opt/maxkb/python-packages')
return self.get('SANDBOX_PYTHON_PACKAGE_PATHS',
'/opt/py3/lib/python3.11/site-packages,/opt/maxkb-app/sandbox/python-packages,/opt/maxkb/python-packages')
def get_admin_path(self):
return self.get('ADMIN_PATH', 'admin')
def get_chat_path(self):
return self.get('CHAT_PATH', '/chat')
def get_session_timeout(self):
return int(self.get('SESSION_TIMEOUT', 28800))

View File

@ -55,7 +55,7 @@ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]
REST_FRAMEWORK = {
@ -63,7 +63,7 @@ REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': ['common.auth.authenticate.AnonymousAuthentication']
}
STATICFILES_DIRS = [(os.path.join(PROJECT_DIR, 'ui', 'dist')), (os.path.join(PROJECT_DIR, 'chat', 'dist'))]
STATICFILES_DIRS = [(os.path.join(PROJECT_DIR, 'ui', 'dist'))]
STATIC_ROOT = os.path.join(BASE_DIR.parent, 'static')
ROOT_URLCONF = 'maxkb.urls'
APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
@ -71,7 +71,7 @@ APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ["apps/static/ui"],
'DIRS': ["apps/static/admin"],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [

View File

@ -16,7 +16,7 @@ Including another URLconf
"""
import os
from django.http import HttpResponse
from django.http import HttpResponse,HttpResponseRedirect
from django.urls import path, re_path, include
from django.views import static
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
@ -25,16 +25,21 @@ from rest_framework import status
from common.result import Result
from maxkb import settings
from maxkb.conf import PROJECT_DIR
from maxkb.const import CONFIG
admin_api_prefix = CONFIG.get_admin_path()[1:] + '/api/'
admin_ui_prefix = CONFIG.get_admin_path()
chat_api_prefix = CONFIG.get_chat_path()[1:] + '/api/'
chat_ui_prefix = CONFIG.get_chat_path()
urlpatterns = [
path("api/", include("users.urls")),
path("api/", include("tools.urls")),
path("api/", include("models_provider.urls")),
path("api/", include("folders.urls")),
path("api/", include("knowledge.urls")),
path("api/", include("system_manage.urls")),
path("api/", include("application.urls")),
path("chat/api/", include("chat.urls")),
path(admin_api_prefix, include("users.urls")),
path(admin_api_prefix, include("tools.urls")),
path(admin_api_prefix, include("models_provider.urls")),
path(admin_api_prefix, include("folders.urls")),
path(admin_api_prefix, include("knowledge.urls")),
path(admin_api_prefix, include("system_manage.urls")),
path(admin_api_prefix, include("application.urls")),
path(chat_api_prefix, include("chat.urls")),
path('oss/', include('oss.urls')),
]
urlpatterns += [
@ -54,12 +59,14 @@ def pro():
)
# 暴露ui静态资源
urlpatterns.append(
re_path(r'^ui/(?P<path>.*)$', static.serve, {'document_root': os.path.join(settings.STATIC_ROOT, "ui")},
name='ui'),
re_path(rf"^{CONFIG.get_admin_path()[1:]}/(?P<path>.*)$", static.serve,
{'document_root': os.path.join(settings.STATIC_ROOT, "admin")},
name='admin'),
)
# 暴露ui静态资源
urlpatterns.append(
re_path(r'^chat/(?P<path>.*)$', static.serve, {'document_root': os.path.join(settings.STATIC_ROOT, "chat")},
re_path(rf'^{CONFIG.get_chat_path()[1:]}/(?P<path>.*)$', static.serve,
{'document_root': os.path.join(settings.STATIC_ROOT, "chat")},
name='chat'),
)
@ -79,18 +86,26 @@ def page_not_found(request, exception):
"""
页面不存在处理
"""
if request.path.startswith("/api/"):
if request.path.startswith(admin_ui_prefix + '/api/'):
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
if request.path.startswith("/chat/api/"):
if request.path.startswith(chat_ui_prefix + '/api/'):
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
if request.path.startswith('/chat'):
if request.path.startswith(chat_ui_prefix):
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'chat', 'index.html')
content = get_index_html(index_path)
content.replace("prefix: '/chat'", f"prefix: {CONFIG.get_chat_path()}")
if not os.path.exists(index_path):
return HttpResponse("页面不存在", status=404)
return HttpResponse(content, status=200)
elif request.path.startswith(admin_ui_prefix):
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'admin', 'index.html')
if not os.path.exists(index_path):
return HttpResponse("页面不存在", status=404)
content = get_index_html(index_path)
content = content.replace("prefix: '/admin'", f"prefix: '{CONFIG.get_admin_path()}'")
return HttpResponse(content, status=200)
else:
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'ui', 'index.html')
if not os.path.exists(index_path):
return HttpResponse("页面不存在", status=404)
content = get_index_html(index_path)
return HttpResponse(content, status=200)
return HttpResponseRedirect(admin_ui_prefix+'/')
handler404 = page_not_found

View File

@ -7,6 +7,11 @@
<base target="_blank" />
<title>%VITE_APP_TITLE%</title>
</head>
<script>
window.MaxKB = {
prefix: '/admin',
}
</script>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>

View File

@ -7,6 +7,11 @@
<base target="_blank" />
<title>%VITE_APP_TITLE%</title>
</head>
<script>
window.MaxKB = {
prefix: '/chat',
}
</script>
<body>
<div id="app"></div>
<script type="module" src="/src/chat.ts"></script>

6
ui/env.d.ts vendored
View File

@ -1 +1,7 @@
/// <reference types="vite/client" />
interface Window {
sendMessage: ?((message: string, other_params_data: any) => void)
MaxKB: {
prefix: string
}
}

6
ui/env/.env vendored
View File

@ -1,5 +1,5 @@
VITE_APP_NAME=ui
VITE_BASE_PATH=/ui/
VITE_APP_NAME=admin
VITE_BASE_PATH=/admin/
VITE_APP_PORT=3000
VITE_APP_TITLE = 'MaxKB'
VITE_ENTRY="entry/system/index.html"
VITE_ENTRY="admin.html"

2
ui/env/.env.chat vendored
View File

@ -2,4 +2,4 @@ VITE_APP_NAME=chat
VITE_BASE_PATH=/chat/
VITE_APP_PORT=3001
VITE_APP_TITLE = 'MaxKB'
VITE_ENTRY="entry/chat/index.html"
VITE_ENTRY="chat.html"

View File

@ -177,7 +177,8 @@ const open: (application_id: string, loading?: Ref<boolean>) => Promise<Result<s
* data
*/
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
return postStream(`/api/chat_message/${chat_id}`, data)
const prefix = (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/admin') + '/api'
return postStream(`${prefix}/chat_message/${chat_id}`, data)
}
/**
*

View File

@ -40,7 +40,8 @@ const open: (loading?: Ref<boolean>) => Promise<Result<string>> = (loading) => {
* data
*/
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
return postStream(`/chat/api/chat_message/${chat_id}`, data)
const prefix = (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/chat') + '/api'
return postStream(`${prefix}/chat_message/${chat_id}`, data)
}
/**

View File

@ -4,12 +4,11 @@ import type { NProgress } from 'nprogress'
import type { Ref } from 'vue'
import type { Result } from '@/request/Result'
import useStore from '@/stores'
import router from '@/router'
import { ref, type WritableComputedRef } from 'vue'
const axiosConfig = {
baseURL: '/chat/api',
baseURL: (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/chat') + '/api',
withCredentials: false,
timeout: 600000,
headers: {},

View File

@ -9,7 +9,7 @@ import router from '@/router'
import { ref, type WritableComputedRef } from 'vue'
const axiosConfig = {
baseURL: '/api',
baseURL: (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/admin') + '/api',
withCredentials: false,
timeout: 600000,
headers: {},

View File

@ -12,7 +12,7 @@ import useStore from '@/stores'
import { routes } from '@/router/chat/routes'
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
history: createWebHistory(window.MaxKB?.prefix ? window.MaxKB?.prefix : import.meta.env.BASE_URL),
routes: routes,
})

View File

@ -7,14 +7,13 @@ import {
createWebHistory,
type NavigationGuardNext,
type RouteLocationNormalized,
type RouteRecordRaw,
type RouteRecordName,
} from 'vue-router'
import useStore from '@/stores'
import { routes } from '@/router/routes'
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
history: createWebHistory(window.MaxKB?.prefix ? window.MaxKB?.prefix : import.meta.env.BASE_URL),
routes: routes,
})

View File

@ -1,3 +1,4 @@
import { model } from '@/permission/model'
import { fileURLToPath, URL } from 'node:url'
import type { ProxyOptions } from 'vite'
import { defineConfig, loadEnv } from 'vite'
@ -6,21 +7,39 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
import DefineOptions from 'unplugin-vue-define-options/vite'
import path from 'path'
import { createHtmlPlugin } from 'vite-plugin-html'
import fs from 'fs'
// import vueDevTools from 'vite-plugin-vue-devtools'
const envDir = './env'
// 自定义插件:重命名入口文件
const renameHtmlPlugin = (outDir: string, entry: string) => {
return {
name: 'rename-html',
closeBundle: () => {
const buildDir = path.resolve(__dirname, outDir)
const oldFile = path.join(buildDir, entry)
const newFile = path.join(buildDir, 'index.html')
// 检查文件是否存在
if (fs.existsSync(oldFile)) {
// 删除已存在的 index.html
if (fs.existsSync(newFile)) {
fs.unlinkSync(newFile)
}
// 重命名文件
fs.renameSync(oldFile, newFile)
}
},
}
}
// https://vite.dev/config/
export default defineConfig(({ mode }) => {
export default defineConfig((conf: any) => {
const mode = conf.mode
const ENV = loadEnv(mode, envDir)
console.log(ENV)
const prefix = process.env.VITE_DYNAMIC_PREFIX || ENV.VITE_BASE_PATH
const proxyConf: Record<string, string | ProxyOptions> = {}
proxyConf['/api'] = {
proxyConf['/admin/api'] = {
// target: 'http://47.92.195.88:8080',
target: 'http://127.0.0.1:8080',
changeOrigin: true,
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
}
proxyConf['/oss'] = {
target: 'http://127.0.0.1:8080',
@ -46,12 +65,19 @@ export default defineConfig(({ mode }) => {
changeOrigin: true,
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
}
return {
preflight: false,
lintOnSave: false,
base: prefix,
base: './',
envDir: envDir,
plugins: [vue(), vueJsx(), DefineOptions(), createHtmlPlugin({ template: ENV.VITE_ENTRY })],
plugins: [
vue(),
vueJsx(),
DefineOptions(),
createHtmlPlugin({ template: ENV.VITE_ENTRY }),
renameHtmlPlugin(`dist${ENV.VITE_BASE_PATH}`, ENV.VITE_ENTRY),
],
server: {
cors: true,
host: '0.0.0.0',
@ -62,7 +88,7 @@ export default defineConfig(({ mode }) => {
build: {
outDir: `dist${ENV.VITE_BASE_PATH}`,
rollupOptions: {
input: path.resolve(__dirname, ENV.VITE_ENTRY),
input: ENV.VITE_ENTRY,
},
},
resolve: {