【Electron桌面应用完整方案】

Electron桌面应用完整方案

完整代码结构

text 复制代码
project-management-system/
├── package.json
├── main.js
├── preload.js
├── index.html
├── styles.css
└── renderer.js

1. package.json

json 复制代码
{
  "name": "project-management-system",
  "version": "1.0.0",
  "description": "项目管理信息系统 - 桌面版",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-builder",
    "dev": "electron . --dev"
  },
  "keywords": ["project", "management", "electron"],
  "author": "Your Name",
  "license": "MIT",
  "devDependencies": {
    "electron": "^22.0.0",
    "electron-builder": "^24.0.0"
  },
  "dependencies": {
    "fs-extra": "^11.0.0"
  },
  "build": {
    "appId": "com.yourcompany.projectmanagementsystem",
    "productName": "项目管理系统",
    "directories": {
      "output": "dist"
    },
    "files": [
      "**/*",
      "!node_modules",
      "!dist"
    ],
    "win": {
      "target": "nsis",
      "icon": "icon.ico"
    },
    "mac": {
      "target": "dmg",
      "icon": "icon.icns"
    },
    "linux": {
      "target": "AppImage",
      "icon": "icon.png"
    }
  }
}

2. main.js (Electron主进程)

javascript 复制代码
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const fs = require('fs-extra');

// 保持对窗口对象的全局引用,避免被垃圾回收
let mainWindow;

// 设置数据存储路径
const DATA_DIR = path.join(app.getPath('documents'), 'ProjectManagementSystem');
const DATA_FILE = path.join(DATA_DIR, 'data.json');
const FILES_DIR = path.join(DATA_DIR, 'uploaded_files');

// 确保目录存在
function ensureDirectories() {
  try {
    fs.ensureDirSync(DATA_DIR);
    fs.ensureDirSync(FILES_DIR);
    console.log('数据目录已创建:', DATA_DIR);
    console.log('文件目录已创建:', FILES_DIR);
  } catch (error) {
    console.error('创建目录失败:', error);
  }
}

function createWindow() {
  // 创建浏览器窗口
  mainWindow = new BrowserWindow({
    width: 1400,
    height: 900,
    minWidth: 1200,
    minHeight: 700,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      enableRemoteModule: false,
      preload: path.join(__dirname, 'preload.js')
    },
    icon: path.join(__dirname, 'icon.png'), // 应用图标
    title: '项目管理系统'
  });

  // 加载应用的 index.html
  mainWindow.loadFile('index.html');
  
  // 开发时打开开发者工具
  if (process.argv.includes('--dev')) {
    mainWindow.webContents.openDevTools();
  }

  // 当窗口被关闭时触发
  mainWindow.on('closed', () => {
    // 取消引用 window 对象
    mainWindow = null;
  });
}

// 当 Electron 完成初始化并准备创建浏览器窗口时调用此方法
app.whenReady().then(() => {
  ensureDirectories();
  createWindow();
  
  app.on('activate', () => {
    // 在 macOS 上,当单击dock图标并且没有其他窗口打开时,
    // 通常在应用程序中重新创建一个窗口。
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

// 当所有窗口关闭时退出应用
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

// IPC 通信处理

// 保存应用数据
ipcMain.handle('save-app-data', async (event, data) => {
  try {
    await fs.writeJson(DATA_FILE, data, { spaces: 2 });
    console.log('数据已保存到:', DATA_FILE);
    return { success: true };
  } catch (error) {
    console.error('保存数据失败:', error);
    return { success: false, error: error.message };
  }
});

// 加载应用数据
ipcMain.handle('load-app-data', async () => {
  try {
    if (await fs.pathExists(DATA_FILE)) {
      const data = await fs.readJson(DATA_FILE);
      console.log('数据已从文件加载:', DATA_FILE);
      return { success: true, data };
    } else {
      console.log('数据文件不存在,使用默认数据');
      return { success: true, data: null };
    }
  } catch (error) {
    console.error('加载数据失败:', error);
    return { success: false, error: error.message };
  }
});

// 保存上传的文件
ipcMain.handle('save-file', async (event, fileInfo) => {
  try {
    const { fileName, fileData, projectId, description } = fileInfo;
    
    // 生成唯一文件名,避免冲突
    const fileExt = path.extname(fileName);
    const baseName = path.basename(fileName, fileExt);
    const timestamp = Date.now();
    const uniqueFileName = `${baseName}_${timestamp}${fileExt}`;
    const filePath = path.join(FILES_DIR, uniqueFileName);
    
    // 解码Base64数据并写入文件
    const base64Data = fileData.replace(/^data:.*?;base64,/, '');
    const buffer = Buffer.from(base64Data, 'base64');
    await fs.writeFile(filePath, buffer);
    
    // 获取文件大小
    const stats = await fs.stat(filePath);
    const fileSize = (stats.size / (1024 * 1024)).toFixed(2) + 'MB';
    
    console.log('文件已保存:', filePath);
    
    return { 
      success: true, 
      fileInfo: {
        id: timestamp,
        name: fileName,
        uniqueName: uniqueFileName,
        projectId: parseInt(projectId),
        uploadDate: new Date().toISOString().split('T')[0],
        description: description || '',
        size: fileSize,
        type: fileExt.substring(1), // 去掉点号
        path: filePath
      }
    };
  } catch (error) {
    console.error('保存文件失败:', error);
    return { success: false, error: error.message };
  }
});

// 下载文件
ipcMain.handle('download-file', async (event, fileInfo) => {
  try {
    const { uniqueName, name } = fileInfo;
    const filePath = path.join(FILES_DIR, uniqueName);
    
    if (!await fs.pathExists(filePath)) {
      return { success: false, error: '文件不存在' };
    }
    
    // 显示保存对话框
    const result = await dialog.showSaveDialog(mainWindow, {
      defaultPath: name,
      filters: [
        { name: '所有文件', extensions: ['*'] }
      ]
    });
    
    if (result.canceled) {
      return { success: false, error: '用户取消操作' };
    }
    
    // 复制文件到用户选择的位置
    await fs.copy(filePath, result.filePath);
    
    console.log('文件已下载到:', result.filePath);
    return { success: true, path: result.filePath };
  } catch (error) {
    console.error('下载文件失败:', error);
    return { success: false, error: error.message };
  }
});

// 获取存储路径信息
ipcMain.handle('get-storage-paths', () => {
  return {
    dataPath: DATA_DIR,
    filesPath: FILES_DIR
  };
});

// 导出数据到文件
ipcMain.handle('export-data', async (event, data) => {
  try {
    const result = await dialog.showSaveDialog(mainWindow, {
      defaultPath: `project_data_${new Date().toISOString().split('T')[0]}.json`,
      filters: [
        { name: 'JSON文件', extensions: ['json'] }
      ]
    });
    
    if (result.canceled) {
      return { success: false, error: '用户取消操作' };
    }
    
    await fs.writeJson(result.filePath, data, { spaces: 2 });
    console.log('数据已导出到:', result.filePath);
    return { success: true, path: result.filePath };
  } catch (error) {
    console.error('导出数据失败:', error);
    return { success: false, error: error.message };
  }
});

// 从文件导入数据
ipcMain.handle('import-data', async () => {
  try {
    const result = await dialog.showOpenDialog(mainWindow, {
      filters: [
        { name: 'JSON文件', extensions: ['json'] }
      ],
      properties: ['openFile']
    });
    
    if (result.canceled) {
      return { success: false, error: '用户取消操作' };
    }
    
    const filePath = result.filePaths[0];
    const data = await fs.readJson(filePath);
    console.log('数据已从文件导入:', filePath);
    
    return { success: true, data };
  } catch (error) {
    console.error('导入数据失败:', error);
    return { success: false, error: error.message };
  }
});

3. preload.js (预加载脚本)

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

// 暴露受保护的API给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
  // 数据操作
  saveAppData: (data) => ipcRenderer.invoke('save-app-data', data),
  loadAppData: () => ipcRenderer.invoke('load-app-data'),
  
  // 文件操作
  saveFile: (fileInfo) => ipcRenderer.invoke('save-file', fileInfo),
  downloadFile: (fileInfo) => ipcRenderer.invoke('download-file', fileInfo),
  
  // 数据导入导出
  exportData: (data) => ipcRenderer.invoke('export-data', data),
  importData: () => ipcRenderer.invoke('import-data'),
  
  // 获取存储路径
  getStoragePaths: () => ipcRenderer.invoke('get-storage-paths')
});

4. styles.css (样式文件)

css 复制代码
:root {
  --primary: #00f3ff;
  --secondary: #9d4edd;
  --accent: #ff006e;
  --success: #38b000;
  --warning: #ff9e00;
  --danger: #ff0054;
  --dark: #0a0a1a;
  --darker: #050510;
  --light: #e2e2e2;
  --gray: #8a8a9a;
  --card-bg: rgba(26, 26, 46, 0.7);
  --card-border: rgba(0, 243, 255, 0.2);
  --glow: 0 0 10px rgba(0, 243, 255, 0.5);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

body {
  background: var(--darker);
  color: var(--light);
  overflow-x: hidden;
  min-height: 100vh;
}

/* 科幻背景 */
.sci-fi-bg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: 
      radial-gradient(circle at 20% 30%, rgba(157, 78, 221, 0.15) 0%, transparent 50%),
      radial-gradient(circle at 80% 70%, rgba(0, 243, 255, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 40% 80%, rgba(255, 0, 110, 0.1) 0%, transparent 50%);
  z-index: -1;
}

.sci-fi-bg::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: 
      linear-gradient(90deg, transparent 98%, rgba(0, 243, 255, 0.03) 100%),
      linear-gradient(0deg, transparent 98%, rgba(0, 243, 255, 0.03) 100%);
  background-size: 30px 30px;
}

/* 主应用容器 */
.container {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 250px;
  background: rgba(10, 10, 26, 0.9);
  border-right: 1px solid var(--card-border);
  height: 100vh;
  position: fixed;
  left: 0;
  top: 0;
  padding: 20px 0;
  backdrop-filter: blur(10px);
  z-index: 100;
}

.logo {
  padding: 0 20px 30px;
  border-bottom: 1px solid var(--card-border);
  margin-bottom: 20px;
}

.logo h1 {
  color: var(--primary);
  font-size: 1.4rem;
}

.nav-links {
  list-style: none;
  padding: 0 15px;
}

.nav-link {
  display: flex;
  align-items: center;
  padding: 12px 15px;
  color: var(--light);
  text-decoration: none;
  border-radius: 8px;
  margin-bottom: 5px;
  transition: all 0.3s ease;
}

.nav-link i {
  margin-right: 10px;
  width: 20px;
  text-align: center;
}

.nav-link:hover, .nav-link.active {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  box-shadow: var(--glow);
}

.main-content {
  margin-left: 250px;
  padding: 20px;
  min-height: 100vh;
  width: calc(100% - 250px);
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 30px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--card-border);
}

.page-title h2 {
  color: var(--primary);
  margin-bottom: 5px;
}

.page-title p {
  color: var(--gray);
}

.user-info {
  display: flex;
  align-items: center;
  gap: 15px;
}

.search-box {
  position: relative;
}

.search-box i {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--gray);
}

.search-box input {
  padding: 10px 15px 10px 40px;
  background: rgba(10, 10, 26, 0.7);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  color: var(--light);
  width: 250px;
  transition: all 0.3s ease;
}

.search-box input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 8px rgba(0, 243, 255, 0.5);
}

.user-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: linear-gradient(45deg, var(--primary), var(--secondary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  cursor: pointer;
}

.user-avatar.floating {
  animation: float 3s ease-in-out infinite;
}

@keyframes float {
  0% { transform: translateY(0px); }
  50% { transform: translateY(-5px); }
  100% { transform: translateY(0px); }
}

/* 统计卡片 */
.stats-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
  margin-bottom: 30px;
}

.stat-card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
  position: relative;
  overflow: hidden;
  transition: all 0.3s ease;
}

.stat-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(90deg, var(--primary), var(--secondary));
}

.stat-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--glow);
}

.stat-card h3 {
  color: var(--gray);
  font-size: 0.9rem;
  margin-bottom: 10px;
}

.stat-card .value {
  font-size: 2rem;
  font-weight: bold;
  color: var(--primary);
  margin-bottom: 10px;
}

/* 项目卡片 */
.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.project-card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
  transition: all 0.3s ease;
  cursor: pointer;
  position: relative;
}

.project-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--glow);
}

.project-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 15px;
}

.project-title {
  flex: 1;
  position: relative;
}

.project-title h4 {
  color: var(--light);
  margin-bottom: 5px;
  padding-right: 20px;
}

.project-title p {
  color: var(--gray);
  font-size: 0.9rem;
}

.project-actions {
  display: flex;
  gap: 5px;
}

.action-btn {
  background: transparent;
  border: 1px solid var(--card-border);
  color: var(--gray);
  width: 30px;
  height: 30px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
}

.action-btn:hover {
  color: var(--primary);
  border-color: var(--primary);
  box-shadow: 0 0 5px rgba(0, 243, 255, 0.5);
}

.project-status {
  padding: 4px 10px;
  border-radius: 20px;
  font-size: 0.7rem;
  font-weight: bold;
  margin-top: 5px;
}

.status-planning {
  background: rgba(255, 158, 0, 0.1);
  color: var(--warning);
  border: 1px solid rgba(255, 158, 0, 0.3);
}

.status-progress {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border: 1px solid rgba(0, 243, 255, 0.3);
}

.status-review {
  background: rgba(157, 78, 221, 0.1);
  color: var(--secondary);
  border: 1px solid rgba(157, 78, 221, 0.3);
}

.status-completed {
  background: rgba(56, 176, 0, 0.1);
  color: var(--success);
  border: 1px solid rgba(56, 176, 0, 0.3);
}

.project-progress {
  margin-bottom: 15px;
}

.progress-bar {
  height: 8px;
  background: rgba(10, 10, 26, 0.7);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}

.progress {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), var(--secondary));
  border-radius: 4px;
  transition: width 0.5s ease;
}

.progress-info {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--gray);
}

.project-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.project-team {
  display: flex;
}

