联系人信息管理 ER 设计

基于现有联系人管理功能,扩展为全维度个人信息管理系统。
创建时间:2026-08-08

一、整体架构

1
2
3
4
5
6
7
8
9
10
11
erDiagram
sys_user ||--o{ user_contact_person : "create_by"
user_contact_person ||--|| user_contact_person_ext : "contact_id 一对一"
user_contact_person ||--o{ user_contact_work : "contact_id 一对多"
user_contact_person ||--o{ user_contact_education : "contact_id 一对多"
user_contact_person ||--o{ user_contact_family : "contact_id 一对多"
user_contact_person ||--o{ user_contact_health : "contact_id 一对多"
user_contact_person ||--o{ user_contact_life : "contact_id 一对多"
user_contact_person ||--o{ user_contact_social : "contact_id 一对多"
user_contact_person ||--o{ user_contact_finance : "contact_id 一对多"
user_contact_person ||--o{ user_contact_certificate : "contact_id 一对多"

二、表关系总览

表名 维度 关系 用途
user_contact_person 基础联系信息 主表 姓名、联系方式、城市
user_contact_person_ext 个人扩展画像 一对一 性别、生日、籍贯、民族、身份证、婚姻、居住地址
user_contact_work 工作经历 一对多 公司、部门、职位、行业、薪资、入职/离职日期
user_contact_education 教育经历 一对多 学校、专业、学历、入学/毕业日期
user_contact_family 家庭成员 一对多 姓名、关系、性别、生日、职业、电话
user_contact_health 健康记录 一对多 血型、身高体重、过敏史、病史、用药、体检记录
user_contact_life 生活记录 一对多 饮食/作息/运动习惯、兴趣爱好、旅行足迹
user_contact_social 社交账号 一对多 微信/QQ/微博/抖音等账号
user_contact_finance 财务信息 一对多 收入/资产/负债、金额、记录日期
user_contact_certificate 证件管理 一对多 身份证/护照/驾照/职业资格证等

三、ER 图详情

3.1 基础表(已实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
erDiagram
user_contact_person ||--|| user_contact_person_ext : "contact_id 一对一"

user_contact_person {
bigint contact_id PK "联系人主键"
varchar name "姓名"
varchar contact_model "联系方式"
varchar contact_no "联系号"
varchar city "城市"
varchar search_keys "搜索暗号(逗号分隔)"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志(0存在 2删除)"
}

user_contact_person_ext {
bigint contact_id PK "扩展主键(关联主表)"
varchar avatar "头像URL"
char gender "性别(0男 1女)"
date birthday "生日"
int age "年龄"
varchar native_place "籍贯"
varchar nation "民族"
varchar id_card "身份证号"
char marital_status "婚姻状况(0未婚 1已婚 2离异 3丧偶)"
varchar home_address "居住地址"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志(0存在 2删除)"
}

3.2 工作经历(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
erDiagram
user_contact_person ||--o{ user_contact_work : "contact_id"

user_contact_work {
bigint work_id PK "工作经历ID"
bigint contact_id FK "联系人ID"
varchar company "公司名称"
varchar department "部门"
varchar position "职位"
varchar industry "行业"
varchar work_address "工作地址"
varchar work_phone "工作电话"
varchar work_email "工作邮箱"
date entry_date "入职日期"
date leave_date "离职日期"
char is_current "是否在职(0是 1否)"
decimal salary "薪资"
varchar remark "工作备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.3 教育经历(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
erDiagram
user_contact_person ||--o{ user_contact_education : "contact_id"

user_contact_education {
bigint edu_id PK "教育经历ID"
bigint contact_id FK "联系人ID"
varchar school_name "学校名称"
varchar major "专业"
varchar degree "学历(字典)"
date start_date "入学日期"
date end_date "毕业日期"
char is_graduated "是否毕业(0是 1否)"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.4 家庭成员(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
erDiagram
user_contact_person ||--o{ user_contact_family : "contact_id"

user_contact_family {
bigint family_id PK "家庭成员ID"
bigint contact_id FK "联系人ID"
varchar member_name "成员姓名"
char relation "关系(字典:父子/夫妻等)"
char gender "性别"
date birthday "生日"
varchar occupation "职业"
varchar phone "电话"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.5 健康记录(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
erDiagram
user_contact_person ||--o{ user_contact_health : "contact_id"

user_contact_health {
bigint health_id PK "健康记录ID"
bigint contact_id FK "联系人ID"
date record_date "记录日期"
char blood_type "血型(字典)"
decimal height "身高(cm)"
decimal weight "体重(kg)"
char allergy "过敏史"
varchar medical_history "既往病史"
varchar current_medication "正在用药"
varchar hospital "体检医院"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.6 生活记录(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
erDiagram
user_contact_person ||--o{ user_contact_life : "contact_id"

user_contact_life {
bigint life_id PK "生活记录ID"
bigint contact_id FK "联系人ID"
date record_date "记录日期"
char diet_habit "饮食习惯(字典)"
char sleep_habit "作息习惯"
char exercise_freq "运动频率"
varchar hobbies "兴趣爱好"
varchar preferences "偏好备注"
varchar travel_history "旅行足迹"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.7 社交账号(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
erDiagram
user_contact_person ||--o{ user_contact_social : "contact_id"

user_contact_social {
bigint social_id PK "社交账号ID"
bigint contact_id FK "联系人ID"
char platform "平台类型(字典)"
varchar account "账号"
varchar nickname "昵称"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.8 财务信息(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
erDiagram
user_contact_person ||--o{ user_contact_finance : "contact_id"

user_contact_finance {
bigint finance_id PK "财务记录ID"
bigint contact_id FK "联系人ID"
char finance_type "类型(收入/资产/负债)"
varchar item_name "项目名称"
decimal amount "金额"
date record_date "记录日期"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

3.9 证件管理(一对多)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
erDiagram
user_contact_person ||--o{ user_contact_certificate : "contact_id"

user_contact_certificate {
bigint cert_id PK "证件ID"
bigint contact_id FK "联系人ID"
char cert_type "证件类型(字典)"
varchar cert_no "证件号码"
varchar issue_org "签发机构"
date issue_date "签发日期"
date expire_date "到期日期"
varchar remark "备注"
varchar create_by "创建者"
datetime create_time "创建时间"
varchar update_by "更新者"
datetime update_time "更新时间"
char del_flag "删除标志"
}

四、分阶段实施计划

第一期(已完成)

表名 状态 说明
user_contact_person 已完成 联系人基础信息
user_contact_person_ext 已完成 联系人扩展画像

第二期(推荐下一步)

表名 说明
user_contact_work 工作经历(支持多段)
user_contact_education 教育经历(支持多段)
user_contact_family 家庭成员

第三期

表名 说明
user_contact_health 健康记录
user_contact_life 生活记录

第四期

表名 说明
user_contact_social 社交账号
user_contact_finance 财务信息
user_contact_certificate 证件管理

五、设计原则

  1. 主表轻量:只存核心联系信息,保证查询效率
  2. 扩展表一对一:存固定画像字段(一个联系人只有一份)
  3. 明细表一对多:工作/教育/健康等有时间属性的、可能多条记录的,单独建表
  4. 逻辑删除:所有表都加 del_flagcreate_bycreate_timeupdate_byupdate_time
  5. 字典化:性别、学历、关系、血型、平台类型等都用字典(sys_dict_type),方便扩展

六、后端功能设计

6.1 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ruoyi-admin/src/main/java/com/ruoyi/identity/
├── domain/ # 实体类
│ ├── UserContactPerson.java # 联系人主表
│ ├── UserContactPersonExt.java # 联系人扩展表
│ ├── UserContactWork.java # 工作经历
│ ├── UserContactEducation.java # 教育经历
│ ├── UserContactFamily.java # 家庭成员
│ ├── UserContactHealth.java # 健康记录
│ ├── UserContactLife.java # 生活记录
│ ├── UserContactSocial.java # 社交账号
│ ├── UserContactFinance.java # 财务信息
│ └── UserContactCertificate.java # 证件管理
├── mapper/ # Mapper 接口
│ ├── UserContactPersonMapper.java
│ ├── UserContactPersonExtMapper.java
│ └── ...
├── service/ # Service 接口
│ ├── IUserContactPersonService.java
│ ├── IUserContactPersonExtService.java
│ └── ...
│ └── impl/ # Service 实现
│ ├── UserContactPersonServiceImpl.java
│ └── ...
└── controller/ # Controller
├── UserContactPersonController.java
├── UserContactPersonExtController.java
└── ...
1
2
3
4
5
ruoyi-admin/src/main/resources/mapper/identity/
├── UserContactPersonMapper.xml
├── UserContactPersonExtMapper.xml
├── UserContactWorkMapper.xml
└── ...

6.2 Controller 接口规范

每张表统一提供以下接口(以工作经历为例):

接口 方法 路径 权限标识 说明
查询列表 GET /identity/contact_work/list identity:contact_work:list 分页查询,支持按 contactId 过滤
查询详情 GET /identity/contact_work/{workId} identity:contact_work:query 按主键查询
新增 POST /identity/contact_work identity:contact_work:add 新增一条记录
修改 PUT /identity/contact_work identity:contact_work:edit 修改一条记录
删除 DELETE /identity/contact_work/{workIds} identity:contact_work:remove 逻辑删除(del_flag='2'
导出 POST /identity/contact_work/export identity:contact_work:export 导出 Excel

6.3 Domain 设计规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 继承 BaseEntity(自动获得 createBy/createTime/updateBy/updateTime/remark)
public class UserContactWork extends BaseEntity {
private static final long serialVersionUID = 1L;

@Excel(name = "工作经历ID")
private Long workId; // 主键

@Excel(name = "联系人ID")
private Long contactId; // 外键,关联主表

@Excel(name = "公司名称")
private String company;

// ... 其他字段

@Excel(name = "入职日期", dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date entryDate;

@Excel(name = "是否在职", readConverterExp = "0=是,1=否")
private String isCurrent;

private String delFlag; // 逻辑删除标志
}

6.4 Mapper XML 查询规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 列表查询:必须加 del_flag = '0' 过滤 -->
<select id="selectUserContactWorkList" parameterType="UserContactWork" resultMap="UserContactWorkResult">
select <include refid="selectUserContactWorkVo"/>
from user_contact_work
<where>
del_flag = '0'
<if test="contactId != null"> and contact_id = #{contactId} </if>
<if test="company != null and company != ''"> and company like concat('%', #{company}, '%') </if>
<if test="isCurrent != null and isCurrent != ''"> and is_current = #{isCurrent} </if>
</where>
order by entry_date desc
</select>

<!-- 逻辑删除:update 而非 delete -->
<update id="deleteUserContactWorkByWorkIds">
update user_contact_work set del_flag = '2'
where work_id in
<foreach item="workId" collection="array" open="(" separator="," close=")">
#{workId}
</foreach>
</update>

6.5 Service 层规范

1
2
3
4
5
6
7
8
9
10
11
12
public interface IUserContactWorkService {
// 查询列表
List<UserContactWork> selectUserContactWorkList(UserContactWork userContactWork);
// 查询详情
UserContactWork selectUserContactWorkByWorkId(Long workId);
// 新增
int insertUserContactWork(UserContactWork userContactWork);
// 修改
int updateUserContactWork(UserContactWork userContactWork);
// 逻辑删除
int deleteUserContactWorkByWorkIds(Long[] workIds);
}

6.6 跨表关联查询

扩展信息展示时需要 JOIN 主表带出联系人姓名:

1
2
3
4
5
6
7
8
9
<select id="selectUserContactWorkList" resultMap="UserContactWorkResult">
select w.*, p.name as contact_name
from user_contact_work w
left join user_contact_person p on w.contact_id = p.contact_id
<where>
w.del_flag = '0'
<if test="contactId != null"> and w.contact_id = #{contactId} </if>
</where>
</select>

6.7 事务管理

涉及多表操作时加 @Transactional

1
2
3
4
5
6
7
8
9
10
@Transactional
public int insertUserContactPerson(UserContactPerson userContactPerson) {
// 1. 插入主表
int rows = userContactPersonMapper.insertUserContactPerson(userContactPerson);
// 2. 插入扩展表
UserContactPersonExt ext = new UserContactPersonExt();
ext.setContactId(userContactPerson.getContactId());
userContactPersonExtMapper.insertUserContactPersonExt(ext);
return rows;
}

七、前端功能设计

7.1 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ruoyi-ui/src/
├── api/identity/ # API 请求
│ ├── contact_person.js # 联系人主表 API
│ ├── contact_person_ext.js # 扩展表 API
│ ├── contact_work.js # 工作经历 API
│ ├── contact_education.js # 教育经历 API
│ ├── contact_family.js # 家庭成员 API
│ ├── contact_health.js # 健康记录 API
│ ├── contact_life.js # 生活记录 API
│ ├── contact_social.js # 社交账号 API
│ ├── contact_finance.js # 财务信息 API
│ └── contact_certificate.js # 证件管理 API
└── views/identity/
├── contact_person/ # 联系人主页面(列表入口)
│ └── index.vue
├── contact_person_ext/ # 扩展信息页面
│ └── index.vue
├── contact_work/ # 工作经历页面
│ └── index.vue
├── contact_education/ # 教育经历页面
│ └── index.vue
└── ...

7.2 页面导航设计

采用「主列表 → 子模块 Tab 切换」模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
联系人列表页(contact_person/index.vue)

├─ 操作列「详情」按钮 → 联系人详情页

└─ 联系人详情页(contact_detail/index.vue)

├─ Tab 1: 基础信息(contact_person + ext)
├─ Tab 2: 工作经历(contact_work)
├─ Tab 3: 教育经历(contact_education)
├─ Tab 4: 家庭成员(contact_family)
├─ Tab 5: 健康记录(contact_health)
├─ Tab 6: 生活记录(contact_life)
├─ Tab 7: 社交账号(contact_social)
├─ Tab 8: 财务信息(contact_finance)
└─ Tab 9: 证件管理(contact_certificate)

7.3 API 请求规范

每个子模块统一提供 6 个方法(以工作经历为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import request from '@/utils/request'

// 查询工作经历列表
export function listContact_work(query) {
return request({
url: '/identity/contact_work/list',
method: 'get',
params: query
})
}

// 查询工作经历详细
export function getContact_work(workId) {
return request({
url: '/identity/contact_work/' + workId,
method: 'get'
})
}

// 新增工作经历
export function addContact_work(data) {
return request({
url: '/identity/contact_work',
method: 'post',
data: data
})
}

// 修改工作经历
export function updateContact_work(data) {
return request({
url: '/identity/contact_work',
method: 'put',
data: data
})
}

// 删除工作经历
export function delContact_work(workId) {
return request({
url: '/identity/contact_work/' + workId,
method: 'delete'
})
}

// 导出工作经历
export function exportContact_work(query) {
return request({
url: '/identity/contact_work/export',
method: 'post',
params: query
})
}

7.4 页面组件规范

7.4.1 一对一扩展表页面(contact_person_ext)

  • 搜索条件:联系人下拉框(filterable)
  • 列表:显示扩展字段 + 联系人姓名(JOIN)
  • 对话框:分区块表单(el-divider 分隔)
  • 新增/修改区分:用 isEdit 标志位,不用 contactId != null

7.4.2 一对多明细表页面(contact_work 等)

  • 搜索条件:默认按 contactId 过滤(从 URL query 传入)
  • 列表:表格显示该联系人的所有记录
  • 对话框:contactId 只读(从 URL 带入或默认选中当前联系人)
  • 时间线展示:工作经历、教育经历可用 el-timeline 按时间倒序展示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="app-container">
<!-- 从联系人详情页带入 contactId -->
<el-timeline>
<el-timeline-item
v-for="work in workList"
:key="work.workId"
:timestamp="work.entryDate + ' ~ ' + (work.leaveDate || '至今')"
placement="top"
>
<el-card>
<h4>{{ work.company }} - {{ work.position }}</h4>
<p>{{ work.department }} | {{ work.workAddress }}</p>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</template>

7.5 路由配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// src/router/index.js
{
path: '/identity',
component: Layout,
children: [
{
path: 'contact_person',
name: 'Contact_person',
component: () => import('@/views/identity/contact_person/index'),
meta: { title: '联系人管理', icon: 'el-icon-user' }
},
{
path: 'contact_person_ext',
name: 'Contact_person_ext',
component: () => import('@/views/identity/contact_person_ext/index'),
meta: { title: '扩展信息', activeMenu: '/identity/contact_person' }
},
{
path: 'contact_detail/:contactId',
name: 'Contact_detail',
component: () => import('@/views/identity/contact_detail/index'),
hidden: true,
meta: { title: '联系人详情', activeMenu: '/identity/contact_person' }
}
]
}

7.6 字典配置

需要在「系统管理 → 字典管理」中新增以下字典:

字典类型 字典名称 字典项示例
contact_tags 搜索暗号 1=spec, 2=job, 3=life
contact_degree 学历 1=博士, 2=硕士, 3=本科, 4=大专, 5=高中
contact_relation 家庭关系 1=父亲, 2=母亲, 3=配偶, 4=儿子, 5=女儿
contact_blood_type 血型 A=A型, B=B型, O=O型, AB=AB型
contact_platform 社交平台 1=微信, 2=QQ, 3=微博, 4=抖音
contact_finance_type 财务类型 1=收入, 2=资产, 3=负债
contact_cert_type 证件类型 1=身份证, 2=护照, 3=驾照, 4=资格证

7.7 菜单配置

在「系统管理 → 菜单管理」中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
联系人管理(目录)
├── 联系人列表(菜单,/identity/contact_person)
│ ├── 新增(按钮 identity:contact_person:add)
│ ├── 修改(按钮 identity:contact_person:edit)
│ ├── 删除(按钮 identity:contact_person:remove)
│ └── 扩展信息(按钮 identity:contact_person_ext:query)
├── 扩展信息(菜单,/identity/contact_person_ext,隐藏)
├── 工作经历(菜单,/identity/contact_work,隐藏)
├── 教育经历(菜单,/identity/contact_education,隐藏)
├── 家庭成员(菜单,/identity/contact_family,隐藏)
├── 健康记录(菜单,/identity/contact_health,隐藏)
├── 生活记录(菜单,/identity/contact_life,隐藏)
├── 社交账号(菜单,/identity/contact_social,隐藏)
├── 财务信息(菜单,/identity/contact_finance,隐藏)
└── 证件管理(菜单,/identity/contact_certificate,隐藏)

子模块菜单设为隐藏,通过联系人列表操作列按钮跳转进入。

八、相关文档

数据库设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
-- ----------------------------
-- 联系人表
-- ----------------------------
DROP TABLE IF EXISTS `crm_contact`;
CREATE TABLE `crm_contact` (
`contact_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',

-- 【核心三要素】
`name` VARCHAR(100) NOT NULL COMMENT '姓名',
`contact_model` VARCHAR(20) NOT NULL DEFAULT '手机' COMMENT '联系方式类型(手机/微信/QQ/邮件)',
`contact_value` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '联系号(对应具体号码)',

-- 【三大搜索加速器】
`company` VARCHAR(200) DEFAULT '' COMMENT '公司/单位',
`city` VARCHAR(100) DEFAULT '' COMMENT '所在城市',
`search_keys` VARCHAR(255) DEFAULT '' COMMENT '搜索暗号(标签/别名,逗号分隔)',

-- 【记忆锚点】
`remark` VARCHAR(500) DEFAULT '' COMMENT '关键备注(见面话题/历史事件)',

-- 【若依标准审计字段(务必保留,让生成器零报错)】
`create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME COMMENT '创建时间',
`update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME COMMENT '更新时间',
`del_flag` CHAR(1) DEFAULT '0' COMMENT '删除标记(0存在 2删除)',

PRIMARY KEY (`contact_id`),
KEY `idx_name` (`name`),
KEY `idx_contact_value` (`contact_value`), -- 搜手机号/微信号走这个索引
KEY `idx_city` (`city`),
KEY `idx_del_flag` (`del_flag`) -- 若依软删除必备索引
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='联系人表(个人极简版)';


-- 联系人信息扩展表(与 user_contact_person 一对一关联)
DROP TABLE IF EXISTS `user_contact_person_ext`;
CREATE TABLE `user_contact_person_ext` (
`contact_id` bigint(20) NOT NULL COMMENT '联系人主键ID(关联 user_contact_person.contact_id)',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`gender` char(1) DEFAULT NULL COMMENT '性别(0男 1女)',
`birthday` date DEFAULT NULL COMMENT '生日',
`age` int(3) DEFAULT NULL COMMENT '年龄',
`id_card` varchar(20) DEFAULT NULL COMMENT '身份证号',
`marital_status` char(1) DEFAULT NULL COMMENT '婚姻状况(0未婚 1已婚 2离异 3丧偶)',
`native_place` varchar(100) DEFAULT NULL COMMENT '籍贯',
`home_address` varchar(255) DEFAULT NULL COMMENT '居住地址',

`company` varchar(100) DEFAULT NULL COMMENT '工作单位',
`department` varchar(50) DEFAULT NULL COMMENT '部门',
`position` varchar(50) DEFAULT NULL COMMENT '职位',
`industry` varchar(50) DEFAULT NULL COMMENT '所属行业',
`work_address` varchar(255) DEFAULT NULL COMMENT '工作地址',

`email` varchar(100) DEFAULT NULL COMMENT '个人邮箱',
`wechat` varchar(50) DEFAULT NULL COMMENT '微信号',
`qq` varchar(20) DEFAULT NULL COMMENT 'QQ号',
`yuni` varchar(20) DEFAULT NULL COMMENT '与你',
`backup_phone` varchar(20) DEFAULT NULL COMMENT '备用电话',
`emergency_contact` varchar(50) DEFAULT NULL COMMENT '紧急联系人',
`emergency_phone` varchar(20) DEFAULT NULL COMMENT '紧急联系电话',
`emergency_relation` varchar(50) DEFAULT NULL COMMENT '与紧急联系人关系',

`hobbies` varchar(255) DEFAULT NULL COMMENT '兴趣爱好',
`preferences` varchar(255) DEFAULT NULL COMMENT '偏好备注(饮食/习惯等)',
`tags` varchar(255) DEFAULT NULL COMMENT '业务标签(逗号分隔)',

`remark` varchar(500) DEFAULT NULL COMMENT '扩展备注',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` char(1) COLLATE utf8mb4_unicode_ci DEFAULT '0' COMMENT '删除标记(0存在 2删除)',
PRIMARY KEY (`contact_id`),
CONSTRAINT `fk_ext_contact` FOREIGN KEY (`contact_id`) REFERENCES `user_contact_person` (`contact_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='联系人信息扩展表';

用户列表

菜单图标

系统菜单 -》用户管理 -》用户列表,点击修改链接

修改对话框标题

前端页面:src/views/system/info/index.vue
253行删掉列表
263行删掉列表

注册时间

无论新增、修改,都不需要注册时间(自动生成)
1.修改前端代码:130行-137行注释掉
2.修改后端代码:修改sql语句,Mapper 映射文件:ruoyi-admin/src/main/resources/mapper/system/UserInfoMapper.xml

1
insert into user_info (user_name, phone, register_time) values(#{userName}, #{phone}, now())

车辆品牌

参考:https://www.yoojia.com/car/0-0-0-0-0-0-0-0-0-0-0-0-0-0-4-0-0.html

创建车辆品牌表

设置主键自增,防止not null 报错

1
2
3
4
5
6
CREATE TABLE `car_brand` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '品牌名',
`logo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'logo图片',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

代码生成

1、登录若依后台管理系统:系统工具 -> 代码生成
2、点击导入按钮,选择车辆品牌表,点击确定
3、点击车辆品牌表后面的编辑按钮,分别修改基本信息、字段信息、生成信息,点击提交

合并代码

1、把下载的代码解压
2、把 sql 导入 cardb 数据库:拖拽 SQL 文件到数据库即可
3、把 main 文件夹里面的代码复制(打开 main 文件夹,选中 java/resources 进行复制),粘贴到 ruoyiadmin/src/main,选中 main 进行粘贴;
4、把 vue 文件夹里面的代码复制(打开 vue 文件夹,选中 api/views 进行复制),粘贴到ruoyi-ui/src,选中 src 进行粘贴
5、重启后端服务即可,前端服务是热部署的

菜单图标

设置菜单图标,才能打开页面
1、系统管理 -> 系统菜单 -> 用户管理 -> 车辆品牌,点击修改链接
2、刷新页面即可

车辆类型

创建数据表

1
2
3
4
5
6
7
CREATE TABLE `car_type` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '类型名',
`img` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '示例图片',
`bid` int DEFAULT NULL COMMENT '所有品牌',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

关联车辆品牌

1、在 CarBrandController 定义查询所有车辆品牌的接口

1
2
3
4
5
6
7
8
9
10
11
/**
* 查询所有车辆品牌列表
* 去掉分页
*/
@PreAuthorize("@ss.hasPermi('car:brand:list')")
@GetMapping("/all")
public TableDataInfo all(CarBrand carBrand)
{
List<CarBrand> list = carBrandService.selectCarBrandList(carBrand);
return getDataTable(list);
}

2、在 src/api/car/brand.js 中,调用查询所有车辆品牌的接口的方法

1
2
3
4
5
6
7
// 调用查询所有车辆品牌的接口的方法
export function listBrand2() {
return request({
url: '/car/brand/all',
method: 'get'
})
}

3、在车辆类型页面(src/views/car/type/index.vue),定义查询车辆品牌的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 添加定义的接口listBrand2,从车辆品牌页面复制
import { listBrand2 } from "@/api/car/brand"
data() {
return {
// 表单校验
rules: {
}
,brandList:[] //存放接口数据
}
},
created() {
this.getList()
this.getBrandList() //将接口调用申明到创建页面生命周期
}
methods: {
/** 查询车辆品牌列表 */
getBrandList() {
this.loading = true
listBrand2().then(response => {
console.log(response);
this.brandList = response.rows
// this.total = response.total
this.loading = false
})
},
/** 新增按钮操作 */
handleAdd() {
this.getBrandList() //调用方法
this.reset()
this.open = true
this.title = "添加车辆类型"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.getBrandList() //调用方法
this.reset()
const id = row.id || this.ids
getType(id).then(response => {
this.form = response.data
this.open = true
this.title = "修改车辆类型"
})
}
}

3、在车辆类型页面(src/views/car/type/index.vue),使用下拉框动态渲染车辆品牌数据el-select 组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<el-form-item label="所属品牌" prop="bid">
<!-- <el-input
v-model="queryParams.bid"
placeholder="请输入所属品牌"
clearable
@keyup.enter.native="handleQuery"
/> -->
<el-select
v-model="queryParams.bid"
placeholder="请输入所属品牌"
clearable
@keyup.enter.native="handleQuery"
>
<el-option
v-for="item in brandList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>


<el-form-item label="所属品牌" prop="bid">
<!-- <el-input v-model="form.bid" placeholder="请输入所属品牌" /> -->
<el-select v-model="form.bid" placeholder="请输入所属品牌">
<el-option
v-for="item in brandList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>

数据表格(多表查询)

1、在 ruoyi-admin/src/main/resouces/mapper/car/CarTypeMapper.xml 修改SQL 语句,实现多表查询
在 CarTypeMapper.xml 手动映射 bname

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    <resultMap type="CarType" id="CarTypeResult">
<result property="id" column="id" />
<result property="name" column="name" />
<result property="img" column="img" />
<result property="bid" column="bid" />
<result property="bname" column="bname" />
</resultMap>

<select id="selectCarTypeList" parameterType="CarType" resultMap="CarTypeResult">
<!-- <include refid="selectCarTypeVo"/>-->
SELECT ct.id, ct.`name`, ct.img, ct.bid, cb.`name` AS bname
FROM car_type ct
LEFT JOIN car_brand cb ON ct.bid = cb.id
<where>
<if test="name != null and name != ''"> and ct.name like concat('%', #{name}, '%')</if>
<if test="bid != null "> and ct.bid = #{bid}</if>
</where>
</select>

2、修改 CarType 实体类,添加 bname 字段;

1
2
3
4
5
6
7
8
9
10
/** 所属品牌名 */
private String bname;

public String getBname() {
return bname;
}

public void setBname(String bname) {
this.bname = bname;
}

3、修改前端页面的数据表格,添加所属品牌列

1
<el-table-column label="所属品牌" prop="bname" />

用户车辆

创建数据表

1
2
3
4
5
6
7
8
9
CREATE TABLE `user_car` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键\r\n',
`uid` int DEFAULT NULL COMMENT '所属用户',
`brand` int DEFAULT NULL COMMENT '所属品牌',
`type` int DEFAULT NULL COMMENT '所属类型',
`car_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '车牌号',
`car_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '车辆照片',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

关联用户

1、在 UserInfoController 定义查询所有用户的接口

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 查询所有用户列表
* 去掉分页
*/
@PreAuthorize("@ss.hasPermi('system:info:list')")
@GetMapping("/list")
public TableDataInfo list(UserInfo userInfo)
{
startPage();
List<UserInfo> list = userInfoService.selectUserInfoList(userInfo);
return getDataTable(list);
}

2、在 src/api/system/info.js 中,调用查询所有用户的接口的方法

1
2
3
4
export function listInfo2() {
return request({
url: '/system/info/all', method: 'get' })
}

3、在 src/views/car/car/index.vue 中,定义查询所有用户的方法

1
2
3
4
5
6
7
8
9
10
11
12
// script 标签的最顶部
import { listInfo2, getInfo, delInfo, addInfo, updateInfo } from "@/api/system/info"
// methods 中定义该方法
/** 查询所有用户 */
getUserList() {
this.loading = true
listInfo2().then(response => {
this.userList = response.rows
console.log(response.rows);
this.loading = false
})
},

4、在新增/修改的事件函数中,调用 getUserList 方法
5、使用下拉框动态渲染用户数据

关联车辆类型

1、把文本框改为下拉框:以下拉框形式,动态显示车辆所属类型
2、根据所属品牌不同,动态显示车辆类型
实现方式:
1、后端代码:定义根据 bid 查询车辆类型的整套代码(Controller、Service、Mapper)

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CarTypeController extends BaseController
{
@Autowired
private ICarTypeService carTypeService;
/**
* 查询车辆品牌,查询所有车辆类型列表
*/
@PreAuthorize("@ss.hasPermi('car:type:list')")
@GetMapping("/listByBid")
public TableDataInfo listByBid(Integer bid)
{
List<CarType> list =
carTypeService.selectCarTypeByBId(bid);
return getDataTable(list);
}
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface ICarTypeService
{
/**
* 根据品牌 id,查询对应的车辆类型
*
* @param bid 车辆品牌主键
* @return 车辆类型
*/
public List<CarType> selectCarTypeByBId(Integer bid);
}
@Service
public class CarTypeServiceImpl implements ICarTypeService{
@Autowired
private CarTypeMapper carTypeMapper;
@Override
public List<CarType> selectCarTypeByBId(Integer bid) {return carTypeMapper.selectCarTypeByBId(bid);
}
}

mapper

1
2
3
4
5
6
7
8
9
10
11
public interface CarTypeMapper
{
/**
* 查询车辆品牌 id,查询对应车辆类型
*
* @param bid 车辆类型主键
* @return 车辆类型
*/
public List<CarType> selectCarTypeByBId(Integer bid);
// 略
}
1
2
3
4
<!--CarTypeMapper.xml 文件-->
<select id="selectCarTypeByBId" parameterType="Integer"
resultMap="CarTypeResult">
SELECT id, name, img, bid FROM car_type WHERE bid = #{bid}</select>

2、每次所属品牌发生改变,发送请求,获取车辆类型数据即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// type.js
// 根据 bid,查询车辆类型列表
export function listType2(bid) {
return request({
url: '/car/type/listByBid?bid=' + bid, method: 'get' })
}
// 120行添加事件@change="handleBrandChange" clearable
<el-select v-model="form.brand" placeholder="请选择品牌" @change="handleBrandChange" clearable>

// 在用户车辆页面,调用
import { listType2, getType, delType, addType, updateType } from "@/api/car/type"
// 车辆品牌改变的回调函数
brandChange(){
console.log('你选择了'+ this.form.brand);
this.loading = true
listType2(this.form.brand).then(response => {
this.typeList = response.rows
console.log(response.rows);
this.loading = false
})
},

<el-form-item label="所属类型" prop="type">
<el-select v-model="form.type" placeholder="请选择所属类型">
<el-option
v-for="item in typeList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>