682 lines
21 KiB
Markdown
682 lines
21 KiB
Markdown
# 后勤满意度调查API文档
|
||
|
||
## 文档信息
|
||
|
||
- **版本**:1.0.1
|
||
- **最后更新**:2026-09-20
|
||
- **作者**:Cursor AI
|
||
- **分类**:后勤管理模块
|
||
|
||
## 概述
|
||
|
||
本文档详细说明后勤满意度调查系统的API接口设计,包括问卷管理、题目管理、选项管理、答题记录等功能。系统采用前后端分离架构,接口采用RESTful API风格设计,所有接口均需通过Token进行身份验证。
|
||
|
||
### 问卷过期处理(2026-09-20)
|
||
|
||
- 原依赖 SnailJob 任务 `surveyEndTimeJob` / `surveyEndTimeJobExecutor` 每小时扫描过期问卷。
|
||
- 已改为 Spring `@Scheduled`:`HqSatSurveyExpireTask`(cron:`0 0 * * * ?`),将 `hq_sat_survey` 中 `end_time` 已过期且未结束的记录 `status` 更新为 `2`。
|
||
- 多实例通过 Redis 锁 `hq:sat:survey:expire:lock` 避免重复执行。
|
||
- 测试库已关闭对应 SnailJob 任务(`job_status=0`),避免与 `@Scheduled` 双跑。
|
||
|
||
## 通用响应格式
|
||
|
||
### 成功响应
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {} // 响应数据,具体结构取决于不同接口
|
||
}
|
||
```
|
||
|
||
### 分页数据响应
|
||
|
||
```json
|
||
{
|
||
"total": 100, // 总记录数
|
||
"rows": [], // 当前页记录列表
|
||
"code": 200, // 状态码
|
||
"msg": "查询成功" // 提示信息
|
||
}
|
||
```
|
||
|
||
### 错误响应
|
||
|
||
```json
|
||
{
|
||
"code": 500, // 错误码
|
||
"msg": "操作失败", // 错误消息
|
||
"data": null // 通常为空
|
||
}
|
||
```
|
||
|
||
## 认证与授权
|
||
|
||
所有接口均需要在请求头中携带Token进行身份验证:
|
||
|
||
```
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
## 接口清单
|
||
|
||
| 接口路径 | 方法 | 描述 | 权限标识 |
|
||
|---------|-----|------|---------|
|
||
| `/hq/satSurvey/list` | GET | 查询问卷列表 | hq:satSurvey:list |
|
||
| `/hq/satSurvey/{id}` | GET | 获取问卷详情 | hq:satSurvey:query |
|
||
| `/hq/satSurvey` | POST | 新增问卷 | hq:satSurvey:add |
|
||
| `/hq/satSurvey` | PUT | 修改问卷 | hq:satSurvey:edit |
|
||
| `/hq/satSurvey/{ids}` | DELETE | 删除问卷 | hq:satSurvey:remove |
|
||
| `/hq/satSurvey/publish/{id}` | PUT | 发布问卷 | hq:satSurvey:publish |
|
||
| `/hq/satQuestion/list` | GET | 查询题目列表 | hq:satQuestion:list |
|
||
> 📌 **排序策略更新(2025-11-13)**:题目列表在按指定字段排序时,会额外追加 `createTime DESC` 作为最后一位兜底排序,确保返回结果顺序稳定。
|
||
| `/hq/satQuestion/{id}` | GET | 获取题目详情 | hq:satQuestion:query |
|
||
| `/hq/satQuestion` | POST | 新增题目 | hq:satQuestion:add |
|
||
| `/hq/satQuestion` | PUT | 修改题目 | hq:satQuestion:edit |
|
||
| `/hq/satQuestion/{ids}` | DELETE | 删除题目 | hq:satQuestion:remove |
|
||
| **`/hq/satQuestion/{questionId}/options`** | GET | 获取题目的选项列表 | hq:satQuestion:query |
|
||
| **`/hq/satOption/list`** | GET | 查询题目选项列表 | hq:satOption:list |
|
||
| **`/hq/satOption/{id}`** | GET | 获取题目选项详情 | hq:satOption:query |
|
||
| **`/hq/satOption`** | POST | 新增题目选项 | hq:satOption:add |
|
||
| **`/hq/satOption`** | PUT | 修改题目选项 | hq:satOption:edit |
|
||
| **`/hq/satOption/{ids}`** | DELETE | 删除题目选项 | hq:satOption:remove |
|
||
| `/hq/satRecord/list` | GET | 查询答题记录列表 | hq:satRecord:list |
|
||
| `/hq/satRecord/{id}` | GET | 获取答题记录详情 | hq:satRecord:query |
|
||
| `/hq/satSurvey/{id}/statistics` | GET | 获取问卷统计分析 | hq:satSurvey:result |
|
||
| `/hq/satSurvey/{id}/records` | GET | 获取问卷答题记录 | hq:satSurvey:result |
|
||
| `/hq/satSurvey/{id}/exportReport` | POST | 导出调查报告 | hq:satSurvey:export |
|
||
|
||
## API详情
|
||
|
||
### 题目选项管理API
|
||
|
||
#### 1. 查询题目选项列表
|
||
|
||
**请求方式**:GET
|
||
|
||
**请求路径**:`/hq/satOption/list`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| questionId | Long | 否 | 题目ID |
|
||
| pageNum | Integer | 否 | 页码,默认1 |
|
||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /hq/satOption/list?questionId=1937751489358733313&pageNum=1&pageSize=10
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"total": 5,
|
||
"rows": [
|
||
{
|
||
"id": 1937810382736855041,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "非常满意",
|
||
"optionScore": 5,
|
||
"optionOrder": 1,
|
||
"isDefault": "N",
|
||
"tenantId": "000000",
|
||
"createBy": 1,
|
||
"createTime": "2025-06-25 17:50:18",
|
||
"updateBy": 1,
|
||
"updateTime": "2025-06-25 17:50:18",
|
||
"deleted": "0"
|
||
},
|
||
{
|
||
"id": 1937810382736855042,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "满意",
|
||
"optionScore": 4,
|
||
"optionOrder": 2,
|
||
"isDefault": "N",
|
||
"tenantId": "000000",
|
||
"createBy": 1,
|
||
"createTime": "2025-06-25 17:50:18",
|
||
"updateBy": 1,
|
||
"updateTime": "2025-06-25 17:50:18",
|
||
"deleted": "0"
|
||
}
|
||
// ... 更多选项数据
|
||
],
|
||
"code": 200,
|
||
"msg": "查询成功"
|
||
}
|
||
```
|
||
|
||
#### 2. 获取题目的选项列表
|
||
|
||
**请求方式**:GET
|
||
|
||
**请求路径**:`/hq/satQuestion/{questionId}/options`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| questionId | Long | 是 | 题目ID |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /hq/satQuestion/1937751489358733313/options
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": [
|
||
{
|
||
"id": 1937810382736855041,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "非常满意",
|
||
"optionScore": 5,
|
||
"optionOrder": 1,
|
||
"isDefault": "N",
|
||
"tenantId": "000000",
|
||
"createBy": 1,
|
||
"createTime": "2025-06-25 17:50:18",
|
||
"updateBy": 1,
|
||
"updateTime": "2025-06-25 17:50:18",
|
||
"deleted": "0"
|
||
},
|
||
{
|
||
"id": 1937810382736855042,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "满意",
|
||
"optionScore": 4,
|
||
"optionOrder": 2,
|
||
"isDefault": "N",
|
||
"tenantId": "000000",
|
||
"createBy": 1,
|
||
"createTime": "2025-06-25 17:50:18",
|
||
"updateBy": 1,
|
||
"updateTime": "2025-06-25 17:50:18",
|
||
"deleted": "0"
|
||
},
|
||
// ... 更多选项数据
|
||
]
|
||
}
|
||
```
|
||
|
||
**前端使用说明**:
|
||
- 此接口返回指定题目的全部选项,数据结构为数组,不分页
|
||
- **实现变更(2025-07-17):**
|
||
- 接口现在根据questionId参数过滤选项,只返回特定题目的选项数据
|
||
- 返回的选项数据已按照optionOrder字段升序排序,无需前端再次排序
|
||
- 适用于问题选择界面或答题场景,可一次性获取题目所有选项
|
||
- 对于单选题和多选题应显示选项,对于问答题则不需要显示
|
||
|
||
#### 3. 获取题目选项详情
|
||
|
||
**请求方式**:GET
|
||
|
||
**请求路径**:`/hq/satOption/{id}`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| id | Long | 是 | 选项ID |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /hq/satOption/1937810382736855041
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"id": 1937810382736855041,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "非常满意",
|
||
"optionScore": 5,
|
||
"optionOrder": 1,
|
||
"isDefault": "N",
|
||
"tenantId": "000000",
|
||
"createBy": 1,
|
||
"createTime": "2025-06-25 17:50:18",
|
||
"updateBy": 1,
|
||
"updateTime": "2025-06-25 17:50:18",
|
||
"deleted": "0"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4. 新增题目选项
|
||
|
||
**请求方式**:POST
|
||
|
||
**请求路径**:`/hq/satOption`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| questionId | Long | 是 | 题目ID |
|
||
| optionContent | String | 是 | 选项内容 |
|
||
| optionScore | Integer | 否 | 选项分值,默认0 |
|
||
| optionOrder | Integer | 否 | 选项排序,默认0 |
|
||
| isDefault | String | 否 | 是否默认选项(Y是 N否),默认N |
|
||
|
||
**请求示例**:
|
||
```json
|
||
{
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "一般般",
|
||
"optionScore": 3,
|
||
"optionOrder": 3,
|
||
"isDefault": "N"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 5. 修改题目选项
|
||
|
||
**请求方式**:PUT
|
||
|
||
**请求路径**:`/hq/satOption`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| id | Long | 是 | 选项ID |
|
||
| questionId | Long | 是 | 题目ID |
|
||
| optionContent | String | 是 | 选项内容 |
|
||
| optionScore | Integer | 否 | 选项分值 |
|
||
| optionOrder | Integer | 否 | 选项排序 |
|
||
| isDefault | String | 否 | 是否默认选项(Y是 N否) |
|
||
|
||
**请求示例**:
|
||
```json
|
||
{
|
||
"id": 1937810382736855041,
|
||
"questionId": 1937751489358733313,
|
||
"optionContent": "非常满意",
|
||
"optionScore": 5,
|
||
"optionOrder": 1,
|
||
"isDefault": "Y"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 6. 删除题目选项
|
||
|
||
**请求方式**:DELETE
|
||
|
||
**请求路径**:`/hq/satOption/{ids}`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| ids | String | 是 | 选项ID,多个用逗号分隔 |
|
||
|
||
**请求示例**:
|
||
```
|
||
DELETE /hq/satOption/1937810382736855041,1937810382736855042
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 题目选项批量管理
|
||
|
||
虽然当前API不直接支持选项批量操作,但前端可以通过组合使用现有API实现选项的批量管理,步骤如下:
|
||
|
||
1. **加载选项**:使用 `GET /hq/satOption/list?questionId={questionId}` 获取题目当前所有选项
|
||
2. **处理更新**:
|
||
- 对于有ID的选项,调用 `PUT /hq/satOption` 更新内容
|
||
- 对于新增的选项,调用 `POST /hq/satOption` 创建
|
||
- 对比前后选项ID差异,对不存在的选项调用 `DELETE /hq/satOption/{ids}` 删除
|
||
|
||
这种实现方式允许在一次操作中完成多个选项的增删改,但需注意以下几点:
|
||
|
||
- 操作非事务性:多个API调用之间没有事务保证,如遇网络问题可能导致数据部分更新
|
||
- 性能考虑:选项数量大时,多次API调用可能影响性能
|
||
- 字段映射:注意前后端字段命名差异(如 `optionContent` → `optionText`)
|
||
|
||
**示例代码**:
|
||
|
||
```javascript
|
||
// 1. 获取当前题目的所有已有选项
|
||
const res = await listSatOption({ questionId: questionId });
|
||
const existingOptions = res.rows || [];
|
||
|
||
// 2. 处理选项数据
|
||
const promises = [];
|
||
|
||
// 新增或修改选项
|
||
for (const option of options) {
|
||
if (!option.optionContent) continue; // 跳过空选项
|
||
|
||
const params = {
|
||
id: option.id,
|
||
questionId: questionId,
|
||
optionText: option.optionContent,
|
||
optionValue: option.optionScore || 0,
|
||
sortOrder: option.optionOrder || 1,
|
||
status: '0',
|
||
isDefault: option.isDefault || 'N'
|
||
};
|
||
|
||
if (option.id) {
|
||
// 已有选项,执行更新
|
||
promises.push(updateSatOption(params));
|
||
} else {
|
||
// 新选项,执行新增
|
||
promises.push(addSatOption(params));
|
||
}
|
||
}
|
||
|
||
// 删除不再存在的选项
|
||
const currentOptionIds = options.filter(opt => opt.id).map(opt => opt.id);
|
||
const optionsToDelete = existingOptions
|
||
.filter(opt => !currentOptionIds.includes(opt.id))
|
||
.map(opt => opt.id);
|
||
|
||
if (optionsToDelete.length > 0) {
|
||
promises.push(delSatOption(optionsToDelete));
|
||
}
|
||
|
||
// 3. 等待所有操作完成
|
||
await Promise.all(promises);
|
||
```
|
||
|
||
**建议改进**:后续可考虑在后端添加批量操作API,如 `POST /hq/satOption/batch` 以提供事务保证和性能优化。
|
||
|
||
## 数据结构说明
|
||
|
||
### 题目选项表(hq_sat_option)
|
||
|
||
| 字段名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| id | bigint(20) | 是 | 选项ID,主键(雪花ID) |
|
||
| question_id | bigint(20) | 是 | 题目ID,关联题目表 |
|
||
| option_content | varchar(255) | 是 | 选项内容 |
|
||
| option_score | int(11) | 否 | 选项分值,用于计算满意度评分 |
|
||
| option_order | int(11) | 否 | 选项排序,控制前端显示顺序 |
|
||
| is_default | char(1) | 否 | 是否默认选项(Y是 N否) |
|
||
| tenant_id | varchar(20) | 是 | 租户编号 |
|
||
| create_by | bigint(20) | 否 | 创建者 |
|
||
| create_time | datetime | 否 | 创建时间 |
|
||
| update_by | bigint(20) | 否 | 更新者 |
|
||
| update_time | datetime | 否 | 更新时间 |
|
||
| deleted | char(1) | 否 | 删除标志(0代表存在 1代表删除) |
|
||
|
||
## 错误码说明
|
||
|
||
| 错误码 | 描述 | 解决方案 |
|
||
|-------|-----|---------|
|
||
| 200 | 操作成功 | 请求正常处理完毕 |
|
||
| 401 | 认证失败 | 检查用户Token是否正确 |
|
||
| 403 | 权限不足 | 检查用户是否有操作权限 |
|
||
| 404 | 资源不存在 | 检查请求的资源是否存在 |
|
||
| 500 | 系统内部错误 | 联系系统管理员 |
|
||
|
||
## 变更记录
|
||
|
||
| 版本号 | 更新日期 | 更新内容 | 更新人 |
|
||
|-------|---------|---------|-------|
|
||
| 1.0.0 | 2025-07-01 | 初始版本:创建满意度调查API文档 | Cursor |
|
||
| 1.0.0 | 2025-07-01 | 更新题目选项表(hq_sat_option)结构,完善选项管理API | Cursor |
|
||
| 1.0.1 | 2025-07-17 | 优化题目选项获取接口,增强前端题目选项显示功能 | Cursor |
|
||
| 1.0.2 | 2025-07-17 | 修复选项排序值保存后实时更新功能,优化用户体验 | wuzilong |
|
||
| 1.0.3 | 2025-07-17 | 添加选项保存防重复提交机制,解决幂等性控制冲突 | wuzilong |
|
||
| 1.0.4 | 2025-07-18 | 优化问答题文本回答展示功能,提高Vue渲染稳定性 | wuzilong |
|
||
| 1.0.5 | 2025-07-18 | 增强问卷答题记录接口功能,返回答题详情数据 | wuzilong |
|
||
| 1.0.6 | 2025-11-13 | 调整题目列表排序策略,追加创建时间倒序兜底,避免排序不稳定 | Cursor |
|
||
|
||
## 附录
|
||
|
||
### 选项分值计算说明
|
||
|
||
选项分值(option_score)用于计算满意度评分,在统计分析时使用,具体规则如下:
|
||
|
||
1. 单选题:直接使用所选选项的分值作为该题得分
|
||
2. 多选题:将所选所有选项的分值相加作为该题得分
|
||
3. 问答题:不计分,分值为0
|
||
|
||
满意度问卷总分计算方式:
|
||
- 总分(total_score) = 所有题目的得分之和
|
||
- 平均分(avg_score) = 总分 ÷ 有分值的题目数量(不包括问答题)
|
||
|
||
### 问答题文本回答数据结构
|
||
|
||
**统计分析接口中问答题文本回答数据结构**:
|
||
|
||
问卷统计分析接口(`/hq/satSurvey/{id}/statistics`)返回的问答题文本回答数据结构如下:
|
||
|
||
```json
|
||
"textAnswers": [
|
||
{
|
||
"id": 393,
|
||
"answer_text": "用户回答内容示例",
|
||
"text_length": 12,
|
||
"answer_time": "2025-07-18 10:40:35"
|
||
}
|
||
]
|
||
```
|
||
|
||
**字段说明**:
|
||
|
||
| 字段名 | 类型 | 描述 |
|
||
|-------|-----|------|
|
||
| id | Integer | 回答ID,唯一标识 |
|
||
| answer_text | String | 回答文本内容 |
|
||
| text_length | Integer | 文本长度(字符数) |
|
||
| answer_time | String | 回答时间,格式:yyyy-MM-dd HH:mm:ss |
|
||
|
||
**前端使用注意事项**:
|
||
- 在Vue循环渲染textAnswers数组时,应使用answer.id作为key值,而非索引,确保Vue的虚拟DOM正确更新
|
||
- 示例:`<div v-for="(answer, idx) in question.textAnswers.slice(0, 5)" :key="answer.id || idx" class="answer-item">`
|
||
- 2025-07-18修复:解决了文本回答因key不唯一导致的渲染问题,详见`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||
|
||
#### 2025-07-18 接口返回顺序与问答题答案优化
|
||
|
||
- `/hq/satSurvey/record/{recordId}` 接口返回参数调整:
|
||
1. `answers` 数组顺序严格按照问卷题目顺序返回。
|
||
2. `answers.options` 选项数组顺序严格按照题目原始选项顺序返回。
|
||
3. 问答题(`questionType=3`)的 `answerValue` 字段取自 `remark` 字段,真实还原用户填写内容。
|
||
|
||
> 以上调整保证了前端展示与问卷设计一致,提升了数据准确性。
|
||
|
||
### 获取问卷的所有答题记录列表
|
||
|
||
**请求方式**:GET
|
||
|
||
**请求路径**:`/hq/satSurvey/{surveyId}/records`
|
||
|
||
**请求参数**:
|
||
|
||
| 参数名 | 类型 | 必填 | 描述 |
|
||
|-------|-----|------|------|
|
||
| surveyId | Long | 是 | 问卷ID,路径参数 |
|
||
| status | String | 否 | 答题状态(1-已提交,0-未提交) |
|
||
| userName | String | 否 | 用户姓名,模糊查询 |
|
||
| dateRange | String[] | 否 | 日期范围 |
|
||
| pageNum | Integer | 否 | 页码,默认1 |
|
||
| pageSize | Integer | 否 | 每页条数,默认10 |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /hq/satSurvey/1945836064483778562/records?pageNum=1&pageSize=10&surveyId=1945836064483778562
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"data": {
|
||
"total": 5,
|
||
"rows": [
|
||
{
|
||
"user_id": 2008,
|
||
"userName": "智控学院郑十",
|
||
"deptName": "智能控制学院",
|
||
"id": "1946035501017587714",
|
||
"survey_id": "1945836064483778562",
|
||
"submit_time": "2025-07-18 10:33:14",
|
||
"total_score": "24.00",
|
||
"create_time": "2025-07-18 10:33:14",
|
||
"status": "1",
|
||
"duration": 313,
|
||
"startTime": "2025-07-18T10:33:14",
|
||
"endTime": "2025-07-18T10:33:14",
|
||
"answers": [
|
||
{
|
||
"id": 1945836064483778563,
|
||
"questionId": 1945836064483778563,
|
||
"questionTitle": "您对后勤服务总体满意度如何?",
|
||
"questionType": "1",
|
||
"score": 4.0,
|
||
"answerValue": "B",
|
||
"options": [
|
||
{
|
||
"optionId": 1945836064483778569,
|
||
"optionValue": "B",
|
||
"optionText": "满意",
|
||
"isSelected": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 1945836064483778564,
|
||
"questionId": 1945836064483778564,
|
||
"questionTitle": "您认为校园环境有哪些需要改善的地方?",
|
||
"questionType": "2",
|
||
"score": 11.0,
|
||
"answerValue": "A,C,D",
|
||
"options": [
|
||
{
|
||
"optionId": 1945836064483778570,
|
||
"optionValue": "A",
|
||
"optionText": "绿化维护",
|
||
"isSelected": true
|
||
},
|
||
{
|
||
"optionId": 1945836064483778572,
|
||
"optionValue": "C",
|
||
"optionText": "卫生状况",
|
||
"isSelected": true
|
||
},
|
||
{
|
||
"optionId": 1945836064483778573,
|
||
"optionValue": "D",
|
||
"optionText": "基础设施",
|
||
"isSelected": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 1945836064483778565,
|
||
"questionId": 1945836064483778565,
|
||
"questionTitle": "您对校园后勤服务的建议",
|
||
"questionType": "3",
|
||
"score": 0,
|
||
"answerValue": "希望增加自习室的开放时间,目前晚上关门太早"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"user_id": 4,
|
||
"userName": "仅本人 密码666666",
|
||
"deptName": "行政单位",
|
||
"id": null,
|
||
"survey_id": null,
|
||
"submit_time": null,
|
||
"total_score": 0,
|
||
"create_time": null,
|
||
"status": "0",
|
||
"duration": 0
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**特殊说明**:
|
||
1. **功能强化(2025-07-18)**:接口现在返回已提交记录的答题详情(`answers`字段),无需额外请求
|
||
2. 每条记录(已提交状态)包含完整的答题详情数据,包括:
|
||
- 题目信息:`questionId`、`questionTitle`、`questionType`
|
||
- 答案内容:`score`、`answerValue`
|
||
- 选项数据(单选/多选题):`options`数组,包含所有选中的选项
|
||
3. 问题类型(`questionType`):
|
||
- `1`:单选题
|
||
- `2`:多选题
|
||
- `3`:问答题
|
||
4. 未提交的记录(`status="0"`)不包含答题详情
|
||
|
||
**最佳实践**:
|
||
- 前端可直接使用返回的`answers`数据渲染答题详情,无需额外请求
|
||
- 单选题和多选题显示选项,问答题显示文本内容
|
||
|
||
### 相关文件
|
||
|
||
- 数据库表结构:`docs/设计文档/database/hzdyjs_xg.sql`
|
||
- 变更记录:`docs/变更管理/code-adjust-record-2025-07-01-cursor.md`
|
||
- 文本回答展示修复:`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||
- 答题详情功能优化:`docs/变更管理/code-adjust-record-2025-07-18-wuzilong.md`
|
||
|
||
## FAQ 常见问题解答
|
||
|
||
### 1. 问卷答题记录查询报错 "Unknown column 'u.deleted' in 'where clause'"
|
||
|
||
**问题描述**:
|
||
获取问卷答题记录列表时报错:`java.sql.SQLSyntaxErrorException: Unknown column 'u.deleted' in 'where clause'`
|
||
|
||
**原因分析**:
|
||
在SQL查询中使用了 `u.deleted = 0` 条件,但实际上 `sys_user` 表中逻辑删除字段名是 `del_flag` 而非 `deleted`。这是系统表与业务表之间的字段命名差异导致的。
|
||
|
||
**解决方案**:
|
||
修改SQL查询,将 `WHERE u.deleted = 0` 改为 `WHERE u.del_flag = '0'`(注意类型也从数字改为了字符串)。
|
||
|
||
**相关代码**:
|
||
```java
|
||
// 修改前
|
||
sql.append("WHERE u.deleted = 0 ");
|
||
|
||
// 修改后
|
||
sql.append("WHERE u.del_flag = '0' ");
|
||
```
|
||
|
||
**注意事项**:
|
||
- 系统表(如sys_user, sys_role等)使用 `del_flag` 作为逻辑删除字段,类型为char(1)
|
||
- 业务表(如hq_sat_survey等)使用 `deleted` 作为逻辑删除字段,类型为tinyint(1)
|
||
- 在跨表关联查询时,务必注意这一差异,避免类似错误 |