# 系统架构与业务流程图
> 基于项目源码自动生成,所有图表均使用 Mermaid 语法,可在支持 Mermaid 的 Markdown 编辑器中渲染。
---
## 一、系统整体架构
### 1.1 分层架构总览
```mermaid
graph TB
subgraph 用户层
Browser["浏览器
(Chrome / Edge)"]
end
subgraph 前端["前端 · Vue 3 + Vite"]
Router["Vue Router
路由守卫 / 权限控制"]
Views["页面组件
Dashboard / Resource / Project ..."]
Store["Pinia Store
用户状态 / Token"]
API["Axios API 层
request.js 统一拦截"]
end
subgraph 反向代理["Nginx 反向代理"]
Static["静态资源托管
dist/"]
Proxy["/api/ → :8080
API 反代"]
end
subgraph 后端["后端 · Spring Boot 3"]
Controller["Controller 层
REST 接口"]
Security["Spring Security
JWT 认证 + 权限"]
Service["Service 层
核心业务逻辑"]
Mapper["Mapper 层
MyBatis-Plus"]
Task["定时任务
ResourceExpireTask"]
Mail["邮件服务
EmailService"]
end
subgraph 数据层
MySQL["MySQL 8.0+
resource_platform"]
SMTP["SMTP 邮件服务器"]
end
Browser -->|HTTP| 反向代理
反向代理 -->|静态文件| Static
反向代理 -->|/api/*| Controller
Router --> Views
Views --> Store
Views --> API
API -->|Bearer Token| Controller
Controller --> Security
Security --> Service
Service --> Mapper
Mapper --> MySQL
Task --> Service
Service --> Mail
Mail --> SMTP
```
### 1.2 后端内部分层
```mermaid
graph LR
subgraph 接入层
A["AuthController"]
RC["ResourceController"]
PC["ProjectController"]
DC["DashboardController"]
UC["UserController"]
RTC["ResourceTypeController"]
PRC["ProviderController"]
LC["OperationLogController"]
end
subgraph 安全层
JWT["JwtAuthenticationFilter"]
SC["SecurityConfig
CORS / 权限规则"]
SU["SecurityUtils"]
end
subgraph 业务层
RS["ResourceServiceImpl"]
PS["ProjectServiceImpl"]
US["SysUserServiceImpl"]
RRS["ResourceRenewalServiceImpl"]
DS["DashboardServiceImpl"]
OLS["OperationLogServiceImpl"]
ES["EmailServiceImpl"]
end
subgraph 数据层
RM["ResourceMapper"]
PM["ProjectMapper"]
UM["SysUserMapper"]
RRM["ResourceRenewalMapper"]
PRM["ProjectResourceMapper"]
OLM["OperationLogMapper"]
ENLM["ExpireNotifyLogMapper"]
end
A --> US
RC --> RS
RC --> RRS
PC --> PS
DC --> DS
UC --> US
RTC --> RS
PRC --> RS
LC --> OLS
RS --> RM
RS --> PRM
PS --> PM
PS --> PRM
US --> UM
RRS --> RRM
RRS --> RM
DS --> RM
DS --> PM
OLS --> OLM
RS --> OLS
ES --> SMTP["SMTP"]
JWT --> SC
```
---
## 二、数据模型关系图
### 2.1 ER 图
```mermaid
erDiagram
sys_user ||--o{ resource : "负责"
sys_user ||--o{ project : "负责"
sys_user ||--o{ operation_log : "操作"
project ||--o{ project : "父子(两层)"
project ||--o{ project_resource : "关联"
resource ||--o{ project_resource : "关联"
resource ||--o{ resource_renewal : "续费"
resource ||--o{ expire_notify_log : "提醒"
resource }o--|| resource_type : "类型"
resource }o--|| provider : "服务商"
sys_user {
int id PK
varchar username
varchar password
varchar real_name
varchar email
int role "1=管理员 2=普通"
int status "0=禁用 1=启用"
}
resource {
int id PK
varchar name
int type_id FK
int provider_id FK
int owner_id FK
date start_date
date expire_date
decimal cost
int cost_cycle "1=月 2=年 3=一次性"
int status "0停用 1使用中 2即将到期 3已过期"
int purchase_duration
varchar account_info
varchar remark
}
project {
int id PK
varchar name
int parent_id FK "NULL=顶层"
int owner_id FK
int status "0=下线 1=进行中"
varchar remark
}
project_resource {
int id PK
int project_id FK
int resource_id FK
decimal allocation_percent "分摊占比"
}
resource_type {
int id PK
varchar name
int sort
varchar remark
}
provider {
int id PK
varchar name
varchar remark
}
resource_renewal {
int id PK
int resource_id FK
date old_expire_date
date new_expire_date
int duration_code
decimal cost
varchar remark
int operator_id FK
}
expire_notify_log {
int id PK
int resource_id FK
varchar stage "far/near/expired"
date notify_date
varchar send_to
}
operation_log {
int id PK
int user_id FK
varchar module
varchar operation
varchar detail
}
```
### 2.2 核心关联关系说明
| 关系 | 类型 | 说明 |
|------|------|------|
| resource ↔ resource_type | 多对一 | 每个资源属于一个类型 |
| resource ↔ provider | 多对一 | 每个资源属于一个服务商 |
| resource ↔ sys_user (owner) | 多对一 | 每个资源有一个负责人 |
| resource ↔ project | 多对多 | 通过 project_resource 关联,支持费用分摊 |
| project_resource.allocation_percent | 分摊占比 | 同一资源在不同项目间按比例分摊费用 |
| project ↔ project (parent) | 自关联 | 两层结构:顶层项目 + 子项目 |
| resource ↔ resource_renewal | 一对多 | 一个资源可有多条续费记录 |
| resource ↔ expire_notify_log | 一对多 | 三阶段提醒记录(far/near/expired) |
---
## 三、核心业务流程图
### 3.1 用户认证流程
```mermaid
sequenceDiagram
participant U as 浏览器
participant F as 前端 (Vue)
participant S as 后端 (Spring Boot)
participant DB as MySQL
U->>F: 输入用户名/密码
F->>S: POST /auth/login {username, password}
S->>DB: 查询用户信息
DB-->>S: sys_user 记录
alt 账号不存在 / 已禁用
S-->>F: {code: 401, message: "账号不存在或已禁用"}
end
alt 连续失败 ≥ 5 次(15 分钟内)
S-->>F: {code: 401, message: "账号已锁定,请 15 分钟后重试"}
end
alt 密码错误
S->>DB: 记录失败次数
S-->>F: {code: 401, message: "密码错误"}
end
alt 认证成功
S->>S: 生成 JWT Token (HS256, 24h)
S->>DB: 清除失败计数
S-->>F: {code: 200, data: {token, userId, username, role}}
F->>F: 存储 token 到 localStorage
F->>F: Pinia store 更新用户状态
F-->>U: 跳转至 Dashboard
end
Note over U,DB: 后续请求
U->>F: 操作页面
F->>S: 请求头 Authorization: Bearer
S->>S: JwtAuthenticationFilter 校验 Token
alt Token 有效
S->>S: 设置 SecurityContext
S-->>F: 返回业务数据
else Token 过期/无效
S-->>F: 401 Unauthorized
F->>F: 清除 token,跳转登录页
end
```
### 3.2 权限控制模型
```mermaid
graph TD
Login["用户登录"] --> JWT["获取 JWT Token"]
JWT --> Filter["JwtAuthenticationFilter"]
Filter -->|每次请求| Check{"Token 有效?"}
Check -->|否| Reject["401 → 跳转登录"]
Check -->|是| Load["加载 LoginUser
(role, status)"]
Load --> SecConfig["SecurityConfig 规则匹配"]
SecConfig --> R1["/auth/login → 公开"]
SecConfig --> R2["/user/enabled-list → 登录即可"]
SecConfig --> R3["/user/** → ROLE_ADMIN"]
SecConfig --> R4["POST/DELETE /resource-type/** → ROLE_ADMIN"]
SecConfig --> R5["POST/DELETE /provider/** → ROLE_ADMIN"]
SecConfig --> R6["其他接口 → 登录即可"]
R1 --> Pass["放行"]
R2 --> Pass
R3 --> Admin{"isAdmin?"}
R4 --> Admin
R5 --> Admin
R6 --> Pass
Admin -->|是| Pass
Admin -->|否| Deny["403 Forbidden"]
```
### 3.3 资源生命周期
```mermaid
stateDiagram-v2
[*] --> 使用中: 创建资源
(expire_date > 今天)
[*] --> 已过期: 创建资源
(expire_date ≤ 今天)
使用中 --> 即将到期: 定时任务扫描
(距到期 ≤ 30 天)
即将到期 --> 即将到期: 定时任务扫描
(距到期 ≤ 7 天)
即将到期 --> 已过期: 超过到期日
使用中 --> 已过期: 超过到期日
已过期 --> 使用中: 续费
(新到期日 > 今天)
已过期 --> 即将到期: 续费
(新到期日在 30 天内)
使用中 --> 已停用: 手动停用
即将到期 --> 已停用: 手动停用
已停用 --> 使用中: 重新启用
(更新到期日)
使用中 --> [*]: 删除资源
即将到期 --> [*]: 删除资源
已过期 --> [*]: 删除资源
已停用 --> [*]: 删除资源
```
### 3.4 资源续费流程
```mermaid
sequenceDiagram
participant U as 用户
participant F as 前端
participant C as ResourceController
participant RRS as ResourceRenewalService
participant RS as ResourceService
participant DB as MySQL
U->>F: 点击"续费",填写续费表单
Note over U,F: 续费日期、新到期日、时长、金额、备注
F->>C: POST /resource/{id}/renew
C->>RRS: renewResource(id, dto)
RRS->>DB: 查询当前资源信息
DB-->>RRS: Resource 记录
RRS->>RRS: 校验:新到期日 > 当前到期日
alt 校验失败
RRS-->>C: 抛出 BusinessException
C-->>F: {code: 400, message: "新到期日必须晚于当前到期日"}
end
RRS->>DB: INSERT resource_renewal
RRS->>DB: UPDATE resource.expire_date = 新到期日
RRS->>RS: 刷新资源状态
RS->>DB: 根据新到期日计算 status
Note over RS,DB: 使用中 / 即将到期
RRS-->>C: 续费成功
C->>C: 记录操作日志
C-->>F: {code: 200}
F->>F: 刷新详情页 + 续费历史列表
```
### 3.5 到期提醒定时任务
```mermaid
flowchart TD
Start["定时触发
每天 08:00
cron: 0 0 8 * * ?"] --> Refresh["刷新所有资源状态
refreshExpireStatus()"]
Refresh --> Scan["扫描需要提醒的资源"]
Scan --> Check30{"距到期 ≤ 30 天
且 > 7 天?"}
Scan --> Check7{"距到期 ≤ 7 天
且 > 0 天?"}
Scan --> CheckExpired{"已过期
expire_date < 今天?"}
Check30 -->|是| Log30{"已发过 far 提醒?"}
Check30 -->|否| Skip1["跳过"]
Check7 -->|是| Log7{"已发过 near 提醒?"}
Check7 -->|否| Skip2["跳过"]
CheckExpired -->|是| LogExp{"已发过 expired 提醒?"}
CheckExpired -->|否| Skip3["跳过"]
Log30 -->|未发| Send30["发送邮件
stage=far
普通提醒"]
Log30 -->|已发| Skip1
Log7 -->|未发| Send7["发送邮件
stage=near
紧急提醒"]
Log7 -->|已发| Skip2
LogExp -->|未发| SendExp["发送邮件
stage=expired
过期通知"]
LogExp -->|已发| Skip3
Send30 --> Record30["INSERT expire_notify_log
stage=far"]
Send7 --> Record7["INSERT expire_notify_log
stage=near"]
SendExp --> RecordExp["INSERT expire_notify_log
stage=expired"]
Record30 --> End["完成"]
Record7 --> End
RecordExp --> End
Skip1 --> End
Skip2 --> End
Skip3 --> End
```
### 3.6 费用分摊计算流程
```mermaid
flowchart TD
Start["资源关联多个项目"] --> Input["用户选择关联项目"]
Input --> Mode{"分摊模式"}
Mode -->|均分| Calc1["每个项目 = 100% / N
尾差加到最后一个"]
Mode -->|自定义| Calc2["用户手动输入各占比
合计必须 = 100%"]
Calc1 --> Save["保存到 project_resource
allocation_percent"]
Calc2 --> Validate{"合计 = 100%?"}
Validate -->|否| Error["提示:分摊占比合计必须为 100%"]
Validate -->|是| Save
Save --> Stat["费用统计时"]
Stat --> Formula["分摊费用 = 资源总费用 ×
allocation_percent / 100"]
Formula --> Report["生成费用报表
按项目 / 按类型"]
```
---
## 四、项目管理流程
### 4.1 项目树形结构
```mermaid
graph TD
subgraph 两层项目模型
P1["顶层项目 A"]
P1 --> C1["子项目 A-1"]
P1 --> C2["子项目 A-2"]
P2["顶层项目 B"]
P2 --> C3["子项目 B-1"]
P3["顶层项目 C
(无子项目)"]
end
C1 --> R1["资源 1"]
C1 --> R2["资源 2"]
C2 --> R3["资源 3"]
C3 --> R4["资源 4"]
P3 --> R5["资源 5"]
style P1 fill:#409eff,color:#fff
style P2 fill:#409eff,color:#fff
style P3 fill:#409eff,color:#fff
style C1 fill:#67c23a,color:#fff
style C2 fill:#67c23a,color:#fff
style C3 fill:#67c23a,color:#fff
```
> **规则**:资源只挂在叶子节点(子项目或无子项目的顶层项目)。父项目的资源统计 = 所有子项目资源的聚合。
### 4.2 项目新增/编辑流程
```mermaid
flowchart TD
Start["用户点击新增/编辑"] --> Form["弹窗表单"]
Form --> Fields["名称 / 父项目 / 负责人 / 状态 / 备注"]
Fields --> Submit["提交"]
Submit --> Check{"有父项目?"}
Check -->|是| Leaf["标记为子项目
parent_id = 选中值"]
Check -->|否| Root["标记为顶层项目
parent_id = NULL"]
Leaf --> Save["保存到 project 表"]
Root --> Save
Save --> Edit{"编辑模式?"}
Edit -->|是| Update["UPDATE + 保留子项目关系"]
Edit -->|否| Insert["INSERT"]
Update --> Done["刷新列表"]
Insert --> Done
```
---
## 五、前端页面结构
### 5.1 页面导航树
```mermaid
graph TD
App["App.vue"] --> Login["/login
Login.vue"]
App --> Layout["Layout.vue
侧边栏 + 顶栏"]
Layout --> Dashboard["/dashboard
工作台"]
Layout --> Resource["/resource
资源台账"]
Layout --> ResourceDetail["/resource/:id
资源详情"]
Layout --> Project["/project
项目管理"]
Layout --> ProjectDetail["/project/:id
项目详情"]
Layout --> CostStat["/cost-stat
费用统计"]
Layout --> ProcurementCost["/procurement-cost
采购费用"]
Layout --> Dict["/dict
字典管理"]
Layout --> User["/user
用户管理 🔒"]
Layout --> Log["/log
操作日志"]
Dashboard --> KPI["6 个 KPI 卡片"]
Dashboard --> Chart1["项目状态环形图"]
Dashboard --> Chart2["资源类型分布条形图"]
Dashboard --> Table["风险清单表格"]
CostStat --> Chart3["资源类型费用环形图"]
CostStat --> Chart4["项目预算消耗排行"]
CostStat --> Chart5["各类型费用条形图"]
CostStat --> Chart6["项目资源数对比"]
Dict --> Tab1["资源类型 Tab"]
Dict --> Tab2["服务商 Tab"]
style User fill:#e6a23c,color:#fff
```
### 5.2 前端组件依赖
```mermaid
graph LR
subgraph 页面组件
RL["ResourceList"]
RF["ResourceForm"]
RD["ResourceDetail"]
PL["ProjectList"]
PD["ProjectDetail"]
DSH["Dashboard"]
CS["CostStat"]
PC["ProcurementCost"]
end
subgraph 组合式函数
UC["useChart()
ECharts 封装"]
USR["useScrollRestore()
滚动恢复"]
end
subgraph 工具
CSV["exportCsv()"]
CC["getChartColors()"]
SC["statusClass()"]
end
subgraph API
RA["api/resource"]
PA["api/project"]
DA["api/dashboard"]
end
subgraph Store
ST["store/user"]
end
RL --> RF
RL --> RA
RL --> SC
RD --> RA
PL --> PA
PD --> PA
DSH --> DA
DSH --> UC
DSH --> CSV
CS --> RA
CS --> UC
CS --> CSV
PC --> RA
PC --> CSV
UC --> CC
RL --> USR
```
---
## 六、部署架构
### 6.1 生产部署拓扑
```mermaid
graph TB
subgraph 客户端
Browser2["浏览器"]
end
subgraph Nginx["Nginx (resource.mizentech.com:80)"]
Frontend["前端静态资源
/opt/resource-platform/frontend/dist/"]
APIProxy["/api/ 反代
→ 127.0.0.1:8080"]
end
subgraph Backend["Spring Boot (127.0.0.1:8080)"]
App["resource-platform.jar
--spring.profiles.active=prod"]
end
subgraph Data["数据层"]
RDS["MySQL 8.0+
resource_platform"]
Mail2["SMTP 邮件服务器
smtp.qiye.aliyun.com:465"]
end
subgraph 配置
Env[".env (chmod 600)
DB_URL / JWT_SECRET
MAIL_* / CORS_ORIGINS"]
Systemd["systemd 服务
自动重启 / 开机自启"]
end
Browser2 -->|HTTP| Nginx
Nginx -->|/| Frontend
Nginx -->|/api/*| APIProxy
APIProxy --> App
App --> RDS
App --> Mail2
Env --> App
Systemd --> App
```
### 6.2 环境配置对比
```mermaid
graph LR
subgraph 开发环境
Dev["application-dev.yml"]
DevDB["阿里云 RDS
明文密码"]
DevMail["smtp.example.com
占位配置"]
DevLog["日志级别: DEBUG"]
DevCORS["CORS: localhost:5173"]
end
subgraph 生产环境
Prod["application-prod.yml"]
ProdDB["环境变量注入
DB_URL / DB_PASSWORD"]
ProdMail["smtp.qiye.aliyun.com
企业邮箱"]
ProdLog["日志级别: INFO"]
ProdCORS["CORS: resource.mizentech.com"]
end
Dev --> DevDB
Dev --> DevMail
Dev --> DevLog
Dev --> DevCORS
Prod --> ProdDB
Prod --> ProdMail
Prod --> ProdLog
Prod --> ProdCORS
```
---
## 七、API 接口全景
### 7.1 接口分组总览
```mermaid
graph TD
subgraph 认证模块
A1["POST /auth/login"]
A2["GET /auth/me"]
A3["PUT /auth/password"]
end
subgraph 资源管理
R1["GET /resource/page"]
R2["GET /resource/{id}"]
R3["POST /resource"]
R4["DELETE /resource/{id}"]
R5["POST /resource/relate"]
R6["DELETE /resource/unrelate"]
R7["POST /resource/{id}/renew"]
R8["GET /resource/{id}/renewals"]
R9["DELETE /resource/{id}/renewals/{rid}"]
R10["GET /resource/export"]
end
subgraph 费用统计
C1["GET /resource/cost-stat/project"]
C2["GET /resource/cost-stat/type"]
C3["GET /resource/procurement-cost"]
C4["GET /resource/procurement-cost/export"]
end
subgraph 项目管理
P1["GET /project/page"]
P2["GET /project/tree"]
P3["GET /project/{id}"]
P4["POST /project"]
P5["DELETE /project/{id}"]
P6["GET /project/active-list"]
P7["GET /project/parent-options"]
end
subgraph 工作台
D1["GET /dashboard"]
end
subgraph 系统管理 🔒
U1["GET /user/list"]
U2["GET /user/enabled-list"]
U3["POST /user"]
U4["DELETE /user/{id}"]
T1["GET /resource-type/list"]
T2["POST /resource-type"]
T3["DELETE /resource-type/{id}"]
V1["GET /provider/list"]
V2["POST /provider"]
V3["DELETE /provider/{id}"]
L1["GET /operation-log/page"]
end
```
---
## 八、技术栈依赖关系
```mermaid
graph TD
subgraph 前端依赖
Vue["Vue 3.4"] --> VRouter["Vue Router 4.3"]
Vue --> Pinia["Pinia 2.1"]
Vue --> EP["Element Plus 2.6"]
Vue --> ECharts["ECharts 6.1"]
Vue --> Axios["Axios 1.6"]
Vue --> DayJS["Day.js 1.11"]
end
subgraph 后端依赖
SB["Spring Boot 3.2.5"] --> SS["Spring Security 6.2"]
SB --> MBP["MyBatis-Plus 3.5.5"]
SB --> SM["Spring Mail"]
SB --> SV["Spring Validation"]
SS --> JWT["JJWT 0.11.5"]
MBP --> MySQL["MySQL Connector 8.3"]
SB --> EE["EasyExcel 3.3.2"]
SB --> Lombok["Lombok 1.18.32"]
end
subgraph 构建工具
Vite["Vite 5.1"]
Maven["Maven"]
Vitest["Vitest 4.1"]
JUnit["JUnit 5 + Mockito"]
end
```