From 7cc10b2d25ae319fc36aabfd5183c204ed8c4883 Mon Sep 17 00:00:00 2001 From: Rumia <3063485007@qq.com> Date: Sun, 12 Oct 2025 18:58:02 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/README.md | 744 ++++++++++++---------------------- src/frontend/electron-main.js | 257 +++++++++++- src/frontend/index.html | 1 - src/frontend/package.json | 15 +- src/frontend/preload.js | 83 ++++ 5 files changed, 608 insertions(+), 492 deletions(-) diff --git a/doc/README.md b/doc/README.md index 6ec3bd9..56f64d4 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,13 +2,13 @@ ## 目录(所使用的代码规范地址在末尾) -### 📱 前端部分 -- [项目概述](#前端项目概述) | [功能特性](#前端功能特性) | [技术栈](#前端技术栈) | [项目结构](#前端项目结构) | [快速开始](#前端快速开始) -- [功能验证流程](#前端功能验证流程) | [后端对接指南](#前端后端对接指南) | [前端核心模块说明](#前端核心模块说明) | [代码规范](#前端代码规范) +### 🖥️ 前端部分 +- [前端项目概述](#前端项目概述) | [前端功能特性](#前端功能特性) | [前端技术栈](#前端技术栈) | [前端项目结构](#前端项目结构) | [前端快速开始](#前端快速开始) +- [前端使用指南](#前端使用指南) | [前端核心模块说明](#前端核心模块说明) | [前端代码规范](#前端代码规范) ### 🔧 后端部分 -- [项目概述](#后端项目概述) | [功能特性](#后端功能特性) | [技术栈](#后端技术栈) | [项目结构](#后端项目结构) | [环境配置](#后端环境配置) -- [快速开始](#后端快速开始) | [API 接口文档](#api-接口文档) | [核心模块说明](#后端核心模块说明) | [数据存储](#数据存储) | [安全特性](#安全特性) +- [后端项目概述](#后端项目概述) | [后端功能特性](#后端功能特性) | [后端技术栈](#后端技术栈) | [后端项目结构](#后端项目结构) | [后端快速开始](#后端快速开始) +- [后端使用指南](#后端使用指南) | [后端核心模块说明](#后端核心模块说明) | [后端代码规范](#后端代码规范) ### 📋 部署与问题 - [完整部署指南](#完整部署指南) @@ -19,8 +19,7 @@ # 前端部分 ## 前端项目概述 -本前端基于 Electron,提供从注册→密码设置→年级选择→输入题数→答题页→评分页的完整界面流程。**已内置测试功能**,无需后端即可验证所有基础功能。 - +本软件是一个基于 Electron 的桌面数学学习应用,采用前后端分离的模块化设计,最终打包为单一可执行程序。提供从用户注册→密码设置→年级选择→数学答题→成绩统计的完整学习流程。 ## 前端功能特性 - ✅ 用户注册与邮箱验证码 @@ -30,28 +29,32 @@ - ✅ 年级选择(小学/初中/高中) - ✅ 数学题目生成与答题 - ✅ 成绩统计与显示 -- ✅ 桌面应用打包 +- ✅ 单一可执行程序(无需外部服务) ## 前端技术栈 -- **框架**: Electron +- **桌面框架**: Electron - **前端**: HTML5 + CSS3 + JavaScript (ES6+) +- **后端**: Node.js + Express(集成到主进程) +- **通信方式**: IPC(进程间通信) +- **数据存储**: JSON文件 - **样式**: 原生CSS(符合Google CSS规范) - **代码规范**: Google JavaScript/CSS/HTML规范 ## 前端项目结构 ``` -src/frontend/ -├─ api/ -│ ├─ httpApi.js # HTTP接口层 -│ └─ mockApi.js # 模拟数据接口 -├─ dist/ # 打包输出目录 -├─ electron-main.js # Electron主进程 -├─ preload.js # 预加载脚本 -├─ index.html # 主页面 -├─ renderer.js # 前端逻辑 -├─ styles.css # 样式文件 -├─ package.json # 项目配置 -└─ package-lock.json # 依赖锁定 +src/ +├─ frontend/ # 前端模块(GUI界面) +│ ├─ electron-main.js # 主进程(集成后端逻辑) +│ ├─ preload.js # IPC通信接口 +│ ├─ renderer.js # 渲染进程(前端逻辑) +│ ├─ index.html # 主页面 +│ ├─ styles.css # 样式文件 +│ └─ package.json # 前端配置 +└─ backend/ # 后端模块(业务逻辑+数据) + ├─ utils/ # 工具类 + ├─ data/ # 数据存储 + ├─ email-config.js # 邮箱配置文件 + └─ package.json # 后端依赖配置 ``` ## 前端快速开始 @@ -62,153 +65,101 @@ src/frontend/ ### 2. 安装依赖 ```bash -cd src/frontend +# 安装后端依赖(必需) +cd src/backend +npm install + +# 安装前端依赖 +cd ../frontend npm install ``` ### 3. 开发模式运行 ```bash -npm run dev +npm start ``` +**⚠️ 重要**: 必须先安装后端依赖,否则应用启动会报错 `Cannot find module 'nodemailer'`。 + ### 4. 打包发布 ```bash npm run build ``` -产物位于 `dist/` 目录,默认生成 NSIS 安装包。 - -## 前端功能验证流程 +产物位于 `dist/` 目录,包含: +- `数学学习软件-7.0.0-Setup.exe` - 安装包 +- `win-unpacked/` - 解压后的可执行程序目录 -### 测试模式 -当前为**测试模式**(`TEST_MODE = true`),可以: -- 模拟邮箱验证码发送(界面直接显示验证码) -- 模拟用户注册和密码设置 -- 自动生成小初高数学题目 -- 完整的答题和评分流程 +## 前端使用指南 -### 1. 注册验证 +### 1. 用户注册 - 输入用户名(必填,需唯一) -- 输入邮箱(如 `test@example.com`) -- 点击"获取验证码":界面会显示验证码(如 `123456`) -- 输入显示的验证码,点击"注册" +- 输入邮箱(支持QQ邮箱和163邮箱) +- 点击"获取验证码":系统会发送验证码到邮箱 +- 输入收到的验证码,点击"注册" -### 2. 密码设置验证 +### 2. 密码设置 - 设置密码(6-10位,含大小写字母和数字,如 `Test123`) - 确认两次输入一致 - 点击"确认设置" - ### 3. 用户信息管理 - 注册完成后,右上角显示"头像+用户名+修改按钮" - 点击头像可选择本地图片更换 - 点击"修改用户名"可更改用户名(需唯一) - 点击"修改密码"可更改密码 -### 4. 答题功能验证 +### 4. 数学学习 - 选择年级(小学/初中/高中) - 输入题目数量(10-30) - 点击"生成试卷" - 逐题作答,查看最终分数 -## 前端后端对接指南 - -### 1. 切换到真实后端 -编辑 `api/httpApi.js`: -```javascript -const BASE_URL = 'http://127.0.0.1:8080'; // 你的后端地址 -const TEST_MODE = false; // 关闭测试模式 -``` - -### 2. 后端接口要求 -你的后端需要实现以下接口(返回 JSON 格式): - -#### 发送验证码 -- **接口**:`POST /api/send-code` -- **请求体**:`{ "email": "user@example.com", "username": "用户名" }` -- **返回**:`{ "ok": true, "message": "验证码已发送" }` - -#### 用户注册 -- **接口**:`POST /api/register` -- **请求体**:`{ "email": "user@example.com", "username": "用户名", "code": "123456" }` -- **返回**:`{ "ok": true, "message": "注册成功" }` - -#### 设置密码 -- **接口**:`POST /api/set-password` -- **请求体**:`{ "email": "user@example.com", "password": "密码" }` -- **返回**:`{ "ok": true, "message": "密码设置成功" }` - -#### 修改密码 -- **接口**:`POST /api/change-password` -- **请求体**:`{ "email": "user@example.com", "oldPassword": "原密码", "newPassword": "新密码" }` -- **返回**:`{ "ok": true, "message": "密码修改成功" }` - -#### 修改用户名 -- **接口**:`POST /api/change-username` -- **请求体**:`{ "email": "user@example.com", "username": "新用户名" }` -- **返回**:`{ "ok": true, "message": "用户名修改成功" }` - -#### 获取题目 -- **接口**:`GET /api/questions?grade=小学&count=10` -- **返回**:`{ "ok": true, "data": [题目数组], "message": "题目生成成功" }` - -### 3. 题目数据格式 -```javascript -{ - "ok": true, - "data": [ - { - "id": "小学-1", - "stem": "计算:2 + 3", - "options": [ - { "key": "A", "text": "5" }, - { "key": "B", "text": "6" }, - { "key": "C", "text": "4" }, - { "key": "D", "text": "7" } - ], - "answer": "A" - } - ] -} -``` - - ## 前端核心模块说明 ### 1. 主进程模块 (electron-main.js) #### 功能概述 -Electron主进程模块负责创建和管理应用程序窗口,处理系统级事件,管理应用程序生命周期。 +Electron主进程模块负责创建和管理应用程序窗口,同时集成了所有后端业务逻辑,实现单一可执行程序。 #### 核心功能 - **窗口管理**: 创建和管理应用窗口 -- **菜单配置**: 应用程序菜单设置 -- **安全配置**: 安全策略和权限控制 +- **后端逻辑集成**: 用户管理、邮箱验证、题目生成 +- **IPC通信处理**: 处理渲染进程的API请求 +- **数据管理**: JSON文件数据存储 - **生命周期管理**: 应用程序启动和关闭 -#### 窗口配置 +#### 集成架构 ```javascript -const mainWindow = new BrowserWindow({ - width: 1200, - height: 800, - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(__dirname, 'preload.js') +// 动态路径处理 +const getBackendPath = (relativePath) => { + if (app.isPackaged) { + return path.join(process.resourcesPath, 'backend', relativePath); + } else { + return path.join(__dirname, '..', 'backend', relativePath); } +}; + +// IPC处理器 +ipcMain.handle('api:send-code', async (event, { email, username }) => { + // 发送验证码逻辑 +}); + +ipcMain.handle('api:login', async (event, { account, password }) => { + // 用户登录逻辑 }); ``` ### 2. 渲染进程模块 (renderer.js) #### 功能概述 -渲染进程模块是前端逻辑的核心,负责处理用户界面交互、数据管理、API调用等功能。 +渲染进程模块是前端逻辑的核心,负责处理用户界面交互、数据管理、与主进程通信等功能。 #### 核心功能 - **界面管理**: 页面切换和状态管理 - **用户交互**: 表单处理、事件监听 - **数据管理**: 本地数据存储和同步 -- **API调用**: 与后端服务通信 +- **IPC通信**: 与主进程通信,调用后端API #### 主要功能模块 ```javascript @@ -257,115 +208,33 @@ class UserManager { ### 3. 预加载脚本 (preload.js) #### 功能概述 -预加载脚本负责在渲染进程中安全地暴露Node.js API,确保应用程序的安全性。 +预加载脚本负责在渲染进程中安全地暴露API接口,实现与主进程的IPC通信。 -#### 预加载安全特性 -- **API暴露**: 安全地暴露必要的Node.js API +#### 核心功能 +- **API暴露**: 安全地暴露所有业务API +- **IPC通信**: 处理渲染进程与主进程的通信 - **权限控制**: 限制渲染进程的权限 - **数据验证**: 输入数据验证和清理 #### 暴露的API ```javascript -contextBridge.exposeInMainWorld('electronAPI', { - // 文件操作 - selectFile: () => ipcRenderer.invoke('select-file'), - - // 窗口操作 - minimizeWindow: () => ipcRenderer.invoke('minimize-window'), - closeWindow: () => ipcRenderer.invoke('close-window') -}); -``` - -### 4. API接口层 (api/) - -#### HTTP接口模块 (httpApi.js) -负责与后端服务通信,处理HTTP请求和响应。 - -#### 核心功能 -- **请求封装**: 统一的HTTP请求处理 -- **错误处理**: 网络错误和业务错误处理 -- **数据转换**: 请求和响应数据格式转换 -- **缓存管理**: 请求缓存和优化 - -#### 接口方法 -```javascript -class HttpAPI { - // 发送验证码 - async sendCode(email, username) +contextBridge.exposeInMainWorld('API', { + // 用户认证 + sendRegisterCode: (email, username) => ipcRenderer.invoke('api:send-code', { email, username }), + verifyCode: (email, username, code) => ipcRenderer.invoke('api:verify-code', { email, username, code }), + register: (email, username, password) => ipcRenderer.invoke('api:register', { email, username, password }), + login: (account, password) => ipcRenderer.invoke('api:login', { account, password }), - // 用户注册 - async register(userData) + // 用户管理 + changePassword: (email, oldPassword, newPassword) => ipcRenderer.invoke('api:change-password', { email, oldPassword, newPassword }), + changeUsername: (email, username) => ipcRenderer.invoke('api:change-username', { email, username }), + deleteAccount: (email, password) => ipcRenderer.invoke('api:delete-account', { email, password }), - // 设置密码 - async setPassword(email, password) - - // 获取题目 - async getQuestions(grade, count) - - // 用户信息管理 - async changeUsername(email, username) - async changePassword(email, oldPassword, newPassword) -} -``` - -#### 模拟接口模块 (mockApi.js) -提供测试模式下的模拟数据,支持离线开发和测试。 - -#### 模拟功能 -- **验证码模拟**: 界面显示验证码 -- **用户数据模拟**: 本地用户数据管理 -- **题目生成模拟**: 本地题目生成 -- **成绩计算模拟**: 本地成绩计算 - -### 5. 样式系统 (styles.css) - -#### 设计系统 -- **颜色系统**: 统一的颜色变量和主题 -- **字体系统**: 字体大小、行高、字重规范 -- **间距系统**: 统一的间距和布局规范 -- **组件样式**: 可复用的组件样式 - -#### CSS变量系统 -```css -:root { - --bg: #0e1116; - --border: #202734; - --danger: #ef4444; - --muted: #9aa4b2; - --panel: #151a21; - --primary: #3b82f6; - --primary-2: #2563eb; - --success: #22c55e; - --text: #e8edf3; -} + // 题目管理 + getQuestions: (grade, count) => ipcRenderer.invoke('api:get-questions', { grade, count }) +}); ``` -#### 响应式设计 -- **移动端适配**: 响应式布局设计 -- **窗口适配**: 不同窗口尺寸适配 -- **主题支持**: 深色主题设计 - -### 6. 用户界面组件 - -#### 页面组件 -- **登录页面**: 用户认证界面 -- **注册页面**: 用户注册界面 -- **设置密码页面**: 密码设置界面 -- **年级选择页面**: 年级选择界面 -- **答题页面**: 题目答题界面 -- **成绩页面**: 成绩显示界面 - -#### 交互组件 -- **表单组件**: 输入框、按钮、选择器 -- **模态框组件**: 确认对话框、提示框 -- **导航组件**: 页面导航和状态指示 -- **反馈组件**: 成功提示、错误提示 - -#### 用户体验 -- **加载状态**: 加载动画和状态提示 -- **错误处理**: 友好的错误提示 -- **操作反馈**: 操作成功和失败反馈 -- **数据验证**: 实时表单验证 ## 前端代码规范 - 所有JavaScript文件符合Google JavaScript规范 @@ -402,196 +271,213 @@ class HttpAPI { ## 后端项目结构 ``` src/backend/ - ├─ data/ - │ └─ users.json # 用户数据文件 - ├─ utils/ - +├─ data/ +│ └─ users.json # 用户数据文件 +├─ utils/ │ ├─ user-manager.js # 用户管理模块 │ ├─ multi-email-service.js # 多邮箱服务 │ └─ question-generator.js # 题目生成器 ├─ email-config.js # 邮箱配置 -├─ server.js # 主服务器文件 -├─ package.json # 项目配置 -└─ package-lock.json # 依赖锁定 +└─ package.json # 项目配置 ``` -## 后端环境配置 - -### 1. 环境变量 -在 `src/backend` 目录下创建 `.env` 文件: -```env -PORT=8080 -NODE_ENV=development -SMTP_QQ_USER=your_qq@example.com -SMTP_QQ_PASS=your_smtp_password -SMTP_163_USER=your_163@example.com -SMTP_163_PASS=your_smtp_password -MAIL_FROM_NAME=数学学习软件 -DATA_PATH=./data/users.json -``` - - -### 2. 邮箱服务配置 -支持多个邮箱服务商: -- QQ邮箱 -- 163邮箱 -- 其他SMTP服务(还没有配置,暂时只有这两个邮箱) - ## 后端快速开始 ### 1. 安装依赖 ```bash - cd src/backend npm install ``` - ### 2. 启动服务 ```bash npm start ``` - ### 3. 验证服务 服务启动后会在终端显示:`Server listening on http://localhost:8080` -## API 接口文档 +## 后端使用指南 -### 基础信息 -- **基础URL**: `http://localhost:8080` -- **数据格式**: JSON -- **请求方法**: GET/POST +### 1. API调用方式 +- 所有API通过IPC通信调用,无需HTTP请求 +- 前端通过 `ipcRenderer.invoke` 调用主进程中的后端逻辑 -### 1. 发送验证码 -- **URL**: `POST /api/send-code` -- **请求体**: -```json +### 2. 用户管理流程 +- 发送验证码 → 用户注册 → 设置密码 +- 登录验证 → 修改信息 → 删除账户 -{ - "email": "user@example.com", - "username": "用户名" -} -``` +### 3. 题目生成流程 +- 选择年级 → 生成题目 → 返回题目数据 +- 支持小学、初中、高中三个年级 +- 自动生成选择题和计算题 -- **响应**: -```json +## 后端核心模块说明 -{ - "ok": true, - "message": "验证码已发送" -} -``` +### 1. 用户管理模块 (user-manager.js) -### 2. 用户注册 -- **URL**: `POST /api/register` -- **请求体**: -```json +#### 功能概述 +用户管理模块是整个后端系统的核心,负责处理所有用户相关的操作,包括注册、登录、密码管理、用户信息修改等。 -{ - "email": "user@example.com", - "username": "用户名", - "code": "123456" -} -``` -- **响应**: -```json +#### 主要功能 +- **用户注册**: 邮箱验证、用户名唯一性检查 +- **用户登录**: 邮箱/用户名登录验证 +- **密码管理**: 密码设置、修改、验证 +- **用户信息**: 用户名修改、账户删除 +- **数据存储**: JSON文件数据持久化 -{ - "ok": true, - "message": "注册成功" -} -``` +#### 核心方法 +- `createUser(email, username)`: 创建新用户 +- `findUserByEmail(email)`: 根据邮箱查找用户 +- `findUserByUsername(username)`: 根据用户名查找用户 +- `updateUser(email, updates)`: 更新用户信息 +- `deleteUser(email)`: 删除用户账户 +- `verifyPassword(email, password)`: 验证密码 -### 3. 设置密码 -- **URL**: `POST /api/set-password` -- **请求体**: -```json +#### 用户管理安全特性 +- **邮箱唯一性**: 每个邮箱只能注册一个账户 +- **用户名唯一性**: 用户名必须唯一 +- **密码安全**: 密码验证和加密存储 +- **数据完整性**: 用户数据一致性检查 +#### 数据存储格式 +```json { "email": "user@example.com", - "password": "新密码" + "username": "用户名", + "registeredAt": "2024-01-01T00:00:00.000Z" } ``` -- **响应**: -```json +### 2. 邮箱服务模块 (multi-email-service.js) -{ - "ok": true, - "message": "密码已设置" -} -``` +#### 功能概述 +邮箱服务模块负责发送验证码邮件,支持多个邮箱服务商,提供统一的邮件发送接口。 -### 4. 修改密码 -- **URL**: `POST /api/change-password` -- **请求体**: -```json +#### 支持的服务商 +- **QQ邮箱**: 支持QQ邮箱SMTP服务 +- **163邮箱**: 支持163邮箱SMTP服务 +- **测试模式**: 开发环境下的模拟发送 -{ - "email": "user@example.com", - "oldPassword": "旧密码", - "newPassword": "新密码" -} +#### 核心功能 +- **验证码生成**: 6位数字验证码 +- **邮件发送**: 通过SMTP发送验证码 +- **模板渲染**: 使用HTML邮件模板 +- **错误处理**: 发送失败时的降级处理 + +#### 配置示例 +```javascript +// QQ邮箱配置 +const qqConfig = { + host: 'smtp.qq.com', + port: 587, + secure: false, + auth: { + user: 'your_qq@qq.com', + pass: 'your_smtp_password' + } +}; + +// 163邮箱配置 +const config163 = { + host: 'smtp.163.com', + port: 587, + secure: false, + auth: { + user: 'your_163@163.com', + pass: 'your_smtp_password' + } +}; ``` -- **响应**: -```json -{ - "ok": true, - "message": "密码修改成功" -} +#### 邮件模板 +```html +
您的验证码是:{{code}}
+验证码有效期为10分钟,请及时使用。
``` -### 5. 修改用户名 -- **URL**: `POST /api/change-username` -- **请求体**: -```json +### 3. 题目生成模块 (question-generator.js) -{ - "email": "user@example.com", - "username": "新用户名" -} -``` +#### 功能概述 +题目生成模块负责根据年级和数量生成数学题目,支持小学、初中、高中三个年级的题目生成。 -- **响应**: -```json +#### 生成逻辑(与个人项目逻辑类似) +- **年级适配**: 根据年级调整题目难度 +- **题型多样**: 选择题、计算题、应用题 +- **选项生成**: 智能生成干扰选项 +- **答案验证**: 确保答案正确性 -{ - "ok": true, - "message": "用户名修改成功" +#### 题目类型 +- **小学**: 基础四则运算、简单应用题 +- **初中**: 代数运算、几何计算、函数基础 +- **高中**: 复杂代数、三角函数、立体几何 + +#### 核心算法 +```javascript +// 题目生成算法 +generateQuestion(grade, type) { + const difficulty = this.getDifficultyByGrade(grade); + const operation = this.selectOperation(type); + const numbers = this.generateNumbers(difficulty); + const expression = this.buildExpression(numbers, operation); + const answer = this.calculateAnswer(expression); + const options = this.generateOptions(answer); + + return { + stem: expression, + options: options, + answer: answer + }; } ``` -### 6. 获取题目 -- **URL**: `GET /api/questions?grade=小学&count=10` -- **参数**: - - `grade`: 年级(小学/初中/高中) - - `count`: 题目数量(10-30) -- **响应**: +#### 题目质量控制 +- **难度梯度**: 根据年级调整题目难度 +- **选项合理性**: 干扰选项不能过于明显 +- **计算准确性**: 确保所有计算正确 +- **格式统一**: 题目格式标准化 + +#### 题目数据结构 ```json { - "ok": true, - "data": [ - { - "id": "小学-1", - "stem": "计算:2 + 3", - - "options": [ - { "key": "A", "text": "5" }, - { "key": "B", "text": "6" }, - { "key": "C", "text": "4" }, - { "key": "D", "text": "7" } - ], - "answer": "A" - } + "id": "小学-1", + "stem": "计算:2 + 3 = ?", + "options": [ + {"key": "A", "text": "4", "isCorrect": false}, + {"key": "B", "text": "5", "isCorrect": true}, + {"key": "C", "text": "6", "isCorrect": false}, + {"key": "D", "text": "7", "isCorrect": false} ], - "message": "题目生成成功" + "answer": "B" } ``` - -## 后端核心模块说明 +#### 智能特性 +- **自适应难度**: 根据用户表现调整难度 +- **题型平衡**: 确保各种题型均匀分布 +- **错误分析**: 分析常见错误类型 + +## 后端代码规范 + +### JavaScript代码规范 +- **命名规范**: 使用camelCase命名变量和函数 +- **函数长度**: 单个函数不超过40行 +- **注释规范**: 关键函数和复杂逻辑必须添加注释 +- **错误处理**: 使用try-catch处理异步操作 +- **代码风格**: 遵循Google JavaScript规范 + +### 模块化规范 +- **单一职责**: 每个模块只负责一个功能 +- **依赖注入**: 通过参数传递依赖关系 +- **接口设计**: 统一的API响应格式 +- **错误处理**: 统一的错误处理机制 + +### 数据安全规范 +- **输入验证**: 所有用户输入必须验证 +- **数据加密**: 敏感数据使用适当加密 +- **权限控制**: 实现用户权限验证 +- **日志记录**: 记录关键操作和错误 ### 1. 用户管理模块 (user-manager.js) @@ -788,98 +674,7 @@ generateHighSchoolQuestion() { - **答案验证**: 多重验证确保正确性 - **格式统一**: 标准化的题目格式 -### 4. 服务器主模块 (server.js) - -#### 功能概述 -服务器主模块是整个后端系统的入口,负责处理HTTP请求、路由分发、中间件配置等核心功能。 - -#### 核心功能 -- **HTTP服务器**: 基于Express框架的Web服务器 -- **路由管理**: RESTful API路由设计 -- **中间件配置**: 跨域、解析、错误处理等 -- **端口监听**: 可配置的端口监听 - -#### API路由设计 -```javascript -// 用户相关路由 -app.post('/api/send-code', sendCodeHandler); -app.post('/api/register', registerHandler); -app.post('/api/set-password', setPasswordHandler); -app.post('/api/change-password', changePasswordHandler); -app.post('/api/change-username', changeUsernameHandler); - -// 题目相关路由 -app.get('/api/questions', getQuestionsHandler); -``` - -#### 错误处理 -- **统一错误格式**: 标准化的错误响应 -- **日志记录**: 详细的错误日志 -- **异常捕获**: 全局异常处理机制 - -#### 安全配置 -- **CORS设置**: 跨域请求处理 -- **请求验证**: 输入数据验证 -- **错误信息**: 安全的错误信息返回 - -### 5. 邮箱配置模块 (email-config.js) - -#### 功能概述 -邮箱配置模块负责管理所有邮箱相关的配置,包括服务商配置、模板配置、发送参数等。 - -#### 配置管理 -- **环境变量**: 从.env文件读取配置 -- **服务商配置**: 多邮箱服务商支持 -- **模板管理**: 邮件模板配置 -- **参数验证**: 配置参数验证 - -#### 配置结构 -```javascript -const emailConfig = { - services: { - qq: { /* QQ邮箱配置 */ }, - netease: { /* 163邮箱配置 */ } - }, - templates: { - verification: { /* 验证码模板 */ } - }, - settings: { - timeout: 30000, - retryCount: 3 - } -} -``` -### 6. 数据管理 - -#### 数据存储 -- **文件存储**: JSON文件存储用户数据 -- **数据备份**: 自动备份机制 -- **数据恢复**: 数据恢复功能 -- **数据验证**: 数据完整性检查 - -#### 数据安全 -- **加密存储**: 敏感数据加密 -- **访问控制**: 数据访问权限控制 -- **备份策略**: 定期数据备份 -- **恢复机制**: 数据恢复流程 - -#### 性能优化 -- **缓存机制**: 数据缓存策略 -- **异步处理**: 异步数据操作 -- **内存管理**: 内存使用优化 -- **并发控制**: 并发请求处理 - -## 数据存储 -- **用户数据**: `src/backend/data/users.json` -- **数据格式**: JSON数组 -- **加密方式**: SHA256 - -## 安全特性 -- 密码SHA256加密存储 -- 邮箱验证码验证 -- 用户名唯一性检查 -- 输入数据验证 --- @@ -889,46 +684,40 @@ const emailConfig = { ### 开发环境部署 -#### 1. 后端部署 +#### 1. 安装依赖 ```bash -# 进入后端目录 +# 安装后端依赖(必需,否则应用启动会报错) cd src/backend +npm install -# 安装依赖 +# 安装前端依赖 +cd ../frontend npm install +``` + +**重要说明**: 后端依赖是必需的,因为前端通过IPC调用后端工具类(如`nodemailer`),如果后端`node_modules`不存在,应用会报错 `Cannot find module 'nodemailer'`。 -# 配置环境变量(创建.env文件) -# 启动服务 +#### 2. 开发模式运行 +```bash +# 启动应用(集成前后端) npm start ``` -#### 2. 前端部署 +### 生产环境部署 + +#### 1. 生成安装包 ```bash -# 进入前端目录 cd src/frontend - -# 安装依赖 -npm install - -# 开发模式运行 -npm run dev - -# 或打包发布 npm run build ``` +生成安装包,包含: +- `数学学习软件-7.0.0-Setup.exe` - 安装包 +- `win-unpacked/` - 解压后的可执行程序目录 -### 生产环境部署 - -#### 1. 后端部署 -- 配置生产环境变量 -- 设置邮箱服务商 -- 配置数据备份 -- 使用PM2等进程管理工具 - -#### 2. 前端部署 -- 打包为桌面应用 -- 生成安装包 -- 分发安装程序 +#### 2. 分发安装程序 +- 将安装包分发给用户 +- 用户双击安装即可使用 +- 无需额外配置或服务 --- @@ -992,29 +781,8 @@ npm install --- -## 项目特色 - -### 代码质量 -- ✅ 完全符合Google代码规范 -- ✅ 统一的代码风格 -- ✅ 完整的错误处理 -- ✅ 详细的注释说明 - -### 用户体验 -- ✅ 直观的界面设计 -- ✅ 流畅的操作体验 -- ✅ 完善的错误提示 -- ✅ 响应式布局 - -### 技术架构 -- ✅ 前后端分离 -- ✅ 模块化设计 -- ✅ 可扩展架构 -- ✅ 安全可靠 - ---- - **项目状态**: 生产就绪 ✅ **最后更新**: 2025年10月12日 +**架构**: 前后端分离 + 单一可执行程序 + 纯IPC通信 -**参考规范**: [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) | [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html) \ No newline at end of file +**参考规范**: [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) | [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html) diff --git a/src/frontend/electron-main.js b/src/frontend/electron-main.js index 0f9113f..6534a61 100644 --- a/src/frontend/electron-main.js +++ b/src/frontend/electron-main.js @@ -1,7 +1,255 @@ const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); +const express = require('express'); +const cors = require('cors'); +const bodyParser = require('body-parser'); +const fs = require('fs'); + +// 获取后端文件路径 +const getBackendPath = (relativePath) => { + if (app.isPackaged) { + // 打包后的路径 + return path.join(process.resourcesPath, 'backend', relativePath); + } else { + // 开发环境路径 + return path.join(__dirname, '..', 'backend', relativePath); + } +}; + +const UserManager = require(getBackendPath('utils/user-manager')); +const MultiEmailService = require(getBackendPath('utils/multi-email-service')); +const MathQuestionGenerator = require(getBackendPath('utils/question-generator')); let mainWindow; +let backendApp; +let userManager; +let emailService; + +// 初始化后端服务 +function initBackend() { + // 创建Express应用 + backendApp = express(); + + // 配置中间件 + backendApp.use(cors()); + backendApp.use(bodyParser.json()); + + // 实例化管理器 + userManager = new UserManager(); + emailService = new MultiEmailService(); + + // 存储验证码(内存存储) + const verificationCodes = new Map(); + + // 生成6位数字验证码 + function generateVerificationCode() { + return Math.floor(100000 + Math.random() * 900000).toString(); + } + + // 验证邮箱格式 + function validateEmail(email) { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + } + + // 注册IPC处理器 + ipcMain.handle('api:send-code', async (event, { email, username }) => { + try { + if (!email || !username) { + return { ok: false, message: '邮箱和用户名不能为空' }; + } + + if (!validateEmail(email)) { + return { ok: false, message: '邮箱格式不正确' }; + } + + if (!email.includes('@qq.com') && !email.includes('@163.com')) { + return { ok: false, message: '只支持QQ邮箱和163邮箱' }; + } + + if (userManager.findUserByUsername(username)) { + return { ok: false, message: '用户名已存在' }; + } + + if (userManager.findUserByEmail(email)) { + return { ok: false, message: '邮箱已被注册' }; + } + + const code = generateVerificationCode(); + verificationCodes.set(email, { + code, + username, + timestamp: Date.now(), + }); + + const emailResult = await emailService.sendVerificationCode(email, code, username); + + if (emailResult.success) { + return { ok: true, message: emailResult.message }; + } else { + if (emailResult.debug) { + return { ok: true, message: emailResult.message + ' ' + emailResult.debug }; + } else { + return { ok: false, message: emailResult.message }; + } + } + } catch (error) { + console.error('发送验证码错误:', error); + return { ok: false, message: '服务器内部错误' }; + } + }); + + ipcMain.handle('api:verify-code', async (event, { email, username, code }) => { + try { + if (!email || !username || !code) { + return { ok: false, message: '请填写完整信息' }; + } + + const storedData = verificationCodes.get(email); + + if (!storedData) { + return { ok: false, message: '请先获取验证码' }; + } + + if (Date.now() - storedData.timestamp > 10 * 60 * 1000) { + verificationCodes.delete(email); + return { ok: false, message: '验证码已过期,请重新获取' }; + } + + if (storedData.code !== code) { + return { ok: false, message: '验证码不正确' }; + } + + if (storedData.username !== username) { + return { ok: false, message: '用户名与验证时不一致' }; + } + + verificationCodes.delete(email); + return { ok: true, message: '验证成功,请设置密码' }; + } catch (error) { + console.error('验证码验证错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:register', async (event, { email, username, password }) => { + try { + if (!email || !username || !password) { + return { ok: false, message: '请填写完整信息' }; + } + + userManager.createUser(email, username); + userManager.setPassword(email, password); + + return { ok: true, message: '注册成功' }; + } catch (error) { + console.error('注册错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:login', async (event, { account, password }) => { + try { + if (!account || !password) { + return { ok: false, message: '请填写账号和密码' }; + } + + let user = userManager.findUserByEmail(account); + if (!user) { + user = userManager.findUserByUsername(account); + } + + if (!user || !user.password) { + return { ok: false, message: '用户不存在' }; + } + + if (!userManager.verifyPassword(user.email, password)) { + return { ok: false, message: '密码不正确' }; + } + + return { + ok: true, + message: '登录成功', + data: { + email: user.email, + username: user.username, + }, + }; + } catch (error) { + console.error('登录错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:change-password', async (event, { email, oldPassword, newPassword }) => { + try { + if (!email || !oldPassword || !newPassword) { + return { ok: false, message: '请填写完整信息' }; + } + + userManager.changePassword(email, oldPassword, newPassword); + return { ok: true, message: '密码修改成功' }; + } catch (error) { + console.error('修改密码错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:change-username', async (event, { email, username }) => { + try { + if (!email || !username) { + return { ok: false, message: '请填写完整信息' }; + } + + userManager.changeUsername(email, username); + return { ok: true, message: '用户名修改成功' }; + } catch (error) { + console.error('修改用户名错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:delete-account', async (event, { email, password }) => { + try { + if (!email || !password) { + return { ok: false, message: '请填写完整信息' }; + } + + if (!userManager.verifyPassword(email, password)) { + return { ok: false, message: '密码不正确' }; + } + + userManager.deleteUser(email); + return { ok: true, message: '账号删除成功' }; + } catch (error) { + console.error('删除账号错误:', error); + return { ok: false, message: error.message }; + } + }); + + ipcMain.handle('api:get-questions', async (event, { grade, count }) => { + try { + if (!grade || !count) { + return { ok: false, message: '请选择年级和题目数量' }; + } + + const countNum = parseInt(count); + if (isNaN(countNum) || countNum < 10 || countNum > 30) { + return { ok: false, message: '题目数量需在10-30之间' }; + } + + const generator = new MathQuestionGenerator(); + const questions = generator.generateQuestions(grade, countNum); + return { + ok: true, + data: questions, + message: '题目生成成功', + }; + } catch (error) { + console.error('生成题目失败:', error); + return { ok: false, message: '生成题目失败' }; + } + }); +} function createWindow() { mainWindow = new BrowserWindow({ @@ -25,7 +273,12 @@ function createWindow() { }); } -app.whenReady().then(createWindow); +app.whenReady().then(() => { + // 初始化后端服务 + initBackend(); + // 创建窗口 + createWindow(); +}); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { @@ -39,7 +292,7 @@ app.on('activate', () => { } }); -// 窗口关闭请求(用于“退出应用”) +// 窗口关闭请求(用于"退出应用") ipcMain.handle('app:close', () => { if (mainWindow) { mainWindow.close(); diff --git a/src/frontend/index.html b/src/frontend/index.html index 24d9af4..ede69bd 100644 --- a/src/frontend/index.html +++ b/src/frontend/index.html @@ -218,7 +218,6 @@ -