## 主要变更 ### 1. Dify 机器人优化 **文件**: public/index.html - ✅ 恢复 Dify 机器人代码 - ✅ 添加显示控制逻辑:只在 /home 页面显示 - ✅ 使用 JavaScript 监听路由变化,动态控制显示/隐藏 - ✅ 保留所有样式配置 ### 2. Bytedesk 客服系统集成 **文件**: src/bytedesk-integration/config/bytedesk.config.js - ✅ 配置开发环境使用代理路径(/bytedesk-api) - ✅ 修复 X-Frame-Options 跨域问题 - ✅ 优化 shouldShowCustomerService 逻辑:默认所有页面显示,只在 /login 隐藏 - ✅ 保留白名单模式代码作为备用方案 **文件**: src/components/GlobalComponents.js - ✅ 集成 BytedeskWidget 组件 - ✅ 使用 shouldShowCustomerService 控制显示 ### 3. 客服显示规则 **Dify 机器人**: - ✅ /home 页面 → 显示 - ❌ 其他页面 → 隐藏 **Bytedesk 客服**: - ✅ 所有页面 → 显示 - ❌ /login 页面 → 隐藏 ## 已知问题 - ⚠️ Bytedesk 服务器配置 enabled: false,需要后端修改为 true - ⚠️ 配置接口: /config/bytedesk/properties ## 测试建议 1. 访问 /home 页面,检查 Dify 机器人是否显示 2. 访问其他页面,检查 Dify 是否隐藏 3. 等待后端修改 enabled 后,测试 Bytedesk 客服功能 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
110 lines
3.7 KiB
JavaScript
110 lines
3.7 KiB
JavaScript
// src/components/GlobalComponents.js
|
|
// 集中管理应用的全局组件
|
|
|
|
import React from 'react';
|
|
import { useLocation } from 'react-router-dom';
|
|
import { useNotification } from '../contexts/NotificationContext';
|
|
import { logger } from '../utils/logger';
|
|
|
|
// Global Components
|
|
import AuthModalManager from './Auth/AuthModalManager';
|
|
import NotificationContainer from './NotificationContainer';
|
|
import NotificationTestTool from './NotificationTestTool';
|
|
import ConnectionStatusBar from './ConnectionStatusBar';
|
|
import ScrollToTop from './ScrollToTop';
|
|
|
|
// Bytedesk客服组件
|
|
import BytedeskWidget from '../bytedesk-integration/components/BytedeskWidget';
|
|
import { getBytedeskConfig, shouldShowCustomerService } from '../bytedesk-integration/config/bytedesk.config';
|
|
|
|
/**
|
|
* ConnectionStatusBar 包装组件
|
|
* 需要在 NotificationProvider 内部使用,所以在这里包装
|
|
*/
|
|
function ConnectionStatusBarWrapper() {
|
|
const { connectionStatus, reconnectAttempt, maxReconnectAttempts, retryConnection } = useNotification();
|
|
const [isDismissed, setIsDismissed] = React.useState(false);
|
|
|
|
// 监听连接状态变化
|
|
React.useEffect(() => {
|
|
// 重连成功后,清除 dismissed 状态
|
|
if (connectionStatus === 'connected' && isDismissed) {
|
|
setIsDismissed(false);
|
|
// 从 localStorage 清除 dismissed 标记
|
|
localStorage.removeItem('connection_status_dismissed');
|
|
}
|
|
|
|
// 从 localStorage 恢复 dismissed 状态
|
|
if (connectionStatus !== 'connected' && !isDismissed) {
|
|
const dismissed = localStorage.getItem('connection_status_dismissed');
|
|
if (dismissed === 'true') {
|
|
setIsDismissed(true);
|
|
}
|
|
}
|
|
}, [connectionStatus, isDismissed]);
|
|
|
|
const handleClose = () => {
|
|
// 用户手动关闭,保存到 localStorage
|
|
setIsDismissed(true);
|
|
localStorage.setItem('connection_status_dismissed', 'true');
|
|
logger.info('App', 'Connection status bar dismissed by user');
|
|
};
|
|
|
|
return (
|
|
<ConnectionStatusBar
|
|
status={connectionStatus}
|
|
reconnectAttempt={reconnectAttempt}
|
|
maxReconnectAttempts={maxReconnectAttempts}
|
|
onRetry={retryConnection}
|
|
onClose={handleClose}
|
|
isDismissed={isDismissed}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* GlobalComponents - 全局组件容器
|
|
* 集中管理所有全局级别的组件,如弹窗、通知、状态栏等
|
|
*
|
|
* 包含的组件:
|
|
* - ConnectionStatusBarWrapper: Socket 连接状态条
|
|
* - ScrollToTop: 路由切换时自动滚动到顶部
|
|
* - AuthModalManager: 认证弹窗管理器
|
|
* - NotificationContainer: 通知容器
|
|
* - NotificationTestTool: 通知测试工具 (仅开发环境)
|
|
* - BytedeskWidget: Bytedesk在线客服 (条件性显示,在/和/home页隐藏)
|
|
*/
|
|
export function GlobalComponents() {
|
|
const location = useLocation();
|
|
const showBytedesk = shouldShowCustomerService(location.pathname);
|
|
|
|
return (
|
|
<>
|
|
{/* Socket 连接状态条 */}
|
|
<ConnectionStatusBarWrapper />
|
|
|
|
{/* 路由切换时自动滚动到顶部 */}
|
|
<ScrollToTop />
|
|
|
|
{/* 认证弹窗管理器 */}
|
|
<AuthModalManager />
|
|
|
|
{/* 通知容器 */}
|
|
<NotificationContainer />
|
|
|
|
{/* 通知测试工具 (仅开发环境) */}
|
|
<NotificationTestTool />
|
|
|
|
{/* Bytedesk在线客服 - 根据路径条件性显示 */}
|
|
{showBytedesk && (
|
|
<BytedeskWidget
|
|
config={getBytedeskConfig()}
|
|
autoLoad={true}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default GlobalComponents;
|