save code
This commit is contained in:
@@ -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
@@ -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']
|
||||
@@ -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 | - | 初始版本创建 |
|
||||
@@ -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 | - | 初始版本创建 |
|
||||
@@ -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 | - | 初始版本创建 |
|
||||
@@ -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 | - | 初始版本创建 |
|
||||
Binary file not shown.
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,634 @@
|
||||
# 项目管理系统技术架构文档
|
||||
|
||||
## 文档信息
|
||||
- **文档版本**: V2.0
|
||||
- **创建日期**: 2026-01-26
|
||||
- **文档类型**: 技术架构文档
|
||||
|
||||
---
|
||||
|
||||
## 1. 技术架构概述
|
||||
|
||||
### 1.1 架构风格
|
||||
本项目采用BS(Browser/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
@@ -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 | - | 初始版本创建 |
|
||||
@@ -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",
|
||||
}
|
||||
Reference in New Issue
Block a user