978 lines
30 KiB
JavaScript
978 lines
30 KiB
JavaScript
// 项目数据
|
||
const projectsData = [
|
||
{
|
||
id: 1,
|
||
title: "智慧工厂",
|
||
date: "2024-06-08 15:56:35",
|
||
type: "industrial",
|
||
image: "🏭",
|
||
favorite: true
|
||
},
|
||
{
|
||
id: 2,
|
||
title: "智慧水务",
|
||
date: "2023-01-10 12:09:04",
|
||
type: "smart",
|
||
image: "💧",
|
||
favorite: false
|
||
},
|
||
{
|
||
id: 3,
|
||
title: "数字工厂",
|
||
date: "2024-06-07 06:57:46",
|
||
type: "industrial",
|
||
image: "🏗️",
|
||
favorite: false
|
||
},
|
||
{
|
||
id: 4,
|
||
title: "智慧监控",
|
||
date: "2024-07-28 17:38:02",
|
||
type: "smart",
|
||
image: "📊",
|
||
favorite: true
|
||
},
|
||
{
|
||
id: 5,
|
||
title: "工业设计平台",
|
||
date: "2025-02-28 18:00:05",
|
||
type: "design",
|
||
image: "🎨",
|
||
favorite: false
|
||
}
|
||
];
|
||
|
||
// DOM 元素
|
||
const createProjectBtn = document.getElementById('createProjectBtn');
|
||
const createProjectModal = document.getElementById('createProjectModal');
|
||
const importProjectModal = document.getElementById('importProjectModal');
|
||
const closeCreateModal = document.getElementById('closeCreateModal');
|
||
const closeImportModal = document.getElementById('closeImportModal');
|
||
const cancelCreate = document.getElementById('cancelCreate');
|
||
const cancelImport = document.getElementById('cancelImport');
|
||
const confirmCreate = document.getElementById('confirmCreate');
|
||
const confirmImport = document.getElementById('confirmImport');
|
||
const projectsGrid = document.getElementById('projectsGrid');
|
||
const uploadZone = document.getElementById('uploadZone');
|
||
const fileInput = document.getElementById('fileInput');
|
||
const projectNameInput = document.getElementById('projectName');
|
||
|
||
// 搜索和过滤相关元素
|
||
let searchBtn, filterBtn, searchFilterArea, searchInput, sortSelect, typeFilter;
|
||
|
||
// 过滤和排序状态
|
||
let filteredProjects = [...projectsData];
|
||
let currentSearchTerm = '';
|
||
let currentSortBy = 'date-desc';
|
||
let currentTypeFilter = 'all';
|
||
|
||
// 初始化
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
initializeSearchElements();
|
||
renderProjects();
|
||
initEventListeners();
|
||
});
|
||
|
||
// 初始化搜索相关元素
|
||
function initializeSearchElements() {
|
||
searchBtn = document.getElementById('searchBtn');
|
||
filterBtn = document.getElementById('filterBtn');
|
||
searchFilterArea = document.getElementById('searchFilterArea');
|
||
searchInput = document.getElementById('searchInput');
|
||
sortSelect = document.getElementById('sortSelect');
|
||
typeFilter = document.getElementById('typeFilter');
|
||
}
|
||
|
||
// 渲染项目列表
|
||
function renderProjects() {
|
||
projectsGrid.innerHTML = '';
|
||
|
||
// 应用过滤和排序
|
||
applyFiltersAndSort();
|
||
|
||
if (filteredProjects.length === 0) {
|
||
projectsGrid.innerHTML = `
|
||
<div class="no-projects">
|
||
<i class="fas fa-folder-open"></i>
|
||
<p>没有找到匹配的项目</p>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
filteredProjects.forEach(project => {
|
||
const projectCard = document.createElement('div');
|
||
projectCard.className = 'project-card';
|
||
projectCard.innerHTML = `
|
||
<div class="project-header">
|
||
<div class="project-title">${project.title}</div>
|
||
<div class="project-header-actions">
|
||
${project.favorite ? '<i class="fas fa-star favorite-icon" title="已收藏"></i>' : ''}
|
||
<div class="project-menu" data-project-id="${project.id}">
|
||
<i class="fas fa-ellipsis-v"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="project-image">
|
||
${project.image}
|
||
<div class="project-type-badge">${getProjectTypeLabel(project.type)}</div>
|
||
</div>
|
||
<div class="project-footer">
|
||
<div class="project-date">${project.date}</div>
|
||
</div>
|
||
`;
|
||
|
||
// 项目卡片点击事件(排除菜单按钮)
|
||
projectCard.addEventListener('click', (e) => {
|
||
if (!e.target.closest('.project-menu')) {
|
||
openProject(project.id);
|
||
}
|
||
});
|
||
|
||
// 菜单按钮点击事件
|
||
const menuBtn = projectCard.querySelector('.project-menu');
|
||
menuBtn.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
showProjectMenu(project.id, menuBtn);
|
||
});
|
||
|
||
projectsGrid.appendChild(projectCard);
|
||
});
|
||
}
|
||
|
||
// 应用过滤和排序
|
||
function applyFiltersAndSort() {
|
||
// 首先应用搜索过滤
|
||
filteredProjects = projectsData.filter(project => {
|
||
const matchesSearch = currentSearchTerm === '' ||
|
||
project.title.toLowerCase().includes(currentSearchTerm.toLowerCase());
|
||
|
||
const matchesType = currentTypeFilter === 'all' ||
|
||
project.type === currentTypeFilter;
|
||
|
||
return matchesSearch && matchesType;
|
||
});
|
||
|
||
// 然后应用排序
|
||
filteredProjects.sort((a, b) => {
|
||
switch (currentSortBy) {
|
||
case 'date-desc':
|
||
return new Date(b.date) - new Date(a.date);
|
||
case 'date-asc':
|
||
return new Date(a.date) - new Date(b.date);
|
||
case 'name-asc':
|
||
return a.title.localeCompare(b.title);
|
||
case 'name-desc':
|
||
return b.title.localeCompare(a.title);
|
||
default:
|
||
return 0;
|
||
}
|
||
});
|
||
}
|
||
|
||
// 初始化事件监听器
|
||
function initEventListeners() {
|
||
// 创建项目按钮 - 顶部和侧边栏
|
||
createProjectBtn.addEventListener('click', () => {
|
||
showModal(createProjectModal);
|
||
});
|
||
|
||
const sidebarCreateBtn = document.getElementById('sidebarCreateBtn');
|
||
const sidebarImportBtn = document.getElementById('sidebarImportBtn');
|
||
|
||
if (sidebarCreateBtn) {
|
||
sidebarCreateBtn.addEventListener('click', () => {
|
||
showModal(createProjectModal);
|
||
});
|
||
}
|
||
|
||
if (sidebarImportBtn) {
|
||
sidebarImportBtn.addEventListener('click', () => {
|
||
showModal(importProjectModal);
|
||
});
|
||
}
|
||
|
||
// 关闭模态框
|
||
closeCreateModal.addEventListener('click', () => {
|
||
hideModal(createProjectModal);
|
||
});
|
||
|
||
closeImportModal.addEventListener('click', () => {
|
||
hideModal(importProjectModal);
|
||
});
|
||
|
||
// 取消按钮
|
||
cancelCreate.addEventListener('click', () => {
|
||
hideModal(createProjectModal);
|
||
});
|
||
|
||
cancelImport.addEventListener('click', () => {
|
||
hideModal(importProjectModal);
|
||
});
|
||
|
||
// 确认按钮
|
||
confirmCreate.addEventListener('click', () => {
|
||
createProject();
|
||
});
|
||
|
||
confirmImport.addEventListener('click', () => {
|
||
importProject();
|
||
});
|
||
|
||
// 树状结构展开/折叠
|
||
initTreeStructure();
|
||
|
||
// 搜索和过滤功能
|
||
initSearchAndFilter();
|
||
|
||
// 模板选择
|
||
const templateItems = document.querySelectorAll('.template-item');
|
||
templateItems.forEach(item => {
|
||
item.addEventListener('click', () => {
|
||
templateItems.forEach(t => t.classList.remove('selected'));
|
||
item.classList.add('selected');
|
||
updateTemplateDescription(item.dataset.template);
|
||
});
|
||
});
|
||
|
||
// 文件上传
|
||
uploadZone.addEventListener('click', () => {
|
||
fileInput.click();
|
||
});
|
||
|
||
uploadZone.addEventListener('dragover', (e) => {
|
||
e.preventDefault();
|
||
uploadZone.classList.add('dragover');
|
||
});
|
||
|
||
uploadZone.addEventListener('dragleave', () => {
|
||
uploadZone.classList.remove('dragover');
|
||
});
|
||
|
||
uploadZone.addEventListener('drop', (e) => {
|
||
e.preventDefault();
|
||
uploadZone.classList.remove('dragover');
|
||
handleFileUpload(e.dataTransfer.files);
|
||
});
|
||
|
||
fileInput.addEventListener('change', (e) => {
|
||
handleFileUpload(e.target.files);
|
||
});
|
||
|
||
// 点击模态框外部关闭
|
||
createProjectModal.addEventListener('click', (e) => {
|
||
if (e.target === createProjectModal) {
|
||
hideModal(createProjectModal);
|
||
}
|
||
});
|
||
|
||
importProjectModal.addEventListener('click', (e) => {
|
||
if (e.target === importProjectModal) {
|
||
hideModal(importProjectModal);
|
||
}
|
||
});
|
||
|
||
// 导航菜单项点击
|
||
const navItems = document.querySelectorAll('.nav-item');
|
||
navItems.forEach(item => {
|
||
item.addEventListener('click', () => {
|
||
navItems.forEach(nav => nav.classList.remove('active'));
|
||
item.classList.add('active');
|
||
|
||
// 更新面包屑导航
|
||
updateBreadcrumb(item);
|
||
|
||
// 根据页面类型过滤项目
|
||
const pageType = item.dataset.page;
|
||
if (pageType) {
|
||
filterProjectsByPage(pageType);
|
||
}
|
||
});
|
||
});
|
||
|
||
// 浏览位置按钮
|
||
const browseLocationBtn = document.getElementById('browseLocation');
|
||
if (browseLocationBtn) {
|
||
browseLocationBtn.addEventListener('click', () => {
|
||
browseProjectLocation();
|
||
});
|
||
}
|
||
|
||
// 视图切换
|
||
const viewBtns = document.querySelectorAll('.view-btn[data-view]');
|
||
viewBtns.forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
viewBtns.forEach(v => v.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
|
||
const view = btn.dataset.view;
|
||
if (view === 'list') {
|
||
projectsGrid.style.gridTemplateColumns = '1fr';
|
||
} else {
|
||
projectsGrid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(280px, 1fr))';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 添加导入项目的快捷方式
|
||
const importBtn = document.createElement('button');
|
||
importBtn.className = 'btn-secondary';
|
||
importBtn.innerHTML = '<i class="fas fa-upload"></i> 导入';
|
||
importBtn.style.marginLeft = '10px';
|
||
importBtn.addEventListener('click', () => {
|
||
showModal(importProjectModal);
|
||
});
|
||
|
||
const topActions = document.querySelector('.top-actions');
|
||
topActions.insertBefore(importBtn, createProjectBtn);
|
||
}
|
||
|
||
// 显示模态框
|
||
function showModal(modal) {
|
||
modal.classList.add('show');
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
|
||
// 隐藏模态框
|
||
function hideModal(modal) {
|
||
modal.classList.remove('show');
|
||
document.body.style.overflow = 'auto';
|
||
|
||
// 重置表单
|
||
if (modal === createProjectModal) {
|
||
projectNameInput.value = '';
|
||
document.querySelectorAll('.template-item').forEach(item => {
|
||
item.classList.remove('selected');
|
||
});
|
||
}
|
||
}
|
||
|
||
// 创建项目
|
||
function createProject() {
|
||
const projectName = projectNameInput.value.trim();
|
||
const selectedTemplate = document.querySelector('.template-item.selected');
|
||
|
||
if (!projectName) {
|
||
alert('请输入项目名称');
|
||
return;
|
||
}
|
||
|
||
if (!selectedTemplate) {
|
||
alert('请选择项目模板');
|
||
return;
|
||
}
|
||
|
||
const templateType = selectedTemplate.dataset.template;
|
||
const templateIcons = {
|
||
empty: '📄',
|
||
industrial: '🏭',
|
||
vr: '🥽',
|
||
smart: '📊',
|
||
game: '🎮'
|
||
};
|
||
|
||
const newProject = {
|
||
id: projectsData.length + 1,
|
||
title: projectName,
|
||
date: new Date().toLocaleString('zh-CN'),
|
||
type: templateType,
|
||
image: templateIcons[templateType] || '📄'
|
||
};
|
||
|
||
projectsData.unshift(newProject);
|
||
renderProjects();
|
||
hideModal(createProjectModal);
|
||
|
||
// 显示成功消息
|
||
showNotification('项目创建成功!', 'success');
|
||
}
|
||
|
||
// 导入项目
|
||
function importProject() {
|
||
const files = fileInput.files;
|
||
if (files.length === 0) {
|
||
alert('请选择要导入的文件');
|
||
return;
|
||
}
|
||
|
||
// 模拟导入过程
|
||
showNotification('正在导入项目...', 'info');
|
||
|
||
setTimeout(() => {
|
||
const newProject = {
|
||
id: projectsData.length + 1,
|
||
title: `导入的项目_${Date.now()}`,
|
||
date: new Date().toLocaleString('zh-CN'),
|
||
type: 'imported',
|
||
image: '📦'
|
||
};
|
||
|
||
projectsData.unshift(newProject);
|
||
renderProjects();
|
||
hideModal(importProjectModal);
|
||
showNotification('项目导入成功!', 'success');
|
||
}, 2000);
|
||
}
|
||
|
||
// 处理文件上传
|
||
function handleFileUpload(files) {
|
||
if (files.length > 0) {
|
||
const file = files[0];
|
||
const allowedTypes = ['.zip', '.rar', '.7z'];
|
||
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
||
|
||
if (allowedTypes.includes(fileExtension)) {
|
||
fileInput.files = files;
|
||
uploadZone.innerHTML = `
|
||
<i class="fas fa-file-archive"></i>
|
||
<p>已选择文件: ${file.name}</p>
|
||
<button class="btn-upload">重新选择</button>
|
||
`;
|
||
} else {
|
||
alert('请选择支持的文件格式 (.zip, .rar, .7z)');
|
||
}
|
||
}
|
||
}
|
||
|
||
// 打开项目
|
||
function openProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (project) {
|
||
showNotification(`正在打开项目: ${project.title}`, 'info');
|
||
// 这里可以添加实际的项目打开逻辑
|
||
}
|
||
}
|
||
|
||
// 显示通知
|
||
function showNotification(message, type = 'info') {
|
||
const notification = document.createElement('div');
|
||
notification.className = `notification ${type}`;
|
||
notification.textContent = message;
|
||
notification.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
padding: 15px 20px;
|
||
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
|
||
color: white;
|
||
border-radius: 8px;
|
||
z-index: 3000;
|
||
animation: slideIn 0.3s ease;
|
||
`;
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
setTimeout(() => {
|
||
notification.style.animation = 'slideOut 0.3s ease';
|
||
setTimeout(() => {
|
||
if (document.body.contains(notification)) {
|
||
document.body.removeChild(notification);
|
||
}
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// 打开项目
|
||
function openProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (project) {
|
||
showNotification(`正在打开项目: ${project.title}`, 'info');
|
||
// 这里可以添加实际的项目打开逻辑
|
||
}
|
||
}
|
||
|
||
// 显示通知
|
||
function showNotification(message, type = 'info') {
|
||
const notification = document.createElement('div');
|
||
notification.className = `notification ${type}`;
|
||
notification.textContent = message;
|
||
notification.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
padding: 15px 20px;
|
||
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
|
||
color: white;
|
||
border-radius: 8px;
|
||
z-index: 3000;
|
||
animation: slideIn 0.3s ease;
|
||
`;
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
setTimeout(() => {
|
||
notification.style.animation = 'slideOut 0.3s ease';
|
||
setTimeout(() => {
|
||
if (document.body.contains(notification)) {
|
||
document.body.removeChild(notification);
|
||
}
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// 更新模板描述
|
||
function updateTemplateDescription(templateType) {
|
||
const templateDescription = document.getElementById('templateDescription');
|
||
if (!templateDescription) return;
|
||
|
||
const descriptions = {
|
||
empty: {
|
||
title: '空白项目模板',
|
||
description: '从零开始创建项目,适合有经验的开发者。提供基础的项目结构和配置文件,您可以根据需要自由定制。'
|
||
},
|
||
industrial: {
|
||
title: '工业项目模板',
|
||
description: '专为工业应用设计的项目模板。包含工业设备监控、数据采集、生产流程管理等常用功能模块和界面组件。'
|
||
},
|
||
vr: {
|
||
title: 'VR虚拟现实模板',
|
||
description: '虚拟现实项目模板,集成VR交互组件和3D场景管理。适合创建沉浸式体验、虚拟展示和培训应用。'
|
||
},
|
||
smart: {
|
||
title: '智能可视化大屏模板',
|
||
description: '智能数据可视化大屏模板,包含丰富的图表组件、实时数据展示和响应式布局。适合创建监控中心和数据分析平台。'
|
||
},
|
||
game: {
|
||
title: '游戏开发模板',
|
||
description: '游戏开发项目模板,提供游戏引擎集成、资源管理、场景编辑等功能。适合2D/3D游戏和交互应用开发。'
|
||
}
|
||
};
|
||
|
||
const template = descriptions[templateType];
|
||
if (template) {
|
||
templateDescription.innerHTML = `
|
||
<h4>${template.title}</h4>
|
||
<p>${template.description}</p>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// 更新面包屑导航
|
||
function updateBreadcrumb(navItem) {
|
||
const breadcrumb = document.getElementById('breadcrumb');
|
||
if (!breadcrumb) return;
|
||
|
||
const pageNames = {
|
||
'all-projects': { section: '我的项目', page: '项目概览' },
|
||
'favorite-projects': { section: '我的项目', page: '收藏项目' },
|
||
'recent-projects': { section: '我的项目', page: '最近项目' },
|
||
'industrial-projects': { section: '我的项目', page: '工业项目' },
|
||
'smart-projects': { section: '我的项目', page: '智能项目' },
|
||
'vr-projects': { section: '我的项目', page: 'VR项目' },
|
||
'resource-category': { section: '内容管理', page: '资源分类' },
|
||
'category-management': { section: '内容管理', page: '分类管理' },
|
||
'asset-library': { section: '内容管理', page: '资源库' },
|
||
'template-library': { section: '内容管理', page: '模板库' }
|
||
};
|
||
|
||
const pageType = navItem.dataset.page;
|
||
const pageInfo = pageNames[pageType];
|
||
|
||
if (pageInfo) {
|
||
breadcrumb.innerHTML = `
|
||
<span>${pageInfo.section}</span>
|
||
<span>/</span>
|
||
<span>${pageInfo.page}</span>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// 根据页面类型过滤项目
|
||
function filterProjectsByPage(pageType) {
|
||
const contentHeader = document.querySelector('.content-header h1');
|
||
|
||
switch (pageType) {
|
||
case 'all-projects':
|
||
currentTypeFilter = 'all';
|
||
if (contentHeader) contentHeader.textContent = '全部项目';
|
||
break;
|
||
case 'favorite-projects':
|
||
currentTypeFilter = 'all';
|
||
if (contentHeader) contentHeader.textContent = '收藏项目';
|
||
// 这里可以添加收藏项目的过滤逻辑
|
||
break;
|
||
case 'recent-projects':
|
||
currentTypeFilter = 'all';
|
||
if (contentHeader) contentHeader.textContent = '最近项目';
|
||
// 按日期排序显示最近的项目
|
||
currentSortBy = 'date-desc';
|
||
break;
|
||
case 'industrial-projects':
|
||
currentTypeFilter = 'industrial';
|
||
if (contentHeader) contentHeader.textContent = '工业项目';
|
||
break;
|
||
case 'smart-projects':
|
||
currentTypeFilter = 'smart';
|
||
if (contentHeader) contentHeader.textContent = '智能项目';
|
||
break;
|
||
case 'vr-projects':
|
||
currentTypeFilter = 'vr';
|
||
if (contentHeader) contentHeader.textContent = 'VR项目';
|
||
break;
|
||
default:
|
||
currentTypeFilter = 'all';
|
||
if (contentHeader) contentHeader.textContent = '全部项目';
|
||
}
|
||
|
||
// 更新过滤器选择框
|
||
if (typeFilter) {
|
||
typeFilter.value = currentTypeFilter;
|
||
}
|
||
|
||
// 重新渲染项目
|
||
renderProjects();
|
||
}
|
||
|
||
// 浏览项目位置
|
||
function browseProjectLocation() {
|
||
const projectLocationInput = document.getElementById('projectLocation');
|
||
if (!projectLocationInput) return;
|
||
|
||
// 尝试调用系统文件选择器
|
||
if (window.showDirectoryPicker) {
|
||
// 现代浏览器支持的文件系统访问API
|
||
showSystemDirectoryPicker(projectLocationInput);
|
||
} else if (window.electronAPI) {
|
||
// Electron环境
|
||
showElectronDirectoryDialog(projectLocationInput);
|
||
} else {
|
||
// 降级方案:显示自定义文件夹选择对话框
|
||
showFallbackFolderDialog(projectLocationInput);
|
||
}
|
||
}
|
||
|
||
// 现代浏览器的目录选择器
|
||
async function showSystemDirectoryPicker(input) {
|
||
try {
|
||
const directoryHandle = await window.showDirectoryPicker();
|
||
const path = directoryHandle.name;
|
||
input.value = path;
|
||
showNotification('已选择项目位置: ' + path, 'success');
|
||
} catch (err) {
|
||
if (err.name !== 'AbortError') {
|
||
console.error('目录选择失败:', err);
|
||
showFallbackFolderDialog(input);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Electron环境的目录选择
|
||
function showElectronDirectoryDialog(input) {
|
||
if (window.electronAPI && window.electronAPI.showOpenDialog) {
|
||
window.electronAPI.showOpenDialog({
|
||
properties: ['openDirectory'],
|
||
title: '选择项目保存位置'
|
||
}).then(result => {
|
||
if (!result.canceled && result.filePaths.length > 0) {
|
||
const selectedPath = result.filePaths[0];
|
||
input.value = selectedPath;
|
||
showNotification('已选择项目位置: ' + selectedPath, 'success');
|
||
}
|
||
}).catch(err => {
|
||
console.error('目录选择失败:', err);
|
||
showFallbackFolderDialog(input);
|
||
});
|
||
} else {
|
||
showFallbackFolderDialog(input);
|
||
}
|
||
}
|
||
|
||
// 降级方案:简化的文件夹选择
|
||
function showFallbackFolderDialog(input) {
|
||
// 创建隐藏的文件输入元素来模拟文件夹选择
|
||
const fileInput = document.createElement('input');
|
||
fileInput.type = 'file';
|
||
fileInput.webkitdirectory = true;
|
||
fileInput.style.display = 'none';
|
||
|
||
fileInput.addEventListener('change', (e) => {
|
||
if (e.target.files.length > 0) {
|
||
// 获取第一个文件的路径,然后提取目录路径
|
||
const file = e.target.files[0];
|
||
const path = file.webkitRelativePath.split('/')[0];
|
||
input.value = path || '已选择文件夹';
|
||
showNotification('已选择项目位置', 'success');
|
||
}
|
||
document.body.removeChild(fileInput);
|
||
});
|
||
|
||
document.body.appendChild(fileInput);
|
||
fileInput.click();
|
||
}
|
||
|
||
|
||
|
||
// 显示项目菜单
|
||
function showProjectMenu(projectId, menuButton) {
|
||
// 移除已存在的菜单
|
||
const existingMenu = document.querySelector('.project-context-menu');
|
||
if (existingMenu) {
|
||
existingMenu.remove();
|
||
}
|
||
|
||
// 获取项目信息
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
// 创建菜单
|
||
const menu = document.createElement('div');
|
||
menu.className = 'project-context-menu';
|
||
menu.innerHTML = `
|
||
<div class="menu-item" data-action="open">
|
||
<i class="fas fa-folder-open"></i>
|
||
<span>打开项目</span>
|
||
</div>
|
||
<div class="menu-item" data-action="rename">
|
||
<i class="fas fa-edit"></i>
|
||
<span>重命名</span>
|
||
</div>
|
||
<div class="menu-item" data-action="duplicate">
|
||
<i class="fas fa-copy"></i>
|
||
<span>复制项目</span>
|
||
</div>
|
||
<div class="menu-item" data-action="export">
|
||
<i class="fas fa-download"></i>
|
||
<span>导出项目</span>
|
||
</div>
|
||
<div class="menu-divider"></div>
|
||
<div class="menu-item" data-action="favorite">
|
||
<i class="fas fa-star${project.favorite ? ' favorited' : ''}"></i>
|
||
<span>${project.favorite ? '从收藏中移除' : '添加到收藏'}</span>
|
||
</div>
|
||
<div class="menu-divider"></div>
|
||
<div class="menu-item danger" data-action="delete">
|
||
<i class="fas fa-trash"></i>
|
||
<span>删除项目</span>
|
||
</div>
|
||
`;
|
||
|
||
// 定位菜单
|
||
const rect = menuButton.getBoundingClientRect();
|
||
menu.style.position = 'fixed';
|
||
menu.style.top = rect.bottom + 5 + 'px';
|
||
menu.style.left = rect.left - 150 + 'px'; // 菜单宽度约150px,向左偏移
|
||
menu.style.zIndex = '2000';
|
||
|
||
// 添加到页面
|
||
document.body.appendChild(menu);
|
||
|
||
// 菜单项点击事件
|
||
menu.addEventListener('click', (e) => {
|
||
const action = e.target.closest('.menu-item')?.dataset.action;
|
||
if (action) {
|
||
handleProjectAction(projectId, action);
|
||
menu.remove();
|
||
}
|
||
});
|
||
|
||
// 点击其他地方关闭菜单
|
||
setTimeout(() => {
|
||
document.addEventListener('click', function closeMenu(e) {
|
||
if (!menu.contains(e.target)) {
|
||
menu.remove();
|
||
document.removeEventListener('click', closeMenu);
|
||
}
|
||
});
|
||
}, 0);
|
||
}
|
||
|
||
// 处理项目操作
|
||
function handleProjectAction(projectId, action) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
switch (action) {
|
||
case 'open':
|
||
openProject(projectId);
|
||
break;
|
||
case 'rename':
|
||
renameProject(projectId);
|
||
break;
|
||
case 'duplicate':
|
||
duplicateProject(projectId);
|
||
break;
|
||
case 'export':
|
||
exportProject(projectId);
|
||
break;
|
||
case 'favorite':
|
||
toggleFavorite(projectId);
|
||
break;
|
||
case 'delete':
|
||
deleteProject(projectId);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 重命名项目
|
||
function renameProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
const newName = prompt('请输入新的项目名称:', project.title);
|
||
if (newName && newName.trim() !== '') {
|
||
project.title = newName.trim();
|
||
renderProjects();
|
||
showNotification('项目重命名成功', 'success');
|
||
}
|
||
}
|
||
|
||
// 复制项目
|
||
function duplicateProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
const newProject = {
|
||
...project,
|
||
id: projectsData.length + 1,
|
||
title: project.title + ' - 副本',
|
||
date: new Date().toLocaleString('zh-CN')
|
||
};
|
||
|
||
projectsData.unshift(newProject);
|
||
renderProjects();
|
||
showNotification('项目复制成功', 'success');
|
||
}
|
||
|
||
// 导出项目
|
||
function exportProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
showNotification(`正在导出项目: ${project.title}`, 'info');
|
||
// 这里可以添加实际的导出逻辑
|
||
}
|
||
|
||
// 切换收藏状态
|
||
function toggleFavorite(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
project.favorite = !project.favorite;
|
||
renderProjects(); // 重新渲染以显示收藏状态变化
|
||
showNotification(project.favorite ? '已添加到收藏' : '已从收藏中移除', 'success');
|
||
}
|
||
|
||
// 删除项目
|
||
function deleteProject(projectId) {
|
||
const project = projectsData.find(p => p.id === projectId);
|
||
if (!project) return;
|
||
|
||
if (confirm(`确定要删除项目 "${project.title}" 吗?此操作不可撤销。`)) {
|
||
const index = projectsData.findIndex(p => p.id === projectId);
|
||
if (index > -1) {
|
||
projectsData.splice(index, 1);
|
||
renderProjects();
|
||
showNotification('项目删除成功', 'success');
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取项目类型标签
|
||
function getProjectTypeLabel(type) {
|
||
const typeLabels = {
|
||
'industrial': '工业',
|
||
'smart': '智能',
|
||
'vr': 'VR',
|
||
'game': '游戏',
|
||
'design': '设计'
|
||
};
|
||
return typeLabels[type] || '其他';
|
||
}
|
||
|
||
// 初始化搜索和过滤功能
|
||
function initSearchAndFilter() {
|
||
if (!searchBtn || !filterBtn) return;
|
||
|
||
// 搜索按钮点击
|
||
searchBtn.addEventListener('click', () => {
|
||
toggleSearchFilterArea();
|
||
});
|
||
|
||
// 过滤按钮点击
|
||
filterBtn.addEventListener('click', () => {
|
||
toggleSearchFilterArea();
|
||
});
|
||
|
||
// 搜索输入
|
||
if (searchInput) {
|
||
searchInput.addEventListener('input', (e) => {
|
||
currentSearchTerm = e.target.value;
|
||
renderProjects();
|
||
});
|
||
}
|
||
|
||
// 排序选择
|
||
if (sortSelect) {
|
||
sortSelect.addEventListener('change', (e) => {
|
||
currentSortBy = e.target.value;
|
||
renderProjects();
|
||
});
|
||
}
|
||
|
||
// 类型过滤
|
||
if (typeFilter) {
|
||
typeFilter.addEventListener('change', (e) => {
|
||
currentTypeFilter = e.target.value;
|
||
renderProjects();
|
||
});
|
||
}
|
||
}
|
||
|
||
// 切换搜索过滤区域显示
|
||
function toggleSearchFilterArea() {
|
||
if (!searchFilterArea) return;
|
||
|
||
if (searchFilterArea.style.display === 'none' || searchFilterArea.style.display === '') {
|
||
searchFilterArea.style.display = 'flex';
|
||
if (searchInput) {
|
||
searchInput.focus();
|
||
}
|
||
} else {
|
||
searchFilterArea.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 初始化树状结构
|
||
function initTreeStructure() {
|
||
// 主分区展开/折叠
|
||
const navTitles = document.querySelectorAll('.nav-title.expandable');
|
||
navTitles.forEach(title => {
|
||
title.addEventListener('click', () => {
|
||
const sectionId = title.dataset.section;
|
||
const subsection = document.getElementById(sectionId);
|
||
const icon = title.querySelector('.expand-icon');
|
||
|
||
if (subsection.classList.contains('collapsed')) {
|
||
subsection.classList.remove('collapsed');
|
||
subsection.style.maxHeight = subsection.scrollHeight + 'px';
|
||
icon.style.transform = 'rotate(0deg)';
|
||
} else {
|
||
subsection.classList.add('collapsed');
|
||
subsection.style.maxHeight = '0px';
|
||
icon.style.transform = 'rotate(-90deg)';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 设置初始状态 - 默认展开所有主分区
|
||
const allSubsections = document.querySelectorAll('.nav-subsection');
|
||
allSubsections.forEach(subsection => {
|
||
subsection.style.maxHeight = subsection.scrollHeight + 'px';
|
||
});
|
||
}
|
||
|
||
// 添加动画样式
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
@keyframes slideIn {
|
||
from { transform: translateX(100%); opacity: 0; }
|
||
to { transform: translateX(0); opacity: 1; }
|
||
}
|
||
|
||
@keyframes slideOut {
|
||
from { transform: translateX(0); opacity: 1; }
|
||
to { transform: translateX(100%); opacity: 0; }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|