# routers/scene.py 接口测试文档 ## 文件功能概述 该文件提供场景模块相关的接口,包括: - 场景层级查询(场景 → 一级场景 → 二级场景 → 三级场景) - 隐患识别记录的增删查及评价 - 场景模板的创建与列表查询 部分接口需要 Token 认证,部分接口为公开接口。 路由前缀:`/apiv1`(以 `routers/__init__.py` 中注册为准) --- ## 接口列表 --- ### 1. GET `/apiv1/get_scene_list` — 获取场景列表 **功能说明:** 查询所有未删除的场景(顶级分类)。 **是否需要认证:** 否 **请求方式:** GET **请求参数:** 无 **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 场景 ID | | data[].scene_name | string | 场景名称(中文) | | data[].scene_en_name | string | 场景英文名称 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_scene_list // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [ { "id": 1, "scene_name": "隧道施工", "scene_en_name": "tunnel_construction" }, { "id": 2, "scene_name": "桥梁施工", "scene_en_name": "bridge_construction" } ] } ``` #### 用例 2:无场景数据 ```json // 请求 GET /apiv1/get_scene_list // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [] } ``` --- ### 2. GET `/apiv1/get_first_scene_list` — 获取一级场景列表 **功能说明:** 根据场景 ID 查询对应的一级场景列表。 **是否需要认证:** 否 **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | scene_id | int | 是 | 场景 ID | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 一级场景 ID | | data[].first_scene_name | string | 一级场景名称 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_first_scene_list?scene_id=1 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [ {"id": 1, "first_scene_name": "开挖作业"}, {"id": 2, "first_scene_name": "支护作业"} ] } ``` #### 用例 2:scene_id 无匹配数据 ```json // 请求 GET /apiv1/get_first_scene_list?scene_id=999 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [] } ``` #### 用例 3:缺少 scene_id 参数 ```json // 请求 GET /apiv1/get_first_scene_list // 预期响应 (HTTP 422) — FastAPI 参数校验失败 { "detail": [ { "loc": ["query", "scene_id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 3. GET `/apiv1/get_second_scene_list` — 获取二级场景列表 **功能说明:** 根据一级场景 ID 查询对应的二级场景列表。 **是否需要认证:** 否 **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | first_scene_id | int | 是 | 一级场景 ID | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 二级场景 ID | | data[].second_scene_name | string | 二级场景名称 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_second_scene_list?first_scene_id=1 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [ {"id": 1, "second_scene_name": "机械开挖"}, {"id": 2, "second_scene_name": "人工开挖"} ] } ``` #### 用例 2:无匹配数据 ```json // 请求 GET /apiv1/get_second_scene_list?first_scene_id=999 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [] } ``` #### 用例 3:缺少参数 ```json // 请求 GET /apiv1/get_second_scene_list // 预期响应 (HTTP 422) { "detail": [ { "loc": ["query", "first_scene_id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 4. GET `/apiv1/get_third_scene_list` — 获取三级场景列表 **功能说明:** 根据二级场景 ID 查询对应的三级场景列表,包含正确和错误示例图。 **是否需要认证:** 否 **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | second_scene_id | int | 是 | 二级场景 ID | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 三级场景 ID | | data[].third_scene_name | string | 三级场景名称 | | data[].correct_example_image | string | 正确示例图 URL | | data[].wrong_example_image | string | 错误示例图 URL | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_third_scene_list?second_scene_id=1 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [ { "id": 1, "third_scene_name": "未佩戴安全帽", "correct_example_image": "https://oss.example.com/correct_helmet.jpg", "wrong_example_image": "https://oss.example.com/wrong_helmet.jpg" } ] } ``` #### 用例 2:无匹配数据 ```json // 请求 GET /apiv1/get_third_scene_list?second_scene_id=999 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [] } ``` #### 用例 3:缺少参数 ```json // 请求 GET /apiv1/get_third_scene_list // 预期响应 (HTTP 422) { "detail": [ { "loc": ["query", "second_scene_id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 5. GET `/apiv1/get_third_scene_example_image` — 获取三级场景示例图 **功能说明:** 通过三级场景名称查询该场景的正确/错误示例图。 **是否需要认证:** 否 **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | third_scene_name | string | 是 | 三级场景名称 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_third_scene_example_image?third_scene_name=未佩戴安全帽 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "id": 1, "third_scene_name": "未佩戴安全帽", "correct_example_image": "https://oss.example.com/correct_helmet.jpg", "wrong_example_image": "https://oss.example.com/wrong_helmet.jpg" } } ``` #### 用例 2:场景不存在 ```json // 请求 GET /apiv1/get_third_scene_example_image?third_scene_name=不存在的场景 // 预期响应 (HTTP 200, 业务码 404) { "statusCode": 404, "msg": "三级场景不存在" } ``` #### 用例 3:空字符串 ```json // 请求 GET /apiv1/get_third_scene_example_image?third_scene_name= // 预期响应 (HTTP 200, 业务码 400) { "statusCode": 400, "msg": "三级场景名称不能为空" } ``` #### 用例 4:缺少参数 ```json // 请求 GET /apiv1/get_third_scene_example_image // 预期响应 (HTTP 422) — FastAPI 参数校验 { "detail": [ { "loc": ["query", "third_scene_name"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 6. GET `/apiv1/get_history_recognition_record` — 获取隐患识别历史记录 **功能说明:** 查询当前用户的所有隐患识别历史记录,按更新时间倒序排列。返回所有记录(不分页)。 **是否需要认证:** 是 **请求方式:** GET **请求参数:** 无 **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 记录 ID | | data[].title | string | 标题 | | data[].original_image_url | string | 原始图片 URL | | data[].recognition_image_url | string | 识别结果图片 URL | | data[].labels | string | 标签 | | data[].created_at | int | 创建时间(Unix 时间戳) | | total | int | 总记录数 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_history_recognition_record token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [ { "id": 5, "title": "隧道口安全检查", "original_image_url": "https://oss.example.com/original.jpg", "recognition_image_url": "https://oss.example.com/result.jpg", "labels": "未佩戴安全帽,未穿反光衣", "created_at": 1700000000 } ], "total": 1 } ``` #### 用例 2:无记录 ```json // 请求 GET /apiv1/get_history_recognition_record token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": [], "total": 0 } ``` #### 用例 3:未认证 ```json // 请求 GET /apiv1/get_history_recognition_record // 预期响应 (HTTP 200, 业务码 401) { "statusCode": 401, "msg": "未授权" } ``` --- ### 7. GET `/apiv1/get_recognition_record_detail` — 获取识别记录详情 **功能说明:** 通过记录 ID 查询识别记录的完整详情。`description` 字段会按空格分割为 `third_scenes` 数组返回。 > **注意:** 该接口未检查用户认证,任何人可通过 ID 查看。 **是否需要认证:** 否(代码中未做认证校验) **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | recognition_id | int | 是 | 识别记录 ID | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data.id | int | 记录 ID | | data.user_id | int | 用户 ID | | data.title | string | 标题 | | data.description | string | 描述(原始字符串) | | data.original_image_url | string | 原始图片 URL | | data.recognition_image_url | string | 识别结果图片 URL | | data.labels | string | 标签 | | data.third_scenes | array | 三级场景数组(description 按空格分割) | | data.tag_type | string | 标签类型 | | data.scene_match | int/null | 场景匹配评分 | | data.tip_accuracy | int/null | 提示准确度评分 | | data.effect_evaluation | int/null | 效果评价评分 | | data.user_remark | string/null | 用户备注 | | data.created_at | int | 创建时间 | | data.updated_at | int | 更新时间 | **测试用例:** #### 用例 1:正常查询 ```json // 请求 GET /apiv1/get_recognition_record_detail?recognition_id=5 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "id": 5, "user_id": 1, "title": "隧道口安全检查", "description": "未佩戴安全帽 未穿反光衣", "original_image_url": "https://oss.example.com/original.jpg", "recognition_image_url": "https://oss.example.com/result.jpg", "labels": "未佩戴安全帽,未穿反光衣", "third_scenes": ["未佩戴安全帽", "未穿反光衣"], "tag_type": "auto", "scene_match": 5, "tip_accuracy": 4, "effect_evaluation": 3, "user_remark": "检测结果较为准确", "created_at": 1700000000, "updated_at": 1700001000 } } ``` #### 用例 2:记录不存在 ```json // 请求 GET /apiv1/get_recognition_record_detail?recognition_id=99999 // 预期响应 (HTTP 200, 业务码 404) { "statusCode": 404, "msg": "记录不存在" } ``` #### 用例 3:description 为空时 third_scenes 为空数组 ```json // 请求 GET /apiv1/get_recognition_record_detail?recognition_id=3 // 预期响应 (HTTP 200) // 当 record.description 为 None 或空字符串时 { "statusCode": 200, "msg": "success", "data": { "id": 3, "...": "...", "description": null, "third_scenes": [], "...": "..." } } ``` #### 用例 4:缺少参数 ```json // 请求 GET /apiv1/get_recognition_record_detail // 预期响应 (HTTP 422) { "detail": [ { "loc": ["query", "recognition_id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 8. POST `/apiv1/delete_recognition_record` — 删除识别记录(软删除) **功能说明:** 软删除指定的识别记录。设置 `is_deleted=1` 和 `deleted_at` 为当前时间戳。仅能删除当前用户自己的记录。 **是否需要认证:** 是 **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | recognition_id | int | 是 | 识别记录 ID | **业务逻辑:** - 通过 `recognition_id` + `user_id` 条件更新 `is_deleted=1, deleted_at=当前时间戳` - 无论记录是否存在,都返回 200 成功(未做存在性检查) **测试用例:** #### 用例 1:正常删除 ```json // 请求 POST /apiv1/delete_recognition_record token: <有效Token> Content-Type: application/json { "recognition_id": 5 } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "删除成功" } ``` #### 用例 2:记录不存在或非本人记录(仍返回成功) ```json // 请求 POST /apiv1/delete_recognition_record token: <有效Token> Content-Type: application/json { "recognition_id": 99999 } // 预期响应 (HTTP 200) // 注意:代码中未检查 update 影响行数,即使没有匹配记录也返回成功 { "statusCode": 200, "msg": "删除成功" } ``` #### 用例 3:未认证 ```json // 请求 POST /apiv1/delete_recognition_record // 预期响应 (HTTP 200, 业务码 401) { "statusCode": 401, "msg": "未授权" } ``` #### 用例 4:缺少必填字段 ```json // 请求 POST /apiv1/delete_recognition_record token: <有效Token> Content-Type: application/json {} // 预期响应 (HTTP 422) { "detail": [ { "loc": ["body", "recognition_id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 9. POST `/apiv1/submit_evaluation` — 提交点评 **功能说明:** 对识别记录提交评价,可选评分场景匹配度、提示准确度、效果评价和用户备注。仅更新传入的非 None 字段。 > **注意:** 该接口未检查用户认证,任何人可提交评价。 **是否需要认证:** 否(代码中未做认证校验) **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | id | int | 是 | 识别记录 ID | | scene_match | int | 否 | 场景匹配度评分 | | tip_accuracy | int | 否 | 提示准确度评分 | | effect_evaluation | int | 否 | 效果评价评分 | | user_remark | string | 否 | 用户备注 | **业务逻辑:** - 查找 `id` 对应的未删除记录 - 仅更新 `data` 中非 None 的字段 - 同时更新 `updated_at` 为当前时间戳 **测试用例:** #### 用例 1:提交完整评价 ```json // 请求 POST /apiv1/submit_evaluation Content-Type: application/json { "id": 5, "scene_match": 5, "tip_accuracy": 4, "effect_evaluation": 3, "user_remark": "检测较为准确,但有一处漏检" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success" } ``` #### 用例 2:部分评价(仅评分效果) ```json // 请求 POST /apiv1/submit_evaluation Content-Type: application/json { "id": 5, "effect_evaluation": 4 } // 预期响应 (HTTP 200) // 仅 effect_evaluation 和 updated_at 被更新 { "statusCode": 200, "msg": "success" } ``` #### 用例 3:记录不存在 ```json // 请求 POST /apiv1/submit_evaluation Content-Type: application/json { "id": 99999, "scene_match": 5 } // 预期响应 (HTTP 200, 业务码 404) { "statusCode": 404, "msg": "记录不存在" } ``` #### 用例 4:缺少 id 字段 ```json // 请求 POST /apiv1/submit_evaluation Content-Type: application/json { "scene_match": 5 } // 预期响应 (HTTP 422) { "detail": [ { "loc": ["body", "id"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 10. GET `/apiv1/get_latest_recognition_record` — 获取最新识别记录 **功能说明:** 获取当前用户的最新一条识别记录。若无记录,返回一个包含 `effect_evaluation: 1` 的默认数据(给前端使用)。 **是否需要认证:** 是 **请求方式:** GET **请求参数:** 无 **测试用例:** #### 用例 1:有记录 ```json // 请求 GET /apiv1/get_latest_recognition_record token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "id": 10, "title": "最新检测记录", "original_image_url": "https://oss.example.com/original.jpg", "recognition_image_url": "https://oss.example.com/result.jpg", "labels": "未佩戴安全帽", "created_at": 1700005000, "effect_evaluation": 3 } } ``` #### 用例 2:无记录(返回默认数据) ```json // 请求 GET /apiv1/get_latest_recognition_record token: <无任何识别记录的用户Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "effect_evaluation": 1 } } ``` #### 用例 3:未认证 ```json // 请求 GET /apiv1/get_latest_recognition_record // 预期响应 (HTTP 200, 业务码 401) { "statusCode": 401, "msg": "未授权" } ``` --- ### 11. POST `/apiv1/scene_template` — 创建场景模板 **功能说明:** 创建一个新的场景模板记录。 > **注意:** 该接口未检查用户认证。 **是否需要认证:** 否(代码中未做认证校验) **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | scene_name | string | 是 | — | 场景模板名称 | | scene_type | string | 是 | — | 场景类型 | | scene_desc | string | 否 | "" | 场景描述 | | model_name | string | 是 | — | 模型名称 | **业务逻辑:** - 创建 `SceneTemplate` 记录,`created_at` 和 `updated_at` 设为当前时间戳,`is_deleted=0` - 插入后通过 `db.refresh(template)` 获取自增 ID **测试用例:** #### 用例 1:正常创建 ```json // 请求 POST /apiv1/scene_template Content-Type: application/json { "scene_name": "隧道口安全检查", "scene_type": "tunnel", "scene_desc": "用于检测隧道口作业人员的安全装备佩戴情况", "model_name": "yolov8-tunnel" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "创建成功", "data": { "id": 1 } } ``` #### 用例 2:不传 scene_desc(使用默认空字符串) ```json // 请求 POST /apiv1/scene_template Content-Type: application/json { "scene_name": "桥梁检查", "scene_type": "bridge", "model_name": "yolov8-bridge" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "创建成功", "data": { "id": 2 } } ``` #### 用例 3:缺少必填字段 ```json // 请求 POST /apiv1/scene_template Content-Type: application/json { "scene_name": "测试" } // 预期响应 (HTTP 422) { "detail": [ { "loc": ["body", "scene_type"], "msg": "field required", "type": "value_error.missing" }, { "loc": ["body", "model_name"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 12. GET `/apiv1/scene_templates` — 获取场景模板列表 **功能说明:** 分页查询场景模板列表。`page_size` 最大限制为 100。 > **注意:** 该接口未检查用户认证。 **是否需要认证:** 否(代码中未做认证校验) **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | page | int | 否 | 1 | 页码 | | page_size | int | 否 | 20 | 每页条数(最大 100) | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data.total | int | 总记录数 | | data.items[].id | int | 模板 ID | | data.items[].scene_name | string | 场景名称 | | data.items[].scene_type | string | 场景类型 | | data.items[].scene_desc | string | 场景描述 | | data.items[].model_name | string | 模型名称 | | data.items[].created_at | int | 创建时间 | **测试用例:** #### 用例 1:默认分页 ```json // 请求 GET /apiv1/scene_templates // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 5, "items": [ { "id": 5, "scene_name": "隧道口安全检查", "scene_type": "tunnel", "scene_desc": "检测安全装备佩戴情况", "model_name": "yolov8-tunnel", "created_at": 1700005000 } ] } } ``` #### 用例 2:自定义分页 ```json // 请求 GET /apiv1/scene_templates?page=2&page_size=5 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 12, "items": [...] } } ``` #### 用例 3:page_size 超过 100(自动限制为 100) ```json // 请求 GET /apiv1/scene_templates?page=1&page_size=500 // 预期行为:page_size 被限制为 100,最多返回 100 条记录 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 200, "items": [...] // 最多 100 条 } } ``` #### 用例 4:无数据 ```json // 请求 GET /apiv1/scene_templates // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 0, "items": [] } } ``` --- ### 13. GET `/apiv1/recognition_records` — 获取识别记录列表(分页+筛选) **功能说明:** 分页查询当前用户的识别记录,可按场景类型筛选。`page_size` 最大限制为 100。 **是否需要认证:** 是 **请求方式:** GET **请求参数(Query):** | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | scene_type | string | 否 | "" | 场景类型筛选(为空则不筛选) | | page | int | 否 | 1 | 页码 | | page_size | int | 否 | 20 | 每页条数(最大 100) | **成功响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | data.total | int | 总记录数 | | data.items[].id | int | 记录 ID | | data.items[].scene_type | string | 场景类型 | | data.items[].original_image_url | string | 原始图片 URL | | data.items[].result_image_url | string | 识别结果图片 URL | | data.items[].hazard_count | int | 隐患数量 | | data.items[].current_step | string | 当前步骤 | | data.items[].created_at | int | 创建时间 | **测试用例:** #### 用例 1:不带筛选条件 ```json // 请求 GET /apiv1/recognition_records token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 8, "items": [ { "id": 10, "scene_type": "tunnel", "original_image_url": "https://oss.example.com/original.jpg", "result_image_url": "https://oss.example.com/result.jpg", "hazard_count": 3, "current_step": "completed", "created_at": 1700005000 } ] } } ``` #### 用例 2:按场景类型筛选 ```json // 请求 GET /apiv1/recognition_records?scene_type=tunnel&page=1&page_size=10 token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 3, "items": [...] } } ``` #### 用例 3:分页 — 第二页 ```json // 请求 GET /apiv1/recognition_records?page=2&page_size=5 token: <有效Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 12, "items": [...] } } ``` #### 用例 4:page_size 超过 100 ```json // 请求 GET /apiv1/recognition_records?page=1&page_size=200 token: <有效Token> // 预期行为:page_size 被限制为 100 // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 150, "items": [...] // 最多 100 条 } } ``` #### 用例 5:无记录 ```json // 请求 GET /apiv1/recognition_records token: <无识别记录的用户Token> // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "total": 0, "items": [] } } ``` #### 用例 6:未认证 ```json // 请求 GET /apiv1/recognition_records // 预期响应 (HTTP 200, 业务码 401) { "statusCode": 401, "msg": "未授权" } ``` --- ## 依赖说明 | 依赖项 | 说明 | |--------|------| | `database.get_db` | SQLAlchemy 数据库会话(Depends 注入) | | `models.scene.Scene` | 顶级场景模型(字段:id, scene_name, scene_en_name, is_deleted) | | `models.scene.FirstScene` | 一级场景模型(字段:id, scene_id, first_scene_name, is_deleted) | | `models.scene.SecondScene` | 二级场景模型(字段:id, first_scene_id, second_scene_name, is_deleted) | | `models.scene.ThirdScene` | 三级场景模型(字段:id, second_scene_id, third_scene_name, correct_example_image, wrong_example_image, is_deleted) | | `models.scene.RecognitionRecord` | 识别记录模型(字段:id, user_id, title, description, original_image_url, recognition_image_url, labels, tag_type, scene_match, tip_accuracy, effect_evaluation, user_remark, scene_type, hazard_count, current_step, is_deleted, deleted_at, created_at, updated_at) | | `models.scene.SceneTemplate` | 场景模板模型(字段:id, scene_name, scene_type, scene_desc, model_name, is_deleted, created_at, updated_at) | | `request.state.user` | 从中间件注入的用户信息(含 user_id) | ## 代码备注 1. **场景四级层级结构:** Scene → FirstScene → SecondScene → ThirdScene,通过外键逐级关联(scene_id → first_scene_id → second_scene_id)。 2. **场景查询接口均为公开接口**(无需认证),而识别记录相关的增删查需要认证。 3. **`get_recognition_record_detail` 和 `submit_evaluation` 未做用户认证校验,** 任何人可通过 ID 查看或评价记录,存在潜在的数据安全风险。 4. **`delete_recognition_record` 不检查记录是否存在,** 即使 `recognition_id` 无效也返回"删除成功"。 5. **`get_latest_recognition_record` 的降级策略:** 无记录时返回 `{"effect_evaluation": 1}` 作为前端默认值,而非空或 404。 6. **`get_history_recognition_record` 查询全量数据(不分页)**,大量记录时可能存在性能问题。新版接口 `recognition_records` 已支持分页。 7. **`description` 到 `third_scenes` 的转换:** 在 `get_recognition_record_detail` 中按空格分割 `description` 字符串为数组。若 `description` 为 `None`(falsy),则 `third_scenes` 为空数组。 8. **`page_size` 最大值限制:** `scene_templates` 和 `recognition_records` 接口均限制 `page_size` 不超过 100。