【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/
相关推荐
fangzhanpeng16820 小时前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心3 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u0103055279 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055279 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝11 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552711 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552712 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552714 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552714 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552715 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节