新功能: - 创建AI聊天助手组件(AIChatWidget) - 支持文字+图片多模态对话 - 集成Gemini AI API - 支持图片编辑和内容生成 - 实时对话历史管理 - 优雅的UI设计,支持黑夜模式 技术实现: - 后端API代理Gemini API(/api/ai-chat) - 支持最多5张图片上传 - 流式响应处理 - 对话历史管理 - Base64图片处理 配置: - 在.env中添加Gemini API配置 - GEMINI_API_KEY - GEMINI_API_BASE_URL - GEMINI_MODEL 替换原弹幕功能,提供更强大的AI助手体验!
404 lines
16 KiB
HTML
Executable File
404 lines
16 KiB
HTML
Executable File
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>AI思维导图 - 由壹点AIGC</title>
|
||
<link rel="icon" href="https://s1.imagehub.cc/images/2025/02/24/f2135789cfaa56e2360f027673b35f2d.png" type="image/png">
|
||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
<link rel="stylesheet" href="/css/fix-black-bars.css">
|
||
<link rel="stylesheet" href="/css/sidebar.css">
|
||
|
||
<!-- 加载导航栏版本管理脚本 -->
|
||
<script src="/js/navbar-version.js"></script>
|
||
|
||
<!-- 检查登录状态 -->
|
||
<script>
|
||
// 页面加载时检查用户是否已登录
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
checkAuth();
|
||
});
|
||
|
||
// 检查用户是否已登录
|
||
async function checkAuth() {
|
||
try {
|
||
// 从localStorage获取登录状态和用户信息
|
||
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
|
||
const username = localStorage.getItem('username');
|
||
|
||
console.log('登录状态检查:', { isLoggedIn, username });
|
||
|
||
// 如果未登录,重定向到登录页面
|
||
if (!isLoggedIn || !username) {
|
||
console.log('未找到登录信息,重定向到登录页面');
|
||
window.location.href = '/login.html?redirect=' + encodeURIComponent(window.location.pathname);
|
||
return;
|
||
}
|
||
|
||
// 验证token有效性
|
||
try {
|
||
const response = await fetch('/api/auth/check', {
|
||
method: 'GET',
|
||
credentials: 'include' // 包含cookies
|
||
});
|
||
|
||
if (!response.ok) {
|
||
// Token无效,清除本地存储并重定向到登录页面
|
||
localStorage.removeItem('isLoggedIn');
|
||
localStorage.removeItem('username');
|
||
localStorage.removeItem('userRole');
|
||
window.location.href = '/login.html?redirect=' + encodeURIComponent(window.location.pathname);
|
||
return;
|
||
}
|
||
|
||
const data = await response.json();
|
||
if (!data.authenticated) {
|
||
// 未通过身份验证,重定向到登录页面
|
||
localStorage.removeItem('isLoggedIn');
|
||
localStorage.removeItem('username');
|
||
localStorage.removeItem('userRole');
|
||
window.location.href = '/login.html?redirect=' + encodeURIComponent(window.location.pathname);
|
||
}
|
||
} catch (error) {
|
||
console.error('验证token时出错:', error);
|
||
// 发生错误时尝试继续,依赖本地存储的状态
|
||
}
|
||
} catch (error) {
|
||
console.error('检查登录状态时出错:', error);
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
body, html {
|
||
margin: 0;
|
||
padding: 0;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
background-color: #1e1e1e; /* 深色背景 */
|
||
}
|
||
|
||
.iframe-container {
|
||
position: absolute;
|
||
top: 64px;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
iframe {
|
||
width: 100%;
|
||
height: 100%;
|
||
border: none;
|
||
opacity: 0;
|
||
transition: opacity 0.5s ease;
|
||
}
|
||
|
||
iframe.loaded {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* 加载动画容器 */
|
||
.loading-container {
|
||
position: absolute;
|
||
top: 64px;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: #1e1e1e;
|
||
color: #ffffff;
|
||
z-index: 100;
|
||
transition: opacity 0.5s ease;
|
||
}
|
||
|
||
.loading-container.hidden {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 加载标题 */
|
||
.loading-title {
|
||
font-size: 24px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 加载进度条 */
|
||
.loading-progress {
|
||
width: 300px;
|
||
height: 4px;
|
||
background-color: #333333;
|
||
border-radius: 2px;
|
||
margin-bottom: 20px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.loading-progress-bar {
|
||
height: 100%;
|
||
width: 0%;
|
||
background-color: #8c61ff;
|
||
border-radius: 2px;
|
||
transition: width 0.3s ease;
|
||
animation: progress-animation 1.5s infinite ease-in-out;
|
||
}
|
||
|
||
/* 进度条动画 */
|
||
@keyframes progress-animation {
|
||
0% {
|
||
width: 0%;
|
||
margin-left: 0;
|
||
}
|
||
50% {
|
||
width: 70%;
|
||
margin-left: 0;
|
||
}
|
||
70% {
|
||
width: 70%;
|
||
margin-left: 30%;
|
||
}
|
||
100% {
|
||
width: 0%;
|
||
margin-left: 100%;
|
||
}
|
||
}
|
||
|
||
/* 加载提示文本 */
|
||
.loading-text {
|
||
font-size: 16px;
|
||
color: #aaaaaa;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- 导入公共导航栏 -->
|
||
<div id="navbar-container"></div>
|
||
|
||
<!-- 添加加载动画 -->
|
||
<div class="loading-container" id="loading-container">
|
||
<div class="loading-title">思维导图加载中</div>
|
||
<div class="loading-progress">
|
||
<div class="loading-progress-bar" id="loading-progress-bar"></div>
|
||
</div>
|
||
<div class="loading-text">正在准备您的思维导图,请稍候...</div>
|
||
</div>
|
||
|
||
<div class="iframe-container">
|
||
<iframe src="/mind-map-main/index.html" id="mindmap-frame" allow="fullscreen"></iframe>
|
||
</div>
|
||
|
||
<script>
|
||
// 加载公共导航栏
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
fetch('/navbar-fragment.html')
|
||
.then(response => response.text())
|
||
.then(data => {
|
||
document.getElementById('navbar-container').innerHTML = data;
|
||
|
||
// 导航栏加载完成后,重新执行版本管理脚本
|
||
if (typeof getSystemVersion === 'function') {
|
||
setTimeout(() => {
|
||
getSystemVersion();
|
||
}, 100);
|
||
}
|
||
|
||
// 动态加载navbar-version.js脚本
|
||
const navbarScript = document.createElement('script');
|
||
navbarScript.src = '/js/navbar-version.js';
|
||
navbarScript.onload = function() {
|
||
// 脚本加载完成后,如果定义了getSystemVersion函数则调用
|
||
if (typeof getSystemVersion === 'function') {
|
||
getSystemVersion();
|
||
}
|
||
};
|
||
document.body.appendChild(navbarScript);
|
||
})
|
||
.catch(error => {
|
||
console.error('加载导航栏失败:', error);
|
||
});
|
||
|
||
// 隐藏AI按钮的函数
|
||
function hideAIButton() {
|
||
try {
|
||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||
|
||
// 1. 创建并注入CSS样式
|
||
if (!iframeDoc.getElementById('hide-ai-button-style')) {
|
||
const styleElement = iframeDoc.createElement('style');
|
||
styleElement.id = 'hide-ai-button-style';
|
||
styleElement.textContent = `
|
||
/* 隐藏所有可能的AI按钮 */
|
||
[data-command="AI"],
|
||
.bts-item[title="AI"],
|
||
div[data-type="ai"],
|
||
.toolbar-item[title="AI"],
|
||
.toolbar div[data-command="AI"],
|
||
.btnlist-item[data-command="AI"],
|
||
.btn-item[data-command="AI"],
|
||
svg[data-icon="robot"],
|
||
svg[data-type="robot"] {
|
||
display: none !important;
|
||
visibility: hidden !important;
|
||
opacity: 0 !important;
|
||
pointer-events: none !important;
|
||
width: 0 !important;
|
||
height: 0 !important;
|
||
position: absolute !important;
|
||
left: -9999px !important;
|
||
}
|
||
`;
|
||
iframeDoc.head.appendChild(styleElement);
|
||
console.log('已注入CSS样式');
|
||
}
|
||
|
||
// 2. 直接查找和隐藏AI按钮
|
||
const aiButtons = Array.from(iframeDoc.querySelectorAll('*')).filter(el => {
|
||
// 检查各种可能的属性和内容
|
||
const hasAIText = el.innerText === 'AI' || el.textContent === 'AI';
|
||
const hasAITitle = el.title === 'AI';
|
||
const hasAIDataAttr = el.dataset && (el.dataset.command === 'AI' || el.dataset.type === 'ai');
|
||
const isIconWithAIParent = el.tagName === 'svg' && el.parentElement &&
|
||
(el.parentElement.title === 'AI' || el.parentElement.dataset && el.parentElement.dataset.command === 'AI');
|
||
|
||
return hasAIText || hasAITitle || hasAIDataAttr || isIconWithAIParent;
|
||
});
|
||
|
||
aiButtons.forEach(btn => {
|
||
btn.style.display = 'none';
|
||
btn.style.visibility = 'hidden';
|
||
btn.style.opacity = '0';
|
||
btn.style.pointerEvents = 'none';
|
||
console.log('直接隐藏了AI按钮:', btn);
|
||
});
|
||
|
||
// 3. 尝试查找右侧工具栏并处理
|
||
const toolbars = iframeDoc.querySelectorAll('.mind-map .toolbar, .bts-container, .btnlist, .bx--toolbar');
|
||
toolbars.forEach(toolbar => {
|
||
// 查找第7个子元素(基于图片所示的位置)
|
||
const allItems = Array.from(toolbar.children);
|
||
if (allItems.length >= 7) {
|
||
// 从第6个位置(索引5)开始查找,可能会有偏差
|
||
for (let i = 5; i < Math.min(allItems.length, 8); i++) {
|
||
const item = allItems[i];
|
||
if (item && (item.title === 'AI' || item.innerText === 'AI' || item.textContent === 'AI')) {
|
||
item.style.display = 'none';
|
||
console.log('已隐藏工具栏中的AI按钮:', item);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('隐藏AI按钮时出错:', error);
|
||
}
|
||
}
|
||
|
||
// 立即执行一次
|
||
hideAIButton();
|
||
|
||
// 设置MutationObserver监听DOM变化
|
||
try {
|
||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||
const observer = new MutationObserver(() => {
|
||
hideAIButton();
|
||
});
|
||
observer.observe(iframeDoc.body, {
|
||
childList: true,
|
||
subtree: true,
|
||
attributes: true,
|
||
attributeFilter: ['class', 'style', 'data-command']
|
||
});
|
||
console.log('已设置MutationObserver监听');
|
||
} catch (error) {
|
||
console.error('设置MutationObserver失败:', error);
|
||
}
|
||
|
||
// 额外定期检查几次,确保晚加载的内容也被处理
|
||
const checkIntervals = [500, 1000, 2000, 3000, 5000];
|
||
checkIntervals.forEach(interval => {
|
||
setTimeout(hideAIButton, interval);
|
||
});
|
||
|
||
// 处理iframe加载
|
||
const iframe = document.getElementById('mindmap-frame');
|
||
const loadingContainer = document.getElementById('loading-container');
|
||
|
||
// 模拟加载进度增加
|
||
let loadTime = 0;
|
||
const loadingInterval = setInterval(() => {
|
||
loadTime += 1;
|
||
// 8秒后如果还没加载完,强制显示
|
||
if (loadTime >= 8) {
|
||
clearInterval(loadingInterval);
|
||
loadingContainer.classList.add('hidden');
|
||
iframe.classList.add('loaded');
|
||
}
|
||
}, 1000);
|
||
|
||
// iframe加载成功
|
||
iframe.onload = function() {
|
||
console.log('思维导图加载成功');
|
||
clearInterval(loadingInterval);
|
||
|
||
// 添加CSS隐藏AI按钮
|
||
try {
|
||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||
const styleElement = iframeDoc.createElement('style');
|
||
styleElement.textContent = `
|
||
/* 隐藏所有可能的AI按钮 */
|
||
[data-command="AI"],
|
||
.bts-item[title="AI"],
|
||
div[data-type="ai"],
|
||
.toolbar-item[title="AI"],
|
||
.toolbar div[data-command="AI"],
|
||
.btnlist-item[data-command="AI"],
|
||
.btn-item[data-command="AI"],
|
||
svg[data-icon="robot"],
|
||
svg[data-type="robot"] {
|
||
display: none !important;
|
||
visibility: hidden !important;
|
||
opacity: 0 !important;
|
||
pointer-events: none !important;
|
||
width: 0 !important;
|
||
height: 0 !important;
|
||
position: absolute !important;
|
||
left: -9999px !important;
|
||
}
|
||
`;
|
||
iframeDoc.head.appendChild(styleElement);
|
||
console.log('已隐藏AI按钮');
|
||
} catch (error) {
|
||
console.error('注入CSS隐藏AI按钮失败:', error);
|
||
}
|
||
|
||
// 添加短暂延迟,确保思维导图已经渲染
|
||
setTimeout(() => {
|
||
loadingContainer.classList.add('hidden');
|
||
iframe.classList.add('loaded');
|
||
}, 500);
|
||
};
|
||
|
||
// iframe加载失败
|
||
iframe.onerror = function() {
|
||
console.error('思维导图加载失败');
|
||
clearInterval(loadingInterval);
|
||
// 显示错误信息
|
||
loadingContainer.innerHTML = `
|
||
<div class="alert alert-danger m-4" role="alert">
|
||
<h4 class="alert-heading">无法加载思维导图</h4>
|
||
<p>思维导图功能暂时不可用,请稍后再试。</p>
|
||
<hr>
|
||
<p class="mb-0">
|
||
<button class="btn btn-outline-danger" onclick="location.reload()">重试</button>
|
||
<a href="/" class="btn btn-outline-secondary ms-2">返回首页</a>
|
||
</p>
|
||
</div>
|
||
`;
|
||
};
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |