欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/

atomgit仓库地址: https://gitcode.com/feng8403000/cms


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一、引言

1.1 鸿蒙PC与Electron框架

随着开源鸿蒙PC生态的不断发展,越来越多的开发者开始关注如何在鸿蒙操作系统上构建桌面应用。Electron作为一种成熟的跨平台桌面应用开发框架,为开发者提供了使用Web技术栈构建原生桌面应用的能力。

鸿蒙PC平台特点

  • 基于OpenHarmony开源项目
  • 支持多设备协同
  • 提供丰富的系统API
  • 良好的性能表现

Electron框架优势

  • 使用HTML/CSS/JavaScript进行开发
  • 一次开发,多平台部署
  • 丰富的社区资源和插件生态
  • 良好的开发者体验

1.2 项目背景

本文将详细介绍如何在鸿蒙PC平台上使用Electron框架构建一个功能完整的智能文章管理系统。通过实际项目实践,展示Electron在鸿蒙PC上的开发流程、技术选型和最佳实践。

1.3 项目概述

智能文章管理系统是一个功能丰富的桌面应用,主要包含以下模块:

模块 功能描述 技术要点
仪表盘 数据统计与概览 实时数据展示、图表渲染
文章管理 文章列表与操作 CRUD操作、搜索过滤
文章编辑器 富文本编辑 Markdown支持、内容预览
分类管理 分类创建与管理 数据关联、层级结构
标签管理 标签系统 颜色标识、关联统计
数据分析 数据可视化 图表展示、趋势分析

二、开发环境搭建

2.1 鸿蒙PC开发环境

在开始开发之前,需要准备好鸿蒙PC的开发环境:

2.1.1 操作系统要求
  • 支持Windows 10/11 (64位)
  • 支持Ubuntu 20.04 LTS及以上版本
2.1.2 安装依赖
# 安装Node.js (建议v16+)
sudo apt-get update
sudo apt-get install nodejs npm

# 安装Electron依赖
npm install -g electron
2.1.3 验证环境
node --version
npm --version
electron --version

2.2 项目初始化

使用Electron官方脚手架初始化项目:

# 创建项目目录
mkdir article-manager && cd article-manager

# 初始化npm项目
npm init -y

# 安装Electron依赖
npm install electron --save-dev
npm install electron-builder --save-dev

2.3 项目结构

article-manager/
├── package.json          # 项目配置
├── main.js              # 主进程入口
├── index.html           # 渲染进程入口
├── style.css            # 全局样式
└── js/                  # JavaScript模块
    ├── config.js        # 数据配置与管理
    └── battle.js        # 应用控制器

三、主进程开发

3.1 主进程架构

Electron应用分为主进程和渲染进程。主进程负责管理应用生命周期、窗口管理和系统级操作。

// main.js - 主进程入口
const { app, BrowserWindow, Menu, ipcMain } = require('electron');
const path = require('path');

let mainWindow;

function createWindow() {
    // 创建主窗口
    mainWindow = new BrowserWindow({
        width: 1200,
        height: 800,
        minWidth: 800,
        minHeight: 600,
        title: '智能文章管理系统',
        icon: path.join(__dirname, 'icon.png'),
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
        },
    });

    // 加载HTML文件
    mainWindow.loadFile('index.html');

    // 窗口关闭事件
    mainWindow.on('closed', function () {
        mainWindow = null;
    });

    // 创建菜单
    createMenu();
}

function createMenu() {
    const menu = Menu.buildFromTemplate([
        {
            label: '文件',
            submenu: [
                {
                    label: '新建文章',
                    accelerator: 'Ctrl+N',
                    click: () => {
                        mainWindow.webContents.executeJavaScript('AppController.openEditor()');
                    },
                },
                { type: 'separator' },
                {
                    label: '退出',
                    accelerator: 'Ctrl+Q',
                    click: () => {
                        app.quit();
                    },
                },
            ],
        },
        // 更多菜单...
    ]);

    Menu.setApplicationMenu(menu);
}

// 应用就绪事件
app.on('ready', createWindow);

// 所有窗口关闭事件
app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') app.quit();
});

