910 lines
29 KiB
HTML
910 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Bot Manager</title>
|
||
<!-- Fonts -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<!-- Lucide Icons -->
|
||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
|
||
|
||
<style>
|
||
:root {
|
||
--primary: #2563EB;
|
||
--primary-hover: #1D4ED8;
|
||
--secondary: #3B82F6;
|
||
--background: #F8FAFC;
|
||
--surface: #FFFFFF;
|
||
--text: #1E293B;
|
||
--text-muted: #64748B;
|
||
--border: #E2E8F0;
|
||
--success: #10B981;
|
||
--warning: #F59E0B;
|
||
--error: #EF4444;
|
||
--glass-bg: rgba(255, 255, 255, 0.8);
|
||
--glass-blur: 12px;
|
||
}
|
||
|
||
.dark {
|
||
--primary: #3B82F6;
|
||
--primary-hover: #60A5FA;
|
||
--secondary: #60A5FA;
|
||
--background: #0F172A;
|
||
--surface: #1E293B;
|
||
--text: #F1F5F9;
|
||
--text-muted: #94A3B8;
|
||
--border: #334155;
|
||
--glass-bg: rgba(30, 41, 59, 0.8);
|
||
}
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Open Sans', sans-serif;
|
||
background: var(--background);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
transition: background-color 0.3s ease, color 0.3s ease;
|
||
}
|
||
|
||
/* ===== Header ===== */
|
||
.header {
|
||
height: 64px;
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(var(--glass-blur));
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 24px;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 10;
|
||
}
|
||
|
||
.header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.header-logo {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 10px;
|
||
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
}
|
||
|
||
.header-title {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.header-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.header-btn {
|
||
width: 38px;
|
||
height: 38px;
|
||
border-radius: 10px;
|
||
border: none;
|
||
background: transparent;
|
||
color: var(--text);
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.header-btn:hover {
|
||
background: var(--background);
|
||
}
|
||
|
||
.header-btn.primary {
|
||
background: var(--primary);
|
||
color: white;
|
||
padding: 0 16px;
|
||
width: auto;
|
||
gap: 8px;
|
||
}
|
||
|
||
.header-btn.primary:hover {
|
||
background: var(--primary-hover);
|
||
}
|
||
|
||
/* ===== Main Content ===== */
|
||
.main-content {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 32px 24px;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.page-title {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.page-subtitle {
|
||
font-size: 14px;
|
||
color: var(--text-muted);
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* ===== Bot Grid ===== */
|
||
.bot-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||
gap: 20px;
|
||
}
|
||
|
||
.bot-card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
position: relative;
|
||
}
|
||
|
||
.bot-card:hover {
|
||
border-color: var(--primary);
|
||
box-shadow: 0 4px 20px rgba(37, 99, 235, 0.1);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.bot-card-header {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 14px;
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.bot-card-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 12px;
|
||
background: linear-gradient(135deg, var(--primary), var(--secondary));
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.bot-card-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.bot-card-name {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.bot-card-id {
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
font-family: 'Monaco', 'Consolas', monospace;
|
||
background: var(--background);
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.bot-card-meta {
|
||
display: flex;
|
||
gap: 16px;
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.bot-card-meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.bot-card-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-top: 14px;
|
||
padding-top: 14px;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.bot-card-action {
|
||
flex: 1;
|
||
padding: 8px 12px;
|
||
border-radius: 8px;
|
||
border: 1px solid var(--border);
|
||
background: transparent;
|
||
color: var(--text);
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.bot-card-action:hover {
|
||
background: var(--background);
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
.bot-card-action.delete:hover {
|
||
background: rgba(239, 68, 68, 0.1);
|
||
border-color: var(--error);
|
||
color: var(--error);
|
||
}
|
||
|
||
/* ===== Empty State ===== */
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 80px 20px;
|
||
}
|
||
|
||
.empty-state-icon {
|
||
width: 80px;
|
||
height: 80px;
|
||
margin: 0 auto 20px;
|
||
border-radius: 20px;
|
||
background: var(--background);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.empty-state-title {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.empty-state-subtitle {
|
||
font-size: 14px;
|
||
color: var(--text-muted);
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
/* ===== Modal ===== */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
backdrop-filter: blur(4px);
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 100;
|
||
}
|
||
|
||
.modal-overlay.active {
|
||
display: flex;
|
||
}
|
||
|
||
.modal {
|
||
background: var(--surface);
|
||
border-radius: 16px;
|
||
width: 90%;
|
||
max-width: 480px;
|
||
max-height: 85vh;
|
||
overflow: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.modal-header {
|
||
padding: 20px 24px;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.modal-title {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.modal-close {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
background: transparent;
|
||
color: var(--text-muted);
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-close:hover {
|
||
background: var(--background);
|
||
color: var(--text);
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 24px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.form-group:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.form-label {
|
||
display: block;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--text-muted);
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
padding: 12px 14px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
font-size: 14px;
|
||
background: var(--background);
|
||
color: var(--text);
|
||
outline: none;
|
||
transition: border-color 0.15s ease;
|
||
}
|
||
|
||
.form-input:focus {
|
||
border-color: var(--primary);
|
||
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
||
}
|
||
|
||
.form-hint {
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 16px 24px;
|
||
border-top: 1px solid var(--border);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: var(--background);
|
||
border: 1px solid var(--border);
|
||
color: var(--text);
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--primary);
|
||
border: none;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: var(--primary-hover);
|
||
}
|
||
|
||
/* ===== Delete Confirmation Modal ===== */
|
||
.delete-confirm-content {
|
||
text-align: center;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.delete-confirm-icon {
|
||
width: 56px;
|
||
height: 56px;
|
||
margin: 0 auto 16px;
|
||
border-radius: 50%;
|
||
background: rgba(239, 68, 68, 0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--error);
|
||
}
|
||
|
||
.delete-confirm-title {
|
||
font-family: 'Poppins', sans-serif;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.delete-confirm-text {
|
||
font-size: 14px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
/* ===== Scrollbar ===== */
|
||
::-webkit-scrollbar {
|
||
width: 6px;
|
||
height: 6px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: var(--border);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: var(--text-muted);
|
||
}
|
||
|
||
/* ===== Responsive ===== */
|
||
@media (max-width: 768px) {
|
||
.header {
|
||
padding: 0 16px;
|
||
}
|
||
|
||
.main-content {
|
||
padding: 20px 16px;
|
||
}
|
||
|
||
.bot-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.page-header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 16px;
|
||
}
|
||
|
||
.header-btn.primary span {
|
||
display: none;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Header -->
|
||
<header class="header">
|
||
<div class="header-left">
|
||
<div class="header-logo">
|
||
<i data-lucide="bot" style="width: 20px; height: 20px;"></i>
|
||
</div>
|
||
<div>
|
||
<div class="header-title">Bot Manager</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
<button class="header-btn" id="theme-toggle" title="切换主题">
|
||
<i data-lucide="moon" style="width: 18px; height: 18px;"></i>
|
||
</button>
|
||
<button class="header-btn primary" id="add-bot-btn">
|
||
<i data-lucide="plus" style="width: 16px; height: 16px;"></i>
|
||
<span>新建 Bot</span>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Main Content -->
|
||
<main class="main-content">
|
||
<div class="page-header">
|
||
<div>
|
||
<h1 class="page-title">我的 Bots</h1>
|
||
<p class="page-subtitle">管理您的 AI 聊天机器人配置</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Bot Grid -->
|
||
<div class="bot-grid" id="bot-grid">
|
||
<!-- 动态生成 -->
|
||
</div>
|
||
</main>
|
||
|
||
<!-- Add/Edit Bot Modal -->
|
||
<div class="modal-overlay" id="bot-modal">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<h3 class="modal-title" id="bot-modal-title">新建 Bot</h3>
|
||
<button class="modal-close" id="bot-modal-close">
|
||
<i data-lucide="x" style="width: 18px; height: 18px;"></i>
|
||
</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="form-group">
|
||
<label class="form-label" for="bot-name">Bot 名称 *</label>
|
||
<input type="text" id="bot-name" class="form-input" placeholder="例如:客服助手、销售顾问">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label" for="bot-id-input">Bot ID *</label>
|
||
<input type="text" id="bot-id-input" class="form-input" placeholder="例如:test 或 UUID">
|
||
<p class="form-hint">这是用于 API 调用的唯一标识符</p>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" id="bot-modal-cancel">取消</button>
|
||
<button class="btn btn-primary" id="bot-modal-save">保存</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Delete Confirmation Modal -->
|
||
<div class="modal-overlay" id="delete-modal">
|
||
<div class="modal" style="max-width: 400px;">
|
||
<div class="modal-body">
|
||
<div class="delete-confirm-content">
|
||
<div class="delete-confirm-icon">
|
||
<i data-lucide="alert-triangle" style="width: 28px; height: 28px;"></i>
|
||
</div>
|
||
<h3 class="delete-confirm-title">确认删除</h3>
|
||
<p class="delete-confirm-text">确定要删除这个 Bot 吗?此操作无法撤销。</p>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" id="delete-modal-cancel">取消</button>
|
||
<button class="btn btn-primary" id="delete-modal-confirm" style="background: var(--error);">删除</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Initialize Lucide icons
|
||
lucide.createIcons();
|
||
|
||
class BotManager {
|
||
constructor() {
|
||
this.elements = {
|
||
themeToggle: document.getElementById('theme-toggle'),
|
||
addBotBtn: document.getElementById('add-bot-btn'),
|
||
botGrid: document.getElementById('bot-grid'),
|
||
// Bot Modal
|
||
botModal: document.getElementById('bot-modal'),
|
||
botModalTitle: document.getElementById('bot-modal-title'),
|
||
botModalClose: document.getElementById('bot-modal-close'),
|
||
botModalCancel: document.getElementById('bot-modal-cancel'),
|
||
botModalSave: document.getElementById('bot-modal-save'),
|
||
botNameInput: document.getElementById('bot-name'),
|
||
botIdInput: document.getElementById('bot-id-input'),
|
||
// Delete Modal
|
||
deleteModal: document.getElementById('delete-modal'),
|
||
deleteModalCancel: document.getElementById('delete-modal-cancel'),
|
||
deleteModalConfirm: document.getElementById('delete-modal-confirm')
|
||
};
|
||
|
||
this.bots = [];
|
||
this.editingBotId = null;
|
||
this.deletingBotId = null;
|
||
|
||
this.initializeEventListeners();
|
||
this.loadTheme();
|
||
this.loadBots();
|
||
}
|
||
|
||
initializeEventListeners() {
|
||
// Theme toggle
|
||
this.elements.themeToggle.addEventListener('click', () => this.toggleTheme());
|
||
|
||
// Add bot
|
||
this.elements.addBotBtn.addEventListener('click', () => this.openBotModal());
|
||
|
||
// Bot modal
|
||
this.elements.botModalClose.addEventListener('click', () => this.closeBotModal());
|
||
this.elements.botModalCancel.addEventListener('click', () => this.closeBotModal());
|
||
this.elements.botModalSave.addEventListener('click', () => this.saveBot());
|
||
this.elements.botModal.addEventListener('click', (e) => {
|
||
if (e.target === this.elements.botModal) this.closeBotModal();
|
||
});
|
||
|
||
// Delete modal
|
||
this.elements.deleteModalCancel.addEventListener('click', () => this.closeDeleteModal());
|
||
this.elements.deleteModalConfirm.addEventListener('click', () => this.confirmDelete());
|
||
}
|
||
|
||
loadTheme() {
|
||
const theme = localStorage.getItem('theme') || 'light';
|
||
if (theme === 'dark') {
|
||
document.documentElement.classList.add('dark');
|
||
}
|
||
this.updateThemeIcon(theme === 'dark');
|
||
}
|
||
|
||
toggleTheme() {
|
||
document.documentElement.classList.toggle('dark');
|
||
const isDark = document.documentElement.classList.contains('dark');
|
||
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
||
this.updateThemeIcon(isDark);
|
||
}
|
||
|
||
updateThemeIcon(isDark) {
|
||
const icon = this.elements.themeToggle.querySelector('i');
|
||
if (!icon) return;
|
||
icon.setAttribute('data-lucide', isDark ? 'sun' : 'moon');
|
||
lucide.createIcons();
|
||
}
|
||
|
||
loadBots() {
|
||
const stored = localStorage.getItem('bot-list');
|
||
if (stored) {
|
||
try {
|
||
this.bots = JSON.parse(stored);
|
||
} catch (e) {
|
||
this.bots = [];
|
||
}
|
||
}
|
||
this.renderBots();
|
||
}
|
||
|
||
saveBots() {
|
||
localStorage.setItem('bot-list', JSON.stringify(this.bots));
|
||
}
|
||
|
||
renderBots() {
|
||
const grid = this.elements.botGrid;
|
||
|
||
if (this.bots.length === 0) {
|
||
grid.innerHTML = `
|
||
<div class="empty-state" style="grid-column: 1 / -1;">
|
||
<div class="empty-state-icon">
|
||
<i data-lucide="bot" style="width: 40px; height: 40px;"></i>
|
||
</div>
|
||
<h2 class="empty-state-title">暂无 Bots</h2>
|
||
<p class="empty-state-subtitle">点击上方按钮创建您的第一个 Bot</p>
|
||
</div>
|
||
`;
|
||
lucide.createIcons();
|
||
return;
|
||
}
|
||
|
||
grid.innerHTML = '';
|
||
this.bots.forEach(bot => {
|
||
const card = this.createBotCard(bot);
|
||
grid.appendChild(card);
|
||
});
|
||
|
||
lucide.createIcons();
|
||
}
|
||
|
||
createBotCard(bot) {
|
||
const card = document.createElement('div');
|
||
card.className = 'bot-card';
|
||
|
||
const formatDate = (timestamp) => {
|
||
const date = new Date(timestamp);
|
||
return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'short', day: 'numeric' });
|
||
};
|
||
|
||
card.innerHTML = `
|
||
<div class="bot-card-header">
|
||
<div class="bot-card-icon">
|
||
<i data-lucide="bot" style="width: 24px; height: 24px;"></i>
|
||
</div>
|
||
<div class="bot-card-info">
|
||
<div class="bot-card-name">${this.escapeHtml(bot.name)}</div>
|
||
<span class="bot-card-id">${this.escapeHtml(bot.botId)}</span>
|
||
</div>
|
||
</div>
|
||
<div class="bot-card-meta">
|
||
<span class="bot-card-meta-item">
|
||
<i data-lucide="calendar" style="width: 12px; height: 12px;"></i>
|
||
创建于 ${formatDate(bot.createdAt)}
|
||
</span>
|
||
<span class="bot-card-meta-item">
|
||
<i data-lucide="clock" style="width: 12px; height: 12px;"></i>
|
||
更新于 ${formatDate(bot.updatedAt)}
|
||
</span>
|
||
</div>
|
||
<div class="bot-card-actions">
|
||
<button class="bot-card-action" data-action="open" data-bot-id="${bot.id}">
|
||
<i data-lucide="external-link" style="width: 14px; height: 14px;"></i>
|
||
打开
|
||
</button>
|
||
<button class="bot-card-action" data-action="edit" data-bot-id="${bot.id}">
|
||
<i data-lucide="pencil" style="width: 14px; height: 14px;"></i>
|
||
编辑
|
||
</button>
|
||
<button class="bot-card-action delete" data-action="delete" data-bot-id="${bot.id}">
|
||
<i data-lucide="trash-2" style="width: 14px; height: 14px;"></i>
|
||
删除
|
||
</button>
|
||
</div>
|
||
`;
|
||
|
||
// Event listeners
|
||
card.addEventListener('click', (e) => {
|
||
const action = e.target.closest('[data-action]')?.dataset.action;
|
||
const botId = e.target.closest('[data-bot-id]')?.dataset.botId;
|
||
|
||
if (action === 'open' && botId) {
|
||
this.openBotChat(botId);
|
||
} else if (action === 'edit' && botId) {
|
||
e.stopPropagation();
|
||
this.openEditModal(botId);
|
||
} else if (action === 'delete' && botId) {
|
||
e.stopPropagation();
|
||
this.openDeleteModal(botId);
|
||
}
|
||
});
|
||
|
||
return card;
|
||
}
|
||
|
||
openBotChat(botInternalId) {
|
||
const bot = this.bots.find(b => b.id === botInternalId);
|
||
if (bot) {
|
||
// 保存当前选中的 bot ID
|
||
sessionStorage.setItem('current-bot-id', bot.id);
|
||
// 跳转到聊天页面
|
||
window.location.href = 'index.html';
|
||
}
|
||
}
|
||
|
||
openBotModal() {
|
||
this.editingBotId = null;
|
||
this.elements.botModalTitle.textContent = '新建 Bot';
|
||
this.elements.botNameInput.value = '';
|
||
this.elements.botIdInput.value = '';
|
||
this.elements.botModal.classList.add('active');
|
||
this.elements.botNameInput.focus();
|
||
}
|
||
|
||
openEditModal(botInternalId) {
|
||
const bot = this.bots.find(b => b.id === botInternalId);
|
||
if (!bot) return;
|
||
|
||
this.editingBotId = botInternalId;
|
||
this.elements.botModalTitle.textContent = '编辑 Bot';
|
||
this.elements.botNameInput.value = bot.name;
|
||
this.elements.botIdInput.value = bot.botId;
|
||
this.elements.botModal.classList.add('active');
|
||
this.elements.botNameInput.focus();
|
||
}
|
||
|
||
closeBotModal() {
|
||
this.elements.botModal.classList.remove('active');
|
||
this.editingBotId = null;
|
||
}
|
||
|
||
saveBot() {
|
||
const name = this.elements.botNameInput.value.trim();
|
||
const botId = this.elements.botIdInput.value.trim();
|
||
|
||
if (!name) {
|
||
alert('请输入 Bot 名称');
|
||
return;
|
||
}
|
||
|
||
if (!botId) {
|
||
alert('请输入 Bot ID');
|
||
return;
|
||
}
|
||
|
||
// 检查 Bot ID 是否重复
|
||
const existingBot = this.bots.find(b => b.botId === botId && b.id !== this.editingBotId);
|
||
if (existingBot) {
|
||
alert('Bot ID 已存在,请使用其他 ID');
|
||
return;
|
||
}
|
||
|
||
const now = Date.now();
|
||
|
||
if (this.editingBotId) {
|
||
// 编辑现有 bot
|
||
const bot = this.bots.find(b => b.id === this.editingBotId);
|
||
if (bot) {
|
||
bot.name = name;
|
||
bot.botId = botId;
|
||
bot.updatedAt = now;
|
||
}
|
||
} else {
|
||
// 新建 bot
|
||
const newBot = {
|
||
id: this.generateUUID(),
|
||
name: name,
|
||
botId: botId,
|
||
createdAt: now,
|
||
updatedAt: now
|
||
};
|
||
this.bots.unshift(newBot);
|
||
}
|
||
|
||
this.saveBots();
|
||
this.renderBots();
|
||
this.closeBotModal();
|
||
}
|
||
|
||
openDeleteModal(botInternalId) {
|
||
this.deletingBotId = botInternalId;
|
||
this.elements.deleteModal.classList.add('active');
|
||
}
|
||
|
||
closeDeleteModal() {
|
||
this.elements.deleteModal.classList.remove('active');
|
||
this.deletingBotId = null;
|
||
}
|
||
|
||
confirmDelete() {
|
||
if (!this.deletingBotId) return;
|
||
|
||
const bot = this.bots.find(b => b.id === this.deletingBotId);
|
||
if (bot) {
|
||
// 删除 bot 的设置数据
|
||
localStorage.removeItem(`bot-settings-${bot.botId}`);
|
||
}
|
||
|
||
this.bots = this.bots.filter(b => b.id !== this.deletingBotId);
|
||
this.saveBots();
|
||
this.renderBots();
|
||
this.closeDeleteModal();
|
||
}
|
||
|
||
generateUUID() {
|
||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||
const r = Math.random() * 16 | 0;
|
||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||
return v.toString(16);
|
||
});
|
||
}
|
||
|
||
escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML;
|
||
}
|
||
}
|
||
|
||
// Initialize app
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
new BotManager();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|