.team-member {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: linear-gradient(45deg, var(--primary), var(--secondary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  margin-right: -8px;
  border: 2px solid var(--card-bg);
}

/* 项目变更记录样式 */
.change-log {
  margin-top: 15px;
  max-height: 120px;
  overflow-y: auto;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 10px;
}

.change-log h4 {
  color: var(--primary);
  font-size: 0.8rem;
  margin-bottom: 8px;
}

.change-log-item {
  padding: 5px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  font-size: 0.7rem;
  line-height: 1.3;
}

.change-log-item:last-child {
  border-bottom: none;
}

.change-log-item span {
  color: var(--gray);
}

.change-log-item .date {
  color: var(--primary);
  font-weight: bold;
}

.change-log-item .user {
  color: var(--secondary);
}

/* 滚动条样式 */
.change-log::-webkit-scrollbar {
  width: 4px;
}

.change-log::-webkit-scrollbar-track {
  background: rgba(10, 10, 26, 0.5);
  border-radius: 2px;
}

.change-log::-webkit-scrollbar-thumb {
  background: var(--primary);
  border-radius: 2px;
}

.change-log::-webkit-scrollbar-thumb:hover {
  background: var(--secondary);
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.section-header h3 {
  color: var(--light);
}

.btn {
  background: linear-gradient(45deg, var(--primary), var(--secondary));
  border: none;
  color: var(--darker);
  padding: 10px 15px;
  border-radius: 8px;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.3s ease;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 243, 255, 0.4);
}

.btn-secondary {
  background: rgba(26, 26, 46, 0.7);
  color: var(--light);
  border: 1px solid var(--card-border);
}

.btn-secondary:hover {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border-color: var(--primary);
  box-shadow: 0 0 8px rgba(0, 243, 255, 0.5);
}

/* 任务和团队布局 */
.tasks-section {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 30px;
}

.task-list, .team-section {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
  max-height: 400px;
  overflow-y: auto;
}

.task-items {
  max-height: 300px;
  overflow-y: auto;
}

.task-item {
  padding: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
}

.task-item:last-child {
  border-bottom: none;
}

.task-info {
  flex: 1;
}

.task-info h4 {
  color: var(--light);
  margin-bottom: 5px;
  padding-right: 20px;
}

.task-info p {
  color: var(--gray);
  font-size: 0.8rem;
}

.task-dates {
  font-size: 0.7rem;
  color: var(--gray);
  margin-top: 3px;
}

.task-priority {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: bold;
}

.priority-high {
  background: rgba(255, 0, 84, 0.1);
  color: var(--danger);
  border: 1px solid rgba(255, 0, 84, 0.3);
}

.priority-medium {
  background: rgba(255, 158, 0, 0.1);
  color: var(--warning);
  border: 1px solid rgba(255, 158, 0, 0.3);
}

.priority-low {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border: 1px solid rgba(0, 243, 255, 0.3);
}

.team-members {
  display: flex;
  flex-direction: column;
  gap: 15px;
  max-height: 300px;
  overflow-y: auto;
}

.team-member-card {
  display: flex;
  align-items: center;
  padding: 15px;
  background: rgba(10, 10, 26, 0.5);
  border-radius: 8px;
  border: 1px solid var(--card-border);
  transition: all 0.3s ease;
}

.team-member-card:hover {
  transform: translateX(5px);
  border-color: var(--primary);
}

.member-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: linear-gradient(45deg, var(--primary), var(--secondary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  margin-right: 15px;
}

.member-info {
  flex: 1;
}

.member-info h4 {
  color: var(--light);
  margin-bottom: 5px;
}

.member-info p {
  color: var(--gray);
  font-size: 0.8rem;
}

.member-role {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 0.7rem;
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border: 1px solid rgba(0, 243, 255, 0.3);
}

/* 任务看板 */
.task-board {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.task-column {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
}

.column-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--card-border);
}

.column-header h3 {
  color: var(--light);
  font-size: 1rem;
}

.task-count {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  width: 25px;
  height: 25px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: bold;
}

.column-tasks {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

/* 日历 */
.calendar-container {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.calendar-nav {
  display: flex;
  gap: 10px;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
}

.calendar-day-header {
  text-align: center;
  padding: 10px;
  color: var(--gray);
  font-weight: bold;
}

.calendar-day {
  height: 80px;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 8px;
  background: rgba(10, 10, 26, 0.5);
  transition: all 0.3s ease;
  position: relative;
}

.calendar-day:hover {
  background: rgba(0, 243, 255, 0.1);
  border-color: var(--primary);
}

.calendar-day.today {
  border-color: var(--primary);
  box-shadow: 0 0 5px rgba(0, 243, 255, 0.5);
}

.calendar-event {
  background: rgba(157, 78, 221, 0.2);
  border-left: 3px solid var(--secondary);
  padding: 3px 5px;
  margin-top: 5px;
  border-radius: 3px;
  font-size: 0.7rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 横道图容器样式 - 优化版 */
.gantt-container {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 20px;
  margin-top: 20px;
  overflow: hidden;
}

.gantt-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
}

.gantt-scroll-container {
  overflow-x: auto;
  position: relative;
  padding-bottom: 10px;
  min-height: 400px;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: rgba(10, 10, 26, 0.5);
}

.gantt-timeline {
  display: flex;
  margin-bottom: 10px;
  position: relative;
  height: 30px;
  min-width: 100%;
}

.gantt-timeline-item {
  flex: 0 0 60px;
  text-align: center;
  font-size: 0.7rem;
  color: var(--gray);
  border-left: 1px solid var(--card-border);
  padding-left: 5px;
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 100%;
}

.gantt-timeline-item.major {
  font-weight: bold;
  color: var(--primary);
  border-left: 1px solid var(--primary);
}

.gantt-chart {
  position: relative;
  min-width: 100%;
}

.gantt-task {
  display: flex;
  margin-bottom: 25px;
  align-items: center;
  position: relative;
  min-height: 30px;
}

.gantt-task-name {
  width: 200px;
  padding-right: 15px;
  flex-shrink: 0;
  color: var(--light);
  font-size: 0.9rem;
  font-weight: bold;
}

.gantt-task-bar-container {
  flex: 1;
  height: 25px;
  position: relative;
  overflow: visible;
  border-left: 1px solid var(--card-border);
  border-right: 1px solid var(--card-border);
  background: rgba(10, 10, 26, 0.3);
}

.gantt-task-bar {
  height: 25px;
  background: rgba(10, 10, 26, 0.7);
  border-radius: 4px;
  position: absolute;
  top: 0;
  overflow: hidden;
  min-width: 20px;
}

.gantt-progress {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), var(--secondary));
  border-radius: 4px;
}

.gantt-date-start, .gantt-date-end {
  position: absolute;
  top: -20px;
  font-size: 0.7rem;
  color: var(--gray);
  white-space: nowrap;
  background: rgba(10, 10, 26, 0.8);
  padding: 2px 5px;
  border-radius: 3px;
  z-index: 5;
}

.gantt-date-start {
  left: 0;
  transform: translateX(-50%);
}

.gantt-date-end {
  right: 0;
  transform: translateX(50%);
}

.gantt-current-date {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background-color: var(--accent);
  z-index: 10;
}

.gantt-current-date::after {
  content: '今天';
  position: absolute;
  top: -20px;
  left: -10px;
  font-size: 0.7rem;
  color: var(--accent);
  white-space: nowrap;
  background: rgba(10, 10, 26, 0.8);
  padding: 2px 5px;
  border-radius: 3px;
}

.gantt-scroll-controls {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 15px;
}

.gantt-scroll-btn {
  padding: 5px 10px;
  background: rgba(26, 26, 46, 0.7);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  color: var(--light);
  cursor: pointer;
  transition: all 0.3s ease;
}

.gantt-scroll-btn:hover {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border-color: var(--primary);
}

/* 数据管理样式 */
.data-management-section {
  margin-top: 20px;
  padding: 20px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
}

.data-actions {
  display: flex;
  gap: 15px;
  margin-top: 15px;
}

.data-info {
  margin-top: 15px;
  padding: 15px;
  background: rgba(10, 10, 26, 0.5);
  border-radius: 8px;
  font-size: 0.9rem;
}

.data-info h4 {
  color: var(--primary);
  margin-bottom: 10px;
}

.data-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  margin-top: 10px;
}

.data-stat {
  padding: 10px;
  background: rgba(0, 243, 255, 0.1);
  border-radius: 6px;
  text-align: center;
}

.data-stat .value {
  font-size: 1.2rem;
  font-weight: bold;
  color: var(--primary);
}

.data-stat .label {
  font-size: 0.8rem;
  color: var(--gray);
}

/* 文件上传区域样式 */
.file-upload-area {
  border: 2px dashed var(--card-border);
  border-radius: 8px;
  padding: 30px;
  text-align: center;
  margin: 15px 0;
  transition: all 0.3s ease;
  cursor: pointer;
}

.file-upload-area:hover {
  border-color: var(--primary);
  background: rgba(0, 243, 255, 0.05);
}

.file-upload-area i {
  font-size: 2rem;
  color: var(--primary);
  margin-bottom: 10px;
}

.file-upload-area p {
  color: var(--gray);
  margin-bottom: 10px;
}

/* 文件列表样式 */
.file-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 20px;
}

.file-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px;
  background: rgba(10, 10, 26, 0.5);
  border-radius: 8px;
  border: 1px solid var(--card-border);
  transition: all 0.3s ease;
}

.file-item:hover {
  border-color: var(--primary);
  transform: translateY(-2px);
}

.file-info {
  display: flex;
  align-items: center;
  gap: 15px;
}

.file-icon {
  font-size: 1.5rem;
  color: var(--primary);
}

.file-details h4 {
  color: var(--light);
  margin-bottom: 5px;
}

.file-details p {
  color: var(--gray);
  font-size: 0.8rem;
}

.file-actions {
  display: flex;
  gap: 10px;
}

/* 延期提醒样式 */
.project-overdue::after {
  content: '!';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  background: var(--danger);
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: bold;
}

.project-soon-due::after {
  content: '!';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  background: var(--warning);
  color: var(--darker);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: bold;
}

.task-overdue::after {
  content: '!';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  background: var(--danger);
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: bold;
}

.task-soon-due::after {
  content: '!';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  background: var(--warning);
  color: var(--darker);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: bold;
}