// 应用激活事件
app.on('activate', function () {
    if (mainWindow === null) createWindow();
});

3.2 IPC通信机制

主进程与渲染进程之间通过IPC(Inter-Process Communication)进行通信。

// 主进程 - 接收渲染进程消息
ipcMain.on('save-article', (event, article) => {
    console.log('Saving article:', article.title);
    // 可以在这里添加文件保存或数据库操作
    event.reply('article-saved', true);
});

ipcMain.on('delete-article', (event, articleId) => {
    console.log('Deleting article:', articleId);
    event.reply('article-deleted', true);
});

在渲染进程中发送消息:

// 渲染进程 - 发送消息到主进程
const { ipcRenderer } = require('electron');

function saveArticle(article) {
    ipcRenderer.send('save-article', article);
}

ipcRenderer.on('article-saved', (event, success) => {
    if (success) {
        console.log('Article saved successfully');
    }
});

3.3 窗口管理

主进程负责管理应用的所有窗口:

// 创建关于窗口
function createAboutWindow() {
    const aboutWindow = new BrowserWindow({
        width: 400,
        height: 280,
        title: '关于智能文章管理系统',
        icon: path.join(__dirname, 'icon.png'),
        resizable: false,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
        },
    });
    
    aboutWindow.loadFile('about.html');
    aboutWindow.setMenu(null);
}

四、渲染进程开发

4.1 界面布局设计

渲染进程负责应用的UI展示和用户交互。

<!-- index.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 href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <!-- 背景效果 -->
    <div class="bg-effects">
        <div class="ink-bg"></div>
        <div class="particles"></div>
    </div>

    <!-- 顶部导航栏 -->
    <header class="top-header">
        <div class="header-left">
            <div class="logo">
                <span class="material-icons logo-icon">article</span>
                <span class="app-title">智能文章管理系统</span>
            </div>
        </div>
        <div class="header-center">
            <div class="search-bar">
                <input type="text" id="search-input" placeholder="搜索文章...">
                <button id="search-btn" class="search-btn">
                    <span class="material-icons">search</span>
                </button>
            </div>
        </div>
        <div class="header-right">
            <div class="theme-switcher">
                <select id="theme-select">
                    <option value="tech">科技感</option>
                    <option value="classical">古典雅致</option>
                    <option value="modern">简约现代</option>
                    <option value="elegant">优雅墨色</option>
                    <option value="warm">温暖秋色</option>
                    <option value="night">夜间模式</option>
                </select>
            </div>
            <button class="header-btn" title="新建文章" id="add-article-btn">
                <span class="material-icons">add</span>
            </button>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="main-container">
        <!-- 左侧导航 -->
        <aside class="sidebar">
            <div class="nav-section">
                <h3 class="nav-title">导航</h3>
                <nav class="nav-menu">
                    <button class="nav-item active" data-view="dashboard" onclick="switchView('dashboard')">
                        <span class="material-icons">dashboard</span>
                        <span class="nav-text">仪表盘</span>
                    </button>
                    <button class="nav-item" data-view="articles" onclick="switchView('articles')">
                        <span class="material-icons">article</span>
                        <span class="nav-text">文章管理</span>
                    </button>
                    <button class="nav-item" data-view="categories" onclick="switchView('categories')">
                        <span class="material-icons">folder</span>
                        <span class="nav-text">分类管理</span>
                    </button>
                    <button class="nav-item" data-view="tags" onclick="switchView('tags')">
                        <span class="material-icons">label</span>
                        <span class="nav-text">标签管理</span>
                    </button>
                    <button class="nav-item" data-view="analytics" onclick="switchView('analytics')">
                        <span class="material-icons">bar_chart</span>
                        <span class="nav-text">数据分析</span>
                    </button>
                </nav>
            </div>
        </aside>

        <!-- 内容区域 -->
        <section class="content-area">
            <!-- 仪表盘视图 -->
            <div id="dashboardView" class="view active">
                <!-- 统计卡片 -->
                <div class="stats-grid">
                    <div class="stat-card">
                        <div class="stat-icon blue">
                            <span class="material-icons">article</span>
                        </div>
                        <div class="stat-info">
                            <span class="stat-value" id="stat-articles">0</span>
                            <span class="stat-label">总文章数</span>
                        </div>
                    </div>
                    <!-- 更多统计卡片... -->
                </div>

                <!-- 快速统计 -->
                <div class="quick-stats">
                    <!-- 统计内容 -->
                </div>

                <!-- 最近文章 -->
                <div class="recent-section">
                    <div class="section-header">
                        <h3>最近文章</h3>
                        <button class="view-all-btn" onclick="switchView('articles')">查看全部</button>
                    </div>
                    <div id="recent-list" class="recent-list">
                        <!-- 文章列表 -->
                    </div>
                </div>
            </div>

            <!-- 文章管理视图 -->
            <div id="articlesView" class="view">
                <!-- 文章列表 -->
                <div id="article-list" class="article-list">
                    <!-- 文章卡片 -->
                </div>
            </div>

            <!-- 编辑器视图 -->
            <div id="editorView" class="view">
                <!-- 文章编辑器 -->
                <form id="article-form" class="editor-form">
                    <!-- 表单内容 -->
                </form>
            </div>

            <!-- 分类管理视图 -->
            <div id="categoriesView" class="view">
                <!-- 分类列表 -->
                <div id="categories-list" class="categories-list">
                    <!-- 分类卡片 -->
                </div>
            </div>

            <!-- 标签管理视图 -->
            <div id="tagsView" class="view">
                <!-- 标签云 -->
                <div id="tags-cloud" class="tags-cloud">
                    <!-- 标签项 -->
                </div>
            </div>

            <!-- 数据分析视图 -->
            <div id="analyticsView" class="view">
                <!-- 分析图表 -->
                <div class="analytics-grid">
                    <!-- 图表卡片 -->
                </div>
            </div>
        </section>
    </main>

    <!-- 模态框 -->
    <div id="articleDetailModal" class="modal-overlay" style="display: none;">
        <!-- 文章详情模态框 -->
    </div>

    <!-- JavaScript模块 -->
    <script src="js/config.js"></script>
    <script src="js/battle.js"></script>
