fundplatform/doc/数据库设计文档.md
zhangjf 46e30c8b06 优化用户登录密码加密方式:从 BCrypt 改为 MD5
主要变更:
1. 新增 Md5Util 工具类,提供 MD5 加密和密码验证方法
2. 修改 AuthServiceImpl 直接比对 MD5 值(前端已加密,无需再次加密)
3. 修改 UserServiceImpl 使用 MD5 加密用户密码
4. 前端 Login.vue 添加 MD5 加密函数,提交前对密码进行 MD5 加密
5. 更新数据库初始化脚本,将 admin 密码改为 MD5 值
6. 更新设计文档中的密码加密说明
7. 添加 Lombok 依赖到 fund-sys 模块
8. 增加日志打印,记录密码加密过程便于调试

技术细节:
- 前端流程:用户输入 → MD5 加密 → 传递给后端
- 后端流程:接收 MD5 值 → 与数据库 MD5 值直接 equals 比对
- 默认管理员密码:admin/admin123,MD5: 0192023a7bbd73250516f069df18b500
2026-02-28 06:51:20 +08:00

803 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 资金服务平台数据库设计文档
> 版本: v1.1
> 更新日期: 2026-02-22
> 作者: zhangjf
> 数据库: MySQL 8.0
> 字符集: utf8mb4
---
## 一、数据库概览
### 1.1 数据库信息
| 项目 | 值 |
|------|-----|
| 数据库名 | fund_platform |
| 字符集 | utf8mb4 |
| 排序规则 | utf8mb4_unicode_ci |
| 存储引擎 | InnoDB |
| 时区 | +08:00 |
### 1.2 表清单
| 模块 | 表名 | 说明 | 记录数 |
|------|------|------|--------|
| **系统管理** | sys_tenant | 租户表 | 2 |
| | sys_dept | 部门表 | 7 |
| | sys_user | 用户表 | 6 |
| | sys_role | 角色表 | 7 |
| | sys_menu | 菜单表 | 38 |
| | sys_user_role | 用户角色关联表 | 6 |
| | sys_role_menu | 角色菜单关联表 | 动态 |
| | sys_operation_log | 操作日志表 | 动态 |
| **客户管理** | customer | 客户表 | 3 |
| | customer_contact | 客户联系人表 | 0 |
| **项目管理** | project | 项目表 | 3 |
| | project_member | 项目成员表 | 6 |
| **需求工单** | requirement | 需求工单表 | 0 |
| **支出管理** | expense_type | 支出类型表 | 12 |
| | expense | 支出表 | 0 |
| **应收款管理** | receivable | 应收款表 | 0 |
| | receipt | 收款记录表 | 0 |
---
## 二、ER 图
```
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ 资金服务平台数据库 ER 图 │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ sys_tenant │ │ sys_user │ │ sys_role │ │
│ │ (租户表) │ │ (用户表) │ │ (角色表) │ │
│ ├──────────────┤ ├──────────────┤ ├──────────────┤ │
│ │ PK tenant_id │◄────────┤ FK tenant_id │ │ FK tenant_id │ │
│ │ code │ │ PK user_id │◄───────►│ PK role_id │ │
│ │ name │ │ username │ │ code │ │
│ │ type │ │ password │ │ name │ │
│ │ status │ │ real_name │ │ type │ │
│ └──────────────┘ │ dept_id │────────►│ scope │ │
│ │ status │ └──────────────┘ │
│ └──────────────┘ ▲ │
│ ▲ │ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ sys_dept │ │sys_user_role│ │
│ │ (部门表) │ │(用户角色关联)│ │
│ ├─────────────┤ ├─────────────┤ │
│ │ PK dept_id │ │ PK id │ │
│ │ FK tenant_id│ │ FK user_id │ │
│ │ name │ │ FK role_id │ │
│ │ parent_id │ └─────────────┘ │
│ └─────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ customer │ │ project │ │ requirement │ │
│ │ (客户表) │ │ (项目表) │ │ (需求工单表) │ │
│ ├──────────────┤ ├──────────────┤ ├──────────────┤ │
│ │ PK customer_id│◄───────┤ FK customer_id│◄───────┤ FK customer_id│ │
│ │ FK tenant_id │ │ FK tenant_id │ │ FK tenant_id │ │
│ │ code │ │ PK project_id│◄───────┤ FK project_id│ │
│ │ name │ │ code │ │ PK req_id │ │
│ │ type │ │ name │ │ code │ │
│ │ level │ │ manager_id│ │ name │ │
│ └──────────────┘ │ status │ │ amount │ │
│ │ └──────────────┘ │ status │ │
│ │ ▲ └──────────────┘ │
│ │ │ │
│ │ ┌──────┴──────┐ │
│ │ │project_member│ │
│ │ │(项目成员表) │ │
│ │ ├─────────────┤ │
│ │ │ PK member_id│ │
│ │ │ FK project_id│ │
│ │ │ FK user_id │ │
│ │ │ role │ │
│ │ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │customer_contact│ │
│ │(客户联系人表) │ │
│ ├──────────────┤ │
│ │ PK contact_id │ │
│ │ FK customer_id│ │
│ │ name │ │
│ │ phone │ │
│ │ is_primary │ │
│ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ expense_type │ │ expense │ │ receivable │ │
│ │ (支出类型表) │ │ (支出表) │ │ (应收款表) │ │
│ ├──────────────┤ ├──────────────┤ ├──────────────┤ │
│ │ PK type_id │◄────────┤ FK type_id │ │ PK receiv_id │ │
│ │ FK tenant_id │ │ FK tenant_id │ │ FK tenant_id │ │
│ │ code │ │ PK expense_id│ │ FK project_id│ │
│ │ name │ │ code │ │ FK customer_id│ │
│ │ parent_id │ │ amount │ │ FK req_id │ │
│ └──────────────┘ │ date │ │ amount │ │
│ │ status │ │ status │ │
│ └──────────────┘ └──────┬───────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ receipt │ │
│ │ (收款记录表) │ │
│ ├─────────────┤ │
│ │ PK receipt_id│ │
│ │ FK receiv_id │ │
│ │ amount │ │
│ │ date │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────┘
```
---
## 三、表结构详细说明
### 3.1 系统管理模块
#### 3.1.1 sys_tenant租户表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| tenant_id | BIGINT | - | 是 | 自增 | 主键租户ID |
| tenant_code | VARCHAR | 50 | 是 | - | 租户编码(唯一) |
| tenant_name | VARCHAR | 100 | 是 | - | 租户名称 |
| tenant_type | TINYINT | - | 否 | 1 | 租户类型1-一库多租户2-一库一租户 |
| contact_name | VARCHAR | 50 | 否 | - | 联系人姓名 |
| contact_phone | VARCHAR | 20 | 否 | - | 联系人电话 |
| contact_email | VARCHAR | 100 | 否 | - | 联系人邮箱 |
| db_config | JSON | - | 否 | - | 数据库配置(一库一租户模式使用) |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| expire_time | DATETIME | - | 否 | - | 过期时间 |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
**索引:**
- PRIMARY KEY (`tenant_id`)
- UNIQUE KEY `uk_code` (`tenant_code`)
- INDEX `idx_status` (`status`)
---
#### 3.1.2 sys_dept部门表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| dept_id | BIGINT | - | 是 | 自增 | 主键部门ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| dept_name | VARCHAR | 100 | 是 | - | 部门名称 |
| parent_id | BIGINT | - | 否 | 0 | 父部门ID0表示顶级部门 |
| dept_code | VARCHAR | 50 | 否 | - | 部门编码 |
| dept_level | INT | - | 否 | 1 | 部门层级 |
| sort_order | INT | - | 否 | 0 | 排序顺序 |
| leader | VARCHAR | 50 | 否 | - | 部门负责人 |
| leader_phone | VARCHAR | 20 | 否 | - | 负责人电话 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`dept_id`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_parent` (`parent_id`)
- INDEX `idx_status` (`status`)
---
#### 3.1.3 sys_user用户表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| user_id | BIGINT | - | 是 | 自增 | 主键用户ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| username | VARCHAR | 50 | 是 | - | 用户名(登录账号) |
| password | VARCHAR | 100 | 是 | - | 密码MD5 加密存储) |
| real_name | VARCHAR | 50 | 是 | - | 真实姓名 |
| gender | TINYINT | - | 否 | 0 | 性别0-未知1-男2-女 |
| phone | VARCHAR | 20 | 否 | - | 手机号码 |
| email | VARCHAR | 100 | 否 | - | 邮箱地址 |
| dept_id | BIGINT | - | 否 | - | 所属部门ID外键 |
| position | VARCHAR | 50 | 否 | - | 岗位/职位 |
| avatar | VARCHAR | 255 | 否 | - | 头像URL |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| last_login_time | DATETIME | - | 否 | - | 最后登录时间 |
| last_login_ip | VARCHAR | 50 | 否 | - | 最后登录IP |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`user_id`)
- UNIQUE KEY `uk_tenant_username` (`tenant_id`, `username`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_dept` (`dept_id`)
- INDEX `idx_status` (`status`)
---
#### 3.1.4 sys_role角色表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| role_id | BIGINT | - | 是 | 自增 | 主键角色ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| role_code | VARCHAR | 50 | 是 | - | 角色编码 |
| role_name | VARCHAR | 100 | 是 | - | 角色名称 |
| role_type | VARCHAR | 20 | 否 | custom | 角色类型system-系统角色custom-自定义角色 |
| data_scope | VARCHAR | 20 | 否 | self | 数据范围all-全部dept-本部门self-本人 |
| sort_order | INT | - | 否 | 0 | 排序顺序 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`role_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `role_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_status` (`status`)
---
#### 3.1.5 sys_menu菜单表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| menu_id | BIGINT | - | 是 | 自增 | 主键菜单ID |
| tenant_id | BIGINT | - | 否 | 0 | 租户ID0表示系统通用菜单 |
| menu_name | VARCHAR | 100 | 是 | - | 菜单名称 |
| menu_type | VARCHAR | 20 | 是 | - | 菜单类型dir-目录menu-菜单button-按钮 |
| parent_id | BIGINT | - | 否 | 0 | 父菜单ID0表示顶级菜单 |
| menu_level | INT | - | 否 | 1 | 菜单层级 |
| icon | VARCHAR | 100 | 否 | - | 菜单图标 |
| path | VARCHAR | 200 | 否 | - | 路由路径 |
| component | VARCHAR | 200 | 否 | - | 组件路径 |
| permission | VARCHAR | 100 | 否 | - | 权限标识user:list |
| sort_order | INT | - | 否 | 0 | 排序顺序 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`menu_id`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_parent` (`parent_id`)
- INDEX `idx_type` (`menu_type`)
- INDEX `idx_status` (`status`)
---
#### 3.1.6 sys_user_role用户角色关联表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| id | BIGINT | - | 是 | 自增 | 主键ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| user_id | BIGINT | - | 是 | - | 用户ID外键 |
| role_id | BIGINT | - | 是 | - | 角色ID外键 |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
**索引:**
- PRIMARY KEY (`id`)
- UNIQUE KEY `uk_user_role` (`tenant_id`, `user_id`, `role_id`)
- INDEX `idx_user` (`user_id`)
- INDEX `idx_role` (`role_id`)
---
#### 3.1.7 sys_role_menu角色菜单关联表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| id | BIGINT | - | 是 | 自增 | 主键ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| role_id | BIGINT | - | 是 | - | 角色ID外键 |
| menu_id | BIGINT | - | 是 | - | 菜单ID外键 |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
**索引:**
- PRIMARY KEY (`id`)
- UNIQUE KEY `uk_role_menu` (`tenant_id`, `role_id`, `menu_id`)
- INDEX `idx_role` (`role_id`)
- INDEX `idx_menu` (`menu_id`)
---
#### 3.1.8 sys_operation_log操作日志表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| log_id | BIGINT | - | 是 | 自增 | 主键日志ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| user_id | BIGINT | - | 否 | - | 操作人ID外键 |
| username | VARCHAR | 50 | 否 | - | 操作人用户名 |
| operation | VARCHAR | 100 | 否 | - | 操作描述 |
| method | VARCHAR | 200 | 否 | - | 操作方法 |
| params | TEXT | - | 否 | - | 操作参数JSON格式 |
| ip | VARCHAR | 50 | 否 | - | 操作IP |
| user_agent | VARCHAR | 500 | 否 | - | 用户代理 |
| operation_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 操作时间 |
| cost_time | BIGINT | - | 否 | 0 | 耗时(毫秒) |
| result | VARCHAR | 20 | 否 | success | 操作结果success-成功fail-失败 |
| error_msg | TEXT | - | 否 | - | 错误信息 |
**索引:**
- PRIMARY KEY (`log_id`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_user` (`user_id`)
- INDEX `idx_time` (`operation_time`)
- INDEX `idx_result` (`result`)
---
### 3.2 客户管理模块
#### 3.2.1 customer客户表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| customer_id | BIGINT | - | 是 | 自增 | 主键客户ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| customer_code | VARCHAR | 50 | 是 | - | 客户编码(唯一) |
| customer_name | VARCHAR | 200 | 是 | - | 客户名称 |
| customer_short | VARCHAR | 100 | 否 | - | 客户简称 |
| customer_type | VARCHAR | 20 | 否 | enterprise | 客户类型enterprise-企业individual-个人 |
| industry | VARCHAR | 50 | 否 | - | 所属行业 |
| scale | VARCHAR | 20 | 否 | - | 企业规模small-小型medium-中型large-大型 |
| level | VARCHAR | 20 | 否 | normal | 客户等级A/B/C/D/normal |
| tax_no | VARCHAR | 50 | 否 | - | 纳税人识别号 |
| legal_person | VARCHAR | 50 | 否 | - | 法定代表人 |
| address | VARCHAR | 500 | 否 | - | 公司地址 |
| phone | VARCHAR | 20 | 否 | - | 联系电话 |
| email | VARCHAR | 100 | 否 | - | 邮箱地址 |
| website | VARCHAR | 200 | 否 | - | 公司网站 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| cooperation_start | DATE | - | 否 | - | 合作开始日期 |
| cooperation_end | DATE | - | 否 | - | 合作结束日期 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`customer_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `customer_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_status` (`status`)
- INDEX `idx_level` (`level`)
---
#### 3.2.2 customer_contact客户联系人表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| contact_id | BIGINT | - | 是 | 自增 | 主键联系人ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| customer_id | BIGINT | - | 是 | - | 客户ID外键 |
| contact_name | VARCHAR | 50 | 是 | - | 联系人姓名 |
| position | VARCHAR | 50 | 否 | - | 职位/职务 |
| department | VARCHAR | 100 | 否 | - | 所属部门 |
| phone | VARCHAR | 20 | 否 | - | 联系电话 |
| mobile | VARCHAR | 20 | 否 | - | 手机号码 |
| email | VARCHAR | 100 | 否 | - | 邮箱地址 |
| wechat | VARCHAR | 50 | 否 | - | 微信号 |
| qq | VARCHAR | 20 | 否 | - | QQ号 |
| is_primary | TINYINT | - | 否 | 0 | 是否主要联系人0-否1-是 |
| sort_order | INT | - | 否 | 0 | 排序顺序 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| remark | VARCHAR | 200 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`contact_id`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_customer` (`customer_id`)
- INDEX `idx_status` (`status`)
---
### 3.3 项目管理模块
#### 3.3.1 project项目表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| project_id | BIGINT | - | 是 | 自增 | 主键项目ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| project_code | VARCHAR | 50 | 是 | - | 项目编号(唯一) |
| project_name | VARCHAR | 200 | 是 | - | 项目名称 |
| project_short | VARCHAR | 100 | 否 | - | 项目简称 |
| customer_id | BIGINT | - | 是 | - | 客户ID外键 |
| project_type | VARCHAR | 20 | 否 | development | 项目类型development-开发maintenance-维护consulting-咨询 |
| project_manager_id | BIGINT | - | 否 | - | 项目经理ID外键 |
| start_date | DATE | - | 否 | - | 项目开始日期 |
| end_date | DATE | - | 否 | - | 项目结束日期 |
| budget_amount | DECIMAL | 15,2 | 否 | 0.00 | 项目预算金额 |
| contract_amount | DECIMAL | 15,2 | 否 | 0.00 | 合同金额 |
| status | VARCHAR | 20 | 否 | preparing | 项目状态preparing-筹备中ongoing-进行中completed-已完成archived-已归档cancelled-已取消 |
| progress | INT | - | 否 | 0 | 项目进度0-100 |
| description | TEXT | - | 否 | - | 项目描述 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| attachment_url | VARCHAR | 500 | 否 | - | 附件URL |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`project_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `project_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_customer` (`customer_id`)
- INDEX `idx_manager` (`project_manager_id`)
- INDEX `idx_status` (`status`)
---
#### 3.3.2 project_member项目成员表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| member_id | BIGINT | - | 是 | 自增 | 主键成员关系ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| project_id | BIGINT | - | 是 | - | 项目ID外键 |
| user_id | BIGINT | - | 是 | - | 用户ID外键 |
| role | VARCHAR | 50 | 否 | member | 项目角色pm-项目经理dev-开发test-测试finance-财务member-普通成员 |
| join_date | DATE | - | 否 | - | 加入日期 |
| leave_date | DATE | - | 否 | - | 离开日期 |
| workload | DECIMAL | 5,2 | 否 | 0.00 | 工作量占比0-100 |
| status | TINYINT | - | 否 | 1 | 状态0-已离开1-在职 |
| remark | VARCHAR | 200 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`member_id`)
- UNIQUE KEY `uk_project_user` (`tenant_id`, `project_id`, `user_id`)
- INDEX `idx_project` (`project_id`)
- INDEX `idx_user` (`user_id`)
---
### 3.4 需求工单模块
#### 3.4.1 requirement需求工单表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| requirement_id | BIGINT | - | 是 | 自增 | 主键需求ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| requirement_code | VARCHAR | 50 | 是 | - | 需求编号(唯一) |
| requirement_name | VARCHAR | 200 | 是 | - | 需求名称 |
| description | TEXT | - | 否 | - | 需求描述 |
| project_id | BIGINT | - | 是 | - | 项目ID外键 |
| customer_id | BIGINT | - | 是 | - | 客户ID外键 |
| priority | VARCHAR | 20 | 否 | normal | 优先级high-高normal-中low-低 |
| estimated_hours | DECIMAL | 8,2 | 否 | 0.00 | 预估开发工时(小时) |
| actual_hours | DECIMAL | 8,2 | 否 | 0.00 | 实际开发工时(小时) |
| planned_start | DATE | - | 否 | - | 计划开始日期 |
| planned_end | DATE | - | 否 | - | 计划结束日期 |
| actual_start | DATE | - | 否 | - | 实际开始日期 |
| actual_end | DATE | - | 否 | - | 实际结束日期 |
| delivery_date | DATE | - | 否 | - | 交付日期 |
| receivable_amount | DECIMAL | 15,2 | 否 | 0.00 | 应收款金额 |
| receivable_date | DATE | - | 否 | - | 应收款日期 |
| status | VARCHAR | 20 | 否 | pending | 状态pending-待开发developing-开发中delivered-已交付completed-已完成 |
| progress | INT | - | 否 | 0 | 开发进度0-100 |
| attachment_url | VARCHAR | 500 | 否 | - | 附件URL |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`requirement_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `requirement_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_project` (`project_id`)
- INDEX `idx_customer` (`customer_id`)
- INDEX `idx_status` (`status`)
---
### 3.5 支出管理模块
#### 3.5.1 expense_type支出类型表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| type_id | BIGINT | - | 是 | 自增 | 主键支出类型ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| type_code | VARCHAR | 50 | 否 | - | 支出类型编码 |
| type_name | VARCHAR | 100 | 是 | - | 支出类型名称 |
| parent_id | BIGINT | - | 否 | 0 | 父类型ID0表示一级类型 |
| type_level | INT | - | 否 | 1 | 类型层级 |
| sort_order | INT | - | 否 | 0 | 排序顺序 |
| description | VARCHAR | 200 | 否 | - | 类型描述 |
| status | TINYINT | - | 否 | 1 | 状态0-禁用1-启用 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`type_id`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_parent` (`parent_id`)
- INDEX `idx_status` (`status`)
---
#### 3.5.2 expense支出表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| expense_id | BIGINT | - | 是 | 自增 | 主键支出ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| expense_code | VARCHAR | 50 | 是 | - | 支出编号(唯一) |
| expense_type_id | BIGINT | - | 是 | - | 支出类型ID外键 |
| expense_amount | DECIMAL | 15,2 | 否 | 0.00 | 支出金额 |
| expense_date | DATE | - | 否 | - | 支出日期 |
| expense_reason | TEXT | - | 否 | - | 支出事由 |
| project_id | BIGINT | - | 否 | - | 所属项目ID外键 |
| applicant_id | BIGINT | - | 是 | - | 申请人ID外键 |
| department_id | BIGINT | - | 否 | - | 申请部门ID外键 |
| payment_method | VARCHAR | 20 | 否 | transfer | 付款方式transfer-转账cash-现金check-支票other-其他 |
| payment_account | VARCHAR | 100 | 否 | - | 付款账户 |
| attachment_url | VARCHAR | 500 | 否 | - | 附件URL |
| status | VARCHAR | 20 | 否 | pending | 状态pending-待付款paid-已付款completed-已完成cancelled-已作废 |
| payment_date | DATE | - | 否 | - | 付款日期 |
| payment_voucher | VARCHAR | 255 | 否 | - | 付款凭证 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`expense_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `expense_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_type` (`expense_type_id`)
- INDEX `idx_project` (`project_id`)
- INDEX `idx_applicant` (`applicant_id`)
- INDEX `idx_status` (`status`)
---
### 3.6 应收款管理模块
#### 3.6.1 receivable应收款表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| receivable_id | BIGINT | - | 是 | 自增 | 主键应收款ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| receivable_code | VARCHAR | 50 | 是 | - | 应收款编号(唯一) |
| requirement_id | BIGINT | - | 是 | - | 需求ID外键 |
| project_id | BIGINT | - | 是 | - | 项目ID外键 |
| customer_id | BIGINT | - | 是 | - | 客户ID外键 |
| receivable_amount | DECIMAL | 15,2 | 否 | 0.00 | 应收款金额 |
| receivable_date | DATE | - | 否 | - | 应收款日期 |
| payment_due_date | DATE | - | 否 | - | 付款截止日期 |
| payment_method | VARCHAR | 20 | 否 | - | 付款方式transfer-转账cash-现金check-支票other-其他 |
| bank_account | VARCHAR | 100 | 否 | - | 收款账户 |
| status | VARCHAR | 20 | 否 | pending | 状态pending-待收款partial-部分收款received-已收款overdue-逾期 |
| received_amount | DECIMAL | 15,2 | 否 | 0.00 | 已收款金额 |
| unpaid_amount | DECIMAL | 15,2 | 否 | 0.00 | 未收款金额 |
| overdue_days | INT | - | 否 | 0 | 逾期天数 |
| remark | VARCHAR | 500 | 否 | - | 备注说明 |
| created_by | BIGINT | - | 否 | - | 创建人ID |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_by | BIGINT | - | 否 | - | 更新人ID |
| updated_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 |
| deleted | TINYINT | - | 否 | 0 | 逻辑删除0-未删除1-已删除 |
**索引:**
- PRIMARY KEY (`receivable_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `receivable_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_requirement` (`requirement_id`)
- INDEX `idx_project` (`project_id`)
- INDEX `idx_customer` (`customer_id`)
- INDEX `idx_status` (`status`)
---
#### 3.6.2 receipt收款记录表
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|--------|------|------|------|--------|------|
| receipt_id | BIGINT | - | 是 | 自增 | 主键收款记录ID |
| tenant_id | BIGINT | - | 是 | - | 租户ID外键 |
| receipt_code | VARCHAR | 50 | 是 | - | 收款编号(唯一) |
| receivable_id | BIGINT | - | 是 | - | 应收款ID外键 |
| receipt_amount | DECIMAL | 15,2 | 否 | 0.00 | 收款金额 |
| receipt_date | DATE | - | 否 | - | 收款日期 |
| receipt_method | VARCHAR | 20 | 否 | transfer | 收款方式transfer-转账cash-现金check-支票other-其他 |
| receipt_account | VARCHAR | 100 | 否 | - | 收款账户 |
| payer_name | VARCHAR | 100 | 否 | - | 付款方名称 |
| receipt_voucher | VARCHAR | 255 | 否 | - | 收款凭证URL |
| operator_id | BIGINT | - | 否 | - | 操作人ID外键 |
| remark | VARCHAR | 200 | 否 | - | 备注说明 |
| created_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
**索引:**
- PRIMARY KEY (`receipt_id`)
- UNIQUE KEY `uk_tenant_code` (`tenant_id`, `receipt_code`)
- INDEX `idx_tenant` (`tenant_id`)
- INDEX `idx_receivable` (`receivable_id`)
---
## 四、数据库设计规范
### 4.1 命名规范
| 项目 | 规范 | 示例 |
|------|------|------|
| 数据库名 | 小写,下划线分隔 | fund_platform |
| 表名 | 小写,下划线分隔 | sys_user |
| 字段名 | 小写,下划线分隔 | user_name |
| 索引名 | 前缀_表名_字段名 | uk_tenant_username |
| 外键名 | fk_表名_字段名 | fk_user_dept |
### 4.2 字段规范
| 字段类型 | 使用场景 | 示例 |
|----------|----------|------|
| BIGINT | 主键、外键、ID | user_id |
| VARCHAR(50) | 编码、用户名、短文本 | user_code |
| VARCHAR(100) | 名称、标题 | user_name |
| VARCHAR(200) | 长名称、URL | project_name |
| VARCHAR(500) | 备注、描述 | remark |
| TEXT | 长文本、JSON | description |
| TINYINT | 状态、布尔值 | status |
| INT | 数量、排序 | sort_order |
| DECIMAL(15,2) | 金额 | amount |
| DATETIME | 日期时间 | created_time |
| DATE | 日期 | start_date |
### 4.3 通用字段
所有表必须包含以下字段:
| 字段名 | 类型 | 说明 |
|--------|------|------|
| created_by | BIGINT | 创建人ID |
| created_time | DATETIME | 创建时间DEFAULT CURRENT_TIMESTAMP |
| updated_by | BIGINT | 更新人ID |
| updated_time | DATETIME | 更新时间DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
| deleted | TINYINT | 逻辑删除标志DEFAULT 0 |
### 4.4 实体类与SQL脚本同步规范
> **强制要求**:修改实体类字段时,必须同步更新 SQL 初始化脚本
#### 4.4.1 同步修改流程
```mermaid
graph LR
A[修改实体类字段] --> B[同步修改SQL脚本]
B --> C[更新数据库设计文档]
C --> D[编译验证]
D --> E[提交代码]
```
| 操作类型 | 实体类修改 | SQL脚本修改 | 文档更新 |
|----------|------------|-------------|----------|
| 新增字段 | 添加属性 + Getter/Setter | ALTER TABLE ADD COLUMN | 更新表结构说明 |
| 删除字段 | 删除属性 + Getter/Setter | ALTER TABLE DROP COLUMN | 更新表结构说明 |
| 修改字段 | 修改属性类型 | ALTER TABLE MODIFY COLUMN | 更新字段说明 |
| 新增实体 | 创建Entity类 | CREATE TABLE | 新增表结构说明 |
#### 4.4.2 常见问题与预防
| 问题 | 原因 | 预防措施 |
|------|------|----------|
| Unknown column | 实体类有字段但数据库表无对应列 | 修改实体类后立即更新SQL脚本 |
| SQLSyntaxErrorException | SQL脚本与实体类不一致 | 提交前对比验证 |
| 字段类型不匹配 | Java类型与MySQL类型映射错误 | 参照4.2字段规范 |
#### 4.4.3 Java与MySQL类型映射
| Java类型 | MySQL类型 | 说明 |
|----------|-----------|------|
| Long | BIGINT | 主键、外键、ID |
| String | VARCHAR(n) | 根据长度选择n值 |
| String (长文本) | TEXT | 超过500字符 |
| Integer | INT | 数量、排序 |
| Boolean / Integer | TINYINT | 0/1状态值 |
| BigDecimal | DECIMAL(15,2) | 金额 |
| LocalDateTime | DATETIME | 日期时间 |
| LocalDate | DATE | 日期 |
### 4.5 自动化检查机制
#### 4.5.1 单元测试验证
建议在 `fund-common` 或各业务模块的测试目录中添加实体类与表结构一致性测试:
```java
@SpringBootTest
class EntitySchemaConsistencyTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
@DisplayName("验证SysConfig实体类与sys_config表结构一致")
void testSysConfigSchema() {
// 获取数据库表结构
var columns = jdbcTemplate.queryForList(
"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS " +
"WHERE TABLE_NAME = 'sys_config' AND TABLE_SCHEMA = DATABASE()"
);
Set<String> dbColumns = columns.stream()
.map(row -> (String) row.get("COLUMN_NAME"))
.collect(Collectors.toSet());
// 获取实体类字段(通过反射)
Set<String> entityFields = Arrays.stream(SysConfig.class.getDeclaredFields())
.map(f -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, f.getName()))
.collect(Collectors.toSet());
// 验证一致性
assertThat(entityFields).isSubsetOf(dbColumns);
}
}
```
#### 4.5.2 CI/CD集成检查
在持续集成流程中添加数据库脚本验证步骤:
```yaml
# .gitlab-ci.yml 或 GitHub Actions
validate-schema:
stage: test
script:
- echo "验证SQL脚本语法"
- mysql --help > /dev/null 2>&1 && echo "MySQL client available"
# 可集成sqlfluff等SQL语法检查工具
```
---
**文档结束**