Files
yudao-ui-admin-vue3/AIRBT.html

148 lines
9.5 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 决策通</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.ai-drawer { transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1); transform: translateX(110%); }
.ai-drawer.active { transform: translateX(0); }
.ai-drawer.fullscreen { width: 85vw !important; height: 80vh !important; right: 7.5vw !important; top: 10vh !important; border-radius: 1.5rem !important; transform: translateX(0); }
.typing::after { content: '|'; animation: blink 1s infinite; margin-left: 2px; color: #3B82F6; }
@keyframes blink { 50% { opacity: 0; } }
.custom-scroll::-webkit-scrollbar { width: 5px; }
.custom-scroll::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
#overlay { display: none; position: fixed; inset: 0; background: rgba(15, 23, 42, 0.4); backdrop-filter: blur(4px); z-index: 55; }
#overlay.active { display: block; }
#fileInput, #imageInput { display: none; }
</style>
</head>
<body class="bg-[#F1F5F9]">
<div id="overlay" onclick="closeAI()"></div>
<div class="fixed bottom-[85px] right-6 z-50" id="aiFab">
<button onclick="openAI()" class="flex items-center gap-2 bg-white border border-blue-100 px-5 py-3 rounded-full shadow-2xl hover:scale-105 transition-all group">
<div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white shadow-lg shadow-blue-200">
<i class="fas fa-robot text-sm"></i>
</div>
<span class="text-blue-600 font-bold text-sm tracking-wide">AI 决策助手</span>
</button>
</div>
<div id="aiPanel" class="fixed top-0 right-0 h-full w-[420px] bg-white shadow-2xl z-[60] ai-drawer flex flex-col overflow-hidden border-l border-slate-100">
<div class="px-6 py-4 border-b flex items-center justify-between bg-white shrink-0">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center text-white shadow-md shadow-blue-100">
<i class="fas fa-robot text-lg"></i>
</div>
<div>
<h3 class="font-bold text-slate-800 text-sm">AI 决策助手</h3>
</div>
</div>
<div class="flex items-center gap-1">
<button onclick="toggleFullscreen()" class="w-9 h-9 rounded-lg hover:bg-slate-100 flex items-center justify-center text-slate-500">
<i class="fas fa-expand-alt" id="expandIcon"></i>
</button>
<button onclick="closeAI()" class="w-9 h-9 rounded-lg hover:bg-red-50 flex items-center justify-center text-slate-400 hover:text-red-500">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<div id="chatBox" class="flex-1 overflow-y-auto p-6 space-y-6 bg-[#FBFCFE] custom-scroll">
<div class="flex gap-4 items-start">
<div class="w-8 h-8 bg-blue-50 text-blue-600 rounded-lg flex items-center justify-center shrink-0 mt-1 border border-blue-100">
<i class="fas fa-robot text-xs"></i>
</div>
<div class="bg-white border border-slate-200 p-4 rounded-2xl rounded-tl-none shadow-sm text-sm text-slate-700">
您好!请发送数据或输入指令。
</div>
</div>
</div>
<div class="p-4 bg-white border-t border-slate-100 shrink-0">
<div class="max-w-4xl mx-auto flex flex-col">
<div class="flex gap-1 mb-2">
<input type="file" id="fileInput" accept=".xls,.xlsx,.csv" onchange="handleFileUpload(event, 'excel')">
<input type="file" id="imageInput" accept="image/*" onchange="handleFileUpload(event, 'image')">
<button onclick="triggerInput('image')" class="w-8 h-8 flex items-center justify-center text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-all">
<i class="fas fa-image"></i>
</button>
<button onclick="triggerInput('excel')" class="w-8 h-8 flex items-center justify-center text-slate-400 hover:text-emerald-600 hover:bg-emerald-50 rounded-md transition-all">
<i class="fas fa-file-excel"></i>
</button>
</div>
<div class="flex items-center gap-3 bg-slate-100 rounded-2xl px-5 py-1.5 border border-transparent focus-within:bg-white focus-within:border-blue-500 transition-all">
<input id="chatInput" type="text" placeholder="输入指令..."
class="flex-1 bg-transparent py-2.5 text-sm outline-none text-slate-700 font-medium"
onkeypress="if(event.key==='Enter') sendMsg()">
<button onclick="sendMsg()" class="w-9 h-9 bg-blue-600 text-white rounded-xl flex items-center justify-center hover:bg-blue-700 shadow-lg shadow-blue-100 active:scale-95 transition-all">
<i class="fas fa-paper-plane text-xs"></i>
</button>
</div>
</div>
</div>
</div>
<script>
const panel = document.getElementById('aiPanel');
const chatBox = document.getElementById('chatBox');
const input = document.getElementById('chatInput');
const overlay = document.getElementById('overlay');
const fab = document.getElementById('aiFab');
const icon = document.getElementById('expandIcon');
function openAI() { panel.classList.add('active'); overlay.classList.add('active'); fab.style.opacity = '0'; }
function closeAI() { panel.classList.remove('active'); panel.classList.remove('fullscreen'); overlay.classList.remove('active'); fab.style.opacity = '1'; icon.className = 'fas fa-expand-alt'; }
function toggleFullscreen() { panel.classList.toggle('fullscreen'); icon.className = panel.classList.contains('fullscreen') ? 'fas fa-compress-alt' : 'fas fa-expand-alt'; }
function triggerInput(type) { document.getElementById(type === 'image' ? 'imageInput' : 'fileInput').click(); }
function handleFileUpload(event, type) {
const file = event.target.files[0];
if (!file) return;
const contentHtml = type === 'image' ? `<img src="${URL.createObjectURL(file)}" class="rounded-lg max-w-full">` : `<div class="flex items-center gap-3 bg-white/10 p-3 rounded-xl border border-white/20"><div class="w-8 h-8 bg-emerald-500 rounded flex items-center justify-center text-white shrink-0"><i class="fas fa-file-excel text-xs"></i></div><p class="text-xs font-bold truncate">${file.name}</p></div>`;
const msgHtml = `<div class="flex justify-end"><div class="bg-blue-600 text-white p-3 rounded-2xl rounded-tr-none text-sm max-w-[85%] shadow-lg">${contentHtml}</div></div>`;
chatBox.insertAdjacentHTML('beforeend', msgHtml);
chatBox.scrollTop = chatBox.scrollHeight;
setTimeout(() => {
const aiId = 'ai-' + Date.now();
const aiHtml = `<div class="flex gap-4 items-start"><div class="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white shrink-0 mt-1 shadow-sm"><i class="fas fa-robot text-xs"></i></div><div class="bg-white border border-slate-200 p-4 rounded-2xl rounded-tl-none shadow-sm text-sm text-slate-700 flex-1"><p id="${aiId}" class="typing leading-relaxed"></p></div></div>`;
chatBox.insertAdjacentHTML('beforeend', aiHtml);
chatBox.scrollTop = chatBox.scrollHeight;
typeWriter(`正在分析您的文件数据...`, aiId);
}, 800);
}
function sendMsg() {
const text = input.value.trim();
if(!text) return;
const userHtml = `<div class="flex justify-end"><div class="bg-blue-600 text-white p-4 rounded-2xl rounded-tr-none text-sm max-w-[80%] shadow-lg shadow-blue-100/50">${text}</div></div>`;
chatBox.insertAdjacentHTML('beforeend', userHtml);
input.value = '';
chatBox.scrollTop = chatBox.scrollHeight;
setTimeout(() => {
const aiId = 'ai-' + Date.now();
const aiHtml = `<div class="flex gap-4 items-start"><div class="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white shrink-0 mt-1 border border-blue-100"><i class="fas fa-robot text-xs"></i></div><div class="bg-white border border-slate-200 p-4 rounded-2xl rounded-tl-none shadow-sm text-sm text-slate-700 flex-1"><p id="${aiId}" class="typing leading-relaxed"></p></div></div>`;
chatBox.insertAdjacentHTML('beforeend', aiHtml);
chatBox.scrollTop = chatBox.scrollHeight;
typeWriter(`正在处理您的指令...`, aiId);
}, 600);
}
function typeWriter(text, elementId) {
let i = 0;
const el = document.getElementById(elementId);
function type() { if (i < text.length) { el.innerHTML += text.charAt(i); i++; chatBox.scrollTop = chatBox.scrollHeight; setTimeout(type, 30); } else { el.classList.remove('typing'); } }
type();
}
</script>
</body>
</html>