</body>
</html>

4.2 样式系统设计

使用CSS变量实现多主题切换:

/* 科技感主题(默认) */
[data-theme="tech"] {
    --primary: #00d9ff;
    --primary-light: #66e5ff;
    --accent: #7b2cbf;
    --bg-paper: #0a0a0f;
    --bg-panel: #121218;
    --bg-card: #1e1e2a;
    --border: #2a2a3a;
    --text-primary: #e0e0e0;
    --text-secondary: #a0a0a0;
    --shadow: 0 0 20px rgba(0, 217, 255, 0.15);
}

/* 古典雅致主题 */
[data-theme="classical"] {
    --primary: #2c3e50;
    --accent: #c0392b;
    --bg-paper: #f5f0e6;
    --bg-panel: #fffef5;
    --bg-card: #ffffff;
    --border: #d4c4a8;
    --text-primary: #2c3e50;
    --text-secondary: #5d6d7e;
}

/* 主题切换逻辑 */
function changeTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('article-theme', theme);
}

4.3 应用控制器

应用控制器负责管理应用状态和用户交互:

// battle.js - 应用控制器
const AppController = {
    currentView: 'dashboard',
    currentArticleId: null,
    selectedCategory: null,
    selectedTag: null,
    searchKeyword: '',

    init() {
        this.setupEventListeners();
        this.loadTheme();
        this.renderDashboard();
        this.initParticles();
    },

    setupEventListeners() {
        // 设置所有事件监听器
        document.querySelectorAll('.nav-item').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const viewId = e.currentTarget.dataset.view;
                this.switchView(viewId);
            });
        });

        document.getElementById('theme-select').addEventListener('change', (e) => {
            this.changeTheme(e.target.value);
        });

        // 更多事件监听...
    },

    switchView(viewId) {
        this.currentView = viewId;
        
        // 更新导航状态
        document.querySelectorAll('.nav-item').forEach(item => {
            item.classList.remove('active');
        });
        document.querySelector(`[data-view="${viewId}"]`).classList.add('active');

        // 切换视图显示
        document.querySelectorAll('.view').forEach(view => {
            view.classList.remove('active');
        });
        document.getElementById(`${viewId}View`).classList.add('active');

        // 根据视图类型渲染内容
        switch(viewId) {
            case 'dashboard':
                this.renderDashboard();
                break;
            case 'articles':
                this.renderArticles();
                break;
            case 'editor':
                this.openEditor();
                break;
            // 其他视图...
        }
    },

    renderDashboard() {
        const stats = ArticleManager.getStats();
        const recentArticles = ArticleManager.getRecentArticles(5);
        
        // 更新统计数据
        document.getElementById('stat-articles').textContent = stats.totalArticles;
        document.getElementById('stat-published').textContent = stats.published;
        document.getElementById('stat-reads').textContent = this.formatNumber(stats.totalReads);
        document.getElementById('stat-likes').textContent = stats.totalLikes;

        // 渲染最近文章列表
        const recentList = document.getElementById('recent-list');
        recentList.innerHTML = recentArticles.map(article => {
            const category = ArticleManager.getCategoryById(article.categoryId);
            return `
                <div class="recent-item" onclick="AppController.openArticleDetail('${article.id}')">
                    <div class="recent-icon">
                        <span class="material-icons">article</span>
                    </div>
                    <div class="recent-info">
                        <div class="recent-title">${article.title}</div>
                        <div class="recent-meta">${category?.name || '未分类'} - ${this.formatDate(article.createdAt)}</div>
                    </div>
                </div>
            `;
        }).join('');
    },

    // 更多方法...
};

