|
|
@@ -0,0 +1,761 @@
|
|
|
+# 系统架构与业务流程图
|
|
|
+
|
|
|
+> 基于项目源码自动生成,所有图表均使用 Mermaid 语法,可在支持 Mermaid 的 Markdown 编辑器中渲染。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、系统整体架构
|
|
|
+
|
|
|
+### 1.1 分层架构总览
|
|
|
+
|
|
|
+```mermaid
|
|
|
+graph TB
|
|
|
+ subgraph 用户层
|
|
|
+ Browser["浏览器<br/>(Chrome / Edge)"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 前端["前端 · Vue 3 + Vite"]
|
|
|
+ Router["Vue Router<br/>路由守卫 / 权限控制"]
|
|
|
+ Views["页面组件<br/>Dashboard / Resource / Project ..."]
|
|
|
+ Store["Pinia Store<br/>用户状态 / Token"]
|
|
|
+ API["Axios API 层<br/>request.js 统一拦截"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 反向代理["Nginx 反向代理"]
|
|
|
+ Static["静态资源托管<br/>dist/"]
|
|
|
+ Proxy["/api/ → :8080<br/>API 反代"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 后端["后端 · Spring Boot 3"]
|
|
|
+ Controller["Controller 层<br/>REST 接口"]
|
|
|
+ Security["Spring Security<br/>JWT 认证 + 权限"]
|
|
|
+ Service["Service 层<br/>核心业务逻辑"]
|
|
|
+ Mapper["Mapper 层<br/>MyBatis-Plus"]
|
|
|
+ Task["定时任务<br/>ResourceExpireTask"]
|
|
|
+ Mail["邮件服务<br/>EmailService"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 数据层
|
|
|
+ MySQL["MySQL 8.0+<br/>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<br/>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 <token>
|
|
|
+ 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<br/>(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
|
|
|
+ [*] --> 使用中: 创建资源<br/>(expire_date > 今天)
|
|
|
+ [*] --> 已过期: 创建资源<br/>(expire_date ≤ 今天)
|
|
|
+
|
|
|
+ 使用中 --> 即将到期: 定时任务扫描<br/>(距到期 ≤ 30 天)
|
|
|
+ 即将到期 --> 即将到期: 定时任务扫描<br/>(距到期 ≤ 7 天)
|
|
|
+ 即将到期 --> 已过期: 超过到期日
|
|
|
+ 使用中 --> 已过期: 超过到期日
|
|
|
+
|
|
|
+ 已过期 --> 使用中: 续费<br/>(新到期日 > 今天)
|
|
|
+ 已过期 --> 即将到期: 续费<br/>(新到期日在 30 天内)
|
|
|
+
|
|
|
+ 使用中 --> 已停用: 手动停用
|
|
|
+ 即将到期 --> 已停用: 手动停用
|
|
|
+ 已停用 --> 使用中: 重新启用<br/>(更新到期日)
|
|
|
+
|
|
|
+ 使用中 --> [*]: 删除资源
|
|
|
+ 即将到期 --> [*]: 删除资源
|
|
|
+ 已过期 --> [*]: 删除资源
|
|
|
+ 已停用 --> [*]: 删除资源
|
|
|
+```
|
|
|
+
|
|
|
+### 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["定时触发<br/>每天 08:00<br/>cron: 0 0 8 * * ?"] --> Refresh["刷新所有资源状态<br/>refreshExpireStatus()"]
|
|
|
+ Refresh --> Scan["扫描需要提醒的资源"]
|
|
|
+
|
|
|
+ Scan --> Check30{"距到期 ≤ 30 天<br/>且 > 7 天?"}
|
|
|
+ Scan --> Check7{"距到期 ≤ 7 天<br/>且 > 0 天?"}
|
|
|
+ Scan --> CheckExpired{"已过期<br/>expire_date < 今天?"}
|
|
|
+
|
|
|
+ Check30 -->|是| Log30{"已发过 far 提醒?"}
|
|
|
+ Check30 -->|否| Skip1["跳过"]
|
|
|
+ Check7 -->|是| Log7{"已发过 near 提醒?"}
|
|
|
+ Check7 -->|否| Skip2["跳过"]
|
|
|
+ CheckExpired -->|是| LogExp{"已发过 expired 提醒?"}
|
|
|
+ CheckExpired -->|否| Skip3["跳过"]
|
|
|
+
|
|
|
+ Log30 -->|未发| Send30["发送邮件<br/>stage=far<br/>普通提醒"]
|
|
|
+ Log30 -->|已发| Skip1
|
|
|
+ Log7 -->|未发| Send7["发送邮件<br/>stage=near<br/>紧急提醒"]
|
|
|
+ Log7 -->|已发| Skip2
|
|
|
+ LogExp -->|未发| SendExp["发送邮件<br/>stage=expired<br/>过期通知"]
|
|
|
+ LogExp -->|已发| Skip3
|
|
|
+
|
|
|
+ Send30 --> Record30["INSERT expire_notify_log<br/>stage=far"]
|
|
|
+ Send7 --> Record7["INSERT expire_notify_log<br/>stage=near"]
|
|
|
+ SendExp --> RecordExp["INSERT expire_notify_log<br/>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<br/>尾差加到最后一个"]
|
|
|
+ Mode -->|自定义| Calc2["用户手动输入各占比<br/>合计必须 = 100%"]
|
|
|
+
|
|
|
+ Calc1 --> Save["保存到 project_resource<br/>allocation_percent"]
|
|
|
+ Calc2 --> Validate{"合计 = 100%?"}
|
|
|
+ Validate -->|否| Error["提示:分摊占比合计必须为 100%"]
|
|
|
+ Validate -->|是| Save
|
|
|
+
|
|
|
+ Save --> Stat["费用统计时"]
|
|
|
+ Stat --> Formula["分摊费用 = 资源总费用 ×<br/>allocation_percent / 100"]
|
|
|
+ Formula --> Report["生成费用报表<br/>按项目 / 按类型"]
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、项目管理流程
|
|
|
+
|
|
|
+### 4.1 项目树形结构
|
|
|
+
|
|
|
+```mermaid
|
|
|
+graph TD
|
|
|
+ subgraph 两层项目模型
|
|
|
+ P1["顶层项目 A"]
|
|
|
+ P1 --> C1["子项目 A-1"]
|
|
|
+ P1 --> C2["子项目 A-2"]
|
|
|
+
|
|
|
+ P2["顶层项目 B"]
|
|
|
+ P2 --> C3["子项目 B-1"]
|
|
|
+
|
|
|
+ P3["顶层项目 C<br/>(无子项目)"]
|
|
|
+ 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["标记为子项目<br/>parent_id = 选中值"]
|
|
|
+ Check -->|否| Root["标记为顶层项目<br/>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<br/>Login.vue"]
|
|
|
+ App --> Layout["Layout.vue<br/>侧边栏 + 顶栏"]
|
|
|
+
|
|
|
+ Layout --> Dashboard["/dashboard<br/>工作台"]
|
|
|
+ Layout --> Resource["/resource<br/>资源台账"]
|
|
|
+ Layout --> ResourceDetail["/resource/:id<br/>资源详情"]
|
|
|
+ Layout --> Project["/project<br/>项目管理"]
|
|
|
+ Layout --> ProjectDetail["/project/:id<br/>项目详情"]
|
|
|
+ Layout --> CostStat["/cost-stat<br/>费用统计"]
|
|
|
+ Layout --> ProcurementCost["/procurement-cost<br/>采购费用"]
|
|
|
+ Layout --> Dict["/dict<br/>字典管理"]
|
|
|
+ Layout --> User["/user<br/>用户管理 🔒"]
|
|
|
+ Layout --> Log["/log<br/>操作日志"]
|
|
|
+
|
|
|
+ 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()<br/>ECharts 封装"]
|
|
|
+ USR["useScrollRestore()<br/>滚动恢复"]
|
|
|
+ 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["前端静态资源<br/>/opt/resource-platform/frontend/dist/"]
|
|
|
+ APIProxy["/api/ 反代<br/>→ 127.0.0.1:8080"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph Backend["Spring Boot (127.0.0.1:8080)"]
|
|
|
+ App["resource-platform.jar<br/>--spring.profiles.active=prod"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph Data["数据层"]
|
|
|
+ RDS["MySQL 8.0+<br/>resource_platform"]
|
|
|
+ Mail2["SMTP 邮件服务器<br/>smtp.qiye.aliyun.com:465"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 配置
|
|
|
+ Env[".env (chmod 600)<br/>DB_URL / JWT_SECRET<br/>MAIL_* / CORS_ORIGINS"]
|
|
|
+ Systemd["systemd 服务<br/>自动重启 / 开机自启"]
|
|
|
+ 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<br/>明文密码"]
|
|
|
+ DevMail["smtp.example.com<br/>占位配置"]
|
|
|
+ DevLog["日志级别: DEBUG"]
|
|
|
+ DevCORS["CORS: localhost:5173"]
|
|
|
+ end
|
|
|
+
|
|
|
+ subgraph 生产环境
|
|
|
+ Prod["application-prod.yml"]
|
|
|
+ ProdDB["环境变量注入<br/>DB_URL / DB_PASSWORD"]
|
|
|
+ ProdMail["smtp.qiye.aliyun.com<br/>企业邮箱"]
|
|
|
+ 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
|
|
|
+```
|