# 蜜雪冰城企业管理系统 —— 后端 API 文档 > 蜜雪冰城总部用于管理加盟商、合同、员工、产品、供应商及售后服务的企业信息管理系统后端服务。 ## 目录 - [快速开始](#快速开始) - [技术栈](#技术栈) - [项目结构](#项目结构) - [架构分层](#架构分层) - [认证机制](#认证机制) - [API 接口总览](#api-接口总览) - [1. 用户认证](#1-用户认证) - [2. 用户管理](#2-用户管理) - [3. 加盟商管理](#3-加盟商管理) - [4. 员工管理](#4-员工管理) - [5. 合同管理](#5-合同管理) - [6. 售后管理](#6-售后管理) - [7. 产品管理](#7-产品管理) - [8. 供应商管理](#8-供应商管理) - [统一响应格式](#统一响应格式) - [数据库设计](#数据库设计) - [表结构详情](#表结构详情) - [表关系 ER 图](#表关系-er-图) - [部门权限系统](#部门权限系统) - [部门定义](#部门定义) - [权限列表](#权限列表) - [部门-权限映射](#部门-权限映射) - [数据范围隔离](#数据范围隔离) - [中间件说明](#中间件说明) - [预置账号](#预置账号) --- ## 快速开始 ### 环境要求 - Node.js >= 18 - MySQL 5.7+ / MariaDB 10.2+ ### 安装与运行 ```bash # 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.permissions` 和 `req.scope` 注入。 --- ## 认证机制 所有 API(除登录外)需要在请求头中携带 JWT Token: ``` Authorization: Bearer ``` ### Token 获取 通过 `POST /api/user/login` 登录获取 Token。 ### Token 有效载荷 (Payload) ```json { "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 开始,默认 1)和 `pageSize`(每页条数,默认 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。 **请求体:** ```json { "username": "admin", "password": "123456" } ``` **成功响应:** ```json { "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。修改当前登录用户自己的密码。 **请求体:** ```json { "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 — 更新用户 **可更新字段:** `username`、`department_id`、`employee_id`、`is_active`、`password` **自保护限制(`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` 中间件):** 当同时传入 `username`、`password`、`department_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 — 更新合同 所有字段均可选。可更新字段包括 `type`、`supplier_id` 和 `responsible_user_id`。 **校验规则:** 更新 `customer_id`、`supplier_id`、`employee_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_id`、`employee_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 — 删除供应商 --- ## 统一响应格式 ### 成功响应 ```json { "code": 0, "message": "ok", "data": { ... } } ``` ### 列表响应 ```json { "code": 0, "message": "ok", "data": { "list": [ ... ], "total": 100, "page": 1, "pageSize": 10, "totalPages": 10 } } ``` ### 错误响应 ```json { "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_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) ``` --- ## 预置账号 系统首次启动时自动创建以下账号,密码均为 `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` | 林峰 | 总经理办公室 | 副总经理 | ### 快速测试 ```bash # 以管理员身份登录 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"}' ```