// DOM加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
    AppController.init();
});

五、数据管理模块

5.1 数据结构设计

设计合理的数据结构是应用的基础:

// config.js - 数据管理模块
const ArticleManager = {
    // 分类数据
    categories: [
        { id: 'cat-1', name: '技术分享', icon: 'code', description: '技术文章、开发经验分享' },
        { id: 'cat-2', name: '生活随笔', icon: 'coffee', description: '生活感悟、日常记录' },
        { id: 'cat-3', name: '读书心得', icon: 'book', description: '阅读感悟、书评' },
        { id: 'cat-4', name: '旅行游记', icon: 'plane', description: '旅行故事、风景分享' },
        { id: 'cat-5', name: '美食探索', icon: 'restaurant', description: '美食推荐、烹饪分享' },
        { id: 'cat-6', name: '摄影艺术', icon: 'camera', description: '摄影作品、技巧分享' },
    ],

    // 标签数据
    tags: [
        { id: 'tag-1', name: 'JavaScript', color: '#f7df1e' },
        { id: 'tag-2', name: '前端开发', color: '#61dafb' },
        { id: 'tag-3', name: '生活', color: '#4caf50' },
        // 更多标签...
    ],

    // 文章数据
    articles: [
        {
            id: 'art-1',
            title: '深入理解JavaScript闭包原理与实战应用',
            excerpt: '闭包是JavaScript中最重要的概念之一...',
            content: '## 什么是闭包\n\n闭包(Closure)是指有权访问另一个函数作用域中变量的函数...',
            categoryId: 'cat-1',
            tagIds: ['tag-1', 'tag-2'],
            status: 'published',
            createdAt: '2024-01-15T10:30:00Z',
            updatedAt: '2024-01-15T14:20:00Z',
            readCount: 1256,
            likeCount: 89,
        },
        // 更多文章...
    ],

    // 数据操作方法
    getCategoryById(id) {
        return this.categories.find(cat => cat.id === id);
    },

    getArticleById(id) {
        return this.articles.find(art => art.id === id);
    },

    getArticlesByCategory(categoryId) {
        if (!categoryId) return this.articles;
        return this.articles.filter(art => art.categoryId === categoryId);
    },

    addArticle(article) {
        const newArticle = {
            id: `art-${Date.now()}`,
            ...article,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            readCount: 0,
            likeCount: 0
        };
        this.articles.unshift(newArticle);
        return newArticle;
    },

    updateArticle(id, updates) {
        const index = this.articles.findIndex(art => art.id === id);
        if (index !== -1) {
            this.articles[index] = {
                ...this.articles[index],
                ...updates,
                updatedAt: new Date().toISOString()
            };
            return this.articles[index];
        }
        return null;
    },

    deleteArticle(id) {
        const index = this.articles.findIndex(art => art.id === id);
        if (index !== -1) {
            return this.articles.splice(index, 1)[0];
        }
        return null;
    },

    getStats() {
        const published = this.articles.filter(a => a.status === 'published').length;
        const drafts = this.articles.filter(a => a.status === 'draft').length;
        const totalReads = this.articles.reduce((sum, a) => sum + a.readCount, 0);
        const totalLikes = this.articles.reduce((sum, a) => sum + a.likeCount, 0);
        
        return {
            totalArticles: this.articles.length,
            published,
            drafts,
            totalReads,
            totalLikes,
            categories: this.categories.length,
            tags: this.tags.length
        };
    },

    getRecentArticles(count = 5) {
        return [...this.articles]
            .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
            .slice(0, count);
    }
};

