Files
backmanager-server/API.md

48 KiB
Raw Permalink Blame History

蜜雪冰城企业管理系统 —— 后端 API 文档

蜜雪冰城总部用于管理加盟商、合同、员工、产品、供应商及售后服务的企业信息管理系统后端服务。

目录


快速开始

环境要求

  • Node.js >= 18
  • MySQL 5.7+ / MariaDB 10.2+

安装与运行

# 1. 安装依赖
npm install

# 2. 配置环境变量
cp .env.example .env
# 编辑 .env 填入数据库连接信息和 JWT 密钥

# 3. 启动开发服务(自动重启)
npm run dev

# 4. 启动生产服务
npm start

# 5. 运行集成测试(需先启动服务)
node test-all.js

环境变量 (.env)

变量 说明 默认值
PORT 服务端口 3000
DB_HOST MySQL 主机
DB_PORT MySQL 端口 3306
DB_USER MySQL 用户名
DB_PASSWORD MySQL 密码
DB_NAME 数据库名 backmanager
JWT_SECRET JWT 签名密钥
JWT_EXPIRES_IN Token 有效期 2h

首次启动时,系统会自动创建数据库、建表、初始化部门权限和预置用户。


技术栈

技术 用途
Express 5 Web 框架
mysql2/promise MySQL 驱动(连接池 + Promise
jsonwebtoken JWT 认证
bcryptjs 密码哈希加密
dotenv 环境变量管理

项目结构

backmanager-server/
├── server.js                  # 入口Express 应用、鉴权中间件、路由注册
├── db.js                      # 数据库:连接池、建表、种子数据
├── middleware/
│   ├── permissions.js         # 权限检查 + 数据范围 + 合同类型校验
│   ├── users.js               # 用户自保护规则(禁止自改部门、自删等)
│   └── employees.js           # 员工创建时同步创建用户账号
├── routes/
│   ├── users.js               # 用户登录/信息/CRUD
│   ├── customers.js           # 加盟商 CRUD + 简易列表
│   ├── employees.js           # 员工 CRUD + 简易列表
│   ├── contracts.js           # 合同 CRUD
│   ├── afterSales.js          # 售后 CRUD
│   ├── products.js            # 产品 CRUD
│   └── 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.permissionsreq.scope 注入。


认证机制

所有 API除登录外需要在请求头中携带 JWT Token

Authorization: Bearer <token>

Token 获取

通过 POST /api/user/login 登录获取 Token。

Token 有效载荷 (Payload)

{
  "id": 1,
  "username": "admin",
  "name": "系统管理员",
  "department_id": 1,
  "departmentName": "admin",
  "departmentDesc": "信息技术部",
  "permissions": ["customer:read", "customer:create", "customer:update", "customer:delete", "contract:read", "..."]
}

中间件执行流程

请求 → 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 状态码 场景
401 未携带 Token 或 Token 无效/过期
403 权限不足(无对应操作权限或数据不在可见范围内)

API 接口总览

通用说明

  • 分页参数:所有列表接口支持 page(页码,从 1 开始,默认 1pageSize(每页条数,默认 10最大 100
  • 分页响应:列表接口返回 { 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 对应权限 全部

1. 用户认证

POST /api/user/login — 登录

无需 Token。

请求体:

{
  "username": "admin",
  "password": "123456"
}

成功响应:

{
  "code": 200,
  "message": "ok",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "userInfo": {
      "id": 1,
      "username": "admin",
      "name": "系统管理员",
      "department_id": 1,
      "departmentName": "admin",
      "departmentDesc": "信息技术部",
      "permissions": ["customer:read", "customer:create", "..."]
    }
  }
}

注意:登录成功返回 code: 200,其他接口统一返回 code: 0。前端通过 res.code === 0 || res.code === 200 兼容判断。

错误响应:

code message
400 用户名和密码必填
400 账号或密码错误
403 账号已被禁用,请联系管理员

GET /api/user/info — 获取当前用户信息

需要 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 number 用户 ID
username string 用户名
real_name string 真实姓名(来自员工表,可能为 null

POST /api/user/logout — 登出

需要 Token。服务端无状态仅返回成功应答客户端自行清除 Token。

PUT /api/user/password — 修改密码

需要 Token。修改当前登录用户自己的密码。

请求体:

{
  "oldPassword": "123456",
  "newPassword": "654321"
}

校验规则:

  • 旧密码和新密码必填
  • 新密码至少 6 位
  • 新密码不能与旧密码相同

2. 用户管理

需要 user:manage 权限(仅系统管理员 / 信息技术部拥有)。

GET /api/users — 用户列表

查询参数:

参数 说明 示例
username 按用户名模糊搜索 ?username=admin
real_name 按真实姓名模糊搜索 ?real_name=张
id 按用户 ID 精确搜索 ?id=1
department_id 按部门 ID 过滤 ?department_id=2
is_active 按状态过滤0-禁用, 1-启用) ?is_active=1
page 页码 ?page=1
pageSize 每页条数 ?pageSize=10

响应数据字段:

字段 类型 说明
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/users/:id — 用户详情

返回单个用户完整信息。

POST /api/users — 创建用户

请求体:

字段 必填 说明
username 用户名3-50 字符)
password 密码(至少 6 位)
department_id 部门 ID需为已存在的部门
employee_id 关联员工 ID需为已存在的员工
is_active 状态,默认 1

校验规则:

  • department_id 必须存在于 departments
  • employee_id 必须存在于 employees
  • username 不可重复(返回 409

PUT /api/users/:id — 更新用户

可更新字段: usernamedepartment_idemployee_idis_activepassword

自保护限制(protectSelfUpdate 中间件):

  • 不能修改自己的 department_id
  • 不能禁用自己(is_active 不能设为 0

DELETE /api/users/:id — 删除用户

自保护限制(protectUserDelete 中间件):

  • 不能删除自己
  • 不能删除信息技术部的最后一个管理员账号

3. 加盟商管理

需要 customer:read / customer:create / customer:update / customer:delete 权限。

GET /api/customers/simple — 简易加盟商列表

需要 customer:read 权限。无数据范围限制,用于前端下拉选择。

响应数据字段:

字段 类型 说明
id number 加盟商 ID
name string 加盟商姓名

GET /api/customers — 加盟商列表

查询参数:

参数 说明
id 按 ID 精确搜索
name 按加盟商名称模糊搜索
phone 按电话模糊搜索
province 按省份精确匹配
city 按城市精确匹配

响应数据字段(含 JOIN 字段):

字段 类型 说明
id number 加盟商 ID
name string 加盟商姓名
phone string 联系电话
province string
city string
district string
address string 详细地址
email string 电子邮箱
remark string 备注信息
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/customers — 新增加盟商

请求体:

字段 必填 说明
name 加盟商姓名
phone 联系电话
province
city
district
address 详细地址
email 电子邮箱
remark 备注

PUT /api/customers/:id — 更新加盟商

所有字段均可选,只传需要修改的字段。

DELETE /api/customers/:id — 删除加盟商

限制: 被合同或售后记录引用的客户无法删除(返回 400


4. 员工管理

需要 employee:read / employee:create / employee:update / employee:delete 权限。

GET /api/employees/simple — 简易员工列表

需要 Token仅需登录。无数据范围限制用于前端下拉选择。支持按部门过滤。

查询参数:

参数 说明
department 按部门精确过滤(如 ?department=运营部

响应数据字段:

字段 类型 说明
id number 员工 ID
name string 姓名
department string 所属部门
position string 职务/岗位

GET /api/employees — 员工列表

查询参数:

参数 说明
id 按 ID 精确搜索
name 按姓名模糊搜索
department 按部门模糊搜索
status 按在职状态过滤0-离职, 1-在职)

响应数据字段:

字段 类型 说明
id number 员工 ID
name string 姓名
gender string 性别(男/女)
age number 年龄
education string 学历
department string 所属部门
entry_date date 入职时间
position string 职务/岗位
salary number 工资金额
phone string 联系电话
email string 电子邮箱
status number 在职状态0-离职, 1-在职
remark string 备注
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/employees — 新增员工

请求体:

字段 必填 说明
name 员工姓名
gender 性别
age 年龄
education 学历
department 部门
entry_date 入职时间格式YYYY-MM-DD
position 职务
salary 工资
phone 电话
email 邮箱
status 在职状态,默认 1
remark 备注
username 需同步创建用户时填写(需 user:manage 权限)
password 需同步创建用户时填写(需 user:manage 权限)
department_id 需同步创建用户时填写(指定用户所属部门 ID

同步创建用户账号(allowUserCreation 中间件):

当同时传入 usernamepassworddepartment_id 三个字段时:

  • 需要拥有 user:manage 权限
  • 系统会在创建员工后自动创建关联的系统用户账号
  • username 长度 3-50 字符,password 至少 6 位

PUT /api/employees/:id — 更新员工

所有字段均可选,只传需要修改的字段。

DELETE /api/employees/:id — 删除员工

特殊行为:

  • 删除员工时会同步删除关联的用户账号(users 表中 employee_id 匹配的记录)
  • 不能删除当前登录用户自己关联的员工账号
  • 被合同或售后记录引用的员工无法删除(返回 400

5. 合同管理

需要 contract:read / contract:create / contract:update / contract:delete 权限。

GET /api/contracts — 合同列表

查询参数:

参数 说明
id 按 ID 精确搜索
status 按合同状态过滤(草稿/生效/完成/作废)
customer_name 按客户名称模糊搜索
contract_no 按合同编号模糊搜索
contract_name 按合同名称模糊搜索
employee_name 按业务员姓名模糊搜索
effective_date_start 按生效日期起始过滤格式YYYY-MM-DD
effective_date_end 按生效日期截止过滤格式YYYY-MM-DD

响应数据字段(含 JOIN 字段):

字段 类型 说明
id number 合同 ID
customer_id number 客户 ID加盟合同必填采购合同为 null
customer_name string 客户名称JOIN 自 customers
supplier_id number 供应商 ID采购合同必填加盟合同为 null
supplier_name string 供应商名称JOIN 自 suppliers
contract_name string 合同名称
contract_no string 合同编号
contract_content string 合同内容/条款
amount number 合同金额
effective_date date 生效日期
expiry_date date 到期日期
employee_id number 业务员 ID
employee_name string 业务员姓名JOIN 自 employees
status string 状态:草稿/生效/完成/作废
remark string 备注
type string 合同类型:franchise(加盟)/ supply(采购)
responsible_user_id number 负责人用户 ID
responsible_user_name string 负责人姓名JOIN 自 users → employees
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/contracts — 新增合同

请求体:

字段 必填 说明
customer_id 条件必填 关联客户 ID加盟合同必填
supplier_id 条件必填 关联供应商 ID采购合同必填
contract_name 合同名称
contract_no 合同编号
contract_content 合同内容
amount 合同金额
effective_date 生效日期
expiry_date 到期日期
employee_id 业务员 ID
status 状态,默认 生效中
remark 备注
type 合同类型(见下方说明)
responsible_user_id 负责人(默认为当前用户,仅管理员可在前端修改)

合同类型限制(validateContractType 中间件):

部门 允许的合同类型 说明
招商部 (franchise_manager) franchise 只能创建加盟合同,且必须选择 customer_id
采购部 (procurement_manager) supply 只能创建采购合同,且必须选择 supplier_id
信息技术部/总经理/财务 不限制 默认 franchise,可手动指定

校验规则:

  • customer_id 必须为已存在的客户
  • supplier_id 必须为已存在的供应商
  • employee_id(如填写)必须为已存在的员工

PUT /api/contracts/:id — 更新合同

所有字段均可选。可更新字段包括 typesupplier_idresponsible_user_id

校验规则: 更新 customer_idsupplier_idemployee_id 时会校验关联记录是否存在。合同类型限制同创建。

DELETE /api/contracts/:id — 删除合同

限制: 被售后记录引用的合同无法删除(返回 400


6. 售后管理

需要 after_sale:read / after_sale:create / after_sale:update / after_sale:delete 权限。

GET /api/after-sales — 售后列表

查询参数:

参数 说明
id 按 ID 精确搜索
customer_id 按客户 ID 精确搜索
customer_name 按客户名称模糊搜索
handle_status 按处理状态过滤(待处理/处理中/已完成)
feedback 按反馈内容模糊搜索

响应数据字段(含 JOIN 字段):

字段 类型 说明
id number 售后记录 ID
customer_id number 客户 ID
customer_name string 客户名称JOIN 自 customers
feedback string 客户反馈意见
employee_id number 处理业务员 ID
employee_name string 业务员姓名JOIN 自 employees
handle_method string 处理方式/解决方案
handle_status string 处理状态:待处理/处理中/已完成
service_date date 售后日期
remark string 备注
responsible_user_id number 负责人用户 ID
responsible_user_name string 负责人姓名JOIN 自 users → employees
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/after-sales — 新增售后

请求体:

字段 必填 说明
customer_id 关联客户 ID
feedback 售后反馈内容
employee_id 处理业务员 ID前端仅显示运营部员工
handle_method 处理方式
handle_status 处理状态,默认 待处理
service_date 售后日期
remark 备注
responsible_user_id 负责人(默认为当前用户,仅管理员可在前端修改)

校验规则:

  • customer_id 必须为已存在的客户
  • employee_id(如填写)必须为已存在的员工

PUT /api/after-sales/:id — 更新售后

所有字段均可选。

校验规则: 更新 customer_idemployee_id 时会校验关联记录是否存在。

DELETE /api/after-sales/:id — 删除售后


7. 产品管理

需要 product:read / product:create / product:update / product:delete 权限。 无数据范围隔离,拥有权限即可查看所有产品。

GET /api/products — 产品列表

查询参数:

参数 说明
id 按 ID 精确搜索
name 按产品名称模糊搜索
type 按产品类型模糊搜索
supplier 按供应商名称模糊搜索

响应数据字段:

字段 类型 说明
id number 产品 ID
name string 产品名称
type string 产品类型/分类
quantity number 库存数量
price number 单价
unit string 计量单位(默认"件"
specification string 规格/型号
supplier string 供应商名称
remark string 备注
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/products — 新增产品

请求体:

字段 必填 说明
name 产品名称
type 类型
quantity 库存数量,默认 0
price 单价,默认 0.00
unit 单位,默认"件"
specification 规格
supplier 供应商名称
remark 备注

PUT /api/products/:id — 更新产品

所有字段均可选。

DELETE /api/products/:id — 删除产品


8. 供应商管理

需要 supplier:read / supplier:create / supplier:update / supplier:delete 权限。 无数据范围隔离,拥有权限即可查看所有供应商。

GET /api/suppliers/simple — 简易供应商列表

需要 supplier:read 权限。返回所有正常状态供应商的基本信息,用于前端下拉选择。

响应数据字段:

字段 类型 说明
id number 供应商 ID
name string 供应商名称

GET /api/suppliers — 供应商列表

查询参数:

参数 说明
id 按 ID 精确搜索
name 按供应商名称模糊搜索
type 按类型模糊搜索
status 按状态过滤0-停用, 1-正常)

响应数据字段:

字段 类型 说明
id number 供应商 ID
name string 供应商名称
contact string 联系人
phone string 联系电话
address string 地址
type string 类型(原材料/包装/设备)
content string 备注说明
status number 状态0-停用, 1-正常
created_at datetime 创建时间
updated_at datetime 更新时间

POST /api/suppliers — 新增供应商

请求体:

字段 必填 说明
name 供应商名称
contact 联系人
phone 联系电话
address 地址
type 类型
content 备注说明
status 状态,默认 1

PUT /api/suppliers/:id — 更新供应商

所有字段均可选。

DELETE /api/suppliers/:id — 删除供应商


统一响应格式

成功响应

{
  "code": 0,
  "message": "ok",
  "data": { ... }
}

列表响应

{
  "code": 0,
  "message": "ok",
  "data": {
    "list": [ ... ],
    "total": 100,
    "page": 1,
    "pageSize": 10,
    "totalPages": 10
  }
}

错误响应

{
  "code": 403,
  "message": "权限不足"
}
HTTP 状态码 code 说明
400 400 参数错误 / 校验失败 / 关联记录不存在
401 401 未登录 / Token 无效
403 403 权限不足 / 账号被禁用 / 合同类型不匹配
404 404 资源不存在
409 409 数据冲突(如用户名重复)
500 500 服务器内部错误

数据库设计

表结构详情

1. users — 系统用户表

存储系统登录账号,每个用户关联一个部门和一个员工。

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 用户 ID
username VARCHAR(50) NOT NULL, UNIQUE 用户名(登录账号)
password VARCHAR(255) NOT NULL 密码bcrypt 哈希)
is_active TINYINT(1) NOT NULL DEFAULT 1 账号状态0-禁用, 1-启用
department_id INT NULLABLE 部门 ID → departments.id
employee_id INT NULLABLE, UNIQUE 员工 ID → employees.id
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

2. departments — 部门表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 部门 ID
name VARCHAR(50) NOT NULL, UNIQUE 部门标识(英文)
description VARCHAR(200) NULLABLE 部门名称(中文)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间

3. permissions — 权限表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 权限 ID
name VARCHAR(100) NOT NULL, UNIQUE 权限标识(resource:action 格式)
description VARCHAR(200) NULLABLE 权限描述(中文)
resource VARCHAR(50) NOT NULL 资源名称
action VARCHAR(50) NOT NULL 操作类型

4. department_permissions — 部门-权限关联表

字段 类型 约束 说明
department_id INT PK (联合) 部门 ID → departments.id
permission_id INT PK (联合) 权限 ID → permissions.id

5. customers — 加盟商信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 加盟商 ID
name VARCHAR(100) NOT NULL, INDEX 加盟商姓名
phone VARCHAR(20) INDEX 联系电话
province VARCHAR(50)
city VARCHAR(50)
district VARCHAR(50)
address VARCHAR(200) 详细地址
email VARCHAR(100) 电子邮箱
remark TEXT 备注信息
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

6. employees — 员工信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 员工 ID
name VARCHAR(100) NOT NULL, INDEX 姓名
gender VARCHAR(4) 性别:男/女
age INT 年龄
education VARCHAR(50) 学历
department VARCHAR(100) INDEX 所属部门
entry_date DATE 入职时间
position VARCHAR(100) 职务/岗位
salary DECIMAL(10,2) 工资金额
phone VARCHAR(20) 联系电话
email VARCHAR(100) 电子邮箱
status TINYINT(1) NOT NULL DEFAULT 1 在职状态0-离职, 1-在职
remark TEXT 备注
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

7. contracts — 合同信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 合同 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 合同内容/条款
amount DECIMAL(12,2) 合同金额
effective_date DATE INDEX 生效日期
expiry_date DATE 到期日期
employee_id INT INDEX 业务员 ID → employees.id
status VARCHAR(20) NOT NULL DEFAULT '生效' 状态:草稿/生效/完成/作废
remark TEXT 备注
type VARCHAR(20) NOT NULL DEFAULT 'franchise' 类型:franchise(加盟) / supply(采购)
responsible_user_id INT 负责人用户 ID → users.id
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

8. after_sales — 售后信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 售后记录 ID
customer_id INT NOT NULL, INDEX 客户 ID → customers.id
feedback TEXT NOT NULL 客户反馈意见
employee_id INT INDEX 处理业务员 ID → employees.id
handle_method TEXT 处理方式/解决方案
handle_status VARCHAR(20) NOT NULL DEFAULT '待处理', INDEX 状态:待处理/处理中/已完成
service_date DATE 售后日期
remark TEXT 备注
responsible_user_id INT 负责人用户 ID → users.id
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

9. products — 产品信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 产品 ID
name VARCHAR(200) NOT NULL, INDEX 产品名称
type VARCHAR(100) INDEX 产品类型/分类
quantity INT NOT NULL DEFAULT 0 库存数量
price DECIMAL(10,2) NOT NULL DEFAULT 0.00 单价
unit VARCHAR(20) DEFAULT '件' 计量单位
specification VARCHAR(200) 规格/型号
supplier VARCHAR(200) 供应商名称
remark TEXT 备注
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

10. suppliers — 供应商信息表

字段 类型 约束 说明
id INT PK, AUTO_INCREMENT 供应商 ID
name VARCHAR(200) NOT NULL, INDEX 供应商名称
contact VARCHAR(100) 联系人
phone VARCHAR(50) 联系电话
address VARCHAR(500) 地址
type VARCHAR(50) 类型(原材料/包装/设备)
content TEXT 备注说明
status TINYINT(1) NOT NULL DEFAULT 1 状态0-停用, 1-正常
created_at DATETIME DEFAULT CURRENT_TIMESTAMP 创建时间
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP 更新时间

表关系 ER 图

┌──────────────┐     ┌──────────────┐     ┌────────────────────────┐
│ departments   │     │ permissions   │     │ department_permissions │
│──────────────│     │──────────────│     │────────────────────────│
│ id (PK)      │◄─┐  │ id (PK)      │◄─┐  │ department_id (PK,FK)  │
│ name         │  │  │ name         │  │  │ permission_id (PK,FK)  │
│ description  │  │  │ description  │  └──│ → permissions.id       │
└──────────────┘  │  │ resource     │     └────────────────────────┘
                  │  │ action       │
                  │  └──────────────┘
                  │
┌──────────────┐  │  ┌──────────────┐
│    users      │  │  │  employees   │
│──────────────│  │  │──────────────│
│ id (PK)      │  │  │ id (PK)      │
│ username     │  │  │ name         │
│ password     │  │  │ gender       │
│ is_active    │  │  │ age          │
│ department_id│──┘  │ education    │
│   (FK)       │     │ department   │◄──── 数据范围隔离字段
│ employee_id  │─ ─ ─│ entry_date   │
│   (FK) ──────┼──→  │ position     │
└──────┬───────┘     │ salary       │
       │             │ phone        │
       │             │ email        │
       │             │ status       │
       │             └──────┬───────┘
       │                    │
       ▼                    ▼
┌──────────────────────────────────────────────┐
│               customers (加盟商)               │
│──────────────────────────────────────────────│
│ id (PK)                                       │
│ name, phone, province, city, district, ...    │
└────────────────────┬─────────────────────────┘
                     │
          ┌──────────┴──────────┐
          ▼                     ▼
┌──────────────────┐  ┌──────────────────┐
│    contracts      │  │   after_sales    │
│──────────────────│  │──────────────────│
│ id (PK)          │  │ id (PK)          │
│ customer_id (FK) │  │ customer_id (FK) │
│   → customers.id │  │   → customers.id │
│ supplier_id (FK) │  │ feedback         │
│   → suppliers.id │  │ employee_id (FK) │
│ contract_name    │  │   → employees.id │
│ contract_no      │  │ handle_method    │
│ amount           │  │ handle_status    │
│ employee_id (FK) │  │ service_date     │
│   → employees.id │  │ responsible_user │
│ status           │  │   _id → users.id │
│ type             │  └──────────────────┘
│   franchise/     │
│   supply         │
│ responsible_user │
│   _id → users.id │
└──────────────────┘

┌──────────────┐  ┌──────────────┐
│   products    │  │  suppliers   │
│──────────────│  │──────────────│
│ id (PK)      │  │ id (PK)      │
│ name         │  │ name         │
│ type         │  │ contact      │
│ quantity     │  │ phone        │
│ price        │  │ address      │
│ unit         │  │ type         │
│ specification│  │ content      │
│ supplier     │  │ status       │
└──────────────┘  └──────────────┘

关系说明:

关系 类型 说明
users → departments 多对一 一个用户属于一个部门,一个部门可以有多个用户
users → employees 一对一 一个用户关联一个员工(通过 employee_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 关联客户
after_sales → employees 多对一 通过 employee_id 关联业务员
after_sales → users 多对一 通过 responsible_user_id 指定负责人

注意:数据库未设置外键约束,引用完整性由应用代码保证(插入/更新前检查关联记录是否存在)。


部门权限系统

部门定义

系统预置 6 个部门,对应蜜雪冰城总部的组织架构:

部门标识 中文名 职责概述
admin 信息技术部 系统全权管理,拥有所有权限
general_manager 总经理办公室 全局只读,查看所有业务数据
franchise_manager 招商部 管理加盟商和加盟合同
operations_manager 运营部 维护加盟商信息、处理售后
procurement_manager 采购部 管理产品、供应商和采购合同
finance 财务部 只读查看业务数据(加盟商、合同、售后、员工)

权限列表

共 25 个权限,按 资源:操作 格式命名:

权限标识 中文描述
加盟商 (customer)
customer:read 查看加盟商
customer:create 新增加盟商
customer:update 修改加盟商
customer:delete 删除加盟商
合同 (contract)
contract:read 查看合同
contract:create 新增合同
contract:update 修改合同
contract:delete 删除合同
售后 (after_sale)
after_sale:read 查看售后
after_sale:create 新增售后
after_sale:update 修改售后
after_sale:delete 删除售后
产品 (product)
product:read 查看产品原料
product:create 新增产品原料
product:update 修改产品原料
product:delete 删除产品原料
供应商 (supplier)
supplier:read 查看供应商
supplier:create 新增供应商
supplier:update 修改供应商
supplier:delete 删除供应商
员工 (employee)
employee:read 查看员工
employee:create 新增员工
employee:update 修改员工
employee:delete 删除员工
用户 (user)
user:manage 管理用户账号

部门-权限映射

权限 admin general_manager franchise_manager operations_manager procurement_manager finance
customer:read
customer:create
customer:update
customer:delete
contract:read
contract:create
contract:update
contract:delete
after_sale:read
after_sale:create
after_sale:update
after_sale:delete
product:read
product:create
product:update
product:delete
supplier:read
supplier:create
supplier:update
supplier:delete
employee:read
employee:create
employee:update
employee:delete
user:manage

数据范围隔离

拥有操作权限 ≠ 能看到所有数据。系统通过 dataScope() 中间件在 SQL 查询层面做数据隔离:

资源 admin general_manager franchise_manager operations_manager procurement_manager finance
customers 全部 全部 全部(过渡期) 全部(过渡期) 全部 全部
contracts 全部 全部 仅加盟合同 仅采购合同 全部
after_sales 全部 全部 全部(过渡期) 全部
employees 全部 全部 仅本部门 仅本部门 仅本部门 全部
products 全部 全部 全部
suppliers 全部 全部 全部
users 全部

"—" 表示该部门无此资源的权限,请求会被 checkPermission 中间件直接拦截(返回 403

隔离机制说明:

隔离类型 资源 实现方式
合同类型过滤 contracts 招商部只能看到 type = 'franchise',采购部只能看到 type = 'supply'
部门过滤 employees 招商部/运营部/采购部只能看到本部门员工(department = 本部门名称
过渡期全量 customers, after_sales 当前不注入数据范围,所有部门看到全量数据
无隔离 products, suppliers 无数据范围过滤,有权限即可看到全部

过渡期说明:

  • customers 已移除 responsible_user_id 字段,不再需要负责人隔离
  • after_salesdataScope() 当前为占位状态(不注入任何 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 注入格式:

// 示例:招商部查看合同时注入
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)

预置账号

系统首次启动时自动创建以下账号,密码均为 123456

用户名 姓名 部门标识 部门 职位
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 林峰 总经理办公室 副总经理

快速测试

# 以管理员身份登录
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"}'