1. 开启交叉评查的显示/隐藏(开启生产环境的配置),优化不同端口的显示/隐藏交叉评查入口的效果。

2. 优化评查结果的AI建议修改的文本输入框的显示效果。
3. 提交17正式环境的api-config.ts,备份一个wafIP的配置api-config-wafIP.ts。
This commit is contained in:
2025-12-16 17:47:15 +08:00
parent d2346aad70
commit d04882bf51
10 changed files with 293 additions and 149 deletions
+2 -2
View File
@@ -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
@@ -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 ? '暂无建议值' : ''}
+19 -1
View File
@@ -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<boolean>(false);
const [isCrossCheckingMode, setIsCrossCheckingMode] = useState<boolean>(false);
// 🔒 检测当前端口,用于控制交叉评查入口的显示
const [currentPort, setCurrentPort] = useState<string>('');
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;
+4 -3
View File
@@ -1760,7 +1760,7 @@ export function ReviewPointsList({
{/* 字段名称标签 */}
<div className="text-xs text-gray-600 mb-2 font-medium">
<i className="ri-lightbulb-line text-yellow-500 mr-1"></i>
AI建议修改 - {key}
AI修改建议 - {key}
</div>
{/* 原因说明 */}
@@ -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 ? '暂无建议值' : ''}
@@ -338,7 +338,7 @@ export function PdfPreview({
fill="#00AA00"
fillOpacity="0.1"
stroke="#00684a"
strokeWidth="1"
strokeWidth="0.5"
rx="2"
>
<title>{`高亮文本: ${highlight.text}`}</title>
@@ -5,24 +5,35 @@
*/
// 环境配置类型
interface ApiConfig {
// 主API基础URL
// 主API基础URLFastAPI后端地址,包含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<string, Partial<ApiConfig>> = {
// 测试主要服务实例
'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<string, ApiConfig> = {
// 开发环境
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'
}
},
});
}
}
/**
*
* true 51707
*/
export const CROSS_CHECKING_ONLY_MODE = process.env.CROSS_CHECKING_ONLY_MODE === 'true';
/**
*
*/
export const CROSS_CHECKING_ONLY_PORT = '51707';
/**
* 使
*/
export { getCurrentPort };
+18 -12
View File
@@ -47,14 +47,12 @@ const portConfigs: Record<string, Partial<ApiConfig>> = {
// 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<string, Partial<ApiConfig>> = {
// 云浮
'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<string, Partial<ApiConfig>> = {
// 省局
'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'
}
+11
View File
@@ -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, // ✅ 返回真实的用户角色
+13 -4
View File
@@ -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})`);
}
// 返回用户信息、入口模块和权限给客户端
+27 -5
View File
@@ -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);