// 导出模块
if (typeof module !== 'undefined' && module.exports) {
    module.exports = ArticleManager;
}

5.2 数据持久化方案

虽然当前使用内存数据,但在实际应用中需要考虑数据持久化:

// 数据持久化方案
const StorageManager = {
    saveData(key, data) {
        try {
            localStorage.setItem(key, JSON.stringify(data));
            return true;
        } catch (error) {
            console.error('保存数据失败:', error);
            return false;
        }
    },

    loadData(key) {
        try {
            const data = localStorage.getItem(key);
            return data ? JSON.parse(data) : null;
        } catch (error) {
            console.error('加载数据失败:', error);
            return null;
        }
    },

    saveArticles() {
        return this.saveData('articles', ArticleManager.articles);
    },

    loadArticles() {
        const saved = this.loadData('articles');
        if (saved) {
            ArticleManager.articles = saved;
        }
    },

    // 自动保存
    setupAutoSave() {
        setInterval(() => {
            this.saveArticles();
        }, 30000); // 每30秒自动保存
    }
};

六、核心功能实现

6.1 文章管理功能

文章管理是系统的核心功能,包括创建、编辑、删除和查看文章。

// 打开文章编辑器
openEditor(articleId = null) {
    this.currentArticleId = articleId;
    
    if (articleId) {
        const article = ArticleManager.getArticleById(articleId);
        if (article) {
            document.getElementById('article-title-input').value = article.title;
            document.getElementById('article-excerpt-input').value = article.excerpt;
            document.getElementById('article-content-input').value = article.content;
            document.getElementById('article-category-select').value = article.categoryId;
            document.getElementById('article-status-select').value = article.status;
            
            // 设置标签选择
            const tagCheckboxes = document.querySelectorAll('.tag-checkbox');
            tagCheckboxes.forEach(checkbox => {
                checkbox.checked = article.tagIds.includes(checkbox.value);
            });
        }
    } else {
        document.getElementById('article-form').reset();
    }
    
    this.switchView('editor');
},

// 保存文章
saveArticle() {
    const title = document.getElementById('article-title-input').value.trim();
    const excerpt = document.getElementById('article-excerpt-input').value.trim();
    const content = document.getElementById('article-content-input').value.trim();
    const categoryId = document.getElementById('article-category-select').value;
    const status = document.getElementById('article-status-select').value;
    
    const selectedTags = Array.from(document.querySelectorAll('.tag-checkbox:checked'))
        .map(checkbox => checkbox.value);

    if (!title || !content) {
        alert('请填写标题和内容');
        return;
    }

    if (this.currentArticleId) {
        ArticleManager.updateArticle(this.currentArticleId, {
            title,
            excerpt,
            content,
            categoryId,
            status,
            tagIds: selectedTags
        });
    } else {
        ArticleManager.addArticle({
            title,
            excerpt,
            content,
            categoryId,
            status,
            tagIds: selectedTags
        });
    }

    this.closeEditor();
},

// 删除文章确认
deleteArticleConfirm(articleId) {
    if (confirm('确定要删除这篇文章吗?')) {
        ArticleManager.deleteArticle(articleId);
        this.renderArticles();
    }
},

