📝 主要改进: • Cursor配置模块化:拆分为前端、后端、移动端、文档、API测试5个专门规范文件 • API文档重新组织:按业务模块拆分到docs/开发文档/API/目录下 • 新增维修分类功能完整测试方案和自动化测试脚本 • 后端热启动脚本完善,支持Linux/Windows双平台 • 强化文档同步更新规范,确保代码与文档一致性 🔧 技术改进: • 优化Cursor AI工作流程和代码生成质量 • 完善API测试规范(AES+RSA双重加密登录方法) • 提升开发效率和代码质量标准化程度 �� 测试覆盖: • 维修分类管理功能端到端测试验证通过 • 包含页面加载、CRUD操作、搜索功能等核心测试用例 更新时间:2025-07-01
2452 lines
72 KiB
Plaintext
2452 lines
72 KiB
Plaintext
# API 接口文档
|
||
|
||
## 文档说明
|
||
|
||
本文档记录项目所有的 API 接口信息,包括请求方式、参数说明、响应格式等。所有接口遵循 RESTful 设计规范。
|
||
|
||
### 基础信息
|
||
|
||
- **基础路径**: `/api`
|
||
- **响应格式**: JSON
|
||
- **字符编码**: UTF-8
|
||
- **权限认证**: Sa-Token + JWT
|
||
- **版本**: v1.0
|
||
|
||
### 🔐 请求头规范(强制性)
|
||
|
||
**所有需要认证的接口必须在请求头中包含 Token,格式如下:**
|
||
|
||
```json
|
||
{
|
||
"Content-Type": "application/json;charset=utf-8",
|
||
"Authorization": "Bearer {access_token}",
|
||
"clientid": "e5cd7e4891bf95d1d19206ce24a7b32e",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
||
"referer": "http://localhost/login?redirect=%252Findex"
|
||
}
|
||
```
|
||
|
||
**请求头字段说明**:
|
||
|
||
- **Authorization**: `Bearer ` + Token 值(⚠️ 注意 Bearer 后面有一个空格)
|
||
- **clientid**: 客户端 ID,用于权限验证
|
||
- **Content-Type**: 请求内容类型,必须为 application/json;charset=utf-8
|
||
- **Accept-Language**: 语言设置,用于国际化
|
||
- **referer**: 来源页面,用于安全验证
|
||
|
||
**Token 格式强制要求**:
|
||
|
||
- ✅ 正确:`"Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."`
|
||
- ❌ 错误:`"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."`(缺少 Bearer 前缀)
|
||
- ❌ 错误:`"Authorization": "Bearer eyJ0eXAi..."`(Bearer 后面没有空格)
|
||
|
||
### 🔴 统一响应格式(强制性)
|
||
|
||
**⚠️ 所有 API 接口必须严格遵循以下统一响应格式!**
|
||
|
||
#### 📊 基础响应格式
|
||
|
||
**分页列表响应格式**:
|
||
|
||
```json
|
||
{
|
||
"total": 7,
|
||
"rows": [],
|
||
"code": 200,
|
||
"msg": "查询成功"
|
||
}
|
||
```
|
||
|
||
#### 🎯 详细响应格式说明
|
||
|
||
**1. 分页列表响应**
|
||
|
||
```json
|
||
{
|
||
"total": 100,
|
||
"rows": [
|
||
{
|
||
"id": 1,
|
||
"name": "示例数据1",
|
||
"createTime": "2025-06-30 12:00:00"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "示例数据2",
|
||
"createTime": "2025-06-30 12:01:00"
|
||
}
|
||
],
|
||
"code": 200,
|
||
"msg": "查询成功"
|
||
}
|
||
```
|
||
|
||
**2. 非分页列表响应**
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "示例数据1"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "示例数据2"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**3. 单条数据响应**
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"id": 1,
|
||
"name": "示例数据",
|
||
"createTime": "2025-06-30 12:00:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
**4. 操作成功响应(无数据)**
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**5. 错误响应**
|
||
|
||
```json
|
||
{
|
||
"code": 400,
|
||
"msg": "参数错误:用户名不能为空",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 📋 状态码规范
|
||
|
||
**成功状态码**:
|
||
|
||
- `200` - 操作成功
|
||
- `201` - 创建成功
|
||
|
||
**客户端错误(4xx)**:
|
||
|
||
- `400` - 请求参数错误
|
||
- `401` - 未认证/认证失败
|
||
- `403` - 无权限访问
|
||
- `404` - 资源不存在
|
||
- `409` - 数据冲突
|
||
|
||
**服务端错误(5xx)**:
|
||
|
||
- `500` - 服务器内部错误
|
||
- `502` - 网关错误
|
||
- `503` - 服务不可用
|
||
|
||
#### 🚨 开发强制要求
|
||
|
||
1. **请求头必须包含 Bearer Token 格式的 Authorization**
|
||
2. **分页接口必须直接返回 TableDataInfo 格式(total、rows、code、msg)**
|
||
3. **非分页接口必须使用 R 类型包装返回结果**
|
||
4. **单条数据接口必须使用 R 类型包装返回结果**
|
||
5. **操作类接口必须使用 R 类型包装返回结果**
|
||
6. **必须包含 clientid、Content-Type 等必要请求头**
|
||
|
||
#### 💥 违规检查
|
||
|
||
如发现接口不符合统一格式,必须立即修改!
|
||
|
||
---
|
||
|
||
## 0. 认证与登录 API
|
||
|
||
### 0.1 用户认证
|
||
|
||
#### 用户登录
|
||
|
||
**接口地址**: `POST /auth/login`
|
||
|
||
**接口描述**: 用户登录认证接口,支持密码登录。请求数据使用 AES+RSA 混合加密传输,确保安全性。
|
||
|
||
**权限要求**: 无需认证(公开接口)
|
||
|
||
**安全机制**:
|
||
|
||
- **数据加密**: 请求参数使用 AES 对称加密
|
||
- **密钥保护**: AES 密钥使用 RSA 非对称加密
|
||
- **自动解密**: 后端自动解密请求数据和响应数据
|
||
|
||
**请求头配置**:
|
||
|
||
```json
|
||
{
|
||
"Content-Type": "application/json;charset=utf-8",
|
||
"clientid": "e5cd7e4891bf95d1d19206ce24a7b32e",
|
||
"encrypt-key": "[RSA加密的AES密钥]",
|
||
"referer": "http://localhost/login?redirect=%252Findex",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
||
"isToken": "false",
|
||
"isEncrypt": "true",
|
||
"repeatSubmit": "false"
|
||
}
|
||
```
|
||
|
||
**关键请求头说明**:
|
||
|
||
| 请求头名 | 必填 | 说明 | 示例值 |
|
||
| ----------- | ---- | --------------------------------- | -------------------------------------------- |
|
||
| clientid | 是 | 客户端 ID,用于身份验证 | "e5cd7e4891bf95d1d19206ce24a7b32e" |
|
||
| encrypt-key | 是 | RSA 加密的 AES 密钥,用于数据解密 | "Q8Td0si9R3EYj3pFe50rzn/8wxo69Y9uR6LE..." |
|
||
| referer | 是 | 来源页面地址,用于请求来源验证 | "http://localhost/login?redirect=%252Findex" |
|
||
|
||
**加密流程说明**:
|
||
|
||
1. 前端生成随机 AES 密钥(32 位字符串)
|
||
2. 使用 AES-ECB-PKCS7 模式加密请求数据
|
||
3. 使用 RSA 公钥加密 AES 密钥
|
||
4. 将加密后的 AES 密钥放入请求头 `encrypt-key`
|
||
5. 后端使用 RSA 私钥解密 AES 密钥,再解密请求数据
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
| --------- | ------ | ---- | ------------------------------------ | ---------------------------------- |
|
||
| tenantId | string | 是 | 租户 ID,多租户系统标识 | "000000" |
|
||
| username | string | 是 | 用户名,长度 2-30 字符 | "admin" |
|
||
| password | string | 是 | 用户密码,长度 5-30 字符 | "admin123" |
|
||
| clientId | string | 是 | 客户端 ID,用于权限控制 | "e5cd7e4891bf95d1d19206ce24a7b32e" |
|
||
| grantType | string | 是 | 授权类型,目前支持 password | "password" |
|
||
| code | string | 否 | 验证码(当系统开启验证码时必填) | "1234" |
|
||
| uuid | string | 否 | 验证码唯一标识(当需要验证码时必填) | "uuid-string" |
|
||
|
||
**请求示例**:
|
||
|
||
```json
|
||
{
|
||
"tenantId": "000000",
|
||
"username": "admin",
|
||
"password": "admin123",
|
||
"clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
|
||
"grantType": "password"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ5MlhvbHRnd1Y2YjUzRnRMVzF4SFR1anRSUERjeGdmYyIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IuaZuuiDveaOp-WItuWtpumZoiIsImRlcHRDYXRlZ29yeSI6IiIsIm5pY2tOYW1lIjoi55av54uC55qE54uu5a2QTGkifQ.WI6iY3AgwPz7ceI8WDsVy-GaTXZnU-JKUYUTjhQdoKM",
|
||
"refresh_token": null,
|
||
"expire_in": 604800,
|
||
"refresh_expire_in": null,
|
||
"client_id": "e5cd7e4891bf95d1d19206ce24a7b32e",
|
||
"scope": null,
|
||
"openid": null
|
||
}
|
||
}
|
||
```
|
||
|
||
**实际 Token 解析信息**:
|
||
|
||
| 字段名 | 值 | 说明 |
|
||
| --------- | ----------------- | --------- |
|
||
| userId | 1 | 用户 ID |
|
||
| userName | admin | 用户名 |
|
||
| nickName | 疯狂狮子 Li | 用户昵称 |
|
||
| deptId | 103 | 部门 ID |
|
||
| deptName | 智胜技术开发团队 | 部门名称 |
|
||
| tenantId | 000000 | 租户 ID |
|
||
| clientId | e5cd7e4891bf95... | 客户端 ID |
|
||
| loginType | login | 登录类型 |
|
||
|
||
**Token 有效期**: 7 天 (604800 秒)
|
||
|
||
**响应参数说明**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
| ----------------- | ------ | ------------------------------ |
|
||
| access_token | string | 访问令牌,用于 API 调用认证 |
|
||
| refresh_token | string | 刷新令牌,用于获取新的访问令牌 |
|
||
| expire_in | long | 访问令牌过期时间(秒) |
|
||
| refresh_expire_in | long | 刷新令牌过期时间(秒) |
|
||
| client_id | string | 客户端 ID |
|
||
| scope | string | 权限范围 |
|
||
| openid | string | 第三方登录标识(可为空) |
|
||
|
||
**多种登录方式支持**:
|
||
|
||
系统采用策略模式,支持多种登录方式:
|
||
|
||
1. **密码登录** (`grantType: "password"`)
|
||
|
||
- 使用用户名和密码登录
|
||
- 支持验证码验证(可配置开关)
|
||
- BCrypt 密码加密存储
|
||
|
||
2. **邮箱登录** (`grantType: "email"`)
|
||
|
||
- 使用邮箱和邮箱验证码登录
|
||
- 需要先发送邮箱验证码
|
||
|
||
3. **短信登录** (`grantType: "sms"`)
|
||
|
||
- 使用手机号和短信验证码登录
|
||
- 需要先发送短信验证码
|
||
|
||
4. **小程序登录** (`grantType: "xcx"`)
|
||
- 微信小程序授权登录
|
||
- 需要小程序码和应用 ID
|
||
|
||
**错误码说明**:
|
||
|
||
| 错误码 | 错误信息 | 说明 | 解决方案 |
|
||
| ------ | ---------------------------- | ----------------------- | ---------------------- |
|
||
| 400 | 参数校验失败 | 请求参数格式错误 | 检查参数格式和必填字段 |
|
||
| 400 | 客户端 id 异常 | clientId 不存在或被禁用 | 检查 clientId 配置 |
|
||
| 400 | 授权类型不正确 | grantType 不支持 | 使用支持的授权类型 |
|
||
| 400 | 当前系统没有开启注册功能 | 租户未开启注册 | 联系管理员开启注册功能 |
|
||
| 401 | 用户不存在 | 用户名不存在 | 检查用户名是否正确 |
|
||
| 401 | 用户已被停用 | 用户账号被禁用 | 联系管理员激活账号 |
|
||
| 401 | 密码错误 | 用户密码不正确 | 检查密码是否正确 |
|
||
| 401 | 验证码已过期 | 验证码超时 | 重新获取验证码 |
|
||
| 401 | 验证码错误 | 验证码输入错误 | 检查验证码是否正确 |
|
||
| 403 | 登录失败次数过多,账户已锁定 | 密码错误次数超限 | 等待解锁或联系管理员 |
|
||
| 500 | 租户不存在 | tenantId 无效 | 检查租户配置 |
|
||
|
||
**安全特性**:
|
||
|
||
1. **密码安全**:
|
||
|
||
- BCrypt 哈希加密存储
|
||
- 登录失败次数限制
|
||
- 账户自动锁定机制
|
||
|
||
2. **传输安全**:
|
||
|
||
- AES+RSA 混合加密
|
||
- 防重放攻击保护
|
||
- HTTPS 协议传输
|
||
|
||
3. **会话安全**:
|
||
|
||
- JWT Token 认证
|
||
- Token 自动过期机制
|
||
- 刷新 Token 机制
|
||
|
||
4. **多租户安全**:
|
||
- 租户隔离验证
|
||
- 客户端权限控制
|
||
- 不同设备类型支持
|
||
|
||
**实际使用示例**:
|
||
|
||
```javascript
|
||
// 完整的登录实现示例(AES+RSA加密)
|
||
const axios = require('axios');
|
||
const CryptoJS = require('crypto-js');
|
||
const NodeRSA = require('node-rsa');
|
||
|
||
async function loginWithEncryption(username = 'admin', password = 'admin123') {
|
||
// 配置信息
|
||
const CONFIG = {
|
||
url: 'http://localhost/dev-api/auth/login',
|
||
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
|
||
tenantId: '000000',
|
||
referer: 'http://localhost/login?redirect=%252Findex',
|
||
rsaKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
|
||
};
|
||
|
||
// 生成32位随机AES密钥
|
||
function generateAESKey() {
|
||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||
let result = '';
|
||
for (let i = 0; i < 32; i++) {
|
||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// AES加密
|
||
function aesEncrypt(data, key) {
|
||
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
|
||
return CryptoJS.AES.encrypt(data, keyUtf8, {
|
||
mode: CryptoJS.mode.ECB,
|
||
padding: CryptoJS.pad.Pkcs7,
|
||
}).toString();
|
||
}
|
||
|
||
// RSA加密AES密钥
|
||
function rsaEncrypt(aesKey) {
|
||
const pemKey = `-----BEGIN PUBLIC KEY-----\n${CONFIG.rsaKey}\n-----END PUBLIC KEY-----`;
|
||
const rsaKey = new NodeRSA(pemKey);
|
||
rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
|
||
const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
|
||
return rsaKey.encrypt(aesKeyBase64, 'base64');
|
||
}
|
||
|
||
// 生成AES密钥并加密登录数据
|
||
const aesKey = generateAESKey();
|
||
const loginData = {
|
||
tenantId: CONFIG.tenantId,
|
||
username: username,
|
||
password: password,
|
||
clientId: CONFIG.clientId,
|
||
grantType: 'password',
|
||
};
|
||
|
||
const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
|
||
const encryptedKey = rsaEncrypt(aesKey);
|
||
|
||
// 设置请求头
|
||
const headers = {
|
||
'Content-Type': 'application/json;charset=utf-8',
|
||
clientid: CONFIG.clientId,
|
||
'encrypt-key': encryptedKey,
|
||
referer: CONFIG.referer,
|
||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||
isToken: 'false',
|
||
isEncrypt: 'true',
|
||
repeatSubmit: 'false',
|
||
};
|
||
|
||
// 发送登录请求
|
||
const response = await axios.post(CONFIG.url, encryptedData, {
|
||
headers: headers,
|
||
timeout: 10000,
|
||
});
|
||
|
||
if (response.data.code === 200 && response.data.data?.access_token) {
|
||
return response.data.data.access_token;
|
||
} else {
|
||
throw new Error(response.data.msg || 'Login failed');
|
||
}
|
||
}
|
||
|
||
// 使用示例
|
||
loginWithEncryption()
|
||
.then((token) => {
|
||
console.log('Login successful, token:', token);
|
||
})
|
||
.catch((error) => {
|
||
console.error('Login failed:', error.message);
|
||
});
|
||
```
|
||
|
||
**快速测试脚本**:
|
||
|
||
项目中提供了完整的测试脚本,位于 `test/` 目录:
|
||
|
||
- `test/custom-login-script.js` - 完整功能版
|
||
- `test/quick-token-getter.js` - 快速获取版
|
||
- `test/登录脚本使用说明.md` - 详细使用文档
|
||
|
||
#### 退出登录
|
||
|
||
**接口地址**: `POST /auth/logout`
|
||
|
||
**接口描述**: 用户退出登录,清除服务端会话信息
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**请求参数**: 无需请求体
|
||
|
||
**请求头**:
|
||
|
||
```json
|
||
{
|
||
"Authorization": "Bearer {access_token}"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "退出成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**功能说明**:
|
||
|
||
- 清除服务端 Token 会话
|
||
- 关闭 SSE 连接(如果开启)
|
||
- 清理用户登录状态
|
||
|
||
#### 获取验证码
|
||
|
||
**接口地址**: `GET /auth/code`
|
||
|
||
**接口描述**: 获取图形验证码,用于登录时的安全验证
|
||
|
||
**权限要求**: 无需认证
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"uuid": "d7c2c4c4-4e9d-4a5f-9c1a-2b3c4d5e6f7g",
|
||
"img": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABH..."
|
||
}
|
||
}
|
||
```
|
||
|
||
**响应参数说明**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
| ------ | ------ | ----------------------- |
|
||
| uuid | string | 验证码唯一标识 |
|
||
| img | string | Base64 编码的验证码图片 |
|
||
|
||
**使用流程**:
|
||
|
||
1. 前端调用此接口获取验证码图片和 UUID
|
||
2. 用户输入验证码
|
||
3. 登录时将验证码和 UUID 一起提交
|
||
4. 服务端验证验证码的正确性和有效性
|
||
|
||
### 0.2 用户信息
|
||
|
||
#### 获取当前用户信息
|
||
|
||
**接口地址**: `GET /system/user/getInfo`
|
||
|
||
**接口描述**: 获取当前登录用户的详细信息,包括角色权限等
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"user": {
|
||
"userId": 1,
|
||
"userName": "admin",
|
||
"nickName": "疯狂狮子Li",
|
||
"email": "admin@example.com",
|
||
"phonenumber": "13800138000",
|
||
"sex": "1",
|
||
"avatar": "/profile/avatar/default.jpg",
|
||
"status": "0",
|
||
"loginIp": "127.0.0.1",
|
||
"loginDate": "2025-01-26 10:30:00",
|
||
"tenantId": "000000",
|
||
"deptId": 103,
|
||
"deptName": "智胜技术开发团队"
|
||
},
|
||
"roles": ["admin", "common"],
|
||
"permissions": ["*:*:*"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**超级管理员权限说明**:
|
||
|
||
admin 用户具有系统最高权限 `*:*:*`,可以访问所有功能模块和执行所有操作。
|
||
|
||
### 0.3 租户管理
|
||
|
||
#### 获取租户列表
|
||
|
||
**接口地址**: `GET /auth/tenant/list`
|
||
|
||
**接口描述**: 获取系统可用的租户列表,用于登录时选择租户
|
||
|
||
**权限要求**: 无需认证
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"tenantEnabled": true,
|
||
"voList": [
|
||
{
|
||
"tenantId": "000000",
|
||
"companyName": "杭州第一技师学院",
|
||
"domain": "hzdyjs.edu.cn",
|
||
"status": "0"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**响应参数说明**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
| ------------- | ------- | ------------------ |
|
||
| tenantEnabled | boolean | 是否启用多租户功能 |
|
||
| voList | array | 租户列表 |
|
||
|
||
**voList 中每项参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
| ----------- | ------ | ------------------- |
|
||
| tenantId | string | 租户 ID |
|
||
| companyName | string | 租户名称 |
|
||
| domain | string | 租户域名 |
|
||
| status | string | 状态(0 正常 1 停用) |
|
||
|
||
---
|
||
|
||
## 1. 物业报修管理 API
|
||
|
||
### 1.1 维修分类管理
|
||
|
||
#### 查询维修分类列表
|
||
|
||
**接口地址**: `GET /hq/pm/repairCategory/list`
|
||
|
||
**接口描述**: 分页查询维修分类列表,支持权限过滤
|
||
|
||
**权限要求**: `pm:category:list`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------------ | ------ | ---- | --------------------- |
|
||
| pageNum | int | 否 | 页码,默认 1 |
|
||
| pageSize | int | 否 | 页大小,默认 10 |
|
||
| categoryName | string | 否 | 分类名称 |
|
||
| categoryCode | string | 否 | 分类编码 |
|
||
| parentId | long | 否 | 父级分类 ID |
|
||
| skillLevel | string | 否 | 技能等级要求 |
|
||
| status | string | 否 | 状态(0-停用,1-正常) |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"total": 6,
|
||
"rows": [
|
||
{
|
||
"id": 1,
|
||
"categoryName": "电路维修",
|
||
"categoryCode": "ELECTRIC",
|
||
"categoryDescription": "电路、照明、开关、插座等电气设备维修",
|
||
"parentId": 0,
|
||
"ancestorIds": "0",
|
||
"levelDepth": 1,
|
||
"childrenCount": 0,
|
||
"requiredSkills": "电工技能、安全操作",
|
||
"skillLevel": "2",
|
||
"estimatedDuration": 120,
|
||
"standardCost": 200.0,
|
||
"iconUrl": null,
|
||
"colorCode": "#FF6B35",
|
||
"sortOrder": 1,
|
||
"status": "1",
|
||
"usageCount": 0,
|
||
"lastUsedTime": null,
|
||
"remark": null,
|
||
"createTime": "2025-01-23 14:30:00"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 获取维修分类树形结构
|
||
|
||
**接口地址**: `GET /hq/pm/repairCategory/tree`
|
||
|
||
**接口描述**: 获取维修分类的树形结构数据
|
||
|
||
**权限要求**: `pm:category:tree`
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"categoryName": "电路维修",
|
||
"categoryCode": "ELECTRIC",
|
||
"categoryDescription": "电路、照明、开关、插座等电气设备维修",
|
||
"parentId": 0,
|
||
"children": []
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 获取维修分类下拉选项
|
||
|
||
**接口地址**: `GET /hq/pm/repairCategory/options`
|
||
|
||
**接口描述**: 获取维修分类的下拉选项数据,用于表单选择器
|
||
|
||
**权限要求**: `pm:category:list`
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"value": 1,
|
||
"label": "电路维修"
|
||
},
|
||
{
|
||
"value": 2,
|
||
"label": "水管维修"
|
||
},
|
||
{
|
||
"value": 3,
|
||
"label": "门窗维修"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**数据格式说明**:
|
||
|
||
- **value**: 分类 ID,用于表单提交
|
||
- **label**: 分类名称,用于显示
|
||
- **扁平化处理**: 将树形结构扁平化,便于下拉选择
|
||
|
||
**使用场景**:
|
||
|
||
- 报修工单创建时选择维修类型
|
||
- 表单编辑时的分类选择
|
||
- 搜索条件中的分类筛选
|
||
|
||
#### 获取维修分类详情
|
||
|
||
**接口地址**: `GET /hq/pm/repairCategory/{id}`
|
||
|
||
**接口描述**: 根据 ID 获取维修分类详细信息
|
||
|
||
**权限要求**: `pm:category:query`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------ | ---- | ---- | ------- |
|
||
| id | long | 是 | 分类 ID |
|
||
|
||
#### 新增维修分类
|
||
|
||
**接口地址**: `POST /hq/pm/repairCategory`
|
||
|
||
**接口描述**: 创建新的维修分类
|
||
|
||
**权限要求**: `pm:category:add`
|
||
|
||
**请求参数**:
|
||
|
||
```json
|
||
{
|
||
"categoryName": "测试维修类型",
|
||
"categoryCode": "TEST_REPAIR",
|
||
"categoryDescription": "这是一个测试的维修类型",
|
||
"parentId": 0,
|
||
"skillLevel": "1",
|
||
"estimatedDuration": 60,
|
||
"standardCost": 100.0,
|
||
"colorCode": "#1890FF",
|
||
"sortOrder": 99,
|
||
"status": "1",
|
||
"remark": "测试数据"
|
||
}
|
||
```
|
||
|
||
### 1.2 报修工单管理
|
||
|
||
#### 查询报修工单列表
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/list`
|
||
|
||
**接口描述**: 分页查询报修工单列表,支持多种条件筛选,根据用户角色进行数据权限过滤
|
||
|
||
**权限要求**: `pm:repairOrder:list`
|
||
|
||
**数据权限说明**:
|
||
|
||
- **超级管理员**: 可查看所有报修工单
|
||
- **物业维修管理员** (role_key: property_maintenance_admin): 可查看所有报修工单
|
||
- **维修人员** (role_key: maintenance_worker): 只能查看自己创建的工单和分配给自己的工单
|
||
- **普通用户**: 只能查看自己创建的工单
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| --------------- | ------ | ---- | --------------- |
|
||
| pageNum | int | 否 | 页码,默认 1 |
|
||
| pageSize | int | 否 | 页大小,默认 10 |
|
||
| orderNo | string | 否 | 工单编号 |
|
||
| title | string | 否 | 报修标题 |
|
||
| repairLocation | string | 否 | 报修地点 |
|
||
| categoryId | long | 否 | 维修类型 ID |
|
||
| priorityLevel | int | 否 | 紧急程度 |
|
||
| reporterName | string | 否 | 报修人姓名 |
|
||
| reporterPhone | string | 否 | 报修人电话 |
|
||
| orderStatus | string | 否 | 工单状态 |
|
||
| assigneeId | long | 否 | 分派维修员 ID |
|
||
| assigneeName | string | 否 | 分派维修员姓名 |
|
||
| createTimeRange | array | 否 | 创建时间范围 |
|
||
| finishTimeRange | array | 否 | 完成时间范围 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"total": 1,
|
||
"rows": [
|
||
{
|
||
"id": "1939510596285673473",
|
||
"tenantId": "000000",
|
||
"orderNo": "RO202506300002",
|
||
"title": "详细测试工单 - 会议室投影仪故障",
|
||
"description": "会议室投影仪无法正常启动,显示器黑屏,影响会议正常进行。设备型号:EPSON EB-U05,购买时间:2023年6月。",
|
||
"repairLocation": "行政楼三楼305会议室",
|
||
"categoryId": 1,
|
||
"categoryName": "电路维修",
|
||
"priorityLevel": 2,
|
||
"expectedFinishTime": "2025-07-02 02:25:34",
|
||
"reporterId": 1,
|
||
"reporterName": "测试用户",
|
||
"reporterPhone": "13900139001",
|
||
"reporterDept": "信息技术部",
|
||
"orderStatus": "1",
|
||
"assignTime": null,
|
||
"assigneeId": null,
|
||
"assigneeName": null,
|
||
"assignRemark": null,
|
||
"startTime": null,
|
||
"finishTime": null,
|
||
"totalDuration": null,
|
||
"repairResult": null,
|
||
"usedMaterials": null,
|
||
"followSuggestions": null,
|
||
"evaluationScore": null,
|
||
"evaluationTime": null,
|
||
"attachmentCount": 0,
|
||
"progressCount": 1,
|
||
"cancelReason": null,
|
||
"remark": "设备在保修期内,请联系厂家技术支持",
|
||
"createTime": "2025-06-30 02:25:34",
|
||
"updateTime": "2025-06-30 02:25:34"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 生成工单编号
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/generateOrderNo`
|
||
|
||
**接口描述**: 自动生成报修工单编号
|
||
|
||
**权限要求**: 无需特殊权限
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "RO202506300002",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**说明**: 工单编号格式为 `RO + 年月日 + 序号`,如 `RO202506300002`
|
||
|
||
#### 获取报修统计数据
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/statistics`
|
||
|
||
**接口描述**: 获取报修工单的统计数据,用于仪表板展示
|
||
|
||
**权限要求**: `pm:repairOrder:statistics`
|
||
|
||
**访问权限说明**:
|
||
|
||
- **超级管理员**: 可以访问统计数据
|
||
- **物业维修管理员** (role_key: property_maintenance_admin): 可以访问统计数据
|
||
- **维修人员** (role_key: maintenance_worker): **无权限访问**
|
||
- **普通用户**: **无权限访问**
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"totalOrders": 156,
|
||
"pendingAssign": 23,
|
||
"inProgress": 45,
|
||
"completed": 88,
|
||
"cancelled": 0,
|
||
"avgProcessTime": 2.5,
|
||
"avgEvaluationScore": 4.3,
|
||
"monthlyNewOrders": 67,
|
||
"monthlyCompletedOrders": 52,
|
||
"statusDistribution": [
|
||
{
|
||
"status": "待分派",
|
||
"count": 23,
|
||
"percentage": 14.7
|
||
},
|
||
{
|
||
"status": "进行中",
|
||
"count": 45,
|
||
"percentage": 28.8
|
||
},
|
||
{
|
||
"status": "已完成",
|
||
"count": 88,
|
||
"percentage": 56.4
|
||
}
|
||
],
|
||
"categoryDistribution": [
|
||
{
|
||
"categoryName": "电路维修",
|
||
"count": 45,
|
||
"percentage": 28.8
|
||
},
|
||
{
|
||
"categoryName": "水管维修",
|
||
"count": 38,
|
||
"percentage": 24.4
|
||
}
|
||
],
|
||
"priorityDistribution": [
|
||
{
|
||
"priorityLevel": 1,
|
||
"count": 12,
|
||
"percentage": 7.7
|
||
},
|
||
{
|
||
"priorityLevel": 2,
|
||
"count": 34,
|
||
"percentage": 21.8
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**统计字段说明**:
|
||
|
||
| 字段名 | 类型 | 说明 |
|
||
| ---------------------- | ----- | ---------------------- |
|
||
| totalOrders | int | 总工单数量 |
|
||
| pendingAssign | int | 待分派工单数 |
|
||
| inProgress | int | 进行中工单数 |
|
||
| completed | int | 已完成工单数 |
|
||
| cancelled | int | 已取消工单数 |
|
||
| avgProcessTime | float | 平均处理时长(小时) |
|
||
| avgEvaluationScore | float | 平均评价得分(1-5 分) |
|
||
| monthlyNewOrders | int | 本月新增工单数 |
|
||
| monthlyCompletedOrders | int | 本月完成工单数 |
|
||
| statusDistribution | array | 各状态分布统计 |
|
||
| categoryDistribution | array | 各类型分布统计 |
|
||
| priorityDistribution | array | 紧急程度分布统计 |
|
||
|
||
**使用场景**:
|
||
|
||
- 报修管理仪表板数据展示
|
||
- 运营分析和报表生成
|
||
- 工单处理效率监控
|
||
- 维修类型热度分析
|
||
|
||
**注意事项**:
|
||
|
||
- 当前版本返回模拟数据,用于前端开发测试
|
||
- 生产环境需要实现真实的统计计算逻辑
|
||
- 统计数据会根据用户权限进行过滤
|
||
|
||
#### 获取报修工单详情
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/{id}`
|
||
|
||
**接口描述**: 根据 ID 获取报修工单详细信息,用于前端详情弹窗展示完整工单信息
|
||
|
||
**权限要求**: `pm:repairOrder:query`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------ | ---- | ---- | ------- |
|
||
| id | long | 是 | 工单 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"id": 1001,
|
||
"orderNo": "RO20250126001",
|
||
"title": "宿舍A304水龙头漏水",
|
||
"description": "水龙头一直滴水,影响正常使用,需要及时维修",
|
||
"repairLocation": "学生宿舍A栋304室",
|
||
"categoryId": 102,
|
||
"categoryName": "水管维修",
|
||
"priorityLevel": 2,
|
||
"expectedFinishTime": "2025-01-27 18:00:00",
|
||
"reporterId": 10001,
|
||
"reporterName": "张小明",
|
||
"reporterPhone": "13800138001",
|
||
"reporterDept": "计算机学院",
|
||
"orderStatus": "1",
|
||
"assignTime": null,
|
||
"assigneeId": null,
|
||
"assigneeName": null,
|
||
"assignRemark": null,
|
||
"startTime": null,
|
||
"finishTime": null,
|
||
"totalDuration": null,
|
||
"repairResult": null,
|
||
"usedMaterials": null,
|
||
"followSuggestions": null,
|
||
"evaluationScore": null,
|
||
"evaluationTime": null,
|
||
"attachmentCount": 0,
|
||
"progressCount": 1,
|
||
"cancelReason": null,
|
||
"remark": null,
|
||
"createTime": "2025-01-26 10:30:00",
|
||
"updateTime": "2025-01-26 10:30:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端使用说明**:
|
||
|
||
- 该接口用于工单详情弹窗展示,返回 RepairOrderVO 完整对象
|
||
- 前端根据字段是否有值决定显示哪些信息区域:
|
||
- 基本信息:工单编号、状态、紧急程度、创建时间、标题、问题描述
|
||
- 报修信息:报修人、联系电话、部门、期望完成时间、报修地点
|
||
- 维修信息:维修员、时间节点、处理时长、进度记录、分派备注
|
||
- 维修结果:维修结果、使用材料、后续建议
|
||
- 评价信息:综合评分、评价时间
|
||
- 其他信息:附件数量、维修类型、取消原因、备注信息
|
||
- 支持响应式布局,在移动端和桌面端都有良好展示
|
||
|
||
#### 新增报修工单
|
||
|
||
**接口地址**: `POST /hq/pm/repairOrder`
|
||
|
||
**接口描述**: 创建新的报修工单
|
||
|
||
**权限要求**: `pm:repairOrder:add`
|
||
|
||
**请求参数**:
|
||
|
||
```json
|
||
{
|
||
"orderNo": "RO202506300002",
|
||
"title": "详细测试工单 - 会议室投影仪故障",
|
||
"description": "会议室投影仪无法正常启动,显示器黑屏,影响会议正常进行。设备型号:EPSON EB-U05,购买时间:2023年6月。",
|
||
"repairLocation": "行政楼三楼305会议室",
|
||
"categoryId": 1,
|
||
"priorityLevel": 2,
|
||
"expectedFinishTime": "2025-07-02 02:25:34",
|
||
"reporterName": "测试用户",
|
||
"reporterPhone": "13900139001",
|
||
"reporterDept": "信息技术部",
|
||
"remark": "设备在保修期内,请联系厂家技术支持"
|
||
}
|
||
```
|
||
|
||
**字段说明**:
|
||
|
||
| 字段名 | 类型 | 必填 | 说明 |
|
||
| ------------------ | ------ | ---- | -------------------------------------------------------- |
|
||
| orderNo | string | 是 | 工单编号 |
|
||
| title | string | 是 | 报修标题 |
|
||
| description | string | 是 | 问题描述 |
|
||
| repairLocation | string | 是 | 报修地点 |
|
||
| categoryId | long | 是 | 维修类型 ID |
|
||
| priorityLevel | int | 是 | 紧急程度:1-非常紧急,2-紧急,3-一般,4-不紧急,5-可延后 |
|
||
| expectedFinishTime | string | 否 | 期望完成时间 |
|
||
| reporterName | string | 是 | 报修人姓名 |
|
||
| reporterPhone | string | 是 | 报修人电话 |
|
||
| reporterDept | string | 否 | 报修人部门 |
|
||
| remark | string | 否 | 备注信息 |
|
||
|
||
### 1.3 工单操作管理
|
||
|
||
#### 分派工单
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/assign`
|
||
|
||
**接口描述**: 将工单分派给维修人员
|
||
|
||
**权限要求**: `pm:repairOrder:assign`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------- | ---- | ---- | ------- |
|
||
| orderId | long | 是 | 工单 ID |
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------------ | ------ | ---- | ------------ |
|
||
| assigneeId | long | 是 | 维修员 ID |
|
||
| assignRemark | string | 否 | 分派备注说明 |
|
||
|
||
#### 开始维修
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/start`
|
||
|
||
**接口描述**: 维修人员开始处理工单
|
||
|
||
**权限要求**: `pm:repairOrder:start`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------- | ---- | ---- | ------- |
|
||
| orderId | long | 是 | 工单 ID |
|
||
|
||
#### 完成维修
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/finish`
|
||
|
||
**接口描述**: 标记工单为已完成
|
||
|
||
**权限要求**: `pm:repairOrder:finish`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------- | ---- | ---- | ------- |
|
||
| orderId | long | 是 | 工单 ID |
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------------- | ------ | ---- | ------------ |
|
||
| repairResult | string | 否 | 维修结果描述 |
|
||
| usedMaterials | string | 否 | 使用材料清单 |
|
||
|
||
#### 取消工单
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/cancel`
|
||
|
||
**接口描述**: 取消工单
|
||
|
||
**权限要求**: `pm:repairOrder:cancel`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------- | ---- | ---- | ------- |
|
||
| orderId | long | 是 | 工单 ID |
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------------ | ------ | ---- | -------- |
|
||
| cancelReason | string | 否 | 取消原因 |
|
||
|
||
#### 获取工单进度列表
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/{orderId}/progress`
|
||
|
||
**接口描述**: 获取指定工单的进度记录列表,按时间顺序展示工单处理进度
|
||
|
||
**权限要求**: `pm:repairOrder:progress`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"orderId": 1,
|
||
"progressType": "1",
|
||
"progressStatus": "工单已分派",
|
||
"progressDetail": "工单已分派给维修人员zwc007",
|
||
"operatorId": 1,
|
||
"operatorName": "管理员",
|
||
"createTime": "2025-06-30 09:00:00"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"orderId": 1,
|
||
"progressType": "2",
|
||
"progressStatus": "接收确认",
|
||
"progressDetail": "维修人员已接收工单,准备前往现场",
|
||
"operatorId": 7,
|
||
"operatorName": "zwc007",
|
||
"createTime": "2025-06-30 09:30:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 403 | 无权限 | 确认用户有查看进度权限 |
|
||
| 404 | 工单不存在 | 检查工单 ID 是否正确 |
|
||
|
||
#### 更新维修进度
|
||
|
||
**接口地址**: `POST /hq/pm/repairOrder/progress`
|
||
|
||
**接口描述**: 维修人员更新工单维修进度,保存真实进度记录到数据库,首次更新时自动将工单状态从"已分派"改为"进行中"
|
||
|
||
**权限要求**: `pm:repairOrder:updateProgress`
|
||
|
||
**业务逻辑**:
|
||
|
||
- 保存进度记录到`pm_repair_progress`表
|
||
- 如果是首次更新进度(工单状态为"已分派"),自动将状态改为"进行中"
|
||
- 自动设置`start_time`开始处理时间
|
||
- 更新工单的`progress_count`统计字段
|
||
- 完整的权限验证和数据权限控制
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
| progressType | String | Y | 进度类型:1-工单分派,2-接收确认,3-到达现场,4-开始维修,5-进度更新,6-完成维修,7-用户评价,8-工单归档,9-其他 | "5" |
|
||
| progressStatus | String | Y | 进度状态描述 | "现场检查中" |
|
||
| progressDetail | String | Y | 进度详细说明 | "已到达现场,正在检查设备状态" |
|
||
| locationInfo | String | N | 位置信息 | "教学楼 A 座 201" |
|
||
| estimatedDuration | Integer | N | 预计用时(分钟) | 120 |
|
||
| nextStep | String | N | 下一步计划 | "安装新部件" |
|
||
| issuesEncountered | String | N | 遇到的问题 | "部分线路老化需要更换" |
|
||
| materialsNeeded | String | N | 所需材料 | "电线、插座" |
|
||
| remark | String | N | 备注信息 | "进度顺利" |
|
||
|
||
**状态自动流转**:
|
||
|
||
- 当工单状态为"已分派"(2)时,首次更新进度将自动触发状态流转为"进行中"(3)
|
||
- 同时设置工单的`start_time`为当前时间
|
||
- 后续进度更新不再触发状态变化
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 400001 | 工单不存在 | 检查工单 ID |
|
||
| 400002 | 无权限操作该工单 | 检查用户权限 |
|
||
| 400003 | 只能为已分派或进行中状态的工单更新进度 | 工单状态必须为"已分派"(2)或"进行中"(3) |
|
||
| 500001 | 进度记录保存失败 | 联系系统管理员 |
|
||
|
||
#### 完成工单(详细版)
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/complete`
|
||
|
||
**接口描述**: 完成工单并填写维修结果,将工单状态从"进行中"改为"已完成",同时记录完成时间和处理时长
|
||
|
||
**权限要求**: `pm:repairOrder:complete`
|
||
|
||
**业务逻辑**:
|
||
|
||
- 验证工单状态必须为"进行中"(3)
|
||
- 自动计算处理时长(基于开始时间和完成时间)
|
||
- 更新工单状态为"已完成"(4)
|
||
- 自动添加完成进度记录
|
||
- 完成的权限验证和数据权限控制
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID(路径参数) | 1 |
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| repairResult | String | Y | 维修结果描述 | "电路故障已修复,更换了老化线路和插座" |
|
||
| usedMaterials | String | N | 使用材料清单 | "电线 2 米、插座 1 个、绝缘胶带 1 卷" |
|
||
| followSuggestions | String | N | 后续建议 | "建议半年后进行一次电路安全检查" |
|
||
|
||
**状态流转**:
|
||
|
||
- 只有"进行中"(3)状态的工单才能完成
|
||
- 完成后状态自动变为"已完成"(4)
|
||
- 自动设置`finish_time`完成时间
|
||
- 自动计算`total_duration`处理时长
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 400001 | 工单不存在 | 检查工单 ID |
|
||
| 400002 | 无权限操作该工单 | 检查用户权限 |
|
||
| 400003 | 只能完成进行中状态的工单 | 工单状态必须为"进行中"(3) |
|
||
| 500001 | 工单完成状态更新失败 | 联系系统管理员 |
|
||
|
||
#### 创建服务评价
|
||
|
||
**接口地址**: `POST /hq/pm/repairOrder/evaluation`
|
||
|
||
**接口描述**: 对已完成的工单进行服务评价,支持多维度评分
|
||
|
||
**权限要求**: `pm:repairOrder:evaluate`
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
| evaluatedWorkerId | Long | N | 被评价的维修员 ID | 7 |
|
||
| overallScore | Integer | Y | 综合评分(1-5) | 5 |
|
||
| qualityScore | Integer | N | 质量评分(1-5) | 5 |
|
||
| attitudeScore | Integer | N | 态度评分(1-5) | 4 |
|
||
| responseSpeedScore | Integer | N | 响应速度评分(1-5) | 5 |
|
||
| communicationScore | Integer | N | 沟通评分(1-5) | 4 |
|
||
| evaluationContent | String | Y | 评价内容 | "维修及时,服务态度好" |
|
||
| satisfactionLevel | String | N | 满意度等级 | "1" |
|
||
| isAnonymous | Integer | N | 是否匿名(0 否 1 是) | 0 |
|
||
| isPublic | Integer | N | 是否公开(0 否 1 是) | 1 |
|
||
| positiveTags | String | N | 正面标签 | "专业,及时" |
|
||
| negativeTags | String | N | 负面标签 | "" |
|
||
| improvementSuggestions | String | N | 改进建议 | "无" |
|
||
| remark | String | N | 备注 | "" |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "服务评价提交成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 400 | 参数错误 | 检查评分范围和必填参数 |
|
||
| 403 | 无权限 | 确认用户有评价权限 |
|
||
| 409 | 重复评价 | 该工单已有评价记录 |
|
||
|
||
#### 获取服务评价
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/{orderId}/evaluation`
|
||
|
||
**接口描述**: 获取指定工单的服务评价信息
|
||
|
||
**权限要求**: `pm:repairOrder:query`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"id": 1,
|
||
"orderId": 1,
|
||
"overallScore": 5,
|
||
"qualityScore": 5,
|
||
"attitudeScore": 4,
|
||
"responseSpeedScore": 5,
|
||
"communicationScore": 4,
|
||
"evaluationContent": "维修及时,服务态度好,质量可靠。",
|
||
"satisfactionLevel": "1",
|
||
"createTime": "2025-06-30 16:00:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 403 | 无权限 | 确认用户有查询权限 |
|
||
| 404 | 评价不存在 | 该工单暂无评价记录 |
|
||
|
||
#### 获取维修人员选项
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/maintenance-workers`
|
||
|
||
**接口描述**: 获取拥有"维修人员"角色的用户选项列表,用于分派工单时选择维修员
|
||
|
||
**权限要求**: `pm:repairOrder:assign`
|
||
|
||
**请求参数**: 无
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"value": 7,
|
||
"label": "zwc007 - 智胜技术开发团队",
|
||
"userName": "zwc007",
|
||
"deptName": "智胜技术开发团队"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 403 | 无权限 | 确认用户有分派权限 |
|
||
|
||
### 1.4 工单状态说明
|
||
|
||
| 状态值 | 状态名称 | 说明 |
|
||
| ------ | -------- | -------------------- |
|
||
| 1 | 待分派 | 工单已创建,等待分派 |
|
||
| 2 | 已分派 | 已分派给维修人员 |
|
||
| 3 | 进行中 | 维修人员正在处理 |
|
||
| 4 | 已完成 | 维修工作已完成 |
|
||
| 5 | 已评价 | 用户已对服务进行评价 |
|
||
| 6 | 已归档 | 工单已归档 |
|
||
| 9 | 已取消 | 工单已被取消 |
|
||
|
||
### 1.5 紧急程度说明
|
||
|
||
| 级别值 | 级别名称 | 说明 |
|
||
| ------ | -------- | ------------------------ |
|
||
| 1 | 非常紧急 | 影响正常运营,需立即处理 |
|
||
| 2 | 紧急 | 影响使用,需尽快处理 |
|
||
| 3 | 一般 | 正常维修需求 |
|
||
| 4 | 不紧急 | 可延后处理 |
|
||
| 5 | 可延后 | 条件允许时处理 |
|
||
|
||
---
|
||
|
||
## 2. 问卷管理 API
|
||
|
||
### 1.1 问卷基础管理
|
||
|
||
#### 查询问卷列表
|
||
|
||
**接口地址**: `GET /hq/satSurvey/list`
|
||
|
||
**接口描述**: 分页查询问卷列表,支持权限过滤
|
||
|
||
**权限要求**: `hq:satSurvey:list`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ----------- | ------ | ---- | --------------------- |
|
||
| pageNum | int | 否 | 页码,默认 1 |
|
||
| pageSize | int | 否 | 页大小,默认 10 |
|
||
| surveyCode | string | 否 | 问卷编号 |
|
||
| surveyTitle | string | 否 | 问卷标题 |
|
||
| targetGroup | string | 否 | 目标群体 |
|
||
| status | string | 否 | 问卷状态 |
|
||
| isPublished | int | 否 | 是否发布(1 是 0 否) |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"total": 100,
|
||
"rows": [
|
||
{
|
||
"id": 1,
|
||
"surveyCode": "SURVEY001",
|
||
"surveyTitle": "满意度调查",
|
||
"surveyDesc": "学生满意度调查",
|
||
"targetGroup": "1",
|
||
"startTime": "2025-01-01 00:00:00",
|
||
"endTime": "2025-01-31 23:59:59",
|
||
"isAnonymous": 1,
|
||
"isPublished": 1,
|
||
"status": "1"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 获取问卷详情
|
||
|
||
**接口地址**: `GET /hq/satSurvey/{id}`
|
||
|
||
**接口描述**: 根据 ID 获取问卷详细信息
|
||
|
||
**权限要求**: `hq:satSurvey:query`
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------ | ---- | ---- | ------- |
|
||
| id | long | 是 | 问卷 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"id": 1,
|
||
"surveyCode": "SURVEY001",
|
||
"surveyTitle": "满意度调查",
|
||
"surveyDesc": "学生满意度调查",
|
||
"surveyInstruction": "请认真填写",
|
||
"targetGroup": "1",
|
||
"startTime": "2025-01-01 00:00:00",
|
||
"endTime": "2025-01-31 23:59:59",
|
||
"maxSubmitTimes": 1,
|
||
"isAnonymous": 1,
|
||
"isPublished": 1,
|
||
"status": "1",
|
||
"remark": ""
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 新增问卷
|
||
|
||
**接口地址**: `POST /hq/satSurvey`
|
||
|
||
**接口描述**: 创建新的问卷
|
||
|
||
**权限要求**: `hq:satSurvey:add`
|
||
|
||
**请求参数**:
|
||
|
||
```json
|
||
{
|
||
"surveyCode": "SURVEY001",
|
||
"surveyTitle": "满意度调查",
|
||
"surveyDesc": "学生满意度调查",
|
||
"surveyInstruction": "请认真填写",
|
||
"targetGroup": "1",
|
||
"startTime": "2025-01-01 00:00:00",
|
||
"endTime": "2025-01-31 23:59:59",
|
||
"maxSubmitTimes": 1,
|
||
"isAnonymous": 1,
|
||
"remark": ""
|
||
}
|
||
```
|
||
|
||
#### 修改问卷
|
||
|
||
**接口地址**: `PUT /hq/satSurvey`
|
||
|
||
**接口描述**: 修改问卷信息
|
||
|
||
**权限要求**: `hq:satSurvey:edit`
|
||
|
||
#### 删除问卷
|
||
|
||
**接口地址**: `DELETE /hq/satSurvey/{ids}`
|
||
|
||
**接口描述**: 批量删除问卷
|
||
|
||
**权限要求**: `hq:satSurvey:remove`
|
||
|
||
#### 发布问卷
|
||
|
||
**接口地址**: `PUT /hq/satSurvey/{id}/publish`
|
||
|
||
**接口描述**: 发布问卷,将状态改为进行中
|
||
|
||
**权限要求**: `hq:satSurvey:publish`
|
||
|
||
#### 撤销发布问卷
|
||
|
||
**接口地址**: `PUT /hq/satSurvey/{id}/unpublish`
|
||
|
||
**接口描述**: 撤销发布问卷,将状态改为草稿
|
||
|
||
**权限要求**: `hq:satSurvey:unpublish`
|
||
|
||
### 1.2 问卷题目管理
|
||
|
||
#### 获取问卷题目列表
|
||
|
||
**接口地址**: `GET /hq/satSurvey/{surveyId}/questions`
|
||
|
||
**接口描述**: 获取问卷关联的题目列表,包含题目详细信息和选项
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| -------- | ---- | ---- | ------- |
|
||
| surveyId | long | 是 | 问卷 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"surveyId": 1,
|
||
"questionId": 1,
|
||
"sortOrder": 1,
|
||
"weight": 1,
|
||
"isRequired": 1,
|
||
"questionTitle": "您对服务质量的评价?",
|
||
"questionType": "1",
|
||
"questionDesc": "请选择一个选项",
|
||
"options": [
|
||
{
|
||
"id": 1,
|
||
"questionId": 1,
|
||
"optionValue": "A",
|
||
"optionText": "非常满意",
|
||
"optionScore": 5,
|
||
"sortOrder": 1
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 更新问卷题目关联
|
||
|
||
**接口地址**: `PUT /hq/satSurvey/{surveyId}/questions`
|
||
|
||
**接口描述**: 批量更新问卷题目关联关系
|
||
|
||
**权限要求**: `hq:satSurvey:question`
|
||
|
||
---
|
||
|
||
## 2. 答题 API(新增)
|
||
|
||
### 2.1 答题提交
|
||
|
||
#### 提交问卷答案
|
||
|
||
**接口地址**: `POST /hq/satSurvey/answer/submit`
|
||
|
||
**接口描述**: 提交问卷答案,正式提交后不可修改
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**请求参数**:
|
||
|
||
```json
|
||
{
|
||
"surveyId": 1,
|
||
"startTime": "2025-01-26T14:00:00.000Z",
|
||
"endTime": "2025-01-26T14:15:00.000Z",
|
||
"isAnonymous": 1,
|
||
"answers": [
|
||
{
|
||
"questionId": 1,
|
||
"questionType": "1",
|
||
"answerValue": "A",
|
||
"options": [
|
||
{
|
||
"optionId": 1,
|
||
"optionValue": "A",
|
||
"optionText": "非常满意",
|
||
"isSelected": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"questionId": 2,
|
||
"questionType": "2",
|
||
"answerValue": "A,C,D",
|
||
"options": [
|
||
{
|
||
"optionId": 2,
|
||
"optionValue": "A",
|
||
"optionText": "选项A",
|
||
"isSelected": true
|
||
},
|
||
{
|
||
"optionId": 4,
|
||
"optionValue": "C",
|
||
"optionText": "选项C",
|
||
"isSelected": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"questionId": 3,
|
||
"questionType": "3",
|
||
"answerValue": "这是我的意见和建议内容",
|
||
"options": []
|
||
}
|
||
],
|
||
"remark": ""
|
||
}
|
||
```
|
||
|
||
**参数说明**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ----------- | ------ | ---- | ----------------------------- |
|
||
| surveyId | long | 是 | 问卷 ID |
|
||
| startTime | string | 是 | 答题开始时间(ISO 8601 格式) |
|
||
| endTime | string | 是 | 答题结束时间(ISO 8601 格式) |
|
||
| isAnonymous | int | 是 | 是否匿名(1 是 0 否) |
|
||
| answers | array | 是 | 答案列表 |
|
||
| remark | string | 否 | 备注 |
|
||
|
||
**answers 中每项参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ------------ | ------ | ---- | ------------------------------------------------ |
|
||
| questionId | long | 是 | 题目 ID |
|
||
| questionType | string | 是 | 题目类型(1 单选题 2 多选题 3 问答题) |
|
||
| answerValue | string | 是 | 答案值(单选存选项值,多选逗号分隔,问答存文本) |
|
||
| options | array | 否 | 选项详情(单选题和多选题需要) |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "答题提交成功",
|
||
"data": {
|
||
"id": 1001,
|
||
"surveyId": 1,
|
||
"userId": 1,
|
||
"userType": "student",
|
||
"submitTime": "2025-01-26T14:15:00.000Z",
|
||
"totalScore": 0,
|
||
"avgScore": 0,
|
||
"remark": ""
|
||
}
|
||
}
|
||
```
|
||
|
||
**多次提交功能说明**(v1.0.3 新增,v1.0.4 优化):
|
||
|
||
系统支持问卷多次提交功能,提交次数限制由问卷的 `max_submit_times` 字段控制:
|
||
|
||
1. **提交次数规则**:
|
||
|
||
- `max_submit_times = 0`: 不限制提交次数,用户可以无限次提交
|
||
- `max_submit_times = 1`: 最多提交 1 次(默认行为,向后兼容)
|
||
- `max_submit_times = N`: 最多提交 N 次
|
||
|
||
2. **数据存储策略**(v1.0.4 重要更新):
|
||
|
||
- **软删除历史数据**: 用户提交新答案时,系统会自动将之前的答题记录标记为已删除(deleted=1)
|
||
- **保持数据完整性**: 历史数据完整保留用于审计,但业务查询只返回最新有效数据
|
||
- **关联删除**: 通过 record_id 关联,确保 hq_sat_record、hq_sat_detail、hq_sat_answer 三表数据状态同步
|
||
|
||
3. **数据状态管理**:
|
||
|
||
- `deleted = 0`: 有效数据,正常业务查询可见
|
||
- `deleted = 1`: 历史数据,仅审计查询可见
|
||
- 用户每次只能看到最新的有效答题记录
|
||
|
||
4. **处理流程**:
|
||
|
||
```
|
||
用户提交新答案 → 标记历史数据为删除 → 保存新答题数据 → 返回最新记录
|
||
```
|
||
|
||
5. **错误处理**:
|
||
|
||
```json
|
||
{
|
||
"code": 500,
|
||
"msg": "您已达到该问卷的最大提交次数限制(3次)",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
6. **使用场景**:
|
||
|
||
- **单次提交**: 正式考试、重要调研等
|
||
- **多次提交**: 练习测试、阶段性评估等
|
||
- **无限提交**: 学习练习、反馈收集等
|
||
|
||
7. **业务优势**:
|
||
- ✅ **用户体验**: 查看答题记录始终是最新版本
|
||
- ✅ **数据审计**: 历史记录完整保留,支持数据回溯
|
||
- ✅ **查询性能**: 业务查询只涉及有效数据,提高效率
|
||
- ✅ **数据一致性**: 避免多版本数据混乱问题
|
||
|
||
**数据保存说明**:
|
||
|
||
此接口在保存答题记录时,会同时保存详细的答案信息到两个表:
|
||
|
||
1. **hq_sat_detail 表**:保存答题概要信息
|
||
|
||
- 记录答题记录 ID、题目 ID、答案分数等基础信息
|
||
- remark 字段存储答案内容的摘要信息
|
||
|
||
2. **hq_sat_answer 表**:保存具体的答案详情(v1.0.1 新增,v1.0.2 修复)
|
||
- **单选题**:为选中的选项创建一条记录,包含选项 ID、选项标识(A/B/C/D)、选项文本、真实分值
|
||
- **多选题**:为每个选中的选项创建一条记录,使用选项标识区分不同选项
|
||
- **问答题**:创建一条记录,选项相关字段为 NULL,答案值存储用户输入的文本内容
|
||
|
||
**hq_sat_answer 表数据示例**(v1.0.2 修复后):
|
||
|
||
```sql
|
||
-- 单选题答案记录(用户选择"非常满意"选项)
|
||
INSERT INTO hq_sat_answer VALUES (
|
||
1, '000000', 1001, NOW(), 1, NOW(), 0, -- 基础字段
|
||
123, 1, '1', 1, 'A', '非常满意', 'A', 5, NULL -- 答案字段
|
||
);
|
||
|
||
-- 多选题答案记录(用户选中A、C两个选项)
|
||
INSERT INTO hq_sat_answer VALUES
|
||
(2, '000000', 1001, NOW(), 1, NOW(), 0, 123, 2, '2', 1, 'A', '非常满意', 'A,C', 5, NULL),
|
||
(3, '000000', 1001, NOW(), 1, NOW(), 0, 123, 2, '2', 3, 'C', '一般', 'A,C', 1, NULL);
|
||
|
||
-- 问答题答案记录
|
||
INSERT INTO hq_sat_answer VALUES (
|
||
4, '000000', 1001, NOW(), 1, NOW(), 0, -- 基础字段
|
||
123, 3, '3', NULL, NULL, NULL, '这是我的意见和建议', 0, NULL -- 答案字段
|
||
);
|
||
```
|
||
|
||
**字段说明**(修复后):
|
||
|
||
- `option_value`: 存储选项标识(A、B、C、D),便于统计分析
|
||
- `answer_score`: 存储真实分值(从 hq_sat_option 表查询获得)
|
||
- `answer_value`: 单选题存选项标识,多选题存逗号分隔的多个标识,问答题存文本
|
||
|
||
#### 保存问卷答案草稿
|
||
|
||
**接口地址**: `POST /hq/satSurvey/answer/draft`
|
||
|
||
**接口描述**: 保存问卷答案草稿,可多次保存和修改
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**请求参数**: 同提交问卷答案
|
||
|
||
**响应示例**: 同提交问卷答案
|
||
|
||
### 2.2 答题状态查询
|
||
|
||
#### 检查用户是否已答过问卷
|
||
|
||
**接口地址**: `GET /hq/satSurvey/{surveyId}/answered`
|
||
|
||
**接口描述**: 检查当前用户是否已经答过指定问卷(v1.0.3 更新:支持多次提交检查)
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| -------- | ---- | ---- | ------- |
|
||
| surveyId | long | 是 | 问卷 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": true
|
||
}
|
||
```
|
||
|
||
**响应说明**(v1.0.3 更新):
|
||
|
||
- `data` 为 `true` 表示用户已答过该问卷(至少提交过 1 次)
|
||
- `data` 为 `false` 表示用户未答过该问卷
|
||
|
||
**多次提交支持**:
|
||
此接口仅返回用户是否有答题记录,不考虑提交次数限制。要检查是否还能继续提交,请参考以下逻辑:
|
||
|
||
- 如果 `max_submit_times = 0`:始终可以提交
|
||
- 如果 `max_submit_times > 0`:需要检查用户提交次数是否小于此限制
|
||
- 具体的提交限制检查由"提交问卷答案"接口在提交时进行
|
||
|
||
#### 获取用户问卷答题记录
|
||
|
||
**接口地址**: `GET /hq/satSurvey/{surveyId}/answer`
|
||
|
||
**接口描述**: 获取当前用户对指定问卷的答题记录(v1.0.5 重大更新:优化数据源,支持前端答案回显)
|
||
|
||
**权限要求**: 需要登录
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| -------- | ---- | ---- | ------- |
|
||
| surveyId | long | 是 | 问卷 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"id": 1001,
|
||
"surveyId": 1,
|
||
"userId": 1,
|
||
"userType": "student",
|
||
"submitTime": "2025-01-26T14:15:00.000Z",
|
||
"totalScore": 0,
|
||
"avgScore": 0,
|
||
"remark": "ANSWERS_DATA:[{\"questionId\":1,\"questionType\":\"1\",\"answerValue\":\"A\"},{\"questionId\":2,\"questionType\":\"2\",\"answerValue\":\"A,C\"}]"
|
||
}
|
||
}
|
||
```
|
||
|
||
**返回数据说明**(v1.0.5 重大更新):
|
||
|
||
- 此接口只返回用户最新的有效答题记录(deleted=0)
|
||
- 如果用户进行了多次提交,历史记录已被软删除,查询不到
|
||
- 返回的是用户最后一次提交的完整答题信息
|
||
- 历史记录完整保留在数据库中,仅用于审计目的
|
||
|
||
**v1.0.5 新增功能 - 答案回显数据**:
|
||
|
||
为支持前端答题界面的历史答案回显功能,此接口现在会在 `remark` 字段中包含格式化的答案数据:
|
||
|
||
1. **数据格式**: `ANSWERS_DATA:[答案JSON数组]`
|
||
2. **数据来源**: 直接从 `hq_sat_answer` 表查询,比 v1.0.4 之前的 `remark` 解析更准确
|
||
3. **答案结构**:
|
||
```json
|
||
[
|
||
{
|
||
"questionId": 1,
|
||
"questionType": "1",
|
||
"answerValue": "A"
|
||
},
|
||
{
|
||
"questionId": 2,
|
||
"questionType": "2",
|
||
"answerValue": "A,C"
|
||
},
|
||
{
|
||
"questionId": 3,
|
||
"questionType": "3",
|
||
"answerValue": "用户输入的文本内容"
|
||
}
|
||
]
|
||
```
|
||
|
||
**前端答案回显逻辑**:
|
||
|
||
- **单选题** (`questionType = "1"`): `answerValue` 直接设置到单选控件(如 "A")
|
||
- **多选题** (`questionType = "2"`): `answerValue` 按逗号分割成数组(如 ["A", "C"])
|
||
- **问答题** (`questionType = "3"`): `answerValue` 直接设置到文本框
|
||
|
||
**使用场景**:
|
||
|
||
- ✅ **首次答题**: 返回 404,前端正常显示空表单
|
||
- ✅ **重新答题**: 返回历史答案,前端自动回显到表单
|
||
- ✅ **多次修改**: 基于上次答案继续编辑,提升用户体验
|
||
|
||
---
|
||
|
||
## 3. 题目管理 API
|
||
|
||
### 3.1 题目基础管理
|
||
|
||
#### 查询题目列表
|
||
|
||
**接口地址**: `GET /hq/satQuestion/list`
|
||
|
||
**权限要求**: `hq:satQuestion:list`
|
||
|
||
#### 获取题目选项
|
||
|
||
**接口地址**: `GET /hq/satQuestion/{questionId}/options`
|
||
|
||
**接口描述**: 获取指定题目的所有选项
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
| ---------- | ---- | ---- | ------- |
|
||
| questionId | long | 是 | 题目 ID |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"questionId": 1,
|
||
"optionValue": "A",
|
||
"optionText": "非常满意",
|
||
"optionScore": 5,
|
||
"sortOrder": 1
|
||
},
|
||
{
|
||
"id": 2,
|
||
"questionId": 1,
|
||
"optionValue": "B",
|
||
"optionText": "满意",
|
||
"optionScore": 4,
|
||
"sortOrder": 2
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 答题记录管理 API
|
||
|
||
### 4.1 答题记录查询
|
||
|
||
#### 查询答题记录列表
|
||
|
||
**接口地址**: `GET /hq/satRecord/list`
|
||
|
||
**权限要求**: `hq:satRecord:list`
|
||
|
||
#### 获取答题记录详情
|
||
|
||
**接口地址**: `GET /hq/satRecord/{id}`
|
||
|
||
**权限要求**: `hq:satRecord:query`
|
||
|
||
---
|
||
|
||
## 5. 错误码说明
|
||
|
||
### 业务错误码
|
||
|
||
| 错误码 | 说明 | 解决方案 |
|
||
| ------ | ------------------ | ------------------------ |
|
||
| 40001 | 问卷不存在 | 检查问卷 ID 是否正确 |
|
||
| 40002 | 问卷未在进行中状态 | 等待问卷开始或联系管理员 |
|
||
| 40003 | 您已经答过这份问卷 | 不能重复答题 |
|
||
| 40004 | 答题记录保存失败 | 重新提交或联系技术支持 |
|
||
| 40005 | 题目类型不支持 | 检查题目类型是否正确 |
|
||
|
||
---
|
||
|
||
## 6. 数据字典
|
||
|
||
### 6.1 问卷状态
|
||
|
||
| 值 | 说明 | 备注 |
|
||
| --- | ------ | -------------- |
|
||
| 0 | 草稿 | 未发布状态 |
|
||
| 1 | 进行中 | 已发布,可答题 |
|
||
| 2 | 已结束 | 超过结束时间 |
|
||
|
||
### 6.2 目标群体
|
||
|
||
| 值 | 说明 | 备注 |
|
||
| --- | ------ | ---------- |
|
||
| 1 | 学生 | 在校学生 |
|
||
| 2 | 教职工 | 教师和职工 |
|
||
| 3 | 全体 | 所有人员 |
|
||
|
||
### 6.4 用户类型
|
||
|
||
| 值 | 说明 | 备注 |
|
||
| --- | ---------- | --------------------------------------------------------- |
|
||
| 1 | 学生 | student、学生、stu 等角色映射为此值 |
|
||
| 2 | 教师 | teacher、老师、教师、教职工、tea 等角色映射为此值 |
|
||
| 3 | 超级管理员 | admin、管理员、超级管理员、administrator 等角色映射为此值 |
|
||
|
||
### 6.3 题目类型
|
||
|
||
| 值 | 说明 | 备注 |
|
||
| --- | ------ | ---------------- |
|
||
| 1 | 单选题 | 只能选择一个选项 |
|
||
| 2 | 多选题 | 可以选择多个选项 |
|
||
| 3 | 问答题 | 文本输入 |
|
||
|
||
---
|
||
|
||
## 7. 版本更新记录
|
||
|
||
### v1.0.5 (2025-01-26)
|
||
|
||
- 🚀 **重大更新**:实现答题界面历史答案回显功能,提升多次答题用户体验
|
||
- 🔧 **数据源优化**:`GET /hq/satSurvey/{surveyId}/answer` 接口改用 hq_sat_answer 表直接查询
|
||
- 📊 新增 `getAnswersFromSatAnswerTable()` 方法,提供更准确的答案数据聚合
|
||
- ✨ 前端新增 `loadPreviousAnswers()` 方法,支持三种题型的智能答案回显
|
||
- 🎯 智能用户体验:只在成功加载历史答案时显示提示,异常时优雅降级
|
||
- 🛡️ 错误处理优化:404 错误不显示提示,历史答案加载失败不阻断答题流程
|
||
|
||
### v1.0.4 (2025-01-26)
|
||
|
||
- 🔄 **重要优化**:多次提交时实现历史数据软删除,确保用户只有一份有效答题记录
|
||
- 🗃️ 保留历史数据用于审计,但业务查询只返回最新有效数据
|
||
- ⚡ 优化查询性能,提交次数统计和答题记录查询只涉及有效数据
|
||
- 🛡️ 增强数据一致性,通过 record_id 关联确保三表数据状态同步
|
||
|
||
### v1.0.3 (2025-01-26)
|
||
|
||
- 🚀 **新功能**:实现问卷多次提交功能,支持根据 max_submit_times 设置控制提交次数
|
||
- 📊 优化提交次数检查逻辑,支持 0=无限制、N=最大 N 次的灵活配置
|
||
- ✅ 保留完整的答题历史记录,每次提交创建新的答题记录
|
||
- 🎯 增强用户体验,提供详细的提交次数限制提示信息
|
||
|
||
### v1.0.2 (2025-01-26)
|
||
|
||
- 🔧 **重要修复**:修复单选题和多选题答案未记录到 hq_sat_answer 表的问题
|
||
- 🎯 修复前端选项绑定使用分值导致的数据类型不匹配问题
|
||
- ✅ 优化答案保存逻辑,正确存储选项标识(A、B、C、D)和分值
|
||
- 📊 增强答案数据查询,支持选项分值自动计算
|
||
- 🐛 修复多选题答案保存逻辑错误
|
||
|
||
### v1.0.1 (2025-01-26)
|
||
|
||
- 🔧 修复答题提交时 user_type 字段长度问题
|
||
- ✅ 新增用户角色到数字编码的转换逻辑
|
||
- 📚 新增用户类型数据字典说明
|
||
- 🆕 新增答案详情记录功能,同时保存到 hq_sat_answer 表
|
||
- 📝 完善提交问卷答案接口的数据保存说明
|
||
|
||
### v1.0.0 (2025-01-26)
|
||
|
||
- ✅ 新增答题提交 API
|
||
- ✅ 新增答题状态查询 API
|
||
- ✅ 完善问卷管理 API
|
||
- ✅ 新增题目选项查询 API
|
||
- ✅ 建立完整的 API 文档体系
|
||
|
||
---
|
||
|
||
## 8. 开发说明
|
||
|
||
### 8.1 接口测试
|
||
|
||
推荐使用以下工具进行接口测试:
|
||
|
||
- **Postman**: 图形化接口测试工具
|
||
- **Apifox**: 国产 API 管理工具
|
||
- **curl**: 命令行工具
|
||
|
||
### 8.2 认证方式
|
||
|
||
所有需要权限的接口都需要在请求头中携带认证信息:
|
||
|
||
```http
|
||
Authorization: Bearer {token}
|
||
```
|
||
|
||
### 8.3 时间格式
|
||
|
||
所有时间字段统一使用 ISO 8601 格式:
|
||
|
||
```
|
||
2025-01-26T14:15:00.000Z
|
||
```
|
||
|
||
### 8.4 分页参数
|
||
|
||
所有分页接口统一使用以下参数:
|
||
|
||
- `pageNum`: 页码,从 1 开始
|
||
- `pageSize`: 页大小,默认 10
|
||
|
||
---
|
||
|
||
## 联系方式
|
||
|
||
如有 API 相关问题,请联系开发团队或查看项目仓库的 Issues。
|
||
|
||
---
|
||
|
||
### 分派工单
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/assign`
|
||
**接口描述**: 分派工单给维修员
|
||
**权限要求**: `pm:repairOrder:assign`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| assigneeId | Long | Y | 维修员 ID | 2 |
|
||
| assignRemark | String | N | 分派备注 | "紧急处理" |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "分派成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**错误码**:
|
||
| 错误码 | 说明 | 解决方案 |
|
||
|--------|------|----------|
|
||
| 400001 | 工单不存在 | 检查工单 ID |
|
||
| 400002 | 维修员不存在 | 检查维修员 ID |
|
||
| 400003 | 工单状态不允许分派 | 检查工单状态 |
|
||
|
||
---
|
||
|
||
### 获取工单进度列表
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/{orderId}/progress`
|
||
**接口描述**: 获取指定工单的进度记录列表
|
||
**权限要求**: `pm:repairOrder:progress`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"orderId": 1,
|
||
"progressType": "5",
|
||
"progressStatus": "正在维修",
|
||
"progressDetail": "已到达现场,开始检查设备",
|
||
"operatorId": 2,
|
||
"operatorName": "张维修",
|
||
"operatorRole": "worker",
|
||
"locationInfo": "教学楼A座301",
|
||
"estimatedDuration": 60,
|
||
"operationTime": "2025-06-30 14:30:00",
|
||
"nextStep": "更换零件",
|
||
"issuesEncountered": "发现零件老化",
|
||
"materialsNeeded": "电路板x1",
|
||
"remark": "需要采购新零件"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 更新维修进度
|
||
|
||
**接口地址**: `POST /hq/pm/repairOrder/progress`
|
||
**接口描述**: 添加工单维修进度记录
|
||
**权限要求**: `pm:repairOrder:updateProgress`
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
| progressType | String | Y | 进度类型:1-工单分派,2-接收确认,3-到达现场,4-开始维修,5-进度更新,6-完成维修,7-用户评价,8-工单归档,9-其他 | "5" |
|
||
| progressStatus | String | Y | 进度状态描述 | "正在维修" |
|
||
| progressDetail | String | Y | 进度详细描述 | "已到达现场,开始检查设备" |
|
||
| locationInfo | String | N | 操作位置信息 | "教学楼 A 座 301" |
|
||
| estimatedDuration | Integer | N | 预计耗时(分钟) | 60 |
|
||
| nextStep | String | N | 下一步计划 | "更换零件" |
|
||
| issuesEncountered | String | N | 遇到的问题 | "发现零件老化" |
|
||
| materialsNeeded | String | N | 需要的材料 | "电路板 x1" |
|
||
| remark | String | N | 备注信息 | "需要采购新零件" |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "进度更新成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 完成工单
|
||
|
||
**接口地址**: `PUT /hq/pm/repairOrder/{orderId}/finish`
|
||
**接口描述**: 完成工单维修,填写维修结果
|
||
**权限要求**: `pm:repairOrder:complete`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| repairResult | String | Y | 维修结果描述 | "已更换故障电路板,设备恢复正常" |
|
||
| usedMaterials | String | N | 使用材料清单 | "电路板 x1, 螺丝 x4" |
|
||
| followSuggestions | String | N | 后续建议 | "建议定期检查电路板状态" |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "工单完成成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 创建服务评价
|
||
|
||
**接口地址**: `POST /hq/pm/repairOrder/evaluation`
|
||
**接口描述**: 创建工单服务评价
|
||
**权限要求**: `pm:repairOrder:evaluate`
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
| evaluatedWorkerId | Long | Y | 被评价维修员 ID | 2 |
|
||
| overallScore | Number | Y | 综合评价得分(1.0-5.0) | 4.5 |
|
||
| qualityScore | Number | Y | 维修质量得分(1.0-5.0) | 4.8 |
|
||
| attitudeScore | Number | Y | 服务态度得分(1.0-5.0) | 4.5 |
|
||
| responseSpeedScore | Number | Y | 响应速度得分(1.0-5.0) | 4.2 |
|
||
| communicationScore | Number | Y | 沟通效果得分(1.0-5.0) | 4.6 |
|
||
| evaluationContent | String | Y | 文字评价内容 | "维修师傅技术过硬,态度很好" |
|
||
| satisfactionLevel | String | Y | 满意度等级:1-非常满意,2-满意,3-一般,4-不满意,5-非常不满意 | "1" |
|
||
| isAnonymous | Integer | N | 是否匿名评价:0-否,1-是 | 0 |
|
||
| isPublic | Integer | N | 是否公开显示:0-否,1-是 | 1 |
|
||
| positiveTags | String | N | 正面标签 | "技术专业,态度友好" |
|
||
| negativeTags | String | N | 负面标签 | "" |
|
||
| improvementSuggestions | String | N | 改进建议 | "希望能提前通知到达时间" |
|
||
| remark | String | N | 备注信息 | "" |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "评价提交成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 获取工单评价
|
||
|
||
**接口地址**: `GET /hq/pm/repairOrder/{orderId}/evaluation`
|
||
**接口描述**: 获取指定工单的服务评价信息
|
||
**权限要求**: `pm:repairOrder:query`
|
||
|
||
**路径参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|
||
|--------|------|------|------|--------|
|
||
| orderId | Long | Y | 工单 ID | 1 |
|
||
|
||
**响应示例**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "查询成功",
|
||
"data": {
|
||
"id": 1,
|
||
"orderId": 1,
|
||
"evaluatorId": 3,
|
||
"evaluatorName": "张老师",
|
||
"evaluatedWorkerId": 2,
|
||
"evaluatedWorkerName": "张维修",
|
||
"overallScore": 4.5,
|
||
"qualityScore": 4.8,
|
||
"attitudeScore": 4.5,
|
||
"responseSpeedScore": 4.2,
|
||
"communicationScore": 4.6,
|
||
"evaluationContent": "维修师傅技术过硬,态度很好",
|
||
"satisfactionLevel": "1",
|
||
"isAnonymous": 0,
|
||
"isPublic": 1,
|
||
"positiveTags": "技术专业,态度友好",
|
||
"improvementSuggestions": "希望能提前通知到达时间",
|
||
"evaluationTime": "2025-06-30 16:30:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|