refactor: 模块化架构重构
将单文件巨型 IIFE (1608行) 拆分为 14 个 ES Module: 核心层: - js/state.js - 轻量级响应式状态管理 (发布-订阅) - js/utils.js - 通用工具函数 - js/sanitizer.js - HTML XSS 净化器 - js/marked-config.js - Markdown 渲染器配置 组件层: - js/components/chat-area.js - 消息渲染/流式更新/导出 - js/components/input-area.js - 文本输入/图片上传/发送 - js/components/history-modal.js - 历史记录面板/搜索/分页 - js/components/settings-modal.js - 设置面板/数据管理 - js/components/header.js - 顶部导航/连接状态 - js/components/model-bar.js - 模型选择栏 - js/components/toast.js - Toast 通知 - js/components/lightbox.js - 图片预览 入口层: - js/app.js - 主入口/初始化协调 index.html: 1608行 → 204行纯模板
This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Utils - 通用工具函数
|
||||
*/
|
||||
|
||||
/** 生成唯一 ID */
|
||||
export function generateId() {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
/** 格式化时间戳 */
|
||||
export function formatTime(ts) {
|
||||
const d = new Date(ts);
|
||||
const pad = n => String(n).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
/** 截断文本 */
|
||||
export function truncate(str, len = 50) {
|
||||
if (!str) return '';
|
||||
return str.length > len ? str.substring(0, len) + '...' : str;
|
||||
}
|
||||
|
||||
/** 防抖 */
|
||||
export function debounce(fn, ms = 300) {
|
||||
let timer;
|
||||
return (...args) => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => fn(...args), ms);
|
||||
};
|
||||
}
|
||||
|
||||
/** 格式化字节大小 */
|
||||
export function formatSize(bytes) {
|
||||
if (!bytes) return '';
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let i = 0;
|
||||
let size = bytes;
|
||||
while (size >= 1024 && i < units.length - 1) {
|
||||
size /= 1024;
|
||||
i++;
|
||||
}
|
||||
return `${size.toFixed(1)} ${units[i]}`;
|
||||
}
|
||||
|
||||
/** HTML 转义 */
|
||||
export function escapeHtml(str) {
|
||||
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
||||
return String(str).replace(/[&<>"']/g, (c) => map[c]);
|
||||
}
|
||||
|
||||
/** 下载文件 */
|
||||
export function downloadFile(filename, content, type) {
|
||||
const blob = new Blob([content], { type: type + ';charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/** File → Base64(去前缀) */
|
||||
export function fileToBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const base64 = reader.result.split(',')[1];
|
||||
resolve(base64);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user