// 打开文章详情
openArticleDetail(articleId) {
    const article = ArticleManager.getArticleById(articleId);
    if (!article) return;

    const category = ArticleManager.getCategoryById(article.categoryId);

    document.getElementById('modal-article-title').textContent = article.title;
    document.getElementById('modal-article-meta').innerHTML = `
        <span>${category?.name || '未分类'}</span>
        <span>${this.formatDate(article.createdAt)}</span>
        <span>阅读 ${article.readCount}</span>
        <span>点赞 ${article.likeCount}</span>
    `;
    document.getElementById('modal-article-content').innerHTML = this.renderMarkdown(article.content);

    document.getElementById('articleDetailModal').style.display = 'flex';

    // 更新阅读计数
    ArticleManager.updateArticle(articleId, {
        readCount: article.readCount + 1
    });
}

6.2 分类管理功能

分类管理允许用户创建和管理文章分类:

// 打开添加分类模态框
openAddCategoryModal() {
    document.getElementById('category-form').reset();
    document.getElementById('addCategoryModal').style.display = 'flex';
},

// 保存分类
saveCategory() {
    const name = document.getElementById('category-name-input').value.trim();
    const description = document.getElementById('category-desc-input').value.trim();
    const icon = document.getElementById('category-icon-select').value;

    if (!name) {
        alert('请输入分类名称');
        return;
    }

    ArticleManager.addCategory({ name, description, icon });
    document.getElementById('addCategoryModal').style.display = 'none';
    this.renderCategories();
},

// 渲染分类列表
renderCategories() {
    const categories = ArticleManager.categories;
    
    const categoriesList = document.getElementById('categories-list');
    categoriesList.innerHTML = categories.map(category => {
        const count = ArticleManager.getArticlesByCategory(category.id).length;
        return `
            <div class="category-card" onclick="AppController.selectCategory('${category.id}')">
                <div class="category-icon">
                    <span class="material-icons">${category.icon}</span>
                </div>
                <div class="category-info">
                    <div class="category-name">${category.name}</div>
                    <div class="category-desc">${category.description}</div>
                </div>
                <span class="category-count">${count} 篇</span>
            </div>
        `;
    }).join('');
}

6.3 标签管理功能

标签管理提供灵活的标签系统:

// 打开添加标签模态框
openAddTagModal() {
    document.getElementById('tag-form').reset();
    document.getElementById('addTagModal').style.display = 'flex';
},

// 保存标签
saveTag() {
    const name = document.getElementById('tag-name-input').value.trim();
    const color = document.getElementById('tag-color-input').value;

    if (!name) {
        alert('请输入标签名称');
        return;
    }

    ArticleManager.addTag({ name, color });
    document.getElementById('addTagModal').style.display = 'none';
    this.renderTags();
},

// 渲染标签云
renderTags() {
    const tags = ArticleManager.tags;
    
    const tagsCloud = document.getElementById('tags-cloud');
    tagsCloud.innerHTML = tags.map(tag => {
        const count = ArticleManager.getArticlesByTag(tag.id).length;
        return `
            <div class="tag-item" onclick="AppController.selectTag('${tag.id}')">
                <span class="tag-color" style="background: ${tag.color}"></span>
                <span class="tag-name">${tag.name}</span>
                <span class="tag-count">${count}</span>
            </div>
        `;
    }).join('');
}

6.4 数据分析功能

数据分析模块展示文章统计信息:

// 渲染数据分析
renderAnalytics() {
    const stats = ArticleManager.getStats();
    const articles = ArticleManager.articles;

    // 分类统计
    const categoryStats = ArticleManager.categories.map(cat => ({
        name: cat.name,
        count: ArticleManager.getArticlesByCategory(cat.id).length
    }));

    // 月度数据
    const monthlyData = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    articles.forEach(article => {
        const month = new Date(article.createdAt).getMonth();
        monthlyData[month]++;
    });

    // 更新统计数据
    document.getElementById('analytics-total').textContent = stats.totalArticles;
    document.getElementById('analytics-published').textContent = stats.published;
    document.getElementById('analytics-drafts').textContent = stats.drafts;
    document.getElementById('analytics-views').textContent = this.formatNumber(stats.totalReads);

    // 绘制图表
    this.drawCategoryChart(categoryStats);
    this.drawMonthlyChart(monthlyData);
},

