接入可配置概览服务并支持自适应缩放
This commit is contained in:
@@ -185,6 +185,9 @@ eco-market:
|
||||
mcp:
|
||||
proxy-base-url: ${MCP_PROXY_URL:http://localhost:8020}
|
||||
|
||||
overview-page:
|
||||
service-url: ${OVERVIEW_SERVICE_URL:http://127.0.0.1:5173/_app/digital}
|
||||
|
||||
intelligent-data:
|
||||
service-url: ${INTELLIGENT_DATA_SERVICE_URL:http://192.168.2.106:3000/test-console}
|
||||
|
||||
|
||||
@@ -185,6 +185,9 @@ eco-market:
|
||||
mcp:
|
||||
proxy-base-url: ${MCP_PROXY_URL:http://localhost:18020}
|
||||
|
||||
overview-page:
|
||||
service-url: ${OVERVIEW_SERVICE_URL:http://127.0.0.1:5173/_app/digital}
|
||||
|
||||
intelligent-data:
|
||||
service-url: ${INTELLIGENT_DATA_SERVICE_URL:http://192.168.2.106:3000/test-console}
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ eco-market:
|
||||
mcp:
|
||||
proxy-base-url: ${MCP_PROXY_URL:http://localhost:8020}
|
||||
|
||||
overview-page:
|
||||
service-url: ${OVERVIEW_SERVICE_URL:http://127.0.0.1:5173/_app/digital}
|
||||
|
||||
intelligent-data:
|
||||
service-url: ${INTELLIGENT_DATA_SERVICE_URL:http://192.168.2.106:3000/test-console}
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ eco-market:
|
||||
mcp:
|
||||
proxy-base-url: ${MCP_PROXY_URL:http://localhost:8020}
|
||||
|
||||
overview-page:
|
||||
service-url: ${OVERVIEW_SERVICE_URL:http://127.0.0.1:5173/_app/digital}
|
||||
|
||||
intelligent-data:
|
||||
service-url: ${INTELLIGENT_DATA_SERVICE_URL:http://192.168.2.106:3000/test-console}
|
||||
|
||||
|
||||
@@ -179,6 +179,9 @@ public class TenantConfigDto implements Serializable {
|
||||
@Schema(description = "模型API根地址")
|
||||
private String baseModelApiUrl;
|
||||
|
||||
@Schema(description = "客户端概览服务地址")
|
||||
private String overviewServiceUrl;
|
||||
|
||||
@Schema(description = "智能取数服务地址")
|
||||
private String intelligentDataServiceUrl;
|
||||
|
||||
|
||||
@@ -72,6 +72,18 @@ public class TenantConfigServiceImpl extends ServiceImpl<TenantConfigMapper, Ten
|
||||
.required(true)
|
||||
.sort(1)
|
||||
.build());
|
||||
tenantConfigDefaultList.add(TenantConfig.builder()
|
||||
.name("overviewServiceUrl")
|
||||
.description("客户端概览服务地址")
|
||||
.value("http://127.0.0.1:5173/_app/digital")
|
||||
.notice("客户端点击概览时加载的 HTTP 或 HTTPS 服务地址")
|
||||
.placeholder("请输入客户端概览服务地址")
|
||||
.category(TenantConfig.ConfigCategory.BaseConfig)
|
||||
.inputType(TenantConfig.InputType.Input)
|
||||
.dataType(TenantConfig.DataType.String)
|
||||
.required(true)
|
||||
.sort(2)
|
||||
.build());
|
||||
tenantConfigDefaultList.add(TenantConfig.builder()
|
||||
.name("intelligentDataServiceUrl")
|
||||
.description("智能取数服务地址")
|
||||
@@ -82,7 +94,7 @@ public class TenantConfigServiceImpl extends ServiceImpl<TenantConfigMapper, Ten
|
||||
.inputType(TenantConfig.InputType.Input)
|
||||
.dataType(TenantConfig.DataType.String)
|
||||
.required(true)
|
||||
.sort(2)
|
||||
.sort(3)
|
||||
.build());
|
||||
tenantConfigDefaultList.add(TenantConfig.builder()
|
||||
.name("documentEditorServiceUrl")
|
||||
@@ -94,7 +106,7 @@ public class TenantConfigServiceImpl extends ServiceImpl<TenantConfigMapper, Ten
|
||||
.inputType(TenantConfig.InputType.Input)
|
||||
.dataType(TenantConfig.DataType.String)
|
||||
.required(false)
|
||||
.sort(3)
|
||||
.sort(4)
|
||||
.build());
|
||||
tenantConfigDefaultList.add(TenantConfig.builder()
|
||||
.name("siteDescription")
|
||||
|
||||
@@ -38,6 +38,9 @@ public class TenantController {
|
||||
@Value("${model-api-proxy.base-api-url:}")
|
||||
private String baseApiUrl;
|
||||
|
||||
@Value("${overview-page.service-url:http://127.0.0.1:5173/_app/digital}")
|
||||
private String overviewServiceUrl;
|
||||
|
||||
@Value("${intelligent-data.service-url:http://192.168.2.106:3000/test-console}")
|
||||
private String intelligentDataServiceUrl;
|
||||
|
||||
@@ -75,6 +78,9 @@ public class TenantController {
|
||||
tenantConfigDto.setFaviconUrl(iFileAccessService.getFileUrlWithAk(tenantConfigDto.getFaviconUrl(), true));
|
||||
tenantConfigDto.setSquareBanner(iFileAccessService.getFileUrlWithAk(tenantConfigDto.getSquareBanner(), true));
|
||||
tenantConfigDto.setMaxFileSize(maxFileSize);
|
||||
if (StringUtils.isBlank(tenantConfigDto.getOverviewServiceUrl())) {
|
||||
tenantConfigDto.setOverviewServiceUrl(overviewServiceUrl);
|
||||
}
|
||||
if (StringUtils.isBlank(tenantConfigDto.getIntelligentDataServiceUrl())) {
|
||||
tenantConfigDto.setIntelligentDataServiceUrl(intelligentDataServiceUrl);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ export default function BaseFormItem({
|
||||
],
|
||||
};
|
||||
const serviceUrlFieldNames = [
|
||||
'overviewServiceUrl',
|
||||
'intelligentDataServiceUrl',
|
||||
'documentEditorServiceUrl',
|
||||
];
|
||||
@@ -135,7 +136,7 @@ export default function BaseFormItem({
|
||||
)
|
||||
? [
|
||||
{
|
||||
required: props.name === 'intelligentDataServiceUrl',
|
||||
required: props.name !== 'documentEditorServiceUrl',
|
||||
message: `请输入${props.description}`,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -369,6 +369,8 @@ export interface TenantConfigDto {
|
||||
siteName?: string;
|
||||
/** 站点描述 */
|
||||
siteDescription?: string;
|
||||
/** 客户端概览服务地址 */
|
||||
overviewServiceUrl?: string;
|
||||
/** 智能取数服务地址 */
|
||||
intelligentDataServiceUrl?: string;
|
||||
/** 文档编辑服务地址 */
|
||||
|
||||
@@ -37,6 +37,7 @@ import SetupWizard from "./components/setup/SetupWizard";
|
||||
import LoginPage from "./components/setup/LoginPage";
|
||||
import SetupDependencies from "./components/setup/SetupDependencies";
|
||||
import ClientPage from "./components/pages/ClientPage";
|
||||
import OverviewPage from "./components/pages/OverviewPage";
|
||||
import SettingsPage from "./components/pages/SettingsPage";
|
||||
import DependenciesPage from "./components/pages/DependenciesPage";
|
||||
import AboutPage from "./components/pages/AboutPage";
|
||||
@@ -103,6 +104,7 @@ export function useI18nLang(): I18nContextValue {
|
||||
|
||||
// Tab 类型定义(对齐 Tauri 客户端)
|
||||
type TabKey =
|
||||
| "overview"
|
||||
| "client"
|
||||
| "sessions"
|
||||
| "legacySessions"
|
||||
@@ -336,7 +338,7 @@ function App() {
|
||||
// ============================================
|
||||
// 核心状态
|
||||
// ============================================
|
||||
const [activeTab, setActiveTab] = useState<TabKey>("client");
|
||||
const [activeTab, setActiveTab] = useState<TabKey>("overview");
|
||||
const [activeNavKey, setActiveNavKey] = useState<NavKey>("overview");
|
||||
const [sessionsAutoOpen, setSessionsAutoOpen] = useState(false);
|
||||
const [aiAgentLaunchContext, setAiAgentLaunchContext] =
|
||||
@@ -1039,7 +1041,7 @@ function App() {
|
||||
await logout();
|
||||
await handleAuthChange();
|
||||
setIsLoggedIn(false);
|
||||
setActiveTab("client");
|
||||
setActiveTab("overview");
|
||||
setActiveNavKey("overview");
|
||||
setServices([]);
|
||||
setServicesLoading(false);
|
||||
@@ -1057,7 +1059,7 @@ function App() {
|
||||
setActiveNavKey(key);
|
||||
|
||||
if (key === "overview") {
|
||||
setActiveTab("client");
|
||||
setActiveTab("overview");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1109,7 +1111,7 @@ function App() {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveTab("client");
|
||||
setActiveTab("overview");
|
||||
}, []);
|
||||
|
||||
const handleLegacySelect = useCallback((key: LegacyTabKey) => {
|
||||
@@ -1358,6 +1360,7 @@ function App() {
|
||||
<div
|
||||
className={
|
||||
webviewActions ||
|
||||
activeTab === "overview" ||
|
||||
activeTab === "document" ||
|
||||
activeTab === "dataFetch"
|
||||
? "app-content app-content-fullwidth"
|
||||
@@ -1373,6 +1376,7 @@ function App() {
|
||||
background: "var(--color-bg-layout)",
|
||||
}}
|
||||
>
|
||||
{activeTab === "overview" && <OverviewPage />}
|
||||
{activeTab === "client" && (
|
||||
<ClientPage
|
||||
onNavigate={(tab) => {
|
||||
|
||||
@@ -6,13 +6,16 @@ import styles from "../../styles/components/ConfiguredServicePage.module.css";
|
||||
interface ConfiguredServicePageProps {
|
||||
title: string;
|
||||
loadServiceUrl: () => Promise<string>;
|
||||
fitContentWidth?: number;
|
||||
}
|
||||
|
||||
function ConfiguredServicePage({
|
||||
title,
|
||||
loadServiceUrl,
|
||||
fitContentWidth,
|
||||
}: ConfiguredServicePageProps) {
|
||||
const webviewRef = useRef<HTMLElement | null>(null);
|
||||
const webviewReadyRef = useRef(false);
|
||||
const [serviceUrl, setServiceUrl] = useState<string | null>(null);
|
||||
const [loadingConfig, setLoadingConfig] = useState(true);
|
||||
const [loadingPage, setLoadingPage] = useState(false);
|
||||
@@ -37,14 +40,36 @@ function ConfiguredServicePage({
|
||||
void loadService();
|
||||
}, [loadService]);
|
||||
|
||||
const applyPageScale = useCallback(() => {
|
||||
if (!fitContentWidth || !webviewReadyRef.current) return;
|
||||
|
||||
const element = webviewRef.current as any;
|
||||
const availableWidth = element?.clientWidth;
|
||||
if (!availableWidth || typeof element?.setZoomFactor !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomFactor = Math.max(
|
||||
0.35,
|
||||
Math.min(1, availableWidth / fitContentWidth),
|
||||
);
|
||||
element.setZoomFactor(Number(zoomFactor.toFixed(3)));
|
||||
}, [fitContentWidth]);
|
||||
|
||||
useEffect(() => {
|
||||
const element = webviewRef.current as any;
|
||||
if (!element || !serviceUrl) return;
|
||||
|
||||
webviewReadyRef.current = false;
|
||||
|
||||
const handleStart = () => {
|
||||
setLoadingPage(true);
|
||||
setError(null);
|
||||
};
|
||||
const handleReady = () => {
|
||||
webviewReadyRef.current = true;
|
||||
applyPageScale();
|
||||
};
|
||||
const handleStop = () => setLoadingPage(false);
|
||||
const handleFailure = (event: any) => {
|
||||
if (event.errorCode !== -3) {
|
||||
@@ -56,14 +81,24 @@ function ConfiguredServicePage({
|
||||
};
|
||||
|
||||
element.addEventListener("did-start-loading", handleStart);
|
||||
element.addEventListener("dom-ready", handleReady);
|
||||
element.addEventListener("did-stop-loading", handleStop);
|
||||
element.addEventListener("did-fail-load", handleFailure);
|
||||
|
||||
const resizeObserver = fitContentWidth
|
||||
? new ResizeObserver(applyPageScale)
|
||||
: null;
|
||||
resizeObserver?.observe(element);
|
||||
|
||||
return () => {
|
||||
resizeObserver?.disconnect();
|
||||
webviewReadyRef.current = false;
|
||||
element.removeEventListener("did-start-loading", handleStart);
|
||||
element.removeEventListener("dom-ready", handleReady);
|
||||
element.removeEventListener("did-stop-loading", handleStop);
|
||||
element.removeEventListener("did-fail-load", handleFailure);
|
||||
};
|
||||
}, [serviceUrl, title]);
|
||||
}, [applyPageScale, fitContentWidth, serviceUrl, title]);
|
||||
|
||||
const handleReload = useCallback(() => {
|
||||
const element = webviewRef.current as any;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import { fetchOverviewServiceUrl } from "../../services/core/servicePages";
|
||||
import ConfiguredServicePage from "./ConfiguredServicePage";
|
||||
|
||||
function OverviewPage() {
|
||||
return (
|
||||
<ConfiguredServicePage
|
||||
title="概览"
|
||||
loadServiceUrl={fetchOverviewServiceUrl}
|
||||
fitContentWidth={1920}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default OverviewPage;
|
||||
@@ -7,12 +7,14 @@ import { getDomainTokenKey } from "@shared/utils/domain";
|
||||
import { normalizeServerHost } from "./auth";
|
||||
|
||||
const SUCCESS_CODE = "0000";
|
||||
const OVERVIEW_FALLBACK_URL = "http://127.0.0.1:5173/_app/digital";
|
||||
const INTELLIGENT_DATA_FALLBACK_URL = "http://192.168.2.106:3000/test-console";
|
||||
|
||||
interface TenantConfigResponse {
|
||||
code: string;
|
||||
message?: string;
|
||||
data?: {
|
||||
overviewServiceUrl?: string;
|
||||
intelligentDataServiceUrl?: string;
|
||||
documentEditorServiceUrl?: string;
|
||||
};
|
||||
@@ -77,6 +79,14 @@ async function fetchTenantConfig(): Promise<TenantConfigResponse["data"]> {
|
||||
return result.data;
|
||||
}
|
||||
|
||||
export async function fetchOverviewServiceUrl(): Promise<string> {
|
||||
const config = await fetchTenantConfig();
|
||||
return normalizeServiceUrl(
|
||||
config?.overviewServiceUrl || OVERVIEW_FALLBACK_URL,
|
||||
"概览",
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchIntelligentDataServiceUrl(): Promise<string> {
|
||||
const config = await fetchTenantConfig();
|
||||
return normalizeServiceUrl(
|
||||
|
||||
Reference in New Issue
Block a user