save code

This commit is contained in:
Your Name
2026-01-26 12:29:56 +08:00
parent 4408f41d81
commit 40d2f3f6ac
13 changed files with 4891 additions and 124 deletions
+152
View File
@@ -0,0 +1,152 @@
# 项目管理系统
## 项目简介
项目管理系统是一个基于BS架构的企业级项目管理平台,旨在帮助企业实现项目全生命周期的数字化管理,包括项目创建、编辑、跟踪、统计等功能。
## 功能特性
### 1. 用户管理
- **管理员**:可以创建用户,修改用户密码,权限
- **市场部**:可以创建项目
- **其他部门**:可以修改项目内容
### 2. 项目创建
- 项目只能由市场部创建
- 支持完整的项目信息录入,包括基本信息、项目描述、项目团队、项目时间、项目预算、项目里程碑、项目风险等
### 3. 项目编辑
- 所有用户可以修改项目
- 自动记录修改历史记录,便于追溯
### 4. 项目统计
- 管理员可以通过各种条件筛选和统计项目
- 支持多维度项目统计分析
## 技术栈
### 前端技术
- **框架**Vue 3
- **状态管理**Pinia
- **UI组件库**Element Plus
- **路由**Vue Router
- **网络请求**Axios
### 后端技术
- **框架**FastAPI 0.104.0+
- **ORM框架**SQLAlchemy 2.0.0+
- **数据库驱动**PyMySQL 1.1.0+
- **数据库**MySQL 8.0+
- **认证**JWT 2.8.0+
- **密码加密**Passlib 1.7.4+
- **数据验证**Pydantic 2.5.0+
- **API文档**Swagger (FastAPI自动生成)
- **构建工具**Poetry 1.7.0+
## 项目结构
### 前端结构
```
├── public/ # 静态资源
├── src/ # 源代码
│ ├── assets/ # 资源文件
│ ├── components/ # 公共组件
│ ├── views/ # 页面组件
│ ├── router/ # 路由配置
│ ├── store/ # 状态管理
│ ├── api/ # API请求
│ ├── utils/ # 工具函数
│ ├── constants/ # 常量定义
│ ├── hooks/ # 自定义Hooks
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .env # 环境变量
├── vite.config.js # Vite配置
├── package.json # 项目依赖
└── README.md # 项目说明
```
### 后端结构
```
├── app/ # 应用代码
│ ├── api/ # API路由
│ ├── models/ # 数据模型
│ ├── schemas/ # Pydantic模式
│ ├── services/ # 业务逻辑
│ ├── database/ # 数据库配置
│ ├── common/ # 公共模块
│ ├── config.py # 应用配置
│ └── main.py # 应用入口
├── tests/ # 测试代码
├── alembic/ # 数据库迁移
├── pyproject.toml # Poetry配置
├── requirements.txt # 依赖列表
└── README.md # 项目说明
```
## 开发环境搭建
### 前端环境
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `npm install`
3. 启动开发服务器: `npm run dev`
4. 访问: `http://localhost:5173`
### 后端环境
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `poetry install``pip install -r requirements.txt`
3. 配置数据库连接 (config.py)
4. 初始化数据库: `alembic upgrade head`
5. 启动应用: `uvicorn app.main:app --reload`
6. 访问: `http://localhost:8000`
7. API文档: `http://localhost:8000/docs`
## 数据库配置
1. 创建数据库: `CREATE DATABASE project_management CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`
2. 执行数据库初始化脚本: `docs/init.sql`
3. 配置数据库连接信息
## 系统初始化
### 初始用户
- **管理员**:用户名: admin, 密码: 123456
- **市场部**:用户名: marketing, 密码: 123456
- **其他部门**:用户名: other, 密码: 123456
## 项目文档
- **产品需求文档**:docs/产品需求文档.md
- **功能规格说明书**:docs/功能规格说明书.md
- **数据库设计文档**:docs/数据库设计文档.md
- **技术架构文档**:docs/技术架构文档.md
- **项目示例文件**docs/example.xsl
## 部署方案
### 前端部署
1. 构建生产版本: `npm run build`
2. 将构建产物复制到 Nginx 静态目录
3. 配置 Nginx 反向代理
### 后端部署
1. 安装依赖: `poetry install --no-dev``pip install -r requirements.txt`
2. 配置环境变量和数据库连接
3. 使用 Gunicorn 启动应用: `gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker`
4. 配置 Nginx 反向代理
## 安全注意事项
1. 首次登录后请修改初始密码
2. 定期备份数据库
3. 避免使用弱密码
4. 限制系统访问IP
5. 定期更新系统和依赖库版本
## 联系方式
如有问题或建议,请联系项目管理员。
---
© 2026 项目管理系统 版权所有
-14
View File
@@ -1,14 +0,0 @@
import os
from .xsl_nodes_mask import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
NODE_CLASS_MAPPINGS = {
**NODE_CLASS_MAPPINGS,
}
NODE_DISPLAY_NAME_MAPPINGS = {
**NODE_DISPLAY_NAME_MAPPINGS,
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
+838
View File
@@ -0,0 +1,838 @@
# 后端API文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 后端API文档
---
## 1. API概述
### 1.1 基础信息
- **API前缀**: `/api`
- **API文档地址**: `/docs`
- **认证方式**: JWT Token (Bearer Token)
- **响应格式**: JSON
- **错误处理**: 统一错误响应格式
### 1.2 响应格式
#### 成功响应
```json
{
"code": 200,
"message": "操作成功",
"data": {...}
}
```
#### 错误响应
```json
{
"code": ,
"message": "错误信息"
}
```
### 1.3 错误码
| 错误码 | 说明 |
|--------|------|
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 禁止访问 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
| 1001 | 用户名或密码错误 |
| 1002 | 用户不存在 |
| 1003 | 用户名已存在 |
| 1004 | 密码不一致 |
| 2001 | 项目不存在 |
| 2002 | 无权限操作 |
---
## 2. 认证API
### 2.1 登录
**接口地址**: `/api/auth/login`
**请求方法**: `POST`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| username | string | body | 是 | 用户名 |
| password | string | body | 是 | 密码 |
**请求示例**:
```json
{
"username": "admin",
"password": "123456"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"userInfo": {
"userId": "admin001",
"username": "admin",
"realName": "系统管理员",
"department": "ADMIN",
"role": "ADMIN"
}
}
}
```
### 2.2 退出登录
**接口地址**: `/api/auth/logout`
**请求方法**: `POST`
**请求参数**: 无
**响应示例**:
```json
{
"code": 200,
"message": "退出成功"
}
```
### 2.3 获取用户信息
**接口地址**: `/api/auth/userInfo`
**请求方法**: `GET`
**请求参数**: 无
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": {
"userId": "admin001",
"username": "admin",
"realName": "系统管理员",
"department": "ADMIN",
"role": "ADMIN"
}
}
```
---
## 3. 用户API
### 3.1 创建用户
**接口地址**: `/api/user`
**请求方法**: `POST`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| username | string | body | 是 | 用户名 |
| password | string | body | 是 | 密码 |
| realName | string | body | 是 | 真实姓名 |
| department | string | body | 是 | 部门 |
| phone | string | body | 否 | 联系电话 |
| email | string | body | 否 | 邮箱 |
| role | string | body | 是 | 角色 |
**请求示例**:
```json
{
"username": "test",
"password": "123456",
"realName": "测试用户",
"department": "技术部",
"phone": "13800138000",
"email": "test@example.com",
"role": "OTHER"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "创建成功"
}
```
### 3.2 更新用户
**接口地址**: `/api/user/{id}`
**请求方法**: `PUT`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 用户ID |
| realName | string | body | 否 | 真实姓名 |
| department | string | body | 否 | 部门 |
| phone | string | body | 否 | 联系电话 |
| email | string | body | 否 | 邮箱 |
| role | string | body | 否 | 角色 |
**请求示例**:
```json
{
"realName": "测试用户1",
"department": "市场部",
"role": "MARKETING"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "更新成功"
}
```
### 3.3 删除用户
**接口地址**: `/api/user/{id}`
**请求方法**: `DELETE`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 用户ID |
**响应示例**:
```json
{
"code": 200,
"message": "删除成功"
}
```
### 3.4 获取用户列表
**接口地址**: `/api/user`
**请求方法**: `GET`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| page | integer | query | 否 | 页码,默认1 |
| size | integer | query | 否 | 每页数量,默认10 |
| username | string | query | 否 | 用户名(模糊查询) |
| department | string | query | 否 | 部门 |
| role | string | query | 否 | 角色 |
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": [
{
"userId": "admin001",
"username": "admin",
"realName": "系统管理员",
"department": "ADMIN",
"role": "ADMIN",
"status": 1,
"createTime": "2025-01-01 00:00:00",
"lastLoginTime": "2025-01-15 10:00:00"
}
],
"total": 1
}
```
### 3.5 重置密码
**接口地址**: `/api/user/resetPassword/{id}`
**请求方法**: `PUT`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 用户ID |
| password | string | body | 是 | 新密码 |
**请求示例**:
```json
{
"password": "123456"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "密码重置成功"
}
```
---
## 4. 项目API
### 4.1 创建项目
**接口地址**: `/api/project`
**请求方法**: `POST`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| projectName | string | body | 是 | 项目名称 |
| status | string | body | 是 | 项目状态 |
| leader | string | body | 是 | 负责人 |
| phone | string | body | 否 | 联系电话 |
| email | string | body | 否 | 邮箱 |
| background | string | body | 否 | 项目背景 |
| goal | string | body | 否 | 项目目标 |
| scope | string | body | 否 | 项目范围 |
| startDate | string | body | 是 | 开始日期 |
| plannedEndDate | string | body | 是 | 预计结束日期 |
| actualEndDate | string | body | 否 | 实际结束日期 |
| totalBudget | number | body | 是 | 总预算 |
| usedBudget | number | body | 否 | 已使用预算 |
| members | array | body | 否 | 项目成员 |
| milestones | array | body | 否 | 项目里程碑 |
| risks | array | body | 否 | 项目风险 |
| remarks | string | body | 否 | 备注 |
**请求示例**:
```json
{
"projectName": "测试项目",
"status": "NOT_STARTED",
"leader": "张三",
"phone": "13800138000",
"email": "zhangsan@example.com",
"background": "为了提升企业运营效率",
"goal": "完成企业内部管理系统的全面数字化改造",
"scope": "包括人力资源、财务管理、供应链管理等模块",
"startDate": "2025-01-15",
"plannedEndDate": "2025-06-30",
"totalBudget": 500000,
"usedBudget": 0,
"members": [
{
"name": "张三",
"role": "项目经理",
"department": "市场部"
},
{
"name": "李四",
"role": "技术负责人",
"department": "技术部"
}
],
"milestones": [
{
"name": "需求分析完成",
"plannedDate": "2025-02-15",
"status": "NOT_STARTED"
},
{
"name": "系统设计完成",
"plannedDate": "2025-03-15",
"status": "NOT_STARTED"
}
],
"risks": [
{
"description": "技术难度较高,可能影响进度",
"level": "HIGH",
"measure": "增加技术团队人员投入"
}
],
"remarks": "项目需要与现有系统进行数据对接"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "创建成功",
"data": {
"projectId": "PRJ2025001"
}
}
```
### 4.2 更新项目
**接口地址**: `/api/project/{id}`
**请求方法**: `PUT`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 项目ID |
| projectName | string | body | 否 | 项目名称 |
| status | string | body | 否 | 项目状态 |
| leader | string | body | 否 | 负责人 |
| phone | string | body | 否 | 联系电话 |
| email | string | body | 否 | 邮箱 |
| background | string | body | 否 | 项目背景 |
| goal | string | body | 否 | 项目目标 |
| scope | string | body | 否 | 项目范围 |
| startDate | string | body | 否 | 开始日期 |
| plannedEndDate | string | body | 否 | 预计结束日期 |
| actualEndDate | string | body | 否 | 实际结束日期 |
| totalBudget | number | body | 否 | 总预算 |
| usedBudget | number | body | 否 | 已使用预算 |
| members | array | body | 否 | 项目成员 |
| milestones | array | body | 否 | 项目里程碑 |
| risks | array | body | 否 | 项目风险 |
| remarks | string | body | 否 | 备注 |
**请求示例**:
```json
{
"projectName": "测试项目1",
"status": "IN_PROGRESS",
"usedBudget": 100000
}
```
**响应示例**:
```json
{
"code": 200,
"message": "更新成功"
}
```
### 4.3 删除项目
**接口地址**: `/api/project/{id}`
**请求方法**: `DELETE`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 项目ID |
**响应示例**:
```json
{
"code": 200,
"message": "删除成功"
}
```
### 4.4 获取项目列表
**接口地址**: `/api/project`
**请求方法**: `GET`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| page | integer | query | 否 | 页码,默认1 |
| size | integer | query | 否 | 每页数量,默认10 |
| projectName | string | query | 否 | 项目名称(模糊查询) |
| status | string | query | 否 | 项目状态 |
| leader | string | query | 否 | 负责人(模糊查询) |
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": [
{
"projectId": "PRJ2025001",
"projectNo": "PRJ2025001",
"projectName": "测试项目",
"status": "IN_PROGRESS",
"leader": "张三",
"createTime": "2025-01-15 00:00:00",
"updateTime": "2025-01-20 10:00:00"
}
],
"total": 1
}
```
### 4.5 获取项目详情
**接口地址**: `/api/project/{id}`
**请求方法**: `GET`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| id | string | path | 是 | 项目ID |
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": {
"projectId": "PRJ2025001",
"projectNo": "PRJ2025001",
"projectName": "测试项目",
"status": "IN_PROGRESS",
"leader": "张三",
"phone": "13800138000",
"email": "zhangsan@example.com",
"background": "为了提升企业运营效率",
"goal": "完成企业内部管理系统的全面数字化改造",
"scope": "包括人力资源、财务管理、供应链管理等模块",
"startDate": "2025-01-15",
"plannedEndDate": "2025-06-30",
"actualEndDate": null,
"totalBudget": 500000,
"usedBudget": 100000,
"remainingBudget": 400000,
"members": [
{
"name": "张三",
"role": "项目经理",
"department": "市场部"
},
{
"name": "李四",
"role": "技术负责人",
"department": "技术部"
}
],
"milestones": [
{
"name": "需求分析完成",
"plannedDate": "2025-02-15",
"actualDate": null,
"status": "NOT_STARTED"
},
{
"name": "系统设计完成",
"plannedDate": "2025-03-15",
"actualDate": null,
"status": "NOT_STARTED"
}
],
"risks": [
{
"description": "技术难度较高,可能影响进度",
"level": "HIGH",
"measure": "增加技术团队人员投入"
}
],
"remarks": "项目需要与现有系统进行数据对接",
"creator": "marketing",
"createTime": "2025-01-15 00:00:00",
"lastModifier": "admin",
"updateTime": "2025-01-20 10:00:00"
}
}
```
---
## 5. 历史记录API
### 5.1 获取项目历史
**接口地址**: `/api/history/{projectId}`
**请求方法**: `GET`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| projectId | string | path | 是 | 项目ID |
| page | integer | query | 否 | 页码,默认1 |
| size | integer | query | 否 | 每页数量,默认10 |
| operator | string | query | 否 | 操作人(模糊查询) |
| startDate | string | query | 否 | 开始日期 |
| endDate | string | query | 否 | 结束日期 |
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": [
{
"historyId": "HIS2025001",
"projectId": "PRJ2025001",
"projectNo": "PRJ2025001",
"operationType": "UPDATE",
"operator": "admin",
"operationTime": "2025-01-20 10:00:00",
"fieldName": "status",
"oldValue": "NOT_STARTED",
"newValue": "IN_PROGRESS"
}
],
"total": 1
}
```
---
## 6. 统计API
### 6.1 筛选项目
**接口地址**: `/api/statistics/filter`
**请求方法**: `POST`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| projectNo | string | body | 否 | 项目编号 |
| projectName | string | body | 否 | 项目名称(模糊查询) |
| status | string | body | 否 | 项目状态 |
| leader | string | body | 否 | 负责人(模糊查询) |
| creator | string | body | 否 | 创建人(模糊查询) |
| createStartDate | string | body | 否 | 创建开始日期 |
| createEndDate | string | body | 否 | 创建结束日期 |
| updateStartDate | string | body | 否 | 更新开始日期 |
| updateEndDate | string | body | 否 | 更新结束日期 |
| page | integer | body | 否 | 页码,默认1 |
| size | integer | body | 否 | 每页数量,默认10 |
**请求示例**:
```json
{
"projectName": "测试",
"status": "IN_PROGRESS",
"createStartDate": "2025-01-01",
"createEndDate": "2025-12-31"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": [
{
"projectId": "PRJ2025001",
"projectNo": "PRJ2025001",
"projectName": "测试项目",
"status": "IN_PROGRESS",
"leader": "张三",
"createTime": "2025-01-15 00:00:00",
"updateTime": "2025-01-20 10:00:00"
}
],
"total": 1
}
```
### 6.2 统计项目
**接口地址**: `/api/statistics/statistics`
**请求方法**: `POST`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| dimension | string | body | 是 | 统计维度:status, department, leader, month |
| startDate | string | body | 否 | 开始日期 |
| endDate | string | body | 否 | 结束日期 |
**请求示例**:
```json
{
"dimension": "status",
"startDate": "2025-01-01",
"endDate": "2025-12-31"
}
```
**响应示例**:
```json
{
"code": 200,
"message": "统计成功",
"data": {
"dimension": "status",
"total": 10,
"details": [
{
"name": "NOT_STARTED",
"value": 2
},
{
"name": "IN_PROGRESS",
"value": 5
},
{
"name": "COMPLETED",
"value": 2
},
{
"name": "PAUSED",
"value": 1
}
]
}
}
```
---
## 7. 系统API
### 7.1 获取操作日志
**接口地址**: `/api/system/log`
**请求方法**: `GET`
**请求参数**:
| 参数名 | 类型 | 位置 | 必填 | 说明 |
|--------|------|------|------|------|
| page | integer | query | 否 | 页码,默认1 |
| size | integer | query | 否 | 每页数量,默认10 |
| username | string | query | 否 | 用户名(模糊查询) |
| operation | string | query | 否 | 操作内容(模糊查询) |
| startDate | string | query | 否 | 开始日期 |
| endDate | string | query | 否 | 结束日期 |
**响应示例**:
```json
{
"code": 200,
"message": "查询成功",
"data": [
{
"logId": "LOG2025001",
"username": "admin",
"operation": "登录系统",
"ipAddress": "127.0.0.1",
"userAgent": "Mozilla/5.0...",
"operationTime": "2025-01-20 10:00:00"
}
],
"total": 1
}
```
---
## 8. 认证与授权
### 8.1 认证流程
1. 客户端发送登录请求到 `/api/auth/login`
2. 服务端验证用户名和密码
3. 验证成功后生成 JWT Token
4. 客户端保存 Token 到 localStorage
5. 后续请求在请求头中携带 Token: `Authorization: Bearer <token>`
6. 服务端验证 Token 的有效性
7. 验证通过后处理请求
### 8.2 授权流程
1. 服务端从 Token 中解析出用户信息
2. 根据用户角色和权限判断是否有权限访问请求的资源
3. 有权限则继续处理请求,无权限则返回 403 错误
### 8.3 角色权限
| 角色 | 权限 |
|------|------|
| ADMIN | 所有权限 |
| MARKETING | 创建项目、编辑项目、查看项目、查看历史记录 |
| OTHER | 编辑项目、查看项目、查看历史记录 |
---
## 9. 附录
### 9.1 数据字典
#### 项目状态
| 值 | 说明 |
|----|------|
| NOT_STARTED | 未开始 |
| IN_PROGRESS | 进行中 |
| COMPLETED | 已完成 |
| PAUSED | 已暂停 |
| CANCELLED | 已取消 |
#### 角色
| 值 | 说明 |
|----|------|
| ADMIN | 管理员 |
| MARKETING | 市场部 |
| OTHER | 其他部门 |
#### 风险等级
| 值 | 说明 |
|----|------|
| HIGH | 高 |
| MEDIUM | 中 |
| LOW | 低 |
#### 操作类型
| 值 | 说明 |
|----|------|
| CREATE | 创建 |
| UPDATE | 更新 |
| DELETE | 删除 |
### 9.2 开发规范
- **API设计**: 遵循 RESTful API 设计规范
- **参数验证**: 使用 Pydantic 进行参数验证
- **错误处理**: 使用统一的错误处理机制
- **日志记录**: 记录重要操作的日志
- **测试**: 为每个 API 编写单元测试
### 9.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
+381
View File
@@ -0,0 +1,381 @@
# 后端依赖管理文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 后端依赖管理文档
---
## 1. 依赖管理工具
本项目使用以下工具管理依赖:
### 1.1 Poetry (推荐)
Poetry 是一个现代化的 Python 依赖管理和打包工具,提供了更简洁、更一致的依赖管理体验。
**安装 Poetry**:
```bash
# 使用 pip 安装
pip install poetry
# 或使用官方安装脚本
curl -sSL https://install.python-poetry.org | python3 -
```
### 1.2 pip
如果您不使用 Poetry,也可以使用 pip 管理依赖。
---
## 2. 核心依赖
### 2.1 主要依赖
| 依赖 | 版本 | 用途 |
|------|------|------|
| fastapi | ^0.104.0 | 后端 Web 框架 |
| uvicorn[standard] | ^0.24.0 | ASGI 服务器 |
| sqlalchemy | ^2.0.0 | ORM 框架 |
| pymysql | ^1.1.0 | MySQL 数据库驱动 |
| python-jose[cryptography] | ^3.3.0 | JWT 库 |
| passlib[bcrypt] | ^1.7.4 | 密码哈希库 |
| pydantic | ^2.5.0 | 数据验证库 |
| pydantic-settings | ^2.1.0 | 配置管理库 |
| alembic | ^1.12.0 | 数据库迁移工具 |
| python-multipart | ^0.0.6 | 表单数据处理 |
| python-dotenv | ^1.0.0 | 环境变量管理 |
| aiomysql | ^0.2.0 | 异步 MySQL 驱动 |
### 2.2 开发依赖
| 依赖 | 版本 | 用途 |
|------|------|------|
| pytest | ^7.4.0 | 测试框架 |
| pytest-asyncio | ^0.21.0 | 异步测试支持 |
| pytest-cov | ^4.1.0 | 测试覆盖率 |
| flake8 | ^6.1.0 | 代码风格检查 |
| black | ^23.11.0 | 代码格式化 |
| isort | ^5.12.0 | 导入排序 |
| mypy | ^1.7.0 | 类型检查 |
---
## 3. 配置文件
### 3.1 pyproject.toml (Poetry)
```toml
[tool.poetry]
name = "project-management-backend"
version = "0.1.0"
description = "项目管理系统后端"
authors = [{ name = "Developer", email = "developer@example.com" }]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.9"
fastapi = "^0.104.0"
uvicorn = { version = "^0.24.0", extras = ["standard"] }
sqlalchemy = "^2.0.0"
pymysql = "^1.1.0"
python-jose = { version = "^3.3.0", extras = ["cryptography"] }
passlib = { version = "^1.7.4", extras = ["bcrypt"] }
pydantic = "^2.5.0"
pydantic-settings = "^2.1.0"
alembic = "^1.12.0"
python-multipart = "^0.0.6"
python-dotenv = "^1.0.0"
aiomysql = "^0.2.0"
[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-asyncio = "^0.21.0"
pytest-cov = "^4.1.0"
flake8 = "^6.1.0"
black = "^23.11.0"
isort = "^5.12.0"
mypy = "^1.7.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```
### 3.2 requirements.txt (pip)
```
fastapi==0.104.0
uvicorn[standard]==0.24.0
sqlalchemy==2.0.0
pymysql==1.1.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
pydantic==2.5.0
pydantic-settings==2.1.0
alembic==1.12.0
python-multipart==0.0.6
python-dotenv==1.0.0
aiomysql==0.2.0
# 开发依赖
pytest==7.4.0
pytest-asyncio==0.21.0
pytest-cov==4.1.0
flake8==6.1.0
black==23.11.0
isort==5.12.0
mypy==1.7.0
```
---
## 4. 依赖管理命令
### 4.1 使用 Poetry
#### 安装依赖
```bash
# 安装所有依赖(包括开发依赖)
poetry install
# 仅安装生产依赖
poetry install --no-dev
```
#### 添加依赖
```bash
# 添加生产依赖
poetry add <package>
# 添加开发依赖
poetry add --group dev <package>
```
#### 更新依赖
```bash
# 更新所有依赖
poetry update
# 更新特定依赖
poetry update <package>
```
#### 导出依赖
```bash
# 导出到 requirements.txt
poetry export --output requirements.txt
# 导出生产依赖
poetry export --output requirements.txt --without dev
```
#### 运行命令
```bash
# 在虚拟环境中运行命令
poetry run <command>
# 例如运行开发服务器
poetry run uvicorn app.main:app --reload
# 例如运行测试
poetry run pytest
```
### 4.2 使用 pip
#### 安装依赖
```bash
# 安装所有依赖
pip install -r requirements.txt
# 安装生产依赖(需要单独创建生产依赖文件)
pip install -r requirements-prod.txt
```
#### 添加依赖
```bash
# 安装并添加到 requirements.txt
pip install <package> && pip freeze | grep <package> >> requirements.txt
```
#### 更新依赖
```bash
# 更新所有依赖
pip install --upgrade -r requirements.txt
# 更新特定依赖
pip install --upgrade <package>
```
---
## 5. 环境配置
### 5.1 环境变量
项目使用 `.env` 文件管理环境变量,示例配置如下:
```env
# 数据库连接信息
DATABASE_URL="mysql+pymysql://username:password@localhost:3306/project_management"
# JWT 配置
SECRET_KEY="your-secret-key"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
# 应用配置
APP_NAME="Project Management System"
DEBUG=True
```
### 5.2 配置文件
项目使用 `app/config.py` 管理应用配置:
```python
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
"""应用配置"""
# 应用配置
app_name: str = "Project Management System"
debug: bool = True
# 数据库配置
database_url: str
# JWT 配置
secret_key: str
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
class Config:
env_file = ".env"
case_sensitive = False
@lru_cache()
def get_settings() -> Settings:
"""获取配置实例"""
return Settings()
settings = get_settings()
```
---
## 6. 依赖版本管理
### 6.1 版本约束
Poetry 使用语义化版本约束,常见的版本约束格式:
| 格式 | 说明 | 示例 |
|------|------|------|
| ^1.0.0 | 兼容 1.x.x 版本 | ^2.0.0 匹配 2.0.0, 2.1.0 但不匹配 3.0.0 |
| ~1.0.0 | 兼容 1.0.x 版本 | ~1.0.0 匹配 1.0.0, 1.0.1 但不匹配 1.1.0 |
| >=1.0.0 | 大于等于 1.0.0 | >=2.0.0 匹配 2.0.0, 3.0.0 |
| ==1.0.0 | 精确匹配 1.0.0 | ==1.0.0 只匹配 1.0.0 |
### 6.2 依赖锁定
Poetry 使用 `poetry.lock` 文件锁定依赖版本,确保在不同环境中安装相同版本的依赖:
```bash
# 生成锁定文件
poetry lock
# 使用锁定文件安装依赖
poetry install
```
### 6.3 依赖解析
如果遇到依赖冲突,可以使用以下方法解决:
1. **更新依赖版本**:尝试更新冲突的依赖版本
2. **指定版本**:为冲突的依赖指定兼容的版本
3. **使用虚拟环境**:为不同项目使用独立的虚拟环境
---
## 7. 开发最佳实践
### 7.1 依赖管理建议
1. **定期更新依赖**:定期更新依赖以获取安全补丁和新特性
2. **使用锁定文件**:在生产环境中使用锁定文件确保依赖版本一致
3. **分离开发和生产依赖**:只在生产环境中安装必要的依赖
4. **使用虚拟环境**:为每个项目使用独立的虚拟环境
5. **记录依赖变更**:在提交代码时同时提交依赖变更
### 7.2 安全注意事项
1. **检查依赖安全**:使用安全扫描工具检查依赖的安全漏洞
2. **使用可信依赖**:只使用来自可信源的依赖
3. **固定依赖版本**:在生产环境中固定依赖版本,避免自动更新引入问题
4. **定期审计依赖**:定期审计项目依赖,移除不再使用的依赖
---
## 8. 常见问题
### 8.1 依赖安装失败
**问题**:依赖安装失败,出现版本冲突
**解决方法**
1. 检查 Python 版本是否兼容
2. 尝试使用 `poetry update` 更新依赖
3. 检查网络连接是否正常
4. 尝试清理缓存:`poetry cache clear --all pypi`
### 8.2 数据库连接失败
**问题**:无法连接到数据库
**解决方法**
1. 检查数据库服务是否运行
2. 检查数据库连接字符串是否正确
3. 检查数据库用户权限是否正确
4. 检查网络连接是否正常
### 8.3 JWT 认证失败
**问题**JWT 认证失败
**解决方法**
1. 检查 `SECRET_KEY` 是否正确设置
2. 检查 Token 是否过期
3. 检查 Token 格式是否正确
4. 检查认证中间件配置是否正确
---
## 9. 附录
### 9.1 Python 版本要求
本项目要求 Python 3.9 或更高版本。
### 9.2 开发工具推荐
| 工具 | 用途 | 安装命令 |
|------|------|----------|
| Poetry | 依赖管理 | `pip install poetry` |
| PyCharm | IDE | [官网下载](https://www.jetbrains.com/pycharm/) |
| VS Code | 编辑器 | [官网下载](https://code.visualstudio.com/) |
| MySQL Workbench | 数据库管理 | [官网下载](https://www.mysql.com/products/workbench/) |
### 9.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
+479
View File
@@ -0,0 +1,479 @@
# 后端技术架构文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 后端技术架构文档
---
## 1. 技术选型
| 分类 | 技术 | 版本 | 选型理由 |
|------|------|------|----------|
| 后端框架 | FastAPI | 0.104.0+ | 高性能Python Web框架,自动生成API文档,支持异步 |
| ORM框架 | SQLAlchemy | 2.0.0+ | Python最流行的ORM框架,支持多种数据库 |
| 数据库驱动 | PyMySQL | 1.1.0+ | 纯Python实现的MySQL客户端 |
| 数据库 | MySQL | 8.0+ | 关系型数据库,稳定可靠,适合企业级应用 |
| 认证 | JWT | 2.8.0+ | JSON Web Token,用于用户认证和授权 |
| 密码加密 | Passlib | 1.7.4+ | 密码哈希库,支持多种加密算法 |
| 数据验证 | Pydantic | 2.5.0+ | 数据验证和设置库,与FastAPI完美集成 |
| API文档 | Swagger | - | FastAPI自动生成,提供交互式API文档 |
| 构建工具 | Poetry | 1.7.0+ | Python依赖管理和打包工具 |
| 数据库迁移 | Alembic | 1.12.0+ | SQLAlchemy的数据库迁移工具 |
| 测试框架 | Pytest | 7.4.0+ | Python最流行的测试框架 |
| 异步支持 | asyncio | - | Python内置的异步IO库 |
---
## 2. 架构设计
### 2.1 分层架构
```
┌─────────────────────────────────────────────────────────┐
│ 路由层 (API) │
│ (Router) │
├─────────────────────────────────────────────────────────┤
│ 业务逻辑层 (Service) │
│ (Service) │
├─────────────────────────────────────────────────────────┤
│ 数据访问层 (Model) │
│ (ORM Model) │
├─────────────────────────────────────────────────────────┤
│ 数据层 │
│ (MySQL) │
└─────────────────────────────────────────────────────────┘
```
### 2.2 核心模块
| 模块名称 | 主要职责 | 文件路径 | 依赖关系 |
|---------|---------|---------|----------|
| 认证模块 | 用户登录、退出、认证 | app/api/auth.py | 依赖用户模型、JWT |
| 用户模块 | 用户管理、权限管理 | app/api/user.py | 依赖用户模型、认证模块 |
| 项目模块 | 项目管理、创建、编辑 | app/api/project.py | 依赖项目模型、历史记录模块 |
| 历史记录模块 | 项目修改历史记录 | app/api/history.py | 依赖历史记录模型 |
| 统计模块 | 项目统计、数据分析 | app/api/statistics.py | 依赖项目模型 |
| 系统模块 | 系统配置、操作日志 | app/api/system.py | 依赖日志模型 |
### 2.3 数据流
1. **请求处理流程**
- 客户端发送请求到API路由
- 路由层验证请求参数和用户权限
- 调用服务层处理业务逻辑
- 服务层调用数据访问层操作数据库
- 数据访问层返回数据给服务层
- 服务层处理数据并返回给路由层
- 路由层返回响应给客户端
2. **项目创建流程**
- 验证用户权限(必须是市场部或管理员)
- 生成项目编号
- 创建项目记录
- 创建项目成员记录
- 创建项目里程碑记录
- 创建项目风险记录
- 创建项目历史记录
3. **项目编辑流程**
- 验证用户权限
- 获取项目当前信息
- 对比修改前后的数据
- 更新项目记录
- 更新相关表数据
- 创建项目历史记录
---
## 3. 目录结构
```
├── app/ # 应用代码
│ ├── api/ # API路由
│ │ ├── auth.py # 认证API
│ │ ├── user.py # 用户API
│ │ ├── project.py # 项目API
│ │ ├── history.py # 历史记录API
│ │ ├── statistics.py # 统计API
│ │ ├── system.py # 系统API
│ │ └── __init__.py # 导出API
│ ├── models/ # 数据模型
│ │ ├── __init__.py # 导出模型
│ │ ├── user.py # 用户模型
│ │ ├── project.py # 项目模型
│ │ ├── member.py # 成员模型
│ │ ├── milestone.py # 里程碑模型
│ │ ├── risk.py # 风险模型
│ │ ├── history.py # 历史记录模型
│ │ └── log.py # 日志模型
│ ├── schemas/ # Pydantic模式
│ │ ├── __init__.py # 导出模式
│ │ ├── auth.py # 认证模式
│ │ ├── user.py # 用户模式
│ │ ├── project.py # 项目模式
│ │ ├── history.py # 历史记录模式
│ │ ├── statistics.py # 统计模式
│ │ ├── system.py # 系统模式
│ │ └── common.py # 通用模式
│ ├── services/ # 业务逻辑
│ │ ├── __init__.py # 导出服务
│ │ ├── auth_service.py # 认证服务
│ │ ├── user_service.py # 用户服务
│ │ ├── project_service.py # 项目服务
│ │ ├── history_service.py # 历史记录服务
│ │ ├── statistics_service.py # 统计服务
│ │ └── system_service.py # 系统服务
│ ├── database/ # 数据库配置
│ │ ├── __init__.py # 导出配置
│ │ ├── config.py # 数据库配置
│ │ └── session.py # 数据库会话
│ ├── common/ # 公共模块
│ │ ├── __init__.py # 导出公共模块
│ │ ├── constants.py # 常量定义
│ │ ├── utils.py # 工具函数
│ │ ├── dependencies.py # 依赖注入
│ │ └── exceptions.py # 异常处理
│ ├── config.py # 应用配置
│ └── main.py # 应用入口
├── tests/ # 测试代码
│ ├── __init__.py # 测试初始化
│ ├── test_auth.py # 认证测试
│ ├── test_user.py # 用户测试
│ ├── test_project.py # 项目测试
│ ├── test_history.py # 历史记录测试
│ ├── test_statistics.py # 统计测试
│ └── conftest.py # 测试配置
├── alembic/ # 数据库迁移
│ ├── versions/ # 迁移版本
│ ├── env.py # 迁移环境
│ └── script.py.mako # 迁移脚本模板
├── pyproject.toml # Poetry配置
├── poetry.lock # Poetry锁文件
├── requirements.txt # 依赖列表
├── README.md # 项目说明
├── .env.example # 环境变量示例
└── .gitignore # Git忽略文件
```
---
## 4. 核心类与函数
### 4.1 认证模块
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `AuthRouter.login()` | 用户登录 | LoginRequest 登录请求 | `AuthResponse` | `HTTPException` | app/api/auth.py |
| `AuthRouter.logout()` | 用户退出 | 无 | `BaseResponse` | `HTTPException` | app/api/auth.py |
| `AuthRouter.get_user_info()` | 获取用户信息 | 无 | `UserInfoResponse` | `HTTPException` | app/api/auth.py |
| `AuthService.authenticate()` | 认证用户 | str username, str password | `AuthResponse` | `AuthenticationException` | app/services/auth_service.py |
| `AuthService.create_token()` | 创建Token | str user_id | `str` Token | `Exception` | app/services/auth_service.py |
| `AuthService.verify_token()` | 验证Token | str token | `dict` Token载荷 | `JWTError` | app/services/auth_service.py |
### 4.2 用户模块
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `UserRouter.create()` | 创建用户 | UserCreate 用户创建请求 | `BaseResponse` | `HTTPException` | app/api/user.py |
| `UserRouter.update()` | 更新用户 | str id, UserUpdate 用户更新请求 | `BaseResponse` | `HTTPException` | app/api/user.py |
| `UserRouter.delete()` | 删除用户 | str id | `BaseResponse` | `HTTPException` | app/api/user.py |
| `UserRouter.list()` | 获取用户列表 | UserQuery 查询参数 | `PageResponse[User]` | `HTTPException` | app/api/user.py |
| `UserRouter.reset_password()` | 重置密码 | str id, PasswordReset 密码重置请求 | `BaseResponse` | `HTTPException` | app/api/user.py |
| `UserService.create_user()` | 创建用户 | UserCreate 用户创建请求 | `User` | `ServiceException` | app/services/user_service.py |
| `UserService.update_user()` | 更新用户 | str id, UserUpdate 用户更新请求 | `User` | `ServiceException` | app/services/user_service.py |
| `UserService.delete_user()` | 删除用户 | str id | `bool` | `ServiceException` | app/services/user_service.py |
| `UserService.get_user_list()` | 获取用户列表 | UserQuery 查询参数 | `List[User]` | `ServiceException` | app/services/user_service.py |
| `UserService.reset_password()` | 重置密码 | str id, str password | `bool` | `ServiceException` | app/services/user_service.py |
### 4.3 项目模块
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `ProjectRouter.create()` | 创建项目 | ProjectCreate 项目创建请求 | `BaseResponse` | `HTTPException` | app/api/project.py |
| `ProjectRouter.update()` | 更新项目 | str id, ProjectUpdate 项目更新请求 | `BaseResponse` | `HTTPException` | app/api/project.py |
| `ProjectRouter.delete()` | 删除项目 | str id | `BaseResponse` | `HTTPException` | app/api/project.py |
| `ProjectRouter.list()` | 获取项目列表 | ProjectQuery 查询参数 | `PageResponse[Project]` | `HTTPException` | app/api/project.py |
| `ProjectRouter.detail()` | 获取项目详情 | str id | `ProjectDetailResponse` | `HTTPException` | app/api/project.py |
| `ProjectService.create_project()` | 创建项目 | ProjectCreate 项目创建请求, str username | `Project` | `ServiceException` | app/services/project_service.py |
| `ProjectService.update_project()` | 更新项目 | str id, ProjectUpdate 项目更新请求, str username | `Project` | `ServiceException` | app/services/project_service.py |
| `ProjectService.delete_project()` | 删除项目 | str id | `bool` | `ServiceException` | app/services/project_service.py |
| `ProjectService.get_project_list()` | 获取项目列表 | ProjectQuery 查询参数 | `List[Project]` | `ServiceException` | app/services/project_service.py |
| `ProjectService.get_project_detail()` | 获取项目详情 | str id | `ProjectDetail` | `ServiceException` | app/services/project_service.py |
### 4.4 历史记录模块
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `HistoryRouter.list()` | 获取项目历史 | str project_id, HistoryQuery 查询参数 | `PageResponse[ProjectHistory]` | `HTTPException` | app/api/history.py |
| `HistoryService.record_history()` | 记录历史 | str project_id, str operation_type, str operator, dict changes | `ProjectHistory` | `ServiceException` | app/services/history_service.py |
| `HistoryService.get_project_history()` | 获取项目历史 | str project_id, HistoryQuery 查询参数 | `List[ProjectHistory]` | `ServiceException` | app/services/history_service.py |
### 4.5 统计模块
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `StatisticsRouter.filter()` | 筛选项目 | ProjectFilter 筛选条件 | `PageResponse[Project]` | `HTTPException` | app/api/statistics.py |
| `StatisticsRouter.statistics()` | 统计项目 | StatisticsRequest 统计请求 | `StatisticsResponse` | `HTTPException` | app/api/statistics.py |
| `StatisticsService.filter_projects()` | 筛选项目 | ProjectFilter 筛选条件 | `List[Project]` | `ServiceException` | app/services/statistics_service.py |
| `StatisticsService.get_project_statistics()` | 获取项目统计 | StatisticsRequest 统计请求 | `StatisticsResult` | `ServiceException` | app/services/statistics_service.py |
---
## 5. 数据库设计
### 5.1 数据库表结构
详细的数据库表结构见《数据库设计文档》。
### 5.2 数据模型关系
```
User (用户)
|
| 1
|
| N
|
OperationLog (操作日志)
Project (项目)
|
| 1
|
| N
|
+-- ProjectMember (项目成员)
|
| 1
|
| N
|
+-- ProjectMilestone (项目里程碑)
|
| 1
|
| N
|
+-- ProjectRisk (项目风险)
|
| 1
|
| N
|
+-- ProjectHistory (项目历史)
```
### 5.3 数据库连接配置
- **开发环境**:使用本地MySQL数据库
- **测试环境**:使用测试MySQL数据库
- **生产环境**:使用生产MySQL数据库
---
## 6. API设计
### 6.1 认证API
| API路径 | 方法 | 模块/文件 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|----------|--------------|------------------|
| `/api/auth/login` | `POST` | `app/api/auth.py` | 用户登录 | `{"username": "admin", "password": "123456"}` | `{"code": 200, "data": {"token": "...", "userInfo": {...}}, "message": "登录成功"}` |
| `/api/auth/logout` | `POST` | `app/api/auth.py` | 用户退出 | N/A | `{"code": 200, "message": "退出成功"}` |
| `/api/auth/userInfo` | `GET` | `app/api/auth.py` | 获取用户信息 | N/A | `{"code": 200, "data": {"userId": "...", "username": "...", "realName": "...", "department": "...", "role": "..."}}` |
### 6.2 用户API
| API路径 | 方法 | 模块/文件 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|----------|--------------|------------------|
| `/api/user` | `GET` | `app/api/user.py` | 获取用户列表 | N/A (Query参数: page, size, username, department, role) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/user` | `POST` | `app/api/user.py` | 创建用户 | `{"username": "test", "password": "123456", "realName": "测试用户", "department": "技术部", "role": "OTHER"}` | `{"code": 200, "message": "创建成功"}` |
| `/api/user/{id}` | `PUT` | `app/api/user.py` | 更新用户 | `{"realName": "测试用户1", "department": "市场部", "role": "MARKETING"}` | `{"code": 200, "message": "更新成功"}` |
| `/api/user/{id}` | `DELETE` | `app/api/user.py` | 删除用户 | N/A | `{"code": 200, "message": "删除成功"}` |
| `/api/user/resetPassword/{id}` | `PUT` | `app/api/user.py` | 重置密码 | `{"password": "123456"}` | `{"code": 200, "message": "密码重置成功"}` |
### 6.3 项目API
| API路径 | 方法 | 模块/文件 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|----------|--------------|------------------|
| `/api/project` | `GET` | `app/api/project.py` | 获取项目列表 | N/A (Query参数: page, size, projectName, status, leader) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/project` | `POST` | `app/api/project.py` | 创建项目 | `{"projectName": "测试项目", "status": "NOT_STARTED", "leader": "张三", ...}` | `{"code": 200, "data": {"projectId": "..."}, "message": "创建成功"}` |
| `/api/project/{id}` | `GET` | `app/api/project.py` | 获取项目详情 | N/A | `{"code": 200, "data": {...}, "message": "查询成功"}` |
| `/api/project/{id}` | `PUT` | `app/api/project.py` | 更新项目 | `{"projectName": "测试项目1", "status": "IN_PROGRESS", ...}` | `{"code": 200, "message": "更新成功"}` |
| `/api/project/{id}` | `DELETE` | `app/api/project.py` | 删除项目 | N/A | `{"code": 200, "message": "删除成功"}` |
### 6.4 历史记录API
| API路径 | 方法 | 模块/文件 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|----------|--------------|------------------|
| `/api/history/{projectId}` | `GET` | `app/api/history.py` | 获取项目历史 | N/A (Query参数: page, size, operator, startDate, endDate) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
### 6.5 统计API
| API路径 | 方法 | 模块/文件 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|----------|--------------|------------------|
| `/api/statistics/filter` | `POST` | `app/api/statistics.py` | 筛选项目 | `{"projectNo": "PRJ2025001", "projectName": "测试", "status": "IN_PROGRESS", ...}` | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/statistics/statistics` | `POST` | `app/api/statistics.py` | 统计项目 | `{"dimension": "status", "startDate": "2025-01-01", "endDate": "2025-12-31"}` | `{"code": 200, "data": {...}, "message": "统计成功"}` |
---
## 7. 安全设计
### 7.1 认证与授权
- **认证方式**: JWT (JSON Web Token) 认证
- **授权方式**: 基于角色的访问控制 (RBAC)
- **密码加密**: 使用 Passlib 的 bcrypt 算法加密存储密码
- **会话管理**: JWT Token 存储在前端 localStorage 中,后端验证 Token 签名和有效期
### 7.2 接口安全
- **统一认证拦截**: 所有接口(除登录接口外)都需要验证 Token
- **权限验证**: 基于用户角色和权限进行接口访问控制
- **请求参数验证**: 使用 Pydantic 验证请求参数的合法性
- **防止SQL注入**: 使用 SQLAlchemy 的参数化查询,避免SQL注入
- **防止XSS攻击**: 前端使用 v-html 时进行转义,后端对输入进行过滤
- **防止CSRF攻击**: 使用 Token 验证,确保请求来自合法来源
### 7.3 数据安全
- **敏感数据加密**: 敏感数据(如密码)加密存储
- **数据备份**: 定期备份数据库,防止数据丢失
- **数据恢复**: 制定数据恢复计划,确保数据可恢复
- **日志审计**: 记录用户操作日志,便于追溯操作行为
---
## 8. 部署与集成
### 8.1 开发环境部署
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `poetry install``pip install -r requirements.txt`
3. 配置环境变量: 复制 `.env.example``.env` 并修改配置
4. 初始化数据库: `alembic upgrade head`
5. 启动应用: `uvicorn app.main:app --reload`
6. 访问: `http://localhost:8000`
7. API文档: `http://localhost:8000/docs`
### 8.2 生产环境部署
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `poetry install --no-dev``pip install -r requirements.txt`
3. 配置环境变量: 复制 `.env.example``.env` 并修改配置
4. 初始化数据库: `alembic upgrade head`
5. 构建应用: 无需构建,直接运行
6. 启动应用: `gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker`
7. 配置 Nginx 反向代理
### 8.3 集成方案
- **前端与后端集成**: 通过 RESTful API 进行数据交互
- **数据库集成**: 使用 SQLAlchemy ORM 操作数据库
- **日志集成**: 使用 Python logging 模块记录系统日志
- **监控集成**: 可集成 Prometheus + Grafana 监控系统性能
---
## 9. 性能优化
### 9.1 代码优化
- **异步处理**: 使用 FastAPI 的异步特性,提高并发处理能力
- **批量操作**: 对批量数据操作使用批量处理,减少数据库交互次数
- **缓存**: 对热点数据使用内存缓存,减少数据库查询
- **分页查询**: 使用分页查询,避免一次性加载大量数据
### 9.2 数据库优化
- **索引优化**: 为常用查询字段创建索引,提高查询性能
- **连接池**: 使用 SQLAlchemy 的连接池,提高数据库连接效率
- **查询优化**: 使用 SQLAlchemy 的 lazy loading 和 eager loading 优化查询
- **数据库配置**: 优化 MySQL 配置参数,提高数据库性能
### 9.3 部署优化
- **负载均衡**: 对多实例部署使用负载均衡
- **水平扩展**: 根据业务需求进行水平扩展
- **资源限制**: 合理设置应用的资源限制(CPU、内存等)
---
## 10. 监控与维护
### 10.1 系统监控
- **应用监控**: 监控应用的运行状态、CPU、内存使用情况
- **数据库监控**: 监控数据库的连接数、查询性能、存储空间
- **API监控**: 监控 API 的响应时间、调用次数、错误率
- **日志监控**: 监控系统日志,及时发现异常情况
### 10.2 故障处理
- **故障定位**: 通过日志和监控工具定位故障原因
- **故障恢复**: 制定故障恢复方案,确保系统快速恢复
- **故障预防**: 定期进行系统检查,预防故障发生
### 10.3 系统维护
- **定期更新**: 定期更新依赖库和框架版本,修复安全漏洞
- **数据备份**: 定期备份数据库,防止数据丢失
- **性能调优**: 定期分析系统性能,进行性能调优
- **文档更新**: 及时更新系统文档,保持文档与系统同步
---
## 11. 开发规范
### 11.1 代码规范
- **代码风格**: 遵循 PEP 8 规范
- **命名规范**:
- 类名: 大驼峰命名法 (PascalCase)
- 函数名: 小驼峰命名法 (camelCase)
- 变量名: 小写下划线分隔 (snake_case)
- 常量名: 全大写下划线分隔 (SNAKE_CASE)
- **注释规范**: 为所有公共函数和类添加文档字符串
- **导入规范**: 分组导入,按标准库、第三方库、本地模块顺序
### 11.2 版本控制
- **分支管理**: 使用 Git Flow 分支管理策略
- **提交规范**: 提交信息使用英文,格式为 `[类型]: 描述`
- **版本号**: 使用语义化版本号 (Semantic Versioning)
### 11.3 测试规范
- **测试覆盖率**: 核心功能测试覆盖率不低于 80%
- **测试类型**: 单元测试、集成测试、端到端测试
- **测试框架**: 使用 Pytest 进行测试
---
## 12. 附录
### 12.1 技术选型对比
| 技术 | 对比方案 | 最终选择理由 |
|------|----------|--------------|
| 后端框架 | FastAPI vs Flask vs Django | FastAPI 高性能,自动生成API文档,支持异步 |
| ORM框架 | SQLAlchemy vs Django ORM | SQLAlchemy 灵活强大,支持多种数据库 |
| 数据库 | MySQL vs PostgreSQL | MySQL 社区活跃,生态成熟,适合企业级应用 |
| 认证 | JWT vs Session | JWT 无状态,便于水平扩展 |
| 构建工具 | Poetry vs pip | Poetry 提供更好的依赖管理和版本控制 |
### 12.2 常用命令
- **安装依赖**: `poetry install``pip install -r requirements.txt`
- **添加依赖**: `poetry add <package>``pip install <package>`
- **启动开发服务器**: `uvicorn app.main:app --reload`
- **运行测试**: `pytest`
- **生成数据库迁移**: `alembic revision --autogenerate -m "描述"`
- **执行数据库迁移**: `alembic upgrade head`
### 12.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
+789
View File
@@ -0,0 +1,789 @@
# 后端数据库迁移文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 后端数据库迁移文档
---
## 1. 数据库迁移概述
### 1.1 什么是数据库迁移
数据库迁移是一种管理数据库模式变更的方法,它允许您:
- 版本化数据库模式
- 跟踪数据库变更历史
- 在不同环境之间一致地应用数据库变更
- 回滚错误的数据库变更
- 协作开发数据库模式
### 1.2 为什么使用数据库迁移
- **可追溯性**: 记录所有数据库变更的历史
- **一致性**: 在开发、测试和生产环境中应用相同的变更
- **安全性**: 提供回滚机制,防止错误变更导致的数据丢失
- **协作**: 团队成员可以共享和审查数据库变更
- **自动化**: 简化数据库部署流程
---
## 2. 迁移工具
### 2.1 Alembic
本项目使用 **Alembic** 作为数据库迁移工具。Alembic 是 SQLAlchemy 的官方数据库迁移工具,提供了以下功能:
- 自动生成迁移脚本
- 管理迁移版本
- 应用和回滚迁移
- 支持多种数据库
- 与 SQLAlchemy 无缝集成
### 2.2 安装 Alembic
Alembic 已经在项目依赖中包含,使用以下命令安装:
```bash
# 使用 Poetry
poetry install
# 使用 pip
pip install -r requirements.txt
```
---
## 3. 迁移配置
### 3.1 初始化 Alembic
如果项目还没有初始化 Alembic,使用以下命令:
```bash
# 在项目根目录执行
alembic init alembic
```
### 3.2 配置文件
Alembic 的主要配置文件是 `alembic.ini`,位于项目根目录:
```ini
# alembic.ini
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = alembic
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library
# timezone =
# max length of characters to apply to the
# "slug" field
# truncate_slug_length = 40
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false
# version location specification; This defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator" below.
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
# version path separator; As mentioned above, this is the character used to split
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
# Valid values for version_path_separator are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
version_path_separator = os # Use os.pathsep.
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = mysql+pymysql://username:password@localhost:3306/project_management
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples
# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
```
### 3.3 环境配置
Alembic 的环境配置文件是 `alembic/env.py`,用于配置数据库连接和迁移行为:
```python
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
import os
import sys
from pathlib import Path
# 将项目根目录添加到 Python 路径
sys.path.append(str(Path(__file__).parent.parent))
# 导入模型和配置
from app.config import settings
from app.database.base import Base
from app.models import * # 导入所有模型
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# 使用环境变量中的数据库 URL
config.set_main_option('sqlalchemy.url', settings.database_url)
# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
```
### 3.4 脚本模板
Alembic 使用 `script.py.mako` 作为迁移脚本的模板,位于 `alembic` 目录:
```mako
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade() -> None:
${upgrades if upgrades else "pass"}
def downgrade() -> None:
${downgrades if downgrades else "pass"}
```
---
## 4. 迁移操作
### 4.1 生成迁移脚本
#### 自动生成迁移脚本
当您修改了模型定义后,使用以下命令自动生成迁移脚本:
```bash
# 在项目根目录执行
alembic revision --autogenerate -m "描述迁移内容"
# 示例
alembic revision --autogenerate -m "创建用户表"
```
#### 手动创建迁移脚本
如果需要手动创建迁移脚本,使用以下命令:
```bash
# 在项目根目录执行
alembic revision -m "描述迁移内容"
# 示例
alembic revision -m "添加用户状态字段"
```
然后编辑生成的迁移脚本,添加具体的迁移操作。
### 4.2 应用迁移
#### 应用所有迁移
使用以下命令将所有未应用的迁移应用到数据库:
```bash
# 在项目根目录执行
alembic upgrade head
```
#### 应用特定迁移
使用以下命令将迁移应用到特定版本:
```bash
# 在项目根目录执行
alembic upgrade <revision_id>
# 示例
alembic upgrade 1234abcd
```
### 4.3 回滚迁移
#### 回滚到上一个版本
使用以下命令回滚到上一个迁移版本:
```bash
# 在项目根目录执行
alembic downgrade -1
```
#### 回滚到特定版本
使用以下命令回滚到特定迁移版本:
```bash
# 在项目根目录执行
alembic downgrade <revision_id>
# 示例
alembic downgrade 1234abcd
```
#### 回滚到初始状态
使用以下命令回滚到初始状态:
```bash
# 在项目根目录执行
alembic downgrade base
```
### 4.4 查看迁移状态
使用以下命令查看当前的迁移状态:
```bash
# 在项目根目录执行
alembic current
```
使用以下命令查看所有迁移版本:
```bash
# 在项目根目录执行
alembic history
# 显示更详细的信息
alembic history --verbose
# 显示图形化的迁移树
alembic history --graph
```
---
## 5. 迁移最佳实践
### 5.1 迁移脚本管理
1. **清晰的迁移消息**: 使用描述性的迁移消息,说明迁移的目的
2. **版本控制**: 将迁移脚本纳入版本控制
3. **测试迁移**: 在应用到生产环境之前,在测试环境中测试迁移
4. **备份数据**: 在应用迁移之前,备份数据库
5. **逐步迁移**: 对于大型迁移,考虑分步骤进行
### 5.2 迁移脚本编写
1. **保持迁移脚本简单**: 每个迁移脚本只包含一个逻辑变更
2. **处理默认值**: 为新添加的列提供合理的默认值
3. **处理数据迁移**: 如果需要迁移数据,在迁移脚本中添加相应的代码
4. **处理约束**: 注意外键约束和唯一约束的处理
5. **编写回滚脚本**: 确保每个迁移都有对应的回滚操作
### 5.3 常见迁移操作
#### 添加表
```python
def upgrade() -> None:
op.create_table(
'users',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=50), nullable=False),
sa.Column('password', sa.String(length=128), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('username')
)
def downgrade() -> None:
op.drop_table('users')
```
#### 添加列
```python
def upgrade() -> None:
op.add_column(
'users',
sa.Column('email', sa.String(length=100), nullable=True)
)
def downgrade() -> None:
op.drop_column('users', 'email')
```
#### 修改列
```python
def upgrade() -> None:
op.alter_column(
'users',
'email',
existing_type=sa.String(length=100),
nullable=False
)
def downgrade() -> None:
op.alter_column(
'users',
'email',
existing_type=sa.String(length=100),
nullable=True
)
```
#### 添加索引
```python
def upgrade() -> None:
op.create_index(
op.f('ix_users_email'),
'users',
['email'],
unique=True
)
def downgrade() -> None:
op.drop_index(op.f('ix_users_email'), table_name='users')
```
---
## 6. 数据库初始化
### 6.1 初始迁移
当创建新项目时,需要执行初始迁移:
1. **创建模型**: 定义所有数据库模型
2. **生成初始迁移**: `alembic revision --autogenerate -m "初始迁移"`
3. **应用初始迁移**: `alembic upgrade head`
### 6.2 数据种子
在应用初始迁移后,可能需要添加一些初始数据,例如管理员用户:
```python
# 在 app/database/seed.py 中
from sqlalchemy.orm import Session
from app.models.user import User
from app.database.session import get_db
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def seed_data(db: Session) -> None:
"""添加初始数据"""
# 检查是否已有管理员用户
admin_user = db.query(User).filter(User.username == "admin").first()
if not admin_user:
# 创建管理员用户
admin_user = User(
username="admin",
password=pwd_context.hash("123456"),
real_name="系统管理员",
department="ADMIN",
role="ADMIN",
status=1
)
db.add(admin_user)
# 检查是否已有市场部用户
marketing_user = db.query(User).filter(User.username == "marketing").first()
if not marketing_user:
# 创建市场部用户
marketing_user = User(
username="marketing",
password=pwd_context.hash("123456"),
real_name="市场部经理",
department="MARKETING",
role="MARKETING",
status=1
)
db.add(marketing_user)
# 检查是否已有其他部门用户
other_user = db.query(User).filter(User.username == "other").first()
if not other_user:
# 创建其他部门用户
other_user = User(
username="other",
password=pwd_context.hash("123456"),
real_name="技术部经理",
department="TECHNOLOGY",
role="OTHER",
status=1
)
db.add(other_user)
db.commit()
if __name__ == "__main__":
db = next(get_db())
try:
seed_data(db)
print("数据种子添加成功")
finally:
db.close()
```
执行数据种子脚本:
```bash
# 在项目根目录执行
python -m app.database.seed
```
---
## 7. 迁移示例
### 7.1 示例 1: 创建用户表
**迁移脚本**: `alembic/versions/1234abcd_create_user_table.py`
```python
"""创建用户表
Revision ID: 1234abcd
Revises:
Create Date: 2025-01-01 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1234abcd'
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table('sys_user',
sa.Column('user_id', sa.String(length=32), nullable=False),
sa.Column('username', sa.String(length=50), nullable=False),
sa.Column('password', sa.String(length=128), nullable=False),
sa.Column('real_name', sa.String(length=50), nullable=False),
sa.Column('department', sa.String(length=50), nullable=False),
sa.Column('phone', sa.String(length=20), nullable=True),
sa.Column('email', sa.String(length=100), nullable=True),
sa.Column('role', sa.String(length=20), nullable=False),
sa.Column('status', sa.Integer(), nullable=False),
sa.Column('create_time', sa.DateTime(), nullable=False),
sa.Column('update_time', sa.DateTime(), nullable=False),
sa.Column('last_login_time', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('user_id'),
sa.UniqueConstraint('username')
)
op.create_index(op.f('ix_sys_user_department'), 'sys_user', ['department'], unique=False)
op.create_index(op.f('ix_sys_user_role'), 'sys_user', ['role'], unique=False)
op.create_index(op.f('ix_sys_user_status'), 'sys_user', ['status'], unique=False)
def downgrade() -> None:
op.drop_index(op.f('ix_sys_user_status'), table_name='sys_user')
op.drop_index(op.f('ix_sys_user_role'), table_name='sys_user')
op.drop_index(op.f('ix_sys_user_department'), table_name='sys_user')
op.drop_table('sys_user')
```
### 7.2 示例 2: 创建项目表
**迁移脚本**: `alembic/versions/5678efgh_create_project_table.py`
```python
"""创建项目表
Revision ID: 5678efgh
Revises: 1234abcd
Create Date: 2025-01-02 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5678efgh'
down_revision = '1234abcd'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table('project',
sa.Column('project_id', sa.String(length=32), nullable=False),
sa.Column('project_no', sa.String(length=20), nullable=False),
sa.Column('project_name', sa.String(length=200), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('create_time', sa.DateTime(), nullable=False),
sa.Column('creator', sa.String(length=50), nullable=False),
sa.Column('update_time', sa.DateTime(), nullable=False),
sa.Column('last_modifier', sa.String(length=50), nullable=True),
sa.Column('leader', sa.String(length=50), nullable=False),
sa.Column('phone', sa.String(length=20), nullable=True),
sa.Column('email', sa.String(length=100), nullable=True),
sa.Column('background', sa.Text(), nullable=True),
sa.Column('goal', sa.Text(), nullable=True),
sa.Column('scope', sa.Text(), nullable=True),
sa.Column('start_date', sa.Date(), nullable=False),
sa.Column('planned_end_date', sa.Date(), nullable=False),
sa.Column('actual_end_date', sa.Date(), nullable=True),
sa.Column('total_budget', sa.Numeric(precision=15, scale=2), nullable=False),
sa.Column('used_budget', sa.Numeric(precision=15, scale=2), nullable=False),
sa.Column('remaining_budget', sa.Numeric(precision=15, scale=2), nullable=False),
sa.Column('remarks', sa.Text(), nullable=True),
sa.PrimaryKeyConstraint('project_id'),
sa.UniqueConstraint('project_no')
)
op.create_index(op.f('ix_project_create_time'), 'project', ['create_time'], unique=False)
op.create_index(op.f('ix_project_creator'), 'project', ['creator'], unique=False)
op.create_index(op.f('ix_project_leader'), 'project', ['leader'], unique=False)
op.create_index(op.f('ix_project_status'), 'project', ['status'], unique=False)
op.create_index(op.f('ix_project_update_time'), 'project', ['update_time'], unique=False)
def downgrade() -> None:
op.drop_index(op.f('ix_project_update_time'), table_name='project')
op.drop_index(op.f('ix_project_status'), table_name='project')
op.drop_index(op.f('ix_project_leader'), table_name='project')
op.drop_index(op.f('ix_project_creator'), table_name='project')
op.drop_index(op.f('ix_project_create_time'), table_name='project')
op.drop_table('project')
```
---
## 8. 常见问题
### 8.1 迁移失败
**问题**:迁移应用失败,出现错误
**解决方法**
1. 查看错误信息,了解失败原因
2. 检查迁移脚本是否正确
3. 检查数据库连接是否正常
4. 如果需要,回滚到之前的版本并修复问题
### 8.2 自动生成的迁移脚本不正确
**问题**:Alembic 自动生成的迁移脚本与预期不符
**解决方法**
1. 检查模型定义是否正确
2. 手动编辑生成的迁移脚本
3. 确保所有模型都已导入到 `env.py`
### 8.3 数据库连接错误
**问题**:无法连接到数据库进行迁移
**解决方法**
1. 检查数据库服务是否运行
2. 检查数据库连接字符串是否正确
3. 检查数据库用户权限是否正确
### 8.4 迁移版本冲突
**问题**:多个开发者创建了相同版本号的迁移
**解决方法**
1. 使用唯一的迁移版本号
2. 在提交迁移脚本前检查版本冲突
3. 如果发生冲突,重新生成迁移脚本
---
## 9. 附录
### 9.1 常用命令汇总
| 命令 | 说明 | 示例 |
|------|------|------|
| `alembic init` | 初始化 Alembic | `alembic init alembic` |
| `alembic revision --autogenerate` | 自动生成迁移脚本 | `alembic revision --autogenerate -m "创建用户表"` |
| `alembic revision` | 手动创建迁移脚本 | `alembic revision -m "添加用户状态字段"` |
| `alembic upgrade head` | 应用所有迁移 | `alembic upgrade head` |
| `alembic upgrade <revision>` | 应用到特定版本 | `alembic upgrade 1234abcd` |
| `alembic downgrade -1` | 回滚到上一个版本 | `alembic downgrade -1` |
| `alembic downgrade <revision>` | 回滚到特定版本 | `alembic downgrade 1234abcd` |
| `alembic downgrade base` | 回滚到初始状态 | `alembic downgrade base` |
| `alembic current` | 查看当前版本 | `alembic current` |
| `alembic history` | 查看所有版本 | `alembic history` |
| `alembic history --verbose` | 查看详细版本信息 | `alembic history --verbose` |
| `alembic history --graph` | 查看迁移树 | `alembic history --graph` |
### 9.2 迁移最佳实践总结
1. **版本控制**: 将迁移脚本纳入版本控制
2. **测试**: 在应用到生产环境之前测试迁移
3. **备份**: 在应用迁移之前备份数据库
4. **简单**: 每个迁移只包含一个逻辑变更
5. **清晰**: 使用描述性的迁移消息
6. **完整**: 编写正确的升级和降级脚本
7. **协作**: 与团队成员协调迁移工作
8. **监控**: 监控迁移执行情况
### 9.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
BIN
View File
Binary file not shown.
+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<基本信息>
<项目编号>PRJ2025001</项目编号>
<项目名称>企业数字化转型系统</项目名称>
<项目状态>进行中</项目状态>
<创建日期>2025-01-15</创建日期>
<负责人>张三</负责人>
<联系电话>13800138000</联系电话>
<邮箱>zhangsan@example.com</邮箱>
</基本信息>
<项目描述>
<项目背景>为了提升企业运营效率,实现业务流程数字化管理</项目背景>
<项目目标>完成企业内部管理系统的全面数字化改造</项目目标>
<项目范围>包括人力资源、财务管理、供应链管理等模块</项目范围>
</项目描述>
<项目团队>
<成员>
<姓名>张三</姓名>
<角色>项目经理</角色>
<部门>市场部</部门>
</成员>
<成员>
<姓名>李四</姓名>
<角色>技术负责人</角色>
<部门>技术部</部门>
</成员>
<成员>
<姓名>王五</姓名>
<角色>设计师</角色>
<部门>设计部</部门>
</成员>
</项目团队>
<项目时间>
<开始日期>2025-01-15</开始日期>
<预计结束日期>2025-06-30</预计结束日期>
<实际结束日期></实际结束日期>
</项目时间>
<项目预算>
<总预算>500000</总预算>
<已使用>120000</已使用>
<剩余>380000</剩余>
</项目预算>
<项目里程碑>
<里程碑>
<名称>需求分析完成</名称>
<计划日期>2025-02-15</计划日期>
<实际日期>2025-02-10</实际日期>
<状态>已完成</状态>
</里程碑>
<里程碑>
<名称>系统设计完成</名称>
<计划日期>2025-03-15</计划日期>
<实际日期></实际日期>
<状态>进行中</状态>
</里程碑>
<里程碑>
<名称>开发完成</名称>
<计划日期>2025-05-30</计划日期>
<实际日期></实际日期>
<状态>未开始</状态>
</里程碑>
</项目里程碑>
<项目风险>
<风险>
<描述>技术难度较高,可能影响进度</描述>
<等级></等级>
<应对措施>增加技术团队人员投入</应对措施>
</风险>
</项目风险>
<项目备注>
项目需要与现有系统进行数据对接,需要提前做好接口设计
</项目备注>
</project>
+482
View File
@@ -0,0 +1,482 @@
# 项目管理系统产品需求文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 产品需求文档 (PRD)
---
## 1. 产品概述
### 1.1 产品简介
项目管理系统是一个基于BS架构的企业级项目管理平台,旨在帮助企业实现项目全生命周期的数字化管理,包括项目创建、编辑、跟踪、统计等功能。
### 1.2 产品目标
- 规范项目管理流程,提高项目执行效率
- 实现项目信息的集中管理和共享
- 提供完善的项目修改历史记录,便于追溯
- 支持多维度项目筛选和统计分析
### 1.3 目标用户
- 管理员:系统最高权限用户,负责用户管理和系统维护
- 市场部人员:负责项目创建和项目信息维护
- 其他部门人员:负责项目内容的修改和更新
---
## 2. 用户角色与权限
### 2.1 角色定义
#### 2.1.1 管理员
**权限范围:**
- 用户管理:创建、编辑、删除用户
- 权限管理:分配用户角色和权限
- 密码管理:重置用户密码
- 项目管理:查看、编辑所有项目
- 统计分析:查看所有项目统计报表
- 系统配置:管理系统基础配置
#### 2.1.2 市场部人员
**权限范围:**
- 项目创建:创建新项目
- 项目编辑:编辑项目信息
- 项目查看:查看所有项目
- 历史记录:查看项目修改历史
#### 2.1.3 其他部门人员
**权限范围:**
- 项目编辑:编辑项目内容
- 项目查看:查看所有项目
- 历史记录:查看项目修改历史
### 2.2 权限矩阵
| 功能模块 | 管理员 | 市场部 | 其他部门 |
|---------|--------|--------|----------|
| 用户管理 | ✓ | ✗ | ✗ |
| 权限管理 | ✓ | ✗ | ✗ |
| 密码管理 | ✓ | ✗ | ✗ |
| 项目创建 | ✓ | ✓ | ✗ |
| 项目编辑 | ✓ | ✓ | ✓ |
| 项目查看 | ✓ | ✓ | ✓ |
| 历史记录查看 | ✓ | ✓ | ✓ |
| 项目统计 | ✓ | ✗ | ✗ |
| 系统配置 | ✓ | ✗ | ✗ |
---
## 3. 功能需求
### 3.1 用户管理模块
#### 3.1.1 用户创建
**功能描述:** 管理员可以创建新用户账号
**输入信息:**
- 用户名(必填,唯一)
- 密码(必填,需满足安全策略)
- 真实姓名(必填)
- 部门(必填,可选:市场部、技术部、设计部、财务部等)
- 联系电话(选填)
- 邮箱(选填,需格式验证)
- 角色(必填:管理员、市场部、其他部门)
**业务规则:**
- 用户名必须唯一,不能重复
- 密码长度不少于8位,包含字母和数字
- 邮箱格式必须正确
- 创建成功后自动分配初始权限
#### 3.1.2 用户编辑
**功能描述:** 管理员可以编辑用户基本信息
**可编辑字段:**
- 真实姓名
- 部门
- 联系电话
- 邮箱
- 角色
**业务规则:**
- 用户名不可修改
- 修改角色会自动更新权限
- 修改部门会影响项目创建权限
#### 3.1.3 密码管理
**功能描述:** 管理员可以重置用户密码
**操作方式:**
- 选择用户
- 生成新随机密码或手动设置密码
- 通知用户新密码
**业务规则:**
- 新密码需满足安全策略
- 密码重置后建议用户首次登录修改密码
#### 3.1.4 用户列表
**功能描述:** 展示所有用户信息
**显示字段:**
- 用户名
- 真实姓名
- 部门
- 角色
- 创建时间
- 最后登录时间
- 状态(正常/禁用)
**支持操作:**
- 编辑用户
- 重置密码
- 禁用/启用用户
- 删除用户
### 3.2 项目管理模块
#### 3.2.1 项目创建
**功能描述:** 市场部人员可以创建新项目
**创建条件:**
- 用户角色为市场部或管理员
**项目信息结构:**
**基本信息**
- 项目编号(自动生成)
- 项目名称
- 项目状态(未开始、进行中、已完成、已暂停、已取消)
- 创建日期(自动生成)
- 负责人
- 联系电话
- 邮箱
**项目描述**
- 项目背景
- 项目目标
- 项目范围
**项目团队**
- 成员列表(姓名、角色、部门)
**项目时间**
- 开始日期
- 预计结束日期
- 实际结束日期
**项目预算**
- 总预算
- 已使用
- 剩余
**项目里程碑**
- 里程碑列表(名称、计划日期、实际日期、状态)
**项目风险**
- 风险列表(描述、等级、应对措施)
**项目备注**
- 备注内容
**业务规则:**
- 项目编号自动生成,格式:PRJ + 年份 + 序号(如:PRJ2025001
- 项目状态默认为"未开始"
- 创建者自动记录为创建人
- 创建时间自动记录
#### 3.2.2 项目编辑
**功能描述:** 所有用户可以编辑项目信息
**编辑权限:**
- 管理员:可编辑所有项目
- 市场部:可编辑所有项目
- 其他部门:可编辑所有项目
**编辑内容:**
- 可编辑项目的所有字段
- 编辑后自动记录修改历史
**业务规则:**
- 项目编号不可修改
- 创建日期不可修改
- 创建人不可修改
- 每次修改都记录修改历史
#### 3.2.3 项目查看
**功能描述:** 所有用户可以查看项目详情
**查看内容:**
- 项目完整信息
- 项目修改历史记录
**业务规则:**
- 所有用户都可以查看所有项目
- 项目修改历史按时间倒序显示
#### 3.2.4 项目列表
**功能描述:** 展示所有项目列表
**显示字段:**
- 项目编号
- 项目名称
- 项目状态
- 负责人
- 创建日期
- 最后修改时间
**支持操作:**
- 查看项目详情
- 编辑项目
- 查看修改历史
### 3.3 项目历史记录模块
#### 3.3.1 历史记录记录
**功能描述:** 自动记录项目修改历史
**记录内容:**
- 修改时间
- 修改人
- 修改字段
- 修改前值
- 修改后值
- 修改类型(创建、更新、删除)
**记录时机:**
- 项目创建时
- 项目信息修改时
- 项目状态变更时
**业务规则:**
- 历史记录不可删除
- 历史记录不可修改
- 历史记录永久保存
#### 3.3.2 历史记录查看
**功能描述:** 查看项目修改历史
**显示内容:**
- 修改时间
- 修改人
- 修改详情
- 修改前后的值对比
**显示方式:**
- 按时间倒序排列
- 支持按修改人筛选
- 支持按时间范围筛选
### 3.4 项目统计模块
#### 3.4.1 项目筛选
**功能描述:** 管理员可以通过多种条件筛选项目
**筛选条件:**
- 项目编号
- 项目名称(模糊查询)
- 项目状态
- 负责人
- 创建日期范围
- 修改日期范围
- 部门
- 项目状态
**业务规则:**
- 支持多条件组合筛选
- 筛选结果可导出
- 筛选条件可保存
#### 3.4.2 项目统计
**功能描述:** 管理员可以查看项目统计数据
**统计维度:**
- 按项目状态统计
- 按部门统计
- 按负责人统计
- 按创建时间统计
- 按项目预算统计
**统计指标:**
- 项目总数
- 各状态项目数量
- 项目完成率
- 项目平均周期
- 预算使用率
**展示方式:**
- 数据表格
- 柱状图
- 饼图
- 折线图
**业务规则:**
- 统计数据实时更新
- 支持时间范围选择
- 支持统计结果导出
---
## 4. 项目数据结构
### 4.1 用户数据结构
```json
{
"userId": "用户ID",
"username": "用户名",
"password": "密码(加密)",
"realName": "真实姓名",
"department": "部门",
"phone": "联系电话",
"email": "邮箱",
"role": "角色",
"status": "状态",
"createTime": "创建时间",
"lastLoginTime": "最后登录时间"
}
```
### 4.2 项目数据结构
```json
{
"projectId": "项目ID",
"projectNo": "项目编号",
"projectName": "项目名称",
"status": "项目状态",
"createTime": "创建时间",
"creator": "创建人",
"basicInfo": {
"leader": "负责人",
"phone": "联系电话",
"email": "邮箱"
},
"description": {
"background": "项目背景",
"goal": "项目目标",
"scope": "项目范围"
},
"team": [
{
"name": "姓名",
"role": "角色",
"department": "部门"
}
],
"timeInfo": {
"startDate": "开始日期",
"plannedEndDate": "预计结束日期",
"actualEndDate": "实际结束日期"
},
"budget": {
"total": "总预算",
"used": "已使用",
"remaining": "剩余"
},
"milestones": [
{
"name": "名称",
"plannedDate": "计划日期",
"actualDate": "实际日期",
"status": "状态"
}
],
"risks": [
{
"description": "描述",
"level": "等级",
"measure": "应对措施"
}
],
"remarks": "备注",
"updateTime": "最后修改时间",
"lastModifier": "最后修改人"
}
```
### 4.3 项目历史记录数据结构
```json
{
"historyId": "历史记录ID",
"projectId": "项目ID",
"projectNo": "项目编号",
"operationType": "操作类型",
"operator": "操作人",
"operationTime": "操作时间",
"changes": [
{
"field": "字段名",
"oldValue": "修改前值",
"newValue": "修改后值"
}
]
}
```
---
## 5. 系统架构
### 5.1 技术架构
- **架构模式**: BS架构(Browser/Server
- **前端技术**: 待定
- **后端技术**: 待定
- **数据库**: 待定
### 5.2 部署架构
- **前端**: Web浏览器访问
- **后端**: 应用服务器部署
- **数据库**: 数据库服务器部署
### 5.3 安全架构
- 用户认证:用户名密码登录
- 权限控制:基于角色的访问控制(RBAC)
- 数据加密:敏感数据加密存储
- 操作审计:记录用户操作日志
---
## 6. 非功能性需求
### 6.1 性能要求
- 系统响应时间:页面加载时间 < 3秒
- 并发用户数:支持至少100个并发用户
- 数据查询:复杂查询响应时间 < 5秒
### 6.2 可用性要求
- 系统可用性:99.5%
- 系统恢复时间:故障恢复时间 < 1小时
### 6.3 安全性要求
- 密码加密:使用安全的加密算法
- 会话管理:会话超时时间30分钟
- 数据备份:每日自动备份数据
- 权限控制:严格的权限验证机制
### 6.4 可扩展性要求
- 支持模块化扩展
- 支持新增用户角色
- 支持自定义项目字段
### 6.5 易用性要求
- 界面简洁直观
- 操作流程清晰
- 提供操作提示
- 支持快捷键操作
---
## 7. 附录
### 7.1 术语表
- **BS架构**: Browser/Server架构,浏览器/服务器架构
- **RBAC**: Role-Based Access Control,基于角色的访问控制
- **PRD**: Product Requirements Document,产品需求文档
### 7.2 参考资料
- 项目示例文件:docs/example.xsl
### 7.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
+533
View File
@@ -0,0 +1,533 @@
# 项目管理系统功能规格说明书
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 功能规格说明书 (FSD)
---
## 1. 引言
### 1.1 文档目的
本文档详细描述项目管理系统的各项功能规格,为系统设计和开发提供详细的功能说明。
### 1.2 适用范围
本文档适用于项目管理系统开发团队,包括前端开发、后端开发、测试人员等。
### 1.3 参考文档
- 《项目管理系统产品需求文档》
---
## 2. 用户管理功能规格
### 2.1 用户登录功能
#### 2.1.1 功能描述
用户通过用户名和密码登录系统。
#### 2.1.2 输入参数
- 用户名:字符串,长度3-20字符
- 密码:字符串,长度8-20字符
#### 2.1.3 处理逻辑
1. 验证用户名和密码是否为空
2. 验证用户名是否存在
3. 验证密码是否正确
4. 验证用户状态是否正常
5. 登录成功后创建会话
6. 记录登录日志
#### 2.1.4 输出结果
- 登录成功:跳转到系统首页
- 登录失败:显示错误提示信息
#### 2.1.5 异常处理
- 用户名不存在:提示"用户名或密码错误"
- 密码错误:提示"用户名或密码错误"
- 用户被禁用:提示"账号已被禁用,请联系管理员"
- 系统异常:提示"系统异常,请稍后重试"
### 2.2 用户创建功能
#### 2.2.1 功能描述
管理员创建新用户账号。
#### 2.2.2 输入参数
- 用户名:字符串,长度3-20字符,必填
- 密码:字符串,长度8-20字符,必填
- 确认密码:字符串,必填
- 真实姓名:字符串,长度2-20字符,必填
- 部门:枚举值,必填
- 联系电话:字符串,选填
- 邮箱:字符串,选填
- 角色:枚举值,必填
#### 2.2.3 处理逻辑
1. 验证输入参数的完整性和格式
2. 验证用户名是否已存在
3. 验证密码和确认密码是否一致
4. 验证邮箱格式是否正确
5. 对密码进行加密处理
6. 生成用户ID
7. 保存用户信息到数据库
8. 记录操作日志
#### 2.2.4 输出结果
- 创建成功:提示"用户创建成功",清空表单
- 创建失败:显示错误提示信息
#### 2.2.5 异常处理
- 用户名已存在:提示"用户名已存在"
- 密码不一致:提示"两次输入的密码不一致"
- 邮箱格式错误:提示"邮箱格式不正确"
- 数据库异常:提示"系统异常,请稍后重试"
### 2.3 用户编辑功能
#### 2.3.1 功能描述
管理员编辑用户基本信息。
#### 2.3.2 输入参数
- 用户ID:字符串,必填
- 真实姓名:字符串,必填
- 部门:枚举值,必填
- 联系电话:字符串,选填
- 邮箱:字符串,选填
- 角色:枚举值,必填
#### 2.3.3 处理逻辑
1. 验证输入参数的完整性和格式
2. 验证用户ID是否存在
3. 验证邮箱格式是否正确
4. 更新用户信息到数据库
5. 如果角色发生变化,更新用户权限
6. 记录操作日志
#### 2.3.4 输出结果
- 编辑成功:提示"用户信息更新成功"
- 编辑失败:显示错误提示信息
#### 2.3.5 异常处理
- 用户不存在:提示"用户不存在"
- 邮箱格式错误:提示"邮箱格式不正确"
- 数据库异常:提示"系统异常,请稍后重试"
### 2.4 密码重置功能
#### 2.4.1 功能描述
管理员重置用户密码。
#### 2.4.2 输入参数
- 用户ID:字符串,必填
- 新密码:字符串,长度8-20字符,必填
- 确认密码:字符串,必填
#### 2.4.3 处理逻辑
1. 验证输入参数的完整性
2. 验证用户ID是否存在
3. 验证新密码和确认密码是否一致
4. 对新密码进行加密处理
5. 更新用户密码到数据库
6. 记录操作日志
#### 2.4.4 输出结果
- 重置成功:提示"密码重置成功"
- 重置失败:显示错误提示信息
#### 2.4.5 异常处理
- 用户不存在:提示"用户不存在"
- 密码不一致:提示"两次输入的密码不一致"
- 数据库异常:提示"系统异常,请稍后重试"
### 2.5 用户列表功能
#### 2.5.1 功能描述
展示所有用户列表。
#### 2.5.2 输入参数
- 页码:整数,默认1
- 每页数量:整数,默认10
- 搜索关键词:字符串,选填
#### 2.5.3 处理逻辑
1. 验证分页参数
2. 根据搜索关键词查询用户列表
3. 计算总记录数和总页数
4. 返回用户列表数据
#### 2.5.4 输出结果
- 用户列表数据
- 分页信息
#### 2.5.5 异常处理
- 参数错误:提示"参数错误"
- 数据库异常:提示"系统异常,请稍后重试"
---
## 3. 项目管理功能规格
### 3.1 项目创建功能
#### 3.1.1 功能描述
市场部人员创建新项目。
#### 3.1.2 输入参数
**基本信息**
- 项目名称:字符串,长度2-100字符,必填
- 项目状态:枚举值,默认"未开始"
- 负责人:字符串,必填
- 联系电话:字符串,选填
- 邮箱:字符串,选填
**项目描述**
- 项目背景:字符串,选填
- 项目目标:字符串,选填
- 项目范围:字符串,选填
**项目团队**
- 成员列表:数组,每个成员包含姓名、角色、部门
**项目时间**
- 开始日期:日期,必填
- 预计结束日期:日期,必填
- 实际结束日期:日期,选填
**项目预算**
- 总预算:数字,必填
- 已使用:数字,默认0
- 剩余:数字,自动计算
**项目里程碑**
- 里程碑列表:数组,每个里程碑包含名称、计划日期、实际日期、状态
**项目风险**
- 风险列表:数组,每个风险包含描述、等级、应对措施
**项目备注**
- 备注:字符串,选填
#### 3.1.3 处理逻辑
1. 验证用户是否有创建项目权限
2. 验证必填参数是否完整
3. 验证日期格式是否正确
4. 验证预算数据是否合法
5. 生成项目编号
6. 生成项目ID
7. 计算剩余预算
8. 保存项目信息到数据库
9. 创建项目创建历史记录
10. 记录操作日志
#### 3.1.4 输出结果
- 创建成功:提示"项目创建成功",跳转到项目列表
- 创建失败:显示错误提示信息
#### 3.1.5 异常处理
- 无权限:提示"您没有创建项目的权限"
- 参数错误:提示"请填写必填项"
- 日期错误:提示"日期格式不正确"
- 数据库异常:提示"系统异常,请稍后重试"
### 3.2 项目编辑功能
#### 3.2.1 功能描述
用户编辑项目信息。
#### 3.2.2 输入参数
- 项目ID:字符串,必填
- 项目信息:项目完整信息(同创建参数)
#### 3.2.3 处理逻辑
1. 验证用户是否有编辑项目权限
2. 验证项目ID是否存在
3. 获取项目当前信息
4. 对比修改前后的数据
5. 验证必填参数是否完整
6. 验证日期格式是否正确
7. 验证预算数据是否合法
8. 更新项目信息到数据库
9. 记录修改历史(只记录有变化的字段)
10. 更新最后修改时间和修改人
11. 记录操作日志
#### 3.2.4 输出结果
- 编辑成功:提示"项目信息更新成功"
- 编辑失败:显示错误提示信息
#### 3.2.5 异常处理
- 项目不存在:提示"项目不存在"
- 参数错误:提示"请填写必填项"
- 日期错误:提示"日期格式不正确"
- 数据库异常:提示"系统异常,请稍后重试"
### 3.3 项目查看功能
#### 3.3.1 功能描述
用户查看项目详情。
#### 3.3.2 输入参数
- 项目ID:字符串,必填
#### 3.3.3 处理逻辑
1. 验证项目ID是否存在
2. 查询项目详细信息
3. 查询项目修改历史记录
4. 返回项目详情和历史记录
#### 3.3.4 输出结果
- 项目详细信息
- 项目修改历史记录
#### 3.3.5 异常处理
- 项目不存在:提示"项目不存在"
- 数据库异常:提示"系统异常,请稍后重试"
### 3.4 项目列表功能
#### 3.4.1 功能描述
展示所有项目列表。
#### 3.4.2 输入参数
- 页码:整数,默认1
- 每页数量:整数,默认10
- 搜索关键词:字符串,选填
- 项目状态:枚举值,选填
- 负责人:字符串,选填
#### 3.4.3 处理逻辑
1. 验证分页参数
2. 根据筛选条件查询项目列表
3. 计算总记录数和总页数
4. 返回项目列表数据
#### 3.4.4 输出结果
- 项目列表数据
- 分页信息
#### 3.4.5 异常处理
- 参数错误:提示"参数错误"
- 数据库异常:提示"系统异常,请稍后重试"
---
## 4. 项目历史记录功能规格
### 4.1 历史记录记录功能
#### 4.1.1 功能描述
自动记录项目修改历史。
#### 4.1.2 输入参数
- 项目ID:字符串,必填
- 操作类型:枚举值,必填
- 操作人:字符串,必填
- 修改数据:对象,必填
#### 4.1.3 处理逻辑
1. 生成历史记录ID
2. 记录操作时间
3. 对比修改前后的数据
4. 提取变化的字段
5. 保存历史记录到数据库
#### 4.1.4 输出结果
- 记录成功:无返回
- 记录失败:记录错误日志
#### 4.1.5 异常处理
- 数据库异常:记录错误日志,不影响主流程
### 4.2 历史记录查看功能
#### 4.2.1 功能描述
查看项目修改历史。
#### 4.2.2 输入参数
- 项目ID:字符串,必填
- 页码:整数,默认1
- 每页数量:整数,默认10
- 修改人:字符串,选填
- 开始时间:日期,选填
- 结束时间:日期,选填
#### 4.2.3 处理逻辑
1. 验证项目ID是否存在
2. 根据筛选条件查询历史记录
3. 按时间倒序排列
4. 计算总记录数和总页数
5. 返回历史记录数据
#### 4.2.4 输出结果
- 历史记录列表
- 分页信息
#### 4.2.5 异常处理
- 项目不存在:提示"项目不存在"
- 参数错误:提示"参数错误"
- 数据库异常:提示"系统异常,请稍后重试"
---
## 5. 项目统计功能规格
### 5.1 项目筛选功能
#### 5.1.1 功能描述
管理员通过多种条件筛选项目。
#### 5.1.2 输入参数
- 项目编号:字符串,选填
- 项目名称:字符串,选填
- 项目状态:枚举值,选填
- 负责人:字符串,选填
- 创建开始日期:日期,选填
- 创建结束日期:日期,选填
- 修改开始日期:日期,选填
- 修改结束日期:日期,选填
- 部门:字符串,选填
#### 5.1.3 处理逻辑
1. 验证用户是否有筛选权限
2. 验证日期格式是否正确
3. 构建查询条件
4. 执行查询
5. 返回筛选结果
#### 5.1.4 输出结果
- 筛选后的项目列表
#### 5.1.5 异常处理
- 无权限:提示"您没有筛选项目的权限"
- 参数错误:提示"参数错误"
- 数据库异常:提示"系统异常,请稍后重试"
### 5.2 项目统计功能
#### 5.2.1 功能描述
管理员查看项目统计数据。
#### 5.2.2 输入参数
- 统计维度:枚举值,必填
- 时间范围:开始日期、结束日期,选填
#### 5.2.3 处理逻辑
1. 验证用户是否有统计权限
2. 根据统计维度查询数据
3. 根据时间范围过滤数据
4. 计算统计指标
5. 返回统计结果
#### 5.2.4 输出结果
- 统计数据
- 统计图表数据
#### 5.2.5 异常处理
- 无权限:提示"您没有查看统计的权限"
- 参数错误:提示"参数错误"
- 数据库异常:提示"系统异常,请稍后重试"
---
## 6. 数据验证规则
### 6.1 用户数据验证
- 用户名:3-20字符,只能包含字母、数字、下划线
- 密码:8-20字符,必须包含字母和数字
- 真实姓名:2-20字符
- 邮箱:标准邮箱格式
- 联系电话:11位数字
### 6.2 项目数据验证
- 项目名称:2-100字符
- 项目编号:自动生成,格式PRJ+年份+序号
- 项目状态:枚举值(未开始、进行中、已完成、已暂停、已取消)
- 预算:非负数
- 日期:YYYY-MM-DD格式
---
## 7. 业务流程图
### 7.1 用户创建流程
1. 管理员登录系统
2. 进入用户管理页面
3. 点击"创建用户"按钮
4. 填写用户信息
5. 提交表单
6. 系统验证数据
7. 保存用户信息
8. 提示创建成功
### 7.2 项目创建流程
1. 市场部人员登录系统
2. 进入项目管理页面
3. 点击"创建项目"按钮
4. 填写项目信息
5. 提交表单
6. 系统验证数据
7. 生成项目编号
8. 保存项目信息
9. 记录创建历史
10. 提示创建成功
### 7.3 项目编辑流程
1. 用户登录系统
2. 进入项目列表页面
3. 选择要编辑的项目
4. 点击"编辑"按钮
5. 修改项目信息
6. 提交表单
7. 系统验证数据
8. 对比修改前后的数据
9. 更新项目信息
10. 记录修改历史
11. 提示更新成功
---
## 8. 附录
### 8.1 枚举值定义
#### 用户角色
- ADMIN:管理员
- MARKETING:市场部
- OTHER:其他部门
#### 项目状态
- NOT_STARTED:未开始
- IN_PROGRESS:进行中
- COMPLETED:已完成
- PAUSED:已暂停
- CANCELLED:已取消
#### 操作类型
- CREATE:创建
- UPDATE:更新
- DELETE:删除
#### 部门
- MARKETING:市场部
- TECHNOLOGY:技术部
- DESIGN:设计部
- FINANCE:财务部
- HR:人力资源部
### 8.2 错误码定义
- 1001:用户名或密码错误
- 1002:用户不存在
- 1003:用户名已存在
- 1004:密码不一致
- 2001:项目不存在
- 2002:无权限操作
- 3001:参数错误
- 9999:系统异常
### 8.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
+634
View File
@@ -0,0 +1,634 @@
# 项目管理系统技术架构文档
## 文档信息
- **文档版本**: V2.0
- **创建日期**: 2026-01-26
- **文档类型**: 技术架构文档
---
## 1. 技术架构概述
### 1.1 架构风格
本项目采用BSBrowser/Server)架构,即浏览器/服务器架构。前端通过浏览器访问系统,后端通过服务器提供服务,数据存储在数据库中。由于系统并发量较小,采用直接操作数据库的方式,无需引入缓存层。
### 1.2 技术选型
| 分类 | 技术 | 版本 | 选型理由 |
|------|------|------|----------|
| 前端框架 | Vue 3 | 3.3.0+ | 轻量级、响应式、组件化开发,适合构建现代化Web应用 |
| 状态管理 | Pinia | 2.1.0+ | Vue 3官方推荐的状态管理库,比Vuex更轻量、更易用 |
| UI组件库 | Element Plus | 2.4.0+ | 基于Vue 3的企业级UI组件库,组件丰富,文档完善 |
| 前端路由 | Vue Router | 4.2.0+ | Vue官方路由库,支持嵌套路由、动态路由等 |
| 网络请求 | Axios | 1.6.0+ | 轻量级HTTP客户端,支持拦截器、取消请求等特性 |
| 后端框架 | FastAPI | 0.104.0+ | 高性能Python Web框架,自动生成API文档,支持异步 |
| ORM框架 | SQLAlchemy | 2.0.0+ | Python最流行的ORM框架,支持多种数据库 |
| 数据库驱动 | PyMySQL | 1.1.0+ | 纯Python实现的MySQL客户端 |
| 数据库 | MySQL | 8.0+ | 关系型数据库,稳定可靠,适合企业级应用 |
| 认证 | JWT | 2.8.0+ | JSON Web Token,用于用户认证和授权 |
| 密码加密 | Passlib | 1.7.4+ | 密码哈希库,支持多种加密算法 |
| 数据验证 | Pydantic | 2.5.0+ | 数据验证和设置库,与FastAPI完美集成 |
| API文档 | Swagger | - | FastAPI自动生成,提供交互式API文档 |
| 构建工具 | Poetry | 1.7.0+ | Python依赖管理和打包工具 |
| 版本控制 | Git | 2.40.0+ | 分布式版本控制系统,便于团队协作开发 |
---
## 2. 系统架构设计
### 2.1 架构分层
```
┌─────────────────────────────────────────────────────────────────┐
│ 前端层 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 视图层 │ │ 业务逻辑层 │ │ 数据层 │ │
│ │ (Vue组件) │ │ (Pinia Store) │ │ (Axios) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ API网关 │
├─────────────────────────────────────────────────────────────────┤
│ 后端层 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 路由层 │ │ 服务层 │ │ 数据访问层 │ │
│ │ (Router) │ │ (Service) │ │ (Model) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ 数据层 │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ MySQL数据库 │ │ 文件存储 │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### 2.2 核心流程图
#### 2.2.1 用户登录流程
```mermaid
sequenceDiagram
participant 前端 as 浏览器
participant 后端 as FastAPI服务
participant 数据库 as MySQL
前端->>后端: POST /api/auth/login (username, password)
后端->>数据库: 查询用户信息
alt 用户存在且密码正确
数据库-->>后端: 返回用户信息
后端->>后端: 生成JWT Token
后端-->>前端: 200 OK { "token": "...", "userInfo": {...} }
else 用户不存在或密码错误
数据库-->>后端: 返回空
后端-->>前端: 401 Unauthorized { "message": "用户名或密码错误" }
end
```
#### 2.2.2 项目创建流程
```mermaid
sequenceDiagram
participant 前端 as 浏览器
participant 后端 as FastAPI服务
participant 数据库 as MySQL
前端->>后端: POST /api/project (项目信息)
后端->>后端: 验证用户权限
alt 有权限
后端->>后端: 生成项目编号
后端->>数据库: 创建项目记录
后端->>数据库: 创建项目成员记录
后端->>数据库: 创建项目里程碑记录
后端->>数据库: 创建项目风险记录
后端->>数据库: 创建项目历史记录
后端-->>前端: 200 OK { "message": "项目创建成功", "projectId": "..." }
else 无权限
后端-->>前端: 403 Forbidden { "message": "您没有创建项目的权限" }
end
```
#### 2.2.3 项目编辑流程
```mermaid
sequenceDiagram
participant 前端 as 浏览器
participant 后端 as FastAPI服务
participant 数据库 as MySQL
前端->>后端: PUT /api/project/{id} (修改后的项目信息)
后端->>后端: 验证用户权限
alt 有权限
后端->>数据库: 查询项目信息
数据库-->>后端: 返回项目信息
后端->>后端: 对比修改前后的数据
后端->>数据库: 更新项目信息
后端->>数据库: 更新相关表数据
后端->>数据库: 创建项目历史记录
后端-->>前端: 200 OK { "message": "项目更新成功" }
else 无权限
后端-->>前端: 403 Forbidden { "message": "您没有编辑项目的权限" }
end
```
### 2.3 模块划分
#### 2.3.1 前端模块
| 模块名称 | 主要功能 | 对应文件路径 |
|---------|---------|------------|
| 登录模块 | 用户登录、退出登录 | src/views/login/ |
| 首页模块 | 系统首页、项目概览 | src/views/home/ |
| 用户管理模块 | 用户列表、创建用户、编辑用户 | src/views/user/ |
| 项目管理模块 | 项目列表、创建项目、编辑项目 | src/views/project/ |
| 项目详情模块 | 项目详细信息、修改历史 | src/views/project/detail/ |
| 项目统计模块 | 项目筛选、统计分析 | src/views/project/statistics/ |
| 系统设置模块 | 系统配置、个人设置 | src/views/settings/ |
#### 2.3.2 后端模块
| 模块名称 | 主要功能 | 对应包路径 |
|---------|---------|-----------|
| 认证模块 | 用户认证、授权 | app.api.auth |
| 用户模块 | 用户管理、权限管理 | app.api.user |
| 项目模块 | 项目管理、项目编辑 | app.api.project |
| 历史记录模块 | 项目修改历史 | app.api.history |
| 统计模块 | 项目统计、数据分析 | app.api.statistics |
| 系统模块 | 系统配置、操作日志 | app.api.system |
| 数据模型 | 数据库模型定义 | app.models |
| 数据库会话 | 数据库连接管理 | app.database |
| 公共模块 | 工具类、常量定义 | app.common |
---
## 3. 目录结构
### 3.1 前端目录结构
```
├── public/ # 静态资源
│ ├── favicon.ico # 网站图标
│ └── index.html # HTML模板
├── src/ # 源代码
│ ├── assets/ # 资源文件
│ │ ├── css/ # 样式文件
│ │ ├── images/ # 图片文件
│ │ └── icons/ # 图标文件
│ ├── components/ # 公共组件
│ ├── views/ # 页面组件
│ │ ├── login/ # 登录页面
│ │ ├── home/ # 首页
│ │ ├── user/ # 用户管理
│ │ ├── project/ # 项目管理
│ │ └── settings/ # 系统设置
│ ├── router/ # 路由配置
│ ├── store/ # 状态管理
│ ├── api/ # API请求
│ ├── utils/ # 工具函数
│ ├── constants/ # 常量定义
│ ├── hooks/ # 自定义Hooks
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .env # 环境变量
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── vite.config.js # Vite配置
├── package.json # 项目依赖
└── README.md # 项目说明
```
### 3.2 后端目录结构
```
├── app/ # 应用代码
│ ├── api/ # API路由
│ │ ├── auth.py # 认证API
│ │ ├── user.py # 用户API
│ │ ├── project.py # 项目API
│ │ ├── history.py # 历史记录API
│ │ ├── statistics.py # 统计API
│ │ └── system.py # 系统API
│ ├── models/ # 数据模型
│ │ ├── user.py # 用户模型
│ │ ├── project.py # 项目模型
│ │ ├── member.py # 成员模型
│ │ ├── milestone.py # 里程碑模型
│ │ ├── risk.py # 风险模型
│ │ ├── history.py # 历史记录模型
│ │ └── log.py # 日志模型
│ ├── schemas/ # Pydantic模式
│ │ ├── auth.py # 认证模式
│ │ ├── user.py # 用户模式
│ │ ├── project.py # 项目模式
│ │ └── common.py # 通用模式
│ ├── services/ # 业务逻辑
│ │ ├── auth_service.py # 认证服务
│ │ ├── user_service.py # 用户服务
│ │ ├── project_service.py # 项目服务
│ │ ├── history_service.py # 历史记录服务
│ │ └── statistics_service.py # 统计服务
│ ├── database/ # 数据库配置
│ │ ├── config.py # 数据库配置
│ │ └── session.py # 数据库会话
│ ├── common/ # 公共模块
│ │ ├── constants.py # 常量定义
│ │ ├── utils.py # 工具函数
│ │ ├── dependencies.py # 依赖注入
│ │ └── exceptions.py # 异常处理
│ ├── config.py # 应用配置
│ └── main.py # 应用入口
├── tests/ # 测试代码
│ ├── test_auth.py # 认证测试
│ ├── test_user.py # 用户测试
│ └── test_project.py # 项目测试
├── alembic/ # 数据库迁移
│ ├── versions/ # 迁移版本
│ └── env.py # 迁移环境
├── pyproject.toml # Poetry配置
├── poetry.lock # Poetry锁文件
├── requirements.txt # 依赖列表
└── README.md # 项目说明
```
---
## 4. 关键类与函数设计
### 4.1 前端关键类与函数
#### 4.1.1 认证相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `login()` | 用户登录 | username: String 用户名<br>password: String 密码 | `{ token: String, userInfo: Object }` | `{ code: Number, message: String }` | src/api/auth.js |
| `logout()` | 用户退出 | 无 | `{ code: 200, message: String }` | `{ code: Number, message: String }` | src/api/auth.js |
| `getUserInfo()` | 获取用户信息 | 无 | `{ userInfo: Object }` | `{ code: Number, message: String }` | src/api/auth.js |
#### 4.1.2 项目相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `createProject()` | 创建项目 | project: Object 项目信息 | `{ code: 200, message: String, projectId: String }` | `{ code: Number, message: String }` | src/api/project.js |
| `updateProject()` | 更新项目 | id: String 项目ID<br>project: Object 项目信息 | `{ code: 200, message: String }` | `{ code: Number, message: String }` | src/api/project.js |
| `getProjectList()` | 获取项目列表 | params: Object 查询参数 | `{ code: 200, data: Array, total: Number }` | `{ code: Number, message: String }` | src/api/project.js |
| `getProjectDetail()` | 获取项目详情 | id: String 项目ID | `{ code: 200, data: Object }` | `{ code: Number, message: String }` | src/api/project.js |
| `getProjectHistory()` | 获取项目历史 | id: String 项目ID<br>params: Object 查询参数 | `{ code: 200, data: Array, total: Number }` | `{ code: Number, message: String }` | src/api/project.js |
#### 4.1.3 用户相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `createUser()` | 创建用户 | user: Object 用户信息 | `{ code: 200, message: String }` | `{ code: Number, message: String }` | src/api/user.js |
| `updateUser()` | 更新用户 | id: String 用户ID<br>user: Object 用户信息 | `{ code: 200, message: String }` | `{ code: Number, message: String }` | src/api/user.js |
| `getUserList()` | 获取用户列表 | params: Object 查询参数 | `{ code: 200, data: Array, total: Number }` | `{ code: Number, message: String }` | src/api/user.js |
| `resetPassword()` | 重置密码 | id: String 用户ID<br>password: String 新密码 | `{ code: 200, message: String }` | `{ code: Number, message: String }` | src/api/user.js |
### 4.2 后端关键类与函数
#### 4.2.1 认证相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `AuthRouter.login()` | 用户登录 | LoginRequest 登录请求 | `AuthResponse` | `HTTPException` | app.api.auth |
| `AuthRouter.logout()` | 用户退出 | 无 | `BaseResponse` | `HTTPException` | app.api.auth |
| `AuthService.authenticate()` | 认证用户 | str username, str password | `AuthResponse` | `AuthenticationException` | app.services.auth_service |
| `AuthService.create_token()` | 创建Token | str user_id | `str` Token | `Exception` | app.services.auth_service |
#### 4.2.2 项目相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `ProjectRouter.create()` | 创建项目 | ProjectRequest 项目请求 | `BaseResponse` | `HTTPException` | app.api.project |
| `ProjectRouter.update()` | 更新项目 | str id, ProjectRequest 项目请求 | `BaseResponse` | `HTTPException` | app.api.project |
| `ProjectRouter.list()` | 获取项目列表 | ProjectQuery 查询参数 | `PageResponse[Project]` | `HTTPException` | app.api.project |
| `ProjectRouter.detail()` | 获取项目详情 | str id | `BaseResponse[ProjectDetail]` | `HTTPException` | app.api.project |
| `ProjectService.create_project()` | 创建项目 | ProjectRequest 项目请求, str username | `str` 项目ID | `ServiceException` | app.services.project_service |
| `ProjectService.update_project()` | 更新项目 | str id, ProjectRequest 项目请求, str username | `None` | `ServiceException` | app.services.project_service |
#### 4.2.3 历史记录相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `HistoryRouter.list()` | 获取项目历史 | str project_id, HistoryQuery 查询参数 | `PageResponse[ProjectHistory]` | `HTTPException` | app.api.history |
| `HistoryService.record_history()` | 记录历史 | str project_id, str operation_type, str operator, dict changes | `None` | `ServiceException` | app.services.history_service |
#### 4.2.4 统计相关
| 类/函数名 | 说明 | 参数(类型/含义) | 成功返回结构/类型 | 失败返回结构/类型 | 所属文件/模块 |
|-----------|------|-----------------|-----------------|-----------------|--------------|
| `StatisticsRouter.filter()` | 筛选项目 | ProjectFilter 筛选条件 | `PageResponse[Project]` | `HTTPException` | app.api.statistics |
| `StatisticsRouter.statistics()` | 统计项目 | StatisticsRequest 统计请求 | `BaseResponse[StatisticsResult]` | `HTTPException` | app.api.statistics |
| `StatisticsService.get_project_statistics()` | 获取项目统计 | StatisticsRequest 统计请求 | `StatisticsResult` | `ServiceException` | app.services.statistics_service |
---
## 5. 数据库与数据结构设计
### 5.1 数据库表结构
详细的数据库表结构见《数据库设计文档》。
### 5.2 数据传输对象 (DTOs)
#### 5.2.1 前端DTOs
##### 登录请求
```javascript
{
username: String, // 用户名
password: String // 密码
}
```
##### 项目请求
```javascript
{
projectName: String, // 项目名称
status: String, // 项目状态
leader: String, // 负责人
phone: String, // 联系电话
email: String, // 邮箱
background: String, // 项目背景
goal: String, // 项目目标
scope: String, // 项目范围
startDate: String, // 开始日期
plannedEndDate: String, // 预计结束日期
actualEndDate: String, // 实际结束日期
totalBudget: Number, // 总预算
usedBudget: Number, // 已使用预算
members: [ // 项目成员
{
name: String, // 姓名
role: String, // 角色
department: String // 部门
}
],
milestones: [ // 项目里程碑
{
name: String, // 名称
plannedDate: String, // 计划日期
actualDate: String, // 实际日期
status: String // 状态
}
],
risks: [ // 项目风险
{
description: String, // 描述
level: String, // 等级
measure: String // 应对措施
}
],
remarks: String // 备注
}
```
#### 5.2.2 后端DTOs (Pydantic Models)
##### 登录请求
```python
from pydantic import BaseModel
class LoginRequest(BaseModel):
username: str # 用户名
password: str # 密码
```
##### 项目请求
```python
from pydantic import BaseModel
from typing import List, Optional
from datetime import date
from decimal import Decimal
class MemberRequest(BaseModel):
name: str # 姓名
role: str # 角色
department: str # 部门
class MilestoneRequest(BaseModel):
name: str # 名称
planned_date: date # 计划日期
actual_date: Optional[date] = None # 实际日期
status: str # 状态
class RiskRequest(BaseModel):
description: str # 描述
level: str # 等级
measure: str # 应对措施
class ProjectRequest(BaseModel):
project_name: str # 项目名称
status: str # 项目状态
leader: str # 负责人
phone: Optional[str] = None # 联系电话
email: Optional[str] = None # 邮箱
background: Optional[str] = None # 项目背景
goal: Optional[str] = None # 项目目标
scope: Optional[str] = None # 项目范围
start_date: date # 开始日期
planned_end_date: date # 预计结束日期
actual_end_date: Optional[date] = None # 实际结束日期
total_budget: Decimal # 总预算
used_budget: Decimal = Decimal('0.00') # 已使用预算
members: List[MemberRequest] = [] # 项目成员
milestones: List[MilestoneRequest] = [] # 项目里程碑
risks: List[RiskRequest] = [] # 项目风险
remarks: Optional[str] = None # 备注
```
---
## 6. 接口设计
### 6.1 认证接口
| API路径 | 方法 | 模块/文件 | 类型 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|------|----------|--------------|------------------|
| `/api/auth/login` | `POST` | `app.api.auth` | `Router` | 用户登录 | `{"username": "admin", "password": "123456"}` | `{"code": 200, "data": {"token": "...", "userInfo": {...}}, "message": "登录成功"}` |
| `/api/auth/logout` | `POST` | `app.api.auth` | `Router` | 用户退出 | N/A | `{"code": 200, "message": "退出成功"}` |
| `/api/auth/userInfo` | `GET` | `app.api.auth` | `Router` | 获取用户信息 | N/A | `{"code": 200, "data": {"userId": "...", "username": "...", "realName": "...", "department": "...", "role": "..."}}` |
### 6.2 用户接口
| API路径 | 方法 | 模块/文件 | 类型 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|------|----------|--------------|------------------|
| `/api/user` | `GET` | `app.api.user` | `Router` | 获取用户列表 | N/A (Query参数: page, size, username, department, role) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/user` | `POST` | `app.api.user` | `Router` | 创建用户 | `{"username": "test", "password": "123456", "realName": "测试用户", "department": "技术部", "role": "OTHER"}` | `{"code": 200, "message": "创建成功"}` |
| `/api/user/{id}` | `PUT` | `app.api.user` | `Router` | 更新用户 | `{"realName": "测试用户1", "department": "市场部", "role": "MARKETING"}` | `{"code": 200, "message": "更新成功"}` |
| `/api/user/{id}` | `DELETE` | `app.api.user` | `Router` | 删除用户 | N/A | `{"code": 200, "message": "删除成功"}` |
| `/api/user/resetPassword/{id}` | `PUT` | `app.api.user` | `Router` | 重置密码 | `{"password": "123456"}` | `{"code": 200, "message": "密码重置成功"}` |
### 6.3 项目接口
| API路径 | 方法 | 模块/文件 | 类型 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|------|----------|--------------|------------------|
| `/api/project` | `GET` | `app.api.project` | `Router` | 获取项目列表 | N/A (Query参数: page, size, projectName, status, leader) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/project` | `POST` | `app.api.project` | `Router` | 创建项目 | `{"projectName": "测试项目", "status": "NOT_STARTED", "leader": "张三", ...}` | `{"code": 200, "data": {"projectId": "..."}, "message": "创建成功"}` |
| `/api/project/{id}` | `GET` | `app.api.project` | `Router` | 获取项目详情 | N/A | `{"code": 200, "data": {...}, "message": "查询成功"}` |
| `/api/project/{id}` | `PUT` | `app.api.project` | `Router` | 更新项目 | `{"projectName": "测试项目1", "status": "IN_PROGRESS", ...}` | `{"code": 200, "message": "更新成功"}` |
| `/api/project/{id}` | `DELETE` | `app.api.project` | `Router` | 删除项目 | N/A | `{"code": 200, "message": "删除成功"}` |
### 6.4 历史记录接口
| API路径 | 方法 | 模块/文件 | 类型 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|------|----------|--------------|------------------|
| `/api/history/{projectId}` | `GET` | `app.api.history` | `Router` | 获取项目历史 | N/A (Query参数: page, size, operator, startDate, endDate) | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
### 6.5 统计接口
| API路径 | 方法 | 模块/文件 | 类型 | 功能描述 | 请求体 (JSON) | 成功响应 (200 OK) |
|---------|------|-----------|------|----------|--------------|------------------|
| `/api/statistics/filter` | `POST` | `app.api.statistics` | `Router` | 筛选项目 | `{"projectNo": "PRJ2025001", "projectName": "测试", "status": "IN_PROGRESS", ...}` | `{"code": 200, "data": [{...}], "total": 10, "message": "查询成功"}` |
| `/api/statistics/statistics` | `POST` | `app.api.statistics` | `Router` | 统计项目 | `{"dimension": "status", "startDate": "2025-01-01", "endDate": "2025-12-31"}` | `{"code": 200, "data": {...}, "message": "统计成功"}` |
---
## 7. 安全设计
### 7.1 认证与授权
- **认证方式**: JWT (JSON Web Token) 认证
- **授权方式**: 基于角色的访问控制 (RBAC)
- **密码加密**: 使用 Passlib 的 bcrypt 算法加密存储密码
- **会话管理**: JWT Token 存储在前端 localStorage 中,后端验证 Token 签名和有效期
### 7.2 接口安全
- **统一认证拦截**: 所有接口(除登录接口外)都需要验证 Token
- **权限验证**: 基于用户角色和权限进行接口访问控制
- **请求参数验证**: 使用 Pydantic 验证请求参数的合法性
- **防止SQL注入**: 使用 SQLAlchemy 的参数化查询,避免SQL注入
- **防止XSS攻击**: 前端使用 v-html 时进行转义,后端对输入进行过滤
- **防止CSRF攻击**: 使用 Token 验证,确保请求来自合法来源
### 7.3 数据安全
- **敏感数据加密**: 敏感数据(如密码)加密存储
- **数据备份**: 定期备份数据库,防止数据丢失
- **数据恢复**: 制定数据恢复计划,确保数据可恢复
- **日志审计**: 记录用户操作日志,便于追溯操作行为
---
## 8. 部署与集成方案
### 8.1 开发环境部署
#### 8.1.1 前端部署
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `npm install`
3. 启动开发服务器: `npm run dev`
4. 访问: `http://localhost:5173`
#### 8.1.2 后端部署
1. 克隆代码库: `git clone <repository-url>`
2. 安装依赖: `poetry install``pip install -r requirements.txt`
3. 配置数据库连接 (config.py)
4. 初始化数据库: `alembic upgrade head`
5. 启动应用: `uvicorn app.main:app --reload`
6. 访问: `http://localhost:8000`
7. API文档: `http://localhost:8000/docs`
### 8.2 生产环境部署
#### 8.2.1 前端部署
1. 构建生产版本: `npm run build`
2. 将构建产物复制到 Nginx 静态目录
3. 配置 Nginx 反向代理
#### 8.2.2 后端部署
1. 安装依赖: `poetry install --no-dev``pip install -r requirements.txt`
2. 配置环境变量和数据库连接
3. 使用 Gunicorn 启动应用: `gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker`
4. 配置 Nginx 反向代理
### 8.3 集成方案
- **前端与后端集成**: 通过 RESTful API 进行数据交互
- **数据库集成**: 使用 SQLAlchemy ORM 操作数据库
- **日志集成**: 使用 Python logging 模块记录系统日志
- **监控集成**: 可集成 Prometheus + Grafana 监控系统性能
---
## 9. 性能优化策略
### 9.1 前端优化
- **代码分割**: 使用 Vue 的路由懒加载,减少初始加载时间
- **组件缓存**: 使用 keep-alive 缓存频繁访问的组件
- **图片优化**: 使用适当尺寸的图片,压缩图片大小
- **网络请求优化**: 使用 Axios 拦截器,统一处理请求和响应
- **减少 DOM 操作**: 使用虚拟列表处理大数据渲染
### 9.2 后端优化
- **数据库索引**: 为常用查询字段创建索引,提高查询性能
- **连接池**: 使用 SQLAlchemy 的连接池,提高数据库连接效率
- **异步处理**: FastAPI 支持异步处理,提高系统响应速度
- **批量操作**: 对批量数据操作使用批量处理,减少数据库交互次数
- **查询优化**: 使用 SQLAlchemy 的 lazy loading 和 eager loading 优化查询
### 9.3 数据库优化
- **表结构优化**: 合理设计表结构,避免冗余字段
- **SQL优化**: 优化 SQL 查询语句,避免全表扫描
- **定期清理**: 定期清理历史数据,避免数据量过大
- **数据库配置**: 优化 MySQL 配置参数,提高数据库性能
---
## 10. 监控与维护
### 10.1 系统监控
- **应用监控**: 监控应用的运行状态、CPU、内存使用情况
- **数据库监控**: 监控数据库的连接数、查询性能、存储空间
- **API监控**: 监控 API 的响应时间、调用次数、错误率
- **日志监控**: 监控系统日志,及时发现异常情况
### 10.2 故障处理
- **故障定位**: 通过日志和监控工具定位故障原因
- **故障恢复**: 制定故障恢复方案,确保系统快速恢复
- **故障预防**: 定期进行系统检查,预防故障发生
### 10.3 系统维护
- **定期更新**: 定期更新依赖库和框架版本,修复安全漏洞
- **数据备份**: 定期备份数据库,防止数据丢失
- **性能调优**: 定期分析系统性能,进行性能调优
- **文档更新**: 及时更新系统文档,保持文档与系统同步
---
## 11. 附录
### 11.1 技术选型对比
| 技术 | 对比方案 | 最终选择理由 |
|------|----------|--------------|
| 前端框架 | Vue 3 vs React | Vue 3 学习曲线平缓,文档完善,适合快速开发 |
| 后端框架 | FastAPI vs Flask vs Django | FastAPI 高性能,自动生成API文档,支持异步 |
| 数据库 | MySQL vs PostgreSQL | MySQL 社区活跃,生态成熟,适合企业级应用 |
| ORM框架 | SQLAlchemy vs Django ORM | SQLAlchemy 灵活强大,支持多种数据库 |
### 11.2 开发规范
#### 前端开发规范
- 组件命名: 大驼峰命名法 (PascalCase)
- 变量命名: 小驼峰命名法 (camelCase)
- 常量命名: 全大写下划线分隔 (SNAKE_CASE)
- 代码风格: 遵循 ESLint 规范
#### 后端开发规范
- 类命名: 大驼峰命名法 (PascalCase)
- 函数命名: 小驼峰命名法 (camelCase)
- 变量命名: 小写下划线分隔 (snake_case)
- 常量命名: 全大写下划线分隔 (SNAKE_CASE)
- 代码风格: 遵循 PEP 8 规范
### 11.3 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
| V2.0 | 2026-01-26 | - | 后端改为Python FastAPI,去掉Redis |
+529
View File
@@ -0,0 +1,529 @@
# 项目管理系统数据库设计文档
## 文档信息
- **文档版本**: V1.0
- **创建日期**: 2026-01-26
- **文档类型**: 数据库设计文档 (DDD)
---
## 1. 数据库概述
### 1.1 数据库选型
- **数据库类型**: 关系型数据库
- **推荐数据库**: MySQL / PostgreSQL
### 1.2 数据库设计原则
- 遵循第三范式(3NF
- 合理使用索引提高查询性能
- 考虑数据完整性和一致性
- 支持事务处理
- 便于扩展和维护
---
## 2. 数据库表设计
### 2.1 用户表 (sys_user)
#### 2.1.1 表说明
存储系统用户的基本信息和认证信息。
#### 2.1.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| user_id | VARCHAR | 32 | 是 | - | 用户ID,主键 |
| username | VARCHAR | 50 | 是 | - | 用户名,唯一 |
| password | VARCHAR | 128 | 是 | - | 密码,加密存储 |
| real_name | VARCHAR | 50 | 是 | - | 真实姓名 |
| department | VARCHAR | 50 | 是 | - | 部门 |
| phone | VARCHAR | 20 | 否 | NULL | 联系电话 |
| email | VARCHAR | 100 | 否 | NULL | 邮箱 |
| role | VARCHAR | 20 | 是 | - | 角色 |
| status | TINYINT | 1 | 是 | 1 | 状态:1-正常,0-禁用 |
| create_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 创建时间 |
| update_time | DATETIME | - | 是 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
| last_login_time | DATETIME | - | 否 | NULL | 最后登录时间 |
#### 2.1.3 索引设计
- PRIMARY KEY: user_id
- UNIQUE KEY: uk_username (username)
- INDEX: idx_department (department)
- INDEX: idx_role (role)
- INDEX: idx_status (status)
#### 2.1.4 外键约束
---
### 2.2 项目表 (project)
#### 2.2.1 表说明
存储项目的基本信息和详细内容。
#### 2.2.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| project_id | VARCHAR | 32 | 是 | - | 项目ID,主键 |
| project_no | VARCHAR | 20 | 是 | - | 项目编号,唯一 |
| project_name | VARCHAR | 200 | 是 | - | 项目名称 |
| status | VARCHAR | 20 | 是 | 'NOT_STARTED' | 项目状态 |
| create_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 创建时间 |
| creator | VARCHAR | 50 | 是 | - | 创建人 |
| update_time | DATETIME | - | 是 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 最后修改时间 |
| last_modifier | VARCHAR | 50 | 否 | NULL | 最后修改人 |
| leader | VARCHAR | 50 | 是 | - | 负责人 |
| phone | VARCHAR | 20 | 否 | NULL | 联系电话 |
| email | VARCHAR | 100 | 否 | NULL | 邮箱 |
| background | TEXT | - | 否 | NULL | 项目背景 |
| goal | TEXT | - | 否 | NULL | 项目目标 |
| scope | TEXT | - | 否 | NULL | 项目范围 |
| start_date | DATE | - | 是 | - | 开始日期 |
| planned_end_date | DATE | - | 是 | - | 预计结束日期 |
| actual_end_date | DATE | - | 否 | NULL | 实际结束日期 |
| total_budget | DECIMAL | 15,2 | 是 | 0.00 | 总预算 |
| used_budget | DECIMAL | 15,2 | 是 | 0.00 | 已使用预算 |
| remaining_budget | DECIMAL | 15,2 | 是 | 0.00 | 剩余预算 |
| remarks | TEXT | - | 否 | NULL | 备注 |
#### 2.2.3 索引设计
- PRIMARY KEY: project_id
- UNIQUE KEY: uk_project_no (project_no)
- INDEX: idx_status (status)
- INDEX: idx_creator (creator)
- INDEX: idx_leader (leader)
- INDEX: idx_create_time (create_time)
- INDEX: idx_update_time (update_time)
#### 2.2.4 外键约束
---
### 2.3 项目成员表 (project_member)
#### 2.3.1 表说明
存储项目成员信息。
#### 2.3.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| member_id | VARCHAR | 32 | 是 | - | 成员ID,主键 |
| project_id | VARCHAR | 32 | 是 | - | 项目ID,外键 |
| name | VARCHAR | 50 | 是 | - | 姓名 |
| role | VARCHAR | 50 | 是 | - | 角色 |
| department | VARCHAR | 50 | 是 | - | 部门 |
| create_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 创建时间 |
#### 2.3.3 索引设计
- PRIMARY KEY: member_id
- INDEX: idx_project_id (project_id)
#### 2.3.4 外键约束
- FOREIGN KEY: project_id -> project(project_id) ON DELETE CASCADE
---
### 2.4 项目里程碑表 (project_milestone)
#### 2.4.1 表说明
存储项目里程碑信息。
#### 2.4.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| milestone_id | VARCHAR | 32 | 是 | - | 里程碑ID,主键 |
| project_id | VARCHAR | 32 | 是 | - | 项目ID,外键 |
| name | VARCHAR | 200 | 是 | - | 名称 |
| planned_date | DATE | - | 是 | - | 计划日期 |
| actual_date | DATE | - | 否 | NULL | 实际日期 |
| status | VARCHAR | 20 | 是 | 'NOT_STARTED' | 状态 |
| create_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 创建时间 |
| update_time | DATETIME | - | 是 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
#### 2.4.3 索引设计
- PRIMARY KEY: milestone_id
- INDEX: idx_project_id (project_id)
- INDEX: idx_status (status)
#### 2.4.4 外键约束
- FOREIGN KEY: project_id -> project(project_id) ON DELETE CASCADE
---
### 2.5 项目风险表 (project_risk)
#### 2.5.1 表说明
存储项目风险信息。
#### 2.5.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| risk_id | VARCHAR | 32 | 是 | - | 风险ID,主键 |
| project_id | VARCHAR | 32 | 是 | - | 项目ID,外键 |
| description | TEXT | - | 是 | - | 描述 |
| level | VARCHAR | 20 | 是 | - | 等级 |
| measure | TEXT | - | 是 | - | 应对措施 |
| create_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 创建时间 |
#### 2.5.3 索引设计
- PRIMARY KEY: risk_id
- INDEX: idx_project_id (project_id)
- INDEX: idx_level (level)
#### 2.5.4 外键约束
- FOREIGN KEY: project_id -> project(project_id) ON DELETE CASCADE
---
### 2.6 项目历史记录表 (project_history)
#### 2.6.1 表说明
存储项目修改历史记录。
#### 2.6.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| history_id | VARCHAR | 32 | 是 | - | 历史记录ID,主键 |
| project_id | VARCHAR | 32 | 是 | - | 项目ID,外键 |
| project_no | VARCHAR | 20 | 是 | - | 项目编号 |
| operation_type | VARCHAR | 20 | 是 | - | 操作类型 |
| operator | VARCHAR | 50 | 是 | - | 操作人 |
| operation_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 操作时间 |
| field_name | VARCHAR | 100 | 是 | - | 字段名 |
| old_value | TEXT | - | 否 | NULL | 修改前值 |
| new_value | TEXT | - | 否 | NULL | 修改后值 |
#### 2.6.3 索引设计
- PRIMARY KEY: history_id
- INDEX: idx_project_id (project_id)
- INDEX: idx_project_no (project_no)
- INDEX: idx_operation_time (operation_time)
- INDEX: idx_operator (operator)
#### 2.6.4 外键约束
- FOREIGN KEY: project_id -> project(project_id) ON DELETE CASCADE
---
### 2.7 操作日志表 (operation_log)
#### 2.7.1 表说明
存储用户操作日志。
#### 2.7.2 表结构
| 字段名 | 数据类型 | 长度 | 是否必填 | 默认值 | 说明 |
|--------|----------|------|----------|--------|------|
| log_id | VARCHAR | 32 | 是 | - | 日志ID,主键 |
| user_id | VARCHAR | 32 | 是 | - | 用户ID,外键 |
| username | VARCHAR | 50 | 是 | - | 用户名 |
| operation | VARCHAR | 100 | 是 | - | 操作内容 |
| ip_address | VARCHAR | 50 | 否 | NULL | IP地址 |
| user_agent | VARCHAR | 500 | 否 | NULL | 用户代理 |
| operation_time | DATETIME | - | 是 | CURRENT_TIMESTAMP | 操作时间 |
#### 2.7.3 索引设计
- PRIMARY KEY: log_id
- INDEX: idx_user_id (user_id)
- INDEX: idx_operation_time (operation_time)
#### 2.7.4 外键约束
- FOREIGN KEY: user_id -> sys_user(user_id) ON DELETE CASCADE
---
## 3. 数据库关系图
### 3.1 ER图描述
```
sys_user (用户表)
|
| 1
|
| N
|
operation_log (操作日志表)
project (项目表)
|
| 1
|
| N
|
+-- project_member (项目成员表)
|
| 1
|
| N
|
+-- project_milestone (项目里程碑表)
|
| 1
|
| N
|
+-- project_risk (项目风险表)
|
| 1
|
| N
|
+-- project_history (项目历史记录表)
```
---
## 4. 数据字典
### 4.1 用户角色枚举值
| 值 | 说明 |
|----|------|
| ADMIN | 管理员 |
| MARKETING | 市场部 |
| OTHER | 其他部门 |
### 4.2 项目状态枚举值
| 值 | 说明 |
|----|------|
| NOT_STARTED | 未开始 |
| IN_PROGRESS | 进行中 |
| COMPLETED | 已完成 |
| PAUSED | 已暂停 |
| CANCELLED | 已取消 |
### 4.3 里程碑状态枚举值
| 值 | 说明 |
|----|------|
| NOT_STARTED | 未开始 |
| IN_PROGRESS | 进行中 |
| COMPLETED | 已完成 |
### 4.4 风险等级枚举值
| 值 | 说明 |
|----|------|
| HIGH | 高 |
| MEDIUM | 中 |
| LOW | 低 |
### 4.5 操作类型枚举值
| 值 | 说明 |
|----|------|
| CREATE | 创建 |
| UPDATE | 更新 |
| DELETE | 删除 |
### 4.6 部门枚举值
| 值 | 说明 |
|----|------|
| MARKETING | 市场部 |
| TECHNOLOGY | 技术部 |
| DESIGN | 设计部 |
| FINANCE | 财务部 |
| HR | 人力资源部 |
---
## 5. 数据库初始化脚本
### 5.1 建表脚本
```sql
-- 创建用户表
CREATE TABLE sys_user (
user_id VARCHAR(32) PRIMARY KEY COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
password VARCHAR(128) NOT NULL COMMENT '密码',
real_name VARCHAR(50) NOT NULL COMMENT '真实姓名',
department VARCHAR(50) NOT NULL COMMENT '部门',
phone VARCHAR(20) COMMENT '联系电话',
email VARCHAR(100) COMMENT '邮箱',
role VARCHAR(20) NOT NULL COMMENT '角色',
status TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态:1-正常,0-禁用',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
last_login_time DATETIME COMMENT '最后登录时间',
INDEX idx_department (department),
INDEX idx_role (role),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 创建项目表
CREATE TABLE project (
project_id VARCHAR(32) PRIMARY KEY COMMENT '项目ID',
project_no VARCHAR(20) NOT NULL UNIQUE COMMENT '项目编号',
project_name VARCHAR(200) NOT NULL COMMENT '项目名称',
status VARCHAR(20) NOT NULL DEFAULT 'NOT_STARTED' COMMENT '项目状态',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
creator VARCHAR(50) NOT NULL COMMENT '创建人',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
last_modifier VARCHAR(50) COMMENT '最后修改人',
leader VARCHAR(50) NOT NULL COMMENT '负责人',
phone VARCHAR(20) COMMENT '联系电话',
email VARCHAR(100) COMMENT '邮箱',
background TEXT COMMENT '项目背景',
goal TEXT COMMENT '项目目标',
scope TEXT COMMENT '项目范围',
start_date DATE NOT NULL COMMENT '开始日期',
planned_end_date DATE NOT NULL COMMENT '预计结束日期',
actual_end_date DATE COMMENT '实际结束日期',
total_budget DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT '总预算',
used_budget DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT '已使用预算',
remaining_budget DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT '剩余预算',
remarks TEXT COMMENT '备注',
INDEX idx_status (status),
INDEX idx_creator (creator),
INDEX idx_leader (leader),
INDEX idx_create_time (create_time),
INDEX idx_update_time (update_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目表';
-- 创建项目成员表
CREATE TABLE project_member (
member_id VARCHAR(32) PRIMARY KEY COMMENT '成员ID',
project_id VARCHAR(32) NOT NULL COMMENT '项目ID',
name VARCHAR(50) NOT NULL COMMENT '姓名',
role VARCHAR(50) NOT NULL COMMENT '角色',
department VARCHAR(50) NOT NULL COMMENT '部门',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
FOREIGN KEY (project_id) REFERENCES project(project_id) ON DELETE CASCADE,
INDEX idx_project_id (project_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目成员表';
-- 创建项目里程碑表
CREATE TABLE project_milestone (
milestone_id VARCHAR(32) PRIMARY KEY COMMENT '里程碑ID',
project_id VARCHAR(32) NOT NULL COMMENT '项目ID',
name VARCHAR(200) NOT NULL COMMENT '名称',
planned_date DATE NOT NULL COMMENT '计划日期',
actual_date DATE COMMENT '实际日期',
status VARCHAR(20) NOT NULL DEFAULT 'NOT_STARTED' COMMENT '状态',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
FOREIGN KEY (project_id) REFERENCES project(project_id) ON DELETE CASCADE,
INDEX idx_project_id (project_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目里程碑表';
-- 创建项目风险表
CREATE TABLE project_risk (
risk_id VARCHAR(32) PRIMARY KEY COMMENT '风险ID',
project_id VARCHAR(32) NOT NULL COMMENT '项目ID',
description TEXT NOT NULL COMMENT '描述',
level VARCHAR(20) NOT NULL COMMENT '等级',
measure TEXT NOT NULL COMMENT '应对措施',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
FOREIGN KEY (project_id) REFERENCES project(project_id) ON DELETE CASCADE,
INDEX idx_project_id (project_id),
INDEX idx_level (level)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目风险表';
-- 创建项目历史记录表
CREATE TABLE project_history (
history_id VARCHAR(32) PRIMARY KEY COMMENT '历史记录ID',
project_id VARCHAR(32) NOT NULL COMMENT '项目ID',
project_no VARCHAR(20) NOT NULL COMMENT '项目编号',
operation_type VARCHAR(20) NOT NULL COMMENT '操作类型',
operator VARCHAR(50) NOT NULL COMMENT '操作人',
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
field_name VARCHAR(100) NOT NULL COMMENT '字段名',
old_value TEXT COMMENT '修改前值',
new_value TEXT COMMENT '修改后值',
FOREIGN KEY (project_id) REFERENCES project(project_id) ON DELETE CASCADE,
INDEX idx_project_id (project_id),
INDEX idx_project_no (project_no),
INDEX idx_operation_time (operation_time),
INDEX idx_operator (operator)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目历史记录表';
-- 创建操作日志表
CREATE TABLE operation_log (
log_id VARCHAR(32) PRIMARY KEY COMMENT '日志ID',
user_id VARCHAR(32) NOT NULL COMMENT '用户ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
operation VARCHAR(100) NOT NULL COMMENT '操作内容',
ip_address VARCHAR(50) COMMENT 'IP地址',
user_agent VARCHAR(500) COMMENT '用户代理',
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
FOREIGN KEY (user_id) REFERENCES sys_user(user_id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_operation_time (operation_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';
```
### 5.2 初始化数据脚本
```sql
-- 插入管理员用户
INSERT INTO sys_user (user_id, username, password, real_name, department, role, status)
VALUES ('admin001', 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '系统管理员', 'ADMIN', 'ADMIN', 1);
-- 插入市场部用户
INSERT INTO sys_user (user_id, username, password, real_name, department, role, status)
VALUES ('marketing001', 'marketing', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '市场部经理', 'MARKETING', 'MARKETING', 1);
-- 插入其他部门用户
INSERT INTO sys_user (user_id, username, password, real_name, department, role, status)
VALUES ('other001', 'other', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '技术部经理', 'TECHNOLOGY', 'OTHER', 1);
```
---
## 6. 数据库性能优化建议
### 6.1 索引优化
- 为常用查询字段创建索引
- 避免在索引列上进行函数操作
- 定期分析和优化索引
### 6.2 查询优化
- 避免使用SELECT *
- 合理使用JOIN
- 使用分页查询减少数据传输量
- 对大表进行分区处理
### 6.3 存储优化
- 定期清理历史数据
- 对大文本字段考虑单独存储
- 使用合适的数据类型减少存储空间
### 6.4 备份策略
- 每日全量备份
- 每小时增量备份
- 定期测试备份恢复
---
## 7. 数据库安全建议
### 7.1 访问控制
- 使用最小权限原则
- 定期修改数据库密码
- 限制数据库访问IP
### 7.2 数据加密
- 敏感字段加密存储
- 使用SSL连接数据库
- 定期更新加密算法
### 7.3 审计日志
- 记录所有数据库操作
- 定期审计日志
- 异常操作及时报警
---
## 8. 附录
### 8.1 变更记录
| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|--------|----------|
| V1.0 | 2026-01-26 | - | 初始版本创建 |
-110
View File
@@ -1,110 +0,0 @@
import numpy as np
import scipy.ndimage
import torch
import comfy.utils
import node_helpers
import folder_paths
import random
import nodes
from nodes import MAX_RESOLUTION
def composite(destination, source, x, y, mask = None, multiplier = 8, resize_source = False):
source = source.to(destination.device)
if resize_source:
source = torch.nn.functional.interpolate(source, size=(destination.shape[2], destination.shape[3]), mode="bilinear")
source = comfy.utils.repeat_to_batch_size(source, destination.shape[0])
x = max(-source.shape[3] * multiplier, min(x, destination.shape[3] * multiplier))
y = max(-source.shape[2] * multiplier, min(y, destination.shape[2] * multiplier))
left, top = (x // multiplier, y // multiplier)
right, bottom = (left + source.shape[3], top + source.shape[2],)
if mask is None:
mask = torch.ones_like(source)
else:
mask = mask.to(destination.device, copy=True)
mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(source.shape[2], source.shape[3]), mode="bilinear")
mask = comfy.utils.repeat_to_batch_size(mask, source.shape[0])
# calculate the bounds of the source that will be overlapping the destination
# this prevents the source trying to overwrite latent pixels that are out of bounds
# of the destination
visible_width, visible_height = (destination.shape[3] - left + min(0, x), destination.shape[2] - top + min(0, y),)
mask = mask[:, :, :visible_height, :visible_width]
inverse_mask = torch.ones_like(mask) - mask
source_portion = mask * source[:, :, :visible_height, :visible_width]
destination_portion = inverse_mask * destination[:, :, top:bottom, left:right]
destination[:, :, top:bottom, left:right] = source_portion + destination_portion
return destination
class MyMaskComposite:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"destination": ("MASK",),
"source": ("MASK",),
"x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
"y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
"offset": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
"operation": (["multiply", "add", "subtract", "and", "or", "xor"],),
}
}
CATEGORY = "mask"
RETURN_TYPES = ("MASK",)
FUNCTION = "combine"
def combine(self, destination, source, x, y, offset, operation):
output = destination.reshape((-1, destination.shape[-2], destination.shape[-1])).clone()
source = source.reshape((-1, source.shape[-2], source.shape[-1]))
print(source.shape) # 输出数组的形状
left, top = (x, y,)
right, bottom = (min(left + source.shape[-1], destination.shape[-1]), min(top + source.shape[-2], destination.shape[-2]))
visible_width, visible_height = (right - left, bottom - top,)
source[:, :offset, :] = 0
source_portion = source[:, :visible_height, :visible_width]
destination_portion = output[:, top:bottom, left:right]
print(f"left:{left} top:{top} right:{right} bottom:{bottom} visible_width:{visible_width} visible_height:{visible_height}")
if operation == "multiply":
output[:, top:bottom, left:right] = destination_portion * source_portion
elif operation == "add":
output[:, top:bottom, left:right] = destination_portion + source_portion
elif operation == "subtract":
output[:, top:bottom, left:right] = destination_portion - source_portion
elif operation == "and":
output[:, top:bottom, left:right] = torch.bitwise_and(destination_portion.round().bool(), source_portion.round().bool()).float()
elif operation == "or":
output[:, top:bottom, left:right] = torch.bitwise_or(destination_portion.round().bool(), source_portion.round().bool()).float()
elif operation == "xor":
output[:, top:bottom, left:right] = torch.bitwise_xor(destination_portion.round().bool(), source_portion.round().bool()).float()
output = torch.clamp(output, 0.0, 1.0)
return (output,)
NODE_CLASS_MAPPINGS = {
"MyMaskComposite": MyMaskComposite,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"MyMaskComposite": "MyMaskComposite",
}