// 绘制分类图表
drawCategoryChart(data) {
    const container = document.getElementById('category-chart');
    const maxCount = Math.max(...data.map(d => d.count), 1);
    
    container.innerHTML = `
        <div style="display: flex; flex-direction: column; gap: 8px; width: 100%;">
            ${data.map(item => `
                <div style="display: flex; align-items: center; gap: 8px;">
                    <span style="width: 80px; font-size: 12px;">${item.name}</span>
                    <div style="flex: 1; height: 20px; background: var(--bg-paper); border-radius: 4px; overflow: hidden;">
                        <div style="height: 100%; background: var(--accent); width: ${(item.count / maxCount) * 100}%; transition: width 0.5s;"></div>
                    </div>
                    <span style="width: 30px; text-align: right; font-size: 12px;">${item.count}</span>
                </div>
            `).join('')}
        </div>
    `;
},

// 绘制月度图表
drawMonthlyChart(data) {
    const container = document.getElementById('monthly-chart');
    const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
    const maxCount = Math.max(...data, 1);
    
    container.innerHTML = `
        <div style="display: flex; align-items: flex-end; justify-content: space-between; height: 100%; padding: 10px;">
            ${data.map((count, index) => `
                <div style="display: flex; flex-direction: column; align-items: center; gap: 4px; flex: 1;">
                    <div style="width: 20px; background: var(--primary); border-radius: 4px 4px 0 0; height: ${(count / maxCount) * 150}px; min-height: 4px;"></div>
                    <span style="font-size: 10px;">${months[index]}</span>
                </div>
            `).join('')}
        </div>
    `;
}

七、主题系统实现

7.1 多主题设计

系统支持6种主题风格:

/* 科技感主题(默认) */
[data-theme="tech"] {
    --primary: #00d9ff;
    --accent: #7b2cbf;
    --bg-paper: #0a0a0f;
    --bg-panel: #121218;
    --bg-card: #1e1e2a;
    --border: #2a2a3a;
    --text-primary: #e0e0e0;
    --text-secondary: #a0a0a0;
}

/* 古典雅致主题 */
[data-theme="classical"] {
    --primary: #2c3e50;
    --accent: #c0392b;
    --bg-paper: #f5f0e6;
    --bg-panel: #fffef5;
    --bg-card: #ffffff;
    --border: #d4c4a8;
    --text-primary: #2c3e50;
    --text-secondary: #5d6d7e;
}

/* 简约现代主题 */
[data-theme="modern"] {
    --primary: #1a1a2e;
    --accent: #4361ee;
    --bg-paper: #f8f9fa;
    --bg-panel: #ffffff;
    --bg-card: #ffffff;
    --border: #e9ecef;
    --text-primary: #1a1a2e;
    --text-secondary: #495057;
}

/* 优雅墨色主题 */
[data-theme="elegant"] {
    --primary: #1a1a1a;
    --accent: #8b5a2b;
    --bg-paper: #faf8f5;
    --bg-panel: #ffffff;
    --bg-card: #ffffff;
    --border: #e8e4e0;
    --text-primary: #1a1a1a;
    --text-secondary: #4a4a4a;
}

/* 温暖秋色主题 */
[data-theme="warm"] {
    --primary: #5d4037;
    --accent: #d84315;
    --bg-paper: #fff8e1;
    --bg-panel: #fffde7;
    --bg-card: #ffffff;
    --border: #ffe0b2;
    --text-primary: #5d4037;
    --text-secondary: #795548;
}

/* 夜间模式主题 */
[data-theme="night"] {
    --primary: #e0e0e0;
    --accent: #ffb74d;
    --bg-paper: #121212;
    --bg-panel: #1e1e1e;
    --bg-card: #2d2d2d;
    --border: #424242;
    --text-primary: #e0e0e0;
    --text-secondary: #bdbdbd;
}

