用户管理:
- POST /user
- PUT /user
- GET /user-list
- POST /signin
- POST /password/change
- GET /user-select-tree
- GET /user/region-relation
区域数据:
报表数据:
- GET /area/list
- GET /area/detail
- GET /school/list
- GET /school/detail
- GET /room/list
- GET /room/detail
- GET /room/student/list
- GET /teacher/list
- GET /school/unassigned/list
数据说明:
创建用户 超级管理员可以创建任意角色的帐号, 区域负责人只能创建更低权限的帐号; 其他角色无权
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
body | phone | String | T | 大陆手机号 |
body | password | String | T | - |
body | name | String | T | - |
body | role | String | T | 角色类型 |
body | tree | Array | F | 选定负责区域, 参考 区域信息树状结构 |
body | String | F | - | |
body | status | String | F | 默认 enabled |
输出结果:
<参考用户信息结构>
登录
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
body | phone | String | T | - |
body | password | String | T | - |
输出结果:
示例:
<参考用户信息结构>
Token 相关:
- 通过登录接口获取 JWT Token, 之后的请求中都需要带上 Token.
- Token 通过响应的 Header: Authorization 获取.
- 所有需要 token 验证的接口, 在请求成功后都有可能会更新 token. 因此每个接口响应成功后需要检查 token 和浏览器本地保存的是否一直, 如不一致则应更新本地存储的 token.
- 退出登录后清除浏览器中保存的 token 信息
- Token有效时间: 登录后获取的 token 有效期 1 小时, 过期前半小时内进行带权限验证的接口请求会返回刷新后的 token
修改用户信息, 包括用户选取的区划信息 超级管理员可以修改自己创建的超管帐号, 及其他低权限帐号; 区域负责人只能修改自己创建的帐号; 其他角色无权
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
body | id | String | T | - |
body | phone | String | T | - |
body | name | String | T | - |
body | tree | Array | F | 选定的负责区域, 参考区域信息树状结构 |
body | String | F | - | |
body | status | String | F | - |
body | password | String | F | 用于设定指定帐号的密码 |
输出结果:
示例:
<参考用户信息结构>
修改密码
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
body | old | String | T | 旧密码 |
body | new | String | T | 新密码 |
返回值: 200 OK
根据区划代码获取该行政区划对应的代理商及区域负责人 用于区域或学校简介时显示代理商信息
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | region | String | T | 要查询的区划代码 |
返回值:
{
"agency": <参考用户信息结构>,
"agencyManager": <参考用户信息结构>
// 如果没有值, 则说明没有相关连的代理商或区域负责人
// 如果只有 agencyManager, 说明只分配给了区域负责人, 但还没有分配给代理商.
// 两者都有则是完整的分配关系.
}
用户列表 超级管理员可以看到所有用户信息; 区域负责人可以看到自己创建的代理商帐号; 其余角色无权请求该接口
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | id | String | F | 如果需要获取单个用户的信息, 传用户ID |
query | status | String | F | enabled/disabled, 不传表示所有 |
query | role | String | F | 角色类型 |
query | skip | String | F | 默认0 |
query | limit | String | F | 默认 100 一页 |
输出结果:
{
"total": 123, // 符合条件的数据总数
"skip": 0, // 当前数据 skip 参数
"limit": 100, // 当前数据 limit 参数
"data": [
<参考用户信息结构>,
<参考用户信息结构>
]
}
根据区划代码获取对应的名称
Mode | Key | Type | Require | Description |
---|---|---|---|---|
query | regions | String | T | 支持批量, 多个代码之间用","分隔 |
输出结果:
[
// 数组 0-2 分别对应 省 市 区 三级名称
// 返回的结果和输入的region顺序保持一致
["北京","北京","东城"],
["河北"],
["甘肃","兰州"]
]
获取用户的区划信息树, 含 state 信息 权限级别同 之前的 修改用户接口 创建编辑用户界面下根据该接口的返回渲染省市区联动模块, 用户操作完成后将新的 tree 结构整体传回服务器即可.
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | id | String | F | 所查询用户的ID. 对于已有用户, 需要传该字段; 创建用户过程中则不需要传该字段 |
输出结果:
<参考 region-tree 结构, 带有 state 信息>
获取不带用户信息的区划树, 无须token
输出结果:
<参考 region-tree 结构, 不带 state 信息>
请求区域列表数据 超管可以请求所有区域信息; 其余角色只能请求到分配给自己的区域
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | region | String | F | 筛选区域代码 |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
region: '110000',
regionInfo: ['河北', '石家庄', '桥东区'],
schoolCount: 1,
roomCount: 1,
studentCount: 1,
teacherCount: 1,
buyVipStudentCount: 1,
createRoomTeacherCount: 1,
studentRoomCount: 1,
experiencedVipCount: 1,
experiencingdVipCount: 1
},
{...}
]
}
请求区域详情数据 权限同区域列表一致
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | region | String | T | 目标区域代码 |
返回结果:
{
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": {
date: '2018-05-31T03:34:30.455Z',
region: '110000',
regionInfo: ['河北', '石家庄', '桥东区'],
schoolCount: 1,
roomCount: 1,
studentCount: 1,
teacherCount: 1,
buyVipStudentCount: 1,
createRoomTeacherCount: 1,
studentRoomCount: 1,
experiencedVipCount: 1,
experiencingdVipCount: 1
},
"history": [
{
start: '2018-05-31T03:34:30.455Z',
end: '2018-05-31T03:34:30.455Z',
region: '110000',
regionInfo: ['河北', '石家庄', '桥东区'],
increaseRoom: 1,
increaseTeacher: 1,
increaseStudent: 1,
increaseRoomStudent: 1,
payUser: 1,
activeStudent: 1,
activeRoomStudent: 1
},
{...}
]
}
请求区域内的学校列表 权限同区域列表一致
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | region | String | T | 目标区域代码 |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
schoolNmae: 'a',
roomCount: 1,
teacherCount: 1,
stduentCount: 1,
buyVipStudentCount: 1,
experiencedVipCount: 1,
experiencingVipCount: 1
},
{...}
]
}
请求区域内的学校详情数据
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | schoolId | String | T | 目标学校ID |
返回结果:
{
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": {
date: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
schoolNmae: 'a',
roomCount: 1,
teacherCount: 1,
stduentCount: 1,
buyVipStudentCount: 1,
experiencedVipCount: 1,
experiencingVipCount: 1
},
"history": [
{
start: '2018-05-31T03:34:30.455Z',
end: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
increaseRoom: 1,
increaseTeacher: 1,
increaseStudent: 1,
increaseRoomStudent: 1,
payUser: 1,
activeStudent: 1,
activeRoomStudent: 1
},
{...}
]
}
获取学校中的班级列表
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | schoolId | String | T | 目标学校 ID |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
schoolNmae: 'a',
roomCount: 1,
teacherCount: 1,
stduentCount: 1,
buyVipStudentCount: 1,
experiencedVipCount: 1,
experiencingVipCount: 1
},
{...}
]
}
获取班级详情
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | roomId | String | T | 目标班级ID |
返回结果:
{
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": {
date: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
schoolNmae: 'a',
roomCount: 1,
teacherCount: 1,
stduentCount: 1,
buyVipStudentCount: 1,
experiencedVipCount: 1,
experiencingVipCount: 1
},
"history": [
{
start: '2018-05-31T03:34:30.455Z',
end: '2018-05-31T03:34:30.455Z',
roomId: '5b0f6d469806575cc05d30e6',
activeStudent: 1,
roomStudent: 1,
increaseStudent: 1
},
{...}
]
}
获取学校页面下的教师列表
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | schoolId | String | T | 目标学校 ID |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
schoolId: '5b0f6d469806575cc05d30e6',
teacherId: '5b0f6d469806575cc05d30e6',
teacherName: '刘老师',
schoolNmae: 'X学校',
roomCount: 2
roomIds: ['roomId0', 'roomId1'],
stduentCount: 1,
weekActiveStudentCount: 1,
experiencedVipCount: 1,
experiencingVipCount: 1,
buyVipStudentCount: 1,
registerTime: '2018-05-31T03:34:30.455Z',
activeTime: '2018-05-31T03:34:30.455Z'
},
{...}
]
}
获取班级内的学生列表
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | roomId | String | T | 目标班级 ID |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
studentId: '5b0f6d469806575cc05d30e6',
schoolId: '5b0f6d469806575cc05d30e6',
roomId: '5b0f6d469806575cc05d30e6',
studentName: 'XXXX',
studentNote: 'YYYY', // 学生姓名备注
registerTime: '2018-05-31T03:34:30.455Z',
activeTime: '2018-05-31T03:34:30.455Z',
isExperiencedVip: true,
residueVipDay: 10,
vipExpireTime: '2018-05-31T03:34:30.455Z',
phoneNumber: '180****1234'
},
{...}
]
}
获取指定学校中未分配任何班级的学生列表
输入参数:
Mode | Key | Type | Require | Description |
---|---|---|---|---|
header | Authorization | String | T | 当前用户的 Token |
query | schoolId | String | T | 目标学校 ID |
query | skip | String | F | 用于分页 |
query | limit | String | F | 用于分页 默认 100 |
返回结果:
{
"total": 1234,
"skip": 200,
"limit": 100,
"updateTime": '2018-05-31T03:34:30.455Z', //数据更新时间
"data": [
{
date: '2018-05-31T03:34:30.455Z',
studentId: '5b0f6d469806575cc05d30e6',
schoolId: '5b0f6d469806575cc05d30e6',
roomId: '5b0f6d469806575cc05d30e6',
studentName: 'XXXX',
studentNote: 'YYYY', // 学生姓名备注
registerTime: '2018-05-31T03:34:30.455Z',
activeTime: '2018-05-31T03:34:30.455Z',
isExperiencedVip: true,
residueVipDay: 10,
vipExpireTime: '2018-05-31T03:34:30.455Z',
phoneNumber: '180****1234'
},
{...}
]
}
role | Key | description |
---|---|---|
superAdmin | 超级管理员 | 超级管理员的 regions 会是空的. 因为超管对所有区域都有权限. |
agencyManager | 区域渠道负责人 | |
agency | 渠道代理商 | |
teacherManager | 教师服务负责人 | 查看所有数据权限, 不能管理用户 |
{
"id": "cb2891ee-68a7-11e8-ad65-8bd2fb9e5ebc", // 用户id
"updatedAt": "2018-05-31T03:34:30.455Z", // 更新时间
"createdAt": "2018-05-31T03:34:30.455Z", // 创建时间
"phone": "18012341234", // 手机(登录帐号)
"name": "代理2", // 用户名称
"role": "agency", // 角色
// 创建者信息
"creator": "cb2891ee-68a7-11e8-ad65-8bd2fb9e5ebc",
"creatorName": "YYYYYY",
"regions": ["110000", "120000"], // 负责区域
"status": "enabled" // 状态 enabled/disabled
}
获取: 通过 GET /user-select-tree 接口获取区划状态树数据, 若用于修改已有用户的区划分配, 则需要传 id, 若用于创建新用户时, 则无须指定 id.
渲染: 按照下方节点状态的说明进行状态渲染, Disabled 节点完全不参与状态计算, check/uncheck/half 状态的计算逻辑中只考虑非 Disabled 节点.
操作:
- 当所有可用子级节点都是 check 状态时, 父节点为 check 状态
- 当所有可用子级节点都是 uncheck 状态是, 父节点为 uncheck 状态
- 其他介于二者之间的状态, 父节点均为 half 状态.
回传: 用户操作过程中同步修改之前获取到的区划状态树中节点的 state 字段, 修改完成后, 将该对象整体作为 PUT /user 接口(或POST接口)的 tree 参数传回, 无需传递 regions 参数.
// 单个节点结构 Node
{
"code": "110000", // 标准区划代码
"name": "XXXXXX", // 区域名称
"children": [Node...], // 子节点列表. 叶子节点无此字段
"state": "check" // 节点状态字段
// undefined 或 state 字段不存在, 表示该节点应 Disable
// check 表示节点被选中
// half 表示节点被部分选中
// uncheck 表示节点没有被选中
// 选中与否的判断逻辑中, 忽略 Disable 节点
}
// 整颗树(森林)的结构
[省节点, 省节点, 省节点 ....]
省节点
|-市节点
|-区节点
|-区节点
|-市节点
省节点
|-市节点
|-区节点
请求服务端接口时, 可能会遇到业务逻辑相关的错误, 此类错误会返回 HTTP 4xx 系列错误码, 同时, body 中会包含 JSON 结构的数据, 示例如下:
{
"ok": false,
"message": "somethine wrong",
"msg": "不支持该操作, 请联系管理员"
}
如果 body 中存在 msg
字段, 则通过弹窗或提示框将内容展现给用户. 如果没有 msg
字段, 则无须展示, 仅按照正常业务逻辑处理即可.