重构后端,使其更加权责分明
This commit is contained in:
422
API.md
422
API.md
@@ -7,25 +7,27 @@
|
||||
- [快速开始](#快速开始)
|
||||
- [技术栈](#技术栈)
|
||||
- [项目结构](#项目结构)
|
||||
- [架构分层](#架构分层)
|
||||
- [认证机制](#认证机制)
|
||||
- [API 接口总览](#api-接口总览)
|
||||
- [用户认证](#1-用户认证)
|
||||
- [用户管理](#2-用户管理)
|
||||
- [加盟商管理](#3-加盟商管理)
|
||||
- [员工管理](#4-员工管理)
|
||||
- [合同管理](#5-合同管理)
|
||||
- [售后管理](#6-售后管理)
|
||||
- [产品管理](#7-产品管理)
|
||||
- [供应商管理](#8-供应商管理)
|
||||
- [1. 用户认证](#1-用户认证)
|
||||
- [2. 用户管理](#2-用户管理)
|
||||
- [3. 加盟商管理](#3-加盟商管理)
|
||||
- [4. 员工管理](#4-员工管理)
|
||||
- [5. 合同管理](#5-合同管理)
|
||||
- [6. 售后管理](#6-售后管理)
|
||||
- [7. 产品管理](#7-产品管理)
|
||||
- [8. 供应商管理](#8-供应商管理)
|
||||
- [统一响应格式](#统一响应格式)
|
||||
- [数据库设计](#数据库设计)
|
||||
- [表结构详情](#表结构详情)
|
||||
- [表关系 ER 图](#表关系-er-图)
|
||||
- [RBAC 权限系统](#rbac-权限系统)
|
||||
- [角色定义](#角色定义)
|
||||
- [部门权限系统](#部门权限系统)
|
||||
- [部门定义](#部门定义)
|
||||
- [权限列表](#权限列表)
|
||||
- [角色-权限映射](#角色-权限映射)
|
||||
- [部门-权限映射](#部门-权限映射)
|
||||
- [数据范围隔离](#数据范围隔离)
|
||||
- [中间件说明](#中间件说明)
|
||||
- [预置账号](#预置账号)
|
||||
|
||||
---
|
||||
@@ -70,7 +72,7 @@ node test-all.js
|
||||
| `JWT_SECRET` | JWT 签名密钥 | — |
|
||||
| `JWT_EXPIRES_IN` | Token 有效期 | `2h` |
|
||||
|
||||
> 首次启动时,系统会自动创建数据库、建表、初始化角色权限和预置用户。
|
||||
> 首次启动时,系统会自动创建数据库、建表、初始化部门权限和预置用户。
|
||||
|
||||
---
|
||||
|
||||
@@ -93,22 +95,43 @@ backmanager-server/
|
||||
├── server.js # 入口:Express 应用、鉴权中间件、路由注册
|
||||
├── db.js # 数据库:连接池、建表、种子数据
|
||||
├── middleware/
|
||||
│ └── permissions.js # RBAC:权限检查 + 数据范围过滤
|
||||
│ ├── permissions.js # 权限检查 + 数据范围 + 合同类型校验
|
||||
│ ├── users.js # 用户自保护规则(禁止自改部门、自删等)
|
||||
│ └── employees.js # 员工创建时同步创建用户账号
|
||||
├── routes/
|
||||
│ ├── users.js # 用户登录/信息/CRUD
|
||||
│ ├── customers.js # 加盟商 CRUD
|
||||
│ ├── employees.js # 员工 CRUD
|
||||
│ ├── customers.js # 加盟商 CRUD + 简易列表
|
||||
│ ├── employees.js # 员工 CRUD + 简易列表
|
||||
│ ├── contracts.js # 合同 CRUD
|
||||
│ ├── afterSales.js # 售后 CRUD
|
||||
│ ├── products.js # 产品 CRUD
|
||||
│ └── suppliers.js # 供应商 CRUD
|
||||
├── test-all.js # 集成测试(覆盖 6 个角色的权限与数据隔离)
|
||||
│ └── suppliers.js # 供应商 CRUD + 简易列表
|
||||
├── test-all.js # 集成测试(覆盖 6 个部门的权限与数据隔离,131 条用例)
|
||||
├── API.md # 本文档
|
||||
├── .env.example # 环境变量模板
|
||||
└── package.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 架构分层
|
||||
|
||||
本项目采用**三层分离架构**,各层职责清晰:
|
||||
|
||||
```
|
||||
请求 → 中间件层(认证/权限/数据范围/业务规则)→ 路由层(纯 CRUD,数据库操作)→ 响应
|
||||
```
|
||||
|
||||
| 分层 | 文件 | 职责 |
|
||||
|------|------|------|
|
||||
| **API 端点层** | `server.js` | 路由注册,串联中间件链 |
|
||||
| **中间件层** | `middleware/*.js` | JWT 认证、权限校验、数据范围注入、业务规则校验 |
|
||||
| **数据库查询层** | `routes/*.js` | 纯 SQL CRUD 操作,不做权限判断和业务逻辑 |
|
||||
|
||||
**路由层纯粹性要求:** 所有 `routes/*.js` 只包含数据库的增删改查操作,不参与权限判断、数据范围计算等逻辑。权限和数据范围由中间件通过 `req.user.permissions` 和 `req.scope` 注入。
|
||||
|
||||
---
|
||||
|
||||
## 认证机制
|
||||
|
||||
所有 API(除登录外)需要在请求头中携带 JWT Token:
|
||||
@@ -128,19 +151,29 @@ Authorization: Bearer <token>
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"name": "系统管理员",
|
||||
"role_id": 1,
|
||||
"roleName": "admin",
|
||||
"department": "信息技术部",
|
||||
"department_id": 1,
|
||||
"departmentName": "admin",
|
||||
"departmentDesc": "信息技术部",
|
||||
"permissions": ["customer:read", "customer:create", "customer:update", "customer:delete", "contract:read", "..."]
|
||||
}
|
||||
```
|
||||
|
||||
### 认证流程
|
||||
### 中间件执行流程
|
||||
|
||||
```
|
||||
客户端请求 → auth 中间件验证 Token → checkPermission 检查权限 → 路由处理 → 数据范围过滤(getDataScope)→ 返回响应
|
||||
请求 → auth(验证 Token)→ checkPermission(权限检查)→ dataScope(数据范围注入)→ [业务中间件] → 路由处理 → 响应
|
||||
```
|
||||
|
||||
| 中间件 | 文件 | 说明 |
|
||||
|--------|------|------|
|
||||
| `auth` | `server.js` | 解析并验证 JWT Token,将用户信息挂载到 `req.user` |
|
||||
| `checkPermission(resource, action)` | `middleware/permissions.js` | 检查 `req.user.permissions` 是否包含 `resource:action` |
|
||||
| `dataScope(resource)` | `middleware/permissions.js` | 根据用户部门计算数据范围,挂载 `req.scope = { sql, params }` |
|
||||
| `validateContractType` | `middleware/permissions.js` | 限制招商部只能操作加盟合同,采购部只能操作采购合同 |
|
||||
| `protectSelfUpdate` | `middleware/users.js` | 禁止用户修改自己的部门或禁用自己 |
|
||||
| `protectUserDelete` | `middleware/users.js` | 禁止删除自己或最后一个管理员 |
|
||||
| `allowUserCreation` | `middleware/employees.js` | 允许有 `user:manage` 权限的用户在创建员工时同步创建账号 |
|
||||
|
||||
### 错误响应
|
||||
|
||||
| HTTP 状态码 | 场景 |
|
||||
@@ -158,6 +191,38 @@ Authorization: Bearer <token>
|
||||
- **分页响应**:列表接口返回 `{ list, total, page, pageSize, totalPages }`
|
||||
- **搜索参数**:通过 URL Query String 传递,如 `GET /api/customers?name=张&phone=138`
|
||||
- **部分更新**:PUT 接口只传需要修改的字段即可,未传字段保持不变
|
||||
- **权限要求**:每个接口所需的权限标注在接口标题下方
|
||||
|
||||
### 接口权限速查表
|
||||
|
||||
| 接口 | 方法 | 权限 | 数据范围 |
|
||||
|------|------|------|---------|
|
||||
| `/api/user/login` | POST | 无 | — |
|
||||
| `/api/user/info` | GET | 登录即可 | 仅自己 |
|
||||
| `/api/user/list` | GET | 登录即可 | 所有启用用户 |
|
||||
| `/api/user/logout` | POST | 登录即可 | — |
|
||||
| `/api/user/password` | PUT | 登录即可 | 仅自己 |
|
||||
| `/api/users` | GET/POST | `user:manage` | 全部 |
|
||||
| `/api/users/:id` | GET/PUT/DELETE | `user:manage` | 全部 |
|
||||
| `/api/customers/simple` | GET | `customer:read` | 全部客户 |
|
||||
| `/api/customers` | GET | `customer:read` | 过渡期全量 |
|
||||
| `/api/customers` | POST | `customer:create` | — |
|
||||
| `/api/customers/:id` | GET/PUT/DELETE | 对应权限 | 过渡期全量 |
|
||||
| `/api/employees/simple` | GET | 登录即可 | 全部在职员工 |
|
||||
| `/api/employees` | GET | `employee:read` | 按部门隔离 |
|
||||
| `/api/employees` | POST | `employee:create` | — |
|
||||
| `/api/employees/:id` | GET/PUT/DELETE | 对应权限 | 按部门隔离 |
|
||||
| `/api/contracts` | GET | `contract:read` | 按合同类型隔离 |
|
||||
| `/api/contracts` | POST | `contract:create` | 按部门限制类型 |
|
||||
| `/api/contracts/:id` | GET/PUT/DELETE | 对应权限 | 按合同类型隔离 |
|
||||
| `/api/after-sales` | GET | `after_sale:read` | 过渡期全量 |
|
||||
| `/api/after-sales` | POST | `after_sale:create` | — |
|
||||
| `/api/after-sales/:id` | GET/PUT/DELETE | 对应权限 | 过渡期全量 |
|
||||
| `/api/products` | GET | `product:read` | 全部 |
|
||||
| `/api/products/:id` | GET/PUT/DELETE | 对应权限 | 全部 |
|
||||
| `/api/suppliers/simple` | GET | `supplier:read` | 全部正常供应商 |
|
||||
| `/api/suppliers` | GET | `supplier:read` | 全部 |
|
||||
| `/api/suppliers/:id` | GET/PUT/DELETE | 对应权限 | 全部 |
|
||||
|
||||
---
|
||||
|
||||
@@ -188,9 +253,9 @@ Authorization: Bearer <token>
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"name": "系统管理员",
|
||||
"role_id": 1,
|
||||
"roleName": "admin",
|
||||
"department": "信息技术部",
|
||||
"department_id": 1,
|
||||
"departmentName": "admin",
|
||||
"departmentDesc": "信息技术部",
|
||||
"permissions": ["customer:read", "customer:create", "..."]
|
||||
}
|
||||
}
|
||||
@@ -209,11 +274,30 @@ Authorization: Bearer <token>
|
||||
|
||||
#### GET /api/user/info — 获取当前用户信息
|
||||
|
||||
需要 Token。返回当前登录用户的完整信息(含角色名、员工名)。
|
||||
需要 Token。
|
||||
|
||||
返回当前登录用户的完整信息(含部门名称、员工姓名)。
|
||||
|
||||
**响应数据字段:**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | number | 用户 ID |
|
||||
| `username` | string | 用户名 |
|
||||
| `is_active` | number | 状态:0-禁用, 1-启用 |
|
||||
| `department_id` | number | 部门 ID |
|
||||
| `employee_id` | number | 关联员工 ID |
|
||||
| `dept_name` | string | 部门标识(如 `admin`) |
|
||||
| `dept_desc` | string | 部门中文名(如 信息技术部) |
|
||||
| `real_name` | string | 真实姓名(来自员工表) |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
#### GET /api/user/list — 简易用户列表
|
||||
|
||||
需要 Token。返回所有启用用户的基本信息(id、用户名、真实姓名),用于前端下拉选择负责人。
|
||||
需要 Token(仅需登录,无需特定权限)。
|
||||
|
||||
返回所有启用用户的基本信息,用于前端下拉选择负责人。
|
||||
|
||||
**响应数据字段:**
|
||||
|
||||
@@ -249,7 +333,7 @@ Authorization: Bearer <token>
|
||||
|
||||
### 2. 用户管理
|
||||
|
||||
> 需要 `user:manage` 权限(仅系统管理员拥有)。
|
||||
> 需要 `user:manage` 权限(仅系统管理员 / 信息技术部拥有)。
|
||||
|
||||
#### GET /api/users — 用户列表
|
||||
|
||||
@@ -260,7 +344,7 @@ Authorization: Bearer <token>
|
||||
| `username` | 按用户名模糊搜索 | `?username=admin` |
|
||||
| `real_name` | 按真实姓名模糊搜索 | `?real_name=张` |
|
||||
| `id` | 按用户 ID 精确搜索 | `?id=1` |
|
||||
| `role_id` | 按角色 ID 过滤 | `?role_id=2` |
|
||||
| `department_id` | 按部门 ID 过滤 | `?department_id=2` |
|
||||
| `is_active` | 按状态过滤(0-禁用, 1-启用) | `?is_active=1` |
|
||||
| `page` | 页码 | `?page=1` |
|
||||
| `pageSize` | 每页条数 | `?pageSize=10` |
|
||||
@@ -272,12 +356,11 @@ Authorization: Bearer <token>
|
||||
| `id` | number | 用户 ID |
|
||||
| `username` | string | 用户名 |
|
||||
| `is_active` | number | 状态:0-禁用, 1-启用 |
|
||||
| `role_id` | number | 角色 ID |
|
||||
| `role_name` | string | 角色标识(如 `admin`) |
|
||||
| `role_description` | string | 角色描述(如 系统管理员) |
|
||||
| `department_id` | number | 部门 ID |
|
||||
| `employee_id` | number | 关联员工 ID |
|
||||
| `dept_name` | string | 部门标识(如 `admin`) |
|
||||
| `dept_desc` | string | 部门中文名(如 信息技术部) |
|
||||
| `real_name` | string | 真实姓名(来自员工表) |
|
||||
| `department` | string | 所属部门 |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
@@ -293,24 +376,28 @@ Authorization: Bearer <token>
|
||||
|------|------|------|
|
||||
| `username` | ✅ | 用户名(3-50 字符) |
|
||||
| `password` | ✅ | 密码(至少 6 位) |
|
||||
| `role_id` | ❌ | 角色 ID(需为已存在的角色) |
|
||||
| `employee_id` | ❌ | 关联员工 ID(需为已存在的员工,会自动同步部门信息) |
|
||||
| `department` | ❌ | 所属部门(若填了 employee_id 且未传 department,会自动从员工表同步) |
|
||||
| `department_id` | ❌ | 部门 ID(需为已存在的部门) |
|
||||
| `employee_id` | ❌ | 关联员工 ID(需为已存在的员工) |
|
||||
| `is_active` | ❌ | 状态,默认 1 |
|
||||
|
||||
**校验规则:**
|
||||
- `department_id` 必须存在于 `departments` 表
|
||||
- `employee_id` 必须存在于 `employees` 表
|
||||
- `username` 不可重复(返回 409)
|
||||
|
||||
#### PUT /api/users/:id — 更新用户
|
||||
|
||||
**可更新字段:** `username`、`role_id`、`employee_id`、`department`、`is_active`、`password`
|
||||
**可更新字段:** `username`、`department_id`、`employee_id`、`is_active`、`password`
|
||||
|
||||
**限制:**
|
||||
- 不能修改自己的角色
|
||||
- 不能禁用自己
|
||||
**自保护限制(`protectSelfUpdate` 中间件):**
|
||||
- 不能修改自己的 `department_id`
|
||||
- 不能禁用自己(`is_active` 不能设为 0)
|
||||
|
||||
#### DELETE /api/users/:id — 删除用户
|
||||
|
||||
**限制:**
|
||||
**自保护限制(`protectUserDelete` 中间件):**
|
||||
- 不能删除自己
|
||||
- 不能删除最后一个管理员账号(当系统中仅剩 1 个 admin 角色用户时,拒绝删除)
|
||||
- 不能删除信息技术部的最后一个管理员账号
|
||||
|
||||
---
|
||||
|
||||
@@ -318,6 +405,17 @@ Authorization: Bearer <token>
|
||||
|
||||
> 需要 `customer:read` / `customer:create` / `customer:update` / `customer:delete` 权限。
|
||||
|
||||
#### GET /api/customers/simple — 简易加盟商列表
|
||||
|
||||
需要 `customer:read` 权限。无数据范围限制,用于前端下拉选择。
|
||||
|
||||
**响应数据字段:**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | number | 加盟商 ID |
|
||||
| `name` | string | 加盟商姓名 |
|
||||
|
||||
#### GET /api/customers — 加盟商列表
|
||||
|
||||
**查询参数:**
|
||||
@@ -343,8 +441,6 @@ Authorization: Bearer <token>
|
||||
| `address` | string | 详细地址 |
|
||||
| `email` | string | 电子邮箱 |
|
||||
| `remark` | string | 备注信息 |
|
||||
| `responsible_user_id` | number | 负责人用户 ID |
|
||||
| `responsible_user_name` | string | 负责人姓名(JOIN 自 users → employees) |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
@@ -362,7 +458,6 @@ Authorization: Bearer <token>
|
||||
| `address` | ❌ | 详细地址 |
|
||||
| `email` | ❌ | 电子邮箱 |
|
||||
| `remark` | ❌ | 备注 |
|
||||
| `responsible_user_id` | ❌ | 负责人(默认为当前登录用户,仅管理员可在前端修改) |
|
||||
|
||||
#### PUT /api/customers/:id — 更新加盟商
|
||||
|
||||
@@ -370,6 +465,8 @@ Authorization: Bearer <token>
|
||||
|
||||
#### DELETE /api/customers/:id — 删除加盟商
|
||||
|
||||
**限制:** 被合同或售后记录引用的客户无法删除(返回 400)。
|
||||
|
||||
---
|
||||
|
||||
### 4. 员工管理
|
||||
@@ -378,7 +475,7 @@ Authorization: Bearer <token>
|
||||
|
||||
#### GET /api/employees/simple — 简易员工列表
|
||||
|
||||
需要 Token。无数据范围限制,用于前端下拉选择(如售后分配业务员)。支持按部门过滤。
|
||||
需要 Token(仅需登录)。无数据范围限制,用于前端下拉选择。支持按部门过滤。
|
||||
|
||||
**查询参数:**
|
||||
|
||||
@@ -444,18 +541,27 @@ Authorization: Bearer <token>
|
||||
| `email` | ❌ | 邮箱 |
|
||||
| `status` | ❌ | 在职状态,默认 1 |
|
||||
| `remark` | ❌ | 备注 |
|
||||
| `username` | ❌ | 需同步创建用户时填写(需 `user:manage` 权限) |
|
||||
| `password` | ❌ | 需同步创建用户时填写(需 `user:manage` 权限) |
|
||||
| `department_id` | ❌ | 需同步创建用户时填写(指定用户所属部门 ID) |
|
||||
|
||||
**同步创建用户账号(`allowUserCreation` 中间件):**
|
||||
|
||||
当同时传入 `username`、`password`、`department_id` 三个字段时:
|
||||
- 需要拥有 `user:manage` 权限
|
||||
- 系统会在创建员工后自动创建关联的系统用户账号
|
||||
- `username` 长度 3-50 字符,`password` 至少 6 位
|
||||
|
||||
#### PUT /api/employees/:id — 更新员工
|
||||
|
||||
所有字段均可选,只传需要修改的字段。
|
||||
|
||||
**特殊行为:** 更新 `department` 字段时,会自动同步到关联的 users 表的 `department` 字段。
|
||||
|
||||
#### DELETE /api/employees/:id — 删除员工
|
||||
|
||||
**特殊行为:**
|
||||
- 删除员工时会同步删除关联的用户账号(users 表中 `employee_id` 匹配的记录)
|
||||
- 删除员工时会同步删除关联的用户账号(`users` 表中 `employee_id` 匹配的记录)
|
||||
- 不能删除当前登录用户自己关联的员工账号
|
||||
- 被合同或售后记录引用的员工无法删除(返回 400)
|
||||
|
||||
---
|
||||
|
||||
@@ -470,7 +576,7 @@ Authorization: Bearer <token>
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| `id` | 按 ID 精确搜索 |
|
||||
| `status` | 按合同状态过滤(草稿/生效中/已完成/作废) |
|
||||
| `status` | 按合同状态过滤(草稿/生效/完成/作废) |
|
||||
| `customer_name` | 按客户名称模糊搜索 |
|
||||
| `contract_no` | 按合同编号模糊搜索 |
|
||||
| `contract_name` | 按合同名称模糊搜索 |
|
||||
@@ -483,9 +589,9 @@ Authorization: Bearer <token>
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | number | 合同 ID |
|
||||
| `customer_id` | number | 客户 ID |
|
||||
| `customer_id` | number | 客户 ID(加盟合同必填,采购合同为 null) |
|
||||
| `customer_name` | string | 客户名称(JOIN 自 customers) |
|
||||
| `supplier_id` | number | 供应商 ID(采购合同必填) |
|
||||
| `supplier_id` | number | 供应商 ID(采购合同必填,加盟合同为 null) |
|
||||
| `supplier_name` | string | 供应商名称(JOIN 自 suppliers) |
|
||||
| `contract_name` | string | 合同名称 |
|
||||
| `contract_no` | string | 合同编号 |
|
||||
@@ -495,7 +601,7 @@ Authorization: Bearer <token>
|
||||
| `expiry_date` | date | 到期日期 |
|
||||
| `employee_id` | number | 业务员 ID |
|
||||
| `employee_name` | string | 业务员姓名(JOIN 自 employees) |
|
||||
| `status` | string | 状态:草稿/生效中/已完成/作废 |
|
||||
| `status` | string | 状态:草稿/生效/完成/作废 |
|
||||
| `remark` | string | 备注 |
|
||||
| `type` | string | 合同类型:`franchise`(加盟)/ `supply`(采购) |
|
||||
| `responsible_user_id` | number | 负责人用户 ID |
|
||||
@@ -523,10 +629,13 @@ Authorization: Bearer <token>
|
||||
| `type` | ❌ | 合同类型(见下方说明) |
|
||||
| `responsible_user_id` | ❌ | 负责人(默认为当前用户,仅管理员可在前端修改) |
|
||||
|
||||
**合同类型自动设置与角色限制规则:**
|
||||
- 采购经理(`procurement_manager`)创建的合同**只能**为 `supply`(采购合同),且必须选择 `supplier_id`
|
||||
- 招商经理(`franchise_manager`)创建的合同**只能**为 `franchise`(加盟合同),且必须选择 `customer_id`
|
||||
- 其他角色默认 `franchise`,也可手动指定 `type`
|
||||
**合同类型限制(`validateContractType` 中间件):**
|
||||
|
||||
| 部门 | 允许的合同类型 | 说明 |
|
||||
|------|-------------|------|
|
||||
| 招商部 (`franchise_manager`) | 仅 `franchise` | 只能创建加盟合同,且必须选择 `customer_id` |
|
||||
| 采购部 (`procurement_manager`) | 仅 `supply` | 只能创建采购合同,且必须选择 `supplier_id` |
|
||||
| 信息技术部/总经理/财务 | 不限制 | 默认 `franchise`,可手动指定 |
|
||||
|
||||
**校验规则:**
|
||||
- `customer_id` 必须为已存在的客户
|
||||
@@ -537,10 +646,12 @@ Authorization: Bearer <token>
|
||||
|
||||
所有字段均可选。可更新字段包括 `type`、`supplier_id` 和 `responsible_user_id`。
|
||||
|
||||
**校验规则:** 更新 `customer_id`、`supplier_id`、`employee_id` 时会校验关联记录是否存在。
|
||||
**校验规则:** 更新 `customer_id`、`supplier_id`、`employee_id` 时会校验关联记录是否存在。合同类型限制同创建。
|
||||
|
||||
#### DELETE /api/contracts/:id — 删除合同
|
||||
|
||||
**限制:** 被售后记录引用的合同无法删除(返回 400)。
|
||||
|
||||
---
|
||||
|
||||
### 6. 售后管理
|
||||
@@ -574,6 +685,7 @@ Authorization: Bearer <token>
|
||||
| `service_date` | date | 售后日期 |
|
||||
| `remark` | string | 备注 |
|
||||
| `responsible_user_id` | number | 负责人用户 ID |
|
||||
| `responsible_user_name` | string | 负责人姓名(JOIN 自 users → employees) |
|
||||
| `created_at` | datetime | 创建时间 |
|
||||
| `updated_at` | datetime | 更新时间 |
|
||||
|
||||
@@ -666,6 +778,17 @@ Authorization: Bearer <token>
|
||||
> 需要 `supplier:read` / `supplier:create` / `supplier:update` / `supplier:delete` 权限。
|
||||
> 无数据范围隔离,拥有权限即可查看所有供应商。
|
||||
|
||||
#### GET /api/suppliers/simple — 简易供应商列表
|
||||
|
||||
需要 `supplier:read` 权限。返回所有正常状态供应商的基本信息,用于前端下拉选择。
|
||||
|
||||
**响应数据字段:**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `id` | number | 供应商 ID |
|
||||
| `name` | string | 供应商名称 |
|
||||
|
||||
#### GET /api/suppliers — 供应商列表
|
||||
|
||||
**查询参数:**
|
||||
@@ -755,7 +878,7 @@ Authorization: Bearer <token>
|
||||
|------------|------|------|
|
||||
| 400 | 400 | 参数错误 / 校验失败 / 关联记录不存在 |
|
||||
| 401 | 401 | 未登录 / Token 无效 |
|
||||
| 403 | 403 | 权限不足 / 账号被禁用 / 角色操作限制 |
|
||||
| 403 | 403 | 权限不足 / 账号被禁用 / 合同类型不匹配 |
|
||||
| 404 | 404 | 资源不存在 |
|
||||
| 409 | 409 | 数据冲突(如用户名重复) |
|
||||
| 500 | 500 | 服务器内部错误 |
|
||||
@@ -768,7 +891,7 @@ Authorization: Bearer <token>
|
||||
|
||||
#### 1. users — 系统用户表
|
||||
|
||||
存储系统登录账号,每个用户关联一个角色和一个员工。
|
||||
存储系统登录账号,每个用户关联一个部门和一个员工。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
@@ -776,19 +899,18 @@ Authorization: Bearer <token>
|
||||
| `username` | VARCHAR(50) | NOT NULL, UNIQUE | 用户名(登录账号) |
|
||||
| `password` | VARCHAR(255) | NOT NULL | 密码(bcrypt 哈希) |
|
||||
| `is_active` | TINYINT(1) | NOT NULL DEFAULT 1 | 账号状态:0-禁用, 1-启用 |
|
||||
| `role_id` | INT | NULLABLE | 角色 ID → roles.id |
|
||||
| `department_id` | INT | NULLABLE | 部门 ID → departments.id |
|
||||
| `employee_id` | INT | NULLABLE, UNIQUE | 员工 ID → employees.id |
|
||||
| `department` | VARCHAR(100) | NULLABLE | 所属部门(冗余字段,从 employees 同步) |
|
||||
| `created_at` | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| `updated_at` | DATETIME | ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 2. roles — 角色表
|
||||
#### 2. departments — 部门表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | INT | PK, AUTO_INCREMENT | 角色 ID |
|
||||
| `name` | VARCHAR(50) | NOT NULL, UNIQUE | 角色标识(英文) |
|
||||
| `description` | VARCHAR(200) | NULLABLE | 角色描述(中文) |
|
||||
| `id` | INT | PK, AUTO_INCREMENT | 部门 ID |
|
||||
| `name` | VARCHAR(50) | NOT NULL, UNIQUE | 部门标识(英文) |
|
||||
| `description` | VARCHAR(200) | NULLABLE | 部门名称(中文) |
|
||||
| `created_at` | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
#### 3. permissions — 权限表
|
||||
@@ -801,11 +923,11 @@ Authorization: Bearer <token>
|
||||
| `resource` | VARCHAR(50) | NOT NULL | 资源名称 |
|
||||
| `action` | VARCHAR(50) | NOT NULL | 操作类型 |
|
||||
|
||||
#### 4. role_permissions — 角色-权限关联表
|
||||
#### 4. department_permissions — 部门-权限关联表
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `role_id` | INT | PK (联合) | 角色 ID → roles.id |
|
||||
| `department_id` | INT | PK (联合) | 部门 ID → departments.id |
|
||||
| `permission_id` | INT | PK (联合) | 权限 ID → permissions.id |
|
||||
|
||||
#### 5. customers — 加盟商信息表
|
||||
@@ -821,7 +943,6 @@ Authorization: Bearer <token>
|
||||
| `address` | VARCHAR(200) | — | 详细地址 |
|
||||
| `email` | VARCHAR(100) | — | 电子邮箱 |
|
||||
| `remark` | TEXT | — | 备注信息 |
|
||||
| `responsible_user_id` | INT | — | 负责人用户 ID → users.id |
|
||||
| `created_at` | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| `updated_at` | DATETIME | ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
@@ -850,8 +971,8 @@ Authorization: Bearer <token>
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | INT | PK, AUTO_INCREMENT | 合同 ID |
|
||||
| `customer_id` | INT | NULLABLE, INDEX | 客户 ID → customers.id(加盟合同必填) |
|
||||
| `supplier_id` | INT | NULLABLE, INDEX | 供应商 ID → suppliers.id(采购合同必填) |
|
||||
| `customer_id` | INT | NULLABLE, INDEX | 客户 ID → customers.id(加盟合同必填,采购合同为 null) |
|
||||
| `supplier_id` | INT | NULLABLE, INDEX | 供应商 ID → suppliers.id(采购合同必填,加盟合同为 null) |
|
||||
| `contract_name` | VARCHAR(200) | NOT NULL | 合同名称 |
|
||||
| `contract_no` | VARCHAR(100) | — | 合同编号 |
|
||||
| `contract_content` | TEXT | — | 合同内容/条款 |
|
||||
@@ -859,7 +980,7 @@ Authorization: Bearer <token>
|
||||
| `effective_date` | DATE | INDEX | 生效日期 |
|
||||
| `expiry_date` | DATE | — | 到期日期 |
|
||||
| `employee_id` | INT | INDEX | 业务员 ID → employees.id |
|
||||
| `status` | VARCHAR(20) | NOT NULL DEFAULT '生效中' | 状态:草稿/生效中/已完成/作废 |
|
||||
| `status` | VARCHAR(20) | NOT NULL DEFAULT '生效' | 状态:草稿/生效/完成/作废 |
|
||||
| `remark` | TEXT | — | 备注 |
|
||||
| `type` | VARCHAR(20) | NOT NULL DEFAULT 'franchise' | 类型:`franchise`(加盟) / `supply`(采购) |
|
||||
| `responsible_user_id` | INT | — | 负责人用户 ID → users.id |
|
||||
@@ -918,13 +1039,13 @@ Authorization: Bearer <token>
|
||||
### 表关系 ER 图
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
|
||||
│ roles │ │ permissions │ │ role_permissions │
|
||||
│──────────────│ │──────────────│ │──────────────────│
|
||||
│ id (PK) │◄─┐ │ id (PK) │◄─┐ │ role_id (PK,FK) │
|
||||
│ name │ │ │ name │ └──│ permission_id │
|
||||
│ description │ │ │ description │ │ (PK,FK) │
|
||||
└──────────────┘ │ │ resource │ └──────────────────┘
|
||||
┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐
|
||||
│ departments │ │ permissions │ │ department_permissions │
|
||||
│──────────────│ │──────────────│ │────────────────────────│
|
||||
│ id (PK) │◄─┐ │ id (PK) │◄─┐ │ department_id (PK,FK) │
|
||||
│ name │ │ │ name │ │ │ permission_id (PK,FK) │
|
||||
│ description │ │ │ description │ └──│ → permissions.id │
|
||||
└──────────────┘ │ │ resource │ └────────────────────────┘
|
||||
│ │ action │
|
||||
│ └──────────────┘
|
||||
│
|
||||
@@ -935,12 +1056,12 @@ Authorization: Bearer <token>
|
||||
│ username │ │ │ name │
|
||||
│ password │ │ │ gender │
|
||||
│ is_active │ │ │ age │
|
||||
│ role_id (FK)─┼──┘ │ education │
|
||||
│ employee_id │─ ─ ─│ department │◄──────── users.department (冗余)
|
||||
│ (FK) ──────┼──→ │ entry_date │
|
||||
│ department │ │ position │
|
||||
│ (冗余) │ │ salary │
|
||||
└──────┬───────┘ │ phone │
|
||||
│ department_id│──┘ │ education │
|
||||
│ (FK) │ │ department │◄──── 数据范围隔离字段
|
||||
│ employee_id │─ ─ ─│ entry_date │
|
||||
│ (FK) ──────┼──→ │ position │
|
||||
└──────┬───────┘ │ salary │
|
||||
│ │ phone │
|
||||
│ │ email │
|
||||
│ │ status │
|
||||
│ └──────┬───────┘
|
||||
@@ -951,7 +1072,6 @@ Authorization: Bearer <token>
|
||||
│──────────────────────────────────────────────│
|
||||
│ id (PK) │
|
||||
│ name, phone, province, city, district, ... │
|
||||
│ responsible_user_id ──────────→ users.id │
|
||||
└────────────────────┬─────────────────────────┘
|
||||
│
|
||||
┌──────────┴──────────┐
|
||||
@@ -995,12 +1115,11 @@ Authorization: Bearer <token>
|
||||
|
||||
| 关系 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| users → roles | 多对一 | 一个用户属于一个角色,一个角色可以有多个用户 |
|
||||
| users → departments | 多对一 | 一个用户属于一个部门,一个部门可以有多个用户 |
|
||||
| users → employees | 一对一 | 一个用户关联一个员工(通过 employee_id,唯一约束) |
|
||||
| roles ↔ permissions | 多对多 | 通过 role_permissions 中间表关联 |
|
||||
| customers → users | 多对一 | 通过 responsible_user_id 指定负责人 |
|
||||
| contracts → customers | 多对一 | 通过 customer_id 关联客户(加盟合同必填) |
|
||||
| contracts → suppliers | 多对一 | 通过 supplier_id 关联供应商(采购合同必填) |
|
||||
| departments ↔ permissions | 多对多 | 通过 department_permissions 中间表关联 |
|
||||
| contracts → customers | 多对一 | 通过 customer_id 关联客户(加盟合同必填,采购合同为 null) |
|
||||
| contracts → suppliers | 多对一 | 通过 supplier_id 关联供应商(采购合同必填,加盟合同为 null) |
|
||||
| contracts → employees | 多对一 | 通过 employee_id 关联业务员 |
|
||||
| contracts → users | 多对一 | 通过 responsible_user_id 指定负责人 |
|
||||
| after_sales → customers | 多对一 | 通过 customer_id 关联客户 |
|
||||
@@ -1011,20 +1130,20 @@ Authorization: Bearer <token>
|
||||
|
||||
---
|
||||
|
||||
## RBAC 权限系统
|
||||
## 部门权限系统
|
||||
|
||||
### 角色定义
|
||||
### 部门定义
|
||||
|
||||
系统预置 6 个角色,对应蜜雪冰城总部的组织架构:
|
||||
系统预置 6 个部门,对应蜜雪冰城总部的组织架构:
|
||||
|
||||
| 角色标识 | 中文名 | 所属部门 | 职责概述 |
|
||||
|---------|--------|---------|---------|
|
||||
| `admin` | 系统管理员 | 信息技术部 | 系统全权管理,拥有所有权限 |
|
||||
| `general_manager` | 总经理 | 总经理办公室 | 全局只读,查看所有业务数据 |
|
||||
| `franchise_manager` | 招商经理 | 招商部 | 管理加盟商和加盟合同 |
|
||||
| `operations_manager` | 运营经理 | 运营部 | 维护加盟商信息、处理售后 |
|
||||
| `procurement_manager` | 采购经理 | 采购部 | 管理产品、供应商和采购合同 |
|
||||
| `finance` | 财务人员 | 财务部 | 只读查看业务数据(加盟商、合同、售后、员工) |
|
||||
| 部门标识 | 中文名 | 职责概述 |
|
||||
|---------|--------|---------|
|
||||
| `admin` | 信息技术部 | 系统全权管理,拥有所有权限 |
|
||||
| `general_manager` | 总经理办公室 | 全局只读,查看所有业务数据 |
|
||||
| `franchise_manager` | 招商部 | 管理加盟商和加盟合同 |
|
||||
| `operations_manager` | 运营部 | 维护加盟商信息、处理售后 |
|
||||
| `procurement_manager` | 采购部 | 管理产品、供应商和采购合同 |
|
||||
| `finance` | 财务部 | 只读查看业务数据(加盟商、合同、售后、员工) |
|
||||
|
||||
### 权限列表
|
||||
|
||||
@@ -1065,15 +1184,15 @@ Authorization: Bearer <token>
|
||||
| **用户 (user)** | |
|
||||
| `user:manage` | 管理用户账号 |
|
||||
|
||||
### 角色-权限映射
|
||||
### 部门-权限映射
|
||||
|
||||
| 权限 | admin | general_manager | franchise_manager | operations_manager | procurement_manager | finance |
|
||||
|------|:-----:|:---------------:|:-----------------:|:------------------:|:-------------------:|:-------:|
|
||||
| customer:read | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
|
||||
| customer:read | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| customer:create | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| customer:update | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ |
|
||||
| customer:update | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| customer:delete | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| contract:read | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| contract:read | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| contract:create | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
|
||||
| contract:update | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
|
||||
| contract:delete | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
|
||||
@@ -1097,30 +1216,64 @@ Authorization: Bearer <token>
|
||||
|
||||
### 数据范围隔离
|
||||
|
||||
拥有操作权限 ≠ 能看到所有数据。系统通过 `getDataScope()` 函数在 SQL 查询层面做数据隔离:
|
||||
拥有操作权限 ≠ 能看到所有数据。系统通过 `dataScope()` 中间件在 SQL 查询层面做数据隔离:
|
||||
|
||||
| 资源 | admin | general_manager | franchise_manager | operations_manager | procurement_manager | finance |
|
||||
|------|-------|-----------------|-------------------|--------------------|--------------------|---------|
|
||||
| customers | 全部 | 全部 | 仅自己负责 | 仅自己负责 | — | 全部 |
|
||||
| contracts | 全部 | 全部 | 仅自己负责的加盟合同 | 仅自己负责的加盟合同 | 仅采购合同 | 全部 |
|
||||
| after_sales | 全部 | 全部 | — | 仅自己负责 | — | 全部 |
|
||||
| customers | 全部 | 全部 | 全部(过渡期) | 全部(过渡期) | 全部 | 全部 |
|
||||
| contracts | 全部 | 全部 | 仅加盟合同 | — | 仅采购合同 | 全部 |
|
||||
| after_sales | 全部 | 全部 | — | 全部(过渡期) | — | 全部 |
|
||||
| employees | 全部 | 全部 | 仅本部门 | 仅本部门 | 仅本部门 | 全部 |
|
||||
| products | 全部 | 全部 | — | — | 全部 | — |
|
||||
| suppliers | 全部 | 全部 | — | — | 全部 | — |
|
||||
| users | 全部 | — | — | — | — | — |
|
||||
|
||||
> **"—"** 表示该角色无此资源的权限,请求会被权限中间件直接拦截(返回 403)。
|
||||
> **"—"** 表示该部门无此资源的权限,请求会被 `checkPermission` 中间件直接拦截(返回 403)。
|
||||
|
||||
**隔离机制说明:**
|
||||
- **负责人类资源**(customers、contracts、after_sales):通过 `responsible_user_id` 字段过滤,只能看到自己负责的记录
|
||||
- **合同类型过滤**(contracts):除了负责人类过滤,还按合同 `type` 字段过滤(franchise/supply)
|
||||
- **部门类资源**(employees):通过 `department` 字段过滤,只能看到自己部门的员工
|
||||
- **全局类资源**(products、suppliers):无数据范围过滤,只要有权限就能看到全部
|
||||
|
||||
**合同类型与角色限制:**
|
||||
- 采购经理(`procurement_manager`)只能查看和操作采购合同(`type = 'supply'`)
|
||||
- 招商经理(`franchise_manager`)和运营经理(`operations_manager`)只能查看和操作加盟合同(`type = 'franchise'`)中自己负责的记录
|
||||
- 创建合同时,采购经理只能创建采购合同,招商经理只能创建加盟合同
|
||||
| 隔离类型 | 资源 | 实现方式 |
|
||||
|---------|------|---------|
|
||||
| 合同类型过滤 | contracts | 招商部只能看到 `type = 'franchise'`,采购部只能看到 `type = 'supply'` |
|
||||
| 部门过滤 | employees | 招商部/运营部/采购部只能看到本部门员工(`department = 本部门名称`) |
|
||||
| 过渡期全量 | customers, after_sales | 当前不注入数据范围,所有部门看到全量数据 |
|
||||
| 无隔离 | products, suppliers | 无数据范围过滤,有权限即可看到全部 |
|
||||
|
||||
**过渡期说明:**
|
||||
- `customers` 已移除 `responsible_user_id` 字段,不再需要负责人隔离
|
||||
- `after_sales` 的 `dataScope()` 当前为占位状态(不注入任何 scope),所有有权限的部门都能看到全量数据
|
||||
- 后续可基于 `responsible_user_id` 对 contracts/after_sales 激活负责人隔离
|
||||
|
||||
**合同类型与部门限制(`validateContractType` 中间件):**
|
||||
- 招商部(`franchise_manager`)只能创建/修改加盟合同(`type = 'franchise'`)
|
||||
- 采购部(`procurement_manager`)只能创建/修改采购合同(`type = 'supply'`)
|
||||
- 信息技术部/总经理/财务不限制
|
||||
|
||||
### 中间件说明
|
||||
|
||||
| 中间件 | 文件 | 类型 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| `auth` | `server.js` | 认证 | 解析 JWT Token,将 `{ id, username, name, department_id, departmentName, departmentDesc, permissions }` 挂到 `req.user` |
|
||||
| `checkPermission(resource, action)` | `middleware/permissions.js` | 权限 | 检查 `req.user.permissions` 是否包含 `"resource:action"`,否 → 403 |
|
||||
| `dataScope(resource)` | `middleware/permissions.js` | 数据范围 | 根据用户部门计算 SQL 过滤条件,挂到 `req.scope = { sql, params }`;admin/general_manager 不注入(全量) |
|
||||
| `validateContractType` | `middleware/permissions.js` | 业务规则 | 限制招商部/采购部只能操作对应类型的合同 |
|
||||
| `protectSelfUpdate` | `middleware/users.js` | 自保护 | 禁止用户修改自己的部门或禁用自己 |
|
||||
| `protectUserDelete` | `middleware/users.js` | 自保护 | 禁止用户删除自己或删除信息技术部最后一个管理员 |
|
||||
| `allowUserCreation` | `middleware/employees.js` | 业务规则 | 允许有 `user:manage` 权限的用户在创建员工时同步创建系统账号 |
|
||||
|
||||
**`req.scope` 注入格式:**
|
||||
|
||||
```javascript
|
||||
// 示例:招商部查看合同时注入
|
||||
req.scope = {
|
||||
sql: 'AND type = ?',
|
||||
params: ['franchise']
|
||||
}
|
||||
|
||||
// 路由层机械使用(contracts list/detail 需加 c. 别名前缀)
|
||||
where += ' ' + req.scope.sql.replace(/\btype\b/g, 'c.type')
|
||||
params.push(...req.scope.params)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -1128,14 +1281,27 @@ Authorization: Bearer <token>
|
||||
|
||||
系统首次启动时自动创建以下账号,密码均为 `123456`:
|
||||
|
||||
| 用户名 | 姓名 | 角色 | 部门 | 职位 |
|
||||
|--------|------|------|------|------|
|
||||
| `admin` | 系统管理员 | admin | 信息技术部 | 系统管理员 |
|
||||
| `zhangchao` | 张超 | general_manager | 总经理办公室 | 总经理 |
|
||||
| `liming` | 李明 | franchise_manager | 招商部 | 招商经理 |
|
||||
| `wangli` | 王丽 | operations_manager | 运营部 | 运营经理 |
|
||||
| `zhaoqiang` | 赵强 | procurement_manager | 采购部 | 采购经理 |
|
||||
| `chenfang` | 陈芳 | finance | 财务部 | 财务主管 |
|
||||
| 用户名 | 姓名 | 部门标识 | 部门 | 职位 |
|
||||
|--------|------|---------|------|------|
|
||||
| `admin` | 系统管理员 | `admin` | 信息技术部 | 系统管理员 |
|
||||
| `zhangchao` | 张超 | `general_manager` | 总经理办公室 | 总经理 |
|
||||
| `liming` | 李明 | `franchise_manager` | 招商部 | 招商经理 |
|
||||
| `wangli` | 王丽 | `operations_manager` | 运营部 | 运营经理 |
|
||||
| `zhaoqiang` | 赵强 | `procurement_manager` | 采购部 | 采购经理 |
|
||||
| `chenfang` | 陈芳 | `finance` | 财务部 | 财务主管 |
|
||||
|
||||
**额外预置账号**(业务员工,同样密码 `123456`):
|
||||
|
||||
| 用户名 | 姓名 | 部门 | 职位 |
|
||||
|--------|------|------|------|
|
||||
| `liuyang` | 刘洋 | 招商部 | 招商专员 |
|
||||
| `sunting` | 孙婷 | 招商部 | 招商专员 |
|
||||
| `zhoujie` | 周杰 | 运营部 | 运营专员 |
|
||||
| `wumin` | 吴敏 | 运营部 | 运营专员 |
|
||||
| `zhengwei` | 郑伟 | 运营部 | 售后工程师 |
|
||||
| `huanglei` | 黄磊 | 采购部 | 采购专员 |
|
||||
| `mali` | 马丽 | 财务部 | 会计 |
|
||||
| `linfeng` | 林峰 | 总经理办公室 | 副总经理 |
|
||||
|
||||
### 快速测试
|
||||
|
||||
@@ -1145,7 +1311,7 @@ curl -X POST http://127.0.0.1:3000/api/user/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"123456"}'
|
||||
|
||||
# 以招商经理身份登录(只能看到自己负责的加盟商)
|
||||
# 以招商经理身份登录(只能看到加盟合同)
|
||||
curl -X POST http://127.0.0.1:3000/api/user/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"liming","password":"123456"}'
|
||||
|
||||
Reference in New Issue
Block a user