/* 任务过滤器 */
.task-filter {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.filter-btn {
  padding: 8px 16px;
  background: rgba(26, 26, 46, 0.7);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  color: var(--light);
  cursor: pointer;
  transition: all 0.3s ease;
}

.filter-btn.active {
  background: rgba(0, 243, 255, 0.1);
  color: var(--primary);
  border-color: var(--primary);
}

/* 模态框 */
.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(5, 5, 16, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  backdrop-filter: blur(5px);
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s ease;
}

.modal.active {
  opacity: 1;
  visibility: visible;
}

.modal-content {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 15px;
  width: 90%;
  max-width: 500px;
  box-shadow: var(--glow);
  transform: translateY(-20px);
  transition: transform 0.3s ease;
}

.modal.active .modal-content {
  transform: translateY(0);
}

.modal-header {
  padding: 20px;
  border-bottom: 1px solid var(--card-border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-title {
  color: var(--primary);
}

.close-modal {
  background: transparent;
  border: none;
  color: var(--gray);
  font-size: 1.5rem;
  cursor: pointer;
  transition: color 0.3s ease;
}

.close-modal:hover {
  color: var(--danger);
}

.modal-body {
  padding: 20px;
}

.form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

/* 表单组样式 */
.form-group {
  margin-bottom: 15px;
}

.form-group label {
  display: block;
  margin-bottom: 5px;
  color: var(--light);
  font-size: 0.9rem;
}

.form-control {
  width: 100%;
  padding: 10px 12px;
  background: rgba(10, 10, 26, 0.7);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  color: var(--light);
  font-size: 0.9rem;
  transition: all 0.3s ease;
}

.form-control:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 8px rgba(0, 243, 255, 0.5);
}

/* 通知样式 */
.notification {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 15px 20px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  color: var(--light);
  box-shadow: var(--glow);
  z-index: 1100;
  transform: translateX(150%);
  transition: transform 0.3s ease;
}

.notification.show {
  transform: translateX(0);
}

.notification.success {
  border-left: 4px solid var(--success);
}

.notification.error {
  border-left: 4px solid var(--danger);
}

/* 页面内容 */
.page-content {
  display: none;
}

.page-content.active {
  display: block;
  animation: fadeIn 0.5s ease;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* 响应式设计 */
@media (max-width: 1024px) {
  .sidebar {
      width: 70px;
  }
  
  .sidebar .logo h1, 
  .sidebar .nav-link span {
      display: none;
  }
  
  .sidebar .nav-link {
      justify-content: center;
      padding: 15px;
  }
  
  .sidebar .nav-link i {
      margin-right: 0;
      font-size: 1.2rem;
  }
  
  .main-content {
      margin-left: 70px;
      width: calc(100% - 70px);
  }
  
  .tasks-section {
      grid-template-columns: 1fr;
  }
  
  .task-board {
      grid-template-columns: 1fr;
  }
}

@media (max-width: 768px) {
  .stats-cards {
      grid-template-columns: 1fr;
  }
  
  .projects-grid {
      grid-template-columns: 1fr;
  }
  
  .header {
      flex-direction: column;
      align-items: flex-start;
      gap: 15px;
  }
  
  .user-info {
      width: 100%;
      justify-content: space-between;
  }
  
  .search-box input {
      width: 200px;
  }
  
  .data-actions {
      flex-direction: column;
  }
  
  .data-stats {
      grid-template-columns: 1fr 1fr;
  }
  
  .gantt-task-name {
      width: 150px;
  }
  
  .gantt-timeline-item {
      flex: 0 0 40px;
  }
}

/* 本地存储信息样式 */
.local-storage-info {
  background: rgba(0, 243, 255, 0.1);
  border: 1px solid var(--primary);
  border-radius: 8px;
  padding: 15px;
  margin-bottom: 20px;
}

.local-storage-info h4 {
  color: var(--primary);
  margin-bottom: 10px;
}

.local-storage-info p {
  color: var(--light);
  margin-bottom: 5px;
  font-size: 0.9rem;
}

.local-storage-info .path {
  font-family: monospace;
  background: rgba(10, 10, 26, 0.5);
  padding: 5px 10px;
  border-radius: 4px;
  display: inline-block;
  margin-top: 5px;
}

5. renderer.js (渲染进程逻辑)

javascript 复制代码
// 数据模型
const appData = {
  projects: [],
  tasks: [],
  teamMembers: [],
  calendarEvents: [],
  files: [],
  currentUser: '管理员'
};

// 初始化应用
async function initApp() {
  // 设置事件监听器
  setupEventListeners();
  
  // 获取存储路径信息
  const paths = await window.electronAPI.getStoragePaths();
  document.getElementById('storagePath').textContent = paths.dataPath;
  document.getElementById('filesPath').textContent = paths.filesPath;
  document.getElementById('storagePath2').textContent = paths.dataPath;
  document.getElementById('filesPath2').textContent = paths.filesPath;
  
  // 初始化数据
  await initData();
  
  // 设置数据管理功能
  setupDataManagement();
}

// 初始化数据
async function initData() {
  // 尝试从本地文件加载数据
  const result = await window.electronAPI.loadAppData();
  
  if (result.success && result.data) {
    // 使用从文件加载的数据
    const loadedData = result.data;
    appData.projects = loadedData.projects || [];
    appData.tasks = loadedData.tasks || [];
    appData.teamMembers = loadedData.teamMembers || [];
    appData.calendarEvents = loadedData.calendarEvents || [];
    appData.files = loadedData.files || [];
    
    console.log('数据已从本地文件加载');
  } else {
    // 使用默认数据
    appData.projects = [
      {
        id: 1,
        name: "网站重构项目",
        department: "技术部",
        manager: "黄晓威",
        progress: 65,
        startDate: "2025-10-01",
        deadline: "2025-12-15",
        status: "progress",
        team: ["黄", "胡", "唐", "+2"],
        completedTasks: 12,
        totalTasks: 18,
        description: "重构公司官网,提升用户体验和性能",
        changeLog: [
          { date: "2025-10-01", user: "黄晓威", action: "创建项目" },
          { date: "2025-10-15", user: "黄晓威", action: "更新项目进度至30%" },
          { date: "2025-11-01", user: "黄晓威", action: "更新项目进度至65%" },
          { date: "2025-11-05", user: "胡镇", action: "添加新功能需求" }
        ]
      },
      {
        id: 2,
        name: "移动应用开发",
        department: "产品部",
        manager: "胡镇",
        progress: 80,
        startDate: "2025-09-15",
        deadline: "2025-11-30",
        status: "review",
        team: ["胡", "余", "+3"],
        completedTasks: 24,
        totalTasks: 30,
        description: "开发新一代移动应用,支持iOS和Android平台",
        changeLog: [
          { date: "2025-09-15", user: "胡镇", action: "创建项目" },
          { date: "2025-10-10", user: "胡镇", action: "更新项目进度至60%" },
          { date: "2025-10-25", user: "胡镇", action: "更新项目进度至80%" }
        ]
      },
      {
        id: 3,
        name: "市场推广活动",
        department: "市场部",
        manager: "唐左琪",
        progress: 20,
        startDate: "2025-11-01",
        deadline: "2026-01-20",
        status: "planning",
        team: ["唐", "文", "+1"],
        completedTasks: 5,
        totalTasks: 25,
        description: "策划并执行新产品市场推广活动",
        changeLog: [
          { date: "2025-11-01", user: "唐左琪", action: "创建项目" },
          { date: "2025-11-05", user: "唐左琪", action: "确定市场策略" }
        ]
      }
    ];
    
    appData.tasks = [
      {
        id: 1,
        name: "完成用户登录模块开发",
        projectId: 1,
        startDate: "2025-11-08",
        deadline: "2025-11-15",
        priority: "high",
        status: "pending",
        description: "实现用户登录、注册和密码找回功能"
      },
      {
        id: 2,
        name: "设计应用主界面原型",
        projectId: 2,
        startDate: "2025-11-05",
        deadline: "2025-11-10",
        priority: "medium",
        status: "completed",
        description: "设计应用主要界面的UI原型和交互流程"
      },
      {
        id: 3,
        name: "制定市场推广策略",
        projectId: 3,
        startDate: "2025-11-05",
        deadline: "2025-11-20",
        priority: "low",
        status: "pending",
        description: "分析目标市场并制定详细的推广策略"
      },
      {
        id: 4,
        name: "编写项目进度报告",
        projectId: 1,
        startDate: "2025-11-01",
        deadline: "2025-11-12",
        priority: "medium",
        status: "progress",
        description: "汇总项目进展并编写进度报告"
      },
      {
        id: 5,
        name: "API接口设计",
        projectId: 2,
        startDate: "2025-11-10",
        deadline: "2025-11-18",
        priority: "medium",
        status: "progress",
        description: "设计后端API接口和数据传输格式"
      },
      {
        id: 6,
        name: "用户需求收集",
        projectId: 1,
        startDate: "2025-11-03",
        deadline: "2025-11-07",
        priority: "low",
        status: "completed",
        description: "收集并整理用户对新功能的需求"
      }
    ];
    
    appData.teamMembers = [
      { id: 1, name: "黄晓威", role: "技术主管", avatar: "黄", skills: ["项目管理", "团队领导"] },
      { id: 2, name: "胡镇", role: "项目经理", avatar: "胡", skills: ["项目管理", "需求分析", "任务分解"] },
      { id: 3, name: "唐左琪", role: "项目经理", avatar: "唐", skills: ["项目管理", "需求分析", "任务分解"] },
      { id: 4, name: "余传意", role: "技术支持", avatar: "余", skills: ["技术专家", "需求收集", "团队合作"] }
    ];
    
    appData.calendarEvents = [
      { id: 1, date: "2025-11-10", title: "项目评审会议", description: "评审移动应用开发项目进度" },
      { id: 2, date: "2025-11-15", title: "用户登录模块交付", description: "网站重构项目的用户登录模块交付" }
    ];
    
    appData.files = [
      {
        id: 1,
        name: "项目需求文档.docx",
        projectId: 1,
        uploadDate: "2025-10-05",
        description: "网站重构项目的详细需求文档",
        size: "2.5MB",
        type: "docx",
        uniqueName: "项目需求文档_1696521600000.docx"
      },
      {
        id: 2,
        name: "UI设计稿.pdf",
        projectId: 2,
        uploadDate: "2025-09-25",
        description: "移动应用UI设计稿",
        size: "5.2MB",
        type: "pdf",
        uniqueName: "UI设计稿_1695600000000.pdf"
      },
      {
        id: 3,
        name: "市场调研报告.xlsx",
        projectId: 3,
        uploadDate: "2025-11-03",
        description: "新产品市场调研数据和分析报告",
        size: "1.8MB",
        type: "xlsx",
        uniqueName: "市场调研报告_1698969600000.xlsx"
      }
    ];
    
    // 保存默认数据到本地文件
    await saveData();
  }
  
  // 初始化日历日期
  window.currentCalendarDate = new Date();
  
  updateStats();
  renderDashboard();
  renderProjectsPage();
  renderTasksPage();
  renderTeamPage();
  renderCalendar();
  renderProgressPage();
  renderReportsPage();
}

// 保存数据到本地文件
async function saveData() {
  const result = await window.electronAPI.saveAppData(appData);
  if (!result.success) {
    console.error('保存数据失败:', result.error);
    showNotification('保存数据失败: ' + result.error, 'error');
  }
}

// 更新统计信息
function updateStats() {
  // 进行中项目
  const activeProjects = appData.projects.filter(p => p.status === 'progress').length;
  document.getElementById('activeProjectsCount').textContent = activeProjects;
  
  // 已完成任务
  const completedTasks = appData.tasks.filter(t => t.status === 'completed').length;
  document.getElementById('completedTasksCount').textContent = completedTasks;
  
  // 逾期项目
  const today = new Date().toISOString().split('T')[0];
  const overdueProjects = appData.projects.filter(p => p.deadline < today && p.status !== 'completed').length;
  document.getElementById('overdueProjectsCount').textContent = overdueProjects;
  
  // 团队效率
  const totalTasks = appData.tasks.length;
  const completed = appData.tasks.filter(t => t.status === 'completed').length;
  const efficiency = totalTasks > 0 ? Math.round((completed / totalTasks) * 100) : 0;
  document.getElementById('teamEfficiency').textContent = efficiency + '%';
}

// 设置数据管理功能
function setupDataManagement() {
  // 数据管理按钮事件
  document.getElementById('exportDataBtn').addEventListener('click', exportData);
  document.getElementById('copyDataBtn').addEventListener('click', copyDataToClipboard);
  document.getElementById('importDataBtn').addEventListener('click', importData);
  document.getElementById('resetDataBtn').addEventListener('click', resetToSampleData);
  
  // 文件上传区域事件
  const fileUploadArea = document.getElementById('fileUploadArea');
  const fileInput = document.getElementById('fileInput');
  
  fileUploadArea.addEventListener('click', () => {
    fileInput.click();
  });
  
  fileUploadArea.addEventListener('dragover', (e) => {
    e.preventDefault();
    fileUploadArea.style.borderColor = 'var(--primary)';
    fileUploadArea.style.background = 'rgba(0, 243, 255, 0.1)';
  });
  
  fileUploadArea.addEventListener('dragleave', () => {
    fileUploadArea.style.borderColor = 'var(--card-border)';
    fileUploadArea.style.background = '';
  });
  
  fileUploadArea.addEventListener('drop', (e) => {
    e.preventDefault();
    fileUploadArea.style.borderColor = 'var(--card-border)';
    fileUploadArea.style.background = '';
    
    if (e.dataTransfer.files.length > 0) {
      fileInput.files = e.dataTransfer.files;
      handleFileSelect();
    }
  });
  
  fileInput.addEventListener('change', handleFileSelect);
  
  // 数据管理页面按钮事件
  document.getElementById('exportDataBtn2').addEventListener('click', exportData);
  document.getElementById('copyDataBtn2').addEventListener('click', copyDataToClipboard);
  document.getElementById('importDataBtn2').addEventListener('click', importData);
  document.getElementById('resetDataBtn2').addEventListener('click', resetToSampleData);
  
  // 文件上传区域事件 - 页面版本
  const fileUploadArea2 = document.getElementById('fileUploadArea2');
  const fileInput2 = document.getElementById('fileInput2');
  
  fileUploadArea2.addEventListener('click', () => {
    fileInput2.click();
  });
  
  fileUploadArea2.addEventListener('dragover', (e) => {
    e.preventDefault();
    fileUploadArea2.style.borderColor = 'var(--primary)';
    fileUploadArea2.style.background = 'rgba(0, 243, 255, 0.1)';
  });
  
  fileUploadArea2.addEventListener('dragleave', () => {
    fileUploadArea2.style.borderColor = 'var(--card-border)';
    fileUploadArea2.style.background = '';
  });
  
  fileUploadArea2.addEventListener('drop', (e) => {
    e.preventDefault();
    fileUploadArea2.style.borderColor = 'var(--card-border)';
    fileUploadArea2.style.background = '';
    
    if (e.dataTransfer.files.length > 0) {
      fileInput2.files = e.dataTransfer.files;
      handleFileSelect2();
    }
  });
  
  fileInput2.addEventListener('change', handleFileSelect2);
  
  // 更新数据统计
  updateDataStats();
}

// 处理文件选择
function handleFileSelect() {
  const fileInput = document.getElementById('fileInput');
  const importDataBtn = document.getElementById('importDataBtn');
  
  if (fileInput.files.length > 0) {
    const file = fileInput.files[0];
    if (file.type === 'application/json' || file.name.endsWith('.json')) {
      importDataBtn.disabled = false;
      showNotification('文件已选择,点击"导入数据"按钮导入', 'success');
    } else {
      importDataBtn.disabled = true;
      showNotification('请选择JSON格式的文件', 'error');
    }
  } else {
    importDataBtn.disabled = true;
  }
}

// 处理文件选择 - 页面版本
function handleFileSelect2() {
  const fileInput2 = document.getElementById('fileInput2');
  const importDataBtn2 = document.getElementById('importDataBtn2');
  
  if (fileInput2.files.length > 0) {
    const file = fileInput2.files[0];
    if (file.type === 'application/json' || file.name.endsWith('.json')) {
      importDataBtn2.disabled = false;
      showNotification('文件已选择,点击"导入数据"按钮导入', 'success');
    } else {
      importDataBtn2.disabled = true;
      showNotification('请选择JSON格式的文件', 'error');
    }
  } else {
    importDataBtn2.disabled = true;
  }
}

// 导出数据
async function exportData() {
  const dataToExport = {
    projects: appData.projects,
    tasks: appData.tasks,
    teamMembers: appData.teamMembers,
    calendarEvents: appData.calendarEvents,
    files: appData.files,
    exportDate: new Date().toISOString(),
    version: '1.0'
  };
  
  const result = await window.electronAPI.exportData(dataToExport);
  if (result.success) {
    showNotification(`数据已导出到: ${result.path}`, 'success');
  } else {
    showNotification('导出数据失败: ' + result.error, 'error');
  }
}

// 复制数据到剪贴板
function copyDataToClipboard() {
  const dataToExport = {
    projects: appData.projects,
    tasks: appData.tasks,
    teamMembers: appData.teamMembers,
    calendarEvents: appData.calendarEvents,
    files: appData.files,
    exportDate: new Date().toISOString(),
    version: '1.0'
  };
  
  const dataStr = JSON.stringify(dataToExport, null, 2);
  
  navigator.clipboard.writeText(dataStr).then(() => {
    showNotification('数据已复制到剪贴板!', 'success');
  }).catch(err => {
    console.error('复制失败: ', err);
    showNotification('复制失败,请手动复制', 'error');
  });
}

// 导入数据
async function importData() {
  const result = await window.electronAPI.importData();
  
  if (result.success) {
    // 确认导入
    if (confirm('导入数据将覆盖当前所有数据,确定要继续吗?')) {
      // 更新应用数据
      appData.projects = result.data.projects || [];
      appData.tasks = result.data.tasks || [];
      appData.teamMembers = result.data.teamMembers || [];
      appData.calendarEvents = result.data.calendarEvents || [];
      appData.files = result.data.files || [];
      
      // 保存到本地存储
      await saveData();
      
      // 更新界面
      updateStats();
      renderDashboard();
      renderProjectsPage();
      renderTasksPage();
      renderTeamPage();
      renderCalendar();
      renderProgressPage();
      renderReportsPage();
      updateDataStats();
      
      // 重置文件输入
      document.getElementById('fileInput').value = '';
      document.getElementById('fileInput2').value = '';
      document.getElementById('importDataBtn').disabled = true;
      document.getElementById('importDataBtn2').disabled = true;
      
      showNotification('数据导入成功!', 'success');
    }
  } else {
    if (result.error !== '用户取消操作') {
      showNotification('导入数据失败: ' + result.error, 'error');
    }
  }
}

// 重置为示例数据
async function resetToSampleData() {
  if (confirm('这将重置所有数据为示例数据,当前数据将丢失。确定要继续吗?')) {
    // 重新初始化数据
    await initData();
    
    // 更新数据统计
    updateDataStats();
    
    showNotification('已重置为示例数据', 'success');
  }
}

// 更新数据统计
function updateDataStats() {
  document.getElementById('projectsCount').textContent = appData.projects.length;
  document.getElementById('tasksCount').textContent = appData.tasks.length;
  document.getElementById('teamMembersCount').textContent = appData.teamMembers.length;
  document.getElementById('eventsCount').textContent = appData.calendarEvents.length;
  
  document.getElementById('projectsCount2').textContent = appData.projects.length;
  document.getElementById('tasksCount2').textContent = appData.tasks.length;
  document.getElementById('teamMembersCount2').textContent = appData.teamMembers.length;
  document.getElementById('eventsCount2').textContent = appData.calendarEvents.length;
}

// 渲染仪表盘
function renderDashboard() {
  renderDashboardProjects();
  renderDashboardTasks();
  renderDashboardTeam();
}

// 渲染仪表盘项目
function renderDashboardProjects() {
  const container = document.getElementById('dashboardProjects');
  container.innerHTML = '';
  
  // 只显示前6个项目
  const projectsToShow = appData.projects.slice(0, 6);
  
  projectsToShow.forEach(project => {
    const card = createProjectCard(project);
    container.appendChild(card);
  });
}

// 渲染仪表盘任务 - 显示前后3天的任务
function renderDashboardTasks() {
  const container = document.getElementById('dashboardTasks');
  container.innerHTML = '';
  
  // 计算前后3天的日期范围
  const today = new Date();
  const startDate = new Date(today);
  startDate.setDate(today.getDate() - 3);
  
  const endDate = new Date(today);
  endDate.setDate(today.getDate() + 3);
  
  // 格式化日期为 YYYY-MM-DD
  const formatDate = (date) => {
    return date.toISOString().split('T')[0];
  };
  
  const startDateStr = formatDate(startDate);
  const endDateStr = formatDate(endDate);
  
  // 筛选在前后3天范围内的任务
  const tasksToShow = appData.tasks.filter(task => {
    return task.startDate >= startDateStr && task.startDate <= endDateStr;
  });
  
  // 按开始日期排序
  tasksToShow.sort((a, b) => new Date(a.startDate) - new Date(b.startDate));
  
  // 只显示前5个任务
  const displayedTasks = tasksToShow.slice(0, 5);
  
  if (displayedTasks.length === 0) {
    container.innerHTML = '<p style="text-align: center; color: var(--gray); padding: 20px;">前后3天内没有任务</p>';
    return;
  }
  
  displayedTasks.forEach(task => {
    const taskElement = createTaskItem(task);
    container.appendChild(taskElement);
  });
}

// 渲染仪表盘团队
function renderDashboardTeam() {
  const container = document.getElementById('dashboardTeam');
  container.innerHTML = '';
  
  appData.teamMembers.forEach(member => {
    const card = createTeamMemberCard(member);
    container.appendChild(card);
  });
}

// 创建项目卡片
function createProjectCard(project) {
  const card = document.createElement('div');
  card.className = 'project-card';
  card.dataset.id = project.id;
  
  const statusClass = {
    'planning': 'status-planning',
    'progress': 'status-progress',
    'review': 'status-review',
    'completed': 'status-completed'
  }[project.status] || 'status-planning';
  
  const statusText = {
    'planning': '规划中',
    'progress': '进行中',
    'review': '评审中',
    'completed': '已完成'
  }[project.status] || '规划中';
  
  // 计算项目进度(基于任务状态)
  const projectProgress = calculateProjectProgress(project.id);
  
  // 计算实际完成任务数量和总任务数量
  const projectTasks = appData.tasks.filter(task => task.projectId === project.id);
  const totalTasks = projectTasks.length;
  const completedTasks = projectTasks.filter(task => task.status === 'completed').length;
  
  // 检查项目是否延期或即将延期
  const today = new Date();
  const deadline = new Date(project.deadline);
  const daysUntilDeadline = Math.ceil((deadline - today) / (1000 * 60 * 60 * 24));
  
  let projectNameClass = '';
  if (project.status !== 'completed') {
    if (daysUntilDeadline < 0) {
      projectNameClass = 'project-overdue';
    } else if (daysUntilDeadline <= 15) {
      projectNameClass = 'project-soon-due';
    }
  }
  
  card.innerHTML = `
    <div class="project-header">
      <div class="project-title">
        <h4 class="${projectNameClass}">${project.name}</h4>
        <p>${project.department} • 负责人: ${project.manager}</p>
      </div>
      <div class="project-actions">
        <button class="action-btn export-project-btn" title="导出项目"><i class="fas fa-download"></i></button>
        <button class="action-btn view-tasks-btn" title="查看任务"><i class="fas fa-tasks"></i></button>
        <button class="action-btn edit-project-btn" title="编辑项目"><i class="fas fa-edit"></i></button>
        <button class="action-btn delete-btn" title="删除项目"><i class="fas fa-trash"></i></button>
        <div class="project-status ${statusClass}">${statusText}</div>
      </div>
    </div>
    <div class="project-progress">
      <div class="progress-bar">
        <div class="progress" style="width: ${projectProgress}%"></div>
      </div>
      <div class="progress-info">
        <span>进度: ${projectProgress}%</span>
        <span>开始: ${project.startDate}</span>
        <span>截止: ${project.deadline}</span>
      </div>
    </div>
    <div class="project-meta">
      <div class="project-team">
        ${project.team.map(member => `<div class="team-member">${member}</div>`).join('')}
      </div>
      <div class="task-count">${completedTasks}/${totalTasks} 任务完成</div>
    </div>
    ${project.changeLog && project.changeLog.length > 0 ? `
    <div class="change-log">
      <h4>变更记录</h4>
      ${project.changeLog.map(log => ` <div class="change-log-item"> <span class="date">${log.date}</span> - <span class="user">${log.user}</span>: ${log.action} </div> `).join('')}
    </div>
    ` : ''}
  `;
  
  // 添加导出项目事件
  const exportProjectBtn = card.querySelector('.export-project-btn');
  exportProjectBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    exportSingleProject(project.id);
  });
  
  // 添加查看任务事件
  const viewTasksBtn = card.querySelector('.view-tasks-btn');
  viewTasksBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    viewProjectTasks(project.id);
  });
  
  // 添加编辑项目事件
  const editProjectBtn = card.querySelector('.edit-project-btn');
  editProjectBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    openEditProjectModal(project);
  });
  
  // 添加删除事件
  const deleteBtn = card.querySelector('.delete-btn');
  deleteBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    if (confirm(`确定要删除项目 "${project.name}" 吗?这将删除所有关联的任务。`)) {
      deleteProject(project.id);
    }
  });
  
  card.addEventListener('click', () => {
    alert('您点击了项目: ' + project.name);
  });
  
  return card;
}

