projects.js•18 kB
/**
* Memory Bank 项目管理页面脚本
*/
document.addEventListener('DOMContentLoaded', function() {
// 当前项目ID
let currentProjectId = null;
let currentDocumentType = null;
// API基础URL
const API_BASE_URL = '/api';
// DOM元素
const projectsList = document.getElementById('projectsList');
const projectDetail = document.getElementById('projectDetail');
const projectName = document.getElementById('projectName');
const documentsList = document.getElementById('documentsList');
const documentTitle = document.getElementById('documentTitle');
const documentViewer = document.getElementById('documentViewer');
const documentEditor = document.getElementById('documentEditor');
const markdownEditor = document.getElementById('markdownEditor');
const documentActions = document.getElementById('documentActions');
// 初始化
loadProjects();
/**
* 加载项目列表
*/
function loadProjects() {
fetch(`${API_BASE_URL}/projects`)
.then(response => response.json())
.then(data => {
if (data.success) {
renderProjects(data.data);
} else {
showError('加载项目列表失败', data.error);
}
})
.catch(error => {
showError('加载项目列表失败', error.message);
});
}
/**
* 渲染项目列表
*/
function renderProjects(projects) {
// 清空项目列表
projectsList.innerHTML = '';
if (projects.length === 0) {
projectsList.innerHTML = `
<tr>
<td colspan="5" class="text-center py-4">
<p class="text-muted mb-0">暂无项目,请创建新项目</p>
</td>
</tr>
`;
return;
}
// 添加项目列表
projects.forEach(project => {
const row = document.createElement('tr');
row.innerHTML = `
<td><strong>${project.name}</strong></td>
<td>${project.description || '无描述'}</td>
<td>${formatDate(project.createdAt)}</td>
<td>${formatDate(project.updatedAt)}</td>
<td>
<button class="btn btn-sm btn-primary view-project" data-id="${project.id}">查看</button>
</td>
`;
projectsList.appendChild(row);
});
// 添加查看项目事件
document.querySelectorAll('.view-project').forEach(button => {
button.addEventListener('click', function() {
const projectId = this.getAttribute('data-id');
viewProject(projectId);
});
});
}
/**
* 查看项目详情
*/
function viewProject(projectId) {
currentProjectId = projectId;
// 获取项目详情
fetch(`${API_BASE_URL}/projects/${projectId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
const project = data.data;
// 显示项目详情
projectName.textContent = project.name;
// 显示项目详情页面
hideElement(projectDetail, false);
// 加载项目文档
loadProjectDocuments(projectId);
} else {
showError('加载项目详情失败', data.error);
}
})
.catch(error => {
showError('加载项目详情失败', error.message);
});
}
/**
* 加载项目文档
*/
function loadProjectDocuments(projectId) {
fetch(`${API_BASE_URL}/projects/${projectId}/documents`)
.then(response => response.json())
.then(data => {
if (data.success) {
renderDocuments(data.data);
} else {
showError('加载项目文档失败', data.error);
}
})
.catch(error => {
showError('加载项目文档失败', error.message);
});
}
/**
* 渲染文档列表
*/
function renderDocuments(documents) {
// 清空文档列表
documentsList.innerHTML = '';
if (documents.length === 0) {
documentsList.innerHTML = '<p class="text-muted">暂无文档</p>';
return;
}
// 按文档类型重要性排序
const documentTypeOrder = {
'projectbrief': 1,
'tasks': 2,
'activeContext': 3,
'systemPatterns': 4,
'techContext': 5,
'progress': 6,
'reflections': 7
};
documents.sort((a, b) => {
const orderA = documentTypeOrder[a.type] || 100;
const orderB = documentTypeOrder[b.type] || 100;
return orderA - orderB;
});
// 添加文档列表
documents.forEach(doc => {
const listItem = document.createElement('a');
listItem.href = '#';
listItem.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center';
listItem.setAttribute('data-type', doc.type);
// 设置文档显示名称
let displayName = doc.name;
if (doc.type === 'projectbrief') displayName = '项目概述';
if (doc.type === 'tasks') displayName = '任务清单';
if (doc.type === 'activeContext') displayName = '当前上下文';
if (doc.type === 'systemPatterns') displayName = '系统架构';
if (doc.type === 'techContext') displayName = '技术上下文';
if (doc.type === 'progress') displayName = '项目进度';
if (doc.type === 'reflections') displayName = '项目反思';
listItem.innerHTML = `
${displayName}
<span class="badge bg-secondary rounded-pill">${formatDate(doc.updatedAt, true)}</span>
`;
documentsList.appendChild(listItem);
// 添加点击事件
listItem.addEventListener('click', function(e) {
e.preventDefault();
const docType = this.getAttribute('data-type');
viewDocument(docType, displayName);
// 高亮当前文档
document.querySelectorAll('#documentsList a').forEach(item => {
item.classList.remove('active');
});
this.classList.add('active');
});
});
}
/**
* 查看文档内容
*/
function viewDocument(type, displayName) {
currentDocumentType = type;
// 获取文档内容
fetch(`${API_BASE_URL}/projects/${currentProjectId}/documents/${type}`)
.then(response => response.json())
.then(data => {
if (data.success) {
const doc = data.data;
// 显示文档标题
documentTitle.textContent = displayName;
// 显示文档内容
documentViewer.innerHTML = doc.html || marked(doc.content);
// 高亮代码块
document.querySelectorAll('pre code').forEach(block => {
hljs.highlightElement(block);
});
// 存储原始markdown内容用于编辑
markdownEditor.value = doc.content;
// 显示文档操作按钮
hideElement(documentActions, false);
// 隐藏编辑器,显示查看器
hideElement(documentEditor, true);
hideElement(documentViewer, false);
} else {
showError('加载文档内容失败', data.error);
}
})
.catch(error => {
showError('加载文档内容失败', error.message);
});
}
/**
* 格式化日期
*/
function formatDate(dateString, shortFormat = false) {
if (!dateString) return '未知';
const date = new Date(dateString);
if (shortFormat) {
return new Intl.DateTimeFormat('zh-CN', {
month: 'numeric',
day: 'numeric'
}).format(date);
}
return new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}).format(date);
}
/**
* 显示错误消息
*/
function showError(title, message) {
console.error(title, message);
// 这里可以添加显示错误提示的代码,如使用Bootstrap的Toast或Alert
alert(`${title}: ${message}`);
}
/**
* 隐藏或显示元素
*/
function hideElement(element, hide = true) {
if (hide) {
element.classList.add('d-none');
} else {
element.classList.remove('d-none');
}
}
// 返回项目列表按钮
document.getElementById('backToListBtn').addEventListener('click', function() {
hideElement(projectDetail, true);
currentProjectId = null;
currentDocumentType = null;
});
// 编辑文档按钮
document.getElementById('editDocumentBtn').addEventListener('click', function() {
// 显示编辑器,隐藏查看器
hideElement(documentViewer, true);
hideElement(documentEditor, false);
});
// 取消编辑按钮
document.getElementById('cancelEditBtn').addEventListener('click', function() {
// 隐藏编辑器,显示查看器
hideElement(documentEditor, true);
hideElement(documentViewer, false);
});
// 保存文档按钮
document.getElementById('saveDocumentBtn').addEventListener('click', function() {
const content = markdownEditor.value;
// 保存文档内容
fetch(`${API_BASE_URL}/projects/${currentProjectId}/documents/${currentDocumentType}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: content
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 重新加载文档
const displayName = documentTitle.textContent;
viewDocument(currentDocumentType, displayName);
} else {
showError('保存文档失败', data.error);
}
})
.catch(error => {
showError('保存文档失败', error.message);
});
});
// 编辑项目按钮
document.getElementById('editProjectBtn').addEventListener('click', function() {
// 加载项目信息到编辑表单
fetch(`${API_BASE_URL}/projects/${currentProjectId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
const project = data.data;
document.getElementById('editProjectNameInput').value = project.name;
document.getElementById('editProjectDescriptionInput').value = project.description || '';
// 显示编辑项目模态框
const editProjectModal = new bootstrap.Modal(document.getElementById('editProjectModal'));
editProjectModal.show();
} else {
showError('加载项目信息失败', data.error);
}
})
.catch(error => {
showError('加载项目信息失败', error.message);
});
});
// 保存项目按钮
document.getElementById('saveProjectBtn').addEventListener('click', function() {
const name = document.getElementById('editProjectNameInput').value;
const description = document.getElementById('editProjectDescriptionInput').value;
if (!name) {
showError('保存项目失败', '项目名称不能为空');
return;
}
// 更新项目信息
fetch(`${API_BASE_URL}/projects/${currentProjectId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: name,
description: description
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('editProjectModal')).hide();
// 更新项目名称
projectName.textContent = name;
// 重新加载项目列表
loadProjects();
} else {
showError('保存项目失败', data.error);
}
})
.catch(error => {
showError('保存项目失败', error.message);
});
});
// 删除项目按钮
document.getElementById('deleteProjectBtn').addEventListener('click', function() {
if (!confirm('确定要删除此项目吗?此操作不可撤销!')) {
return;
}
// 删除项目
fetch(`${API_BASE_URL}/projects/${currentProjectId}`, {
method: 'DELETE'
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('editProjectModal')).hide();
// 返回项目列表
hideElement(projectDetail, true);
currentProjectId = null;
// 重新加载项目列表
loadProjects();
} else {
showError('删除项目失败', data.error);
}
})
.catch(error => {
showError('删除项目失败', error.message);
});
});
// 创建项目按钮
document.getElementById('createProjectBtn').addEventListener('click', function() {
const name = document.getElementById('projectNameInput').value;
const description = document.getElementById('projectDescriptionInput').value;
if (!name) {
showError('创建项目失败', '项目名称不能为空');
return;
}
// 创建项目
fetch(`${API_BASE_URL}/projects`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: name,
description: description
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('createProjectModal')).hide();
// 重置表单
document.getElementById('createProjectForm').reset();
// 重新加载项目列表
loadProjects();
// 查看新创建的项目
viewProject(data.data.id);
} else {
showError('创建项目失败', data.error);
}
})
.catch(error => {
showError('创建项目失败', error.message);
});
});
// 导出项目按钮
document.getElementById('exportProjectBtn').addEventListener('click', function() {
const format = prompt('请选择导出格式 (markdown 或 html):', 'markdown');
if (!format) return;
if (format !== 'markdown' && format !== 'html') {
showError('导出项目失败', '不支持的导出格式,请选择 markdown 或 html');
return;
}
// 调用导出API
fetch(`${API_BASE_URL}/projects/${currentProjectId}/export`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
format: format
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(`项目导出成功!\n导出路径: ${data.data.exportDir}`);
} else {
showError('导出项目失败', data.error);
}
})
.catch(error => {
showError('导出项目失败', error.message);
});
});
});