diff --git a/API.md b/API.md index d7934f3..a172cce 100644 --- a/API.md +++ b/API.md @@ -197,6 +197,8 @@ Authorization: Bearer } ``` +> **注意**:登录成功返回 `code: 200`,其他接口统一返回 `code: 0`。前端通过 `res.code === 0 || res.code === 200` 兼容判断。 + **错误响应:** | code | message | @@ -209,6 +211,18 @@ Authorization: Bearer 需要 Token。返回当前登录用户的完整信息(含角色名、员工名)。 +#### GET /api/user/list — 简易用户列表 + +需要 Token。返回所有启用用户的基本信息(id、用户名、真实姓名),用于前端下拉选择负责人。 + +**响应数据字段:** + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | number | 用户 ID | +| `username` | string | 用户名 | +| `real_name` | string | 真实姓名(来自员工表,可能为 null) | + #### POST /api/user/logout — 登出 需要 Token。服务端无状态,仅返回成功应答,客户端自行清除 Token。 @@ -244,6 +258,8 @@ Authorization: Bearer | 参数 | 说明 | 示例 | |------|------|------| | `username` | 按用户名模糊搜索 | `?username=admin` | +| `real_name` | 按真实姓名模糊搜索 | `?real_name=张` | +| `id` | 按用户 ID 精确搜索 | `?id=1` | | `role_id` | 按角色 ID 过滤 | `?role_id=2` | | `is_active` | 按状态过滤(0-禁用, 1-启用) | `?is_active=1` | | `page` | 页码 | `?page=1` | @@ -277,9 +293,9 @@ Authorization: Bearer |------|------|------| | `username` | ✅ | 用户名(3-50 字符) | | `password` | ✅ | 密码(至少 6 位) | -| `role_id` | ❌ | 角色 ID | -| `employee_id` | ❌ | 关联员工 ID | -| `department` | ❌ | 所属部门(若填了 employee_id 会自动同步) | +| `role_id` | ❌ | 角色 ID(需为已存在的角色) | +| `employee_id` | ❌ | 关联员工 ID(需为已存在的员工,会自动同步部门信息) | +| `department` | ❌ | 所属部门(若填了 employee_id 且未传 department,会自动从员工表同步) | | `is_active` | ❌ | 状态,默认 1 | #### PUT /api/users/:id — 更新用户 @@ -292,7 +308,9 @@ Authorization: Bearer #### DELETE /api/users/:id — 删除用户 -**限制:** 不能删除自己。 +**限制:** +- 不能删除自己 +- 不能删除最后一个管理员账号(当系统中仅剩 1 个 admin 角色用户时,拒绝删除) --- @@ -306,12 +324,13 @@ Authorization: Bearer | 参数 | 说明 | |------|------| +| `id` | 按 ID 精确搜索 | | `name` | 按加盟商名称模糊搜索 | | `phone` | 按电话模糊搜索 | | `province` | 按省份精确匹配 | | `city` | 按城市精确匹配 | -**响应数据字段:** +**响应数据字段(含 JOIN 字段):** | 字段 | 类型 | 说明 | |------|------|------| @@ -325,6 +344,7 @@ Authorization: Bearer | `email` | string | 电子邮箱 | | `remark` | string | 备注信息 | | `responsible_user_id` | number | 负责人用户 ID | +| `responsible_user_name` | string | 负责人姓名(JOIN 自 users → employees) | | `created_at` | datetime | 创建时间 | | `updated_at` | datetime | 更新时间 | @@ -342,7 +362,7 @@ Authorization: Bearer | `address` | ❌ | 详细地址 | | `email` | ❌ | 电子邮箱 | | `remark` | ❌ | 备注 | -| `responsible_user_id` | ❌ | 负责人(默认为当前登录用户) | +| `responsible_user_id` | ❌ | 负责人(默认为当前登录用户,仅管理员可在前端修改) | #### PUT /api/customers/:id — 更新加盟商 @@ -356,12 +376,32 @@ Authorization: Bearer > 需要 `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-在职) | @@ -409,8 +449,14 @@ Authorization: Bearer 所有字段均可选,只传需要修改的字段。 +**特殊行为:** 更新 `department` 字段时,会自动同步到关联的 users 表的 `department` 字段。 + #### DELETE /api/employees/:id — 删除员工 +**特殊行为:** +- 删除员工时会同步删除关联的用户账号(users 表中 `employee_id` 匹配的记录) +- 不能删除当前登录用户自己关联的员工账号 + --- ### 5. 合同管理 @@ -423,10 +469,14 @@ Authorization: Bearer | 参数 | 说明 | |------|------| -| `status` | 按合同状态过滤(草稿/生效/完成/作废) | +| `id` | 按 ID 精确搜索 | +| `status` | 按合同状态过滤(草稿/生效中/已完成/作废) | | `customer_name` | 按客户名称模糊搜索 | | `contract_no` | 按合同编号模糊搜索 | +| `contract_name` | 按合同名称模糊搜索 | | `employee_name` | 按业务员姓名模糊搜索 | +| `effective_date_start` | 按生效日期起始过滤(格式:YYYY-MM-DD) | +| `effective_date_end` | 按生效日期截止过滤(格式:YYYY-MM-DD) | **响应数据字段(含 JOIN 字段):** @@ -435,6 +485,8 @@ Authorization: Bearer | `id` | number | 合同 ID | | `customer_id` | number | 客户 ID | | `customer_name` | string | 客户名称(JOIN 自 customers) | +| `supplier_id` | number | 供应商 ID(采购合同必填) | +| `supplier_name` | string | 供应商名称(JOIN 自 suppliers) | | `contract_name` | string | 合同名称 | | `contract_no` | string | 合同编号 | | `contract_content` | string | 合同内容/条款 | @@ -443,10 +495,11 @@ Authorization: Bearer | `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 | +| `responsible_user_name` | string | 负责人姓名(JOIN 自 users → employees) | | `created_at` | datetime | 创建时间 | | `updated_at` | datetime | 更新时间 | @@ -456,7 +509,8 @@ Authorization: Bearer | 字段 | 必填 | 说明 | |------|------|------| -| `customer_id` | ✅ | 关联客户 ID | +| `customer_id` | 条件必填 | 关联客户 ID(加盟合同必填) | +| `supplier_id` | 条件必填 | 关联供应商 ID(采购合同必填) | | `contract_name` | ✅ | 合同名称 | | `contract_no` | ❌ | 合同编号 | | `contract_content` | ❌ | 合同内容 | @@ -464,18 +518,26 @@ Authorization: Bearer | `effective_date` | ❌ | 生效日期 | | `expiry_date` | ❌ | 到期日期 | | `employee_id` | ❌ | 业务员 ID | -| `status` | ❌ | 状态,默认 `生效` | +| `status` | ❌ | 状态,默认 `生效中` | | `remark` | ❌ | 备注 | | `type` | ❌ | 合同类型(见下方说明) | -| `responsible_user_id` | ❌ | 负责人(默认为当前用户) | +| `responsible_user_id` | ❌ | 负责人(默认为当前用户,仅管理员可在前端修改) | -**合同类型自动设置规则:** -- 采购经理创建的合同自动设为 `supply` -- 其他角色默认 `franchise`,也可手动指定 +**合同类型自动设置与角色限制规则:** +- 采购经理(`procurement_manager`)创建的合同**只能**为 `supply`(采购合同),且必须选择 `supplier_id` +- 招商经理(`franchise_manager`)创建的合同**只能**为 `franchise`(加盟合同),且必须选择 `customer_id` +- 其他角色默认 `franchise`,也可手动指定 `type` + +**校验规则:** +- `customer_id` 必须为已存在的客户 +- `supplier_id` 必须为已存在的供应商 +- `employee_id`(如填写)必须为已存在的员工 #### PUT /api/contracts/:id — 更新合同 -所有字段均可选。可更新字段包括 `type` 和 `responsible_user_id`。 +所有字段均可选。可更新字段包括 `type`、`supplier_id` 和 `responsible_user_id`。 + +**校验规则:** 更新 `customer_id`、`supplier_id`、`employee_id` 时会校验关联记录是否存在。 #### DELETE /api/contracts/:id — 删除合同 @@ -491,8 +553,11 @@ Authorization: Bearer | 参数 | 说明 | |------|------| -| `handle_status` | 按处理状态过滤(待处理/处理中/已完成) | +| `id` | 按 ID 精确搜索 | +| `customer_id` | 按客户 ID 精确搜索 | | `customer_name` | 按客户名称模糊搜索 | +| `handle_status` | 按处理状态过滤(待处理/处理中/已完成) | +| `feedback` | 按反馈内容模糊搜索 | **响应数据字段(含 JOIN 字段):** @@ -520,17 +585,23 @@ Authorization: Bearer |------|------|------| | `customer_id` | ✅ | 关联客户 ID | | `feedback` | ✅ | 售后反馈内容 | -| `employee_id` | ❌ | 处理业务员 ID | +| `employee_id` | ❌ | 处理业务员 ID(前端仅显示运营部员工) | | `handle_method` | ❌ | 处理方式 | | `handle_status` | ❌ | 处理状态,默认 `待处理` | | `service_date` | ❌ | 售后日期 | | `remark` | ❌ | 备注 | -| `responsible_user_id` | ❌ | 负责人(默认为当前用户) | +| `responsible_user_id` | ❌ | 负责人(默认为当前用户,仅管理员可在前端修改) | + +**校验规则:** +- `customer_id` 必须为已存在的客户 +- `employee_id`(如填写)必须为已存在的员工 #### PUT /api/after-sales/:id — 更新售后 所有字段均可选。 +**校验规则:** 更新 `customer_id`、`employee_id` 时会校验关联记录是否存在。 + #### DELETE /api/after-sales/:id — 删除售后 --- @@ -546,9 +617,10 @@ Authorization: Bearer | 参数 | 说明 | |------|------| +| `id` | 按 ID 精确搜索 | | `name` | 按产品名称模糊搜索 | | `type` | 按产品类型模糊搜索 | -| `supplier` | 按供应商模糊搜索 | +| `supplier` | 按供应商名称模糊搜索 | **响应数据字段:** @@ -561,7 +633,7 @@ Authorization: Bearer | `price` | number | 单价 | | `unit` | string | 计量单位(默认"件") | | `specification` | string | 规格/型号 | -| `supplier` | string | 供应商 | +| `supplier` | string | 供应商名称 | | `remark` | string | 备注 | | `created_at` | datetime | 创建时间 | | `updated_at` | datetime | 更新时间 | @@ -578,7 +650,7 @@ Authorization: Bearer | `price` | ❌ | 单价,默认 0.00 | | `unit` | ❌ | 单位,默认"件" | | `specification` | ❌ | 规格 | -| `supplier` | ❌ | 供应商 | +| `supplier` | ❌ | 供应商名称 | | `remark` | ❌ | 备注 | #### PUT /api/products/:id — 更新产品 @@ -600,6 +672,7 @@ Authorization: Bearer | 参数 | 说明 | |------|------| +| `id` | 按 ID 精确搜索 | | `name` | 按供应商名称模糊搜索 | | `type` | 按类型模糊搜索 | | `status` | 按状态过滤(0-停用, 1-正常) | @@ -680,9 +753,9 @@ Authorization: Bearer | HTTP 状态码 | code | 说明 | |------------|------|------| -| 400 | 400 | 参数错误 / 校验失败 | +| 400 | 400 | 参数错误 / 校验失败 / 关联记录不存在 | | 401 | 401 | 未登录 / Token 无效 | -| 403 | 403 | 权限不足 / 账号被禁用 | +| 403 | 403 | 权限不足 / 账号被禁用 / 角色操作限制 | | 404 | 404 | 资源不存在 | | 409 | 409 | 数据冲突(如用户名重复) | | 500 | 500 | 服务器内部错误 | @@ -704,7 +777,7 @@ Authorization: Bearer | `password` | VARCHAR(255) | NOT NULL | 密码(bcrypt 哈希) | | `is_active` | TINYINT(1) | NOT NULL DEFAULT 1 | 账号状态:0-禁用, 1-启用 | | `role_id` | INT | NULLABLE | 角色 ID → roles.id | -| `employee_id` | INT | NULLABLE | 员工 ID → employees.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 | 更新时间 | @@ -777,7 +850,8 @@ Authorization: Bearer | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | INT | PK, AUTO_INCREMENT | 合同 ID | -| `customer_id` | INT | NOT NULL, INDEX | 客户 ID → customers.id | +| `customer_id` | INT | NULLABLE, INDEX | 客户 ID → customers.id(加盟合同必填) | +| `supplier_id` | INT | NULLABLE, INDEX | 供应商 ID → suppliers.id(采购合同必填) | | `contract_name` | VARCHAR(200) | NOT NULL | 合同名称 | | `contract_no` | VARCHAR(100) | — | 合同编号 | | `contract_content` | TEXT | — | 合同内容/条款 | @@ -785,7 +859,7 @@ Authorization: Bearer | `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 | @@ -888,15 +962,17 @@ Authorization: Bearer │ id (PK) │ │ id (PK) │ │ customer_id (FK) │ │ customer_id (FK) │ │ → customers.id │ │ → customers.id │ -│ contract_name │ │ feedback │ -│ contract_no │ │ employee_id (FK) │ -│ amount │ │ → employees.id │ -│ employee_id (FK) │ │ handle_method │ -│ → employees.id │ │ handle_status │ -│ status │ │ service_date │ -│ type │ │ responsible_user │ -│ franchise/ │ │ _id → users.id │ -│ supply │ └──────────────────┘ +│ 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 │ └──────────────────┘ @@ -920,10 +996,11 @@ Authorization: Bearer | 关系 | 类型 | 说明 | |------|------|------| | users → roles | 多对一 | 一个用户属于一个角色,一个角色可以有多个用户 | -| users → employees | 一对一 | 一个用户关联一个员工(通过 employee_id) | +| users → employees | 一对一 | 一个用户关联一个员工(通过 employee_id,唯一约束) | | roles ↔ permissions | 多对多 | 通过 role_permissions 中间表关联 | | customers → users | 多对一 | 通过 responsible_user_id 指定负责人 | -| contracts → customers | 多对一 | 通过 customer_id 关联客户 | +| contracts → customers | 多对一 | 通过 customer_id 关联客户(加盟合同必填) | +| contracts → suppliers | 多对一 | 通过 supplier_id 关联供应商(采购合同必填) | | contracts → employees | 多对一 | 通过 employee_id 关联业务员 | | contracts → users | 多对一 | 通过 responsible_user_id 指定负责人 | | after_sales → customers | 多对一 | 通过 customer_id 关联客户 | @@ -1040,6 +1117,11 @@ Authorization: Bearer - **部门类资源**(employees):通过 `department` 字段过滤,只能看到自己部门的员工 - **全局类资源**(products、suppliers):无数据范围过滤,只要有权限就能看到全部 +**合同类型与角色限制:** +- 采购经理(`procurement_manager`)只能查看和操作采购合同(`type = 'supply'`) +- 招商经理(`franchise_manager`)和运营经理(`operations_manager`)只能查看和操作加盟合同(`type = 'franchise'`)中自己负责的记录 +- 创建合同时,采购经理只能创建采购合同,招商经理只能创建加盟合同 + --- ## 预置账号