// 创建任务项
function createTaskItem(task) {
  const taskElement = document.createElement('div');
  taskElement.className = 'task-item';
  taskElement.dataset.id = task.id;
  
  const project = appData.projects.find(p => p.id === task.projectId);
  const projectName = project ? project.name : '未知项目';
  
  const priorityClass = {
    'high': 'priority-high',
    'medium': 'priority-medium',
    'low': 'priority-low'
  }[task.priority] || 'priority-medium';
  
  const priorityText = {
    'high': '高',
    'medium': '中',
    'low': '低'
  }[task.priority] || '中';
  
  // 检查任务是否延期或即将到期
  const today = new Date();
  const deadline = new Date(task.deadline);
  const daysUntilDeadline = Math.ceil((deadline - today) / (1000 * 60 * 60 * 24));
  
  let taskNameClass = '';
  if (task.status !== 'completed') {
    if (daysUntilDeadline < 0) {
      taskNameClass = 'task-overdue';
    } else if (daysUntilDeadline <= 2) {
      taskNameClass = 'task-soon-due';
    }
  }
  
  taskElement.innerHTML = `
    <div class="task-info">
      <h4 class="${taskNameClass}">${task.name}</h4>
      <p>${projectName}</p>
      <div class="task-dates">开始: ${task.startDate} • 截止: ${task.deadline}</div>
    </div>
    <div class="task-priority ${priorityClass}">${priorityText}</div>
    <div class="task-actions">
      <button class="action-btn edit-task-btn" title="编辑任务"><i class="fas fa-edit"></i></button>
      <button class="action-btn delete-btn" title="删除任务"><i class="fas fa-trash"></i></button>
    </div>
  `;
  
  // 添加编辑任务事件
  const editTaskBtn = taskElement.querySelector('.edit-task-btn');
  editTaskBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    openEditTaskModal(task);
  });
  
  // 添加删除事件
  const deleteBtn = taskElement.querySelector('.delete-btn');
  deleteBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    if (confirm(`确定要删除任务 "${task.name}" 吗?`)) {
      deleteTask(task.id);
    }
  });
  
  return taskElement;
}

// 创建团队成员卡片
function createTeamMemberCard(member) {
  const card = document.createElement('div');
  card.className = 'team-member-card';
  card.dataset.id = member.id;
  
  card.innerHTML = `
    <div class="member-avatar">${member.avatar}</div>
    <div class="member-info">
      <h4>${member.name}</h4>
      <p>${member.role}</p>
      ${member.skills && member.skills.length > 0 ? 
      `<p class="member-skills">技能: ${member.skills.join(', ')}</p>` : ''}
    </div>
    <div class="member-actions">
      <button class="action-btn edit-member-btn" title="编辑成员"><i class="fas fa-edit"></i></button>
      <button class="action-btn delete-btn" title="删除成员"><i class="fas fa-trash"></i></button>
    </div>
    <div class="member-role">${member.role.includes('主管') || member.role.includes('经理') ? '管理员' : '成员'}</div>
  `;
  
  // 添加编辑成员事件
  const editMemberBtn = card.querySelector('.edit-member-btn');
  editMemberBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    openEditTeamMemberModal(member);
  });
  
  // 添加删除事件
  const deleteBtn = card.querySelector('.delete-btn');
  deleteBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    if (confirm(`确定要删除团队成员 "${member.name}" 吗?`)) {
      deleteTeamMember(member.id);
    }
  });
  
  return card;
}

// 渲染项目页面
function renderProjectsPage() {
  const container = document.getElementById('allProjects');
  container.innerHTML = '';
  
  appData.projects.forEach(project => {
    const card = createProjectCard(project);
    container.appendChild(card);
  });
}

// 渲染任务页面
function renderTasksPage() {
  const container = document.getElementById('taskBoard');
  container.innerHTML = '';
  
  // 定义任务状态
  const statuses = [
    { id: 'pending', name: '待处理', color: 'var(--warning)' },
    { id: 'progress', name: '进行中', color: 'var(--primary)' },
    { id: 'review', name: '评审中', color: 'var(--secondary)' },
    { id: 'completed', name: '已完成', color: 'var(--success)' }
  ];
  
  // 应用过滤器
  let filteredTasks = appData.tasks;
  
  // 应用状态过滤器
  if (window.currentTaskFilter && window.currentTaskFilter !== 'all') {
    filteredTasks = filteredTasks.filter(task => task.status === window.currentTaskFilter);
  }
  
  // 应用项目过滤器
  if (window.currentProjectFilter && window.currentProjectFilter !== 'all') {
    filteredTasks = filteredTasks.filter(task => task.projectId == window.currentProjectFilter);
  }
  
  // 创建任务列
  statuses.forEach(status => {
    const column = document.createElement('div');
    column.className = 'task-column';
    
    const tasksInColumn = filteredTasks.filter(task => task.status === status.id);
    
    column.innerHTML = `
      <div class="column-header">
        <h3>${status.name}</h3>
        <div class="task-count">${tasksInColumn.length}</div>
      </div>
      <div class="column-tasks" data-status="${status.id}">
        ${tasksInColumn.map(task => {
          const project = appData.projects.find(p => p.id === task.projectId);
          const projectName = project ? project.name : '未知项目';
          
          // 检查任务是否延期或即将到期
          const today = new Date();
          const deadline = new Date(task.deadline);
          const daysUntilDeadline = Math.ceil((deadline - today) / (1000 * 60 * 60 * 24));
          
          let taskNameClass = '';
          if (task.status !== 'completed') {
            if (daysUntilDeadline < 0) {
              taskNameClass = 'task-overdue';
            } else if (daysUntilDeadline <= 2) {
              taskNameClass = 'task-soon-due';
            }
          }
          
          return `
            <div class="task-item" data-id="${task.id}">
              <div class="task-info">
                <h4 class="${taskNameClass}">${task.name}</h4>
                <p>${projectName} • 开始: ${task.startDate} • 截止: ${task.deadline}</p>
              </div>
              <div class="task-priority priority-${task.priority}">
                ${task.priority === 'high' ? '高' : task.priority === 'medium' ? '中' : '低'}
              </div>
              <div class="task-actions">
                <button class="action-btn edit-task-btn" title="编辑任务"><i class="fas fa-edit"></i></button>
                <button class="action-btn delete-btn" title="删除任务"><i class="fas fa-trash"></i></button>
              </div>
            </div>
          `;
        }).join('')}
      </div>
    `;
    
    // 为任务项添加事件
    column.querySelectorAll('.edit-task-btn').forEach((btn, index) => {
      btn.addEventListener('click', () => {
        const task = tasksInColumn[index];
        openEditTaskModal(task);
      });
    });
    
    column.querySelectorAll('.delete-btn').forEach((btn, index) => {
      btn.addEventListener('click', () => {
        const task = tasksInColumn[index];
        if (confirm(`确定要删除任务 "${task.name}" 吗?`)) {
          deleteTask(task.id);
        }
      });
    });
    
    container.appendChild(column);
  });
}

// 渲染团队页面
function renderTeamPage() {
  const container = document.getElementById('teamMembers');
  container.innerHTML = '';
  
  appData.teamMembers.forEach(member => {
    const card = createTeamMemberCard(member);
    container.appendChild(card);
  });
}

