重构了main.html的主函数
重构了大量的页面的sidebar 优化了代码结构
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
<script src="../js/components/table.js"></script>
|
||||
<script src="../js/pages/render.js"></script>
|
||||
<script src="../js/main.js"></script>
|
||||
<!-- 常量配置 -->
|
||||
<script src="../js/config/constants.js"></script>
|
||||
<link href="../lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="../css/main.css" rel="stylesheet">
|
||||
</head>
|
||||
@@ -50,12 +52,6 @@
|
||||
<span class="ml-2">模型调优</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-item-wrapper">
|
||||
<a href="main.html?page=my-models" data-page="my-models" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<i class="fa fa-database w-5 text-center"></i>
|
||||
<span class="ml-2">我的模型</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-item-wrapper">
|
||||
<a href="#" data-page="model-eval" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<i class="fa fa-line-chart w-5 text-center"></i>
|
||||
@@ -85,7 +81,7 @@
|
||||
</div>
|
||||
<div class="nav-item-wrapper">
|
||||
<a href="tools.html" class="nav-link flex items-center px-4 py-2.5 hover:bg-[#001529]/20 transition-colors">
|
||||
<i class="fa fa-database w-5 text-center"></i>
|
||||
<i class="fa fa-wrench w-5 text-center"></i>
|
||||
<span class="ml-2">其他工具</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -171,12 +167,19 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// API 基础地址 - 使用 config.yaml 中的 app.port (7861)
|
||||
// 加载常量配置
|
||||
if (typeof window.CONSTANTS === 'undefined') {
|
||||
// 如果constants.js还未加载,使用默认值
|
||||
window.CONSTANTS = { API_CONFIG: { PORT: 7861, METRICS_INTERVAL: 30000 } };
|
||||
}
|
||||
const CONFIG = window.CONSTANTS.API_CONFIG;
|
||||
|
||||
// API 基础地址
|
||||
if (typeof window.getApiBase !== 'function') {
|
||||
window.getApiBase = () => {
|
||||
const protocol = window.location.protocol;
|
||||
const hostname = window.location.hostname;
|
||||
return `${protocol}//${hostname}:7861/api`;
|
||||
return `${protocol}//${hostname}:${CONFIG.PORT}/api`;
|
||||
};
|
||||
}
|
||||
if (typeof window.API_BASE === 'undefined') {
|
||||
@@ -215,9 +218,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时获取监控数据,并每30秒刷新
|
||||
// 页面加载时获取监控数据,并定期刷新
|
||||
fetchSystemMetrics();
|
||||
setInterval(fetchSystemMetrics, 30000);
|
||||
setInterval(fetchSystemMetrics, CONFIG.METRICS_INTERVAL);
|
||||
|
||||
// 各功能模块的表格配置
|
||||
const tableConfigs = {
|
||||
@@ -274,7 +277,7 @@
|
||||
}},
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
],
|
||||
actions: ['compare', 'delete']
|
||||
actions: ['startCompare', 'delete']
|
||||
},
|
||||
'dataset-manage': {
|
||||
title: '数据集管理',
|
||||
@@ -356,7 +359,15 @@
|
||||
{ title: '描述', key: 'description', render: (val) => val || '-' },
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
],
|
||||
actions: ['edit', 'delete']
|
||||
actions: ['edit', 'delete'],
|
||||
// 训练模型 tab 的列配置
|
||||
trainedColumns: [
|
||||
{ title: '模型名称', key: 'name' },
|
||||
{ title: '训练方法', key: 'train_methods', render: (val) => val && val[0] ? val[0].name : '-' },
|
||||
{ title: '基座模型', key: 'base_model_path', render: (val) => `<span class="text-xs text-gray-500 truncate block" title="${val}">${val || '-'}</span>` },
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
],
|
||||
trainedActions: ['view', 'delete']
|
||||
},
|
||||
'logs': {
|
||||
title: '查看日志',
|
||||
@@ -563,7 +574,7 @@
|
||||
progressRefreshTimer = setInterval(() => {
|
||||
refreshTrainingProgress();
|
||||
checkAndUpdateTaskStatus();
|
||||
}, 5000);
|
||||
}, CONFIG.TRAINING_REFRESH_INTERVAL);
|
||||
|
||||
// 更新侧边栏高亮状态
|
||||
document.querySelectorAll('.nav-link').forEach(link => {
|
||||
@@ -761,7 +772,10 @@
|
||||
}
|
||||
let data = await fetchData(apiUrl);
|
||||
// 如果配置了 dataPath,从返回数据中提取指定字段
|
||||
if (config.dataPath && typeof data === 'object' && data !== null) {
|
||||
// 训练模型 tab 需要从 {models: [...]} 中提取数据
|
||||
if (config.hasModelTabs && currentModelTab === 'trained' && typeof data === 'object' && data !== null) {
|
||||
data = data.models || [];
|
||||
} else if (config.dataPath && typeof data === 'object' && data !== null) {
|
||||
data = data[config.dataPath] || [];
|
||||
}
|
||||
currentPageData = data; // 保存当前页面数据
|
||||
@@ -1075,15 +1089,13 @@
|
||||
|
||||
// 下载数据集(打包下载)
|
||||
function downloadDataset(datasetId) {
|
||||
const protocol = window.location.protocol;
|
||||
const hostname = window.location.hostname;
|
||||
window.open(`${protocol}//${hostname}:7861/api/dataset-manage/download/${datasetId}`, '_blank');
|
||||
window.open(`${API_BASE}/dataset-manage/download/${datasetId}`, '_blank');
|
||||
}
|
||||
|
||||
// 开始模型对比
|
||||
async function startCompare(id) {
|
||||
// 跳转到模型对比聊天页面(通过主框架加载)
|
||||
window.location.href = `main.html?page=model-compare-chat&id=${id}`;
|
||||
// 跳转到模型对比聊天页面(独立页面)
|
||||
window.location.href = `model-compare-chat.html?id=${id}`;
|
||||
}
|
||||
|
||||
// 筛选表格
|
||||
@@ -1108,16 +1120,23 @@
|
||||
|
||||
// 渲染表格页面
|
||||
function renderTablePage(config, data) {
|
||||
// 使用配置中的列定义,如果没有则使用默认列
|
||||
const columns = config.columns || [
|
||||
{ title: '模型名称', key: 'name' },
|
||||
{ title: '训练方法', key: 'train_methods', render: (val) => val && val[0] ? val[0].name : '-' },
|
||||
{ title: '基座模型', key: 'base_model_path', render: (val) => `<span class="text-xs text-gray-500 truncate block" title="${val}">${val || '-'}</span>` },
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
];
|
||||
// 根据 tab 选择列配置和当前 API
|
||||
let columns;
|
||||
let currentApi = config.api;
|
||||
if (config.hasModelTabs && currentModelTab === 'trained') {
|
||||
columns = config.trainedColumns || config.columns;
|
||||
currentApi = 'model-manage/trained-models';
|
||||
} else {
|
||||
columns = config.columns || [
|
||||
{ title: '模型名称', key: 'name' },
|
||||
{ title: '训练方法', key: 'train_methods', render: (val) => val && val[0] ? val[0].name : '-' },
|
||||
{ title: '基座模型', key: 'base_model_path', render: (val) => `<span class="text-xs text-gray-500 truncate block" title="${val}">${val || '-'}</span>` },
|
||||
{ title: '创建时间', key: 'create_time', render: (val) => val ? new Date(val).toLocaleString('zh-CN') : '-' }
|
||||
];
|
||||
}
|
||||
|
||||
// 搜索框
|
||||
const searchBox = (config.api === 'model-manage' || config.api === 'model-manage/trained-models' || config.api === 'dataset-manage' || config.api === 'fine-tune') ? `
|
||||
const searchBox = (currentApi === 'model-manage' || currentApi === 'model-manage/trained-models' || config.api === 'dataset-manage' || config.api === 'fine-tune') ? `
|
||||
<div class="relative">
|
||||
<input type="text" id="tableSearchInput" placeholder="搜索${config.title}..."
|
||||
class="w-72 pl-9 pr-3 py-1.5 rounded border border-gray-300 text-sm focus:outline-none focus:border-primary focus:ring-1 focus:border-primary"
|
||||
@@ -1126,27 +1145,50 @@
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
// 是否支持多选(模型管理和数据集管理)
|
||||
const supportsMultiSelect = config.api === 'model-manage' || config.api === 'model-manage/trained-models' || config.api === 'dataset-manage' || config.api === 'fine-tune';
|
||||
// 是否支持多选
|
||||
const supportsMultiSelect = currentApi === 'model-manage' || currentApi === 'model-manage/trained-models' || config.api === 'dataset-manage' || config.api === 'fine-tune';
|
||||
|
||||
// 创建按钮(根据API类型决定是否显示)
|
||||
const createButton = config.api === 'model-manage' ? `
|
||||
// 创建按钮(根据 tab 类型决定是否显示)
|
||||
let createButton = '';
|
||||
if (config.hasModelTabs && currentModelTab === 'trained') {
|
||||
// 训练模型 tab 不显示创建按钮
|
||||
createButton = '';
|
||||
} else if (config.hasModelTabs && currentModelTab === 'config') {
|
||||
// 配置模型 tab 显示创建按钮
|
||||
createButton = `
|
||||
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
|
||||
<i class="fa fa-plus mr-1"></i>新建模型
|
||||
</button>
|
||||
` : (config.api === 'dataset-manage' ? `
|
||||
`;
|
||||
} else if (config.api === 'model-manage') {
|
||||
createButton = `
|
||||
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
|
||||
<i class="fa fa-plus mr-1"></i>新建模型
|
||||
</button>
|
||||
`;
|
||||
} else if (config.api === 'dataset-manage') {
|
||||
createButton = `
|
||||
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
|
||||
<i class="fa fa-plus mr-1"></i>创建数据集
|
||||
</button>
|
||||
` : (config.api === 'fine-tune' ? `
|
||||
`;
|
||||
} else if (config.api === 'fine-tune') {
|
||||
createButton = `
|
||||
<button onclick="navigateToPage('fine-tune-create')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
|
||||
<i class="fa fa-plus mr-1"></i>新建调优任务
|
||||
</button>
|
||||
` : ''));
|
||||
`;
|
||||
} else if (config.api === 'model-compare') {
|
||||
createButton = `
|
||||
<button onclick="showCreateModal('${config.api}')" class="bg-primary text-white px-3 py-1.5 rounded text-sm hover:bg-primary/90 transition-colors">
|
||||
<i class="fa fa-plus mr-1"></i>新建对比
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
// 批量删除按钮(仅当有选中项时显示)
|
||||
const batchDeleteButton = supportsMultiSelect && selectedItems.size > 0 ? `
|
||||
<button onclick="batchDeleteItems('${config.api}')" class="bg-red-500 text-white px-4 py-2 rounded text-sm hover:bg-red-600 transition-colors font-medium shadow-sm">
|
||||
<button onclick="batchDeleteItems('${currentApi}')" class="bg-red-500 text-white px-4 py-2 rounded text-sm hover:bg-red-600 transition-colors font-medium shadow-sm">
|
||||
<i class="fa fa-trash mr-1"></i>批量删除 (${selectedItems.size})
|
||||
</button>
|
||||
` : '';
|
||||
@@ -1157,7 +1199,7 @@
|
||||
const selectAllHeader = supportsMultiSelect ? `
|
||||
<th class="px-4 py-3 text-center font-medium w-10">
|
||||
<input type="checkbox" class="w-4 h-4 text-primary rounded border-gray-300 cursor-pointer"
|
||||
onchange="toggleSelectAll(this, '${config.api}')">
|
||||
onchange="toggleSelectAll(this, '${currentApi}')">
|
||||
</th>
|
||||
` : '';
|
||||
|
||||
@@ -1212,7 +1254,7 @@
|
||||
<td class="px-4 py-4 text-sm text-center">
|
||||
<input type="checkbox" class="w-4 h-4 text-primary rounded border-gray-300 cursor-pointer"
|
||||
${selectedItems.has(item.name || item.id) ? 'checked' : ''}
|
||||
onchange="toggleItemSelection('${item.name || item.id}', '${config.api}')">
|
||||
onchange="toggleItemSelection('${item.name || item.id}', '${currentApi}')">
|
||||
</td>
|
||||
` : ''}
|
||||
${columns.map(col => `
|
||||
@@ -1222,23 +1264,27 @@
|
||||
`).join('')}
|
||||
<td class="px-4 py-4 text-sm text-center">
|
||||
<div class="flex justify-center space-x-2">
|
||||
${config.api === 'fine-tune' ? `
|
||||
${currentApi === 'fine-tune' ? `
|
||||
<button onclick="viewFineTuneLogs('${item.id}', '${item.name}')" class="bg-blue-500 text-white px-3 py-1 rounded text-xs hover:bg-blue-600">查看日志</button>
|
||||
<button onclick="deleteItem('${config.api}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除任务</button>
|
||||
` : (config.api === 'model-manage/trained-models' ? `
|
||||
<button onclick="deleteItem('${currentApi}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除任务</button>
|
||||
` : (currentApi === 'model-manage/trained-models' ? `
|
||||
${getMergeButtonHtml(item.name, item.train_methods?.[0]?.name || 'lora', item.base_model_path || '', item.merged, item.merging)}
|
||||
<button onclick="deleteTrainedWeight('${item.name}')" class="bg-orange-500 text-white px-3 py-1 rounded text-xs hover:bg-orange-600">删除权重</button>
|
||||
${(item.merged && !item.merging) ? `
|
||||
<button onclick="exportModel('${item.name}')" class="bg-green-500 text-white px-3 py-1 rounded text-xs hover:bg-green-600">导出权重</button>
|
||||
<button onclick="deleteItem('${config.api}', '${item.name || item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
<button onclick="deleteItem('${currentApi}', '${item.name || item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除模型</button>
|
||||
` : ''}
|
||||
` : (config.api === 'model-manage' ? `
|
||||
` : (currentApi === 'model-manage' ? `
|
||||
<button onclick="editModel('${item.id}')" class="bg-blue-500 text-white px-3 py-1 rounded text-xs hover:bg-blue-600">编辑</button>
|
||||
<button onclick="deleteItem('${config.api}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
` : (config.api === 'dataset-manage' ? `
|
||||
<button onclick="deleteItem('${currentApi}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
` : (currentApi === 'dataset-manage' ? `
|
||||
<button onclick="previewDataset('${item.id}')" class="bg-blue-500 text-white px-3 py-1 rounded text-xs hover:bg-blue-600">预览</button>
|
||||
<button onclick="downloadDataset('${item.id}')" class="bg-green-500 text-white px-3 py-1 rounded text-xs hover:bg-green-600">下载</button>
|
||||
<button onclick="deleteItem('${config.api}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
` : '')))}
|
||||
<button onclick="deleteItem('${currentApi}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
` : (currentApi === 'model-compare' ? `
|
||||
<button onclick="startCompare('${item.id}')" class="bg-blue-500 text-white px-3 py-1 rounded text-xs hover:bg-blue-600">开始对比</button>
|
||||
<button onclick="deleteItem('${currentApi}', '${item.id}')" class="bg-red-500 text-white px-3 py-1 rounded text-xs hover:bg-red-600">删除</button>
|
||||
` : ''))))}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -1463,14 +1509,30 @@
|
||||
// 获取合并按钮HTML(根据合并状态显示不同按钮)
|
||||
function getMergeButtonHtml(name, method, path, merged, merging) {
|
||||
// 优先检查 sessionStorage 中的临时状态(用于前端实时显示)
|
||||
const tempStatus = sessionStorage.getItem('merge_status_' + name);
|
||||
const storageKey = 'merge_status_' + name;
|
||||
const tempStatus = sessionStorage.getItem(storageKey);
|
||||
const tempStatusTime = sessionStorage.getItem(storageKey + '_time');
|
||||
console.log('[DEBUG] getMergeButtonHtml:', name, 'tempStatus:', tempStatus, 'merged:', merged, 'merging:', merging);
|
||||
|
||||
// 如果前端正在合并中,显示合并中
|
||||
if (tempStatus === 'merging') {
|
||||
return `<button class="bg-gray-300 text-gray-500 px-3 py-1 rounded text-xs cursor-not-allowed flex items-center" disabled>
|
||||
<i class="fa fa-spinner fa-spin mr-1"></i>合并中...
|
||||
</button>`;
|
||||
// 检查临时状态是否过期(超过5分钟视为过期)
|
||||
const now = Date.now();
|
||||
const statusExpired = tempStatusTime && (now - parseInt(tempStatusTime)) > 5 * 60 * 1000;
|
||||
|
||||
// 如果状态过期或无效,清除并视为无状态
|
||||
if (statusExpired || (tempStatus && !tempStatusTime)) {
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
// 继续检查后端状态
|
||||
} else if (tempStatus === 'merging') {
|
||||
// 如果后端已经完成合并但前端状态未更新,清除临时状态
|
||||
if (merged) {
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
} else {
|
||||
return `<button class="bg-gray-300 text-gray-500 px-3 py-1 rounded text-xs cursor-not-allowed flex items-center" disabled>
|
||||
<i class="fa fa-spinner fa-spin mr-1"></i>合并中...
|
||||
</button>`;
|
||||
}
|
||||
}
|
||||
// 如果后端返回正在合并中(锁文件存在)
|
||||
if (merging) {
|
||||
@@ -1481,12 +1543,14 @@
|
||||
// 如果前端成功状态且后端也返回已合并,显示成功
|
||||
if (tempStatus === 'success' && merged) {
|
||||
// 清除临时成功状态,让后端状态接管
|
||||
sessionStorage.removeItem('merge_status_' + name);
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
return `<button class="bg-gray-300 text-gray-500 px-3 py-1 rounded text-xs cursor-not-allowed" disabled>合并成功</button>`;
|
||||
}
|
||||
// 如果前端成功状态但后端返回未合并,说明目录被删除,重置状态
|
||||
if (tempStatus === 'success' && !merged) {
|
||||
sessionStorage.removeItem('merge_status_' + name);
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
}
|
||||
// 如果后端返回已合并,显示成功
|
||||
if (merged) {
|
||||
@@ -1498,7 +1562,9 @@
|
||||
// 启动合并任务
|
||||
async function startMerge(name, method, path) {
|
||||
// 先设置状态为"合并中"(存储到 sessionStorage)
|
||||
sessionStorage.setItem('merge_status_' + name, 'merging');
|
||||
const storageKey = 'merge_status_' + name;
|
||||
sessionStorage.setItem(storageKey, 'merging');
|
||||
sessionStorage.setItem(storageKey + '_time', Date.now().toString());
|
||||
// 刷新表格显示合并中状态
|
||||
loadTableData();
|
||||
|
||||
@@ -1517,19 +1583,21 @@
|
||||
|
||||
if (result.code === 0) {
|
||||
// 设置为成功状态,确保即使后端还没更新也能显示成功
|
||||
sessionStorage.setItem('merge_status_' + name, 'success');
|
||||
sessionStorage.setItem(storageKey, 'success');
|
||||
// 延迟刷新表格,用后端真实状态替换前端状态
|
||||
setTimeout(() => loadTableData(), 1500);
|
||||
} else {
|
||||
// 清除合并状态
|
||||
sessionStorage.removeItem('merge_status_' + name);
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
showMessage('失败', result.message || '合并失败', 'error');
|
||||
loadTableData();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[DEBUG] 合并失败:', error);
|
||||
// 清除合并状态
|
||||
sessionStorage.removeItem('merge_status_' + name);
|
||||
sessionStorage.removeItem(storageKey);
|
||||
sessionStorage.removeItem(storageKey + '_time');
|
||||
showMessage('错误', '合并失败: ' + error.message, 'error');
|
||||
loadTableData();
|
||||
}
|
||||
@@ -1546,6 +1614,29 @@
|
||||
window.open(`${API_BASE}/model-manage/trained-models/${encodeURIComponent(modelName)}/export`, '_blank');
|
||||
}
|
||||
|
||||
// 删除已训练模型的权重
|
||||
window.deleteTrainedWeight = function(modelName) {
|
||||
showConfirm('确认删除', `确定要删除模型 "${modelName}" 的权重文件吗?合并模型不受影响。`, async () => {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/model-manage/trained-models/${encodeURIComponent(modelName)}?type=lora`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
if (result.code === 0) {
|
||||
showMessage('成功', '权重已删除', 'success');
|
||||
// 清除该模型的合并状态缓存,让前端重新从后端获取状态
|
||||
sessionStorage.removeItem('merge_status_' + modelName);
|
||||
sessionStorage.removeItem('merge_status_' + modelName + '_time');
|
||||
} else {
|
||||
showMessage('错误', result.message || '删除失败', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除权重失败:', error);
|
||||
showMessage('错误', '删除失败: ' + error.message, 'error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑模型 - 全局
|
||||
window.editModel = function(modelId) {
|
||||
window.location.href = `model-manage-create.html?id=${modelId}`;
|
||||
@@ -1754,64 +1845,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Web日志系统 ============
|
||||
const webLogger = {
|
||||
_currentPage: 'main',
|
||||
|
||||
// 初始化当前页面名称
|
||||
init: function(pageName) {
|
||||
this._currentPage = pageName || 'unknown';
|
||||
},
|
||||
|
||||
// 发送日志到服务器
|
||||
_sendLog: async function(level, message) {
|
||||
try {
|
||||
await fetch(`${API_BASE}/web-log`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
level: level,
|
||||
message: message,
|
||||
page: this._currentPage,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
// 发送失败时只记录到控制台
|
||||
console.warn('日志发送失败:', e);
|
||||
}
|
||||
},
|
||||
|
||||
info: function(message) {
|
||||
console.log(`[INFO] ${message}`);
|
||||
this._sendLog('info', message);
|
||||
},
|
||||
|
||||
error: function(message) {
|
||||
console.error(`[ERROR] ${message}`);
|
||||
this._sendLog('error', message);
|
||||
},
|
||||
|
||||
warning: function(message) {
|
||||
console.warn(`[WARNING] ${message}`);
|
||||
this._sendLog('warning', message);
|
||||
},
|
||||
|
||||
debug: function(message) {
|
||||
console.debug(`[DEBUG] ${message}`);
|
||||
this._sendLog('debug', message);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载完成后初始化日志
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 获取当前页面名称
|
||||
const path = window.location.pathname;
|
||||
const pageName = path.split('/').pop().replace('.html', '') || 'main';
|
||||
webLogger.init(pageName);
|
||||
webLogger.info('页面加载完成');
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 自定义消息弹窗 -->
|
||||
|
||||
Reference in New Issue
Block a user