7.2 主题切换逻辑

// 加载保存的主题
loadTheme() {
    const savedTheme = localStorage.getItem('article-theme') || 'tech';
    document.documentElement.setAttribute('data-theme', savedTheme);
    document.getElementById('theme-select').value = savedTheme;
},

// 切换主题
changeTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('article-theme', theme);
}

八、性能优化策略

8.1 渲染优化

使用虚拟列表优化长列表渲染:

// 虚拟列表优化
function renderArticlesWithVirtualScroll() {
    const container = document.getElementById('article-list');
    const articles = ArticleManager.articles;
    
    // 只渲染可见区域的文章
    const visibleCount = 10;
    const startIndex = Math.max(0, scrollPosition - 2);
    const endIndex = Math.min(articles.length, startIndex + visibleCount);
    
    container.innerHTML = articles.slice(startIndex, endIndex).map(article => {
        // 渲染文章卡片
    }).join('');
}

8.2 事件节流与防抖

// 节流函数
function throttle(fn, delay) {
    let lastTime = 0;
    
    return function(...args) {
        const now = Date.now();
        if (now - lastTime >= delay) {
            lastTime = now;
            fn.apply(this, args);
        }
    };
}

// 防抖函数
function debounce(fn, delay) {
    let timer = null;
    
    return function(...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, delay);
    };
}

// 应用节流和防抖
const throttledScroll = throttle(function() {
    updateVisibleArticles();
}, 100);

const debouncedSearch = debounce(function(keyword) {
    performSearch(keyword);
}, 300);

8.3 资源优化

// 图片懒加载
function setupImageLazyLoad() {
    const images = document.querySelectorAll('img[data-src]');
    
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                observer.unobserve(img);
            }
        });
    });
    
    images.forEach(img => observer.observe(img));
}

九、构建与部署

9.1 项目构建

配置package.json中的构建脚本:

{
    "scripts": {
        "start": "electron .",
        "build": "electron-builder",
        "build:win": "electron-builder --win",
        "build:linux": "electron-builder --linux",
        "build:mac": "electron-builder --mac"
    },
    "build": {
        "appId": "com.example.article-manager",
        "productName": "智能文章管理系统",
        "directories": {
            "output": "dist"
        },
        "files": [
            "**/*",
            "!node_modules/**/*"
        ],
        "win": {
            "target": "nsis",
            "icon": "icon.ico"
        },
        "linux": {
            "target": "deb",
            "icon": "icon.png"
        }
    }
}

9.2 构建命令

# 开发模式
npm start

# 构建Windows版本
npm run build:win

# 构建Linux版本
npm run build:linux

# 构建所有平台
npm run build

9.3 鸿蒙PC平台部署

在鸿蒙PC平台上部署Electron应用需要注意:

  1. 权限配置:确保应用具有必要的系统权限
  2. 依赖检查:确保所有native依赖在鸿蒙PC上可用
  3. 兼容性测试:在实际鸿蒙PC设备上测试应用
  4. 性能优化:针对鸿蒙PC平台进行性能调优

十、总结与展望

10.1 项目总结

通过本文的实践,我们成功构建了一个基于Electron框架的智能文章管理系统,主要完成了以下工作:

  1. 环境搭建:配置了鸿蒙PC上的Electron开发环境
  2. 架构设计:设计了主进程与渲染进程的架构
  3. 功能实现:实现了文章管理、分类管理、标签管理和数据分析等核心功能
  4. 主题系统:实现了6种主题风格的切换
  5. 性能优化:应用了节流、防抖、虚拟列表等优化策略

10.2 技术亮点

  • 模块化架构:代码组织清晰,便于维护和扩展
  • 响应式设计:支持不同屏幕尺寸
  • 多主题支持:满足不同用户的视觉偏好
  • 数据持久化:支持本地存储

10.3 未来展望

未来可以进一步扩展的功能:

  • 云端同步:支持文章数据的云端备份和同步
  • 团队协作:支持多人协作编辑
  • 富文本编辑器:增强编辑功能
  • 移动端适配:开发移动端版本
  • 插件系统:支持第三方插件扩展

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