// ============================================================
// 状态管理
// ============================================================
const state = {
docs: [],
page: 1,
size: 10,
total: 0,
currentInstanceId: null,
history: [],
historyPage: 1,
historySize: 10,
historyTotal: 0,
pollInterval: null,
currentTaskId: null,
genInterfaces: [],
};
// ============================================================
// DOM 引用
// ============================================================
const docList = document.getElementById('docList');
const listCount = document.getElementById('listCount');
const pagination = document.getElementById('pagination');
const pageInfo = document.getElementById('pageInfo');
const prevPage = document.getElementById('prevPage');
const nextPage = document.getElementById('nextPage');
// 添加文档
const addDocBtn = document.getElementById('addDocBtn');
const addDocModal = document.getElementById('addDocModal');
const addDocModalClose = document.getElementById('addDocModalClose');
const addCancelBtn = document.getElementById('addCancelBtn');
const addSubmitBtn = document.getElementById('addSubmitBtn');
const addForm = document.getElementById('addDocForm');
const addUploadZone = document.getElementById('addUploadZone');
const addFileInput = document.getElementById('addFileInput');
const addFileInfo = document.getElementById('addFileInfo');
const addFileName = document.getElementById('addFileName');
const addRemoveFile = document.getElementById('addRemoveFile');
// 修改文档
const editDocModal = document.getElementById('editDocModal');
const editDocModalClose = document.getElementById('editDocModalClose');
const editCancelBtn = document.getElementById('editCancelBtn');
const editSubmitBtn = document.getElementById('editSubmitBtn');
const editForm = document.getElementById('editDocForm');
const editInstanceId = document.getElementById('editInstanceId');
const editDesc = document.getElementById('editDesc');
const editRefinedDocRaw = document.getElementById('editRefinedDocRaw');
const editRefinedDocPreview = document.getElementById('editRefinedDocPreview');
const editInterfaceList = document.getElementById('editInterfaceList');
const toggleMarkdownView = document.getElementById('toggleMarkdownView');
// 生成代码
const generateModal = document.getElementById('generateModal');
const generateModalClose = document.getElementById('generateModalClose');
const genCancelBtn = document.getElementById('genCancelBtn');
const genSubmitBtn = document.getElementById('genSubmitBtn');
const genForm = document.getElementById('generateForm');
const genInstanceId = document.getElementById('genInstanceId');
const genInterfacesList = document.getElementById('genInterfacesList');
const genInstanceIdHidden = document.getElementById('genInstanceIdHidden');
const genCodeType = document.getElementById('genCodeType');
const genSdkName = document.getElementById('genSdkName');
const genGenerateType = document.getElementById('genGenerateType');
const genApiKey = document.getElementById('genApiKey');
const genBaseUrl = document.getElementById('genBaseUrl');
const genModel = document.getElementById('genModel');
const genMsgContent = document.getElementById('genMsgContent');
const genMesSendToken = document.getElementById('genMesSendToken');
// 历史任务
const historyModal = document.getElementById('historyModal');
const historyModalClose = document.getElementById('historyModalClose');
const historyInstanceId = document.getElementById('historyInstanceId');
const historyList = document.getElementById('historyList');
const historyPagination = document.getElementById('historyPagination');
const historyPageInfo = document.getElementById('historyPageInfo');
const historyPrevPage = document.getElementById('historyPrevPage');
const historyNextPage = document.getElementById('historyNextPage');
const refreshHistoryBtn = document.getElementById('refreshHistoryBtn');
// 任务详情
const taskDetailModal = document.getElementById('taskDetailModal');
const taskDetailModalClose = document.getElementById('taskDetailModalClose');
const taskDetailId = document.getElementById('taskDetailId');
const taskDetailContent = document.getElementById('taskDetailContent');
// 用量详情
const usageModal = document.getElementById('usageModal');
const usageModalClose = document.getElementById('usageModalClose');
const usageContent = document.getElementById('usageContent');
// 刷新
const refreshListBtn = document.getElementById('refreshListBtn');
// ============================================================
// 工具函数
// ============================================================
function formatTime(isoStr) {
if (!isoStr) return '-';
const d = new Date(isoStr);
return d.toLocaleString('zh-CN');
}
function getGenerateTypeLabel(type) {
const map = {
1: '客户端 SDK',
2: '服务端骨架',
};
return map[type] || type || '-';
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function parseInterfaces(interfaceStr) {
if (!interfaceStr) return [];
try {
return typeof interfaceStr === 'string' ? JSON.parse(interfaceStr) : interfaceStr;
} catch {
return [];
}
}
// ============================================================
// 文档列表
// ============================================================
async function loadDocs(page = state.page) {
try {
const formData = new URLSearchParams();
formData.append('page', String(page));
formData.append('page_size', String(state.size));
const response = await fetch('/api/v1/refine/list', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '加载失败');
}
state.docs = data.data.data || [];
state.total = data.data.total || 0;
state.page = page;
renderDocs();
renderPagination();
} catch (err) {
console.error('加载列表失败:', err);
docList.innerHTML = `
加载失败: ${err.message}
`;
}
}
function renderDocs() {
if (state.docs.length === 0) {
docList.innerHTML = '暂无文档实例,点击「添加文档实例」创建
';
listCount.textContent = '共 0 个';
return;
}
let html = '';
state.docs.forEach(doc => {
const interfaces = parseInterfaces(doc.interface);
const interfaceTags = interfaces.map(i =>
`${i.method || 'POST'} ${escapeHtml(i.summary || '')}`
).join('');
html += `
${escapeHtml(doc.desc || '未命名')}
🆔 ${doc.instance_id}
📅 ${formatTime(doc.created_at)}
📊 ${interfaces.length} 个接口
${doc.status === 1 ? '✅ 有效' : '❌ 无效'}
${interfaceTags}
`;
});
docList.innerHTML = html;
listCount.textContent = `共 ${state.total} 个`;
docList.querySelectorAll('.btn-edit').forEach(btn => {
btn.addEventListener('click', () => openEditModal(btn.dataset.instanceId));
});
docList.querySelectorAll('.btn-generate').forEach(btn => {
btn.addEventListener('click', () => openGenerateModal(btn.dataset.instanceId));
});
docList.querySelectorAll('.btn-history').forEach(btn => {
btn.addEventListener('click', () => openHistoryModal(btn.dataset.instanceId));
});
}
function renderPagination() {
const totalPages = Math.ceil(state.total / state.size);
if (totalPages <= 1) {
pagination.style.display = 'none';
return;
}
pagination.style.display = 'flex';
pageInfo.textContent = `${state.page} / ${totalPages}`;
prevPage.disabled = state.page <= 1;
nextPage.disabled = state.page >= totalPages;
}
prevPage.addEventListener('click', () => {
if (state.page > 1) loadDocs(state.page - 1);
});
nextPage.addEventListener('click', () => {
const totalPages = Math.ceil(state.total / state.size);
if (state.page < totalPages) loadDocs(state.page + 1);
});
refreshListBtn.addEventListener('click', () => loadDocs(state.page));
// ============================================================
// 添加文档实例
// ============================================================
let addFileData = null;
addDocBtn.addEventListener('click', () => {
addFileData = null;
addFileInfo.style.display = 'none';
addUploadZone.style.display = 'block';
addFileInput.value = '';
addForm.reset();
addSubmitBtn.disabled = false;
addSubmitBtn.querySelector('.btn-text').textContent = '📝 精炼并保存';
addSubmitBtn.querySelector('.btn-spinner').style.display = 'none';
addDocModal.style.display = 'flex';
});
addDocModalClose.addEventListener('click', () => { addDocModal.style.display = 'none'; });
addCancelBtn.addEventListener('click', () => { addDocModal.style.display = 'none'; });
addUploadZone.addEventListener('click', () => addFileInput.click());
addUploadZone.addEventListener('dragover', (e) => { e.preventDefault(); addUploadZone.classList.add('dragover'); });
addUploadZone.addEventListener('dragleave', () => { addUploadZone.classList.remove('dragover'); });
addUploadZone.addEventListener('drop', (e) => {
e.preventDefault();
addUploadZone.classList.remove('dragover');
if (e.dataTransfer.files.length > 0) {
handleAddFile(e.dataTransfer.files[0]);
}
});
addFileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
handleAddFile(e.target.files[0]);
}
});
addRemoveFile.addEventListener('click', () => {
addFileData = null;
addFileInfo.style.display = 'none';
addUploadZone.style.display = 'block';
addFileInput.value = '';
});
function handleAddFile(file) {
const validTypes = ['.md', '.txt', '.doc', '.docx', '.pdf'];
const ext = '.' + file.name.split('.').pop().toLowerCase();
if (!validTypes.includes(ext)) {
alert('不支持的文件类型');
return;
}
if (file.size > 50 * 1024 * 1024) {
alert('文件大小超过 50MB');
return;
}
addFileData = file;
addFileName.textContent = file.name;
addFileInfo.style.display = 'flex';
addUploadZone.style.display = 'none';
}
addForm.addEventListener('submit', async (e) => {
e.preventDefault();
if (!addFileData) {
alert('请上传文档文件');
return;
}
const apiKey = document.getElementById('addApiKey').value.trim();
const baseUrl = document.getElementById('addBaseUrl').value.trim();
const model = document.getElementById('addModel').value.trim();
const desc = document.getElementById('addDesc').value.trim();
if (!apiKey) { alert('请输入 API Key'); return; }
if (!baseUrl) { alert('请输入 Base URL'); return; }
if (!model) { alert('请输入大模型名称'); return; }
addSubmitBtn.disabled = true;
addSubmitBtn.querySelector('.btn-text').textContent = '精炼中...';
addSubmitBtn.querySelector('.btn-spinner').style.display = 'inline-block';
const formData = new FormData();
formData.append('file', addFileData);
formData.append('llm_api_key', apiKey);
formData.append('llm_base_url', baseUrl);
formData.append('llm_model', model);
formData.append('desc', desc || addFileData.name);
try {
const response = await fetch('/api/v1/refine', {
method: 'POST',
body: formData,
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '精炼失败');
}
alert('✅ 文档精炼成功!');
addDocModal.style.display = 'none';
loadDocs(state.page);
} catch (err) {
alert('❌ ' + err.message);
} finally {
addSubmitBtn.disabled = false;
addSubmitBtn.querySelector('.btn-text').textContent = '📝 精炼并保存';
addSubmitBtn.querySelector('.btn-spinner').style.display = 'none';
}
});
// ============================================================
// 修改文档(接口列表只读展示,Markdown 渲染)
// ============================================================
let editInterfaces = [];
let showRawMarkdown = false;
async function openEditModal(instanceId) {
try {
const formData = new URLSearchParams();
formData.append('page', '1');
formData.append('page_size', '100');
formData.append('instance_id', instanceId);
const response = await fetch('/api/v1/refine/list', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
if (data.code !== 200 || !data.data.data || data.data.data.length === 0) {
throw new Error('文档不存在');
}
const doc = data.data.data[0];
state.currentInstanceId = instanceId;
editInstanceId.textContent = 'ID: ' + instanceId;
editDesc.value = doc.desc || '';
// 接口列表只读展示
editInterfaces = parseInterfaces(doc.interface);
renderEditInterfaces();
// Markdown 渲染精炼文档
const refinedDoc = doc.refined_doc || '';
editRefinedDocPreview.innerHTML = renderMarkdown(refinedDoc);
editRefinedDocRaw.value = refinedDoc;
// 默认显示预览,隐藏源码
showRawMarkdown = false;
editRefinedDocPreview.style.display = 'block';
editRefinedDocRaw.style.display = 'none';
if (toggleMarkdownView) {
toggleMarkdownView.textContent = '✏️ 修改';
}
editDocModal.style.display = 'flex';
} catch (err) {
alert('加载文档失败: ' + err.message);
}
}
function renderEditInterfaces() {
const container = editInterfaceList;
container.innerHTML = '';
if (!editInterfaces || editInterfaces.length === 0) {
container.innerHTML = '暂无接口';
return;
}
editInterfaces.forEach(iface => {
const tag = document.createElement('span');
tag.className = 'tag';
tag.innerHTML = `
${escapeHtml(iface.method || 'POST')}
${escapeHtml(iface.summary || '')}
`;
container.appendChild(tag);
});
}
// Markdown 渲染(支持标题、代码块、表格、列表)
function renderMarkdown(text) {
if (!text) return '暂无内容';
let html = text;
// 代码块 ``` ... ```
html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (match, lang, code) => {
return `${escapeHtml(code)}
`;
});
// 标题
html = html.replace(/^### (.*$)/gm, '$1
');
html = html.replace(/^## (.*$)/gm, '$1
');
html = html.replace(/^# (.*$)/gm, '$1
');
// 表格
html = html.replace(/\|(.+)\|\n\|[-:| ]+\|\n((?:\|.+\|\n?)*)/g, (match, header, rows) => {
const headers = header.split('|').filter(h => h.trim());
const headerHtml = `${headers.map(h => `| ${h.trim()} | `).join('')}
`;
const bodyRows = rows.split('\n').filter(r => r.trim()).map(row => {
const cells = row.split('|').filter(c => c.trim());
return `${cells.map(c => `| ${c.trim()} | `).join('')}
`;
});
return `${headerHtml}${bodyRows.join('')}
`;
});
// 列表
html = html.replace(/^- (.*$)/gm, '$1');
html = html.replace(/((?:.*<\/li>\n?)+)/g, '');
// 粗体
html = html.replace(/\*\*(.*?)\*\*/g, '$1');
// 换行
html = html.replace(/\n/g, '
');
return html;
}
// 切换 Markdown 源码/预览(修改按钮)
if (toggleMarkdownView) {
toggleMarkdownView.addEventListener('click', function() {
showRawMarkdown = !showRawMarkdown;
if (showRawMarkdown) {
editRefinedDocPreview.style.display = 'none';
editRefinedDocRaw.style.display = 'block';
this.textContent = '📄 预览';
} else {
editRefinedDocPreview.style.display = 'block';
editRefinedDocRaw.style.display = 'none';
// 重新渲染预览
editRefinedDocPreview.innerHTML = renderMarkdown(editRefinedDocRaw.value);
this.textContent = '✏️ 修改';
}
});
}
editDocModalClose.addEventListener('click', () => { editDocModal.style.display = 'none'; });
editCancelBtn.addEventListener('click', () => { editDocModal.style.display = 'none'; });
editForm.addEventListener('submit', async (e) => {
e.preventDefault();
const refinedDoc = editRefinedDocRaw.value.trim();
const desc = editDesc.value.trim();
editSubmitBtn.disabled = true;
editSubmitBtn.querySelector('.btn-text').textContent = '保存中...';
editSubmitBtn.querySelector('.btn-spinner').style.display = 'inline-block';
try {
const formData = new URLSearchParams();
formData.append('instance_id', state.currentInstanceId);
if (refinedDoc) formData.append('refined_doc', refinedDoc);
if (desc) formData.append('desc', desc);
const response = await fetch('/api/v1/refine/update', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '保存失败');
}
alert('✅ 保存成功!');
editDocModal.style.display = 'none';
loadDocs(state.page);
} catch (err) {
alert('❌ ' + err.message);
} finally {
editSubmitBtn.disabled = false;
editSubmitBtn.querySelector('.btn-text').textContent = '💾 保存修改';
editSubmitBtn.querySelector('.btn-spinner').style.display = 'none';
}
});
// ============================================================
// 生成代码(接口可勾选,默认全选)
// ============================================================
async function openGenerateModal(instanceId) {
state.currentInstanceId = instanceId;
genInstanceId.textContent = 'ID: ' + instanceId;
genInstanceIdHidden.value = instanceId;
genCodeType.value = 'go';
genForm.reset();
genSubmitBtn.disabled = false;
genSubmitBtn.querySelector('.btn-text').textContent = '🚀 生成代码';
genSubmitBtn.querySelector('.btn-spinner').style.display = 'none';
// 加载接口列表(可勾选)
try {
const formData = new URLSearchParams();
formData.append('page', '1');
formData.append('page_size', '100');
formData.append('instance_id', instanceId);
const response = await fetch('/api/v1/refine/list', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
const container = genInterfacesList;
container.innerHTML = '';
if (data.code === 200 && data.data.data && data.data.data.length > 0) {
const doc = data.data.data[0];
const interfaces = parseInterfaces(doc.interface);
state.genInterfaces = interfaces;
if (interfaces.length === 0) {
container.innerHTML = '暂无接口';
} else {
// 默认全选
interfaces.forEach((iface, index) => {
const label = document.createElement('label');
label.className = 'checkbox-item checked';
label.innerHTML = `
${escapeHtml(iface.method || 'POST')}
${escapeHtml(iface.summary || '')}
`;
const checkbox = label.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', function() {
label.classList.toggle('checked', this.checked);
});
container.appendChild(label);
});
}
} else {
container.innerHTML = '加载接口列表失败';
}
} catch (err) {
console.error('加载接口列表失败:', err);
genInterfacesList.innerHTML = '加载接口列表失败';
}
generateModal.style.display = 'flex';
}
generateModalClose.addEventListener('click', () => { generateModal.style.display = 'none'; });
genCancelBtn.addEventListener('click', () => { generateModal.style.display = 'none'; });
genForm.addEventListener('submit', async (e) => {
e.preventDefault();
const instanceId = genInstanceIdHidden.value;
const sdkName = genSdkName.value.trim();
const generateType = genGenerateType.value;
const apiKey = genApiKey.value.trim();
const baseUrl = genBaseUrl.value.trim();
const model = genModel.value.trim();
const msgContent = genMsgContent.value.trim();
const mesSendToken = genMesSendToken.value.trim();
// 获取选中的接口
const checkboxes = document.querySelectorAll('#genInterfacesList input[type="checkbox"]:checked');
const selectedInterfaces = [];
checkboxes.forEach(cb => {
const idx = parseInt(cb.dataset.index);
if (state.genInterfaces && state.genInterfaces[idx]) {
selectedInterfaces.push(state.genInterfaces[idx]);
}
});
if (selectedInterfaces.length === 0) {
alert('请至少选择一个接口');
return;
}
if (!instanceId) { alert('文档实例ID不能为空'); return; }
if (!sdkName) { alert('请输入仓库名称'); return; }
if (!apiKey) { alert('请输入 API Key'); return; }
if (!baseUrl) { alert('请输入 Base URL'); return; }
if (!model) { alert('请输入大模型名称'); return; }
genSubmitBtn.disabled = true;
genSubmitBtn.querySelector('.btn-text').textContent = '提交中...';
genSubmitBtn.querySelector('.btn-spinner').style.display = 'inline-block';
try {
const formData = new URLSearchParams();
formData.append('instance_id', instanceId);
formData.append('llm_api_key', apiKey);
formData.append('llm_base_url', baseUrl);
formData.append('llm_model', model);
formData.append('desc', sdkName);
formData.append('code_type', 'go');
formData.append('generate_type', generateType);
formData.append('interfaces', JSON.stringify(selectedInterfaces));
if (msgContent) formData.append('msg_content', msgContent);
if (mesSendToken) formData.append('mes_send_token', mesSendToken);
const response = await fetch('/api/v1/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '提交失败');
}
const taskId = data.data?.task_id || data.task_id;
alert(`✅ 任务已提交!任务ID: ${taskId}`);
generateModal.style.display = 'none';
loadDocs(state.page);
} catch (err) {
alert('❌ ' + err.message);
} finally {
genSubmitBtn.disabled = false;
genSubmitBtn.querySelector('.btn-text').textContent = '🚀 生成代码';
genSubmitBtn.querySelector('.btn-spinner').style.display = 'none';
}
});
// ============================================================
// 历史任务列表(美化版)
// ============================================================
async function openHistoryModal(instanceId) {
state.currentInstanceId = instanceId;
historyInstanceId.textContent = 'ID: ' + instanceId;
state.historyPage = 1;
historyModal.style.display = 'flex';
await loadHistory(instanceId, 1);
}
historyModalClose.addEventListener('click', () => { historyModal.style.display = 'none'; });
refreshHistoryBtn.addEventListener('click', () => {
if (state.currentInstanceId) {
loadHistory(state.currentInstanceId, state.historyPage);
}
});
async function loadHistory(instanceId, page = 1) {
try {
const formData = new URLSearchParams();
formData.append('page', String(page));
formData.append('page_size', String(state.historySize));
formData.append('task_id', instanceId);
const response = await fetch('/api/v1/tasks/list', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: formData.toString(),
});
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '加载失败');
}
state.history = data.data.data || [];
state.historyTotal = data.data.total || 0;
state.historyPage = page;
renderHistory();
} catch (err) {
historyList.innerHTML = `加载失败: ${err.message}
`;
}
}
function renderHistory() {
if (state.history.length === 0) {
historyList.innerHTML = '暂无历史任务
';
historyPagination.style.display = 'none';
return;
}
let html = '';
state.history.forEach(task => {
const statusClass = task.task_status === 'completed' ? 'completed' :
task.task_status === 'failed' ? 'failed' :
task.task_status === 'pending' ? 'pending' : 'processing';
const interfaces = parseInterfaces(task.interfaces);
let usageSummary = '';
let usageDetail = null;
try {
const ua = typeof task.use_age === 'string' ? JSON.parse(task.use_age) : task.use_age;
if (ua) {
usageSummary = `总: ${ua.total_tokens || 0}`;
usageDetail = ua;
}
} catch {}
html += `
`;
});
historyList.innerHTML = html;
historyList.querySelectorAll('.history-item').forEach(item => {
item.addEventListener('click', () => {
const taskId = item.dataset.taskId;
openTaskDetail(taskId);
});
});
const totalPages = Math.ceil(state.historyTotal / state.historySize);
if (totalPages <= 1) {
historyPagination.style.display = 'none';
} else {
historyPagination.style.display = 'flex';
historyPageInfo.textContent = `${state.historyPage} / ${totalPages}`;
historyPrevPage.disabled = state.historyPage <= 1;
historyNextPage.disabled = state.historyPage >= totalPages;
}
}
historyPrevPage.addEventListener('click', () => {
if (state.historyPage > 1 && state.currentInstanceId) {
loadHistory(state.currentInstanceId, state.historyPage - 1);
}
});
historyNextPage.addEventListener('click', () => {
const totalPages = Math.ceil(state.historyTotal / state.historySize);
if (state.historyPage < totalPages && state.currentInstanceId) {
loadHistory(state.currentInstanceId, state.historyPage + 1);
}
});
// ============================================================
// 用量详情弹窗(美化版)
// ============================================================
function showUsageDetail(el) {
const item = el.closest('.history-item');
if (!item) return;
const usageData = JSON.parse(item.dataset.usage || '{}');
const content = usageContent;
if (!usageData || Object.keys(usageData).length === 0 || usageData.total_tokens === 0) {
content.innerHTML = '暂无用量数据
';
usageModal.style.display = 'flex';
return;
}
const promptTokens = usageData.prompt_tokens || 0;
const completionTokens = usageData.completion_tokens || 0;
const totalTokens = usageData.total_tokens || 0;
const detail = usageData.detail || [];
let detailHtml = '';
if (detail.length > 0) {
detailHtml = `
分步详情
${detail.map(d => `
${escapeHtml(d.state_name || '未知步骤')}
${d.total_tokens || 0} tokens
`).join('')}
`;
}
content.innerHTML = `
${promptTokens}
输入 Tokens (Prompt)
${completionTokens}
输出 Tokens (Completion)
${detailHtml}
`;
usageModal.style.display = 'flex';
}
usageModalClose.addEventListener('click', () => {
usageModal.style.display = 'none';
});
// 点击弹窗外关闭
usageModal.addEventListener('click', (e) => {
if (e.target === usageModal) {
usageModal.style.display = 'none';
}
});
// ============================================================
// 任务详情
// ============================================================
async function openTaskDetail(taskId) {
taskDetailId.textContent = 'ID: ' + taskId;
taskDetailContent.innerHTML = '加载中...
';
taskDetailModal.style.display = 'flex';
try {
const response = await fetch(`/api/v1/tasks/${taskId}`);
const data = await response.json();
if (data.code !== 200) {
throw new Error(data.message || '加载失败');
}
const task = data.data?.Task || data.data || {};
renderTaskDetail(task);
} catch (err) {
taskDetailContent.innerHTML = `加载失败: ${err.message}
`;
}
}
function renderTaskDetail(task) {
const interfaces = parseInterfaces(task.interfaces);
const interfaceTags = interfaces.map(i =>
`${i.method || 'POST'} ${escapeHtml(i.summary || '')}`
).join('');
let useAge = '';
try {
const ua = typeof task.use_age === 'string' ? JSON.parse(task.use_age) : task.use_age;
if (ua) {
useAge = `
总 Tokens: ${ua.total_tokens || 0}
${ua.detail ? ua.detail.map(d =>
`${d.state_name || '未知'}: ${d.total_tokens || 0}`
).join('') : ''}
`;
}
} catch {}
taskDetailContent.innerHTML = `
任务ID
${task.task_id}
状态
${task.task_status}
仓库名称
${escapeHtml(task.desc || '-')}
生成类型
${getGenerateTypeLabel(task.generate_type)}
代码类型
${escapeHtml(task.code_type || 'go')}
大模型
${escapeHtml(task.llm_model || '-')}
接口列表
${interfaceTags || '-'}
创建时间
${formatTime(task.created_at)}
完成时间
${formatTime(task.completed_at)}
错误信息
${escapeHtml(task.error || '-')}
Token 用量
${useAge || '-'}
`;
}
taskDetailModalClose.addEventListener('click', () => { taskDetailModal.style.display = 'none'; });
// ============================================================
// 初始化
// ============================================================
loadDocs(1);