// 渲染日历
function renderCalendar() {
  const calendarGrid = document.getElementById('calendarGrid');
  const calendarMonth = document.getElementById('calendarMonth');
  
  // 设置月份标题
  const monthNames = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"];
  calendarMonth.textContent = `${window.currentCalendarDate.getFullYear()}年 ${monthNames[window.currentCalendarDate.getMonth()]}`;
  
  // 清空日历
  calendarGrid.innerHTML = '';
  
  // 添加星期标题
  const weekdays = ["日", "一", "二", "三", "四", "五", "六"];
  weekdays.forEach(day => {
    const dayElement = document.createElement('div');
    dayElement.className = 'calendar-day-header';
    dayElement.textContent = day;
    calendarGrid.appendChild(dayElement);
  });
  
  // 获取当月第一天和最后一天
  const firstDay = new Date(window.currentCalendarDate.getFullYear(), window.currentCalendarDate.getMonth(), 1);
  const lastDay = new Date(window.currentCalendarDate.getFullYear(), window.currentCalendarDate.getMonth() + 1, 0);
  
  // 获取第一天是星期几 (0 = 星期日, 6 = 星期六)
  const firstDayIndex = firstDay.getDay();
  
  // 填充空白
  for (let i = 0; i < firstDayIndex; i++) {
    const emptyDay = document.createElement('div');
    emptyDay.className = 'calendar-day';
    calendarGrid.appendChild(emptyDay);
  }
  
  // 填充日期
  const today = new Date();
  for (let day = 1; day <= lastDay.getDate(); day++) {
    const dayElement = document.createElement('div');
    dayElement.className = 'calendar-day selectable';
    
    // 检查是否是今天
    if (window.currentCalendarDate.getFullYear() === today.getFullYear() &&
        window.currentCalendarDate.getMonth() === today.getMonth() &&
        day === today.getDate()) {
      dayElement.classList.add('today');
    }
    
    const dateStr = `${window.currentCalendarDate.getFullYear()}-${(window.currentCalendarDate.getMonth()+1).toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
    
    // 查找当天的日历事件
    const dayEvents = appData.calendarEvents.filter(event => event.date === dateStr);
    
    dayElement.innerHTML = `<div>${day}</div>`;
    
    // 添加事件
    dayEvents.forEach(event => {
      const eventElement = document.createElement('div');
      eventElement.className = 'calendar-event';
      eventElement.textContent = event.title;
      dayElement.appendChild(eventElement);
    });
    
    // 添加编辑按钮
    const editBtn = document.createElement('button');
    editBtn.className = 'calendar-event-edit';
    editBtn.innerHTML = '<i class="fas fa-edit"></i>';
    editBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      openCalendarEventModal(dateStr);
    });
    dayElement.appendChild(editBtn);
    
    // 添加点击事件
    dayElement.addEventListener('click', () => {
      openCalendarEventModal(dateStr);
    });
    
    calendarGrid.appendChild(dayElement);
  }
}

// 渲染进度管理页面
function renderProgressPage() {
  const projectSelect = document.getElementById('projectSelect');
  projectSelect.innerHTML = '<option value="">请选择项目</option>';
  
  appData.projects.forEach(project => {
    const option = document.createElement('option');
    option.value = project.id;
    option.textContent = project.name;
    projectSelect.appendChild(option);
  });
  
  // 默认显示第一个项目的横道图
  if (appData.projects.length > 0) {
    renderGanttChart(appData.projects[0].id);
  }
}

// 渲染横道图 - 优化后的版本
function renderGanttChart(projectId) {
  const container = document.getElementById('ganttChart');
  const timelineContainer = document.getElementById('ganttTimeline');
  container.innerHTML = '';
  timelineContainer.innerHTML = '';
  
  const project = appData.projects.find(p => p.id == projectId);
  if (!project) {
    container.innerHTML = '<p style="color: var(--gray); text-align: center; padding: 20px;">请选择项目</p>';
    return;
  }
  
  // 计算项目总体进度
  const projectProgress = calculateProjectProgress(projectId);
  
  // 获取项目开始和结束日期
  const startDate = new Date(project.startDate);
  const endDate = new Date(project.deadline);
  
  // 计算项目总天数
  const totalDays = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24));
  
  // 计算当前日期
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  
  // 计算当前日期在项目时间轴上的位置
  const daysFromStart = Math.ceil((today - startDate) / (1000 * 60 * 60 * 24));
  
  // 设置横道图容器的宽度 - 根据总天数动态计算
  const dayWidth = 60; // 每个日期单元的宽度(像素)
  const totalWidth = totalDays * dayWidth;
  timelineContainer.style.minWidth = totalWidth + 'px';
  
  // 生成时间线 - 每7天一个主要标记
  for (let i = 0; i <= totalDays; i++) {
    const date = new Date(startDate);
    date.setDate(startDate.getDate() + i);
    
    const timelineItem = document.createElement('div');
    timelineItem.className = 'gantt-timeline-item';
    
    // 每7天显示一个主要标记
    if (i % 7 === 0) {
      timelineItem.classList.add('major');
      timelineItem.textContent = `${date.getMonth()+1}/${date.getDate()}`;
    } else {
      // 其他天显示小点
      timelineItem.innerHTML = '<div style="width: 2px; height: 2px; background: var(--gray); border-radius: 50%; margin: 0 auto;"></div>';
    }
    
    timelineContainer.appendChild(timelineItem);
  }
  
  // 创建项目总体进度条
  const projectProgressElement = document.createElement('div');
  projectProgressElement.className = 'gantt-task';
  
  // 计算项目进度条的位置和宽度
  const projectLeft = 0;
  const projectWidth = totalWidth; // 项目占满整个时间轴
  
  projectProgressElement.innerHTML = `
    <div class="gantt-task-name">${project.name} (总体进度)</div>
    <div class="gantt-task-bar-container" style="position: relative; min-width: ${totalWidth}px;">
      <div class="gantt-task-bar" style="position: absolute; left: ${projectLeft}px; width: ${projectWidth}px;">
        <div class="gantt-progress" style="width: ${projectProgress}%"></div>
      </div>
      <div class="gantt-date-start" style="left: ${projectLeft}px;">${formatDate(startDate)}</div>
      <div class="gantt-date-end" style="left: ${projectLeft + projectWidth}px;">${formatDate(endDate)}</div>
    </div>
    <div style="margin-left: 10px; font-size: 0.8rem; min-width: 40px;">
      ${projectProgress}%
    </div>
  `;
  container.appendChild(projectProgressElement);
  
  // 显示项目下的任务
  const projectTasks = appData.tasks.filter(task => task.projectId == projectId);
  
  if (projectTasks.length === 0) {
    container.innerHTML += '<p style="color: var(--gray); text-align: center; padding: 20px;">该项目暂无任务</p>';
    return;
  }
  
  projectTasks.forEach(task => {
    // 根据任务状态计算进度
    const taskProgress = calculateTaskProgress(task.status);
    
    // 计算任务在时间线上的位置和宽度
    const taskStartDate = new Date(task.startDate);
    const taskEndDate = new Date(task.deadline);
    
    // 计算任务相对于项目开始日期的偏移量(天数)
    const taskStartOffset = Math.ceil((taskStartDate - startDate) / (1000 * 60 * 60 * 24));
    const taskDuration = Math.ceil((taskEndDate - taskStartDate) / (1000 * 60 * 60 * 24));
    
    // 计算任务在时间轴上的位置和宽度(像素)
    const taskLeft = Math.max(0, taskStartOffset * dayWidth);
    const taskWidth = Math.max(20, taskDuration * dayWidth); // 最小宽度20px
    
    const taskElement = document.createElement('div');
    taskElement.className = 'gantt-task';
    
    taskElement.innerHTML = `
      <div class="gantt-task-name">${task.name}</div>
      <div class="gantt-task-bar-container" style="position: relative; min-width: ${totalWidth}px;">
        <div class="gantt-task-bar" style="position: absolute; left: ${taskLeft}px; width: ${taskWidth}px;">
          <div class="gantt-progress" style="width: ${taskProgress}%"></div>
        </div>
        <div class="gantt-date-start" style="left: ${taskLeft}px;">${formatDate(taskStartDate)}</div>
        <div class="gantt-date-end" style="left: ${taskLeft + taskWidth}px;">${formatDate(taskEndDate)}</div>
      </div>
      <div style="margin-left: 10px; font-size: 0.8rem; min-width: 40px;">
        ${taskProgress}%
      </div>
    `;
    
    container.appendChild(taskElement);
  });
  
  // 添加当前日期指示线
  if (daysFromStart >= 0 && daysFromStart <= totalDays) {
    const currentDateLine = document.createElement('div');
    currentDateLine.className = 'gantt-current-date';
    currentDateLine.style.left = `${daysFromStart * dayWidth}px`;
    
    container.appendChild(currentDateLine);
  }
  
  // 添加滚动控制按钮
  addGanttScrollControls();
  
  // 初始滚动到当前日期位置
  setTimeout(() => {
    scrollToCurrentDate();
  }, 100);
}

// 格式化日期为 MM/DD 格式
function formatDate(date) {
  return `${date.getMonth()+1}/${date.getDate()}`;
}

// 添加横道图滚动控制
function addGanttScrollControls() {
  const ganttContainer = document.querySelector('.gantt-scroll-container');
  const existingControls = document.querySelector('.gantt-scroll-controls');
  
  if (existingControls) {
    existingControls.remove();
  }
  
  const scrollControls = document.createElement('div');
  scrollControls.className = 'gantt-scroll-controls';
  
  scrollControls.innerHTML = `
    <button class="gantt-scroll-btn" id="scrollLeftBtn"><i class="fas fa-chevron-left"></i> 向左滚动</button>
    <button class="gantt-scroll-btn" id="scrollTodayBtn">滚动到今天</button>
    <button class="gantt-scroll-btn" id="scrollRightBtn">向右滚动 <i class="fas fa-chevron-right"></i></button>
  `;
  
  ganttContainer.parentNode.insertBefore(scrollControls, ganttContainer.nextSibling);
  
  // 添加滚动事件监听
  document.getElementById('scrollLeftBtn').addEventListener('click', () => {
    ganttContainer.scrollBy({ left: -200, behavior: 'smooth' });
  });
  
  document.getElementById('scrollRightBtn').addEventListener('click', () => {
    ganttContainer.scrollBy({ left: 200, behavior: 'smooth' });
  });
  
  document.getElementById('scrollTodayBtn').addEventListener('click', scrollToCurrentDate);
}

// 滚动到当前日期
function scrollToCurrentDate() {
  const ganttContainer = document.querySelector('.gantt-scroll-container');
  const currentDateLine = document.querySelector('.gantt-current-date');
  
  if (currentDateLine && ganttContainer) {
    const currentDatePos = parseInt(currentDateLine.style.left);
    
    // 滚动到当前日期位置,使其位于容器中央
    ganttContainer.scrollTo({
      left: currentDatePos - ganttContainer.clientWidth / 2,
      behavior: 'smooth'
    });
  }
}

// 渲染报告页面
function renderReportsPage() {
  const fileProjectFilter = document.getElementById('fileProjectFilter');
  fileProjectFilter.innerHTML = '<option value="all">所有项目</option>';
  
  appData.projects.forEach(project => {
    const option = document.createElement('option');
    option.value = project.id;
    option.textContent = project.name;
    fileProjectFilter.appendChild(option);
  });
  
  renderFileList();
}

// 渲染文件列表
function renderFileList() {
  const fileList = document.getElementById('fileList');
  fileList.innerHTML = '';
  
  const projectFilter = document.getElementById('fileProjectFilter').value;
  let filesToShow = appData.files;
  
  if (projectFilter !== 'all') {
    filesToShow = appData.files.filter(file => file.projectId == projectFilter);
  }
  
  if (filesToShow.length === 0) {
    fileList.innerHTML = '<p style="text-align: center; color: var(--gray); padding: 20px;">暂无文件</p>';
    return;
  }
  
  filesToShow.forEach(file => {
    const project = appData.projects.find(p => p.id === file.projectId);
    const projectName = project ? project.name : '未知项目';
    
    const fileIcon = getFileIcon(file.type);
    
    const fileItem = document.createElement('div');
    fileItem.className = 'file-item';
    fileItem.innerHTML = `
      <div class="file-info">
        <div class="file-icon">
          <i class="${fileIcon}"></i>
        </div>
        <div class="file-details">
          <h4>${file.name}</h4>
          <p>关联项目: ${projectName} • 上传日期: ${file.uploadDate} • 大小: ${file.size}</p>
          ${file.description ? `<p>描述: ${file.description}</p>` : ''}
        </div>
      </div>
      <div class="file-actions">
        <button class="action-btn download-file-btn" title="下载文件"><i class="fas fa-download"></i></button>
        <button class="action-btn delete-file-btn" title="删除文件"><i class="fas fa-trash"></i></button>
      </div>
    `;
    
    // 添加下载文件事件
    const downloadBtn = fileItem.querySelector('.download-file-btn');
    downloadBtn.addEventListener('click', async () => {
      const result = await window.electronAPI.downloadFile(file);
      if (result.success) {
        showNotification(`文件 "${file.name}" 下载成功!`, 'success');
      } else {
        showNotification(`下载文件失败: ${result.error}`, 'error');
      }
    });
    
    // 添加删除文件事件
    const deleteBtn = fileItem.querySelector('.delete-file-btn');
    deleteBtn.addEventListener('click', () => {
      if (confirm(`确定要删除文件 "${file.name}" 吗?`)) {
        deleteFile(file.id);
      }
    });
    
    fileList.appendChild(fileItem);
  });
}

// 获取文件图标
function getFileIcon(fileType) {
  const iconMap = {
    'docx': 'fas fa-file-word',
    'pdf': 'fas fa-file-pdf',
    'xlsx': 'fas fa-file-excel',
    'ppt': 'fas fa-file-powerpoint',
    'zip': 'fas fa-file-archive',
    'jpg': 'fas fa-file-image',
    'png': 'fas fa-file-image',
    'txt': 'fas fa-file-alt',
    'default': 'fas fa-file'
  };
  
  return iconMap[fileType] || iconMap.default;
}

// 删除文件
function deleteFile(fileId) {
  appData.files = appData.files.filter(f => f.id !== fileId);
  saveData();
  renderReportsPage();
  showNotification('文件已删除!', 'success');
}

// 计算任务进度
function calculateTaskProgress(status) {
  switch(status) {
    case 'pending': return 0;
    case 'progress': return 40;
    case 'review': return 80;
    case 'completed': return 100;
    default: return 0;
  }
}

// 计算项目总体进度
function calculateProjectProgress(projectId) {
  const projectTasks = appData.tasks.filter(task => task.projectId == projectId);
  
  if (projectTasks.length === 0) {
    return 0;
  }
  
  const totalProgress = projectTasks.reduce((sum, task) => {
    return sum + calculateTaskProgress(task.status);
  }, 0);
  
  return Math.round(totalProgress / projectTasks.length);
}

// 打开编辑项目模态框
function openEditProjectModal(project) {
  document.getElementById('projectId').value = project.id;
  document.getElementById('projectName').value = project.name;
  document.getElementById('projectDepartment').value = project.department;
  document.getElementById('projectManager').value = project.manager;
  document.getElementById('projectStartDate').value = project.startDate;
  document.getElementById('projectDeadline').value = project.deadline;
  document.getElementById('projectStatus').value = project.status;
  document.getElementById('projectDescription').value = project.description || '';
  
  document.getElementById('projectModalTitle').textContent = '编辑项目';
  
  // 显示模态框
  document.getElementById('projectModal').classList.add('active');
}

// 打开编辑任务模态框
function openEditTaskModal(task) {
  document.getElementById('taskId').value = task.id;
  document.getElementById('taskName').value = task.name;
  document.getElementById('taskStartDate').value = task.startDate;
  document.getElementById('taskDeadline').value = task.deadline;
  document.getElementById('taskPriority').value = task.priority;
  document.getElementById('taskStatus').value = task.status;
  document.getElementById('taskDescription').value = task.description || '';
  
  // 填充项目选择
  const projectSelect = document.getElementById('taskProject');
  projectSelect.innerHTML = '<option value="">请选择项目</option>';
  
  appData.projects.forEach(project => {
    const option = document.createElement('option');
    option.value = project.id;
    option.textContent = project.name;
    if (project.id === task.projectId) {
      option.selected = true;
    }
    projectSelect.appendChild(option);
  });
  
  document.getElementById('taskModalTitle').textContent = '编辑任务';
  
  // 显示模态框
  document.getElementById('taskModal').classList.add('active');
}

// 打开编辑团队成员模态框
function openEditTeamMemberModal(member) {
  document.getElementById('teamMemberId').value = member.id;
  document.getElementById('teamMemberName').value = member.name;
  document.getElementById('teamMemberRole').value = member.role;
  document.getElementById('teamMemberSkills').value = member.skills ? member.skills.join(', ') : '';
  
  document.getElementById('teamMemberModalTitle').textContent = '编辑团队成员';
  
  // 显示模态框
  document.getElementById('teamMemberModal').classList.add('active');
}

// 打开日历事件编辑模态框
function openCalendarEventModal(date) {
  document.getElementById('calendarEventDate').value = date;
  
  // 查找当天的事件
  const existingEvent = appData.calendarEvents.find(event => event.date === date);
  
  if (existingEvent) {
    document.getElementById('calendarEventId').value = existingEvent.id;
    document.getElementById('calendarEventTitle').value = existingEvent.title;
    document.getElementById('calendarEventDescription').value = existingEvent.description || '';
    document.getElementById('calendarEventModalTitle').textContent = '编辑事件';
  } else {
    document.getElementById('calendarEventId').value = '';
    document.getElementById('calendarEventTitle').value = '';
    document.getElementById('calendarEventDescription').value = '';
    document.getElementById('calendarEventModalTitle').textContent = '添加事件';
  }
  
  // 显示模态框
  document.getElementById('calendarEventModal').classList.add('active');
}

// 打开文件上传模态框
function openFileUploadModal() {
  const projectSelect = document.getElementById('uploadFileProject');
  projectSelect.innerHTML = '<option value="">请选择项目</option>';
  
  appData.projects.forEach(project => {
    const option = document.createElement('option');
    option.value = project.id;
    option.textContent = project.name;
    projectSelect.appendChild(option);
  });
  
  // 重置表单
  document.getElementById('uploadFileDescription').value = '';
  document.getElementById('uploadFileInput').value = '';
  document.getElementById('confirmFileUpload').disabled = true;
  
  // 显示模态框
  document.getElementById('fileUploadModal').classList.add('active');
}

// 设置事件监听器
function setupEventListeners() {
  // 页面导航
  setupPageNavigation();
  
  // 模态框功能
  setupModals();
  
  // 日历功能
  setupCalendar();
  
  // 文件上传功能
  setupFileUpload();
  
  // 搜索功能
  setupSearch();
  
  // 项目表单提交
  document.getElementById('projectForm').addEventListener('submit', handleProjectForm);
  
  // 任务表单提交
  document.getElementById('taskForm').addEventListener('submit', handleTaskForm);
  
  // 团队成员表单提交
  document.getElementById('teamMemberForm').addEventListener('submit', handleTeamMemberForm);
  
  // 日历事件表单提交
  document.getElementById('calendarEventForm').addEventListener('submit', handleCalendarEventForm);
  
  // 任务过滤器
  setupTaskFilters();
  
  // 仪表盘编辑按钮
  setupDashboardEditButtons();
  
  // 项目选择变化事件
  document.getElementById('projectSelect').addEventListener('change', function() {
    renderGanttChart(this.value);
  });
  
  // 文件项目筛选器变化事件
  document.getElementById('fileProjectFilter').addEventListener('change', function() {
    renderFileList();
  });
  
  // 导入项目按钮
  document.getElementById('importProjectBtn').addEventListener('click', function() {
    document.getElementById('fileInput2').click();
  });
  
  // 单个项目导入处理
  document.getElementById('fileInput2').addEventListener('change', handleSingleProjectImport);
}

// 设置页面导航
function setupPageNavigation() {
  const navLinks = document.querySelectorAll('.nav-link');
  const pageContents = document.querySelectorAll('.page-content');
  
  navLinks.forEach(link => {
    link.addEventListener('click', function(e) {
      e.preventDefault();
      
      const targetPage = this.getAttribute('data-page');
      
      navLinks.forEach(l => l.classList.remove('active'));
      this.classList.add('active');
      
      pageContents.forEach(content => {
        content.classList.remove('active');
      });
      
      document.getElementById(targetPage).classList.add('active');
      
      // 如果是进度管理页面,渲染横道图
      if (targetPage === 'progress') {
        renderProgressPage();
      }
      
      // 如果是数据管理页面,更新数据统计
      if (targetPage === 'dataManagement') {
        updateDataStats();
      }
      
      // 如果是报告页面,渲染文件列表
      if (targetPage === 'reports') {
        renderReportsPage();
      }
      
      // 如果是任务页面,清除项目过滤器,显示所有任务
      if (targetPage === 'tasks') {
        window.currentProjectFilter = 'all';
        window.currentTaskFilter = 'all';
        
        // 设置所有任务过滤器为激活状态
        const filterBtns = document.querySelectorAll('.filter-btn');
        filterBtns.forEach(btn => {
          btn.classList.remove('active');
          if (btn.dataset.filter === 'all') {
            btn.classList.add('active');
          }
        });
        
        // 更新项目筛选器
        const projectFilter = document.getElementById('taskProjectFilter');
        projectFilter.value = 'all';
        
        renderTasksPage();
      }
    });
  });
}

// 设置模态框
function setupModals() {
  // 关闭模态框
  const closeButtons = document.querySelectorAll('.close-modal, .btn-secondary');
  closeButtons.forEach(button => {
    button.addEventListener('click', closeAllModals);
  });
  
  // 点击模态框外部关闭
  const modals = document.querySelectorAll('.modal');
  modals.forEach(modal => {
    modal.addEventListener('click', (e) => {
      if (e.target === modal) {
        closeAllModals();
      }
    });
  });
}

// 设置日历功能
function setupCalendar() {
  document.getElementById('prevMonth').addEventListener('click', () => {
    window.currentCalendarDate.setMonth(window.currentCalendarDate.getMonth() - 1);
    renderCalendar();
  });
  
  document.getElementById('nextMonth').addEventListener('click', () => {
    window.currentCalendarDate.setMonth(window.currentCalendarDate.getMonth() + 1);
    renderCalendar();
  });
}

// 设置文件上传功能
function setupFileUpload() {
  // 文件上传按钮
  document.getElementById('uploadFileBtn').addEventListener('click', openFileUploadModal);
  
  // 文件上传区域事件
  const uploadFileArea = document.getElementById('uploadFileArea');
  const uploadFileInput = document.getElementById('uploadFileInput');
  const confirmFileUpload = document.getElementById('confirmFileUpload');
  
  uploadFileArea.addEventListener('click', () => {
    uploadFileInput.click();
  });
  
  uploadFileArea.addEventListener('dragover', (e) => {
    e.preventDefault();
    uploadFileArea.style.borderColor = 'var(--primary)';
    uploadFileArea.style.background = 'rgba(0, 243, 255, 0.1)';
  });
  
  uploadFileArea.addEventListener('dragleave', () => {
    uploadFileArea.style.borderColor = 'var(--card-border)';
    uploadFileArea.style.background = '';
  });
  
  uploadFileArea.addEventListener('drop', (e) => {
    e.preventDefault();
    uploadFileArea.style.borderColor = 'var(--card-border)';
    uploadFileArea.style.background = '';
    
    if (e.dataTransfer.files.length > 0) {
      uploadFileInput.files = e.dataTransfer.files;
      handleUploadFileSelect();
    }
  });
  
  uploadFileInput.addEventListener('change', handleUploadFileSelect);
  
  // 确认文件上传
  confirmFileUpload.addEventListener('click', handleFileUpload);
  
  // 取消文件上传
  document.getElementById('cancelFileUpload').addEventListener('click', () => {
    closeAllModals();
  });
}

// 处理上传文件选择
function handleUploadFileSelect() {
  const uploadFileInput = document.getElementById('uploadFileInput');
  const confirmFileUpload = document.getElementById('confirmFileUpload');
  
  if (uploadFileInput.files.length > 0) {
    confirmFileUpload.disabled = false;
  } else {
    confirmFileUpload.disabled = true;
  }
}

// 处理文件上传
async function handleFileUpload() {
  const uploadFileProject = document.getElementById('uploadFileProject');
  const uploadFileDescription = document.getElementById('uploadFileDescription');
  const uploadFileInput = document.getElementById('uploadFileInput');
  
  if (!uploadFileProject.value) {
    showNotification('请选择关联项目', 'error');
    return;
  }
  
  if (uploadFileInput.files.length === 0) {
    showNotification('请选择要上传的文件', 'error');
    return;
  }
  
  const file = uploadFileInput.files[0];
  
  // 读取文件为Base64
  const reader = new FileReader();
  reader.onload = async function(e) {
    const fileInfo = {
      fileName: file.name,
      fileData: e.target.result,
      projectId: uploadFileProject.value,
      description: uploadFileDescription.value
    };
    
    const result = await window.electronAPI.saveFile(fileInfo);
    
    if (result.success) {
      // 添加到应用数据
      appData.files.push(result.fileInfo);
      
      // 保存数据
      await saveData();
      
      // 更新界面
      renderReportsPage();
      
      closeAllModals();
      showNotification('文件上传成功!', 'success');
    } else {
      showNotification('文件上传失败: ' + result.error, 'error');
    }
  };
  
  reader.onerror = function() {
    showNotification('文件读取失败', 'error');
  };
  
  reader.readAsDataURL(file);
}

// 设置搜索功能
function setupSearch() {
  // 全局搜索
  document.getElementById('globalSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    
    // 搜索项目
    const projectCards = document.querySelectorAll('.project-card');
    projectCards.forEach(card => {
      const projectName = card.querySelector('h4').textContent.toLowerCase();
      const projectManager = card.querySelector('p').textContent.toLowerCase();
      
      if (projectName.includes(searchTerm) || projectManager.includes(searchTerm)) {
        card.style.display = 'block';
      } else {
        card.style.display = 'none';
      }
    });
    
    // 搜索任务
    const taskItems = document.querySelectorAll('.task-item');
    taskItems.forEach(item => {
      const taskName = item.querySelector('h4').textContent.toLowerCase();
      const taskProject = item.querySelector('p').textContent.toLowerCase();
      
      if (taskName.includes(searchTerm) || taskProject.includes(searchTerm)) {
        item.style.display = 'flex';
      } else {
        item.style.display = 'none';
      }
    });
    
    // 搜索团队成员
    const teamCards = document.querySelectorAll('.team-member-card');
    teamCards.forEach(card => {
      const memberName = card.querySelector('h4').textContent.toLowerCase();
      const memberRole = card.querySelector('p').textContent.toLowerCase();
      
      if (memberName.includes(searchTerm) || memberRole.includes(searchTerm)) {
        card.style.display = 'flex';
      } else {
        card.style.display = 'none';
      }
    });
  });
  
  // 项目页面搜索
  document.getElementById('projectSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    const projectCards = document.querySelectorAll('#allProjects .project-card');
    
    projectCards.forEach(card => {
      const projectName = card.querySelector('h4').textContent.toLowerCase();
      const projectManager = card.querySelector('p').textContent.toLowerCase();
      
      if (projectName.includes(searchTerm) || projectManager.includes(searchTerm)) {
        card.style.display = 'block';
      } else {
        card.style.display = 'none';
      }
    });
  });
  
  // 任务页面搜索
  document.getElementById('taskSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    const taskItems = document.querySelectorAll('.task-item');
    
    taskItems.forEach(item => {
      const taskName = item.querySelector('h4').textContent.toLowerCase();
      const taskProject = item.querySelector('p').textContent.toLowerCase();
      
      if (taskName.includes(searchTerm) || taskProject.includes(searchTerm)) {
        item.style.display = 'flex';
      } else {
        item.style.display = 'none';
      }
    });
  });
  
  // 团队页面搜索
  document.getElementById('teamSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    const teamCards = document.querySelectorAll('#teamMembers .team-member-card');
    
    teamCards.forEach(card => {
      const memberName = card.querySelector('h4').textContent.toLowerCase();
      const memberRole = card.querySelector('p').textContent.toLowerCase();
      
      if (memberName.includes(searchTerm) || memberRole.includes(searchTerm)) {
        card.style.display = 'flex';
      } else {
        card.style.display = 'none';
      }
    });
  });
  
  // 日历页面搜索
  document.getElementById('calendarSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    const calendarDays = document.querySelectorAll('.calendar-day');
    
    calendarDays.forEach(day => {
      const dayNumber = day.querySelector('div')?.textContent.toLowerCase();
      if (dayNumber && dayNumber.includes(searchTerm)) {
        day.style.backgroundColor = 'rgba(0, 243, 255, 0.2)';
      } else {
        day.style.backgroundColor = '';
      }
    });
  });
  
  // 进度管理页面搜索
  document.getElementById('progressSearch').addEventListener('input', function() {
    const searchTerm = this.value.toLowerCase();
    const projectSelect = document.getElementById('projectSelect');
    const options = projectSelect.querySelectorAll('option');
    
    options.forEach(option => {
      const projectName = option.textContent.toLowerCase();
      
      if (projectName.includes(searchTerm)) {
        option.style.display = 'block';
      } else {
        option.style.display = 'none';
      }
    });
  });
}

// 设置任务过滤器
function setupTaskFilters() {
  const filterBtns = document.querySelectorAll('.filter-btn');
  const projectFilter = document.getElementById('taskProjectFilter');
  
  // 填充项目筛选器
  projectFilter.innerHTML = '<option value="all">所有项目</option>';
  appData.projects.forEach(project => {
    const option = document.createElement('option');
    option.value = project.id;
    option.textContent = project.name;
    projectFilter.appendChild(option);
  });
  
  filterBtns.forEach(btn => {
    btn.addEventListener('click', function() {
      filterBtns.forEach(b => b.classList.remove('active'));
      this.classList.add('active');
      
      window.currentTaskFilter = this.dataset.filter;
      renderTasksPage();
    });
  });
  
  projectFilter.addEventListener('change', function() {
    window.currentProjectFilter = this.value;
    renderTasksPage();
  });
}

// 设置仪表盘编辑按钮
function setupDashboardEditButtons() {
  // 添加项目按钮
  document.getElementById('addProjectBtn').addEventListener('click', () => {
    document.getElementById('projectId').value = '';
    document.getElementById('projectName').value = '';
    document.getElementById('projectDepartment').value = '';
    document.getElementById('projectManager').value = '';
    document.getElementById('projectStartDate').value = '';
    document.getElementById('projectDeadline').value = '';
    document.getElementById('projectStatus').value = 'planning';
    document.getElementById('projectDescription').value = '';
    
    document.getElementById('projectModalTitle').textContent = '新建项目';
    document.getElementById('projectModal').classList.add('active');
  });
  
  document.getElementById('addProjectBtn2').addEventListener('click', () => {
    document.getElementById('projectId').value = '';
    document.getElementById('projectName').value = '';
    document.getElementById('projectDepartment').value = '';
    document.getElementById('projectManager').value = '';
    document.getElementById('projectStartDate').value = '';
    document.getElementById('projectDeadline').value = '';
    document.getElementById('projectStatus').value = 'planning';
    document.getElementById('projectDescription').value = '';
    
    document.getElementById('projectModalTitle').textContent = '新建项目';
    document.getElementById('projectModal').classList.add('active');
  });
  
  // 添加任务按钮
  document.getElementById('addTaskBtn').addEventListener('click', () => {
    document.getElementById('taskId').value = '';
    document.getElementById('taskName').value = '';
    document.getElementById('taskStartDate').value = '';
    document.getElementById('taskDeadline').value = '';
    document.getElementById('taskPriority').value = 'medium';
    document.getElementById('taskStatus').value = 'pending';
    document.getElementById('taskDescription').value = '';
    
    // 填充项目选择
    const projectSelect = document.getElementById('taskProject');
    projectSelect.innerHTML = '<option value="">请选择项目</option>';
    
    appData.projects.forEach(project => {
      const option = document.createElement('option');
      option.value = project.id;
      option.textContent = project.name;
      projectSelect.appendChild(option);
    });
    
    document.getElementById('taskModalTitle').textContent = '新建任务';
    document.getElementById('taskModal').classList.add('active');
  });
  
  // 添加团队成员按钮
  document.getElementById('addTeamMemberBtn').addEventListener('click', () => {
    document.getElementById('teamMemberId').value = '';
    document.getElementById('teamMemberName').value = '';
    document.getElementById('teamMemberRole').value = '';
    document.getElementById('teamMemberSkills').value = '';
    
    document.getElementById('teamMemberModalTitle').textContent = '添加团队成员';
    document.getElementById('teamMemberModal').classList.add('active');
  });
  
  document.getElementById('addTeamMemberBtn2').addEventListener('click', () => {
    document.getElementById('teamMemberId').value = '';
    document.getElementById('teamMemberName').value = '';
    document.getElementById('teamMemberRole').value = '';
    document.getElementById('teamMemberSkills').value = '';
    
    document.getElementById('teamMemberModalTitle').textContent = '添加团队成员';
    document.getElementById('teamMemberModal').classList.add('active');
  });
}

// 关闭所有模态框
function closeAllModals() {
  const modals = document.querySelectorAll('.modal');
  modals.forEach(modal => {
    modal.classList.remove('active');
  });
}

// 处理项目表单提交
async function handleProjectForm(e) {
  e.preventDefault();
  
  const projectId = document.getElementById('projectId').value;
  const projectName = document.getElementById('projectName').value;
  const projectDepartment = document.getElementById('projectDepartment').value;
  const projectManager = document.getElementById('projectManager').value;
  const projectStartDate = document.getElementById('projectStartDate').value;
  const projectDeadline = document.getElementById('projectDeadline').value;
  const projectStatus = document.getElementById('projectStatus').value;
  const projectDescription = document.getElementById('projectDescription').value;
  
  let project;
  let isNew = false;
  
  if (projectId) {
    // 编辑现有项目
    project = appData.projects.find(p => p.id == projectId);
    
    // 记录变更
    const changeLogItem = {
      date: new Date().toISOString().split('T')[0],
      user: appData.currentUser,
      action: `更新项目信息: ${projectName}`
    };
    
    if (!project.changeLog) {
      project.changeLog = [];
    }
    project.changeLog.push(changeLogItem);
    
    // 更新项目信息
    project.name = projectName;
    project.department = projectDepartment;
    project.manager = projectManager;
    project.startDate = projectStartDate;
    project.deadline = projectDeadline;
    project.status = projectStatus;
    project.description = projectDescription;
  } else {
    // 创建新项目
    project = {
      id: appData.projects.length > 0 ? Math.max(...appData.projects.map(p => p.id)) + 1 : 1,
      name: projectName,
      department: projectDepartment,
      manager: projectManager,
      progress: 0,
      startDate: projectStartDate,
      deadline: projectDeadline,
      status: projectStatus,
      team: [projectManager.charAt(0)],
      completedTasks: 0,
      totalTasks: 0,
      description: projectDescription,
      changeLog: [
        {
          date: new Date().toISOString().split('T')[0],
          user: appData.currentUser,
          action: "创建项目"
        }
      ]
    };
    
    appData.projects.push(project);
    isNew = true;
  }
  
  await saveData();
  updateStats();
  renderDashboard();
  renderProjectsPage();
  renderReportsPage();
  
  closeAllModals();
  document.getElementById('projectForm').reset();
  
  showNotification(`项目${isNew ? '创建' : '更新'}成功!`, 'success');
}

// 处理任务表单提交
async function handleTaskForm(e) {
  e.preventDefault();
  
  const taskId = document.getElementById('taskId').value;
  const taskName = document.getElementById('taskName').value;
  const taskProject = document.getElementById('taskProject').value;
  const taskStartDate = document.getElementById('taskStartDate').value;
  const taskDeadline = document.getElementById('taskDeadline').value;
  const taskPriority = document.getElementById('taskPriority').value;
  const taskStatus = document.getElementById('taskStatus').value;
  const taskDescription = document.getElementById('taskDescription').value;
  
  let task;
  let isNew = false;
  
  if (taskId) {
    // 编辑现有任务
    task = appData.tasks.find(t => t.id == taskId);
    
    // 更新任务信息
    task.name = taskName;
    task.projectId = parseInt(taskProject);
    task.startDate = taskStartDate;
    task.deadline = taskDeadline;
    task.priority = taskPriority;
    task.status = taskStatus;
    task.description = taskDescription;
  } else {
    // 创建新任务
    task = {
      id: appData.tasks.length > 0 ? Math.max(...appData.tasks.map(t => t.id)) + 1 : 1,
      name: taskName,
      projectId: parseInt(taskProject),
      startDate: taskStartDate,
      deadline: taskDeadline,
      priority: taskPriority,
      status: taskStatus,
      description: taskDescription
    };
    
    appData.tasks.push(task);
    isNew = true;
  }
  
  await saveData();
  updateStats();
  renderDashboard();
  renderTasksPage();
  renderProgressPage();
  
  closeAllModals();
  document.getElementById('taskForm').reset();
  
  showNotification(`任务${isNew ? '创建' : '更新'}成功!`, 'success');
}

// 处理团队成员表单提交
async function handleTeamMemberForm(e) {
  e.preventDefault();
  
  const teamMemberId = document.getElementById('teamMemberId').value;
  const teamMemberName = document.getElementById('teamMemberName').value;
  const teamMemberRole = document.getElementById('teamMemberRole').value;
  const teamMemberSkills = document.getElementById('teamMemberSkills').value;
  
  let member;
  let isNew = false;
  
  if (teamMemberId) {
    // 编辑现有成员
    member = appData.teamMembers.find(m => m.id == teamMemberId);
    
    // 更新成员信息
    member.name = teamMemberName;
    member.role = teamMemberRole;
    member.skills = teamMemberSkills ? teamMemberSkills.split(',').map(s => s.trim()) : [];
  } else {
    // 创建新成员
    member = {
      id: appData.teamMembers.length > 0 ? Math.max(...appData.teamMembers.map(m => m.id)) + 1 : 1,
      name: teamMemberName,
      role: teamMemberRole,
      avatar: teamMemberName.charAt(0),
      skills: teamMemberSkills ? teamMemberSkills.split(',').map(s => s.trim()) : []
    };
    
    appData.teamMembers.push(member);
    isNew = true;
  }
  
  await saveData();
  renderDashboard();
  renderTeamPage();
  
  closeAllModals();
  document.getElementById('teamMemberForm').reset();
  
  showNotification(`团队成员${isNew ? '添加' : '更新'}成功!`, 'success');
}

// 处理日历事件表单提交
async function handleCalendarEventForm(e) {
  e.preventDefault();
  
  const eventId = document.getElementById('calendarEventId').value;
  const eventDate = document.getElementById('calendarEventDate').value;
  const eventTitle = document.getElementById('calendarEventTitle').value;
  const eventDescription = document.getElementById('calendarEventDescription').value;
  
  let event;
  let isNew = false;
  
  if (eventId) {
    // 编辑现有事件
    event = appData.calendarEvents.find(e => e.id == eventId);
    
    // 更新事件信息
    event.title = eventTitle;
    event.description = eventDescription;
  } else {
    // 创建新事件
    event = {
      id: appData.calendarEvents.length > 0 ? Math.max(...appData.calendarEvents.map(e => e.id)) + 1 : 1,
      date: eventDate,
      title: eventTitle,
      description: eventDescription
    };
    
    appData.calendarEvents.push(event);
    isNew = true;
  }
  
  await saveData();
  renderCalendar();
  
  closeAllModals();
  document.getElementById('calendarEventForm').reset();
  
  showNotification(`日历事件${isNew ? '添加' : '更新'}成功!`, 'success');
}

// 删除项目
async function deleteProject(projectId) {
  // 删除项目
  appData.projects = appData.projects.filter(p => p.id !== projectId);
  
  // 删除关联的任务
  appData.tasks = appData.tasks.filter(t => t.projectId !== projectId);
  
  // 删除关联的文件
  appData.files = appData.files.filter(f => f.projectId !== projectId);
  
  await saveData();
  updateStats();
  renderDashboard();
  renderProjectsPage();
  renderTasksPage();
  renderReportsPage();
  renderProgressPage();
  
  showNotification('项目已删除!', 'success');
}

// 删除任务
async function deleteTask(taskId) {
  appData.tasks = appData.tasks.filter(t => t.id !== taskId);
  
  await saveData();
  updateStats();
  renderDashboard();
  renderTasksPage();
  renderProgressPage();
  
  showNotification('任务已删除!', 'success');
}

// 删除团队成员
async function deleteTeamMember(memberId) {
  appData.teamMembers = appData.teamMembers.filter(m => m.id !== memberId);
  
  await saveData();
  renderDashboard();
  renderTeamPage();
  
  showNotification('团队成员已删除!', 'success');
}

// 导出单个项目
async function exportSingleProject(projectId) {
  const project = appData.projects.find(p => p.id === projectId);
  if (!project) return;
  
  // 获取项目相关的任务
  const projectTasks = appData.tasks.filter(t => t.projectId === projectId);
  
  // 获取项目相关的文件
  const projectFiles = appData.files.filter(f => f.projectId === projectId);
  
  // 创建导出数据
  const exportData = {
    project: project,
    tasks: projectTasks,
    files: projectFiles,
    exportDate: new Date().toISOString(),
    version: '1.0'
  };
  
  const result = await window.electronAPI.exportData(exportData);
  if (result.success) {
    showNotification(`项目 "${project.name}" 导出成功!`, 'success');
  } else {
    showNotification(`导出项目失败: ${result.error}`, 'error');
  }
}

// 查看项目任务
function viewProjectTasks(projectId) {
  // 切换到任务页面
  const taskNavLink = document.querySelector('[data-page="tasks"]');
  const taskPage = document.getElementById('tasks');
  
  document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
  document.querySelectorAll('.page-content').forEach(c => c.classList.remove('active'));
  
  taskNavLink.classList.add('active');
  taskPage.classList.add('active');
  
  // 设置项目筛选器
  const projectFilter = document.getElementById('taskProjectFilter');
  projectFilter.value = projectId;
  window.currentProjectFilter = projectId;
  
  // 设置所有任务过滤器
  const filterBtns = document.querySelectorAll('.filter-btn');
  filterBtns.forEach(btn => {
    btn.classList.remove('active');
    if (btn.dataset.filter === 'all') {
      btn.classList.add('active');
    }
  });
  window.currentTaskFilter = 'all';
  
  // 渲染任务页面
  renderTasksPage();
}

// 处理单个项目导入
async function handleSingleProjectImport(e) {
  const file = e.target.files[0];
  if (!file) return;
  
  const reader = new FileReader();
  
  reader.onload = async function(e) {
    try {
      const importedData = JSON.parse(e.target.result);
      
      // 验证数据格式
      if (!importedData.project) {
        showNotification('项目数据格式不正确,无法导入', 'error');
        return;
      }
      
      // 确认导入
      if (confirm(`确定要导入项目 "${importedData.project.name}" 吗?`)) {
        // 检查项目是否已存在
        const existingProject = appData.projects.find(p => p.id === importedData.project.id);
        
        if (existingProject) {
          // 更新现有项目
          Object.assign(existingProject, importedData.project);
          
          // 更新或添加任务
          if (importedData.tasks) {
            importedData.tasks.forEach(task => {
              const existingTask = appData.tasks.find(t => t.id === task.id);
              if (existingTask) {
                Object.assign(existingTask, task);
              } else {
                appData.tasks.push(task);
              }
            });
          }
          
          // 更新或添加文件
          if (importedData.files) {
            importedData.files.forEach(file => {
              const existingFile = appData.files.find(f => f.id === file.id);
              if (existingFile) {
                Object.assign(existingFile, file);
              } else {
                appData.files.push(file);
              }
            });
          }
        } else {
          // 添加新项目
          appData.projects.push(importedData.project);
          
          // 添加任务
          if (importedData.tasks) {
            appData.tasks.push(...importedData.tasks);
          }
          
          // 添加文件
          if (importedData.files) {
            appData.files.push(...importedData.files);
          }
        }
        
        // 保存到本地存储
        await saveData();
        
        // 更新界面
        updateStats();
        renderDashboard();
        renderProjectsPage();
        renderTasksPage();
        renderReportsPage();
        renderProgressPage();
        
        // 重置文件输入
        document.getElementById('fileInput2').value = '';
        
        showNotification('项目导入成功!', 'success');
      }
    } catch (error) {
      console.error('导入失败:', error);
      showNotification('文件解析失败,请检查文件格式', 'error');
    }
  };
  
  reader.onerror = function() {
    showNotification('文件读取失败', 'error');
  };
  
  reader.readAsText(file);
}

// 显示通知
function showNotification(message, type = 'success') {
  const notification = document.getElementById('notification');
  notification.textContent = message;
  notification.className = `notification ${type}`;
  notification.classList.add('show');
  
  setTimeout(() => {
    notification.classList.remove('show');
  }, 3000);
}

// 初始化应用
document.addEventListener('DOMContentLoaded', initApp);

6. index.html (主HTML文件)

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>项目管理信息系统 - 桌面版</title>
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
    <div class="sci-fi-bg"></div>
    
    <!-- 通知 -->
    <div class="notification" id="notification"></div>
    
    <!-- 项目编辑模态框 -->
    <div id="projectModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title" id="projectModalTitle">编辑项目</h3>
                <button class="close-modal">&times;</button>
            </div>
            <form id="projectForm">
                <input type="hidden" id="projectId">
                <div class="modal-body">
                    <div class="form-group">
                        <label for="projectName">项目名称</label>
                        <input type="text" id="projectName" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="projectDepartment">部门</label>
                        <input type="text" id="projectDepartment" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="projectManager">负责人</label>
                        <input type="text" id="projectManager" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="projectStartDate">开始日期</label>
                        <input type="date" id="projectStartDate" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="projectDeadline">截止日期</label>
                        <input type="date" id="projectDeadline" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="projectStatus">状态</label>
                        <select id="projectStatus" class="form-control" required>
                            <option value="planning">规划中</option>
                            <option value="progress">进行中</option>
                            <option value="review">评审中</option>
                            <option value="completed">已完成</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="projectDescription">项目描述</label>
                        <textarea id="projectDescription" class="form-control" rows="3"></textarea>
                    </div>
                    <div class="form-actions">
                        <button type="button" class="btn btn-secondary" id="cancelProject">取消</button>
                        <button type="submit" class="btn">保存项目</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
    
    <!-- 任务编辑模态框 -->
    <div id="taskModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title" id="taskModalTitle">编辑任务</h3>
                <button class="close-modal">&times;</button>
            </div>
            <form id="taskForm">
                <input type="hidden" id="taskId">
                <div class="modal-body">
                    <div class="form-group">
                        <label for="taskName">任务名称</label>
                        <input type="text" id="taskName" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="taskProject">关联项目</label>
                        <select id="taskProject" class="form-control" required>
                            <option value="">请选择项目</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="taskStartDate">开始日期</label>
                        <input type="date" id="taskStartDate" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="taskDeadline">截止日期</label>
                        <input type="date" id="taskDeadline" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="taskPriority">优先级</label>
                        <select id="taskPriority" class="form-control" required>
                            <option value="high">高</option>
                            <option value="medium">中</option>
                            <option value="low">低</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="taskStatus">状态</label>
                        <select id="taskStatus" class="form-control" required>
                            <option value="pending">待处理</option>
                            <option value="progress">进行中</option>
                            <option value="review">评审中</option>
                            <option value="completed">已完成</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="taskDescription">任务描述</label>
                        <textarea id="taskDescription" class="form-control" rows="3"></textarea>
                    </div>
                    <div class="form-actions">
                        <button type="button" class="btn btn-secondary" id="cancelTask">取消</button>
                        <button type="submit" class="btn">保存任务</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
    
    <!-- 团队成员编辑模态框 -->
    <div id="teamMemberModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title" id="teamMemberModalTitle">编辑团队成员</h3>
                <button class="close-modal">&times;</button>
            </div>
            <form id="teamMemberForm">
                <input type="hidden" id="teamMemberId">
                <div class="modal-body">
                    <div class="form-group">
                        <label for="teamMemberName">成员姓名</label>
                        <input type="text" id="teamMemberName" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="teamMemberRole">角色</label>
                        <input type="text" id="teamMemberRole" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="teamMemberSkills">技能</label>
                        <input type="text" id="teamMemberSkills" class="form-control" placeholder="用逗号分隔技能">
                    </div>
                    <div class="form-actions">
                        <button type="button" class="btn btn-secondary" id="cancelTeamMember">取消</button>
                        <button type="submit" class="btn">保存成员</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
    
    <!-- 日历事件编辑模态框 -->
    <div id="calendarEventModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title" id="calendarEventModalTitle">添加/编辑事件</h3>
                <button class="close-modal">&times;</button>
            </div>
            <form id="calendarEventForm">
                <input type="hidden" id="calendarEventId">
                <input type="hidden" id="calendarEventDate">
                <div class="modal-body">
                    <div class="form-group">
                        <label for="calendarEventTitle">事件标题</label>
                        <input type="text" id="calendarEventTitle" class="form-control" required>
                    </div>
                    <div class="form-group">
                        <label for="calendarEventDescription">事件描述</label>
                        <textarea id="calendarEventDescription" class="form-control" rows="3"></textarea>
                    </div>
                    <div class="form-actions">
                        <button type="button" class="btn btn-secondary" id="cancelCalendarEvent">取消</button>
                        <button type="submit" class="btn">保存事件</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
    
    <!-- 数据管理模态框 -->
    <div id="dataManagementModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title">数据管理</h3>
                <button class="close-modal">&times;</button>
            </div>
            <div class="modal-body">
                <div class="data-management-section">
                    <h4>数据导出</h4>
                    <p>将当前系统中的项目、任务、团队成员和日历事件数据导出为JSON文件。</p>
                    <div class="data-actions">
                        <button class="btn" id="exportDataBtn">
                            <i class="fas fa-download"></i> 导出数据
                        </button>
                        <button class="btn btn-secondary" id="copyDataBtn">
                            <i class="fas fa-copy"></i> 复制到剪贴板
                        </button>
                    </div>
                    
                    <div class="data-info">
                        <h4>数据导入</h4>
                        <p>从JSON文件导入数据到系统中。注意:导入数据将覆盖当前所有数据,请谨慎操作!</p>
                        
                        <div class="file-upload-area" id="fileUploadArea">
                            <i class="fas fa-cloud-upload-alt"></i>
                            <p>点击选择文件或拖拽文件到此处</p>
                            <p class="file-hint">支持JSON格式文件</p>
                            <input type="file" id="fileInput" accept=".json" style="display: none">
                        </div>
                        
                        <div class="data-actions">
                            <button class="btn btn-secondary" id="importDataBtn" disabled>
                                <i class="fas fa-upload"></i> 导入数据
                            </button>
                            <button class="btn btn-secondary" id="resetDataBtn">
                                <i class="fas fa-trash"></i> 重置为示例数据
                            </button>
                        </div>
                    </div>
                    
                    <div class="data-info">
                        <h4>当前数据统计</h4>
                        <div class="data-stats">
                            <div class="data-stat">
                                <div class="value" id="projectsCount">0</div>
                                <div class="label">项目</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="tasksCount">0</div>
                                <div class="label">任务</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="teamMembersCount">0</div>
                                <div class="label">团队成员</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="eventsCount">0</div>
                                <div class="label">日历事件</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <!-- 文件上传模态框 -->
    <div id="fileUploadModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title">上传文件</h3>
                <button class="close-modal">&times;</button>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="uploadFileProject">关联项目</label>
                    <select id="uploadFileProject" class="form-control" required>
                        <option value="">请选择项目</option>
                    </select>
                </div>
                <div class="form-group">
                    <label for="uploadFileDescription">文件描述</label>
                    <input type="text" id="uploadFileDescription" class="form-control" placeholder="请输入文件描述">
                </div>
                <div class="file-upload-area" id="uploadFileArea">
                    <i class="fas fa-cloud-upload-alt"></i>
                    <p>点击选择文件或拖拽文件到此处</p>
                    <p class="file-hint">支持所有格式文件</p>
                    <input type="file" id="uploadFileInput" style="display: none">
                </div>
                <div class="form-actions">
                    <button type="button" class="btn btn-secondary" id="cancelFileUpload">取消</button>
                    <button type="button" class="btn" id="confirmFileUpload" disabled>上传文件</button>
                </div>
            </div>
        </div>
    </div>
    
    <!-- 主应用容器 -->
    <div class="container" id="appContainer">
        <!-- 侧边栏 -->
        <div class="sidebar">
            <div class="logo">
                <h1><i class="fas fa-rocket"></i> 项目管理系统</h1>
            </div>
            <ul class="nav-links">
                <li><a href="#" class="nav-link active" data-page="dashboard"><i class="fas fa-home"></i> <span>仪表盘</span></a></li>
                <li><a href="#" class="nav-link" data-page="projects"><i class="fas fa-project-diagram"></i> <span>项目</span></a></li>
                <li><a href="#" class="nav-link" data-page="tasks"><i class="fas fa-tasks"></i> <span>任务</span></a></li>
                <li><a href="#" class="nav-link" data-page="team"><i class="fas fa-users"></i> <span>团队</span></a></li>
                <li><a href="#" class="nav-link" data-page="calendar"><i class="fas fa-calendar-alt"></i> <span>日历</span></a></li>
                <li><a href="#" class="nav-link" data-page="reports"><i class="fas fa-chart-bar"></i> <span>报告</span></a></li>
                <li><a href="#" class="nav-link" data-page="progress"><i class="fas fa-chart-line"></i> <span>进度管理</span></a></li>
                <li><a href="#" class="nav-link" data-page="dataManagement"><i class="fas fa-database"></i> <span>数据管理</span></a></li>
            </ul>
        </div>
        
        <!-- 主内容区 -->
        <div class="main-content">
            <!-- 仪表盘页面 -->
            <div id="dashboard" class="page-content active">
                <div class="header">
                    <div class="page-title">
                        <h2>项目仪表盘</h2>
                        <p>欢迎回来,查看您的项目进展和团队动态</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="globalSearch" placeholder="搜索项目、任务或成员...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar">PM</div>
                    </div>
                </div>
                
                <!-- 统计卡片 -->
                <div class="stats-cards">
                    <div class="stat-card">
                        <h3>进行中项目</h3>
                        <div class="value" id="activeProjectsCount">0</div>
                    </div>
                    <div class="stat-card">
                        <h3>已完成任务</h3>
                        <div class="value" id="completedTasksCount">0</div>
                    </div>
                    <div class="stat-card">
                        <h3>逾期项目</h3>
                        <div class="value" id="overdueProjectsCount">0</div>
                    </div>
                    <div class="stat-card">
                        <h3>团队效率</h3>
                        <div class="value" id="teamEfficiency">0%</div>
                    </div>
                </div>
                
                <!-- 项目列表 -->
                <div class="projects-section">
                    <div class="section-header">
                        <h3>我的项目</h3>
                        <div>
                            <button class="btn" id="addProjectBtn"><i class="fas fa-plus"></i> 新建项目</button>
                        </div>
                    </div>
                    <div class="projects-grid" id="dashboardProjects">
                        <!-- 项目卡片将动态生成 -->
                    </div>
                </div>
                
                <!-- 任务和团队 -->
                <div class="tasks-section">
                    <div class="task-list">
                        <div class="section-header">
                            <h3>近期任务</h3>
                            <div>
                                <button class="btn" id="addTaskBtn"><i class="fas fa-plus"></i> 新建任务</button>
                            </div>
                        </div>
                        <div class="task-items" id="dashboardTasks">
                            <!-- 任务将动态生成 -->
                        </div>
                    </div>
                    
                    <div class="team-section">
                        <div class="section-header">
                            <h3>团队成员</h3>
                            <div>
                                <button class="btn" id="addTeamMemberBtn"><i class="fas fa-user-plus"></i> 添加成员</button>
                            </div>
                        </div>
                        <div class="team-members" id="dashboardTeam">
                            <!-- 团队成员将动态生成 -->
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 项目页面 -->
            <div id="projects" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>项目管理</h2>
                        <p>查看和管理所有项目</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="projectSearch" placeholder="搜索项目...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar2">PM</div>
                    </div>
                </div>
                
                <div class="projects-section">
                    <div class="section-header">
                        <h3>所有项目</h3>
                        <div>
                            <button class="btn" id="addProjectBtn2"><i class="fas fa-plus"></i> 新建项目</button>
                            <button class="btn btn-secondary" id="importProjectBtn"><i class="fas fa-file-import"></i> 导入项目</button>
                        </div>
                    </div>
                    <div class="projects-grid" id="allProjects">
                        <!-- 项目卡片将动态生成 -->
                    </div>
                </div>
            </div>
            
            <!-- 任务页面 -->
            <div id="tasks" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>任务管理</h2>
                        <p>查看和管理所有任务</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="taskSearch" placeholder="搜索任务...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar3">PM</div>
                    </div>
                </div>
                
                <!-- 任务过滤器 -->
                <div class="task-filter">
                    <button class="filter-btn active" data-filter="all">所有任务</button>
                    <button class="filter-btn" data-filter="pending">待处理</button>
                    <button class="filter-btn" data-filter="progress">进行中</button>
                    <button class="filter-btn" data-filter="completed">已完成</button>
                    <select class="form-control" id="taskProjectFilter" style="width: auto;">
                        <option value="all">所有项目</option>
                    </select>
                </div>
                
                <div class="task-board" id="taskBoard">
                    <!-- 任务列将动态生成 -->
                </div>
            </div>
            
            <!-- 团队页面 -->
            <div id="team" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>团队管理</h2>
                        <p>管理团队成员和权限</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="teamSearch" placeholder="搜索成员...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar4">PM</div>
                    </div>
                </div>
                
                <div class="section-header">
                    <h3>团队成员</h3>
                    <button class="btn" id="addTeamMemberBtn2"><i class="fas fa-user-plus"></i> 添加成员</button>
                </div>
                
                <div class="team-members" id="teamMembers">
                    <!-- 团队成员将动态生成 -->
                </div>
            </div>
            
            <!-- 日历页面 -->
            <div id="calendar" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>项目日历</h2>
                        <p>查看项目时间表和重要事件</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="calendarSearch" placeholder="搜索事件...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar5">PM</div>
                    </div>
                </div>
                
                <div class="calendar-container">
                    <div class="calendar-header">
                        <h3 id="calendarMonth">2025年 十一月</h3>
                        <div class="calendar-nav">
                            <button class="btn btn-secondary" id="prevMonth"><i class="fas fa-chevron-left"></i></button>
                            <button class="btn btn-secondary" id="nextMonth"><i class="fas fa-chevron-right"></i></button>
                        </div>
                    </div>
                    
                    <div class="calendar-grid" id="calendarGrid">
                        <!-- 日历将动态生成 -->
                    </div>
                </div>
            </div>
            
            <!-- 报告页面 -->
            <div id="reports" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>项目报告</h2>
                        <p>查看项目统计和分析</p>
                    </div>
                    <div class="user-avatar floating" id="userAvatar6">PM</div>
                </div>
                
                <div class="section-header">
                    <h3>文件管理</h3>
                    <div>
                        <button class="btn" id="uploadFileBtn"><i class="fas fa-upload"></i> 上传文件</button>
                        <select id="fileProjectFilter" class="form-control" style="display: inline-block; width: auto; margin-left: 15px;">
                            <option value="all">所有项目</option>
                        </select>
                    </div>
                </div>
                
                <div class="file-list" id="fileList">
                    <!-- 文件列表将动态生成 -->
                </div>
            </div>
            
            <!-- 项目进度管理页面 -->
            <div id="progress" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>项目进度管理</h2>
                        <p>横道图展示项目任务进度</p>
                    </div>
                    <div class="user-info">
                        <div class="search-box">
                            <i class="fas fa-search"></i>
                            <input type="text" id="progressSearch" placeholder="搜索项目...">
                        </div>
                        <div class="user-avatar floating" id="userAvatar8">PM</div>
                    </div>
                </div>
                
                <div class="section-header">
                    <h3>项目选择</h3>
                </div>
                
                <select id="projectSelect" class="form-control">
                    <option value="">请选择项目</option>
                </select>
                
                <div class="gantt-container" id="ganttContainer">
                    <div class="gantt-header">
                        <h3>项目横道图</h3>
                    </div>
                    <div class="gantt-scroll-container">
                        <div class="gantt-timeline" id="ganttTimeline">
                            <!-- 时间线将动态生成 -->
                        </div>
                        <div class="gantt-chart" id="ganttChart">
                            <!-- 横道图将动态生成 -->
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 数据管理页面 -->
            <div id="dataManagement" class="page-content">
                <div class="header">
                    <div class="page-title">
                        <h2>数据管理</h2>
                        <p>导入、导出和备份系统数据</p>
                    </div>
                    <div class="user-avatar floating" id="userAvatar7">PM</div>
                </div>
                
                <div class="data-management-section">
                    <div class="local-storage-info">
                        <h4>本地数据存储</h4>
                        <p><strong>数据存储路径:</strong></p>
                        <p class="path" id="storagePath2">文档/ProjectManagementSystem/</p>
                        <p><strong>文件存储路径:</strong></p>
                        <p class="path" id="filesPath2">文档/ProjectManagementSystem/uploaded_files/</p>
                    </div>
                    
                    <h3>数据导出</h3>
                    <p>将当前系统中的项目、任务、团队成员和日历事件数据导出为JSON文件。</p>
                    <div class="data-actions">
                        <button class="btn" id="exportDataBtn2">
                            <i class="fas fa-download"></i> 导出数据到本地文件
                        </button>
                        <button class="btn btn-secondary" id="copyDataBtn2">
                            <i class="fas fa-copy"></i> 复制到剪贴板
                        </button>
                    </div>
                    
                    <div class="data-info">
                        <h3>数据导入</h3>
                        <p>从JSON文件导入数据到系统中。注意:导入数据将覆盖当前所有数据,请谨慎操作!</p>
                        
                        <div class="file-upload-area" id="fileUploadArea2">
                            <i class="fas fa-cloud-upload-alt"></i>
                            <p>点击选择文件或拖拽文件到此处</p>
                            <p class="file-hint">支持JSON格式文件</p>
                            <input type="file" id="fileInput2" accept=".json" style="display: none">
                        </div>
                        
                        <div class="data-actions">
                            <button class="btn btn-secondary" id="importDataBtn2" disabled>
                                <i class="fas fa-upload"></i> 从本地文件导入
                            </button>
                            <button class="btn btn-secondary" id="resetDataBtn2">
                                <i class="fas fa-trash"></i> 重置为示例数据
                            </button>
                        </div>
                    </div>
                    
                    <div class="data-info">
                        <h3>当前数据统计</h3>
                        <div class="data-stats">
                            <div class="data-stat">
                                <div class="value" id="projectsCount2">0</div>
                                <div class="label">项目</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="tasksCount2">0</div>
                                <div class="label">任务</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="teamMembersCount2">0</div>
                                <div class="label">团队成员</div>
                            </div>
                            <div class="data-stat">
                                <div class="value" id="eventsCount2">0</div>
                                <div class="label">日历事件</div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="renderer.js"></script>
</body>
</html>

使用说明

安装和运行

1.将上述文件保存到项目文件夹中

2.在项目文件夹中打开命令行,运行以下命令安装依赖:

text 复制代码
npm install

3.运行应用:

text 复制代码
npm start

构建分发版本

text 复制代码
npm run build

这将在 dist 文件夹中生成应用程序的安装包

功能特点

  • 本地数据存储:所有数据存储在用户文档目录下的 ProjectManagementSystem 文件夹中

  • 文件上传:上传的文件保存在 ProjectManagementSystem/uploaded_files 目录中

  • 文件下载:从本地文件系统下载文件到用户选择的位置

  • 数据导入导出:支持完整的数据导入导出功能

  • 保持原有UI和功能:完全保留了原有HTML应用的所有功能和界面设计

存储路径

  • 数据文件:文档/ProjectManagementSystem/data.json
  • 上传文件:文档/ProjectManagementSystem/uploaded_files/
相关推荐
陌上明苏4 小时前
使用ssrs矩阵
1024程序员节
墨利昂4 小时前
深度学习常用优化器解析
人工智能·深度学习·机器学习·1024程序员节
asdfsdgss4 小时前
PyTorch 生成式 AI(1):模型训练过拟合处理,神经网络正则化方法详解
1024程序员节
PyHaVolask4 小时前
Metasploit网络嗅探实战:从数据包捕获到协议分析的完整指南
数据包分析·metasploit·1024程序员节·流量分析·网络嗅探
XH-hui5 小时前
【打靶日记】THL 之 Facultad
linux·网络安全·1024程序员节·thehackerlabs
.NET修仙日记5 小时前
Visual Studio 演进之路:从集成套件到AI驱动的开发平台
ide·编辑器·ai编程·visual studio·1024程序员节
lixinnnn.5 小时前
算法总结篇(枚举-分治)
算法·1024程序员节
小小小糖果人6 小时前
Linux云计算基础篇(28)-Samba文件服务
1024程序员节
技术杠精6 小时前
Docker Swarm 的负载均衡和平滑切换原理
docker·容器·负载均衡·1024程序员节