nodebookls/frontend/components.py
2025-10-29 13:56:24 +08:00

182 lines
5.8 KiB
Python

"""
前端组件模块
提供可重用的UI组件和交互逻辑
"""
class UIComponent:
"""UI组件基类"""
def __init__(self, element_id: str):
self.element_id = element_id
def render(self) -> str:
"""渲染组件"""
raise NotImplementedError
def get_script(self) -> str:
"""获取组件相关的JavaScript代码"""
return ""
class ProgressBar(UIComponent):
"""进度条组件"""
def __init__(self, element_id: str, label: str = "进度"):
super().__init__(element_id)
self.label = label
def render(self) -> str:
return f"""
<div class="form-group">
<label>{self.label}:</label>
<div class="progress" id="{self.element_id}_container" style="display: none;">
<div class="progress-bar" id="{self.element_id}" style="width: 0%">0%</div>
</div>
</div>
"""
def get_script(self) -> str:
return f"""
function showProgress_{self.element_id}(percent) {{
const container = document.getElementById('{self.element_id}_container');
const bar = document.getElementById('{self.element_id}');
container.style.display = 'block';
bar.style.width = percent + '%';
bar.textContent = percent + '%';
}}
function hideProgress_{self.element_id}() {{
const container = document.getElementById('{self.element_id}_container');
container.style.display = 'none';
}}
"""
class AlertBox(UIComponent):
"""提示框组件"""
def __init__(self, element_id: str):
super().__init__(element_id)
def render(self) -> str:
return f"""
<div id="{self.element_id}" class="alert hidden"></div>
"""
def get_script(self) -> str:
return f"""
function showAlert_{self.element_id}(message, type = 'info') {{
const alertBox = document.getElementById('{self.element_id}');
alertBox.textContent = message;
alertBox.className = 'alert ' + type;
alertBox.classList.remove('hidden');
// 3秒后自动隐藏
setTimeout(() => {{
alertBox.classList.add('hidden');
}}, 3000);
}}
"""
class Modal(UIComponent):
"""模态框组件"""
def __init__(self, element_id: str, title: str):
super().__init__(element_id)
self.title = title
def render(self) -> str:
return f"""
<div id="{self.element_id}" class="modal hidden">
<div class="modal-content">
<div class="modal-header">
<h3>{self.title}</h3>
<span class="close" onclick="closeModal_{self.element_id}()">&times;</span>
</div>
<div class="modal-body" id="{self.element_id}_body">
<!-- 模态框内容 -->
</div>
</div>
</div>
"""
def get_script(self) -> str:
return f"""
function showModal_{self.element_id}(content = '') {{
const modal = document.getElementById('{self.element_id}');
const body = document.getElementById('{self.element_id}_body');
if (content) {{
body.innerHTML = content;
}}
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
}}
function closeModal_{self.element_id}() {{
const modal = document.getElementById('{self.element_id}');
modal.classList.add('hidden');
document.body.style.overflow = 'auto';
}}
// 点击模态框外部关闭
document.getElementById('{self.element_id}').addEventListener('click', function(e) {{
if (e.target === this) {{
closeModal_{self.element_id}();
}}
}});
"""
class Tabs(UIComponent):
"""标签页组件"""
def __init__(self, element_id: str, tabs: list):
super().__init__(element_id)
self.tabs = tabs # [(tab_id, tab_label), ...]
def render(self) -> str:
tab_buttons = ""
tab_contents = ""
for i, (tab_id, tab_label) in enumerate(self.tabs):
active_class = "active" if i == 0 else ""
tab_buttons += f"""
<button class="tab-button {active_class}" onclick="switchTab_{self.element_id}('{tab_id}')">{tab_label}</button>
"""
tab_contents += f"""
<div id="{tab_id}" class="tab-content {'active' if i == 0 else ''}">
<!-- {tab_label} 内容 -->
</div>
"""
return f"""
<div class="tabs">
<div class="tab-buttons">
{tab_buttons}
</div>
<div class="tab-contents">
{tab_contents}
</div>
</div>
"""
def get_script(self) -> str:
return f"""
function switchTab_{self.element_id}(tabId) {{
// 隐藏所有标签内容
const tabContents = document.querySelectorAll('.tab-content');
tabContents.forEach(content => {{
content.classList.remove('active');
}});
// 移除所有按钮的激活状态
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(button => {{
button.classList.remove('active');
}});
// 显示选中的标签内容
document.getElementById(tabId).classList.add('active');
// 激活选中的按钮
event.target.classList.add('active');
}}
"""