chore: initial import

This commit is contained in:
2026-04-19 14:05:40 +08:00
commit 89e9eae36e
81 changed files with 37363 additions and 0 deletions
+487
View File
@@ -0,0 +1,487 @@
# 科技成果转化管理系统 — PPT 提纲(草案)
> 用途:领导汇报型讲解 PPT,包含系统开发逻辑、开发历程、开发心得,并强调“小切口解决问题”的实践。包含安全专题与关键代码摘录。
---
## 0. 封面
- 项目名称:科技成果转化管理系统
- 汇报人 / 团队 / 日期
## 汇报时长与页数建议(30 分钟)
- 建议页数:18–22 页(含 2 张图:系统架构图 + 核心流程图)
- 时间分配:导入 2–3 分钟|主体 22–24 分钟|总结 3–4 分钟
## 30 分钟版(20 页)结构分配
- 业务与管理:8 页
- 技术与实现:12 页(含安全专题与代码亮点)
### 20 页目录建议(可直接用作 PPT 页标题)
1. 封面
2. 背景与目标(业务痛点 + 目标)
3. 业务价值与管理收益(闭环、合规、可追溯)
4. 系统开发逻辑(业务链路)
5. 核心流程图(从申报到归档)
6. 业务模块总览(功能地图)
7. 权限与角色体系(管理视角)
8. 统计分析与决策支持(管理视角)
9. 系统总体架构(技术总览)
10. 系统架构图(Nginx/Server/DB/文件)
11. 数据模型与权限策略(RBAC + 状态约束)
12. 上传与文件安全(白名单 + Magic Number
13. 审计与日志体系(可追溯)
14. 认证与单点登录(JWT + token_version
15. 接口防护与限流(分级限流 + 验证码)
16. 运维保障(磁盘监控 + 告警)
17. 开发历程(里程碑)
18. 小切口解决问题(工程细节)
19. 安全专题(集中总结)
20. 价值总结与下一步
### 页内时间建议(总计 30 分钟)
- 12 页:每页 1 分钟
- 3–8 页(业务/管理 6 页):每页 1–1.5 分钟
- 9–16 页(技术 8 页):每页 1.5–2 分钟
- 17–20 页(收束 4 页):每页 1 分钟
---
# 20 页逐页内容(标题 + 关键点 + 口播稿 + 配图建议)
## 1. 封面
关键点
- 项目名称、汇报人、单位、日期
口播稿
- “今天汇报科技成果转化管理系统,重点讲业务闭环、管理价值与技术亮点。”
配图建议
- 项目 Logo 或简洁科技感背景图
## 2. 背景与目标
关键点
- 痛点:成果类型多、流程长、数据分散、统计难
- 目标:全生命周期管理,统一流程与口径
口播稿
- “核心目标是把成果从申报到归档形成标准化闭环,并保证数据口径一致。”
配图建议
- 痛点对比图或“问题→目标”对照图
## 3. 业务价值与管理收益
关键点
- 闭环流程:可控、可追溯
- 合规与审计:有据可查
- 统计可视化:辅助决策
口播稿
- “系统不仅解决业务效率,还能把过程做成可追溯的管理证据链。”
配图建议
- 价值三角图(效率/合规/决策)
## 4. 系统开发逻辑(业务链路)
关键点
- 申报→审核→统计→归档→运维
- 以业务路径驱动技术设计
口播稿
- “先确定业务主链路,再围绕关键节点补齐权限、安全与运维。”
配图建议
- 业务链路流程条
## 5. 核心流程图(从申报到归档)
关键点
- 查重拦截、审核分流、通过入库
- 统计分析与导出归档
口播稿
- “每个关键节点都定义了自动校验和权限控制,确保流程闭环。”
配图建议
- 使用下方 Mermaid 流程图渲染
## 6. 业务模块总览
关键点
- 账号权限、成果管理、审核、统计、导出、公告
- 模块之间的依赖关系
口播稿
- “业务模块围绕成果流转展开,管理侧在审核与统计两端发力。”
配图建议
- 功能模块矩阵或系统功能地图
## 7. 权限与角色体系(管理视角)
关键点
- RBAC 角色分级:普通/中级/高级/管理员/维护员/超管
- 关键场景:提交人与完成人权限分离、审核回避
口播稿
- “权限模型保证数据边界清晰,避免同人审核、越权查看。”
配图建议
- 角色金字塔或权限矩阵简图
## 8. 统计分析与决策支持
关键点
- 多维度统计(部门/年度/类型)
- 趋势图、雷达图、堆叠图
口播稿
- “统计不是展示数量,而是提供结构与趋势,支撑管理决策。”
配图建议
- 统计图示例(柱状/雷达/趋势)
## 9. 系统总体架构(技术总览)
关键点
- 前后端分离,RESTful API
- Nginx 统一入口,后端服务化
口播稿
- “技术架构选择以可扩展与可运维为优先。”
配图建议
- 架构分层示意图
## 10. 系统架构图(细化)
关键点
- SPA → Nginx → API → DB/文件
- 日志与审计并行
口播稿
- “数据流与文件流分开管理,方便安全控制与归档。”
配图建议
- 使用下方 Mermaid 架构图渲染
## 11. 数据模型与权限策略
关键点
- JSONB 处理完成人列表
- 状态驱动权限(pending/rejected/approved
口播稿
- “用 JSONB 保证结构灵活,用状态机控制访问边界。”
配图建议
- 简化 ER 图或“状态×角色”矩阵
## 12. 上传与文件安全
关键点
- 扩展名白名单
- Magic Number 校验真实类型
- 下载强制 attachment
口播稿
- “文件安全是最大的攻击入口,因此做了三层防护。”
配图建议
- 三层防护示意图(白名单/校验/下载控制)
## 13. 审计与日志体系
关键点
- 全局审计日志拦截
- 语义化动作映射
- 入库可追溯
口播稿
- “任何关键操作都可追溯到人、时间与结果。”
配图建议
- 日志链路图或“审计追溯”示意
## 14. 认证与单点登录
关键点
- JWT + 过期控制
- token_version 实现强制下线
口播稿
- “不依赖复杂系统,用一个版本号实现单点登录与强制失效。”
配图建议
- Token 版本演进示意图
## 15. 接口防护与限流
关键点
- 全局限流 + 认证接口更严限流
- 验证码与短信验证机制
口播稿
- “对高风险入口进行更严格的限流,防暴力破解。”
配图建议
- “分级限流”示意图
## 16. 运维保障(监控告警)
关键点
- 磁盘空间监控
- 自动告警通知
口播稿
- “提前发现问题比处理事故更重要,系统自动告警避免资源耗尽。”
配图建议
- 监控告警流程图
## 17. 开发历程(里程碑)
关键点
- 需求澄清 → 权限模型 → 联调闭环 → 安全加固
口播稿
- “按关键链路推进,先保证主流程可用,再做安全与运维加固。”
配图建议
- 时间线图
## 18. 小切口解决问题
关键点
- token_version 单点登录
- URL 脱敏日志
- Magic Number 校验
- 磁盘告警
口播稿
- “这些小机制代价低,但显著降低了安全与运维风险。”
配图建议
- 四象限小结卡片
## 19. 安全专题(集中总结)
关键点
- 认证、密码、传输、接口、文件、日志六层防护
口播稿
- “安全不是单点技术,是全链路策略组合。”
配图建议
- 六层安全防护环
## 20. 价值总结与下一步
关键点
- 价值:闭环、合规、可追溯、可扩展
- 下一步:流程可配置、多租户、统计深化
口播稿
- “本期完成的是基础闭环,下一步聚焦可配置与更深的管理洞察。”
配图建议
- “现在/下一步”对比图
## 1. 项目背景与目标
- 业务痛点:成果类型多、流程长、数据分散、审查流程不统一、统计与归档难
- 目标:实现成果全生命周期管理(录入—审核—统计—归档/导出),保障合规与安全
## 2. 系统开发逻辑(从需求到架构)
- 业务逻辑主线:成果申报 → 审核流转 → 统计分析 → 归档导出 → 运维保障
- 技术逻辑主线:前后端分离 → API 标准化 → RBAC + 状态权限 → 审计与安全 → 可运维
## 3. 系统总体架构(概览)
- SPA 前端 + Node.js 后端 + PostgreSQL + Nginx
- 架构图(可引用文档中的 mermaid 图)
- 核心数据流:前端请求 → 反向代理 → API → DB/文件存储
## 3.1 系统架构图(素材)
用途:用于 PPT 的“总体架构”页,可直接粘贴成图或用 Mermaid 生成。
```mermaid
graph TD
Client[Web 前端 SPA<br/>React] -->|HTTPS/JSON| Nginx[Nginx 反向代理]
Nginx -->|Proxy Pass| Server[Node.js 后端 API]
Nginx -->|Static Files| Uploads[文件存储 Uploads]
Server -->|SQL| DB[(PostgreSQL)]
Server -->|审计日志| Logs[日志系统/审计库]
```
讲解要点(口播要点)
- 前后端分离,接口统一,安全与运维可控
- 文件与数据库分层存储,方便归档与扩展
- Nginx 统一入口,支持 HTTPS 与静态资源托管
## 4. 业务模块拆解
- 账号与权限(注册/登录/角色/权限矩阵)
- 成果管理(10 种类型、动态表单、附件、查重机制)
- 审核管理(多角色分工、回避机制、状态约束)
- 统计分析(多维度图表、趋势与贡献)
- 归档与导出(CSV、ZIP、电子档案)
- 通知公告(富文本、附件、系统告警)
## 5. 核心数据与权限模型(亮点)
- 角色体系:user / intermediate_user / senior_user / admin / maintainer / super_admin
- 权限控制:RBAC + 成果状态细粒度限制(pending / rejected / approved
- 关键场景:提交人 vs 完成人权限区分、管理员回避审查
## 6. 关键技术实现(亮点聚焦)
- 文件上传安全:白名单 + Magic Number 校验 + 下载强制 attachment
- 审计日志:全局拦截、语义化动作映射、入库审计
- 单点登录:JWT + token_version 控制同账号并发
- 运维守护:磁盘空间监控 + 自动告警
- 限流与防暴力:全局与认证接口分级限流
## 7. 开发历程(里程碑)
- 需求澄清 → 权限模型定稿
- 数据结构与接口标准 → 后端骨架
- 前后端联调 → 上传/审核/统计闭环
- 安全与运维加固 → 上线前合规检查
## 7.1 核心流程图(素材)
用途:用于 PPT 的“业务流程”页,可直接粘贴成图或用 Mermaid 生成。
```mermaid
flowchart LR
A[用户登录/注册] --> B[成果申报]
B --> C{查重拦截}
C -- 通过 --> D[进入审核队列]
C -- 重复/无效 --> B
D --> E{审核结果}
E -- 通过 --> F[入库统计/归档]
E -- 驳回 --> B
F --> G[统计分析]
F --> H[导出/归档]
G --> I[管理决策支持]
```
讲解要点(口播要点)
- 全流程闭环,关键节点有自动校验与权限控制
- 审核环节是质量门槛,统计与导出为管理输出
## 8. 开发过程中的关键抉择(为什么这样做)
- 为什么选择前后端分离:迭代快、职责清晰、部署灵活
- 为什么权限细分:保障科研数据边界与合规
- 为什么强调审计与日志:管理系统必须可追溯
## 9. 小切口解决问题(可讲的“工程细节”)
- Token 版本号:用最小改动实现“单点登录”和强制下线
- URL 脱敏日志:一行正则规避日志泄密风险
- Magic Number 校验:阻断伪装文件上载
- 磁盘空间监控:运维问题提前暴露,避免事故
## 10. 安全专题(单独章节)
- 身份认证:JWT + 过期控制 + token_version
- 密码安全:bcrypt 加盐哈希
- 传输安全:HTTPS + Nginx 反向代理
- 接口防护:Rate Limit + 验证码
- 数据与日志:敏感参数脱敏、审计日志入库
- 文件安全:白名单、Magic Number、下载强制 attachment
## 11. 开发心得(可复用的方法)
- 先稳定关键路径,再扩展边缘能力
- 面向“审计/合规”做系统设计,而不是事后补丁
- 把运维与安全作为功能的一部分
- 小机制大收益:用最小成本带来可见提升
## 12. 价值总结与下一步
- 业务价值:流程闭环、统计可视化、管理可追溯
- 技术价值:统一权限模型、安全与运维体系化
- 下一步(可选):多租户、流程可配置、更多统计维度
---
# 关键代码摘录(可用作“技术亮点/安全章节”附页)
> 提示:以下代码块可直接截图进 PPT。路径已标注。
## A. 限流 + 移动端拦截 + 日志脱敏
路径:`server/index.js`
```js
morgan.token('safe-url', (req) => {
let url = req.originalUrl || req.url;
url = url.replace(/([?&])(token|password|code)=([^&]+)/gi, '$1$2=***');
return url;
});
const globalLimiter = rateLimit({
windowMs: 1 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
});
const authLimiter = rateLimit({
windowMs: 1 * 60 * 1000,
max: 10,
standardHeaders: true,
legacyHeaders: false,
});
app.use((req, res, next) => {
const ua = req.headers['user-agent'] || '';
const isMobile = /mobile|android|iphone|ipad|phone/i.test(ua);
if (isMobile) return res.status(403).send('移动端访问被禁止');
next();
});
```
## B. JWT 校验 + token_version 单点登录
路径:`server/middleware/auth.js`
```js
const token = req.headers['authorization']?.split(' ')[1] || req.query.token;
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const tokenVersion = decoded.token_version || 0;
const result = await db.query('SELECT token_version FROM users WHERE id = $1', [decoded.id]);
const dbVersion = result.rows[0].token_version || 0;
if (tokenVersion !== dbVersion) {
return res.status(401).json({ message: '账号在其他设备登录,请重新登录' });
}
```
## C. 密码加盐哈希(bcrypt
路径:`server/routes/auth.js`
```js
const salt = await bcrypt.genSalt(10);
const passwordHash = await bcrypt.hash(newPassword, salt);
await db.query(
'UPDATE users SET password_hash = $1, token_version = CASE WHEN token_version >= 2000000000 THEN 1 ELSE token_version + 1 END WHERE username = $2',
[passwordHash, phoneNumber]
);
```
## D. 文件上传白名单 + Magic Number 校验
路径:`server/routes/achievements.js`
```js
const allowedExtensions = [
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
'.txt', '.jpg', '.jpeg', '.png', '.zip', '.rar', '.7z'
];
const upload = multer({
storage,
fileFilter: (req, file, cb) => {
const ext = path.extname(file.originalname).toLowerCase();
if (allowedExtensions.includes(ext)) cb(null, true);
else cb(new Error(`不支持的文件类型 (${ext})`));
}
});
const fileType = await FileType.fromFile(file.path);
const allowedMimes = [
'image/', 'application/pdf', 'application/msword',
'application/vnd.openxmlformats-officedocument',
'application/vnd.ms-excel', 'application/vnd.ms-powerpoint',
'application/zip', 'application/x-zip-compressed',
'application/x-rar-compressed', 'application/x-7z-compressed'
];
if (fileType && !allowedMimes.some(m => fileType.mime.startsWith(m))) {
fs.unlinkSync(file.path);
return res.status(400).json({ message: '文件真实类型不被允许' });
}
```
## E. 审计日志(语义映射 + 入库)
路径:`server/middleware/auditLogger.js`
```js
const getActionDescription = (method, url) => {
if (path === '/api/auth/login' && method === 'POST') return '用户登录';
if (path === '/api/achievements' && method === 'POST') return '上传成果';
// ... 更多动作映射
};
const logMessage = `[AUDIT] IP:${clientIp} | User:${userInfo} | ${method} ${safeUrl} | Action:${description || 'Unknown'} | Status:${status} | Time:${duration}ms`;
await db.query(
'INSERT INTO audit_logs (user_id, username, real_name, ip_address, method, url, description, status, duration) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)',
[userId, username, realName, clientIp, method, safeUrl, description, status, duration]
);
```
## F. 运营级监控:磁盘空间告警
路径:`server/utils/diskMonitor.js`
```js
const THRESHOLD_BYTES = 10 * 1024 * 1024 * 1024; // 10GB
if (FreeSpace < THRESHOLD_BYTES) {
const title = `【系统警告】磁盘空间不足(${root})`;
const content = `剩余空间 ${freeGB} GB,低于阈值 10GB`;
await db.query(
'INSERT INTO notifications (title, content, publisher_id, publisher_name, is_top, created_at) VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP)',
[title, content, publisherId, '系统监控', true]
);
}
```
---
## 附:引用的项目文档范围
- `PROJECT_DOCUMENTATION.md` 的“项目概述、权限体系、业务流程、技术架构、安全防御体系”章节
- 代码路径:`server/index.js`, `server/middleware/auth.js`, `server/middleware/auditLogger.js`, `server/routes/auth.js`, `server/routes/achievements.js`, `server/utils/diskMonitor.js`
```