diff --git a/.env b/.env index 6df2eee..7ac608c 100644 --- a/.env +++ b/.env @@ -3,6 +3,6 @@ JWT_SECRET=gdyc-super-secrets-jjwtt-key-change-this-in-production-20250721-from-login-callback # 交叉评查专属模式 -# 设置为 true 时,端口51707只显示交叉评查入口,隐藏其他模块 -# 设置为 false 时,保持正常模式显示所有模块 +# 设置为 true 时,端口51707只显示交叉评查入口,隐藏其他模块(上线模式) +# 设置为 false 时,保持正常模式显示所有模块(测试/开发模式) CROSS_CHECKING_ONLY_MODE=true \ No newline at end of file diff --git a/app/components/cross-checking/ReviewPointsList.tsx b/app/components/cross-checking/ReviewPointsList.tsx index f21f4b3..1c59bed 100644 --- a/app/components/cross-checking/ReviewPointsList.tsx +++ b/app/components/cross-checking/ReviewPointsList.tsx @@ -2100,10 +2100,11 @@ export function ReviewPointsList({ value={suggestionValue.suggested_value || ''} readOnly disabled={!hasSuggestedValue} + rows={Math.min(Math.max(Math.ceil((suggestionValue.suggested_value || '').length / 30), 1), 5)} className={`flex-1 p-2 border rounded text-xs resize-none overflow-y-auto focus:outline-none ${ hasSuggestedValue - ? 'border-gray-200 bg-gray-50 text-gray-700 cursor-not-allowed' - : 'border-gray-200 bg-gray-100 text-gray-400 cursor-not-allowed' + ? 'border-gray-200 bg-gray-50 text-gray-700' + : 'border-gray-200 bg-gray-100 text-gray-400' }`} aria-label={`${key}的AI建议内容`} placeholder={!hasSuggestedValue ? '暂无建议值' : ''} diff --git a/app/components/layout/Sidebar.tsx b/app/components/layout/Sidebar.tsx index 5beb7b8..e8dc95d 100644 --- a/app/components/layout/Sidebar.tsx +++ b/app/components/layout/Sidebar.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; import { Link, useLocation, useNavigate } from '@remix-run/react'; import type { UserRole } from '~/root'; import { getUserRoutesByRole, mapUserRoleToRoleKey, type MenuItem } from '~/api/auth/user-routes'; -import { DOCUMENT_URL } from '~/config/api-config'; +import { DOCUMENT_URL, CROSS_CHECKING_ONLY_PORT, CROSS_CHECKING_ONLY_MODE } from '~/config/api-config'; interface SidebarProps { onToggle: () => void; @@ -95,6 +95,15 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '' }: Sid const [isSettingsMode, setIsSettingsMode] = useState(false); const [isCrossCheckingMode, setIsCrossCheckingMode] = useState(false); + // 🔒 检测当前端口,用于控制交叉评查入口的显示 + const [currentPort, setCurrentPort] = useState(''); + + useEffect(() => { + if (typeof window !== 'undefined') { + setCurrentPort(window.location.port || ''); + } + }, []); + // 从 sessionStorage 读取当前选中的模块名称和图片路径,以及各种模式标志 useEffect(() => { if (typeof window !== 'undefined') { @@ -200,6 +209,15 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '' }: Sid return false; } + // 🔒 交叉评查访问控制: + // - CROSS_CHECKING_ONLY_MODE=false 时,所有端口都可访问(根据后端权限) + // - CROSS_CHECKING_ONLY_MODE=true 时,只有 51707 端口可访问 + if (CROSS_CHECKING_ONLY_MODE && currentPort && currentPort !== CROSS_CHECKING_ONLY_PORT) { + if (item.path === '/cross-checking' || item.path?.startsWith('/cross-checking/')) { + return false; + } + } + // 🔑 重要:非交叉评查模式下,隐藏所有 /cross-checking 相关菜单 if (item.path === '/cross-checking' || item.path?.startsWith('/cross-checking/')) { return false; diff --git a/app/components/reviews/ReviewPointsList.tsx b/app/components/reviews/ReviewPointsList.tsx index f62fe32..cd9857c 100644 --- a/app/components/reviews/ReviewPointsList.tsx +++ b/app/components/reviews/ReviewPointsList.tsx @@ -1760,7 +1760,7 @@ export function ReviewPointsList({ {/* 字段名称标签 */}
- AI建议修改 - {key} + AI修改建议 - {key}
{/* 原因说明 */} @@ -1785,10 +1785,11 @@ export function ReviewPointsList({ value={suggestionValue.suggested_value || ''} readOnly disabled={!hasSuggestedValue} + rows={Math.min(Math.max(Math.ceil((suggestionValue.suggested_value || '').length / 30), 1), 5)} className={`flex-1 p-2 border rounded text-xs resize-none overflow-y-auto focus:outline-none ${ hasSuggestedValue - ? 'border-gray-200 bg-gray-50 text-gray-700 cursor-not-allowed' - : 'border-gray-200 bg-gray-100 text-gray-400 cursor-not-allowed' + ? 'border-gray-200 bg-gray-50 text-gray-700' + : 'border-gray-200 bg-gray-100 text-gray-400' }`} aria-label={`${key}的AI建议内容`} placeholder={!hasSuggestedValue ? '暂无建议值' : ''} diff --git a/app/components/reviews/previewComponents/PdfPreview.tsx b/app/components/reviews/previewComponents/PdfPreview.tsx index 527d76c..3bfbaf2 100644 --- a/app/components/reviews/previewComponents/PdfPreview.tsx +++ b/app/components/reviews/previewComponents/PdfPreview.tsx @@ -338,7 +338,7 @@ export function PdfPreview({ fill="#00AA00" fillOpacity="0.1" stroke="#00684a" - strokeWidth="1" + strokeWidth="0.5" rx="2" > {`高亮文本: ${highlight.text}`} diff --git a/app/config/api-config-b.ts b/app/config/api-config-wafIP.ts similarity index 57% rename from app/config/api-config-b.ts rename to app/config/api-config-wafIP.ts index a9f13ca..1103b3f 100644 --- a/app/config/api-config-b.ts +++ b/app/config/api-config-wafIP.ts @@ -5,24 +5,35 @@ */ // 环境配置类型 interface ApiConfig { - // 主API基础URL + // 主API基础URL(FastAPI后端地址,包含Dify代理) baseUrl: string; // 文档服务URL documentUrl: string; // 文档上传API URL uploadUrl: string; + // Collabora Online 服务器地址 + collaboraUrl: string; + // 应用基础URL(用于 WOPI 回调) + appUrl: string; // OAuth2.0配置 oauth: { // IDaaS服务器地址 - serverUrl: string; + serverUrl?: string; // OAuth2应用Client ID - clientId: string; + clientId?: string; // OAuth2应用Client Secret - clientSecret: string; + clientSecret?: string; // 回调地址 - redirectUri: string; + redirectUri?: string; // 应用ID(用于登出) - appId: string; + appId?: string; + }; + // Dify 知识库检索配置 + dify: { + // Reranking 模型提供商 + rerankingProviderName: string; + // Reranking 模型名称 + rerankingModelName: string; }; } @@ -30,154 +41,191 @@ interface ApiConfig { // 根据不同端口提供不同的API配置 const portConfigs: Record> = { - // 测试主要服务实例 - '5173': { - baseUrl: 'http://172.16.0.55:8000', - documentUrl: 'http://172.16.0.55:8000/docauditai/', - uploadUrl: 'http://172.16.0.55:8000/admin/documents' - }, - // 测试客户端实例 - '5174': { - baseUrl: 'http://172.16.0.55:5174', - documentUrl: 'http://172.16.0.55:5174/docauditai/', - uploadUrl: 'http://172.16.0.55:5174/admin/documents' - }, - // 测试客户端实例 - '5175': { - baseUrl: 'http://172.16.0.55:5175', - documentUrl: 'http://172.16.0.55:5175/docauditai/', - uploadUrl: 'http://172.16.0.55:5175/admin/documents' - }, - // 测试客户端实例 - '5176': { - baseUrl: 'http://172.16.0.55:5176', - documentUrl: 'http://172.16.0.55:5176/docauditai/', - uploadUrl: 'http://172.16.0.55:5176/admin/documents' - }, - // 测试客户端实例 - '5177': { - baseUrl: 'http://172.16.0.55:5177', - documentUrl: 'http://172.16.0.55:5177/docauditai/', - uploadUrl: 'http://172.16.0.55:5177/admin/documents' - }, - // 测试客户端实例 - '5178': { - baseUrl: 'http://172.16.0.55:8008', - documentUrl: 'http://172.16.0.55:8008/docauditai/', - uploadUrl: 'http://172.16.0.55:8008/admin/documents' - }, - - - // 主要 // 梅州 '51703': { - baseUrl: 'http://172.16.0.55:8073', - documentUrl: 'http://172.16.0.55:8073/docauditai/', - uploadUrl: 'http://172.16.0.55:8073/admin/documents' - // baseUrl: 'http://nas.7bm.co:8873', - // documentUrl: 'http://nas.7bm.co:8873/docauditai/', - // uploadUrl: 'http://nas.7bm.co:8873/admin/documents' + // baseUrl: 'http://172.16.0.56:8073', + // documentUrl: 'http://172.16.0.56:8073/docauditai/', + // uploadUrl: 'http://172.16.0.56:8073/api/v2/documents', + // collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://172.16.0.34:51703', + + baseUrl: 'http://10.79.96.233:8000', + documentUrl: 'http://10.79.96.233:8000/docauditai/', + uploadUrl: 'http://10.79.96.233:8000/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51703', + + oauth: { + redirectUri: 'http://10.79.96.233:51703/callback' + } }, - + // 云浮 '51704': { - baseUrl: 'http://10.79.97.17:8001', - documentUrl: 'http://10.79.97.17:8001/docauditai/', - uploadUrl: 'http://10.79.97.17:8001/admin/documents' + // baseUrl: 'http://172.16.0.55:8001', + // documentUrl: 'http://172.16.0.55:8001/docauditai/', + // uploadUrl: 'http://172.16.0.55:8001/api/v2/documents', + // collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://172.16.0.34:51704', + + baseUrl: 'http://10.79.96.233:8001', + documentUrl: 'http://10.79.96.233:8001/docauditai/', + uploadUrl: 'http://10.79.96.233:8001/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51704', + oauth: { + redirectUri: 'http://10.79.96.233:51704/callback' + } }, // 揭阳 '51705': { - baseUrl: 'http://10.79.97.17:8002', - documentUrl: 'http://10.79.97.17:8002/docauditai/', - uploadUrl: 'http://10.79.97.17:8002/admin/documents' + baseUrl: 'http://10.79.96.233:8002', + documentUrl: 'http://10.79.96.233:8002/docauditai/', + uploadUrl: 'http://10.79.96.233:8002/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51705', + oauth: { + redirectUri: 'http://10.79.96.233:51705/callback' + } }, // 潮州 '51706': { - baseUrl: 'http://10.79.97.17:8003', - documentUrl: 'http://10.79.97.17:8003/docauditai/', - uploadUrl: 'http://10.79.97.17:8003/admin/documents' + baseUrl: 'http://10.79.96.233:8003', + documentUrl: 'http://10.79.96.233:8003/docauditai/', + uploadUrl: 'http://10.79.96.233:8003/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51706', + oauth: { + redirectUri: 'http://10.79.96.233:51706/callback' + } }, + // 省局 '51707': { - baseUrl: 'http://10.79.97.17:8004', - documentUrl: 'http://10.79.97.17:8004/docauditai/', - uploadUrl: 'http://10.79.97.17:8004/admin/documents' + // baseUrl: 'http://172.16.0.55:8866', + // documentUrl: 'http://172.16.0.55:8866/docauditai/', + // uploadUrl: 'http://172.16.0.55:8866/api/v2/documents', + // collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://172.16.0.34:51707', + + // 正式环境 + baseUrl: 'http://10.79.96.233:8004', + documentUrl: 'http://10.79.96.233:8004/docauditai/', + uploadUrl: 'http://10.79.96.233:8004/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51707', + + oauth: { + redirectUri: 'http://10.79.96.233:51707/callback' + } }, + //test '51708': { - baseUrl: 'http://10.79.97.17:8005', - documentUrl: 'http://10.79.97.17:8005/docauditai/', - uploadUrl: 'http://10.79.97.17:8005/admin/documents' + baseUrl: 'http://10.79.96.233:8005', + documentUrl: 'http://10.79.96.233:8005/docauditai/', + uploadUrl: 'http://10.79.96.233:8005/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51708' }, }; // 不同环境的默认配置 -// 由于合同模板的上传,后续的的uploadUrl都不需要/upload,直接写/admin/documents,由程序自动添加/upload或/upload_contract_template +// 由于合同模板的上传,后续的的uploadUrl都不需要/upload,直接写/api/v2/documents,由程序自动添加/upload或/upload_contract_template const configs: Record = { // 开发环境 development: { - baseUrl: 'http://172.16.0.55:8000', - documentUrl: 'http://172.16.0.55:8000/docauditai/', - uploadUrl: 'http://172.16.0.55:8000/admin/documents', + // baseUrl: 'http://172.16.0.58:8073', // FastAPI后端(包含/dify代理) + // documentUrl: 'http://172.16.0.58:8073/docauditai/', + // uploadUrl: 'http://172.16.0.58:8073/api/v2/documents', + baseUrl: 'http://172.16.0.55:8073', // FastAPI后端(包含/dify代理) + documentUrl: 'http://172.16.0.55:8073/docauditai/', + uploadUrl: 'http://172.16.0.55:8073/api/v2/documents', + + collaboraUrl: 'http://172.16.0.81:9980', + appUrl: 'http://172.16.0.34:5173', + oauth: { serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: 'none', clientSecret: 'none', // 需要替换为实际的Client Secret - redirectUri: 'http://10.79.97.17/', // 回调地址 + redirectUri: 'http://10.79.96.233/', // 回调地址 appId: 'idaasoauth2' // 应用ID,用于登出 + }, + dify: { + rerankingProviderName: 'langgenius/tongyi/tongyi', + rerankingModelName: 'gte-rerank' } }, - + // 测试环境 testing: { - baseUrl: 'http://nas.7bm.co:8873', - documentUrl: 'http://nas.7bm.co:8873/docauditai/', - uploadUrl: 'http://nas.7bm.co:8873/admin/documents', + baseUrl: 'http://172.16.0.55:8073', // FastAPI后端(包含/dify代理) + documentUrl: 'http://172.16.0.55:8073/docauditai/', + uploadUrl: 'http://172.16.0.55:8073/api/v2/documents', + collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://10.79.96.233:51703', + appUrl: 'http://172.16.0.34:5183', oauth: { serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: '54d2a619fe5c81ae1250434c441fccccqMtKwh7H4fO', clientSecret: 'placeholder', // 需要替换为实际的Client Secret - redirectUri: 'http://10.79.97.17/', // 回调地址 + redirectUri: 'http://10.79.96.233/', // 回调地址 appId: 'idaasoauth2' // 应用ID,用于登出 + }, + dify: { + rerankingProviderName: 'langgenius/tongyi/tongyi', + rerankingModelName: 'gte-rerank' } }, - + // 生产环境 production: { - // postgrest - baseUrl: 'http://10.79.97.17:8000', + baseUrl: 'http://10.79.96.233:8000', // FastAPI后端(包含/dify代理) // minio documentUrl: 'http://10.76.244.156:9000/docauditai/', // 文件上传 - uploadUrl: 'http://10.79.97.17:8000/admin/documents', + uploadUrl: 'http://10.79.96.233:8000/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://10.79.96.233:51703', oauth: { - serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: '54d2a619fe5c81ae1250434c441fccccqMtKwh7H4fO', - // clientSecret: 'VYk1AC5XIJEfnEXwyq0u9JEY3fi3byCfSD58zANGeb', // 需要替换为实际的Client Secret + serverUrl: 'http://10.79.112.85', // IDaaS服务器地址(测试) + // serverUrl: 'http://10.79.97.252', // IDaaS服务器地址(生产) // ⚠️ 安全警告:clientSecret 不应该硬编码在代码中 // 请在生产环境使用环境变量 OAUTH_CLIENT_SECRET clientSecret: 'placeholder', // 占位符,实际值从环境变量获取 - redirectUri: 'http://10.79.97.17/', // 回调地址 + redirectUri: 'http://10.79.96.233/', // 回调地址 appId: 'idaasoauth2' // 应用ID,用于登出 + }, + dify: { + rerankingProviderName: 'langgenius/tongyi/tongyi', + rerankingModelName: 'gte-rerank' } }, - + // 备用配置 (可以根据需要添加更多环境) staging: { - baseUrl: 'http://172.16.0.119:9000/admin', + baseUrl: 'http://172.16.0.119:9000/admin', // FastAPI后端(包含/dify代理) documentUrl: 'http://nas.7bm.co:9000/docauditai/', - uploadUrl: 'http://172.16.0.119:8000/admin/documents/upload', + uploadUrl: 'http://172.16.0.119:8000/api/v2/documents', + collaboraUrl: 'http://10.79.96.233:9980', + appUrl: 'http://172.16.0.119:3000', oauth: { serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: 'none', // 需要替换为实际的Client ID clientSecret: 'your_client_secret', // 需要替换为实际的Client Secret redirectUri: 'http://172.16.0.119:3000/callback', // 回调地址 appId: 'idaasoauth2' // 应用ID,用于登出 + }, + dify: { + rerankingProviderName: 'langgenius/tongyi/tongyi', + rerankingModelName: 'gte-rerank' } } }; @@ -194,18 +242,18 @@ const getCurrentEnvironment = (): string => { }); return nodeEnv || 'development'; } - + // 客户端:优先使用NEXT_PUBLIC_前缀的环境变量 const nextPublicNodeEnv = process.env.NEXT_PUBLIC_NODE_ENV; const nodeEnv = process.env.NODE_ENV; const result = nextPublicNodeEnv || nodeEnv || 'development'; - + console.log('🔧 客户端环境检测:', { NEXT_PUBLIC_NODE_ENV: nextPublicNodeEnv, NODE_ENV: nodeEnv, result: result }); - + return result; }; @@ -215,6 +263,10 @@ const getConfigFromEnv = (defaultConfig: ApiConfig): ApiConfig => { baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL || defaultConfig.baseUrl, documentUrl: process.env.NEXT_PUBLIC_DOCUMENT_URL || defaultConfig.documentUrl, uploadUrl: process.env.NEXT_PUBLIC_UPLOAD_URL || defaultConfig.uploadUrl, + + collaboraUrl: defaultConfig.collaboraUrl || '', + appUrl: defaultConfig.appUrl || '', + oauth: { serverUrl: process.env.NEXT_PUBLIC_OAUTH_SERVER_URL || defaultConfig.oauth.serverUrl, clientId: process.env.NEXT_PUBLIC_OAUTH_CLIENT_ID || defaultConfig.oauth.clientId, @@ -223,7 +275,8 @@ const getConfigFromEnv = (defaultConfig: ApiConfig): ApiConfig => { clientSecret: process.env.OAUTH_CLIENT_SECRET || defaultConfig.oauth.clientSecret, redirectUri: process.env.NEXT_PUBLIC_OAUTH_REDIRECT_URI || defaultConfig.oauth.redirectUri, appId: process.env.NEXT_PUBLIC_OAUTH_APP_ID || defaultConfig.oauth.appId - } + }, + dify: defaultConfig.dify }; }; @@ -237,7 +290,7 @@ const getCurrentPort = (): string => { if (typeof window !== 'undefined') { windowPort = window.location.port || ''; } - + // 在服务器端,优先使用运行时端口检测 if (typeof window === 'undefined') { const runtimePort = getRuntimePort(); @@ -246,16 +299,16 @@ const getCurrentPort = (): string => { return runtimePort; } } - + // 优先使用环境变量中的端口配置 const nextPublicApiPortConfig = process.env.NEXT_PUBLIC_API_PORT_CONFIG; const nextPublicPort = process.env.NEXT_PUBLIC_PORT; const apiPortConfig = process.env.API_PORT_CONFIG; const portEnv = process.env.PORT; - + // 优先级:windowPort > NEXT_PUBLIC_API_PORT_CONFIG > NEXT_PUBLIC_PORT > API_PORT_CONFIG > PORT环境变量 const result = windowPort || nextPublicApiPortConfig || nextPublicPort || apiPortConfig || portEnv || ''; - + console.log('🔧 端口检测:', { windowPort: windowPort, NEXT_PUBLIC_API_PORT_CONFIG: nextPublicApiPortConfig, @@ -264,7 +317,7 @@ const getCurrentPort = (): string => { PORT: portEnv, result: result }); - + return result; }; @@ -276,7 +329,7 @@ const getRuntimePort = (): string => { if (typeof window !== 'undefined') { return ''; // 客户端不执行此逻辑 } - + // 尝试从进程参数中获取端口 const args = process.argv; for (let i = 0; i < args.length; i++) { @@ -287,7 +340,7 @@ const getRuntimePort = (): string => { return args[i].split('=')[1]; } } - + // 从环境变量获取 return process.env.PORT || ''; }; @@ -299,40 +352,44 @@ const getRuntimePort = (): string => { const getCurrentConfig = (): ApiConfig => { const env = getCurrentEnvironment(); const port = getCurrentPort(); - + console.log('🔧 配置调试信息:', { environment: env, port: port, hasPortConfig: !!(port && portConfigs[port]), portConfig: port ? portConfigs[port] : null }); - + // 获取基础配置 let defaultConfig = configs[env] || configs.development; - + // 如果有端口特定配置,则合并配置 if (port && portConfigs[port]) { - console.log(`🔧 使用端口特定配置: ${port}`, portConfigs[port]); + console.log(`🔧 使用端口特定配置: ${port}`); + const portConfig = portConfigs[port]; defaultConfig = { - ...defaultConfig, - ...portConfigs[port], - // 保持oauth配置不变,只覆盖API相关配置 - oauth: defaultConfig.oauth + ...defaultConfig, + ...portConfig, + // 如果端口配置中有oauth,需要深度合并oauth配置 + oauth: portConfig.oauth + ? { ...defaultConfig.oauth, ...portConfig.oauth } + : defaultConfig.oauth }; + console.log(`🔧 使用端口特定配置---深度合并后: ${JSON.stringify(defaultConfig.oauth)}`) } else { console.log(`🔧 使用环境配置: ${env}`, defaultConfig); } - + // 只有在明确设置了环境变量的情况下才覆盖配置 - const hasEnvOverrides = process.env.NEXT_PUBLIC_API_BASE_URL || - process.env.NEXT_PUBLIC_DOCUMENT_URL || - process.env.NEXT_PUBLIC_UPLOAD_URL; - + const hasEnvOverrides = process.env.NEXT_PUBLIC_API_BASE_URL || + process.env.NEXT_PUBLIC_DOCUMENT_URL || + process.env.NEXT_PUBLIC_UPLOAD_URL; + if (hasEnvOverrides) { console.log('🔧 检测到环境变量覆盖,使用环境变量配置'); return getConfigFromEnv(defaultConfig); } - + console.log('🔧 最终配置:', defaultConfig); return defaultConfig; }; @@ -343,9 +400,12 @@ export const apiConfig = getCurrentConfig(); // 导出具体的配置项,方便使用 export const { baseUrl: API_BASE_URL, - documentUrl: DOCUMENT_URL, + documentUrl: DOCUMENT_URL, uploadUrl: UPLOAD_URL, - oauth: OAUTH_CONFIG + collaboraUrl: COLLABORA_URL, + appUrl: APP_URL, + oauth: OAUTH_CONFIG, + dify: DIFY_CONFIG } = apiConfig; /** @@ -353,10 +413,10 @@ export const { * 可以安全地在客户端代码中使用 */ export const CLIENT_OAUTH_CONFIG = { - serverUrl: OAUTH_CONFIG.serverUrl, - clientId: OAUTH_CONFIG.clientId, - redirectUri: OAUTH_CONFIG.redirectUri, - appId: OAUTH_CONFIG.appId, + serverUrl: OAUTH_CONFIG.serverUrl as string, + clientId: OAUTH_CONFIG.clientId as string, + redirectUri: OAUTH_CONFIG.redirectUri as string, + appId: OAUTH_CONFIG.appId as string, // 客户端不需要 clientSecret }; @@ -396,4 +456,20 @@ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'testing' } }, }); -} \ No newline at end of file +} + +/** + * 交叉评查专属模式配置 + * 当为 true 且端口为 51707 时,首页只显示交叉评查入口 + */ +export const CROSS_CHECKING_ONLY_MODE = process.env.CROSS_CHECKING_ONLY_MODE === 'true'; + +/** + * 交叉评查专属模式的目标端口 + */ +export const CROSS_CHECKING_ONLY_PORT = '51707'; + +/** + * 获取当前端口(服务端使用) + */ +export { getCurrentPort }; \ No newline at end of file diff --git a/app/config/api-config.ts b/app/config/api-config.ts index 1a685ea..950ee8c 100644 --- a/app/config/api-config.ts +++ b/app/config/api-config.ts @@ -47,14 +47,12 @@ const portConfigs: Record> = { // baseUrl: 'http://172.16.0.56:8073', // documentUrl: 'http://172.16.0.56:8073/docauditai/', // uploadUrl: 'http://172.16.0.56:8073/api/v2/documents', - // collaboraUrl: 'http://172.16.0.81:9980', // appUrl: 'http://172.16.0.34:51703', baseUrl: 'http://10.79.97.17:8000', documentUrl: 'http://10.79.97.17:8000/docauditai/', uploadUrl: 'http://10.79.97.17:8000/api/v2/documents', - collaboraUrl: 'http://10.79.97.17:9980', appUrl: 'http://10.79.97.17:51703', @@ -66,17 +64,17 @@ const portConfigs: Record> = { // 云浮 '51704': { - baseUrl: 'http://172.16.0.55:8001', - documentUrl: 'http://172.16.0.55:8001/docauditai/', - uploadUrl: 'http://172.16.0.55:8001/api/v2/documents', - collaboraUrl: 'http://172.16.0.81:9980', - appUrl: 'http://172.16.0.34:51704', + // baseUrl: 'http://172.16.0.55:8001', + // documentUrl: 'http://172.16.0.55:8001/docauditai/', + // uploadUrl: 'http://172.16.0.55:8001/api/v2/documents', + // collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://172.16.0.34:51704', - // baseUrl: 'http://10.79.97.17:8001', - // documentUrl: 'http://10.79.97.17:8001/docauditai/', - // uploadUrl: 'http://10.79.97.17:8001/api/v2/documents', - // collaboraUrl: 'http://10.79.97.17:9980', - // appUrl: 'http://10.79.97.17:51704', + baseUrl: 'http://10.79.97.17:8001', + documentUrl: 'http://10.79.97.17:8001/docauditai/', + uploadUrl: 'http://10.79.97.17:8001/api/v2/documents', + collaboraUrl: 'http://10.79.97.17:9980', + appUrl: 'http://10.79.97.17:51704', oauth: { redirectUri: 'http://10.79.97.17:51704/callback' } @@ -109,11 +107,19 @@ const portConfigs: Record> = { // 省局 '51707': { + // baseUrl: 'http://172.16.0.55:8866', + // documentUrl: 'http://172.16.0.55:8866/docauditai/', + // uploadUrl: 'http://172.16.0.55:8866/api/v2/documents', + // collaboraUrl: 'http://172.16.0.81:9980', + // appUrl: 'http://172.16.0.34:51707', + + // 正式环境 baseUrl: 'http://10.79.97.17:8004', documentUrl: 'http://10.79.97.17:8004/docauditai/', uploadUrl: 'http://10.79.97.17:8004/api/v2/documents', collaboraUrl: 'http://10.79.97.17:9980', appUrl: 'http://10.79.97.17:51707', + oauth: { redirectUri: 'http://10.79.97.17:51707/callback' } diff --git a/app/root.tsx b/app/root.tsx index 0bce61d..d6d754b 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -313,6 +313,17 @@ export async function loader({ request }: LoaderFunctionArgs) { } } + // 🔒 交叉评查访问控制: + // - CROSS_CHECKING_ONLY_MODE=false 时,所有端口都可访问(根据后端权限) + // - CROSS_CHECKING_ONLY_MODE=true 时,只有 51707 端口可访问 + if (CROSS_CHECKING_ONLY_MODE && !isPublicPath && currentPort !== CROSS_CHECKING_ONLY_PORT) { + const isCrossCheckingPath = pathname === '/cross-checking' || pathname.startsWith('/cross-checking/'); + if (isCrossCheckingPath) { + console.warn(`⚠️ [Root Loader] CROSS_CHECKING_ONLY_MODE启用,非51707端口禁止访问交叉评查:端口=${currentPort},路径=${pathname}`); + throw new Response("当前端口无权访问交叉评查功能", { status: 403 }); + } + } + // 向组件传递路径信息 return Response.json({ userRole, // ✅ 返回真实的用户角色 diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index ebaf81e..330015c 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -75,7 +75,15 @@ export async function loader({ request }: LoaderFunctionArgs) { } // 检查是否存在顶级路由 '/cross-checking' - hasCrossCheckingAccess = routesResult.data.some(route => route.path === '/cross-checking'); + // 🔒 交叉评查访问控制: + // - CROSS_CHECKING_ONLY_MODE=false 时,所有端口都可访问(根据后端权限) + // - CROSS_CHECKING_ONLY_MODE=true 时,只有 51707 端口可访问 + const currentPort = getCurrentPort(); + if (!CROSS_CHECKING_ONLY_MODE || currentPort === CROSS_CHECKING_ONLY_PORT) { + hasCrossCheckingAccess = routesResult.data.some(route => route.path === '/cross-checking'); + } else { + hasCrossCheckingAccess = false; // CROSS_CHECKING_ONLY_MODE=true 且非51707端口不显示交叉评查入口 + } // 检查是否存在顶级路由 '/chat-with-llm' hasChatLLMAccess = routesResult.data.some(route => route.path === '/chat-with-llm'); @@ -89,11 +97,12 @@ export async function loader({ request }: LoaderFunctionArgs) { // 🔑 判断是否启用交叉评查专属模式 // 条件:CROSS_CHECKING_ONLY_MODE=true 且 当前端口为 51707 - const currentPort = getCurrentPort(); - const isCrossCheckingOnlyMode = CROSS_CHECKING_ONLY_MODE && currentPort === CROSS_CHECKING_ONLY_PORT; + // 注意:currentPort 已在上面的权限检查中获取,这里复用(如果在 if 块外需要则重新获取) + const currentPortForMode = getCurrentPort(); + const isCrossCheckingOnlyMode = CROSS_CHECKING_ONLY_MODE && currentPortForMode === CROSS_CHECKING_ONLY_PORT; if (isCrossCheckingOnlyMode) { - console.log(`🔒 [Index Loader] 交叉评查专属模式已启用 (端口: ${currentPort})`); + console.log(`🔒 [Index Loader] 交叉评查专属模式已启用 (端口: ${currentPortForMode})`); } // 返回用户信息、入口模块和权限给客户端 diff --git a/app/routes/files.upload.tsx b/app/routes/files.upload.tsx index fe7c12f..62dfa20 100644 --- a/app/routes/files.upload.tsx +++ b/app/routes/files.upload.tsx @@ -253,20 +253,42 @@ type LoaderData = { // 添加 loader 函数 export async function loader({ request }: LoaderFunctionArgs) { try { + const loaderStart = Date.now(); + // 获取用户会话信息 + const sessionStart = Date.now(); const { getUserSession } = await import("~/api/login/auth.server"); const { userInfo, frontendJWT } = await getUserSession(request); - + // console.log(`[loader 耗时] getUserSession: ${Date.now() - sessionStart}ms`); + // console.log('loader: 开始加载数据...'); const url = new URL(request.url); const mode = url.searchParams.get("mode") || "create"; - + // 我们不能在服务器端访问 sessionStorage,所以在客户端组件中处理 documentTypeIds 过滤 - // 并行加载文档和文档类型 + // 并行加载文档和文档类型(分别计时) + const apiStart = Date.now(); + + const documentsPromise = (async () => { + const start = Date.now(); + const result = await getTodayDocuments(userInfo, frontendJWT); + // console.log(`[loader 耗时] getTodayDocuments API: ${Date.now() - start}ms`); + return result; + })(); + + const typesPromise = (async () => { + const start = Date.now(); + const result = await getDocumentTypes(frontendJWT); + // console.log(`[loader 耗时] getDocumentTypes API: ${Date.now() - start}ms`); + return result; + })(); + const [documentsResponse, typesResponse] = await Promise.all([ - getTodayDocuments(userInfo, frontendJWT), - getDocumentTypes(frontendJWT) + documentsPromise, + typesPromise ]); + // console.log(`[loader 耗时] 并行API调用总耗时: ${Date.now() - apiStart}ms`); + console.log(`[loader 耗时] loader总耗时: ${(Date.now() - loaderStart)/1000}s`); // console.log('loader: 文档加载结果:', documentsResponse); // console.log('loader: 文档类型加载结果:', typesResponse);