diff --git a/.gitignore b/.gitignore index a2f0332..667aaef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -<<<<<<< HEAD HELP.md target/ .mvn/wrapper/maven-wrapper.jar @@ -32,31 +31,3 @@ build/ ### VS Code ### .vscode/ -======= -# ---> Java -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - ->>>>>>> 3012a74fb7c44026907ee929a5832e4986ec7a46 diff --git a/README.md b/README.md deleted file mode 100644 index 2149d25..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# my-springboot-project - diff --git a/bug.txt b/bug.txt index 0d0c680..be20cfb 100644 --- a/bug.txt +++ b/bug.txt @@ -1,78 +1,169 @@ -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8ec4794] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1316742363 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring + + + +Creating a new SqlSession +SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74a5df74] was not registered for synchronization because synchronization is not active +JDBC Connection [HikariProxyConnection@833048452 wrapping com.mysql.cj.jdbc.ConnectionImpl@76ba610e] will not be managed by Spring ==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? ==> Parameters: 1(Long) <== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time <== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 <== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8ec4794] -2026-06-02 10:17:30 - 请求 | URL: http://localhost:8080/api/ai/session/sess_1780387846575_3rnw6o00w | 方法: GET | IP: 127.0.0.1 +Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74a5df74] +2026-06-10 13:44:38 - 请求 | URL: http://localhost:8080/api/exam/grade | 方法: POST | IP: 127.0.0.1 +2026-06-10 13:44:38 - ========== 批阅接口请求开始 ========== +2026-06-10 13:44:38 - 请求完整内容: {"answer_type":"practice","answers":[{"max_score":10.0,"question_content":{"answer":"加强吸烟场所维护的主要目的是确保设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度。","data":{"scoring_points":[{"point":"要点1:确保设施设备良好状态","weight":0.5},{"point":"要点2:保障文明吸烟环境功能发挥","weight":0.3},{"point":"要点3:提高消费者满意度","weight":0.2}]},"stem":"请简述加强吸烟场所维护的主要目的及意义。"},"question_id":"806754e9-3951-4562-8641-553c42564ab8","question_type":"subjective","student_answer":"加强吸烟场所维护可以确保设施良好,提升吸烟环境,让消费者更满意。"}],"request_id":"test_005"} Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4f50dd49] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@845849611 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring +SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@503b434e] was not registered for synchronization because synchronization is not active +JDBC Connection [HikariProxyConnection@437070389 wrapping com.mysql.cj.jdbc.ConnectionImpl@76ba610e] will not be managed by Spring ==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? ==> Parameters: 1(Long) <== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time <== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 <== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4f50dd49] +Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@503b434e] +2026-06-10 13:44:38 - 当前用户ID: 1 +2026-06-10 13:44:38 - 答案数量: 1 +2026-06-10 13:44:38 - 日常练习/模拟考模式,开始验证答案数据... +2026-06-10 13:44:38 - 答案数据验证通过,共1个答案 +2026-06-10 13:44:38 - 空试卷标记: isBlankSubmission=false +2026-06-10 13:44:38 - 自动生成试卷ID: paperId=68b2574e-e68b-486a-b86b-5426ab2e488b +2026-06-10 13:44:38 - 自动生成sessionId: grade_e099f4df +2026-06-10 13:44:38 - ========== 准备调用批阅服务 ========== +2026-06-10 13:44:38 - 批改答案请求参数汇总: +2026-06-10 13:44:38 - - userId: 1 +2026-06-10 13:44:38 - - requestId: test_005 +2026-06-10 13:44:38 - - paperId: 68b2574e-e68b-486a-b86b-5426ab2e488b +2026-06-10 13:44:38 - - sessionId: grade_e099f4df +2026-06-10 13:44:38 - - answerType: practice +2026-06-10 13:44:38 - - answers count: 1 +2026-06-10 13:44:38 - Service层:开始批改题目 +2026-06-10 13:44:38 - Service层参数详情: +2026-06-10 13:44:38 - - userId: 1 +2026-06-10 13:44:38 - - paperId: 68b2574e-e68b-486a-b86b-5426ab2e488b +2026-06-10 13:44:38 - - sessionId: grade_e099f4df +2026-06-10 13:44:38 - - answerType: practice +2026-06-10 13:44:38 - - 答案数量: 1 +2026-06-10 13:44:38 - - AI服务地址: http://localhost:5001/exam/grade +2026-06-10 13:44:38 - Service层:准备发送请求到AI服务 +2026-06-10 13:44:38 - 请求体内容: {"request_id":"test_005","paper_id":"68b2574e-e68b-486a-b86b-5426ab2e488b","session_id":"grade_e099f4df","record_id":null,"answer_type":"practice","answers":[{"question_id":"806754e9-3951-4562-8641-553c42564ab8","question_type":"subjective","question_content":{"stem":"请简述加强吸烟场所维护的主要目的及意义。","data":{"scoring_points":[{"point":"要点1:确保设施设备良好状态","weight":0.5},{"point":"要点2:保障文明吸烟环境功能发挥","weight":0.3},{"point":"要点3:提高消费者满意度","weight":0.2}]},"answer":"加强吸烟场所维护的主要目的是确保设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度。"},"student_answer":"加强吸烟场所维护可以确保设施良好,提升吸烟环境,让消费者更满意。","max_score":10.0}]} +2026-06-10 13:44:38 - 请求超时时间: 60000ms (60秒) +2026-06-10 13:44:41 - Service层:收到AI服务响应 +2026-06-10 13:44:41 - 响应原始内容: {"data":{"request_id":"test_005","results":[{"details":{"highlights":["\u5b66\u751f\u7b54\u6848\u7b80\u6d01\u660e\u4e86\uff0c\u80fd\u591f\u6293\u4f4f\u6838\u5fc3\u8981\u70b9\u3002","\u5bf9\u6d88\u8d39\u8005\u6ee1\u610f\u5ea6\u7684\u8868\u8ff0\u51c6\u786e\u3002"],"overall_feedback":"\u5b66\u751f\u7684\u7b54\u6848\u57fa\u672c\u7b26\u5408\u8981\u6c42\uff0c\u80fd\u591f\u6293\u4f4f\u4e3b\u8981\u89c2\u70b9\uff0c\u4f46\u5728\u90e8\u5206\u8981\u70b9\u7684\u8868\u8fbe\u4e0a\u7565\u663e\u7b80\u7565\uff0c\u5efa\u8bae\u8fdb\u4e00\u6b65\u5b8c\u5584\u8bed\u8a00\u8868\u8ff0\u4ee5\u63d0\u9ad8\u51c6\u786e\u6027\u3002","scoring_breakdown":[{"achieved":0.8,"comment":"\u5b66\u751f\u7b54\u6848\u63d0\u5230\u4e86'\u786e\u4fdd\u8bbe\u65bd\u826f\u597d'\uff0c\u4e0e\u8981\u70b9\u57fa\u672c\u4e00\u81f4\uff0c\u4f46\u672a\u660e\u786e\u63d0\u5230'\u8bbe\u65bd\u8bbe\u5907'\u7684\u5b8c\u6574\u8868\u8ff0\u3002","point":"\u8981\u70b91\uff1a\u786e\u4fdd\u8bbe\u65bd\u8bbe\u5907\u826f\u597d\u72b6\u6001","weight":0.5},{"achieved":0.6,"comment":"\u5b66\u751f\u7b54\u6848\u63d0\u5230'\u63d0\u5347\u5438\u70df\u73af\u5883'\uff0c\u4f46\u672a\u76f4\u63a5\u4f53\u73b0'\u4fdd\u969c\u6587\u660e\u5438\u70df\u73af\u5883\u529f\u80fd\u53d1\u6325'\u7684\u6838\u5fc3\u5185\u5bb9\u3002","point":"\u8981\u70b92\uff1a\u4fdd\u969c\u6587\u660e\u5438\u70df\u73af\u5883\u529f\u80fd\u53d1\u6325","weight":0.3},{"achieved":1.0,"comment":"\u5b66\u751f\u7b54\u6848\u660e\u786e\u63d0\u5230'\u8ba9\u6d88\u8d39\u8005\u66f4\u6ee1\u610f'\uff0c\u4e0e\u8981\u70b9\u5b8c\u5168\u4e00\u81f4\u3002","point":"\u8981\u70b93\uff1a\u63d0\u9ad8\u6d88\u8d39\u8005\u6ee1\u610f\u5ea6","weight":0.2}],"shortcomings":["\u672a\u660e\u786e\u63d0\u53ca'\u8bbe\u65bd\u8bbe\u5907'\u7684\u5b8c\u6574\u8868\u8ff0\u3002","\u5bf9'\u6587\u660e\u5438\u70df\u73af\u5883\u529f\u80fd\u53d1\u6325'\u7684\u7406\u89e3\u4e0d\u591f\u6df1\u5165\u3002"]},"max_score":10.0,"question_id":"806754e9-3951-4562-8641-553c42564ab8","score":8.0}],"score_rate":80.0,"success":true,"total_max_score":10.0,"total_score":8.0},"message":"\u6279\u9605\u5b8c\u6210","status":"success","status_code":2021,"success":true} + +2026-06-10 13:44:41 - 开始解析 1 道题 +2026-06-10 13:44:41 - 第 1 题 resultNode 内容: {"details":{"highlights":["学生答案简洁明了,能够抓住核心要点。","对消费者满意度的表述准确。"],"overall_feedback":"学生的答案基本符合要求,能够抓住主要观点,但在部分要点的表达上略显简略,建议进一步完善语言表述以提高准确性。","scoring_breakdown":[{"achieved":0.8,"comment":"学生答案提到了'确保设施良好',与要点基本一致,但未明确提到'设施设备'的完整表述。","point":"要点1:确保设施设备良好状态","weight":0.5},{"achieved":0.6,"comment":"学生答案提到'提升吸烟环境',但未直接体现'保障文明吸烟环境功能发挥'的核心内容。","point":"要点2:保障文明吸烟环境功能发挥","weight":0.3},{"achieved":1.0,"comment":"学生答案明确提到'让消费者更满意',与要点完全一致。","point":"要点3:提高消费者满意度","weight":0.2}],"shortcomings":["未明确提及'设施设备'的完整表述。","对'文明吸烟环境功能发挥'的理解不够深入。"]},"max_score":10.0,"question_id":"806754e9-3951-4562-8641-553c42564ab8","score":8.0} +2026-06-10 13:44:41 - resultNode 字段: , 10.0, 806754e9-3951-4562-8641-553c42564ab8, 8.0 +2026-06-10 13:44:41 - 读取到 question_id: 806754e9-3951-4562-8641-553c42564ab8 +2026-06-10 13:44:41 - 已解析 details 结构 +2026-06-10 13:44:41 - 从请求中补全 question_type: subjective +2026-06-10 13:44:41 - 处理第 1 题, 类型: subjective, grading_status: null +2026-06-10 13:44:41 - 检测到主观题,手动解析 details +2026-06-10 13:44:41 - 主观题 feedback 已设置,长度: 408 +2026-06-10 13:44:41 - Service层:AI服务批改完成 +2026-06-10 13:44:41 - 批改结果: success=true, totalScore=8.0, totalMaxScore=10.0, scoreRate=80.0 +2026-06-10 13:44:41 - 各题目批改结果: +2026-06-10 13:44:41 - 题目1(806754e9-3951-4562-8641-553c42564ab8): correct=null, score=8.0/10.0, feedback=【亮点】 +1. 学生答案简洁明了,能够抓住核心要点。 +2. 对消费者满意度的表述准确。 +【综合评价】 +学生的答案基本符合要求,能够抓住主要观点,但在部分要点的表达上略显简略,建议进一步完善语言表述以提高准确性。 +【评分详情】 +- 要点1:确保设施设备良好状态 (权重: 50%, 得分率: 80%) + 评价: 学生答案提到了'确保设施良好',与要点基本一致,但未明确提到'设施设备'的完整表述。 +- 要点2:保障文明吸烟环境功能发挥 (权重: 30%, 得分率: 60%) + 评价: 学生答案提到'提升吸烟环境',但未直接体现'保障文明吸烟环境功能发挥'的核心内容。 +- 要点3:提高消费者满意度 (权重: 20%, 得分率: 100%) + 评价: 学生答案明确提到'让消费者更满意',与要点完全一致。 +【可改进之处】 +1. 未明确提及'设施设备'的完整表述。 +2. 对'文明吸烟环境功能发挥'的理解不够深入。 +2026-06-10 13:44:41 - ========== 批阅成功 ========== +2026-06-10 13:44:41 - 批阅结果: totalScore=8.0, totalMaxScore=10.0, scoreRate=80.0% +2026-06-10 13:44:41 - 开始批量保存答题记录: count=1 Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@9e498f7] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1083680279 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (user_id = ?) ORDER BY create_time DESC -==> Parameters: 1(Long) -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 62, sess_1780387846575_3rnw6o00w, 1, <>, 2026-06-02 08:10:46 -<== Row: 61, sess_1780386659498_e2i0pli3t, 1, <>, 2026-06-02 07:50:59 -<== Row: 60, sess_1780385074333_3ektq0vgx, 1, <>, 2026-06-02 07:24:34 -<== Row: 59, sess_1780379728867_z5d8v05yp, 1, <>, 2026-06-02 05:55:28 -<== Total: 4 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@9e498f7] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5287e229] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@2131360686 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (session_id = ?) -==> Parameters: sess_1780387846575_3rnw6o00w(String) -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 62, sess_1780387846575_3rnw6o00w, 1, <>, 2026-06-02 08:10:46 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5287e229] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75d9a876] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@413309518 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring -==> Preparing: SELECT id,conversation_id,role,content,message_type,is_finished,summary,kb_paths,answer,mode,duration_ms,images,sources,create_time FROM context_message WHERE (conversation_id = ?) ORDER BY create_time ASC -==> Parameters: 62(Long) -<== Columns: id, conversation_id, role, content, message_type, is_finished, summary, kb_paths, answer, mode, duration_ms, images, sources, create_time -<== Row: 170, 62, assistant, <>, rag, 1, <>, <>, <>, null, 150685, <>, <>, 2026-06-02 08:13:17 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75d9a876] -2026-06-02 10:17:30 - 获取图片: imageId=0cb2b4cd0ca4407a3fc0360f318c16b2 -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@22e0ae58] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1397047197 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring -==> Preparing: SELECT id,image_id,filename,path,size_bytes,format,source,page,page_end,page_range,section,chunk_type,type,description,full_description,score,collection,create_time FROM context_image WHERE (image_id = ?) -==> Parameters: 0cb2b4cd0ca4407a3fc0360f318c16b2(String) +Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] +JDBC Connection [HikariProxyConnection@305915904 wrapping com.mysql.cj.jdbc.ConnectionImpl@76ba610e] will be managed by Spring +==> Preparing: SELECT id,user_id,question_id,question_type,answer_type,paper_id,session_id,user_answer,score,max_score,is_correct,grading_type,feedback,time_spent,paper_time_spent,created_at,updated_at FROM user_answer WHERE (user_id = ? AND question_id = ? AND paper_id = ? AND answer_type = ?) +==> Parameters: 1(Long), 806754e9-3951-4562-8641-553c42564ab8(String), 68b2574e-e68b-486a-b86b-5426ab2e488b(String), practice(String) <== Total: 0 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@22e0ae58] -2026-06-02 10:17:30 - 调用RAG服务获取图片: url=http://localhost:5001/images/0cb2b4cd0ca4407a3fc0360f318c16b2 -2026-06-02 10:17:30 - RAG服务响应状态码: 404 -2026-06-02 10:17:30 - RAG服务错误响应内容: {"error":"\u56fe\u7247\u4e0d\u5b58\u5728","image_id":"0cb2b4cd0ca4407a3fc0360f318c16b2"} -2026-06-02 10:17:30 - 调用RAG服务获取图片失败: 调用RAG服务失败: RAG服务返回错误状态码: 404, 错误信息: {"error":"\u56fe\u7247\u4e0d\u5b58\u5728","image_id":"0cb2b4cd0ca4407a3fc0360f318c16b2"} -java.io.IOException: 调用RAG服务失败: RAG服务返回错误状态码: 404, 错误信息: {"error":"\u56fe\u7247\u4e0d\u5b58\u5728","image_id":"0cb2b4cd0ca4407a3fc0360f318c16b2"} - at top.tqx.demo_1.service.RagService.getBinaryRequest(RagService.java:202) - at top.tqx.demo_1.service.impl.ImageServiceImpl.getImage(ImageServiceImpl.java:165) - at top.tqx.demo_1.service.impl.ChatServiceImpl.findLocalImageUrl(ChatServiceImpl.java:261) - at top.tqx.demo_1.service.impl.ChatServiceImpl.processImageUrls(ChatServiceImpl.java:235) - at top.tqx.demo_1.service.impl.ChatServiceImpl.getSessionMessages(ChatServiceImpl.java:205) +Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] +Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] from current transaction +==> Preparing: INSERT INTO user_answer ( user_id, question_id, question_type, answer_type, paper_id, session_id, user_answer, score, max_score, is_correct, grading_type, feedback, created_at, updated_at ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) +==> Parameters: 1(Long), 806754e9-3951-4562-8641-553c42564ab8(String), subjective(String), practice(String), 68b2574e-e68b-486a-b86b-5426ab2e488b(String), grade_e099f4df(String), "加强吸烟场所维护可以确保设施良好,提升吸烟环境,让消费者更满意。"(String), 8.0(BigDecimal), 10.0(BigDecimal), 0(Integer), ai(String), 【亮点】 +1. 学生答案简洁明了,能够抓住核心要点。 +2. 对消费者满意度的表述准确。 +【综合评价】 +学生的答案基本符合要求,能够抓住主要观点,但在部分要点的表达上略显简略,建议进一步完善语言表述以提高准确性。 +【评分详情】 +- 要点1:确保设施设备良好状态 (权重: 50%, 得分率: 80%) + 评价: 学生答案提到了'确保设施良好',与要点基本一致,但未明确提到'设施设备'的完整表述。 +- 要点2:保障文明吸烟环境功能发挥 (权重: 30%, 得分率: 60%) + 评价: 学生答案提到'提升吸烟环境',但未直接体现'保障文明吸烟环境功能发挥'的核心内容。 +- 要点3:提高消费者满意度 (权重: 20%, 得分率: 100%) + 评价: 学生答案明确提到'让消费者更满意',与要点完全一致。 +【可改进之处】 +1. 未明确提及'设施设备'的完整表述。 +2. 对'文明吸烟环境功能发挥'的理解不够深入。(String), 2026-06-10T13:44:41.140192733(LocalDateTime), 2026-06-10T13:44:41.140943974(LocalDateTime) +Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] +Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] +Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70586209] +2026-06-10 13:44:41 - ========== 批改答案发生未知异常 ========== +2026-06-10 13:44:41 - 错误类型: org.springframework.dao.DataIntegrityViolationException +2026-06-10 13:44:41 - 错误信息: +### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) +### The error may exist in top/tqx/demo_1/mapper/UserAnswerMapper.java (best guess) +### The error may involve top.tqx.demo_1.mapper.UserAnswerMapper.insert-Inline +### The error occurred while setting parameters +### SQL: INSERT INTO user_answer ( user_id, question_id, question_type, answer_type, paper_id, session_id, user_answer, score, max_score, is_correct, grading_type, feedback, created_at, updated_at ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) +### Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) +; Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) +2026-06-10 13:44:41 - 可能的错误位置: +2026-06-10 13:44:41 - at top.tqx.demo_1.service.impl.UserAnswerServiceImpl.batchSaveAnswers:UserAnswerServiceImpl.java (行号: 98) +2026-06-10 13:44:41 - at top.tqx.demo_1.service.impl.UserAnswerServiceImpl$$SpringCGLIB$$0.batchSaveAnswers: (行号: -1) +2026-06-10 13:44:41 - at top.tqx.demo_1.controller.ExamController.saveUserAnswers:ExamController.java (行号: 583) +2026-06-10 13:44:41 - at top.tqx.demo_1.controller.ExamController.gradeAnswers:ExamController.java (行号: 416) +2026-06-10 13:44:41 - at top.tqx.demo_1.aspect.LogAspect.around:LogAspect.java (行号: 43) +2026-06-10 13:44:41 - at top.tqx.demo_1.controller.ExamController$$SpringCGLIB$$0.gradeAnswers: (行号: -1) +2026-06-10 13:44:41 - 完整堆栈: +org.springframework.dao.DataIntegrityViolationException: +### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) +### The error may exist in top/tqx/demo_1/mapper/UserAnswerMapper.java (best guess) +### The error may involve top.tqx.demo_1.mapper.UserAnswerMapper.insert-Inline +### The error occurred while setting parameters +### SQL: INSERT INTO user_answer ( user_id, question_id, question_type, answer_type, paper_id, session_id, user_answer, score, max_score, is_correct, grading_type, feedback, created_at, updated_at ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) +### Cause: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) +; Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) + at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:258) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439) + at jdk.proxy2/jdk.proxy2.$Proxy87.insert(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:59) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy107.insert(Unknown Source) + at top.tqx.demo_1.service.impl.UserAnswerServiceImpl.batchSaveAnswers(UserAnswerServiceImpl.java:98) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:716) - at top.tqx.demo_1.service.impl.ChatServiceImpl$$SpringCGLIB$$0.getSessionMessages() - at top.tqx.demo_1.controller.AIChatController.getSessionDetail(AIChatController.java:227) - at jdk.internal.reflect.GeneratedMethodAccessor332.invoke(Unknown Source) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) + at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) + at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:392) + at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720) + at top.tqx.demo_1.service.impl.UserAnswerServiceImpl$$SpringCGLIB$$0.batchSaveAnswers() + at top.tqx.demo_1.controller.ExamController.saveUserAnswers(ExamController.java:583) + at top.tqx.demo_1.controller.ExamController.gradeAnswers(ExamController.java:416) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354) @@ -81,7 +172,8 @@ java.io.IOException: 调用RAG服务失败: RAG服务返回错误状态码: 404, at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) at top.tqx.demo_1.aspect.LogAspect.around(LogAspect.java:43) - at jdk.internal.reflect.GeneratedMethodAccessor157.invoke(Unknown Source) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:637) @@ -93,7 +185,7 @@ java.io.IOException: 调用RAG服务失败: RAG服务返回错误状态码: 404, at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720) - at top.tqx.demo_1.controller.AIChatController$$SpringCGLIB$$0.getSessionDetail() + at top.tqx.demo_1.controller.ExamController$$SpringCGLIB$$0.gradeAnswers() at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) @@ -107,8 +199,8 @@ java.io.IOException: 调用RAG服务失败: RAG服务返回错误状态码: 404, at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) - at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) - at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:206) @@ -148,467 +240,43 @@ java.io.IOException: 调用RAG服务失败: RAG服务返回错误状态码: 404, at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) at java.base/java.lang.Thread.run(Unknown Source) -Caused by: java.io.IOException: RAG服务返回错误状态码: 404, 错误信息: {"error":"\u56fe\u7247\u4e0d\u5b58\u5728","image_id":"0cb2b4cd0ca4407a3fc0360f318c16b2"} - at top.tqx.demo_1.service.RagService.getBinaryRequest(RagService.java:190) - ... 88 common frames omitted -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@80c5035] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@125775329 wrapping com.mysql.cj.jdbc.ConnectionImpl@5ae44be2] will not be managed by Spring -==> Preparing: SELECT id,message_id,chunk_id,doc_path,doc_name,page,page_end,page_range,section,chunk_type,doc_type,section_chunk_id,excerpt,preview,bbox,bbox_mode,score,create_time FROM context_reference WHERE (message_id = ?) -==> Parameters: 170(Long) -<== Columns: id, message_id, chunk_id, doc_path, doc_name, page, page_end, page_range, section, chunk_type, doc_type, section_chunk_id, excerpt, preview, bbox, bbox_mode, score, create_time -<== Row: 355, 170, , null, 1.docx, 1, 1, 1, 2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。, text, other, null, <>, <>, null, null, 0.9960, 2026-06-02 08:13:17 -<== Row: 356, 170, , null, 1.txt, 9, 9, 9, , text, other, null, <>, <>, null, null, 0.0040, 2026-06-02 08:13:17 -<== Row: 357, 170, , null, 货源投放工作规范.docx, 1, 1, 1, 2.指标值与权重确定。 > ①指标值的确定:, text, other, null, <>, <>, null, null, 0.9400, 2026-06-02 08:13:17 -<== Row: 358, 170, , null, 需求分析.docx, 1, 1, 1, 需求分析, text, other, null, <>, <>, null, null, 0.9820, 2026-06-02 08:13:17 -<== Row: 359, 170, , null, 3.docx, 1, 1, 1, 第五篇 投入管理 > **第三章 投入标准**, text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 08:13:17 -<== Row: 360, 170, , null, test.docx, 1, 1, 1, 第五条 管理人员负责日常监督检查,定期核查登记台账、系统上传记录,对漏登、错登、代登等问题及时整改追责。, text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 08:13:17 -<== Row: 361, 170, , null, longrule.docx, 1, 1, 1, , text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 08:13:17 -<== Row: 362, 170, , null, 2.docx, 1, 1, 1, 第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市, table, other, null, <>, <>, null, null, 1.0000, 2026-06-02 08:13:17 -<== Row: 363, 170, 1.docx_62, null, 1.docx, 1, 1, null, 3.按价位段自选投放工作指引 > **3.终端动销率公式。**, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 364, 170, 1.docx_94, null, 1.docx, 1, 1, null, 3.状态评价办法与标准。 > 备注:, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 365, 170, 1.docx_22, null, 1.docx, 1, 1, null, 6.坚持区域协同、高效运作。 > **3.市场状态指标:**, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 366, 170, 1.docx_80, null, 1.docx, 1, 1, null, 1.市场状态的计算公式为: > 市场状态=+二级指标均值\*权重, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 367, 170, 1.docx_90, null, 1.docx, 1, 1, null, 3.状态评价办法与标准。 > **(二)品规属性聚类评价**, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 368, 170, 1.docx_56, null, 1.docx, 1, 1, null, 3.按价位段自选投放工作指引 > **\*\*市场状态评价指标体系**, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Row: 369, 170, 1.docx_79, null, 1.docx, 1, 1, null, 1.市场状态的计算公式为:, null, other, 0, <>, <>, null, null, null, 2026-06-02 08:13:17 -<== Total: 15 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@80c5035] -2026-06-02 10:17:30 - 响应 | 耗时: 137ms - - - - - - - - - - -curl -X GET "http://localhost:8080/api/ai/session/sess_1780387846575_3rnw6o00w" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDM5NjI1OCwiZXhwIjoxNzgwNDAzNDU4fQ.Lxp1TpJKG1mVsIidkuhhPsgxrMH1nxhoBlJfcm4Q3M6zB_fqoCknzCeIGTIHcm0NFayxeMnrjRUBb4mL0l-wiA" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Connecting to 47.116.16.222:22... -Connection established. -To escape to local shell, press 'Ctrl+Alt+]'. - -Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-142-generic x86_64) - - * Documentation: https://help.ubuntu.com - * Management: https://landscape.canonical.com - * Support: https://ubuntu.com/pro - - System information as of Tue Jun 2 10:36:27 PM CST 2026 - - System load: 0.1 Processes: 157 - Usage of /: 49.3% of 68.53GB Users logged in: 1 - Memory usage: 47% IPv4 address for eth0: 172.24.53.43 - Swap usage: 0% - - * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s - just raised the bar for easy, resilient and secure K8s cluster deployment. - - https://ubuntu.com/engage/secure-kubernetes-at-the-edge - -Expanded Security Maintenance for Applications is not enabled. - -5 updates can be applied immediately. -To see these additional updates run: apt list --upgradable - -6 additional security updates can be applied with ESM Apps. -Learn more about enabling ESM Apps service at https://ubuntu.com/esm - -New release '24.04.4 LTS' available. -Run 'do-release-upgrade' to upgrade to it. - - -1 updates could not be installed automatically. For more details, -see /var/log/unattended-upgrades/unattended-upgrades.log - -*** System restart required *** - -Welcome to Alibaba Cloud Elastic Compute Service ! - -Last login: Tue Jun 2 21:25:58 2026 from 112.2.253.193 -root@iZuf69tvv5un8t8r0jvzn0Z:~# docker logs -f --tail 300 demo-app -<== Row: 69, 1.docx, resources/rule/总公司/1/v2/1.docx, 483352, application/vnd.openxmlformats-officedocument.word, .docx, null, 1, 1, <>, 1, rule, null, 1, 1, dept_1_kb/1.docx, 2026-06-02 14:05:52, 2026-06-02 14:14:10, INDEXED, <>, GENERATED, EXAM_GENERATED, 题目生成完成 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e7d3373] -2026-06-02 14:34:23 - 响应 | 耗时: 38ms -<== Total: 3 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e56456d] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b7053c7] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@63894377 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b7053c7] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4599b09e] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@481181057 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,dept_name,dept_code,parent_id,dept_level,dept_type,manager_id,status,sort_order,remark,create_time,update_time FROM department WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, dept_name, dept_code, parent_id, dept_level, dept_type, manager_id, status, sort_order, remark, create_time, update_time -<== Row: 1, 总公司, HEADQUARTERS_MAIN, 0, 1, HEADQUARTERS, null, 1, 0, 集团总公司, 2026-04-27 09:22:57, 2026-04-27 09:36:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4599b09e] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@798e5451] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1897596606 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@798e5451] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@aab1589] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@26014801 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,dept_name,dept_code,parent_id,dept_level,dept_type,manager_id,status,sort_order,remark,create_time,update_time FROM department WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, dept_name, dept_code, parent_id, dept_level, dept_type, manager_id, status, sort_order, remark, create_time, update_time -<== Row: 1, 总公司, HEADQUARTERS_MAIN, 0, 1, HEADQUARTERS, null, 1, 0, 集团总公司, 2026-04-27 09:22:57, 2026-04-27 09:36:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@aab1589] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17f9c337] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1160551196 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17f9c337] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@527fc3bc] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@189153983 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,dept_name,dept_code,parent_id,dept_level,dept_type,manager_id,status,sort_order,remark,create_time,update_time FROM department WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, dept_name, dept_code, parent_id, dept_level, dept_type, manager_id, status, sort_order, remark, create_time, update_time -<== Row: 1, 总公司, HEADQUARTERS_MAIN, 0, 1, HEADQUARTERS, null, 1, 0, 集团总公司, 2026-04-27 09:22:57, 2026-04-27 09:36:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@527fc3bc] -2026-06-02 14:34:23 - 响应 | 耗时: 58ms -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@59499ce7] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1326040202 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@59499ce7] -2026-06-02 14:34:23 - 请求 | URL: http://47.116.16.222/api/ai/sessions | 方法: GET | IP: 112.2.253.199 -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@725fe044] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1743053900 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@725fe044] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ce76c9d] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@20443269 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (user_id = ?) ORDER BY create_time DESC -==> Parameters: 1(Long) -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 65, sess_1780410472658_9qg9a9hhp, 1, <>, 2026-06-02 14:27:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ce76c9d] -2026-06-02 14:34:23 - 响应 | 耗时: 5ms -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7cbe5b14] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@156517454 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7cbe5b14] -2026-06-02 14:34:23 - 请求 | URL: http://47.116.16.222/api/user/1 | 方法: GET | IP: 112.2.253.199 -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@899bce8] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@108081172 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@899bce8] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4daedb18] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@143999161 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,dept_name,dept_code,parent_id,dept_level,dept_type,manager_id,status,sort_order,remark,create_time,update_time FROM department WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, dept_name, dept_code, parent_id, dept_level, dept_type, manager_id, status, sort_order, remark, create_time, update_time -<== Row: 1, 总公司, HEADQUARTERS_MAIN, 0, 1, HEADQUARTERS, null, 1, 0, 集团总公司, 2026-04-27 09:22:57, 2026-04-27 09:36:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4daedb18] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@491cfb00] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1926340384 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT r.* FROM role r INNER JOIN user_role ur ON r.id = ur.role_id WHERE ur.user_id = ? -==> Parameters: 1(Long) -<== Columns: id, uuid, role_name, role_code, role_type, description, status, sort_order, create_time, update_time -<== Row: 1, dad50ea8-392f-11f1-8d4f-7cb566b7fb8c, 系统管理员, admin, 1, 系统管理员,拥有所有权限, 1, 1, 2026-04-16 09:01:52, 2026-04-16 09:01:52 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@491cfb00] -2026-06-02 14:34:23 - 响应 | 耗时: 5ms -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c882f2c] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@293497846 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c882f2c] -2026-06-02 14:34:23 - 请求 | URL: http://47.116.16.222/api/ai/session/sess_1780410472658_9qg9a9hhp | 方法: GET | IP: 112.2.253.199 -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@39ce6e88] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1684195282 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@39ce6e88] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4e0779c2] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@74966180 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (user_id = ?) ORDER BY create_time DESC -==> Parameters: 1(Long) -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c750e8f] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1797211410 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 65, sess_1780410472658_9qg9a9hhp, 1, <>, 2026-06-02 14:27:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4e0779c2] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@797c62be] was not registered for synchronization because synchronization is not active -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -JDBC Connection [HikariProxyConnection@213966138 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (session_id = ?) -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -==> Parameters: sess_1780410472658_9qg9a9hhp(String) -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c750e8f] -2026-06-02 14:34:23 - 请求 | URL: http://47.116.16.222/api/ai/session/sess_1780410472658_9qg9a9hhp | 方法: GET | IP: 112.2.253.199 -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 65, sess_1780410472658_9qg9a9hhp, 1, <>, 2026-06-02 14:27:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@797c62be] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e34ef1f] was not registered for synchronization because synchronization is not active -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32a8cb9a] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1986902582 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,username,password,real_name,email,phone,avatar,user_type,status,dept_id,last_login_time,create_time,update_time FROM user WHERE id=? -==> Parameters: 1(Long) -JDBC Connection [HikariProxyConnection@340202997 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,conversation_id,role,content,message_type,is_finished,summary,kb_paths,answer,mode,duration_ms,images,sources,create_time FROM context_message WHERE (conversation_id = ?) ORDER BY create_time ASC -==> Parameters: 65(Long) -<== Columns: id, username, password, real_name, email, phone, avatar, user_type, status, dept_id, last_login_time, create_time, update_time -<== Row: 1, admin, $2a$10$o/mdlaGbhm7Fm0yrYFGICODFyqYUu/cd9Nj1xzc/qD9r3ukNZQr8W, 系统管理员, admin@system.com, 13800000000, null, 1, 1, 1, null, 2026-04-16 09:05:15, 2026-05-10 19:08:59 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32a8cb9a] -<== Columns: id, conversation_id, role, content, message_type, is_finished, summary, kb_paths, answer, mode, duration_ms, images, sources, create_time -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@267a41] was not registered for synchronization because synchronization is not active -<== Row: 175, 65, assistant, <>, rag, 1, <>, <>, <>, null, 75512, <>, <>, 2026-06-02 14:29:09 -<== Row: 176, 65, assistant, <>, rag, 1, <>, <>, <>, null, 97190, <>, <>, 2026-06-02 14:32:03 -<== Total: 2 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e34ef1f] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6366151e] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1957074372 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (user_id = ?) ORDER BY create_time DESC -==> Parameters: 1(Long) -JDBC Connection [HikariProxyConnection@1250116218 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,message_id,chunk_id,doc_path,doc_name,page,page_end,page_range,section,chunk_type,doc_type,section_chunk_id,excerpt,preview,bbox,bbox_mode,score,create_time FROM context_reference WHERE (message_id = ?) -==> Parameters: 175(Long) -<== Columns: id, message_id, chunk_id, doc_path, doc_name, page, page_end, page_range, section, chunk_type, doc_type, section_chunk_id, excerpt, preview, bbox, bbox_mode, score, create_time -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 65, sess_1780410472658_9qg9a9hhp, 1, <>, 2026-06-02 14:27:53 -<== Row: 393, 175, , null, 1.docx, 1, 1, 1, 1.市场状态的计算公式为:, image, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@267a41] -<== Row: 394, 175, , null, 3.docx, 1, 1, 1, 第六章 附则 > (不公开), text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -<== Row: 395, 175, , null, 2.docx, 1, 1, 1, 4.终端类型维护 > **(一)运营指导**, text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -Creating a new SqlSession -<== Row: 396, 175, , null, test.docx, 1, 1, 1, \## 第一章 总则, text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 14:29:09 -<== Row: 397, 175, 1.docx_24, null, 1.docx, 1, 1, null, 6.坚持区域协同、高效运作。 > **(一)统一货源投放周期**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:29:09 -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@52466c06] was not registered for synchronization because synchronization is not active -<== Total: 5 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6366151e] -JDBC Connection [HikariProxyConnection@1635905661 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,session_id,user_id,summary,create_time FROM context_conversation WHERE (session_id = ?) -==> Parameters: sess_1780410472658_9qg9a9hhp(String) -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@59860f83] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@169553736 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,image_id,filename,path,size_bytes,format,source,page,page_end,page_range,section,chunk_type,type,description,full_description,score,collection,create_time FROM context_image WHERE (image_id = ?) -==> Parameters: 49d2910b148d.jpg(String) -<== Columns: id, session_id, user_id, summary, create_time -<== Row: 65, sess_1780410472658_9qg9a9hhp, 1, <>, 2026-06-02 14:27:53 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@52466c06] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47c5e224] was not registered for synchronization because synchronization is not active -<== Columns: id, image_id, filename, path, size_bytes, format, source, page, page_end, page_range, section, chunk_type, type, description, full_description, score, collection, create_time -<== Row: 7, 49d2910b148d.jpg, null, img/49d2910b148d.jpg, 3004, JPEG, 1.docx, 1, null, null, null, null, image, <>, <>, 10.9000, null, 2026-06-02 14:32:03 -JDBC Connection [HikariProxyConnection@637702278 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,conversation_id,role,content,message_type,is_finished,summary,kb_paths,answer,mode,duration_ms,images,sources,create_time FROM context_message WHERE (conversation_id = ?) ORDER BY create_time ASC -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@59860f83] -==> Parameters: 65(Long) -2026-06-02 14:34:23 - 图片URL已转换: imageId=49d2910b148d.jpg, nginxUrl=/files/img/49d2910b148d.jpg -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4b11dd4] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1831006422 wrapping com.mysql.cj.jdbc.ConnectionImpl@135636f5] will not be managed by Spring -==> Preparing: SELECT id,message_id,chunk_id,doc_path,doc_name,page,page_end,page_range,section,chunk_type,doc_type,section_chunk_id,excerpt,preview,bbox,bbox_mode,score,create_time FROM context_reference WHERE (message_id = ?) -==> Parameters: 176(Long) -<== Columns: id, conversation_id, role, content, message_type, is_finished, summary, kb_paths, answer, mode, duration_ms, images, sources, create_time -<== Row: 175, 65, assistant, <>, rag, 1, <>, <>, <>, null, 75512, <>, <>, 2026-06-02 14:29:09 -<== Row: 176, 65, assistant, <>, rag, 1, <>, <>, <>, null, 97190, <>, <>, 2026-06-02 14:32:03 -<== Total: 2 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47c5e224] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@234566b3] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1274635325 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,message_id,chunk_id,doc_path,doc_name,page,page_end,page_range,section,chunk_type,doc_type,section_chunk_id,excerpt,preview,bbox,bbox_mode,score,create_time FROM context_reference WHERE (message_id = ?) -==> Parameters: 175(Long) -<== Columns: id, message_id, chunk_id, doc_path, doc_name, page, page_end, page_range, section, chunk_type, doc_type, section_chunk_id, excerpt, preview, bbox, bbox_mode, score, create_time -<== Row: 398, 176, , null, 1.docx, 1, 1, 1, 6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**, text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 14:32:03 -<== Row: 399, 176, , null, 2.docx, 1, 1, 1, 2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**, table, other, null, <>, <>, null, null, 0.9980, 2026-06-02 14:32:03 -<== Row: 400, 176, , null, 3.docx, 1, 1, 1, 2.日常维护管理内容: > A2卫生医疗机构和各类院校, text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:32:03 -<== Row: 401, 176, 1.docx_22, null, 1.docx, 1, 1, null, 6.坚持区域协同、高效运作。 > **3.市场状态指标:**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Row: 402, 176, 1.docx_80, null, 1.docx, 1, 1, null, 1.市场状态的计算公式为: > 市场状态=+二级指标均值\*权重, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Columns: id, message_id, chunk_id, doc_path, doc_name, page, page_end, page_range, section, chunk_type, doc_type, section_chunk_id, excerpt, preview, bbox, bbox_mode, score, create_time -<== Row: 403, 176, 1.docx_62, null, 1.docx, 1, 1, null, 3.按价位段自选投放工作指引 > **3.终端动销率公式。**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Row: 393, 175, , null, 1.docx, 1, 1, 1, 1.市场状态的计算公式为:, image, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -<== Row: 404, 176, 1.docx_86, null, 1.docx, 1, 1, null, 2.指标值与权重确定。 > 一级指标合计权重不低于70%。, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Total: 7 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4b11dd4] -<== Row: 394, 175, , null, 3.docx, 1, 1, 1, 第六章 附则 > (不公开), text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -<== Row: 395, 175, , null, 2.docx, 1, 1, 1, 4.终端类型维护 > **(一)运营指导**, text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:29:09 -<== Row: 396, 175, , null, test.docx, 1, 1, 1, \## 第一章 总则, text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 14:29:09 -<== Row: 397, 175, 1.docx_24, null, 1.docx, 1, 1, null, 6.坚持区域协同、高效运作。 > **(一)统一货源投放周期**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:29:09 -<== Total: 5 -2026-06-02 14:34:23 - 响应 | 耗时: 21ms -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@234566b3] -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@45eecdf8] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1293306632 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,image_id,filename,path,size_bytes,format,source,page,page_end,page_range,section,chunk_type,type,description,full_description,score,collection,create_time FROM context_image WHERE (image_id = ?) -==> Parameters: 49d2910b148d.jpg(String) -<== Columns: id, image_id, filename, path, size_bytes, format, source, page, page_end, page_range, section, chunk_type, type, description, full_description, score, collection, create_time -<== Row: 7, 49d2910b148d.jpg, null, img/49d2910b148d.jpg, 3004, JPEG, 1.docx, 1, null, null, null, null, image, <>, <>, 10.9000, null, 2026-06-02 14:32:03 -<== Total: 1 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@45eecdf8] -2026-06-02 14:34:23 - 图片URL已转换: imageId=49d2910b148d.jpg, nginxUrl=/files/img/49d2910b148d.jpg -Creating a new SqlSession -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5ecb72bd] was not registered for synchronization because synchronization is not active -JDBC Connection [HikariProxyConnection@1836705169 wrapping com.mysql.cj.jdbc.ConnectionImpl@6dd60de9] will not be managed by Spring -==> Preparing: SELECT id,message_id,chunk_id,doc_path,doc_name,page,page_end,page_range,section,chunk_type,doc_type,section_chunk_id,excerpt,preview,bbox,bbox_mode,score,create_time FROM context_reference WHERE (message_id = ?) -==> Parameters: 176(Long) -<== Columns: id, message_id, chunk_id, doc_path, doc_name, page, page_end, page_range, section, chunk_type, doc_type, section_chunk_id, excerpt, preview, bbox, bbox_mode, score, create_time -<== Row: 398, 176, , null, 1.docx, 1, 1, 1, 6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**, text, other, null, <>, <>, null, null, 0.9990, 2026-06-02 14:32:03 -<== Row: 399, 176, , null, 2.docx, 1, 1, 1, 2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**, table, other, null, <>, <>, null, null, 0.9980, 2026-06-02 14:32:03 -<== Row: 400, 176, , null, 3.docx, 1, 1, 1, 2.日常维护管理内容: > A2卫生医疗机构和各类院校, text, other, null, <>, <>, null, null, 1.0000, 2026-06-02 14:32:03 -<== Row: 401, 176, 1.docx_22, null, 1.docx, 1, 1, null, 6.坚持区域协同、高效运作。 > **3.市场状态指标:**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Row: 402, 176, 1.docx_80, null, 1.docx, 1, 1, null, 1.市场状态的计算公式为: > 市场状态=+二级指标均值\*权重, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Row: 403, 176, 1.docx_62, null, 1.docx, 1, 1, null, 3.按价位段自选投放工作指引 > **3.终端动销率公式。**, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Row: 404, 176, 1.docx_86, null, 1.docx, 1, 1, null, 2.指标值与权重确定。 > 一级指标合计权重不低于70%。, null, other, 0, <>, <>, null, null, null, 2026-06-02 14:32:03 -<== Total: 7 -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5ecb72bd] -2026-06-02 14:34:23 - 响应 | 耗时: 21ms +Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`knowledge_management_system`.`user_answer`, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT) + at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:118) + at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) + at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:912) + at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354) + at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44) + at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java) + at jdk.internal.reflect.GeneratedMethodAccessor30.invoke(Unknown Source) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:58) + at jdk.proxy3/jdk.proxy3.$Proxy163.execute(Unknown Source) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:48) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:75) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) + at jdk.proxy2/jdk.proxy2.$Proxy161.update(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) + at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) + at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:106) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:59) + at jdk.proxy2/jdk.proxy2.$Proxy160.update(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) + at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425) + ... 102 common frames omitted +2026-06-10 13:44:41 - 响应 | 耗时: 2889ms diff --git a/default b/default index 41c641d..659e8a0 100644 --- a/default +++ b/default @@ -27,13 +27,6 @@ server { root /var/www/html; index index.html; - # 文件直接访问路径 - ^~ 表示前缀匹配且优先级高于正则 - location ^~ /files/ { - alias /opt/deploy/uploads/; - add_header Cache-Control "public, max-age=604800"; - try_files $uri $uri/ =404; - } - # 静态资源 location ~* \.(js|css|svg|png|jpg|woff|ttf)$ { expires 7d; @@ -62,3 +55,4 @@ server { proxy_set_header Connection ''; } } + diff --git a/docs/999.md b/docs/999.md new file mode 100644 index 0000000..f1739f2 --- /dev/null +++ b/docs/999.md @@ -0,0 +1,4 @@ +curl -X POST \ +-H "Authorization: Bearer " \ +-H "Content-Type: application/json" \ +-d '{"message": "什么是自然周?", "session\_id": "test\_session"}' diff --git a/docs/AI流式问答与出题接口-前端使用指南.md b/docs/AI流式问答与出题接口-前端使用指南.md new file mode 100644 index 0000000..80d4408 --- /dev/null +++ b/docs/AI流式问答与出题接口-前端使用指南.md @@ -0,0 +1,1162 @@ +# AI 流式问答与出题接口 - 前端使用指南 + +> **适用范围**:知识库问答、会话管理、题目生成、答案批改 +> **Base URL**:`http://localhost:8080/api` +> **认证方式**:`Authorization: Bearer ` +> **接口版本**:v2.17.0 +> **更新时间**:2026-06-05 + +--- + +## 目录 + +1. [快速开始](#一快速开始) +2. [AI 流式问答接口](#二ai-流式问答接口) +3. [AI 会话管理接口](#三ai-会话管理接口) +4. [题目生成接口](#四题目生成接口) +5. [题目批改接口](#五题目批改接口) +6. [答题记录接口](#六答题记录接口) +7. [前后端字段对照表](#七前后端字段对照表) +8. [常见问题 FAQ](#八常见问题-faq) +9. [附录:cURL 完整示例](#九附录curl-完整示例) + +--- + +## 一、快速开始 + +### 1.1 认证流程 + +所有接口(登录接口除外)均需携带 JWT Token: + +```http +POST /api/auth/login +Content-Type: application/json + +{ + "username": "admin", + "password": "123456" +} +``` + +**响应**: + +```json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzUxMiJ9...", + "user": { + "id": 1, + "username": "admin", + "role": 1 + } + } +} +``` + +后续所有接口请求头需添加: + +``` +Authorization: Bearer +``` + +### 1.2 接口总览 + +| 模块 | 接口 | 方法 | 功能 | +|------|------|------|------| +| **流式问答** | `/ai/chat/stream` | `POST` | 发起 AI 流式问答 | +| **中断问答** | `/ai/chat/stop?sessionId=xxx` | `POST` | 中断流式回答 | +| **会话列表** | `/ai/sessions?page=1&pageSize=10` | `GET` | 获取当前用户的会话列表 | +| **会话详情** | `/ai/session/{sessionId}` | `GET` | 获取指定会话的消息记录 | +| **消息引用** | `/ai/message/{messageId}/references` | `GET` | 获取某条消息的引用列表 | +| **消息文件来源** | `/ai/message/{messageId}/sources` | `GET` | 获取某条消息引用的文件来源(去重) | +| **会话引用** | `/ai/session/{sessionId}/references` | `GET` | 获取会话的全部引用 | +| **删除会话** | `/ai/session/{sessionId}` | `DELETE` | 删除单个会话及相关数据 | +| **批量删除会话** | `/ai/sessions` | `DELETE` | 批量删除多个会话 | +| **生成题目** | `/exam/generate` | `POST` | 根据文档生成题目(异步) | +| **生成试卷** | `/exam/paper/generate` | `POST` | 动态生成试卷 | +| **开始考试** | `/exam/paper/{paperId}/start` | `POST` | 获取试卷题目 | +| **考试结果** | `/exam/record/{recordId}/result` | `GET` | 获取批阅结果 | +| **正式考试批改** | `/exam/record/{recordId}/grade` | `POST` | 正式考试提交并批改 | +| **批改答案** | `/exam/grade` | `POST` | 批改学生答案(通用) | +| **查询答题记录** | `/exam/answers/query` | `POST` | 查询用户答题记录 | +| **考试记录列表** | `/exam/records?type=practice` | `GET` | 获取考试/练习记录列表 | + +--- + +## 二、AI 流式问答接口 + +### 2.1 发起流式问答 + +**接口**:`POST /api/ai/chat/stream` +**Content-Type**:`application/json` +**返回类型**:`text/event-stream` (Server-Sent Events) + +#### 请求体 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `message` | string | ✅ | 用户提问内容 | +| `session_id` | string | ❌ | 会话ID,不传则自动生成;传空字符串 `""` 也会自动生成 | +| `id` | string | ❌ | 自定义请求ID,用于追踪 | + +**请求示例**: + +```json +{ + "message": "请介绍一下知识库管理系统", + "session_id": "sess_1780410472658_9qg9a9hhp" +} +``` + +#### 内部逻辑说明 + +- 后端自动获取用户可访问的知识库(`collections`),无需前端传递 +- 后端自动从数据库加载该会话的历史消息作为上下文 +- 流式返回过程中,finish 事件到达时会自动保存: + - 用户提问 → `context_message`(role=user) + - AI 回答 → `context_message`(role=assistant,含 answer、images 等) + - 引用切片 → `context_reference`(自动从 RAG 获取 preview 字段) + - 图片 → `context_image`(保留 score 字段) + +#### 流式事件类型 + +| 事件 type | 说明 | 是否入库 | +|-----------|------|----------| +| `start` | 对话开始事件 | ❌ | +| `connected` | RAG 服务连接成功 | ❌ | +| `thinking` | AI 思考中 | ❌ | +| `searching` | 知识库检索中 | ❌ | +| `sources` | 检索到的候选来源信息 | ❌ 仅前端展示,**不写入数据库** | +| `chunk` | 流式内容片段 | ❌ 前端拼接显示 | +| `result` / `finish` | 最终完整结果(最重要) | ✅ 存入数据库 | +| `error` | 错误信息 | ❌ | + +#### finish 事件核心字段 + +```json +{ + "type": "finish", + "answer": "根据【参考资料】...完整的AI回答内容,其中包含 [ref:文档名_86] 这样的引用标记。", + "duration_ms": 75512, + "citations": [ + { + "chunk_id": "文档名_86", + "chunk_index": 86, + "source": "文档名.docx", + "collection": "dept_1_kb", + "doc_type": "other", + "section": "3.1 权重计算公式", + "chunk_type": "text", + "page": 1, + "score": 0.838, + "preview": "【系统自动从 RAG 接口获取的目标切片完整正文】", + "content": { + "stem": "切片摘要内容", + "data": {} + } + } + ], + "images": [ + { + "image_id": "49d2910b.jpg", + "path": "/api/image/49d2910b.jpg/data", + "source": "来源文档.docx", + "page": 1, + "chunk_type": "image", + "description": "图片描述", + "score": 0.85, + "collection": "dept_1_kb" + } + ] +} +``` + +> **重要说明**: +> - `answer` 中的 `[ref:chunk_id]` 标记:前端需解析为可点击链接,点击后跳转/展示对应引用信息 +> - `preview` 字段:后端写入 `context_reference` 表时,会自动调用 RAG 预览接口 `GET /documents/{collection}/{source}/preview?chunk_index=N&context=0` 填充该字段;若接口报错,则填入错误信息 +> - `context_message.answer` 字段保留完整的 `[ref:chunk_id]` 标记文本 + +#### answer 字段引用标记解析 + +前端需解析 `[ref:chunk_id]` 为可点击元素: + +```text +"市场状态 = Σ(二级指标均值 × 权重)[ref:文档名_86]。 +此外,一级指标合计权重不低于70%[ref:文档名_93]。" +``` + +#### 前端 JavaScript 调用示例(fetch + ReadableStream) + +```javascript +// 发起流式问答 +async function chatStream(message, sessionId, token) { + const response = await fetch('/api/ai/chat/stream', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + token + }, + body: JSON.stringify({ message, session_id: sessionId }) + }); + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + let buffer = ''; + let fullAnswer = ''; + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split('\n'); + buffer = lines.pop() || ''; // 保留未完成的行 + + for (const line of lines) { + if (!line.startsWith('data:')) continue; + try { + const data = JSON.parse(line.slice(5).trim()); + handleEvent(data); // 分发到事件处理器 + } catch (e) { + console.warn('解析失败:', line); + } + } + } +} + +// 事件处理器(前端自行实现 UI 更新) +function handleEvent(data) { + switch (data.type) { + case 'chunk': + // 实时拼接显示到对话框 + fullAnswer += data.content; + // renderAnswer(fullAnswer); + break; + case 'finish': + // 对话完成,拿到完整 answer、citations、images + console.log('完整回答:', data.answer); + console.log('引用列表:', data.citations); + console.log('图片列表:', data.images); + break; + case 'error': + console.error('AI 错误:', data.message); + break; + } +} +``` + +> **为什么不用 EventSource**:EventSource 只能 GET 请求,且无法自定义请求头(无法传 Token)。推荐使用 `fetch + ReadableStream` 方式。 + +### 2.2 中断流式问答 + +**接口**:`POST /api/ai/chat/stop?sessionId=sess_xxx` + +**响应**: + +```json +{ + "success": true, + "message": "已中断AI回答" +} +``` + +--- + +## 三、AI 会话管理接口 + +> 统一响应结构(`Map`): +> ```json +> { +> "success": true, +> "data": [...], +> "total": 10, +> "page": 1, +> "pageSize": 10, +> "pages": 1 +> } +> ``` + +### 3.1 获取用户会话列表 + +**接口**:`GET /api/ai/sessions?page=1&pageSize=10` + +**查询参数**: + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| `page` | int | ❌ | 1 | 页码 | +| `pageSize` | int | ❌ | 10 | 每页数量 | + +**响应 data 元素字段**(ChatSession): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | long | 数据库主键 | +| `sessionId` | string | 会话唯一ID | +| `userId` | long | 用户ID | +| `createTime` | datetime | 创建时间 | + +### 3.2 获取会话详情(消息记录) + +**接口**:`GET /api/ai/session/{sessionId}?page=1&pageSize=20` + +**权限检查**:后端自动校验该会话是否属于当前用户 + +**响应 data 元素字段**(ChatMessage): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | long | 消息ID | +| `conversationId` | long | 会话ID(数据库主键) | +| `role` | string | `user` / `assistant` | +| `content` | string | 用户提问原文(role=user)或 AI 回答内容(role=assistant 时通常与 answer 一致) | +| `messageType` | string | `rag` 等 | +| `isFinished` | int | 1=完成 | +| `answer` | string | AI 完整回答(含 `[ref:chunk_id]` 标记),仅 role=assistant 时有值 | +| `images` | string(JSON数组) | 图片列表(JSON 字符串,需前端解析) | +| `durationMs` | long | 耗时(毫秒) | +| `createTime` | datetime | 创建时间 | + +> **注意**:`ChatMessage` 实体中已**移除 `sources` 字段**。引用信息需通过 `/ai/message/{messageId}/references` 接口单独获取。 + +### 3.3 获取消息引用列表 + +**接口**:`GET /api/ai/message/{messageId}/references?docName=xxx` + +**查询参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `docName` | string | ❌ | 按文档名称过滤引用 | + +**响应 data 元素字段**(ChatReference): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | long | 引用记录ID | +| `messageId` | long | 关联的消息ID | +| `chunkId` | string | 切片唯一标识 `{docName}_{chunkIndex}` | +| `chunkIndex` | int | 切片序号 | +| `collection` | string | 向量库名称 | +| `docName` | string | 文档名称 | +| `docType` | string | 文档类型 | +| `page` | int | 页码 | +| `section` | string | 章节/段落位置 | +| `chunkType` | string | `text` / `image` / `table` | +| `excerpt` | string | 切片摘要内容 | +| **`preview`** | string | **目标切片完整正文(系统自动从 RAG 获取,失败则填错误信息)** | +| `score` | decimal | 相关性评分 0-1 | +| `createTime` | datetime | 创建时间 | + +### 3.4 获取消息文件来源列表(去重) + +**接口**:`GET /api/ai/message/{messageId}/sources` + +**用途**:对同一条消息的引用按文档名做去重汇总,用于展示"参考文档列表"侧栏 + +**响应 data 元素字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `docName` | string | 文档名称(去重后的唯一标识) | +| `docType` | string | 文档类型 | +| `referenceCount` | int | 该文档被引用的次数 | +| `pages` | string | 页码范围,如 `"5"` 或 `"1-10"` | + +**响应示例**: + +```json +{ + "success": true, + "data": [ + { + "docName": "薪酬制度.docx", + "docType": "other", + "referenceCount": 5, + "pages": "1-8" + }, + { + "docName": "考核办法.docx", + "docType": "other", + "referenceCount": 3, + "pages": "3" + } + ], + "total": 2 +} +``` + +### 3.5 获取会话全部引用 + +**接口**:`GET /api/ai/session/{sessionId}/references` + +**用途**:返回整个会话中所有 AI 回答的引用汇总,字段与单条消息引用接口一致 + +### 3.6 删除单个会话 + +**接口**:`DELETE /api/ai/session/{sessionId}` + +删除指定会话及其所有消息和引用数据。后端自动校验会话所属权。 + +### 3.7 批量删除会话 + +**接口**:`DELETE /api/ai/sessions` + +**请求体**: + +```json +["sess_xxx1", "sess_xxx2", "sess_xxx3"] +``` + +**响应**: + +```json +{ + "success": true, + "message": "会话批量删除成功", + "deletedCount": 3 +} +``` + +--- + +## 四、题目生成接口 + +> 本模块接口统一响应结构(`Result`): +> ```json +> { +> "code": 200, +> "message": "操作成功", +> "data": { ... } +> } +> ``` + +### 4.1 生成题目(异步) + +**接口**:`POST /api/exam/generate` +**Content-Type**:`application/json` + +#### 请求体字段 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `file_id` | Long | ⭐二选一 | 文件ID,系统自动从 `knowledge_file` 表查询向量库信息(**推荐**) | +| `file_path` | string | ⭐二选一 | 文件路径(如 `dept_1_kb/薪酬制度.docx`) | +| `collection` | string | file_path 必填 | 向量库名称(使用 file_path 时必须提供) | +| `question_types` | object | ❌ | 指定题型及数量;不传则使用 AI 智能生成模式 | +| `question_scores` | object | ❌ | 自定义题型分数配置 | +| `difficulty` | int | ❌ | 难度等级 1-5,默认 3 | +| `request_id` | string | ❌ | 请求ID,用于幂等性 | + +#### question_types 可选值 + +| 题型 | key | 说明 | +|------|-----|------| +| 单选题 | `single_choice` | 四个选项单选 | +| 多选题 | `multiple_choice` | 四个选项多选 | +| 判断题 | `true_false` | 对/错两选 | +| 填空题 | `fill_blank` | 按空格填写答案,支持同义词 | +| 简答题 | `subjective` | 开放回答,由 LLM 评分 | + +#### 请求示例:指定题型模式 + +```json +{ + "file_id": 1, + "question_types": { + "single_choice": 3, + "multiple_choice": 2, + "true_false": 2, + "fill_blank": 2, + "subjective": 1 + }, + "difficulty": 3, + "request_id": "gen_req_001" +} +``` + +#### 请求示例:智能生成模式(推荐) + +不提供 `question_types` 参数时,系统调用 AI 智能出题接口,自动根据文档内容判断题型和数量: + +```json +{ + "file_id": 1, + "difficulty": 3 +} +``` + +#### 响应示例(成功) + +```json +{ + "code": 200, + "message": "收到请求", + "data": { + "requestId": "gen_req_001", + "fileId": 1, + "fileMatchStatus": "success", + "matchedCollection": "dept_1_kb", + "documentName": "薪酬制度.docx", + "collectionFilled": true, + "asyncTaskStarted": true, + "nextStep": "请通过文件状态接口查询生成进度", + "status": "success" + } +} +``` + +#### 响应示例(文件验证失败) + +```json +{ + "code": 400, + "message": "文件不存在,请确认 file_id 是否正确", + "data": { + "status": "error", + "errorType": "FILE_VALIDATION_ERROR", + "errorDetail": "文件不存在", + "suggestion": "请检查 file_id 是否正确、文件是否已删除、或文件是否已完成向量化" + } +} +``` + +**fileMatchStatus 可能值**: + +| 值 | 说明 | HTTP 状态码 | +|----|------|------------| +| `success` | 文件验证通过,启动异步任务 | 200 | +| `FILE_NOT_FOUND` | 文件不存在 | 400 | +| `FILE_DELETED` | 文件已被删除 | 400 | +| `NOT_VECTORIZED` | 文件尚未完成向量化 | 400 | +| `PARAM_MISSING` | 参数不完整 | 400 | +| `INTERNAL_ERROR` | 服务器内部错误 | 500 | + +### 4.2 轮询题目生成进度 + +**接口**:`GET /api/file/{fileId}` + +**关键字段**: + +| 字段 | 说明 | +|------|------| +| `processStatus` | 文件处理状态(如 `INDEXED`) | +| `examStatus` | **题目生成状态**:`UNGENERATED` / `GENERATING` / `GENERATED` / `FAILED` | +| `processMessage` | 生成详情,包含题目数量和 AI 分析结果 | + +**examStatus 流转**: + +``` +UNGENERATED ──► GENERATING ──► GENERATED + │ + └──────► FAILED +``` + +**轮询策略建议**:初始间隔 2-3 秒;超时 5-10 分钟;examStatus 达到终态则停止。 + +### 4.3 生成试卷 + +**接口**:`POST /api/exam/paper/generate` + +**请求体**: + +```json +{ + "single_choice_count": 5, + "multiple_choice_count": 3, + "true_false_count": 2, + "fill_blank_count": 2, + "subjective_count": 1, + "difficulty": 3, + "include_personal": false, + "file_ids": [1, 2, 3] +} +``` + +**响应 data 字段**(`ExamPaperGenerateResponse`): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `paperId` | string | 试卷ID | +| `paperTitle` | string | 试卷标题 | +| `totalScore` | decimal | 总分 | +| `questionCount` | int | 题目总数 | +| `generatedAt` | datetime | 生成时间 | +| `questions` | array | 题目列表 | + +--- + +## 五、题目批改接口 + +### 5.1 批改答案(日常练习 / 模拟考 / 正式考试通用) + +**接口**:`POST /api/exam/grade` + +**请求体字段**: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `request_id` | string | ❌ | 请求ID | +| `type` / `answerType` | string | ❌ | `practice` / `mock_exam` / `formal_exam` | +| `record_id` | string | ❌ | 正式考试记录ID;提供时走正式考试提交/批改分支 | +| `paper_id` | string | ❌ | 试卷ID | +| `session_id` | string | ❌ | 会话ID | +| `answers` | array | ✅ | 答案列表 | + +**answers 数组元素字段**: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `question_id` | string | ✅ | 题目ID | +| `question_type` | string | ✅ | `single_choice` / `multiple_choice` / `true_false` / `fill_blank` / `subjective` | +| `question_content` | object | ✅ | 题目内容(含 stem / options / answer 等) | +| `student_answer` | any | ✅ | 学生提交的答案 | +| `max_score` | number | ✅ | 满分 | + +**请求示例**: + +```json +{ + "request_id": "grade_req_001", + "answer_type": "practice", + "answers": [ + { + "question_id": "q_001", + "question_type": "single_choice", + "question_content": { + "stem": "根据公司规定,员工薪资由哪几部分组成?", + "data": { + "options": [ + { "key": "A", "content": "基本工资+奖金" }, + { "key": "B", "content": "基本工资+绩效奖金+津贴补贴" } + ] + }, + "answer": "B" + }, + "student_answer": "B", + "max_score": 5.0 + }, + { + "question_id": "q_002", + "question_type": "multiple_choice", + "question_content": { + "stem": "以下哪些属于绩效奖金的评定因素?", + "data": { "options": [...] }, + "answer": ["A", "B", "D"] + }, + "student_answer": ["A", "B"], + "max_score": 4.0 + }, + { + "question_id": "q_003", + "question_type": "true_false", + "question_content": { + "stem": "公司规定员工每月绩效奖金上限为工资的20%。", + "answer": "F" + }, + "student_answer": "T", + "max_score": 2.0 + }, + { + "question_id": "q_004", + "question_type": "fill_blank", + "question_content": { + "stem": "员工薪资由___、___和___三部分组成。", + "data": { "blank_count": 3 }, + "answer": [["基本工资"], ["绩效奖金", "绩效"], ["津贴补贴", "补贴"]] + }, + "student_answer": ["基本工资", "绩效奖金", "交通补贴"], + "max_score": 6.0 + }, + { + "question_id": "q_005", + "question_type": "subjective", + "question_content": { + "stem": "请简述公司薪酬制度的核心原则。", + "data": { + "scoring_points": [ + { "point": "公平性", "weight": 0.3 }, + { "point": "激励性", "weight": 0.3 }, + { "point": "竞争力", "weight": 0.2 }, + { "point": "合法性", "weight": 0.2 } + ] + }, + "answer": "公司薪酬制度遵循公平、激励、竞争、合法四大原则..." + }, + "student_answer": "我认为公司的薪酬制度应该公平公正...", + "max_score": 10.0 + } + ] +} +``` + +**响应 data 字段**(`ExamGradeResponse`): + +| 字段 | 类型 | 说明 | +|------|------|------| +| `success` | boolean | 是否成功 | +| `totalScore` | decimal | 得分 | +| `totalMaxScore` | decimal | 满分 | +| `scoreRate` | decimal | 得分率(百分比) | +| `results` | array | 每题批改结果 | + +**results 元素字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `questionId` | string | 题目ID | +| `questionType` | string | 题型 | +| `score` | decimal | 本题得分 | +| `maxScore` | decimal | 本题满分 | +| `correct` / `isCorrect` | boolean | 是否答对 | +| `studentAnswer` | any | 学生答案 | +| `correctAnswer` | any | 正确答案 | +| `feedback` | string | 批改反馈 | + +**批阅规则**: + +| 题型 | 批阅方式 | 得分规则 | +|------|----------|----------| +| 单选题 | 精确匹配 | 正确得满分,错误得 0 | +| 多选题 | 集合比对 | 全对满分,少选一半,错选得 0 | +| 判断题 | 精确匹配 | 正确得满分,错误得 0 | +| 填空题 | 多答案匹配 | 每空独立评分,支持同义词匹配 | +| 简答题 | LLM 评分 | 根据得分点评分,不超过 max_score | + +### 5.2 正式考试提交并批改 + +**接口**:`POST /api/exam/record/{recordId}/grade` + +**路径参数**:`recordId`(正式考试记录ID) + +**请求体**(`ExamSaveRequest`): + +```json +{ + "answers": [ + { + "question_id": "q_001", + "question_type": "single_choice", + "answer": "B" + } + ] +} +``` + +--- + +## 六、答题记录接口 + +### 6.1 开始考试(获取题目) + +**接口**:`POST /api/exam/paper/{paperId}/start` + +系统自动查找或创建考试记录,返回试卷题目内容。 + +### 6.2 获取考试结果 + +**接口**:`GET /api/exam/record/{recordId}/result` + +**权限检查**:后端校验该记录是否属于当前用户 + +**响应 data 字段**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| `recordId` | string | 记录ID | +| `paperId` | string | 试卷ID | +| `paperTitle` | string | 试卷标题 | +| `status` | string | `submitted` 等 | +| `totalScore` | decimal | 得分 | +| `totalMaxScore` | decimal | 满分 | +| `scoreRate` | decimal | 得分率 | +| `submitTime` | datetime | 提交时间 | +| `answers` | array | 每题结果 | + +### 6.3 查询用户答题记录 + +**接口**:`POST /api/exam/answers/query` + +**请求体**(`UserAnswerQueryRequest`): + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `paper_id` | string | ⭐二选一 | 按试卷ID查询 | +| `session_id` | string | ⭐二选一 | 按会话ID查询 | +| `answer_type` | string | ❌ | 过滤类型:practice / mock_exam / formal_exam | +| `page` | int | ❌ | 页码,默认 1 | +| `page_size` | int | ❌ | 每页数量,默认 20 | + +**请求示例**: + +```json +{ + "paper_id": "paper_abc123", + "answer_type": "practice", + "page": 1, + "page_size": 20 +} +``` + +### 6.4 获取考试记录列表 + +**接口**:`GET /api/exam/records?type=practice` + +**查询参数**: + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| `type` | string | ❌ | `practice` | `practice` / `mock_exam` / `formal_exam` | + +**分支逻辑**: + +- `type=practice` → 返回日常练习答题记录(`UserAnswerQueryResponse`) +- `type=mock_exam` 或 `formal_exam` → 返回试卷考试记录列表(`List`) + +--- + +## 七、前后端字段对照表 + +### 7.1 ChatReference 引用字段映射 + +| 后端字段 | 前端字段(AI返回) | 类型 | 说明 | +|----------|-------------------|------|------| +| `chunkId` | `chunk_id` | string | 切片唯一标识 `{docName}_{chunkIndex}` | +| `chunkIndex` | `chunk_index` | int | 切片序号 | +| `collection` | `collection` | string | 向量库名称 | +| `docName` | `source` / `doc_name` | string | 文档名称 | +| `docType` | `doc_type` | string | 文档类型 | +| `page` | `page` | int | 页码 | +| `section` | `section` | string | 章节/段落位置 | +| `chunkType` | `chunk_type` | string | `text` / `image` / `table` | +| `excerpt` | `content.stem` | string | 切片摘要 | +| **`preview`** | —(系统自动填充) | string | **目标切片完整正文**,由后端从 RAG 预览接口获取,失败则填错误信息 | +| `score` | `score` | decimal | 相关性评分 0-1 | +| `createTime` | — | datetime | 创建时间 | + +### 7.2 ChatMessage 消息字段映射 + +| 后端字段 | 前端字段 | 类型 | 说明 | +|----------|----------|------|------| +| `id` | `message_id` | long | 消息唯一ID | +| `conversationId` | `conversation_id` | long | 会话(数据库主键)ID | +| `role` | `role` | string | `user` / `assistant` | +| `content` | `content` | string | 用户提问原文 / AI 回答 | +| `answer` | `answer` | string | AI 完整回答(含 `[ref:chunk_id]` 标记),role=assistant 有效 | +| `messageType` | `message_type` | string | `rag` 等 | +| `isFinished` | `is_finished` | int | 1=完成 | +| `images` | `images` | string(JSON数组) | 图片列表(JSON 字符串,前端需 JSON.parse) | +| `durationMs` | `duration_ms` | long | 耗时(毫秒) | +| `createTime` | `create_time` | datetime | 创建时间 | + +> **已移除字段**:`sources`。引用信息需通过 `/ai/message/{messageId}/references` 接口获取。 + +### 7.3 Image 图片字段映射(context_image 表) + +| 后端字段 | 前端字段(AI返回) | 类型 | 说明 | +|----------|-------------------|------|------| +| `imageId` | `image_id` | string | 图片标识 | +| `path` | `path` / `url` | string | 图片访问路径,如 `/api/image/xxx/data` | +| `source` | `source` | string | 来源文档 | +| `page` | `page` | int | 页码 | +| `section` | `section` | string | 章节位置 | +| `chunkType` | `chunk_type` | string | 切片类型(image) | +| `description` | `description` | string | 图片描述 | +| `score` | `score` | decimal | 相关性评分(**保留**) | +| `collection` | `collection` | string | 向量库名称 | + +> **已移除字段**:`filename`、`size_bytes`、`format`、`page_end`、`type`、`full_description` + +--- + +## 八、常见问题 FAQ + +### Q1: answer 中的 `[ref:chunk_id]` 标记如何解析? + +**答**:前端需要在渲染 `answer` 时,使用正则匹配 `\[ref:([^\]]+)\]`,将其替换为可点击的引用链接: + +```javascript +const renderAnswer = (answer) => { + const regex = /\[ref:([^\]]+)\]/g; + return answer.replace(regex, (match, chunkId) => { + return `[引用]`; + }); +}; +``` + +### Q2: 流式问答如何处理?为什么不用 EventSource? + +**答**:由于 EventSource 只能 GET 请求,且无法自定义请求头(无法传 Token),推荐使用 `fetch + ReadableStream` 方式: + +```javascript +const response = await fetch('/api/ai/chat/stream', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + token + }, + body: JSON.stringify({ message, session_id: sessionId }) +}); + +const reader = response.body.getReader(); +const decoder = new TextDecoder(); +let buffer = ''; +let fullAnswer = ''; + +while (true) { + const { value, done } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split('\n'); + buffer = lines.pop() || ''; + + for (const line of lines) { + if (!line.startsWith('data:')) continue; + const dataStr = line.slice(5).trim(); + if (!dataStr) continue; + try { + const data = JSON.parse(dataStr); + if (data.type === 'chunk') { + fullAnswer += data.content; + // renderAnswer(fullAnswer); // 更新 UI + } else if (data.type === 'finish') { + console.log('引用:', data.citations); + console.log('图片:', data.images); + } + } catch (e) { + console.warn('解析失败:', dataStr); + } + } +} +``` + +### Q3: 题目生成接口为什么是异步的?如何获取生成结果? + +**答**:题目生成需要调用 AI LLM 进行内容理解和题目构造,耗时较长(通常 10-60 秒)。使用异步方式可避免前端超时等待。 + +获取结果方式: +1. 调用 `POST /api/exam/generate` 提交任务,得到 `fileId` +2. 轮询 `GET /api/file/{fileId}` 检查 `examStatus` 字段 +3. 当 `examStatus` 变为 `GENERATED` 时,通过题目列表接口查看题目 + +### Q4: citations 和 sources 有什么区别? + +**答**: +- **citations**(finish 事件中):AI 回答中真正引用到的切片。会写入 `context_reference` 表,可通过引用列表接口查询 +- **sources**(流式事件中):检索阶段命中的候选来源文档。**仅用于前端展示**,**不写入数据库**,`context_message` 表也没有 `sources` 字段 + +### Q5: context_reference.preview 字段是怎么来的? + +**答**:当 citations 写入 `context_reference` 表时,后端会对每条引用自动调用 RAG 预览接口: + +``` +GET /documents/{collection}/{source}/preview?chunk_index=N&context=0 +``` + +获取该切片的完整正文写入 `preview` 字段。若接口调用失败,`preview` 填入错误信息(如"预览获取失败: ...")。前端可直接展示 `preview` 内容,无需再调用 RAG 接口。 + +### Q6: 同一会话多次提问,如何区分不同消息的引用? + +**答**:`context_reference` 表通过 `messageId` 字段关联到具体消息。每个消息的引用列表独立。可通过: +- `/ai/message/{messageId}/references` — 查询某条消息的引用 +- `/ai/session/{sessionId}/references` — 查询整个会话的所有引用 + +### Q7: context_image 表中的 score 字段有什么用? + +**答**:保留 score 字段用于记录 AI 返回的图片相关性评分(0-1)。前端可根据 score 排序展示图片,或过滤低分图片。 + +--- + +## 九、附录:cURL 完整示例 + +> 以下示例均需替换 `` 为实际登录获取的 JWT Token + +### 9.1 登录获取 Token + +```bash +curl -X POST "http://localhost:8080/api/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"123456"}' +``` + +### 9.2 发起流式问答 + +```bash +curl -X POST "http://localhost:8080/api/ai/chat/stream" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"message":"市场状态评价指标体系中一级指标有哪些","session_id":""}' \ + --no-buffer +``` + +### 9.3 中断流式问答 + +```bash +curl -X POST "http://localhost:8080/api/ai/chat/stop?sessionId=sess_xxx" \ + -H "Authorization: Bearer " +``` + +### 9.4 获取会话列表 + +```bash +curl -X GET "http://localhost:8080/api/ai/sessions?page=1&pageSize=10" \ + -H "Authorization: Bearer " +``` + +### 9.5 获取会话详情 + +```bash +curl -X GET "http://localhost:8080/api/ai/session/sess_1780410472658_9qg9a9hhp" \ + -H "Authorization: Bearer " +``` + +### 9.6 获取消息引用列表 + +```bash +curl -X GET "http://localhost:8080/api/ai/message/178/references" \ + -H "Authorization: Bearer " +``` + +### 9.7 获取消息文件来源列表(去重) + +```bash +curl -X GET "http://localhost:8080/api/ai/message/178/sources" \ + -H "Authorization: Bearer " +``` + +### 9.8 删除单个会话 + +```bash +curl -X DELETE "http://localhost:8080/api/ai/session/sess_1780410472658_9qg9a9hhp" \ + -H "Authorization: Bearer " +``` + +### 9.9 批量删除会话 + +```bash +curl -X DELETE "http://localhost:8080/api/ai/sessions" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '["sess_xxx1","sess_xxx2"]' +``` + +### 9.10 生成题目(指定题型) + +```bash +curl -X POST "http://localhost:8080/api/exam/generate" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "file_id": 1, + "question_types": { + "single_choice": 3, + "multiple_choice": 2, + "true_false": 2, + "fill_blank": 2, + "subjective": 1 + }, + "difficulty": 3, + "request_id": "gen_req_001" + }' +``` + +### 9.11 生成题目(智能模式) + +```bash +curl -X POST "http://localhost:8080/api/exam/generate" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"file_id":1,"difficulty":3}' +``` + +### 9.12 轮询题目生成状态 + +```bash +curl -X GET "http://localhost:8080/api/file/1" \ + -H "Authorization: Bearer " +``` + +### 9.13 生成试卷 + +```bash +curl -X POST "http://localhost:8080/api/exam/paper/generate" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "single_choice_count": 5, + "multiple_choice_count": 3, + "true_false_count": 2, + "fill_blank_count": 2, + "subjective_count": 1, + "difficulty": 3, + "include_personal": false + }' +``` + +### 9.14 批改答案(日常练习) + +```bash +curl -X POST "http://localhost:8080/api/exam/grade" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "request_id": "grade_req_001", + "answer_type": "practice", + "answers": [ + { + "question_id": "q_001", + "question_type": "single_choice", + "question_content": { + "stem": "题目内容...", + "data": { "options": [...] }, + "answer": "B" + }, + "student_answer": "B", + "max_score": 5.0 + } + ] + }' +``` + +### 9.15 开始考试(获取题目) + +```bash +curl -X POST "http://localhost:8080/api/exam/paper/paper_xxx/start" \ + -H "Authorization: Bearer " +``` + +### 9.16 获取考试结果 + +```bash +curl -X GET "http://localhost:8080/api/exam/record/record_xxx/result" \ + -H "Authorization: Bearer " +``` + +### 9.17 查询答题记录 + +```bash +curl -X POST "http://localhost:8080/api/exam/answers/query" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"paper_id":"paper_xxx"}' +``` + +### 9.18 获取考试记录列表 + +```bash +# 日常练习 +curl -X GET "http://localhost:8080/api/exam/records?type=practice" \ + -H "Authorization: Bearer " + +# 正式考试 +curl -X GET "http://localhost:8080/api/exam/records?type=formal_exam" \ + -H "Authorization: Bearer " +``` + +--- + +**文档版本**:v2.17.0 +**最后更新**:2026-06-05 +**适用代码版本**:与当前 Spring Boot 后端(`AIChatController` / `ExamController`)同步 diff --git a/docs/ai/RAG引用跳转-前端实现说明.md b/docs/ai/RAG引用跳转-前端实现说明.md new file mode 100644 index 0000000..5137833 --- /dev/null +++ b/docs/ai/RAG引用跳转-前端实现说明.md @@ -0,0 +1,192 @@ +## RAG 引用溯源跳转 — 接口说明与实现思路 + +### 一、整体流程 + +``` +用户提问 → /rag 流式返回 → 回答文本中嵌入 [ref:chunk_id] 标记 + citations 数组 + ↓ + 前端解析标记,渲染为可点击的 [1] [2] 上标 + ↓ + 用户点击引用 → 前端调 /documents/{path}/preview 获取切片上下文 + ↓ + 前端展示:左侧原文档预览(跳转/高亮) + 右侧切片内容 +``` + +--- + +### 二、/rag 返回的引用数据结构 + +SSE 流结束时,`finish` 事件的 `citations` 字段是一个数组,每个元素结构如下: + +```jsonc +{ + // ===== 通用字段(所有文档类型都有) ===== + "chunk_id": "三峡公报.pdf_5", // 原始切片 ID(文件名_序号) + "chunk_index": 5, // 全局切片序号(从 0 开始递增,入库时写入) + "source": "三峡公报.pdf", // 来源文件名 + "collection": "public_kb", // 所属知识库 + "doc_type": "pdf", // 文档类型:pdf / word / excel / txt / other + "section": "第一章 > 1.2 概述", // 章节层级路径 + "preview": "元数据中的预览文本", // 入库时生成的摘要/预览 + "content": "切片正文(截断至 300 字)", // 实际切片内容的前 300 字 + "chunk_type": "text", // 切片类型:text / table / image_caption + + // ===== PDF 专属字段 ===== + "page": 3, // 起始页码 + "page_end": 4, // 结束页码(跨页时存在) + "bbox": [100, 200, 500, 600], // 边界框坐标(可用于页内精准定位) + "bbox_mode": "pixel", // 坐标模式 + + // ===== Word 专属字段 ===== + "section_chunk_id": "sec_3_para_2" // 章节内段落序号 + + // ===== Excel 专属字段 ===== + "page": 1 // 工作表序号 +} +``` + +**关键字段说明:** + +| 字段 | 用途 | 备注 | +|------|------|------| +| `chunk_index` | 调用 preview 接口的核心参数,精准定位切片在文档中的位置 | 从 0 开始,入库时按顺序分配 | +| `source` + `collection` | 拼接文档路径 `{collection}/{source}`,用于调 preview 接口 | 例:`public_kb/三峡公报.pdf` | +| `doc_type` | 前端据此选择预览方式(PDF 渲染 / DOCX 渲染 / 纯文本) | | +| `page` | PDF 页码跳转、Excel 工作表定位 | | +| `bbox` | PDF 页内矩形高亮(可选,精度更高) | | +| `section` | 给用户展示定位信息(如"第三章 > 3.1 市场分析") | | +| `content` | 截断的正文预览,用于 DOCX 文本匹配高亮 | 仅 300 字,完整内容需调 preview 接口 | + +**回答文本中的引用标记:** + +后端在 LLM 回答的段落末尾自动插入 `[ref:chunk_id]` 标记,前端需要将其解析为可点击的上标: + +``` +原文:根据相关研究,三峡工程年均发电量约 882 亿千瓦时。[ref:三峡公报.pdf_5] +渲染:根据相关研究,三峡工程年均发电量约 882 亿千瓦时。[5] ← 可点击上标 +``` + +--- + +### 三、文档预览接口 + +``` +GET /api/documents/{collection}/{source}/preview?chunk_index={N}&context={K} +``` + +**参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `collection` | path | 是 | 知识库名称(如 `public_kb`) | +| `source` | path | 是 | 文件名(如 `三峡公报.pdf`) | +| `chunk_index` | query | 是 | 目标切片序号(来自 citation 的 `chunk_index`) | +| `context` | query | 否 | 前后各取几个切片,默认 2 | + +**响应示例:** + +```jsonc +{ + "success": true, + "collection": "public_kb", + "source": "三峡公报.pdf", + "total_chunks": 42, // 文档总切片数 + "target_index": 5, // 请求的 chunk_index + "chunks": [ + { + "id": "uuid-xxx", + "document": "完整切片正文...", // 完整内容(不截断) + "metadata": { + "chunk_index": 3, + "source": "三峡公报.pdf", + "page": 2, + "section": "第一章 > 1.1 项目背景", + "doc_type": "pdf", + ... + }, + "is_target": false // 是否为目标切片 + }, + { + "id": "uuid-yyy", + "document": "目标切片的完整正文...", + "metadata": { "chunk_index": 5, "page": 3, ... }, + "is_target": true // ← 这是用户点击的那个切片 + }, + // ... 上下文切片 + ] +} +``` + +--- + +### 四、前端实现思路 + +#### 4.1 引用标记解析 + +``` +1. 从 finish 事件取 answer(回答全文)和 citations(引用数组) +2. 用正则 /\[ref:([^\]]+)\]/g 从 answer 中按出现顺序提取所有 chunk_id +3. 与 citations 数组匹配,建立 chunk_id → 显示序号 [1] [2] ... 的映射 +4. 渲染回答时,将 [ref:xxx] 替换为可点击的上标元素 +``` + +#### 4.2 点击引用后的跳转 + +``` +用户点击引用 [N] + │ + ├─ 1. 从 citation 中取 source + collection,拼出文档路径 + │ docPath = `${collection}/${source}` + │ + ├─ 2. 调用 preview 接口获取切片上下文 + │ GET /documents/${docPath}/preview?chunk_index=${chunk_index}&context=3 + │ + ├─ 3. 根据 doc_type 选择预览方式: + │ ├─ PDF → 用 page 字段跳转到对应页(可选:用 bbox 绘制高亮矩形) + │ ├─ DOCX → 用目标切片的 document 字段做文本匹配,高亮并滚动到对应段落 + │ └─ TXT → 直接显示文本,搜索目标内容并滚动定位 + │ + └─ 4. 右侧面板展示切片上下文列表 + ├─ 高亮标记 is_target=true 的切片 + ├─ 显示每个切片的 section、page 信息 + └─ 点击其他切片可切换预览位置 +``` + +#### 4.3 各文档类型的定位策略 + +**PDF 文档:** + +最直接的方案是利用 `page` 字段做页码跳转。如果需要更精确的页内定位,`bbox` 字段提供了文本区域的坐标 `[x1, y1, x2, y2]`,可以在 PDF 渲染层上叠加一个半透明高亮矩形。 + +**Word 文档:** + +Word 没有页码概念,定位方式是文本匹配。用 preview 接口返回的目标切片 `document`(完整正文)在渲染后的文档中做模糊匹配,找到最相似的段落并高亮滚动。`content` 字段只有 300 字可能不够用,建议用 preview 接口的 `document` 字段。 + +**纯文本 / 其他:** + +直接渲染文本内容,通过字符串搜索定位目标切片并滚动到视口中央。 + +#### 4.4 弹窗内切片切换 + +右侧面板展示上下文切片后,用户可以点击其他切片切换预览位置。切换时需要: + +``` +1. 从切片的 metadata.chunk_index 获取序号(注意:切片的 id 是 UUID,不能用来定位) +2. 更新目标标记(is_target) +3. 用切片的 document 字段更新左侧文档的高亮/定位 +4. 如果切片 metadata 中有 page 字段,同步更新 PDF 页码 +``` + +--- + +### 五、注意事项 + +1. **`chunk_index` 是核心定位字段**。它在入库时按文档切片顺序从 0 递增分配,preview 接口通过它查找目标切片。不要与数组下标混淆——后端已按 `metadata.chunk_index` 排序后查找,不依赖数组位置。 + +2. **`content` 字段被截断到 300 字**。这是为了控制 SSE 流的数据量。前端如果需要完整切片内容(比如 DOCX 高亮匹配),应调用 preview 接口获取 `document` 字段。 + +3. **`bbox` 坐标的可用性**。目前 PDF 解析器会提取文本块的 bbox 信息,但不是所有切片都有。前端使用 bbox 时应做空值判断。 + +4. **`collection` 字段的回退策略**。citation 中带有 `collection` 字段,但如果为空,前端可以用当前用户选中的知识库名称作为回退。 + +5. **LLM 可能自行生成 `[1]`、`[2]` 等引用标记**,与后端注入的 `[ref:chunk_id]` 格式不同。前端应先清理 LLM 的 `[数字]` 标记,再处理后端的 `[ref:xxx]` 标记,避免冲突。 diff --git a/docs/ai/curl测试手册 (4).md b/docs/ai/curl测试手册 (4).md index 9896654..9408e33 100644 --- a/docs/ai/curl测试手册 (4).md +++ b/docs/ai/curl测试手册 (4).md @@ -85,7 +85,7 @@ curl -s http://localhost:5001/health 知识库问答(SSE 流式返回)。 ```bash -echo '{"message":"三峡工程","chat_history":[]}' > /tmp/rag.json +echo '{"message":"市场权重计算公式","chat_history":[]}' > /tmp/rag.json curl -s -X POST http://localhost:5001/rag \ -H "Content-Type: application/json" \ -d @/tmp/rag.json @@ -121,7 +121,7 @@ data: {"type": "finish", "answer": "完整回答", "sources": [...]} **带 collections 参数**: ```bash -echo '{"message":"三峡工程","chat_history":[],"collections":["public_kb"]}' > /tmp/rag.json +echo '{"message":"市场权重计算公式","chat_history":[],"collections":["dept_1_kb"]}' > /tmp/rag.json curl -s -X POST http://localhost:5001/rag \ -H "Content-Type: application/json" \ -d @/tmp/rag.json @@ -1375,7 +1375,7 @@ curl -s http://localhost:5001/exam/health curl -s -X POST http://localhost:5001/exam/generate \ -H "Authorization: Bearer mock-token-admin" \ -H "Content-Type: application/json" \ - -d '{"file_path":"public_kb/1.docx","collection":"public_kb","question_types":{"single_choice":5,"true_false":3,"fill_blank":2}}' + -d '{"file_path":"dept_1_kb/1.docx","collection":"dept_1_kb","question_types":{"single_choice":5,"true_false":3,"fill_blank":2}}' ``` **请求体**: @@ -1458,7 +1458,7 @@ AI 智能出题 - 自动分析文件并决定题型和数量。 ```bash curl -s -X POST http://localhost:5001/exam/generate-smart \ -H "Content-Type: application/json" \ - -d '{"file_path":"dept_1_kb/test.docx","collection":"dept_1_kb"}' + -d '{"file_path":"dept_1_kb/需求分析.docx","collection":"dept_1_kb"}' ``` **请求体**: diff --git a/docs/ai/出题批阅接口变更说明(2026-06-05).md b/docs/ai/出题批阅接口变更说明(2026-06-05).md new file mode 100644 index 0000000..e39a396 --- /dev/null +++ b/docs/ai/出题批阅接口变更说明(2026-06-05).md @@ -0,0 +1,403 @@ +# 出题批阅接口变更说明(2026-06-05) + +> 本文档面向后端开发人员,汇总出题/批卷接口本次升级的所有变更点,以及后端需要适配的代码修改。 + +--- + +## 一、变更总览 + +| 变更项 | 变更类型 | 影响范围 | 后端是否必须改 | +|--------|----------|----------|---------------| +| 批卷请求字段 `question_content` → `content` | **破坏性变更** | `/exam/grade` 请求体 | **是** | +| 批卷结果格式统一为 `grading_status` + `details` | **格式变更** | `/exam/grade` 响应体 | **是** | +| 出题总题数上限 20 道 | 新增校验 | `/exam/generate` | 需注意 | +| 批卷 `question_type` 枚举校验 | 新增校验 | `/exam/grade` | 需注意 | +| **`exclude_stems` 跨调用去重** | **新增参数** | `/exam/generate`、`/exam/generate-smart` | **建议使用** | +| 出题结果新增 `requested_types`、`actual_types`、`warnings` | 新增字段 | `/exam/generate` 响应体 | 可选消费 | +| 主观题缺少评分标准时返回 `warnings` | 新增字段 | `/exam/grade` 响应体 | 可选消费 | + +--- + +## 二、破坏性变更(必须修改) + +### 2.1 批卷请求字段重命名:`question_content` → `content` + +**变更前**: +```json +{ + "question_id": "q-001", + "question_type": "single_choice", + "question_content": { + "stem": "题干", + "answer": "B", + "data": {"options": [...]} + }, + "student_answer": "B", + "max_score": 2 +} +``` + +**变更后**: +```json +{ + "question_id": "q-001", + "question_type": "single_choice", + "content": { + "stem": "题干", + "answer": "B", + "data": {"options": [...]} + }, + "student_answer": "B", + "max_score": 2 +} +``` + +**为什么要改**:出题接口 `/exam/generate` 返回的每道题里,题目内容字段叫 `content`。批卷接口改用同名 `content` 后,后端可以直接把出题结果的 `content` 透传到批卷接口,不需要做任何字段映射。 + +**后端代码修改示例**: + +```python +# 修改前 +grade_answers.append({ + "question_id": qid, + "question_type": question.question_type, + "question_content": question.content, # ← 旧字段名 + "student_answer": ans['answer'], + "max_score": question.score +}) + +# 修改后 +grade_answers.append({ + "question_id": qid, + "question_type": question.question_type, + "content": question.content, # ← 新字段名,与出题接口一致 + "student_answer": ans['answer'], + "max_score": question.score +}) +``` + +### 2.2 批卷结果格式统一 + +**变更前**:各题型返回格式不统一,客观题直接返回 `correct` + `feedback`,填空题返回 `details.blank_scores`,主观题返回 `details.scoring_breakdown`,没有统一的结构标识。 + +```json +// 旧 - 客观题 +{"question_id": "q1", "score": 2, "max_score": 2, "correct": true, "feedback": "正确!"} + +// 旧 - 填空题 +{"question_id": "q4", "score": 2, "max_score": 4, "details": {"blank_scores": [2, 0]}} + +// 旧 - 主观题 +{"question_id": "q5", "score": 7, "max_score": 10, "details": {"scoring_breakdown": [...]}} +``` + +**变更后**:所有题型统一使用 `grading_status` + `details` 结构。 + +```json +// 新 - 客观题 +{ + "question_id": "q1", + "score": 2, + "max_score": 2, + "grading_status": "success", + "details": { + "correct": true, + "student_answer": "B", + "correct_answer": "B", + "feedback": "正确!" + } +} + +// 新 - 填空题 +{ + "question_id": "q4", + "score": 2.0, + "max_score": 4.0, + "grading_status": "success", + "details": { + "total_blanks": 2, + "correct_blanks": 1, + "blank_scores": [2.0, 0], + "feedback": "2 个空中答对 1 个" + } +} + +// 新 - 主观题 +{ + "question_id": "q5", + "score": 7.5, + "max_score": 10.0, + "grading_status": "success", + "details": { + "scoring_breakdown": [ + {"point": "核心概念", "weight": 0.5, "achieved": 0.8, "comment": "概念描述准确"} + ], + "highlights": ["条理清晰"], + "shortcomings": ["缺少应用场景"], + "overall_feedback": "整体回答较好,建议补充实际应用场景。" + } +} + +// 新 - 评分失败(LLM 异常或超时) +{ + "question_id": "q6", + "score": 0, + "max_score": 10.0, + "grading_status": "failed", + "details": { + "error": "评分结果解析失败" + } +} +``` + +**后端需要关注的点**: + +1. **判断评分是否成功**:改用 `grading_status` 字段判断,不再依赖 `correct` 或 `score > 0` + - `"success"` → 正常评分,`score` 和 `details` 有效 + - `"failed"` → 评分失败,`score` 为 0,`details.error` 包含失败原因 +2. **获取反馈信息**:原来客观题的 `correct`/`feedback` 现在统一在 `details` 里 +3. **成绩更新逻辑**:`grading_status: "failed"` 的题目,后端可选择标记为"待重批"而非直接记 0 分 + +**后端代码修改示例**: + +```python +# 修改前 +for result in grade_result['results']: + is_correct = result.get('correct', False) + feedback = result.get('feedback', '') + # 更新成绩... + +# 修改后 +for result in grade_result['results']: + status = result.get('grading_status', 'success') + details = result.get('details', {}) + + if status == 'failed': + # 评分失败,标记待重批 + mark_for_regrade(result['question_id'], details.get('error', '')) + continue + + is_correct = details.get('correct', None) # 仅客观题有此字段 + feedback = details.get('feedback', '') + # 更新成绩... +``` + +--- + +## 三、新增校验规则(需注意) + +### 3.1 出题接口入参校验 + +`POST /exam/generate` 新增以下校验,不满足时返回 **HTTP 400**,`error_code` 为 `INVALID_PARAMS`: + +| 校验项 | 规则 | 示例(会返回 400) | +|--------|------|-------------------| +| 题型合法性 | `question_types` 的 key 必须属于 5 种题型 | `{"essay": 2}` → 不支持 | +| 题型数量 | 每种题型数量必须为非负整数 | `{"single_choice": -1}` → 不合法 | +| 难度范围 | `difficulty` 必须为 1-5 的整数 | `"difficulty": 10` → 超范围 | +| **总题数上限** | **所有题型数量之和不能超过 20** | `{"single_choice": 15, "true_false": 10}` → 超限 | + +合法的 5 种题型 key:`single_choice`、`multiple_choice`、`true_false`、`fill_blank`、`subjective` + +**后端建议**:在前端提交出题请求时做前置校验,避免不必要的网络请求。 + +### 3.2 批卷接口 question_type 校验 + +`POST /exam/grade` 的 `answers` 数组中,每道题的 `question_type` 现在也会校验。无效值返回 **HTTP 400**。 + +```json +// 返回 400 +{"answers": [{"question_type": "essay", ...}]} + +// 错误信息 +{"error_code": "INVALID_PARAMS", "message": "第 1 题的 question_type 无效: essay,合法值: fill_blank, multiple_choice, single_choice, subjective, true_false"} +``` + +### 3.3 错误响应格式 + +校验失败统一返回: +```json +{ + "success": false, + "error_code": "INVALID_PARAMS", + "message": "具体错误描述", + "status": "failed", + "status_code": 4000 +} +``` + +--- + +## 三点五、跨调用去重:`exclude_stems`(强烈建议使用) + +### 背景问题 + +同一份文档多次调用出题接口时,由于知识点来源相同,新生成的题目很可能与已有题目高度重复。单次调用上限 20 道,当需要更多题目时,这个问题尤为突出。 + +### 解决方式 + +两个出题接口(`/exam/generate` 和 `/exam/generate-smart`)新增可选参数 `exclude_stems`,后端把该文件已入库的题目题干传过来,RAG 在生成后自动排除匹配的题目。 + +**请求示例**: +```json +POST /exam/generate +{ + "file_path": "public_kb/产品手册.pdf", + "collection": "public_kb", + "question_types": {"single_choice": 10}, + "exclude_stems": [ + "重购率的定义是下列哪一项?", + "以下哪项属于现代终端分类?", + "客户满意度的计算公式为___" + ] +} +``` + +### 参数说明 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `exclude_stems` | string[] | 否 | 已有题目的题干列表,最多 100 条 | + +### 去重策略 + +- 基于题干前 80 个字符进行匹配 +- 新生成的题目如果与 `exclude_stems` 中任意一条匹配,会被自动过滤 +- 不传或传空数组时行为不变(向后兼容) + +### 后端使用流程 + +``` +第一次出题: +POST /exam/generate { question_types: {...} } +→ 返回 20 道新题 → 审核后入库 + +第二次出题(想多出 10 道选择题): +1. 查询数据库,获取该文件已有的所有题目题干 +2. POST /exam/generate { + question_types: {"single_choice": 10}, + exclude_stems: ["已有题干1", "已有题干2", ...] + } +→ 返回 10 道不与已有题目重复的新题 +``` + +**后端代码示例**: +```python +def generate_more_questions(file_path, collection, question_types): + # 1. 查询该文件已有的题目题干 + existing_stems = db.query(""" + SELECT JSON_EXTRACT(content, '$.stem') + FROM questions + WHERE source_file = ? + """, [file_path]) + + # 2. 调用出题接口,传入已有题干 + response = requests.post('http://rag-service:5001/exam/generate', json={ + 'file_path': file_path, + 'collection': collection, + 'question_types': question_types, + 'exclude_stems': [row[0] for row in existing_stems] + }) + + return response.json() +``` + +--- + +## 四、新增字段(可选消费) + +### 4.1 出题结果新增字段 + +`POST /exam/generate` 和 `POST /exam/generate-smart` 的 `data` 对象新增三个字段: + +```json +{ + "data": { + "questions": [...], + "total": 8, + "requested_types": {"single_choice": 5, "true_false": 3, "fill_blank": 2}, + "actual_types": {"single_choice": 5, "true_false": 3, "fill_blank": 0}, + "warnings": ["fill_blank: 请求 2 道,实际生成 0 道"], + ... + } +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `requested_types` | object | 后端请求的题型和数量(原样回传) | +| `actual_types` | object | 实际生成的题型和数量 | +| `warnings` | string[] | 短缺提示数组,全部生成成功时为空数组 | + +**后端建议**:检查 `warnings` 是否为空,不为空时可提示用户"部分题型生成不足",或自动补发请求。 + +### 4.2 主观题评分警告 + +当主观题的 `content` 中缺少 `data.scoring_points` 评分标准时,批卷结果会在 `details.warnings` 中给出提示: + +```json +{ + "question_id": "q5", + "score": 7.0, + "max_score": 10.0, + "grading_status": "success", + "details": { + "scoring_breakdown": [...], + "overall_feedback": "...", + "warnings": ["缺少评分标准(scoring_points),评分结果仅供参考"] + } +} +``` + +此时 `grading_status` 仍为 `"success"`,但评分准确度可能受影响。后端可在前端展示时附上"评分仅供参考"的提示。 + +--- + +## 五、完整的出题→入库→批卷数据流(更新后) + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ 后端完整流程 │ +│ │ +│ 1. 调用出题接口 │ +│ POST /exam/generate │ +│ → 首次出题:不传 exclude_stems │ +│ → 追加出题:查询已有题干,传入 exclude_stems 避免重复 │ +│ → 返回 questions[],每题包含 question_type, content, source_trace │ +│ → 检查 warnings 是否有短缺提示 │ +│ │ +│ 2. 审核入库(后端自行决定) │ +│ → 可删除/修改不满意的题目 │ +│ → 存入数据库时保留 content 字段原样 │ +│ → 生成 question_id (UUID),设置 max_score │ +│ │ +│ 3. 学生作答 │ +│ → 收集 student_answer │ +│ │ +│ 4. 调用批卷接口 │ +│ POST /exam/grade │ +│ → content 直接从数据库取出透传(与出题接口返回的结构一致) │ +│ → 检查 grading_status 判断每题是否评分成功 │ +│ → grading_status=failed 的题目可标记待重批 │ +│ │ +│ 5. 更新成绩 │ +│ → 根据 question_id 匹配结果,写入学生成绩表 │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + +**关键要点**:出题返回的 `content` 和批卷接收的 `content` 结构完全一致,后端只需原样存取即可,无需任何字段转换。 + +--- + +## 六、后端修改清单 + +| 序号 | 修改项 | 紧急程度 | 说明 | +|------|--------|----------|------| +| 1 | 批卷请求 `question_content` 改为 `content` | **必须** | 否则批卷接口无法读取题目内容,所有评分失败 | +| 2 | 批卷结果解析改用 `grading_status` + `details` | **必须** | 否则无法正确获取评分详情 | +| 3 | 处理 `grading_status: "failed"` 情况 | **建议** | 避免将 LLM 异常导致的 0 分直接记入成绩 | +| 4 | **追加出题时传入 `exclude_stems`** | **强烈建议** | 避免同一文件多次出题产生重复题目 | +| 5 | 出题请求总题数控制在 20 以内 | **建议** | 否则返回 400 错误 | +| 6 | 前端校验 question_types 和 difficulty | **建议** | 减少无效请求 | +| 7 | 消费 `warnings` 字段做短缺提示 | 可选 | 提升用户体验 | +| 8 | 消费主观题 `details.warnings` | 可选 | 提示评分可信度 | diff --git a/docs/ai/出题批题后端对接指南.md b/docs/ai/出题批题后端对接指南.md deleted file mode 100644 index 0b672eb..0000000 --- a/docs/ai/出题批题后端对接指南.md +++ /dev/null @@ -1,468 +0,0 @@ -# 出题批题接口 - 后端对接指南 - -## 一、接口概览 - -| 接口 | 方法 | 功能 | 超时建议 | -|------|------|------|----------| -| `/exam/generate` | POST | 生成题目 | 120秒 | -| `/exam/grade` | POST | 批阅答案 | 60秒 | - ---- - -## 二、出题接口 - -### 2.1 请求 - -``` -POST /exam/generate -Content-Type: application/json -``` - -**请求体字段说明:** - -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| `file_path` | string | ✅ | 文档路径(相对于 documents 目录) | -| `collection` | string 或 string[] | ✅ | 向量库名称,支持数组(按优先级顺序检索,找到文件即停止) | -| `question_types` | object | ✅ | 题型及数量 | -| `difficulty` | int | ❌ | 难度等级 1-5,默认 3 | -| `request_id` | string | ❌ | 请求ID,相同ID返回缓存结果(幂等性) | - -**请求示例:** - -```json -{ - "file_path": "薪酬制度.docx", - "collection": ["dept_hr", "public_kb"], - "question_types": { - "single_choice": 3, - "multiple_choice": 2, - "true_false": 2, - "fill_blank": 2, - "subjective": 1 - }, - "difficulty": 3, - "request_id": "uuid-for-idempotency" -} -``` - -> **collection 检索逻辑说明**: -> - 出题接口采用**按优先级顺序检索**策略 -> - 先在 `dept_hr` 中查找文件,找到则停止 -> - 未找到则继续在 `public_kb` 中查找 -> - 这与 RAG 问答接口的**并行检索+融合**策略不同 -> - 原因:出题需要特定文件的完整内容,而非广泛搜索 - -### 2.2 响应 - -**成功响应:** - -```json -{ - "success": true, - "status": "success", - "status_code": 2011, - "message": "出题完成", - "data": { - "request_id": "uuid-xxx", - "total": 10, - "source_chunks_used": 25, - "questions": [ - { - "question_type": "single_choice", - "difficulty": 3, - "content": { - "stem": "题干内容", - "data": { - "options": [ - {"key": "A", "content": "选项A"}, - {"key": "B", "content": "选项B"}, - {"key": "C", "content": "选项C"}, - {"key": "D", "content": "选项D"} - ] - }, - "answer": "B", - "explanation": "答案解析" - }, - "source_trace": { - "document_name": "薪酬制度.docx", - "chunks_count": 3 - } - } - ] - } -} -``` - -**失败响应:** - -```json -{ - "success": false, - "status": "failed", - "error_code": "FILE_NOT_FOUND", - "message": "文件不存在" -} -``` - -### 2.3 返回字段说明 - -**RAG 服务返回的字段(后端需存储):** - -| 字段 | 类型 | 说明 | 后端是否需要存储 | -|------|------|------|------------------| -| `question_type` | string | 题型 | ✅ 存储 | -| `difficulty` | int | 难度 1-5 | ✅ 存储 | -| `content` | object | 题目内容 | ✅ 存储 | -| `content.stem` | string | 题干 | ✅ | -| `content.data` | object | 附加数据(选项、评分标准等) | ✅ | -| `content.answer` | any | 正确答案 | ✅ 批阅时需要 | -| `content.explanation` | string | 答案解析 | ✅ | -| `source_trace` | object | 来源追踪 | ✅ 存储 | - -**后端需要自己生成的字段:** - -| 字段 | 说明 | -|------|------| -| `question_id` | UUID,唯一标识 | -| `score` | 满分,根据业务需求设定 | -| `tags` | 标签 | -| `status` | 状态(待审核/已通过/已拒绝) | - -> **重要**:RAG 服务不返回 `score` 字段,分值由后端在入库时指定。 - -### 2.4 题型格式对照表 - -| 题型 | question_type | content.answer 格式 | content.data | -|------|---------------|---------------------|--------------| -| 单选题 | `single_choice` | `"B"` | `{options: [{key, content}]}` | -| 多选题 | `multiple_choice` | `["A", "C"]` | `{options: [{key, content}]}` | -| 判断题 | `true_false` | `"T"` 或 `"F"` | 无 | -| 填空题 | `fill_blank` | `[["答案1"], ["答案2", "同义词"]]` | `{blank_count: 2}` | -| 简答题 | `subjective` | `"参考范文..."` | `{scoring_points: [...]}` | - -### 2.5 错误码 - -| 错误码 | HTTP | 说明 | -|--------|------|------| -| `FILE_NOT_FOUND` | 404 | 指定文件不存在 | -| `COLLECTION_NOT_FOUND` | 404 | 指定向量库不存在 | -| `NO_CONTENT` | 400 | 文件内容为空,无法出题 | -| `LLM_ERROR` | 500 | LLM 调用失败 | -| `PARSE_ERROR` | 500 | 解析失败 | - ---- - -## 三、批阅接口 - -### 3.1 请求 - -``` -POST /exam/grade -Content-Type: application/json -``` - -**请求体字段说明:** - -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| `request_id` | string | ❌ | 请求ID,用于追踪 | -| `answers` | array | ✅ | 答案列表 | - -**answers 数组中每个对象的字段:** - -| 字段 | 类型 | 必需 | 说明 | 来源 | -|------|------|------|------|------| -| `question_id` | string | ✅ | 题目ID | 后端数据库 | -| `question_type` | string | ✅ | 题型 | 后端数据库 | -| `question_content` | object | ✅ | 题目内容(含正确答案) | 后端数据库 | -| `student_answer` | any | ✅ | 学生答案 | 学生提交 | -| `max_score` | number | ✅ | 满分 | 后端数据库 | - -**请求示例:** - -```json -{ - "request_id": "grade-uuid-xxx", - "answers": [ - { - "question_id": "q-001", - "question_type": "single_choice", - "question_content": { - "stem": "根据公司规定,员工薪资由哪几部分组成?", - "data": { - "options": [ - {"key": "A", "content": "基本工资+奖金"}, - {"key": "B", "content": "基本工资+绩效奖金+津贴补贴"}, - {"key": "C", "content": "基本工资+加班费"}, - {"key": "D", "content": "基本工资"} - ] - }, - "answer": "B" - }, - "student_answer": "B", - "max_score": 5.0 - }, - { - "question_id": "q-002", - "question_type": "multiple_choice", - "question_content": { - "stem": "以下哪些属于绩效奖金的评定因素?", - "data": { - "options": [ - {"key": "A", "content": "工作质量"}, - {"key": "B", "content": "工作态度"}, - {"key": "C", "content": "考勤情况"}, - {"key": "D", "content": "团队协作"} - ] - }, - "answer": ["A", "B", "D"] - }, - "student_answer": ["A", "B"], - "max_score": 4.0 - }, - { - "question_id": "q-003", - "question_type": "true_false", - "question_content": { - "stem": "公司规定员工每月绩效奖金上限为工资的20%。", - "answer": "F" - }, - "student_answer": "T", - "max_score": 2.0 - }, - { - "question_id": "q-004", - "question_type": "fill_blank", - "question_content": { - "stem": "员工薪资由___、___和___三部分组成。", - "data": {"blank_count": 3}, - "answer": [["基本工资"], ["绩效奖金", "绩效"], ["津贴补贴", "补贴"]] - }, - "student_answer": ["基本工资", "绩效奖金", "交通补贴"], - "max_score": 6.0 - }, - { - "question_id": "q-005", - "question_type": "subjective", - "question_content": { - "stem": "请简述公司薪酬制度的核心原则。", - "data": { - "scoring_points": [ - {"point": "公平性", "weight": 0.3}, - {"point": "激励性", "weight": 0.3}, - {"point": "竞争力", "weight": 0.2}, - {"point": "合法性", "weight": 0.2} - ] - }, - "answer": "公司薪酬制度遵循公平、激励、竞争、合法四大原则..." - }, - "student_answer": "我认为公司的薪酬制度应该公平公正...", - "max_score": 10.0 - } - ] -} -``` - -### 3.2 响应 - -**成功响应:** - -```json -{ - "success": true, - "status": "success", - "status_code": 2012, - "message": "批阅完成", - "data": { - "request_id": "grade-uuid-xxx", - "total_score": 14.0, - "total_max_score": 27.0, - "score_rate": 51.85, - "results": [ - { - "question_id": "q-001", - "question_type": "single_choice", - "score": 5.0, - "max_score": 5.0, - "is_correct": true, - "student_answer": "B", - "correct_answer": "B", - "feedback": "回答正确" - }, - { - "question_id": "q-002", - "question_type": "multiple_choice", - "score": 2.0, - "max_score": 4.0, - "is_correct": false, - "student_answer": ["A", "B"], - "correct_answer": ["A", "B", "D"], - "feedback": "少选了 D 选项,正确答案: A, B, D" - }, - { - "question_id": "q-003", - "question_type": "true_false", - "score": 0.0, - "max_score": 2.0, - "is_correct": false, - "student_answer": "T", - "correct_answer": "F", - "feedback": "正确答案: F" - }, - { - "question_id": "q-004", - "question_type": "fill_blank", - "score": 4.0, - "max_score": 6.0, - "is_correct": false, - "student_answer": ["基本工资", "绩效奖金", "交通补贴"], - "correct_answer": [["基本工资"], ["绩效奖金", "绩效"], ["津贴补贴", "补贴"]], - "feedback": "第1、2空正确,第3空答案应为:津贴补贴或补贴" - }, - { - "question_id": "q-005", - "question_type": "subjective", - "score": 3.0, - "max_score": 10.0, - "is_correct": false, - "student_answer": "我认为公司的薪酬制度应该公平公正...", - "correct_answer": "公司薪酬制度遵循公平、激励、竞争、合法四大原则...", - "feedback": "得分点:提到公平性概念,但未展开说明激励性和竞争力原则" - } - ] - } -} -``` - -### 3.3 返回字段说明 - -| 字段 | 类型 | 说明 | -|------|------|------| -| `total_score` | number | 总得分 | -| `total_max_score` | number | 总满分 | -| `score_rate` | number | 得分率(百分比) | -| `results` | array | 每道题的批阅结果 | -| `results[].question_id` | string | 题目ID | -| `results[].score` | number | 该题得分 | -| `results[].max_score` | number | 该题满分 | -| `results[].is_correct` | boolean | 是否完全正确 | -| `results[].feedback` | string | 批阅反馈 | - -### 3.4 批阅规则 - -| 题型 | 批阅方式 | 得分规则 | -|------|----------|----------| -| 单选题 | 精确匹配 | 正确得满分,错误得 0 | -| 多选题 | 集合比对 | 全对满分,少选得一半,错选得 0 | -| 判断题 | 精确匹配 | 正确得满分,错误得 0 | -| 填空题 | 多答案匹配 | 每空独立评分,支持同义词匹配 | -| 简答题 | LLM 评分 | 根据得分点评分,不超过 `max_score` | - -### 3.5 错误码 - -| 错误码 | HTTP | 说明 | -|--------|------|------| -| `INVALID_ANSWER_FORMAT` | 400 | 答案格式不正确 | -| `GRADING_ERROR` | 500 | 批阅过程出错 | - ---- - -## 四、完整调用流程 - -### 4.1 出题流程 - -``` -后端调用 /exam/generate - │ - ▼ - RAG 返回题目 - (question_type, difficulty, content, source_trace) - │ - ▼ - 后端生成 question_id - 后端设置 score (满分) - 后端设置 status - │ - ▼ - 后端存入数据库 -``` - -### 4.2 批阅流程 - -``` -学生提交答案 - │ - ▼ - 后端从数据库查询: - - question_id - - question_type - - question_content (含正确答案) - - score (满分) - │ - ▼ - 后端组装请求调用 /exam/grade - │ - ▼ - RAG 返回批阅结果 - (score, feedback, is_correct) - │ - ▼ - 后端存入成绩表 -``` - ---- - -## 五、字段来源速查表 - -### 5.1 出题接口 - -| 字段 | 返回方 | 存储方 | 说明 | -|------|--------|--------|------| -| question_id | ❌ 不返回 | 后端生成 | UUID | -| question_type | ✅ RAG | 后端存储 | 题型 | -| difficulty | ✅ RAG | 后端存储 | 难度 1-5 | -| content | ✅ RAG | 后端存储 | 题目内容 | -| source_trace | ✅ RAG | 后端存储 | 来源追踪 | -| **score** | ❌ 不返回 | **后端设定** | 满分 | -| tags | ❌ 不返回 | 后端设定 | 标签 | -| status | ❌ 不返回 | 后端设定 | 状态 | - -### 5.2 批阅接口 - -| 字段 | 来源 | 说明 | -|------|------|------| -| question_id | 后端数据库 | 题目唯一标识 | -| question_type | 后端数据库 | 题型 | -| question_content | 后端数据库 | 题目内容(含正确答案) | -| student_answer | 学生提交 | 学生作答 | -| **max_score** | **后端数据库** | 满分(决定得分上限) | - ---- - -## 六、常见问题 - -### Q1: 出题接口返回的题目需要审核吗? - -建议后端设置 `status` 字段进行审核流程,审核通过后再用于组卷。 - -### Q2: 分值如何动态调整? - -后端在入库时自由设定 `score` 字段,批阅时传入 `max_score` 即可。RAG 服务不干预分值。 - -### Q3: 填空题同义词匹配是如何实现的? - -填空题答案格式为 `[["主答案", "同义词1", "同义词2"], ...]`,学生答案匹配任意一个即视为正确。 - -### Q4: 批阅接口超时怎么办? - -建议: -- 单次批阅不超过 50 道题 -- 设置 60 秒超时 -- 主观题较多时适当延长 - ---- - -**文档版本**: v1.1 -**更新时间**: 2026-05-17 -**相关文档**: [后端对接规范.md](./后端对接规范.md) diff --git a/docs/error.txt b/docs/error.txt deleted file mode 100644 index f4876bb..0000000 --- a/docs/error.txt +++ /dev/null @@ -1,109 +0,0 @@ -index-DxCaeH_z.js:504 POST http://47.116.16.222/api/exam/record/103edf6a-e026-4314-889f-4187f6b44147/submit 500 (Internal Server Error) -(匿名) @ index-DxCaeH_z.js:504 -xhr @ index-DxCaeH_z.js:504 -dispatchRequest @ index-DxCaeH_z.js:506 -Promise.then -_request @ index-DxCaeH_z.js:510 -request @ index-DxCaeH_z.js:506 -(匿名) @ index-DxCaeH_z.js:510 -(匿名) @ index-DxCaeH_z.js:502 -submit @ index-DxCaeH_z.js:659 -fn @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 [提交] submit(结束考试) 失败: -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 message: 系统异常 -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 HTTP状态: 500 -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 响应数据: {"code":500,"message":"系统异常","data":null,"timestamp":"2026-06-01 08:44:52","success":false} -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 响应头: {"connection":"keep-alive","content-type":"application/json","date":"Mon, 01 Jun 2026 08:44:52 GMT","server":"nginx/1.18.0 (Ubuntu)","transfer-encoding":"chunked","vary":"Origin, Access-Control-Request-Method, Access-Control-Request-Headers"} -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 请求URL: /api/exam/record/103edf6a-e026-4314-889f-4187f6b44147/submit -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 请求方法: post -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:659 [examAPI] 正式考试提交批改 - recordId: 103edf6a-e026-4314-889f-4187f6b44147 题目数: 5 -index-DxCaeH_z.js:707 [提交] gradeExamRecord(空答案) 失败: -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 message: 提交失败: Index 0 out of bounds for length 0 -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 完全无响应对象, error keys: -yt @ index-DxCaeH_z.js:707 -ft @ index-DxCaeH_z.js:707 -await in ft -Bt @ index-DxCaeH_z.js:709 -createBaseVNode.onClick.fn..fn. @ index-DxCaeH_z.js:709 -callWithErrorHandling @ index-DxCaeH_z.js:16 -callWithAsyncErrorHandling @ index-DxCaeH_z.js:16 -ee @ index-DxCaeH_z.js:22 -index-DxCaeH_z.js:707 [提交] 所有2种提交方式均失败 \ No newline at end of file diff --git a/docs/sql/knowledge_management_system.sql b/docs/sql/knowledge_management_system.sql index 90e2784..0eceff8 100644 --- a/docs/sql/knowledge_management_system.sql +++ b/docs/sql/knowledge_management_system.sql @@ -3,15 +3,15 @@ Source Server : yun Source Server Type : MySQL - Source Server Version : 80045 (8.0.45-0ubuntu0.22.04.1) + Source Server Version : 80046 (8.0.46-0ubuntu0.22.04.2) Source Host : 127.0.0.1:3306 Source Schema : knowledge_management_system Target Server Type : MySQL - Target Server Version : 80045 (8.0.45-0ubuntu0.22.04.1) + Target Server Version : 80046 (8.0.46-0ubuntu0.22.04.2) File Encoding : 65001 - Date: 02/06/2026 16:34:39 + Date: 10/06/2026 20:42:07 */ SET NAMES utf8mb4; @@ -43,16 +43,14 @@ CREATE TABLE `collection` ( INDEX `idx_department`(`department` ASC) USING BTREE, INDEX `idx_owner_type`(`owner_type` ASC) USING BTREE, INDEX `idx_visibility`(`visibility` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库存放路径表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库存放路径表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of collection -- ---------------------------- -INSERT INTO `collection` VALUES (17, 'test1', '/knowledge/dept', '1', '总公司', 'department', 'public', NULL, '', '', '2026-05-16 13:44:10', '2026-05-28 22:46:59', 'LATEST', NULL, NULL); -INSERT INTO `collection` VALUES (19, 'dept_2_kb', '/knowledge/dept_2_kb', '1', '南京分公司', 'department', 'public', NULL, '部门2知识库', '自动创建的向量库', '2026-05-29 10:36:15', '2026-05-29 19:17:30', 'LATEST', NULL, NULL); -INSERT INTO `collection` VALUES (20, 'dept_3_kb', '/knowledge/dept_3_kb', '1', '技术部', 'department', 'public', NULL, '部门3知识库', '自动创建的向量库', '2026-05-29 10:49:55', '2026-05-29 19:17:32', 'LATEST', NULL, NULL); -INSERT INTO `collection` VALUES (21, 'dept_4_kb', '/knowledge/dept_4_kb', '1', '采购部门', 'department', 'public', NULL, '部门4知识库', '自动创建的向量库', '2026-05-29 12:01:46', '2026-05-29 12:01:46', 'LATEST', NULL, NULL); -INSERT INTO `collection` VALUES (22, 'dept_6_kb', '/knowledge/dept_6_kb', '1', '人事部门', 'department', 'public', NULL, '部门6知识库', '自动创建的向量库', '2026-05-30 14:39:29', '2026-05-30 14:39:29', 'LATEST', NULL, NULL); +INSERT INTO `collection` VALUES (23, 'dept_1_kb', '/knowledge/dept_1_kb', '1', '总公司', 'department', 'public', NULL, '部门1知识库', '自动创建的向量库', '2026-06-02 14:05:53', '2026-06-02 14:05:53', 'LATEST', NULL, NULL); +INSERT INTO `collection` VALUES (28, 'dept_3_kb', '/knowledge/dept_3_kb', '1', '技术部', 'department', 'public', NULL, '部门3知识库', '自动创建的向量库', '2026-06-10 04:58:28', '2026-06-10 04:58:28', 'LATEST', NULL, NULL); +INSERT INTO `collection` VALUES (30, 'dept_6_kb', '/knowledge/dept_6_kb', '1', '人事部门', 'department', 'public', NULL, '部门6知识库', '自动创建的向量库', '2026-06-10 06:19:34', '2026-06-10 06:19:34', 'LATEST', NULL, NULL); -- ---------------------------- -- Table structure for collection_file @@ -74,25 +72,16 @@ CREATE TABLE `collection_file` ( INDEX `idx_doc_name`(`doc_name` ASC) USING BTREE, INDEX `idx_file_id`(`file_id` ASC) USING BTREE, CONSTRAINT `fk_collection_file_file` FOREIGN KEY (`file_id`) REFERENCES `file` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '向量库文件关联表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 61 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '向量库文件关联表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of collection_file -- ---------------------------- -INSERT INTO `collection_file` VALUES (26, 'test1', '1.docx', 48, 'resources/rule/总公司/1/v1/1.docx', '.docx', 1, '2026-05-28 22:51:44', '2026-05-29 17:18:41'); -INSERT INTO `collection_file` VALUES (27, 'test1', '2.docx', 22, 'resources/rule/总公司/南京分公司/公共部门/1/v1/2.docx', 'docx', 1, '2026-05-28 22:51:44', '2026-05-29 17:18:47'); -INSERT INTO `collection_file` VALUES (28, 'test1', '3.docx', 23, 'resources/rule/总公司/南京分公司/公共部门/1/v1/3.docx', 'docx', 1, '2026-05-28 22:51:44', '2026-05-29 17:18:54'); -INSERT INTO `collection_file` VALUES (31, 'dept_2_kb', 'longrule.docx', 43, 'resources/rule/总公司/南京分公司/longrule/v2/longrule.docx', '.docx', 1, '2026-05-29 18:36:26', '2026-05-29 18:36:26'); -INSERT INTO `collection_file` VALUES (32, 'dept_3_kb', 'test.docx', 45, 'resources/rule/总公司/南京分公司/技术部/test/v1/test.docx', '.docx', 1, '2026-05-29 18:50:09', '2026-05-29 18:50:09'); -INSERT INTO `collection_file` VALUES (33, 'dept_4_kb', 'longrule.docx', 49, 'resources/rule/总公司/南京分公司/采购部门/longrule/v1/longrule.docx', '.docx', 1, '2026-05-29 20:01:53', '2026-05-29 20:01:53'); -INSERT INTO `collection_file` VALUES (34, 'test1', '作业管理系统测试计划.doc', 57, 'resources/rule/总公司/作业管理系统测试计划/v5/作业管理系统测试计划.doc', '.doc', 1, '2026-05-29 22:04:35', '2026-05-29 22:04:35'); -INSERT INTO `collection_file` VALUES (35, 'dept_4_kb', '作业管理系统测试计划.doc', 54, 'resources/rule/总公司/南京分公司/采购部门/作业管理系统测试计划/v1/作业管理系统测试计划.doc', '.doc', 1, '2026-05-30 21:17:44', '2026-05-30 21:17:44'); -INSERT INTO `collection_file` VALUES (36, 'test1', '需求分析.docx', 59, 'resources/rule/总公司/需求分析/v3/需求分析.docx', '.docx', 1, '2026-05-30 22:06:32', '2026-05-30 22:06:32'); -INSERT INTO `collection_file` VALUES (37, 'dept_6_kb', 'test.docx', 60, 'resources/rule/总公司/南京分公司/人事部门/test/v3/test.docx', '.docx', 1, '2026-05-30 22:39:47', '2026-05-30 22:39:47'); -INSERT INTO `collection_file` VALUES (38, 'dept_4_kb', '需求分析.docx', 61, 'resources/rule/总公司/南京分公司/采购部门/需求分析/v1/需求分析.docx', '.docx', 1, '2026-05-30 22:45:08', '2026-05-30 22:45:08'); -INSERT INTO `collection_file` VALUES (39, 'dept_2_kb', '1.docx', 63, 'resources/rule/总公司/南京分公司/1/v1/1.docx', '.docx', 1, '2026-06-02 14:34:12', '2026-06-02 14:34:12'); -INSERT INTO `collection_file` VALUES (40, 'dept_2_kb', '货源投放工作规范.docx', 67, 'resources/rule/总公司/南京分公司/货源投放工作规范/v4/货源投放工作规范.docx', '.docx', 1, '2026-06-02 14:38:09', '2026-06-02 14:38:09'); -INSERT INTO `collection_file` VALUES (41, 'dept_2_kb', '1.txt', 68, 'resources/rule/总公司/南京分公司/1/v2/1.txt', '.txt', 1, '2026-06-02 16:09:31', '2026-06-02 16:09:31'); +INSERT INTO `collection_file` VALUES (42, 'dept_1_kb', '1.docx', 72, 'resources/rule/总公司/南京分公司/技术部/1/v1/1.docx', '.docx', 1, '2026-06-02 22:06:41', '2026-06-05 16:10:42'); +INSERT INTO `collection_file` VALUES (49, 'dept_1_kb', '需求分析.docx', 74, 'resources/rule/总公司/需求分析/v5/需求分析.docx', '.docx', 1, '2026-06-04 10:23:36', '2026-06-04 10:23:36'); +INSERT INTO `collection_file` VALUES (55, 'dept_1_kb', '3.docx', 71, 'resources/rule/总公司/3/v1/3.docx', '.docx', 1, '2026-06-10 11:48:05', '2026-06-10 11:48:05'); +INSERT INTO `collection_file` VALUES (57, 'dept_3_kb', 'longrule.docx', 76, 'resources/rule/总公司/南京分公司/技术部/longrule/v1/longrule.docx', '.docx', 1, '2026-06-10 13:01:38', '2026-06-10 13:01:38'); +INSERT INTO `collection_file` VALUES (59, 'dept_1_kb', '参考样例.pdf', 79, 'resources/rule/总公司/参考样例/v8/参考样例.pdf', '.pdf', 1, '2026-06-10 13:14:08', '2026-06-10 13:14:08'); -- ---------------------------- -- Table structure for context_conversation @@ -107,17 +96,12 @@ CREATE TABLE `context_conversation` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_user_id`(`user_id` ASC) USING BTREE, INDEX `idx_session_id`(`session_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 63 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文会话表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 73 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文会话表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of context_conversation -- ---------------------------- -INSERT INTO `context_conversation` VALUES (57, 'sess_1780120519597_1wqmohgs2', 1, '用户问: 给我整理一下三峡的资料,最好带点图片', '2026-05-30 05:55:20'); -INSERT INTO `context_conversation` VALUES (58, 'sess_1780120929564_ryg7s3m20', 3, '用户问: 品牌布局规划', '2026-05-30 06:02:10'); -INSERT INTO `context_conversation` VALUES (59, 'sess_1780379728867_z5d8v05yp', 1, '用户问: 确定周供应总量的主要依据有哪些', '2026-06-02 05:55:28'); -INSERT INTO `context_conversation` VALUES (60, 'sess_1780385074333_3ektq0vgx', 1, '用户问: 确定周供应总量的主要依据有哪些', '2026-06-02 07:24:34'); -INSERT INTO `context_conversation` VALUES (61, 'sess_1780386659498_e2i0pli3t', 1, '用户问: 市场状态的计算方式是什么', '2026-06-02 07:50:59'); -INSERT INTO `context_conversation` VALUES (62, 'sess_1780387846575_3rnw6o00w', 1, '用户问: 市场状态的计算方式是什么', '2026-06-02 08:10:46'); +INSERT INTO `context_conversation` VALUES (72, 'sess_1780638743383', 1, '用户问: 市场权重计算公式', '2026-06-05 05:52:23'); -- ---------------------------- -- Table structure for context_image @@ -126,32 +110,25 @@ DROP TABLE IF EXISTS `context_image`; CREATE TABLE `context_image` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `image_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片唯一标识', - `filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '原始文件名', `path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '存储路径', - `size_bytes` bigint NULL DEFAULT NULL COMMENT '文件大小(字节)', - `format` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片格式', `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '来源文档', `page` int NULL DEFAULT NULL COMMENT '来源页码(PDF)', - `page_end` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '结束页码', - `page_range` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '页码范围', `section` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '章节信息', `chunk_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '块类型(chart/image)', - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片类型', `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '图片描述', - `full_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '完整描述', `score` decimal(10, 4) NULL DEFAULT NULL COMMENT '相关性评分', `collection` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属向量库', `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `uk_image_id`(`image_id` ASC) USING BTREE, INDEX `idx_collection`(`collection` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图片存储表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图片存储表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of context_image -- ---------------------------- -INSERT INTO `context_image` VALUES (5, 'dcbee1500209.jpg', NULL, '/app/uploads/img/dcbee1500209.jpg', 261714, 'JPEG', '1.docx', 1, NULL, NULL, NULL, NULL, 'image', '这张图片是一张表格,属于数据图表类型。表格详细列出了不同市场状态下的投放结果评估、市场表现和供求分析、投放策略中可能存在的问题以及优化和改进的初步建议。主要内容包括八个序号的评估项,每个项下有供货面、', '这张图片是一张表格,属于数据图表类型。表格详细列出了不同市场状态下的投放结果评估、市场表现和供求分析、投放策略中可能存在的问题以及优化和改进的初步建议。主要内容包括八个序号的评估项,每个项下有供货面、订货面、订足面的指标和结果,以及对应的市场状态评价、市场表现和供求分析、投放策略中的问题和优化建议。关键信息涉及本地消费需求、供求关系、客户订单满足率、公司货源利用率等,并针对不同情况提出具体的优化措施。', 11.8000, NULL, '2026-06-02 05:57:19'); -INSERT INTO `context_image` VALUES (6, '49d2910b148d.jpg', NULL, '/app/uploads/img/49d2910b148d.jpg', 3004, 'JPEG', '1.docx', 1, NULL, NULL, NULL, NULL, 'image', '这张图片展示了一个数学公式,属于数学表达式类型。公式表示的是一个一级指标(\\(\\xi_i\\))乘以相应的权重(\\(w_i^*\\))。主要内容是数学符号和变量的组合,关键信息在于表示了指标与权重的乘积关', '这张图片展示了一个数学公式,属于数学表达式类型。公式表示的是一个一级指标(\\(\\xi_i\\))乘以相应的权重(\\(w_i^*\\))。主要内容是数学符号和变量的组合,关键信息在于表示了指标与权重的乘积关系。没有数据趋势或数值可描述。', 11.3000, NULL, '2026-06-02 06:03:55'); +INSERT INTO `context_image` VALUES (10, '49d2910b148d.jpg', 'img/49d2910b148d.jpg', '1.docx', 1, NULL, NULL, '这张图片展示了一个数学公式,属于数学表达式类型。公式表示的是一个一级指标(\\(\\xi_i\\))乘以相应的权重(\\(w_i^*\\))。主要内容是数学符号和变量的组合,关键信息在于表示了指标与权重的乘积关', 12.8000, NULL, '2026-06-05 03:57:03'); +INSERT INTO `context_image` VALUES (11, '34d876d1a23b.jpg', 'img/34d876d1a23b.jpg', '1.docx', 1, NULL, NULL, '这张图片是一个占位符图像,显示“WMF/EMF placeholder Use Windows to parse the original image”,表明原始图像未加载或无法解析。图片类型为占位符', 3.5000, NULL, '2026-06-05 03:57:03'); -- ---------------------------- -- Table structure for context_message @@ -171,26 +148,19 @@ CREATE TABLE `context_message` ( `duration_ms` int NULL DEFAULT NULL COMMENT '处理耗时(毫秒)', `images` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '图片信息列表(JSON格式,存储image_id和url)', `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP, - `sources` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '来源信息列表(JSON格式)', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_conversation_id`(`conversation_id` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 171 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文消息表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 188 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文消息表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of context_message -- ---------------------------- -INSERT INTO `context_message` VALUES (159, 57, 'assistant', '品牌布局规划', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\"]', '品牌布局规划相关内容在参考资料中明确提及,具体如下:[ref:1.docx_14]\n\n**(三)制定品牌布局规划** [ref:1.docx_14]\n各地市公司要认真落实《\\*\\*品牌管理办法》《全省\\*\\*品牌发展规划》的要求,明确各价位段主导、护卫和潜力品规[1]: [ref:1.docx_14]\n- **主导品规**:一般有1–4个,属于深受本地消费者喜爱、零售客户欢迎,符合工业企业发展方向,在一定时期本地市场所属价位段内具有相当规模的品规; [ref:1.docx_14]\n- **护卫品规**:一般有2–5个,属于本地有相当数量消费者喜爱、零售客户欢迎,符合工业企业发展方向,在一定时期本地市场所属价位段内有一定规模的品规; [ref:1.docx_14]\n- **潜力品规**:属于开始被本地消费者接受,受到一定数量消费者欢迎,消费需求不断增加,符合工业企业发展方向,在本地市场处于上升期的品规[ref:1.docx_14]。 \n\n品规的市场地位应结合地市公司品牌发展规划,按照区域品牌培育一体化品牌规划管理联动机制要求,以年度为单位进行确定,可视品规的市场表现每半年进行调整[ref:1.docx_25]。要通过持续的品牌培育和市场引导,在各价位段形成**梯次化、有层次的品牌布局**,给消费者、零售客户更多的选择、替代和补充[1][ref:1.docx_14]。\n\n此外,关于护卫品规和潜力品规的投放要求进一步强化了品牌布局的动态协同性: [ref:1.docx_14]\n- 当主导品规供应不足或需调整状态时,应增加护卫和潜力品规的投放强度; [ref:1.docx_40]\n- 每周“主导品规+护卫品规”投放量不低于该价位段投放总量的85%(或“主导品规+潜力品规”不低于80%); [ref:1.docx_40]\n- 要加强对护卫品规和潜力品规的市场培育,使其逐步成长壮大,努力形成稳定、有层次的供给能力(高价位和低价位\\*\\*可不参照执行)[2][ref:1.docx_40]。\n\n综上,品牌布局规划的核心是:**按价位段分类管理(主导/护卫/潜力)、年度定标+半年动态调整、梯次化培育、投放协同支撑**[ref:1.docx_40]。\n\n引用编号: \n[1] —— 对应原文中“(三)制定品牌布局规划”全部内容; [ref:1.docx_14]\n[2] —— 对应原文中“(二)货源投放要求”下“8.关于护卫品规和潜力品规投放”部分[ref:1.docx_40]。', NULL, 110075, NULL, '2026-05-30 05:57:10', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"2.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":4,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (160, 58, 'assistant', '品牌布局规划', 'rag', 1, NULL, '[\"test1\"]', '品牌布局规划相关内容在参考资料中明确体现于 **“(三)制定品牌布局规划”** 部分,具体如下:[ref:1.docx_14]\n\n各地市公司要认真落实《\\*\\*品牌管理办法》《全省\\*\\*品牌发展规划》的要求,明确各价位段的**主导品规、护卫品规和潜力品规**,并实施梯次化、有层次的品牌布局:[ref:1.docx_14]\n\n- **主导品规**:一般有1–4个,属于深受本地消费者喜爱、零售客户欢迎,符合工业企业发展方向,在一定时期本地市场所属价位段内具有相当规模的品规; [ref:1.docx_14]\n- **护卫品规**:一般有2–5个,属于本地有相当数量消费者喜爱、零售客户欢迎,符合工业企业发展方向,在一定时期本地市场所属价位段内有一定规模的品规; [ref:1.docx_14]\n- **潜力品规**:属于开始被本地消费者接受,受到一定数量消费者欢迎,消费需求不断增加,符合工业企业发展方向,在本地市场处于上升期的品规[ref:1.docx_14]。\n\n品规的市场地位应结合地市公司品牌发展规划,按照**区域品牌培育一体化品牌规划管理联动机制**要求,以**年度为单位进行确定**,并可视品规市场表现**每半年动态调整**[ref:1.docx_25]。目标是通过持续的品牌培育和市场引导,在各价位段形成**梯次化、有层次的品牌布局**,为消费者和零售客户提供更多选择、替代与补充[1][ref:1.docx_14]。\n\n此外,关于护卫品规和潜力品规的投放协同要求也予以明确: [ref:1.docx_14]\n> 当主导品规供应不足或需调整状态时,应增加护卫和潜力品规的投放强度;每周“主导品规+护卫品规”投放量不低于该价位段投放总量的85%(或每周“主导品规+潜力品规”投放量不低于该价位段投放总量的80%);要加强对护卫品规和潜力品规的市场培育,使其逐步成长壮大,努力形成稳定、有层次的供给能力(高价位\\*\\*和低价位\\*\\*可不参照执行)[2][ref:1.docx_40]。\n\n综上,品牌布局规划的核心是:**按价位段分类管理、动态调整品规定位、强化梯队协同培育、实现供给结构优化**[ref:1.docx_40]。\n\n引用编号: \n[1] —— “(三)制定品牌布局规划”全文; [ref:1.docx_14]\n[2] —— “(二)货源投放要求”中第8条关于护卫品规和潜力品规投放的内容[ref:1.docx_40]。', NULL, 95402, NULL, '2026-05-30 06:03:45', '[{\"docName\":\"2.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":4,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (161, 57, 'assistant', '给我整理一下三峡的资料,最好带点图片', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '参考资料中**未提及任何关于“三峡”(如三峡大坝、三峡工程、三峡地区等)的相关信息**,所有内容均围绕吸烟场所管理、证件查验、档案存档、系统故障处理、协议解除、货源公开、终端运营指导等主题展开,涉及的是烟草行业或住宿场所的管理制度与操作规范。\n\n因此,**无法根据所提供的参考资料整理出关于“三峡”的资料,亦无相关图片可提供**。\n\n如需三峡相关资料(如地理、工程、历史、旅游等),需另行提供对应参考资料或明确说明信息来源[ref:2.docx_90]。', NULL, 74400, NULL, '2026-06-02 04:34:29', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"2.docx\",\"docType\":\"other\",\"referenceCount\":2,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"需求分析.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (162, 59, 'assistant', '货源投放的总体要求是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '货源投放的总体要求是:**货源投放是\\*\\*营销的核心业务,总体要求是:**[ref:1.docx_3]\n\n该内容直接出自【参考资料】中标题为“**二、总体要求**”的部分,原文仅此一句,未展开具体条目或进一步说明[1][ref:1.docx_38]。\n\n> 【注】编号[1]对应参考资料中“**二、总体要求**”主题下的唯一陈述句:“货源投放是\\*\\*营销的核心业务,总体要求是:”[ref:1.docx_3]。\n\n其余资料中虽详述了适用范围、投放办法、指标定义、评估策略、监管要求等,但均未对“总体要求”本身作补充性定义或扩展性阐释[ref:1.docx_93]。因此,**参考资料中关于“总体要求”的内容仅有且仅限于此句,无其他条目或细则**[ref:1.docx_40]。', NULL, 110896, '[{\"image_id\":\"dcbee1500209.jpg\",\"url\":\"/api/image/dcbee1500209.jpg/data\"}]', '2026-06-02 05:57:19', '[{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":5,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (163, 59, 'assistant', '关于按档位投放有什么要求', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '参考资料中**未提及“按档位投放”的具体要求**[ref:1.docx_38]。\n\n所有提供的资料均围绕“**按价位段自选投放**”展开,包括其总体要求、价位段划分、规格选择、其他要求(如公平公正、评估测试、灵活调控、指导沟通)、市场状态评价指标体系等,但**全文未出现“按档位投放”这一概念,也未对其设定任何条款、禁止情形或操作要求**[ref:1.docx_102]。\n\n因此,关于“按档位投放有什么要求”,依据现有【参考资料】,**缺少相关依据**[ref:1.docx_38]。', NULL, 109506, '[{\"image_id\":\"dcbee1500209.jpg\",\"url\":\"/api/image/dcbee1500209.jpg/data\"}]', '2026-06-02 06:02:07', '[{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":3,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (164, 59, 'assistant', '市场状态的计算公式是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '市场状态的计算公式为: [ref:1.docx_80]\n**市场状态 = Σ(二级指标均值 × 权重)**,即对各项二级指标的均值分别乘以其对应权重后加总得出[1][ref:1.docx_90]。\n\n该公式在参考资料中多次明确表述,如:“市场状态=+二级指标均值\\*权重”[1];同时图片1也直观展示了该公式的数学形式:一级指标(ξᵢ)与权重(wᵢ*)的乘积关系,印证了加权计算逻辑[图片1][ref:1.docx_79]。\n\n此外,市场状态评价采用“双层双级”指标体系——“双层”指单品规和品规属性聚类,“双级”指市场/零售终端类一级指标与零售客户订货类二级指标,最终通过定量分析确定“俏、紧、平、松、软”五种状态[3][ref:1.docx_56]。', NULL, 83466, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"}]', '2026-06-02 06:03:55', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"2.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":5,\"pages\":\"1\"},{\"docName\":\"需求分析.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (165, 59, 'assistant', '统一货源投放的周期是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '统一货源投放周期为**自然周**[ref:1.docx_24]。\n\n根据参考资料: \n地市公司统一参照**自然周**确定货源投放周期,如遇国家法定节假日,由省公司销售管理处统一调整;两个投放周期之间不能存在交集,且一经执行不得修改[ref:1.docx_24]。地市公司如需调整投放周期,须报省公司销售管理处审核[1][ref:1.docx_24]。\n\n(注:此处引用编号[1]对应参考资料中“(一)统一货源投放周期”部分)[ref:1.docx_24]', NULL, 130165, '[{\"image_id\":\"dcbee1500209.jpg\",\"url\":\"/api/image/dcbee1500209.jpg/data\"}]', '2026-06-02 06:09:19', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":2,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (166, 59, 'assistant', '确定周供应总量的主要依据有哪些', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '根据参考资料,**确定周供应总量的主要依据**如下(严格按资料原文顺序完整列出):[ref:1.docx_43]\n\n1. 地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量[2]; [ref:1.docx_33]\n2. 确定可供货源:下周可供货源量 = 期末库存量 + 本周确定到货量[3]; [ref:1.docx_34]\n3. 当可供货源大于等于下周应销售量时,货源供应总量等于下周应销售量;当可供货源小于下周应销售量时,用其他品规进行替代,替代品规依次为:同价位品规、相邻价位品规、周均销量相同或相近的品规[4][ref:1.docx_34]。\n\n以上三点是资料中明确列出的确定周供应总量的全部依据,无其他条目[ref:1.docx_43]。', NULL, 96896, '[{\"image_id\":\"dcbee1500209.jpg\",\"url\":\"/api/image/dcbee1500209.jpg/data\"}]', '2026-06-02 06:11:50', '[{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":4,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (167, 60, 'assistant', '确定周供应总量的主要依据有哪些', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '根据参考资料,**确定周供应总量的主要依据**在文档中明确列为“(三)确定周供应总量的主要依据”,但资料中**仅完整列出第2条**,其余条目缺失或未提供具体内容。\n\n具体如下:\n\n2. 地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量[ref:货源投放工作规范.docx_33]。[原文重复出现多次,属同一依据项][ref:1.docx_93]\n\n此外,虽未被编号列为“主要依据”的条目,但与周供应总量确定直接相关的**支撑性规则和计算逻辑**还包括:[ref:货源投放工作规范.docx_47]\n\n- 周货源供应总量应根据本月累计销售数量,结合当月、周销售计划完成进度,预排下周应销售量[ref:1.docx_31]。[出自“——应与区域物流分拣配送能力匹配”段落末句] [ref:1.docx_31]\n- 下周可供货源量 = 期末库存量 + 本周确定到货量[ref:货源投放工作规范.docx_34]。[3. 确定可供货源] [ref:货源投放工作规范.docx_34]\n- 当可供货源 ≥ 下周应销售量时,货源供应总量 = 下周应销售量;当可供货源 < 下周应销售量时,采用替代品规(同价位→相邻价位→周均销量相近)进行补充[ref:货源投放工作规范.docx_34]。[4.]\n\n但需特别说明: \n✅ 资料中明确标题为“(三)确定周供应总量的主要依据”的部分,**只提供了第2条内容**; [ref:货源投放工作规范.docx_47]\n❌ **第1条、第3条及后续编号条目在参考资料中缺失**(即无“1.”“3.”等其他 numbered items); \n❌ 也**未见对“主要依据”总数的说明**(如是否共5条、共3条等),无法判断是否遗漏全部或部分[ref:1.docx_43]。\n\n因此,依据所提供资料,**确定周供应总量的主要依据仅有且仅为第2条**,其余依据未在资料中给出[ref:货源投放工作规范.docx_47]。[1] \n\n(注:此处[1]指代资料中所有关于“(三)确定周供应总量的主要依据”的原文位置,因资料未编号引用源,统一视为同一出处)[ref:1.docx_42]', NULL, 114468, '[{\"image_id\":\"dcbee1500209.jpg\",\"url\":\"/api/image/dcbee1500209.jpg/data\"}]', '2026-06-02 07:26:28', '[{\"docName\":\"货源投放工作规范.docx\",\"docType\":\"other\",\"referenceCount\":4,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":5,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (168, 61, 'assistant', '市场状态的计算公式是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '市场状态的计算公式为: [ref:货源投放工作规范.docx_80]\n**市场状态 = 二级指标均值 × 权重** [ref:货源投放工作规范.docx_80]\n\n该公式在参考资料中被多次明确提及,例如: \n> “市场状态=+二级指标均值\\*权重” [多次重复,无独立编号,但属于主题“1.市场状态的计算公式为:”下的核心表述] [ref:货源投放工作规范.docx_80]\n\n此外,资料进一步说明,市场状态评价采用“双层双级”指标体系: [ref:1.docx_56]\n- **双层**:单品规层、品规属性聚类层; [ref:1.docx_56]\n- **双级**:市场和零售终端类的一级指标,以及零售客户订货类的**二级指标**; [ref:1.docx_56]\n而市场状态正是基于这些**二级指标的均值与对应权重的乘积**来计算得出[**\\*\\*市场状态评价指标体系**][ref:货源投放工作规范.docx_90]。\n\n需要注意的是,虽然公式形式简洁(二级指标均值 × 权重),但实际应用中需依据附件2《市场状态评价指标体系》确定具体二级指标(如零售价格指数、终端动销率、社会存销比、订足面等)、各指标权重及评分标准[**\\*\\*市场状态评价指标体系**][ref:1.docx_22]。\n\n综上,参考资料中明确给出了市场状态的通用计算逻辑,即**二级指标均值加权平均**,但未提供完整加权求和的详细展开式(如∑(xᵢ·wᵢ))或具体权重数值表——后者应见于附件2(未在当前资料中呈现)[**\\*\\*市场状态评价指标体系**]。', NULL, 221453, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"}]', '2026-06-02 07:54:40', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"货源投放工作规范.docx\",\"docType\":\"other\",\"referenceCount\":3,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":3,\"pages\":\"1\"},{\"docName\":\"需求分析.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (169, 61, 'assistant', '市场状态的计算方式是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '市场状态的计算公式为: [ref:货源投放工作规范.docx_80]\n**市场状态 = +二级指标均值 × 权重** [ref:货源投放工作规范.docx_80]\n\n该公式在参考资料中被多次明确提及,例如: \n> “市场状态=+二级指标均值\\*权重” [ref:货源投放工作规范.docx_80]\n> “主题:1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重” [ref:货源投放工作规范.docx_80]\n\n此外,资料指出该计算属于“双层双级”市场状态评价指标体系中的**二级指标(零售客户订货类)**层面,即通过对零售客户订货相关指标(如订货面、订足面、订单满足率、货源利用率等)取均值后,乘以其对应权重,加总得出市场状态综合得分[1]。\n\n注:一级指标(如市场类指标:零售价格指数、终端动销率、社会存销比等)与二级指标共同构成完整评价体系,但具体加总方式(如是否线性加权求和)在资料中未给出更详细的数学表达式;所列公式明确指向“二级指标均值×权重”这一核心计算环节[1]。\n\n【图片1说明】 \n图片1展示了一个数学表达式:$\\xi_i \\times w_i^*$,表示某一级指标$\\xi_i$与其标准化权重$w_i^*$的乘积[ref:1.docx_79]。该图用于示意指标加权的基本逻辑,与市场状态计算中“指标×权重”的核心思想一致,可作为权重赋值与指标合成的可视化参考(来源:1.docx 第1页)[1][ref:货源投放工作规范.docx_90]。', NULL, 120122, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"}]', '2026-06-02 07:58:39', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"货源投放工作规范.docx\",\"docType\":\"other\",\"referenceCount\":3,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":2,\"pages\":\"1\"},{\"docName\":\"需求分析.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"}]'); -INSERT INTO `context_message` VALUES (170, 62, 'assistant', '市场状态的计算方式是什么', 'rag', 1, NULL, '[\"test1\",\"dept_2_kb\",\"dept_3_kb\",\"dept_4_kb\",\"dept_6_kb\"]', '市场状态的计算方式在参考资料中有明确说明,存在两种表述,但核心均为加权计算:[ref:1.docx_90]\n\n1. **基础公式**: [ref:1.docx_80]\n 市场状态 = 二级指标均值 × 权重 [ref:1.docx_80]\n 该公式多次重复出现,如资料开头及多处主题中均指出:“市场状态=+二级指标均值\\*权重”[1][ref:1.docx_80]。\n\n2. **更完整的双层结构公式(含一级指标)**: [ref:1.docx_22]\n 在“单一品规评价”部分明确给出: [ref:1.docx_22]\n **市场状态 = Σ(一级指标 × 权重ₙ) + 二级指标均值 × 权重** [ref:1.docx_80]\n 其中强调“一级指标合计权重不低于70%”,且二级指标权重需与一级指标协同确定;指标值通过历史数据散点图研究确定评分标准,权重可采用专家评分法(由营销管理人员、一线人员、工业企业代表、零售客户代表等共同参与)确定[2]。\n\n此外,市场状态最终按总分划分为五档: [ref:1.docx_22]\n- ≥95分:俏 \n- 85–95分(含):紧 [ref:1.docx_22]\n- 70–85分(含):平 [ref:1.docx_90]\n- 50–70分(含):松 [ref:1.docx_22]\n- ≤50分:软[3][ref:1.docx_62]。\n\n综上,市场状态是基于**一级指标加权和 + 二级指标均值加权**的综合得分,属“双层双级”评价体系中的核心输出结果[4][ref:1.docx_90]。\n\n引用编号说明: \n[1] —— 开篇及多处重复的公式“市场状态=+二级指标均值\\*权重”; [ref:1.docx_80]\n[2] —— “(一)单一品规评价”中关于公式、权重设定与指标值确定的完整描述; [ref:1.docx_79]\n[3] —— “状态评价办法与标准”中分档评分标准; [ref:1.docx_94]\n[4] —— “市场状态评价指标体系”部分对“双层双级”体系的定义[5][ref:1.docx_56]。', NULL, 150685, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"}]', '2026-06-02 08:13:17', '[{\"docName\":\"test.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"货源投放工作规范.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"2.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"longrule.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"3.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"},{\"docName\":\"1.docx\",\"docType\":\"other\",\"referenceCount\":8,\"pages\":\"1\"},{\"docName\":\"1.txt\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"9\"},{\"docName\":\"需求分析.docx\",\"docType\":\"other\",\"referenceCount\":1,\"pages\":\"1\"}]'); +INSERT INTO `context_message` VALUES (182, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场状态的计算公式为:市场状态=+二级指标均值\\*权重。这里的“二级指标均值”指的是各个二级指标的平均值,而“权重”则是每个二级指标在整体市场状态评估中的重要性比例。这个公式用于综合评估不同指标对市场状态的影响。\n\n对于市场权重的计算,资料中提到各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。这意味着权重的确定是一个基于专家意见的过程,旨在反映各个指标在市场状态评估中的相对重要性。[ref:1.docx_86]\n\n综上所述,市场权重的计算涉及到确定每个二级指标的均值以及它们各自的权重,而这些权重是通过专家评分来确定的。不过,具体的权重数值或计算步骤在提供的资料中并未详细说明。', NULL, 66805, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-05 05:53:30'); +INSERT INTO `context_message` VALUES (183, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场权重的计算公式并没有直接给出。但是,有提到“市场状态=+二级指标均值\\*权重”,这表明市场状态是通过将各个二级指标的均值乘以相应的权重后相加得到的。\n\n此外,还提到了一级指标合计权重不低于70%,并且各明细指标权重确定可采用专家评分法确定。[ref:1.docx_86]\n\n因此,虽然没有明确的市场权重计算公式,但可以推断市场权重的计算涉及将各个指标的均值乘以相应的权重,并且一级指标的权重总和应不低于70%。', NULL, 61181, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-05 06:04:59'); +INSERT INTO `context_message` VALUES (184, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场权重的计算公式并没有直接给出。但是,有提到“市场状态=+二级指标均值\\*权重”,这表明市场状态的计算涉及二级指标的均值与权重的乘积。\n\n此外,关于权重确定的方法,资料中提到可以采用专家评分法来确定各明细指标的权重,组织专家对各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。[ref:1.docx_86]\n\n因此,虽然没有明确的市场权重计算公式,但可以推断出市场权重的计算可能涉及到将各个二级指标的均值与其对应的权重相乘,然后将这些结果相加得到市场状态的综合值。具体的权重数值需要通过专家评分等方法来确定。', NULL, 67865, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-05 06:18:14'); +INSERT INTO `context_message` VALUES (185, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场权重的计算公式并没有直接给出。但是,有提到“市场状态=+二级指标均值\\*权重”,这表明市场状态的计算涉及到二级指标的均值乘以相应的权重。\n\n此外,还提到“一级指标合计权重不低于70%”,这说明在计算市场状态时,各个一级指标的权重总和应该至少为70%。[ref:1.docx_86]\n\n对于具体的权重确定方法,资料中提到可以采用专家评分法来确定各明细指标的权重,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。[ref:1.docx_86]\n\n综上所述,虽然没有直接提供市场权重的计算公式,但可以推断出市场权重的计算涉及到了二级指标的均值与权重的乘积,以及一级指标权重的合计不低于70%。具体的权重值需要通过专家评分等方法来确定。', NULL, 63932, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-05 06:28:41'); +INSERT INTO `context_message` VALUES (186, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场权重的计算公式并没有直接给出。但是,有提到“市场状态=+二级指标均值\\*权重”,这表明市场状态是通过将各个二级指标的均值乘以相应的权重来计算的。\n\n此外,还提到“一级指标合计权重不低于70%”,这说明在计算市场状态时,需要确保所有一级指标的权重总和至少为70%。[ref:1.docx_86]\n\n对于具体的权重确定方法,资料中提到可以采用专家评分法,组织专家对各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。[ref:1.docx_86]\n\n综上所述,虽然没有直接给出市场权重的计算公式,但可以通过上述信息推断出市场权重的计算方式。', NULL, 60684, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-05 06:37:10'); +INSERT INTO `context_message` VALUES (187, 72, 'assistant', '市场权重计算公式', 'rag', 1, NULL, '[\"dept_1_kb\"]', '根据提供的参考资料,市场权重的计算公式并没有直接给出。但是,有提到“市场状态=+二级指标均值\\*权重”,这表明市场状态是通过将各个二级指标的均值乘以相应的权重来计算的。\n\n此外,还提到“一级指标合计权重不低于70%”,这说明在计算市场状态时,各个一级指标的权重总和必须至少为70%。[ref:1.docx_86]\n\n对于具体的权重确定方法,资料中提到可以采用专家评分法,组织专家对各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。[ref:1.docx_86]\n\n综上所述,虽然没有明确的市场权重计算公式,但可以根据上述信息推断出市场权重的计算方式。', NULL, 61949, '[{\"image_id\":\"49d2910b148d.jpg\",\"url\":\"/api/image/49d2910b148d.jpg/data\"},{\"image_id\":\"34d876d1a23b.jpg\",\"url\":\"/api/image/34d876d1a23b.jpg/data\"}]', '2026-06-06 07:17:19'); -- ---------------------------- -- Table structure for context_reference @@ -200,7 +170,8 @@ CREATE TABLE `context_reference` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '引用ID', `message_id` bigint NOT NULL COMMENT '消息ID', `chunk_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'Chunk唯一ID', - `doc_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件存储路径', + `chunk_index` int NULL DEFAULT NULL COMMENT '全局切片序号', + `collection` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属知识库', `doc_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件展示名称', `doc_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档类型:pdf、word、excel', `page` int NULL DEFAULT NULL COMMENT '起始页码', @@ -215,184 +186,26 @@ CREATE TABLE `context_reference` ( `excerpt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '匹配原文片段', `score` decimal(5, 4) NULL DEFAULT NULL COMMENT '相关性分数(0-1)', `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP, + `file_id` bigint NULL DEFAULT NULL COMMENT '关联的 collection_file 表的 id', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_message_id`(`message_id` ASC) USING BTREE, INDEX `idx_chunk_id`(`chunk_id` ASC) USING BTREE, + INDEX `idx_chunk_index`(`chunk_index` ASC) USING BTREE, + INDEX `idx_collection`(`collection` ASC) USING BTREE, + INDEX `idx_file_id`(`file_id` ASC) USING BTREE, CONSTRAINT `fk_context_reference_message` FOREIGN KEY (`message_id`) REFERENCES `context_message` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 370 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文引用表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 481 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '上下文引用表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of context_reference -- ---------------------------- -INSERT INTO `context_reference` VALUES (201, 159, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (202, 159, '', NULL, '3.docx', 'other', 1, 1, '1', '2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**', 'table', NULL, NULL, NULL, NULL, '', 0.9990, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (203, 159, '', NULL, '2.docx', 'other', 1, 1, '1', '第三章 制定文明吸烟环境建设规划 > **第五条** 制定建设规划', 'text', NULL, NULL, NULL, NULL, '', 0.9710, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (204, 159, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (205, 159, '', NULL, 'test.docx', 'other', 1, 1, '1', '第八条 严格比对人脸与证件信息,发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (206, 159, '1.docx_14', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)制定品牌布局规划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (207, 159, '1.docx_25', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(二)制定月度投放计划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (208, 159, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 05:57:10'); -INSERT INTO `context_reference` VALUES (209, 160, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (210, 160, '', NULL, '3.docx', 'other', 1, 1, '1', '2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**', 'table', NULL, NULL, NULL, NULL, '', 0.9990, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (211, 160, '', NULL, '2.docx', 'other', 1, 1, '1', '第三章 制定文明吸烟环境建设规划 > **第五条** 制定建设规划', 'text', NULL, NULL, NULL, NULL, '', 0.9710, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (212, 160, '1.docx_14', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)制定品牌布局规划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (213, 160, '1.docx_25', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(二)制定月度投放计划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (214, 160, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:03:46'); -INSERT INTO `context_reference` VALUES (215, 160, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (216, 160, '', NULL, '3.docx', 'other', 1, 1, '1', '2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**', 'table', NULL, NULL, NULL, NULL, '', 0.9990, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (217, 160, '', NULL, '2.docx', 'other', 1, 1, '1', '第三章 制定文明吸烟环境建设规划 > **第五条** 制定建设规划', 'text', NULL, NULL, NULL, NULL, '', 0.9710, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (218, 160, '3.docx_144', NULL, '3.docx', 'other', 1, 1, NULL, '1.建设标准:新现代终端每户可配备双屏机、扫码设备及“金丝利·通”智慧门店管理系统。 > **(一)加强统一规划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (219, 160, '1.docx_25', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(二)制定月度投放计划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (220, 160, '1.docx_92', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **货源投放结果评估和优化策略**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (221, 160, '1.docx_14', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)制定品牌布局规划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (222, 160, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 06:06:07'); -INSERT INTO `context_reference` VALUES (223, 159, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (224, 159, '', NULL, '3.docx', 'other', 1, 1, '1', '2.诚信守法经营,三年内无违法记录。 > **零售终端日常维护申请表**', 'table', NULL, NULL, NULL, NULL, '', 0.9990, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (225, 159, '', NULL, '2.docx', 'other', 1, 1, '1', '第三章 制定文明吸烟环境建设规划 > **第五条** 制定建设规划', 'text', NULL, NULL, NULL, NULL, '', 0.9710, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (226, 159, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (227, 159, '', NULL, 'test.docx', 'other', 1, 1, '1', '第八条 严格比对人脸与证件信息,发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (228, 159, '2.docx_75', NULL, '2.docx', 'other', 1, 1, NULL, '第三章 制定文明吸烟环境建设规划 > **第五条** 制定建设规划', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (229, 159, '1.docx_25', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(二)制定月度投放计划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (230, 159, '1.docx_14', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)制定品牌布局规划**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (231, 159, '1.docx_56', NULL, '1.docx', 'other', 1, 1, NULL, '3.按价位段自选投放工作指引 > **\\*\\*市场状态评价指标体系**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (232, 159, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-05-30 07:10:12'); -INSERT INTO `context_reference` VALUES (233, 161, '', NULL, '2.docx', 'other', 1, 1, '1', '第七章 附则 > 附件1', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (234, 161, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十七条 系统出现故障、网络中断时,先手工逐人登记,故障恢复后第一时间补录上传,并做好故障登记记录备案。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (235, 161, '', NULL, '3.docx', 'other', 1, 1, '1', '3.积极配合烟草公司开展新现代终端功能发挥。 > 附件3', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (236, 161, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (237, 161, '', NULL, '1.docx', 'other', 1, 1, '1', '5.新品按照新品上市方案实施供应。 > **(三)货源信息公开**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (238, 161, '2.docx_90', NULL, '2.docx', 'other', 1, 1, NULL, '第七章 吸烟场所的档案资料管理 > **第十六条** 拍照存档', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 04:34:29'); -INSERT INTO `context_reference` VALUES (239, 162, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > ——应与区域物流分拣配送能力匹配。', 'text', NULL, NULL, NULL, NULL, '', 0.4210, '2026-06-02 05:57:19'); -INSERT INTO `context_reference` VALUES (240, 162, '1.docx_38', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 05:57:19'); -INSERT INTO `context_reference` VALUES (241, 162, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 05:57:19'); -INSERT INTO `context_reference` VALUES (242, 162, '1.docx_3', NULL, '1.docx', 'other', 1, 1, NULL, '**二、总体要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 05:57:19'); -INSERT INTO `context_reference` VALUES (243, 162, '1.docx_93', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **货源投放结果评估和优化策略**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 05:57:19'); -INSERT INTO `context_reference` VALUES (244, 163, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(一)客户分档**', 'text', NULL, NULL, NULL, NULL, '', 0.9760, '2026-06-02 06:02:07'); -INSERT INTO `context_reference` VALUES (245, 163, '1.docx_38', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:02:07'); -INSERT INTO `context_reference` VALUES (246, 163, '1.docx_102', NULL, '1.docx', 'other', 1, 1, NULL, '2.如果人为设置单品规投放限量过低(如1条),会推高订足面。 > **四、其他要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:02:07'); -INSERT INTO `context_reference` VALUES (247, 164, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (248, 164, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (249, 164, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (250, 164, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '1.心理健康工作将全面提质增效,坚持“健康第一”理念。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (251, 164, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (252, 164, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (253, 164, '1.docx_56', NULL, '1.docx', 'other', 1, 1, NULL, '3.按价位段自选投放工作指引 > **\\*\\*市场状态评价指标体系**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (254, 164, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (255, 164, '1.docx_90', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (256, 164, '1.docx_79', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:03:55'); -INSERT INTO `context_reference` VALUES (257, 165, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 0.9980, '2026-06-02 06:09:19'); -INSERT INTO `context_reference` VALUES (258, 165, '', NULL, '3.docx', 'other', 1, 1, '1', '4.自愿使用“金丝利·通”智慧门店管理系统进行全店铺、全商品的管理,自愿学习并具备熟练操作的能力。 > **“金丝利零售”加盟终端建成验收报告**', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:09:19'); -INSERT INTO `context_reference` VALUES (259, 165, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十五条 严禁泄露、倒卖、私自查阅旅客身份登记信息,保护旅客个人隐私与信息安全。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:09:19'); -INSERT INTO `context_reference` VALUES (260, 165, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '1.心理健康工作将全面提质增效,坚持“健康第一”理念。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:09:19'); -INSERT INTO `context_reference` VALUES (261, 165, '1.docx_24', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(一)统一货源投放周期**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:09:19'); -INSERT INTO `context_reference` VALUES (262, 166, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 0.9980, '2026-06-02 06:11:50'); -INSERT INTO `context_reference` VALUES (263, 166, '1.docx_34', NULL, '1.docx', 'other', 1, 1, NULL, '3.确定可供货源:下周可供货源量=期末库存量+本周确定到货\\*\\*量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:11:50'); -INSERT INTO `context_reference` VALUES (264, 166, '1.docx_33', NULL, '1.docx', 'other', 1, 1, NULL, '2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:11:50'); -INSERT INTO `context_reference` VALUES (265, 166, '1.docx_43', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(四)特殊客户供货**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:11:50'); -INSERT INTO `context_reference` VALUES (266, 164, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (267, 164, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (268, 164, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (269, 164, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '1.心理健康工作将全面提质增效,坚持“健康第一”理念。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (270, 164, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (271, 164, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (272, 164, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (273, 164, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:34:13'); -INSERT INTO `context_reference` VALUES (274, 164, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '1.市场状态的计算公式为:', 'text', NULL, NULL, NULL, NULL, '', 0.0010, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (275, 164, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (276, 164, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (277, 164, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (278, 164, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (279, 164, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (280, 164, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (281, 164, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (282, 164, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (283, 164, '1.docx_90', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (284, 164, '货源投放工作规范.docx_79', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:45:11'); -INSERT INTO `context_reference` VALUES (285, 164, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '1.市场状态的计算公式为:', 'text', NULL, NULL, NULL, NULL, '', 0.0010, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (286, 164, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (287, 164, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (288, 164, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (289, 164, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (290, 164, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (291, 164, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (292, 164, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (293, 164, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (294, 164, '1.docx_90', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (295, 164, '货源投放工作规范.docx_79', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 06:49:20'); -INSERT INTO `context_reference` VALUES (296, 164, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '1.市场状态的计算公式为:', 'text', NULL, NULL, NULL, NULL, '', 0.0010, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (297, 164, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (298, 164, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (299, 164, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (300, 164, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (301, 164, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (302, 164, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (303, 164, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (304, 164, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (305, 164, '1.docx_90', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (306, 164, '货源投放工作规范.docx_79', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:06:39'); -INSERT INTO `context_reference` VALUES (307, 166, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 公式:订货量/投放量\\*100%', 'text', NULL, NULL, NULL, NULL, '', 0.9560, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (308, 166, '', NULL, '1.docx', 'other', 1, 1, '1', '5.新品按照新品上市方案实施供应。 > 附件:1.\\*\\*市场状态评价指标体系', 'text', NULL, NULL, NULL, NULL, '', 0.9970, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (309, 166, '1.docx_39', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (310, 166, '1.docx_32', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(四)确定周可供货源量**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (311, 166, '1.docx_43', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(四)特殊客户供货**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (312, 166, '1.docx_42', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(三)投放限量设定**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (313, 166, '货源投放工作规范.docx_47', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(一)周货源投放策略的建立**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (314, 166, '1.docx_93', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **货源投放结果评估和优化策略**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (315, 166, '货源投放工作规范.docx_33', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (316, 166, '1.docx_31', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > ——应与区域物流分拣配送能力匹配。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (317, 166, '1.docx_16', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(一)货源属性分类**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (318, 166, '货源投放工作规范.docx_26', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (319, 166, '货源投放工作规范.docx_34', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '3.确定可供货源:下周可供货源量=期末库存量+本周确定到货\\*\\*量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:10:06'); -INSERT INTO `context_reference` VALUES (320, 167, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '5.新品按照新品上市方案实施供应。 > **(六)停供与减供**', 'text', NULL, NULL, NULL, NULL, '', 0.9920, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (321, 167, '', NULL, '1.docx', 'other', 1, 1, '1', '5.新品按照新品上市方案实施供应。 > 附件:1.\\*\\*市场状态评价指标体系', 'text', NULL, NULL, NULL, NULL, '', 0.9970, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (322, 167, '1.docx_43', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(四)特殊客户供货**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (323, 167, '货源投放工作规范.docx_47', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(一)周货源投放策略的建立**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (324, 167, '1.docx_93', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **货源投放结果评估和优化策略**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (325, 167, '1.docx_42', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(三)投放限量设定**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (326, 167, '货源投放工作规范.docx_33', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (327, 167, '1.docx_31', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > ——应与区域物流分拣配送能力匹配。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (328, 167, '货源投放工作规范.docx_34', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '3.确定可供货源:下周可供货源量=期末库存量+本周确定到货\\*\\*量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:26:28'); -INSERT INTO `context_reference` VALUES (329, 166, '', NULL, '1.docx', 'other', 1, 1, '1', '3.按价位段自选投放工作指引 > 说明:各品规库存与月销量之间的比值。', 'text', NULL, NULL, NULL, NULL, '', 0.9980, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (330, 166, '1.docx_34', NULL, '1.docx', 'other', 1, 1, NULL, '3.确定可供货源:下周可供货源量=期末库存量+本周确定到货\\*\\*量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (331, 166, '1.docx_43', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(四)特殊客户供货**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (332, 166, '1.docx_42', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(三)投放限量设定**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (333, 166, '1.docx_26', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (334, 166, '1.docx_33', NULL, '1.docx', 'other', 1, 1, NULL, '2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (335, 166, '1.docx_40', NULL, '1.docx', 'other', 1, 1, NULL, '5.新品按照新品上市方案实施供应。 > **(二)货源投放要求**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:47:16'); -INSERT INTO `context_reference` VALUES (336, 168, '', NULL, '1.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (337, 168, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > ——应符合公司商业库存管理要求。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (338, 168, '', NULL, '3.docx', 'other', 1, 1, '1', '3.法律诉讼。若处置过程中产生分歧纠纷无法调解的,由地市公司处理法律诉讼。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (339, 168, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9730, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (340, 168, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (341, 168, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (342, 168, '货源投放工作规范.docx_80', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (343, 168, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (344, 168, '1.docx_56', NULL, '1.docx', 'other', 1, 1, NULL, '3.按价位段自选投放工作指引 > **\\*\\*市场状态评价指标体系**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (345, 168, '货源投放工作规范.docx_90', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:54:40'); -INSERT INTO `context_reference` VALUES (346, 169, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '6.坚持区域协同、高效运作。 > **(三)确定周供应总量的主要依据**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (347, 169, '', NULL, '1.docx', 'other', 1, 1, '1', '3.状态评价办法与标准。 > ①状态评价', 'table', NULL, NULL, NULL, NULL, '', 0.9930, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (348, 169, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9820, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (349, 169, '', NULL, '3.docx', 'other', 1, 1, '1', '第五篇 投入管理 > **第三章 投入标准**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (350, 169, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 0.9990, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (351, 169, '', NULL, 'test.docx', 'other', 1, 1, '1', '第十六条 住宿登记纸质台账、电子记录须妥善留存,\\*\\*保存期限不少于两年\\*\\*,随时接受公安及主管部门检查。', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (352, 169, '货源投放工作规范.docx_80', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (353, 169, '1.docx_79', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (354, 169, '货源投放工作规范.docx_90', NULL, '货源投放工作规范.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 07:58:39'); -INSERT INTO `context_reference` VALUES (355, 170, '', NULL, '1.docx', 'other', 1, 1, '1', '2.地市公司营销中心采供部根据工业企业调运计划预计在途货源中本周可确定到货品种及数量。', 'text', NULL, NULL, NULL, NULL, '', 0.9960, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (356, 170, '', NULL, '1.txt', 'other', 9, 9, '9', '', 'text', NULL, NULL, NULL, NULL, '', 0.0040, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (357, 170, '', NULL, '货源投放工作规范.docx', 'other', 1, 1, '1', '2.指标值与权重确定。 > ①指标值的确定:', 'text', NULL, NULL, NULL, NULL, '', 0.9400, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (358, 170, '', NULL, '需求分析.docx', 'other', 1, 1, '1', '需求分析', 'text', NULL, NULL, NULL, NULL, '', 0.9820, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (359, 170, '', NULL, '3.docx', 'other', 1, 1, '1', '第五篇 投入管理 > **第三章 投入标准**', 'text', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (360, 170, '', NULL, 'test.docx', 'other', 1, 1, '1', '第五条 管理人员负责日常监督检查,定期核查登记台账、系统上传记录,对漏登、错登、代登等问题及时整改追责。', 'text', NULL, NULL, NULL, NULL, '', 0.9990, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (361, 170, '', NULL, 'longrule.docx', 'other', 1, 1, '1', '', 'text', NULL, NULL, NULL, NULL, '', 0.9990, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (362, 170, '', NULL, '2.docx', 'other', 1, 1, '1', '第六章 各类吸烟场所的建设标准 > **B1类:** 大型商场、超市', 'table', NULL, NULL, NULL, NULL, '', 1.0000, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (363, 170, '1.docx_62', NULL, '1.docx', 'other', 1, 1, NULL, '3.按价位段自选投放工作指引 > **3.终端动销率公式。**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (364, 170, '1.docx_94', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > 备注:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (365, 170, '1.docx_22', NULL, '1.docx', 'other', 1, 1, NULL, '6.坚持区域协同、高效运作。 > **3.市场状态指标:**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (366, 170, '1.docx_80', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (367, 170, '1.docx_90', NULL, '1.docx', 'other', 1, 1, NULL, '3.状态评价办法与标准。 > **(二)品规属性聚类评价**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (368, 170, '1.docx_56', NULL, '1.docx', 'other', 1, 1, NULL, '3.按价位段自选投放工作指引 > **\\*\\*市场状态评价指标体系**', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); -INSERT INTO `context_reference` VALUES (369, 170, '1.docx_79', NULL, '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为:', NULL, 0, 'null', 'null', '', '', NULL, '2026-06-02 08:13:17'); +INSERT INTO `context_reference` VALUES (474, 182, '1.docx_80', 80, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重', 'text', 0, 'null', 'null', '市场状态=+二级指标均值\\*权重\n主题:1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重\n市场状态=+二级指标均值\\*权重', '市场状态=+二级指标均值\\*权重\n主题:1.市场状态的计算公式为: > 市场状态=+二级指标均值\\*权重\n市场状态=+二级指标均值\\*权重', NULL, '2026-06-05 06:01:08', 42); +INSERT INTO `context_reference` VALUES (475, 182, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-05 06:01:08', 42); +INSERT INTO `context_reference` VALUES (476, 183, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-05 06:04:59', 42); +INSERT INTO `context_reference` VALUES (477, 184, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-05 06:18:14', 42); +INSERT INTO `context_reference` VALUES (478, 185, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-05 06:28:41', 42); +INSERT INTO `context_reference` VALUES (479, 186, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-05 06:37:10', 42); +INSERT INTO `context_reference` VALUES (480, 187, '1.docx_86', 86, 'dept_1_kb', '1.docx', 'other', 1, 1, NULL, '', 'text', 0, 'null', 'null', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', '一级指标合计权重不低于70%。\n主题:2.指标值与权重确定。 > 一级指标合计权重不低于70%。\n一级指标合计权重不低于70%。\n各明细指标权重确定可采用专家评分法确定,组织专家选取各类市场状态有代表性的在销品规进行评分,并根据市场状态计算公式确定各指标的权重。\n专家评分可由系统内营销管理人员、一线营销人员、工业企业营销代表和零售客户代表组成,以集中研讨或调查问卷的方式开展。', NULL, '2026-06-06 07:17:20', 42); -- ---------------------------- -- Table structure for data_dict @@ -507,21 +320,12 @@ CREATE TABLE `exam_assignment` ( INDEX `idx_status`(`status` ASC) USING BTREE, CONSTRAINT `fk_exam_assignment_dept` FOREIGN KEY (`dept_id`) REFERENCES `department` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT, CONSTRAINT `fk_exam_assignment_paper` FOREIGN KEY (`paper_id`) REFERENCES `exam_paper` (`paper_id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 55 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '试卷分配表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 70 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '试卷分配表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of exam_assignment -- ---------------------------- -INSERT INTO `exam_assignment` VALUES (45, '2bd9f7a1-5022-4133-9724-9dd5e25a601c', NULL, '[1]', '[]', '[]', '2026-06-01 13:49:30', NULL, 'active', '2026-06-01 13:49:30', '2026-06-01 13:49:30'); -INSERT INTO `exam_assignment` VALUES (46, '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '[1]', '[]', '[]', '2026-06-01 14:25:52', NULL, 'active', '2026-06-01 14:25:52', '2026-06-01 14:25:52'); -INSERT INTO `exam_assignment` VALUES (47, '72e283f2-683b-4f5b-b76e-39e3047b2ebe', NULL, '[1]', '[]', '[]', '2026-06-01 14:27:08', NULL, 'active', '2026-06-01 14:27:08', '2026-06-01 14:27:08'); -INSERT INTO `exam_assignment` VALUES (48, '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '[1]', '[]', '[]', '2026-06-02 00:09:56', NULL, 'active', '2026-06-02 00:09:56', '2026-06-02 00:09:56'); -INSERT INTO `exam_assignment` VALUES (49, 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', NULL, '[1]', '[]', '[]', '2026-06-02 03:16:17', NULL, 'active', '2026-06-02 03:16:17', '2026-06-02 03:16:17'); -INSERT INTO `exam_assignment` VALUES (50, 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '[1]', '[]', '[]', '2026-06-02 03:16:57', NULL, 'active', '2026-06-02 03:16:57', '2026-06-02 03:16:57'); -INSERT INTO `exam_assignment` VALUES (51, '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '[1]', '[]', '[]', '2026-06-02 04:27:33', NULL, 'active', '2026-06-02 04:27:33', '2026-06-02 04:27:33'); -INSERT INTO `exam_assignment` VALUES (52, '1df188af-647c-457e-9d1e-ea76a2b7fb2f', NULL, '[1]', '[]', '[]', '2026-06-02 05:35:45', NULL, 'active', '2026-06-02 05:35:45', '2026-06-02 05:35:45'); -INSERT INTO `exam_assignment` VALUES (53, 'c281572d-99f7-4e93-b684-590fbaea52e4', NULL, '[1]', '[]', '[]', '2026-06-02 05:38:27', NULL, 'active', '2026-06-02 05:38:27', '2026-06-02 05:38:27'); -INSERT INTO `exam_assignment` VALUES (54, '399ade38-3b02-4e83-8509-d6ea7624c437', NULL, '[1]', '[]', '[]', '2026-06-02 05:51:23', NULL, 'active', '2026-06-02 05:51:23', '2026-06-02 05:51:23'); +INSERT INTO `exam_assignment` VALUES (69, '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', NULL, '[1]', '[]', '[]', '2026-06-10 11:11:17', NULL, 'active', '2026-06-10 11:11:17', '2026-06-10 11:11:17'); -- ---------------------------- -- Table structure for exam_paper @@ -550,23 +354,12 @@ CREATE TABLE `exam_paper` ( INDEX `idx_status`(`status` ASC) USING BTREE, INDEX `idx_publish_time`(`publish_time` ASC) USING BTREE, CONSTRAINT `fk_exam_paper_user` FOREIGN KEY (`created_by`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 47 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '试卷基础信息表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 58 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '试卷基础信息表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of exam_paper -- ---------------------------- -INSERT INTO `exam_paper` VALUES (35, '2bd9f7a1-5022-4133-9724-9dd5e25a601c', '自动生成的试卷', NULL, 19.00, 120, 4, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"f30a7401-508b-4591-8fb8-46437699e577\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-01 13:49:23', '2026-06-01 13:49:30', '2026-06-01 13:49:30', NULL, 1); -INSERT INTO `exam_paper` VALUES (36, '31304832-7a1f-49e0-9f31-ed723d6d64f0', '自动生成的试卷', NULL, 24.00, 120, 5, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"f30a7401-508b-4591-8fb8-46437699e577\", \"bfbe43d3-fc30-44a8-9b05-7b7520dc20d0\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-01 14:25:48', '2026-06-01 14:25:52', '2026-06-01 14:25:52', NULL, 1); -INSERT INTO `exam_paper` VALUES (37, '72e283f2-683b-4f5b-b76e-39e3047b2ebe', '自动生成的试卷', NULL, 15.00, 120, 3, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-01 14:26:57', '2026-06-01 14:27:08', '2026-06-01 14:27:08', NULL, 1); -INSERT INTO `exam_paper` VALUES (38, '698eb5fa-13fa-4ed0-9831-6ee6934f053e', '自动生成的试卷', NULL, 24.00, 120, 5, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"f30a7401-508b-4591-8fb8-46437699e577\", \"bfbe43d3-fc30-44a8-9b05-7b7520dc20d0\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 00:09:50', '2026-06-02 00:09:56', '2026-06-02 00:09:56', NULL, 1); -INSERT INTO `exam_paper` VALUES (39, 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', '自动生成的试卷', NULL, 15.00, 120, 3, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 03:16:10', '2026-06-02 03:16:17', '2026-06-02 03:16:17', NULL, 1); -INSERT INTO `exam_paper` VALUES (40, 'c5656307-6255-4298-8c4e-82e53d91e379', '自动生成的试卷', NULL, 15.00, 120, 3, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 03:16:52', '2026-06-02 03:16:57', '2026-06-02 03:16:57', NULL, 1); -INSERT INTO `exam_paper` VALUES (41, '036bcb39-7d41-45f8-9fac-0d7899ceb16f', '自动生成的试卷', NULL, 24.00, 120, 5, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"f30a7401-508b-4591-8fb8-46437699e577\", \"bfbe43d3-fc30-44a8-9b05-7b7520dc20d0\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 04:27:24', '2026-06-02 04:27:33', '2026-06-02 04:27:33', NULL, 1); -INSERT INTO `exam_paper` VALUES (42, '1df188af-647c-457e-9d1e-ea76a2b7fb2f', '自动生成的试卷', NULL, 15.00, 120, 3, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 05:35:35', '2026-06-02 05:35:45', '2026-06-02 05:35:45', NULL, 1); -INSERT INTO `exam_paper` VALUES (43, 'c281572d-99f7-4e93-b684-590fbaea52e4', '自动生成的试卷', NULL, 15.00, 120, 3, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 05:38:18', '2026-06-02 05:38:27', '2026-06-02 05:38:27', NULL, 1); -INSERT INTO `exam_paper` VALUES (44, '399ade38-3b02-4e83-8509-d6ea7624c437', '自动生成的试卷', NULL, 19.00, 120, 4, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"f30a7401-508b-4591-8fb8-46437699e577\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'published', 1, '2026-06-02 05:51:06', '2026-06-02 05:51:23', '2026-06-02 05:51:23', NULL, 1); -INSERT INTO `exam_paper` VALUES (45, '377dcf90-4d6c-4530-af91-ba71adc69ea0', '自动生成的试卷', NULL, 30.00, 120, 6, '[\"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8\", \"a774495c-7bb1-448b-926f-a32bf1480836\", \"0831d91a-2e3a-4c9a-9b7a-74160ce4b5b5\", \"5e069067-a10d-4230-9564-e7503d72d738\", \"4d544b15-71c3-4335-ab0b-37b152206389\", \"e6bb2566-90a8-4651-b553-083a1d695b3c\"]', '本部门', 'draft', 1, '2026-06-02 06:28:48', '2026-06-02 06:28:48', NULL, NULL, 1); -INSERT INTO `exam_paper` VALUES (46, '3d1f2744-df2c-413d-8101-80ec70f68e9f', '自动生成的试卷', NULL, 40.00, 120, 8, '[\"dbc7c4dc-785c-4600-a3bd-893c608035dc\", \"fd2b20d1-584f-4a10-8b45-1bb5eff8fe19\", \"5a493eec-933c-4a1c-8c5c-aa7c32fe6736\", \"47384b42-decb-4610-b95e-c157f5f2f9e6\", \"209d3717-8288-47aa-908f-c88caec74c09\", \"ca0df912-a41c-4851-8391-cf4cc1696759\", \"5b99608a-bbdc-4435-9c86-f11e4953bd64\", \"01045a70-2b45-454c-aab5-bcc52b2eccec\"]', '本部门', 'draft', 1, '2026-06-02 06:42:55', '2026-06-02 06:42:55', NULL, NULL, 1); +INSERT INTO `exam_paper` VALUES (57, '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', '自动生成的试卷', NULL, 4.00, 120, 2, '[\"ea6a7f44-9077-4f19-b10e-8239a5198f4d\", \"9d59e7c5-edfc-4517-9fb5-780b389b66fb\"]', '本部门', 'published', 1, '2026-06-10 11:11:11', '2026-06-10 11:11:17', '2026-06-10 11:11:17', NULL, 1); -- ---------------------------- -- Table structure for exam_record @@ -599,41 +392,14 @@ CREATE TABLE `exam_record` ( INDEX `fk_exam_record_graded_by`(`graded_by` ASC) USING BTREE, CONSTRAINT `fk_exam_record_graded_by` FOREIGN KEY (`graded_by`) REFERENCES `user` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT, CONSTRAINT `fk_exam_record_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 196 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '考试记录表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 242 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '考试记录表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of exam_record -- ---------------------------- -INSERT INTO `exam_record` VALUES (165, '60eb4587-d9df-480b-900d-9e7d6eb8f39a', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', 'formal_exam', 1, 'graded', 0.00, '2026-06-01 14:26:37', '2026-06-01 14:26:37', NULL, 5, '2026-06-01 14:26:31', '2026-06-01 14:26:31', '2026-06-01 13:49:30', '2026-06-01 14:26:37'); -INSERT INTO `exam_record` VALUES (166, 'ace46d6b-62fb-4002-9e16-a3e45c8e0f3e', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 13:49:30', '2026-06-01 13:49:30'); -INSERT INTO `exam_record` VALUES (167, 'cad1aa48-9908-4657-80f1-a2358e921f8e', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 13:49:30', '2026-06-01 13:49:30'); -INSERT INTO `exam_record` VALUES (169, 'c935a703-5ba6-45d0-8e2c-68b0f3ed90be', '31304832-7a1f-49e0-9f31-ed723d6d64f0', 'formal_exam', 1, 'graded', 9.00, '2026-06-01 14:26:25', '2026-06-01 14:26:25', NULL, 4, '2026-06-01 14:26:20', '2026-06-01 14:26:20', '2026-06-01 14:25:52', '2026-06-01 14:26:25'); -INSERT INTO `exam_record` VALUES (170, 'd62513ce-0b62-4e1a-b88e-c94659d05214', '31304832-7a1f-49e0-9f31-ed723d6d64f0', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 14:25:52', '2026-06-01 14:25:52'); -INSERT INTO `exam_record` VALUES (171, '60012fe0-3703-422a-ad35-ac71f6b530b3', '31304832-7a1f-49e0-9f31-ed723d6d64f0', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 14:25:52', '2026-06-01 14:25:52'); -INSERT INTO `exam_record` VALUES (172, '1ba562e2-2f9a-41f5-aa26-89937edbe271', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', 'formal_exam', 1, 'graded', 0.00, '2026-06-01 14:27:23', '2026-06-01 14:27:23', NULL, 9, '2026-06-01 14:27:13', '2026-06-01 14:27:13', '2026-06-01 14:27:08', '2026-06-01 14:27:23'); -INSERT INTO `exam_record` VALUES (173, '22ab0dce-689e-48d9-8c0c-4c19c26aab45', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 14:27:08', '2026-06-01 14:27:08'); -INSERT INTO `exam_record` VALUES (174, '6f023a97-57a2-4329-8041-64e15bd56763', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-01 14:27:08', '2026-06-01 14:27:08'); -INSERT INTO `exam_record` VALUES (175, '1563b009-51f0-4ca9-9155-360c2f193242', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 00:10:02', '2026-06-02 00:10:02', NULL, 4, '2026-06-02 00:09:58', '2026-06-02 00:09:58', '2026-06-02 00:09:56', '2026-06-02 00:10:02'); -INSERT INTO `exam_record` VALUES (176, '69a7a4af-fb07-4dd3-b2e7-933d987484e4', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 00:09:56', '2026-06-02 00:09:56'); -INSERT INTO `exam_record` VALUES (177, 'cb12bd7a-108e-4b4a-8f2b-91483629554d', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 00:09:56', '2026-06-02 00:09:56'); -INSERT INTO `exam_record` VALUES (178, '27e5e21c-8acb-4aa6-9a52-801b7dfb1b84', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 03:16:24', '2026-06-02 03:16:24', NULL, 1, '2026-06-02 03:16:22', '2026-06-02 03:16:22', '2026-06-02 03:16:17', '2026-06-02 03:16:24'); -INSERT INTO `exam_record` VALUES (179, 'cc42f8a7-6f73-49be-ba8c-c0e7411d075e', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 03:16:17', '2026-06-02 03:16:17'); -INSERT INTO `exam_record` VALUES (180, 'e1e5219c-8212-4db7-b7f7-20d3846689e0', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 03:16:17', '2026-06-02 03:16:17'); -INSERT INTO `exam_record` VALUES (181, '4542d0b1-fa18-4177-a4a7-5bfc76ceac7f', 'c5656307-6255-4298-8c4e-82e53d91e379', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 03:17:04', '2026-06-02 03:17:04', NULL, 4, '2026-06-02 03:17:00', '2026-06-02 03:17:00', '2026-06-02 03:16:57', '2026-06-02 03:17:04'); -INSERT INTO `exam_record` VALUES (182, 'e05ab76c-6bf4-48a9-82bc-8e1772f6888c', 'c5656307-6255-4298-8c4e-82e53d91e379', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 03:16:57', '2026-06-02 03:16:57'); -INSERT INTO `exam_record` VALUES (183, 'b261ea2f-ecf2-49eb-aaf7-26b0d7e9697f', 'c5656307-6255-4298-8c4e-82e53d91e379', 'formal_exam', 4, 'graded', 0.00, '2026-06-02 04:29:51', '2026-06-02 04:29:51', NULL, 5, '2026-06-02 04:29:45', '2026-06-02 04:29:45', '2026-06-02 03:16:57', '2026-06-02 04:29:51'); -INSERT INTO `exam_record` VALUES (184, 'e5773b81-462a-418c-81a9-c80e6b7ee04b', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 04:27:52', '2026-06-02 04:27:52', NULL, 15, '2026-06-02 04:27:36', '2026-06-02 04:27:36', '2026-06-02 04:27:33', '2026-06-02 04:27:52'); -INSERT INTO `exam_record` VALUES (185, '9fa36286-b342-492c-a9f6-d7819d435b4d', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 04:27:33', '2026-06-02 04:27:33'); -INSERT INTO `exam_record` VALUES (186, '49a29c7a-96b8-43be-96c1-d239a5606dae', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', 'formal_exam', 4, 'graded', 0.00, '2026-06-02 04:29:32', '2026-06-02 04:29:32', NULL, 34, '2026-06-02 04:28:57', '2026-06-02 04:28:57', '2026-06-02 04:27:33', '2026-06-02 04:29:32'); -INSERT INTO `exam_record` VALUES (187, '985d18f0-383e-45c0-8232-bc38ceafd4a5', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 05:35:52', '2026-06-02 05:35:52', NULL, 4, '2026-06-02 05:35:48', '2026-06-02 05:35:48', '2026-06-02 05:35:45', '2026-06-02 05:35:52'); -INSERT INTO `exam_record` VALUES (188, 'f7c9e8a3-5b74-4288-b6d2-dfc7cfc75cd6', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:35:45', '2026-06-02 05:35:45'); -INSERT INTO `exam_record` VALUES (189, '1e1bc16c-f932-4cc1-b39d-c8403d45b3dc', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:35:45', '2026-06-02 05:35:45'); -INSERT INTO `exam_record` VALUES (190, '3b38596c-e66a-47b7-9dbf-ed6ea02ef9ba', 'c281572d-99f7-4e93-b684-590fbaea52e4', 'formal_exam', 1, 'graded', 0.00, '2026-06-02 05:38:42', '2026-06-02 05:38:42', NULL, 12, '2026-06-02 05:38:30', '2026-06-02 05:38:30', '2026-06-02 05:38:27', '2026-06-02 05:38:42'); -INSERT INTO `exam_record` VALUES (191, 'e311359e-f59b-4499-b6f9-831c88daf159', 'c281572d-99f7-4e93-b684-590fbaea52e4', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:38:27', '2026-06-02 05:38:27'); -INSERT INTO `exam_record` VALUES (192, '2dc1ecf5-33b2-47de-8d06-73d61b9becaf', 'c281572d-99f7-4e93-b684-590fbaea52e4', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:38:27', '2026-06-02 05:38:27'); -INSERT INTO `exam_record` VALUES (193, 'dbeaf205-2133-4fab-80d1-a2059f27c3a2', '399ade38-3b02-4e83-8509-d6ea7624c437', 'formal_exam', 1, 'graded', 5.00, '2026-06-02 05:51:33', '2026-06-02 05:51:33', NULL, 6, '2026-06-02 05:51:26', '2026-06-02 05:51:26', '2026-06-02 05:51:23', '2026-06-02 05:51:33'); -INSERT INTO `exam_record` VALUES (194, 'abe0cb88-cfe3-4078-bf15-c91c91f50a2f', '399ade38-3b02-4e83-8509-d6ea7624c437', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:51:23', '2026-06-02 05:51:23'); -INSERT INTO `exam_record` VALUES (195, '22debf42-feb0-46da-902e-4b5133b7be42', '399ade38-3b02-4e83-8509-d6ea7624c437', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-02 05:51:23', '2026-06-02 05:51:23'); +INSERT INTO `exam_record` VALUES (239, '17f5be59-3d81-480a-98bb-1e1a2a4556e6', '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', 'formal_exam', 1, 'graded', 0.00, '2026-06-10 11:11:49', '2026-06-10 11:11:49', NULL, 30, '2026-06-10 11:11:19', '2026-06-10 11:11:19', '2026-06-10 11:11:17', '2026-06-10 11:11:49'); +INSERT INTO `exam_record` VALUES (240, 'ff860338-99ed-4211-bf85-fce6605c8fcc', '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', 'formal_exam', 3, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-10 11:11:17', '2026-06-10 11:11:17'); +INSERT INTO `exam_record` VALUES (241, '26b9fac0-3f92-4d71-a5dc-3e8b432bd580', '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', 'formal_exam', 4, 'not_started', 0.00, NULL, NULL, NULL, 0, NULL, NULL, '2026-06-10 11:11:17', '2026-06-10 11:11:17'); -- ---------------------------- -- Table structure for faq @@ -740,6 +506,7 @@ CREATE TABLE `file` ( `process_step_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'UPLOADED' COMMENT '流程状态: UPLOADED-文件已上传, VECTORIZING-正在向量化, VECTORIZED-向量化完成, VECTORIZE_FAILED-向量化失败, EXAM_GENERATING-正在生成题目, EXAM_GENERATED-题目生成完成, EXAM_GENERATE_FAILED-题目生成失败, COMPLETED-全部流程完成', `process_step_message` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '流程状态信息', `process_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '处理信息/错误消息', + `tags` json NULL COMMENT '文件自定义标签,如版本信息、分类标识等元数据', PRIMARY KEY (`id`) USING BTREE, INDEX `idx_upload_user_id`(`upload_user_id` ASC) USING BTREE, INDEX `idx_dept_id`(`dept_id` ASC) USING BTREE, @@ -747,77 +514,22 @@ CREATE TABLE `file` ( INDEX `idx_create_time`(`create_time` ASC) USING BTREE, INDEX `idx_is_public`(`is_public` ASC) USING BTREE, INDEX `idx_file_category`(`file_category` ASC) USING BTREE, - INDEX `idx_audit_status`(`audit_status` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件管理表' ROW_FORMAT = DYNAMIC; + INDEX `idx_audit_status`(`audit_status` ASC) USING BTREE, + INDEX `idx_file_status`(`status` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 81 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件管理表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of file -- ---------------------------- -INSERT INTO `file` VALUES (2, 'longrule.docx', 'resources/user/admin/public/longrule/v14/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-05 08:01:36', '2026-05-06 00:23:30', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (3, '15_朱灿文_实验四.docx', 'resources/user/admin/public/15_朱灿文_实验四/v5/15_朱灿文_实验四.docx', 461080, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-05 08:01:55', '2026-05-06 00:23:30', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (4, 'longrule.docx', 'resources/user/admin/public/longrule/v15/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'dept_hr/longrule.docx', '2026-05-05 08:02:00', '2026-05-06 00:30:32', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (5, 'AI绘图技能的应用.pdf', 'resources/user/admin/public/AI绘图技能的应用/v2/AI绘图技能的应用.pdf', 246639, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'public_kb/AI绘图技能的应用.pdf', '2026-05-05 11:58:09', '2026-05-27 08:22:32', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '警告:未生成任何题目。可能原因:文档内容为空、文档内容无法提取题目、或文档格式不支持。source_chunks_used=0'); -INSERT INTO `file` VALUES (6, '汤齐星.pdf', 'resources/user/admin/public/汤齐星/v10/汤齐星.pdf', 300008, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-06 00:09:59', '2026-05-06 00:23:33', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (7, '形势与政策.docx', 'resources/user/admin/public/形势与政策/v2/形势与政策.docx', 42513, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'personal_kb/形势与政策.docx', '2026-05-06 00:16:07', '2026-05-25 07:51:50', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, '向量化成功,耗时 112073 毫秒,生成 null 个切片'); -INSERT INTO `file` VALUES (8, '第8章练习题.pdf', 'resources/user/user/public/第8章练习题/v1/第8章练习题.pdf', 473518, 'application/pdf', '.pdf', NULL, 3, 1, NULL, 1, 'personal', NULL, 1, 1, NULL, '2026-05-06 00:18:48', '2026-05-06 00:49:56', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (9, '设备接入协议-MQTT.docx', 'resources/user/user/public/设备接入协议-MQTT/v1/设备接入协议-MQTT.docx', 702530, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 3, 1, NULL, 1, 'personal', NULL, 1, 1, NULL, '2026-05-06 00:22:22', '2026-05-06 00:49:57', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (10, '参考样例.pdf', 'resources/user/admin/public/参考样例/v1/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-06 00:38:55', '2026-05-07 06:29:38', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (11, '参考样例.pdf', 'resources/rule/总公司/参考样例/v2/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 0, 'rule', NULL, 0, 1, NULL, '2026-05-06 00:49:51', '2026-05-07 06:29:36', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (12, '电商后台1.docx', 'resources/user/user/public/电商后台1/v1/电商后台1.docx', 2891770, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 3, 1, NULL, 1, 'personal', NULL, 0, 1, NULL, '2026-05-07 02:41:44', '2026-05-07 02:43:19', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (13, '1安装node和vuecli.docx', 'resources/user/user/private/1安装node和vuecli/v1/1安装node和vuecli.docx', 777257, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 3, 1, NULL, 0, 'personal', NULL, 1, 1, NULL, '2026-05-07 02:43:45', '2026-05-07 10:43:44', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (14, '电商后台2.docx', 'resources/user/user/public/电商后台2/v1/电商后台2.docx', 2644467, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 3, 1, NULL, 1, 'personal', NULL, 1, 1, NULL, '2026-05-07 02:45:12', '2026-05-07 02:45:56', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (15, '电商后台3.docx', 'resources/user/user/public/电商后台3/v1/电商后台3.docx', 3753517, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 3, 1, NULL, 1, 'personal', NULL, 1, 1, NULL, '2026-05-07 02:46:57', '2026-05-07 02:47:20', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (16, 'test.pdf', 'resources/rule/总公司/南京分公司/人事部门/test/v1/test.pdf', 99261, 'application/pdf', '.pdf', NULL, 1, 6, NULL, 1, 'rule', NULL, 1, 1, 'dept_hr/test.pdf', '2026-05-07 06:25:03', '2026-05-07 06:26:01', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (17, '参考样例.pdf', 'resources/user/user_1/public/参考样例/v9/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'personal', NULL, 0, 1, NULL, '2026-05-07 06:30:15', '2026-05-07 06:50:16', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (18, '参考样例.pdf', 'resources/user/user_1/public/参考样例/v10/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'personal', NULL, 0, 1, NULL, '2026-05-07 06:56:34', '2026-05-13 02:05:18', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (19, '参考样例.pdf', 'resources/user/user_1/public/参考样例/v11/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-07 08:50:14', '2026-05-13 02:05:31', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (20, '参考样例.pdf', 'resources/user/user_1/public/参考样例/v12/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-07 09:08:07', '2026-05-13 02:05:30', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (21, '1.docx', 'resources/rule/总公司/南京分公司/公共部门/1/v1/1.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-07 11:00:23', '2026-05-29 10:27:26', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共15道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":7,\"multiple_choice\":6,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含具体规则、分类、步骤,适合单选、多选和填空;无判断性表述,主观题不适用。\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (22, '2.docx', 'resources/rule/总公司/南京分公司/公共部门/2/v1/2.docx', 775988, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-07 11:00:37', '2026-05-07 19:00:36', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (23, '3.docx', 'resources/rule/总公司/南京分公司/公共部门/3/v1/3.docx', 1454500, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-07 11:00:48', '2026-05-20 08:19:03', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共10道题'); -INSERT INTO `file` VALUES (24, '三峡公报_1-15页.pdf', 'resources/rule/总公司/南京分公司/公共部门/三峡公报_1-15页/v2/三峡公报_1-15页.pdf', 2773520, 'application/pdf', '.pdf', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, 'personal_kb/三峡公报_1-15页.pdf', '2026-05-07 11:01:03', '2026-05-21 00:21:37', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共0道题'); -INSERT INTO `file` VALUES (25, '货源投放.docx', 'resources/rule/总公司/南京分公司/公共部门/货源投放/v1/货源投放.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, 'public_kb/货源投放.docx', '2026-05-07 11:01:17', '2026-05-27 02:54:48', 'INDEXED', 'FAILED', 'UPLOADED', NULL, '生成失败: 所有题目保存失败,共5道题'); -INSERT INTO `file` VALUES (26, '住宿.docx', 'resources/rule/总公司/南京分公司/人事部门/住宿/v1/住宿.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 1, 1, 'dept_hr/住宿.docx', '2026-05-09 02:02:53', '2026-05-09 02:07:10', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (27, '1774100313622.png', 'resources/rule/总公司/1774100313622/v1/1774100313622.png', 3945797, 'image/png', '.png', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-13 01:47:09', '2026-05-13 09:47:09', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (28, 'code.png', 'resources/rule/总公司/code/v1/code.png', 3004, 'image/png', '.png', NULL, 1, 1, NULL, 0, 'personal', NULL, 1, 1, NULL, '2026-05-13 01:47:32', '2026-05-13 09:47:31', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (29, '关于印发《南京工业职业技术大学2026年机构设置与调整方案》的通知.pdf', 'resources/rule/总公司/关于印发《南京工业职业技术大学2026年机构设置与调整方案》的通知/v1/关于印发《南京工业职业技术大学2026年机构设置与调整方案》的通知.pdf', 1016315, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 0, 'personal', NULL, 0, 1, NULL, '2026-05-13 02:04:42', '2026-05-13 02:05:10', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (30, '若依系统安装指南 (1).docx', 'resources/user/user_1/public/若依系统安装指南 (1)/v1/若依系统安装指南 (1).docx', 73872, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 4, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-13 02:06:25', '2026-05-13 02:06:43', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (31, '项目4作业-智能2531-15-张俊豪.pdf', 'resources/rule/总公司/项目4作业-智能2531-15-张俊豪/v1/项目4作业-智能2531-15-张俊豪.pdf', 1989774, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-13 06:07:55', '2026-05-13 14:07:55', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (32, '参赛声明签署件.pdf', 'resources/user/user_1/public/参赛声明签署件/v1/参赛声明签署件.pdf', 423200, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-13 06:09:38', '2026-05-13 06:10:08', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (33, '参赛声明签署件.pdf', 'resources/user/user_1/public/参赛声明签署件/v2/参赛声明签署件.pdf', 423200, 'application/pdf', '.pdf', NULL, 4, 1, NULL, 1, 'rule', NULL, 1, 1, 'personal_kb/参赛声明签署件.pdf', '2026-05-13 06:47:37', '2026-05-20 05:00:50', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (34, 'test.docx', 'resources/rule/总公司/南京分公司/公共部门/test/v1/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 7, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-17 07:06:24', '2026-05-17 15:06:24', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (35, 'test.docx', 'resources/rule/总公司/南京分公司/人事部门/test/v2/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 0, 1, 'dept/test.docx', '2026-05-17 07:08:29', '2026-05-29 10:35:48', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '警告:未生成任何题目。可能原因:文档内容为空、文档内容无法提取题目、或文档格式不支持。source_chunks_used=0'); -INSERT INTO `file` VALUES (36, 'longrule.docx', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 1, 1, 'public_kb/longrule.docx', '2026-05-20 09:53:50', '2026-05-27 02:16:09', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '向量化成功,耗时 23677 毫秒,生成 null 个切片'); -INSERT INTO `file` VALUES (37, 'start.txt', 'resources/rule/总公司/南京分公司/人事部门/start/v1/start.txt', 2047, 'text/plain', '.txt', NULL, 1, 6, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-20 10:16:49', '2026-05-20 18:16:48', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, NULL); -INSERT INTO `file` VALUES (38, '需求分析.docx', 'resources/rule/总公司/需求分析/v1/需求分析.docx', 15330, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, 'public_kb/需求分析.docx', '2026-05-27 07:58:03', '2026-05-30 14:30:07', 'INDEXED', 'UNGENERATED', 'UPLOADED', NULL, '向量化成功,耗时 21682 毫秒,生成 null 个切片'); -INSERT INTO `file` VALUES (41, 'test.docx', 'resources/rule/总公司/test/v3/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-29 10:30:39', '2026-05-29 10:35:12', 'FAILED', 'UNGENERATED', 'UPLOADED', NULL, '向量化失败: 确保collection存在失败: 创建collection失败: 400 BAD REQUEST: \"{\"error\":\"\\u521b\\u5efa\\u5411\\u91cf\\u5e93\\u5931\\u8d25\"}\" (耗时 163 毫秒)'); -INSERT INTO `file` VALUES (42, 'test.docx', 'resources/rule/总公司/test/v4/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-29 10:35:23', '2026-05-29 10:35:52', 'FAILED', 'UNGENERATED', 'UPLOADED', NULL, '向量化失败: 确保collection存在失败: 创建collection失败: 400 BAD REQUEST: \"{\"error\":\"\\u521b\\u5efa\\u5411\\u91cf\\u5e93\\u5931\\u8d25\"}\" (耗时 174 毫秒)'); -INSERT INTO `file` VALUES (43, 'longrule.docx', 'resources/rule/总公司/南京分公司/longrule/v2/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 1, 1, 'dept_2_kb/longrule.docx', '2026-05-29 10:36:14', '2026-05-29 10:39:08', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共4道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":1,\"multiple_choice\":0,\"single_choice\":2,\"subjective\":0,\"true_false\":1},\"reason\":\"内容政策性强、要点明确,适合单选、判断、填空;无复杂推理,主观题不适用。\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":4}'); -INSERT INTO `file` VALUES (44, 'test.docx', 'resources/rule/总公司/test/v5/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-29 10:48:32', '2026-05-29 10:48:32', 'FAILED', 'UNGENERATED', 'UPLOADED', NULL, '向量化失败: 确保collection存在失败: 创建collection失败: 400 BAD REQUEST: \"{\"error\":\"\\u521b\\u5efa\\u5411\\u91cf\\u5e93\\u5931\\u8d25\"}\" (耗时 172 毫秒)'); -INSERT INTO `file` VALUES (45, 'test.docx', 'resources/rule/总公司/南京分公司/技术部/test/v1/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 3, NULL, 1, 'rule', NULL, 1, 1, 'dept_3_kb/test.docx', '2026-05-29 10:49:55', '2026-05-29 10:56:06', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共20道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":5,\"multiple_choice\":0,\"single_choice\":8,\"subjective\":0,\"true_false\":7},\"reason\":\"内容以操作规范、原则性条款为主,适合考查记忆与辨析,主观题不适配;填空适配关键术语,单选和判断覆盖核心要点。\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (46, 'longrule.docx', 'resources/rule/总公司/longrule/v3/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-29 11:04:08', '2026-05-29 11:04:08', 'FAILED', 'UNGENERATED', 'UPLOADED', NULL, '向量化失败: 确保collection存在失败: 创建collection失败: 400 BAD REQUEST: \"{\"error\":\"\\u521b\\u5efa\\u5411\\u91cf\\u5e93\\u5931\\u8d25\"}\" (耗时 314 毫秒)'); -INSERT INTO `file` VALUES (47, 'start.txt', 'resources/rule/总公司/start/v1/start.txt', 2047, 'text/plain', '.txt', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-29 11:05:08', '2026-05-29 11:05:08', 'FAILED', 'UNGENERATED', 'UPLOADED', NULL, '向量化失败: 确保collection存在失败: 创建collection失败: 400 BAD REQUEST: \"{\"error\":\"\\u521b\\u5efa\\u5411\\u91cf\\u5e93\\u5931\\u8d25\"}\" (耗时 143 毫秒)'); -INSERT INTO `file` VALUES (48, '1.docx', 'resources/rule/总公司/1/v1/1.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'test1/1.docx', '2026-05-29 11:16:30', '2026-05-29 11:21:18', 'INDEXED', 'GENERATED', 'UPLOADED', NULL, '生成成功,共11道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":3,\"multiple_choice\":4,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含明确规则、分类、流程,适合单选、多选、填空;无判断性陈述,主观题不适配\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (49, 'longrule.docx', 'resources/rule/总公司/南京分公司/采购部门/longrule/v1/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 4, NULL, 1, 'rule', NULL, 1, 1, 'dept_4_kb/longrule.docx', '2026-05-29 12:01:46', '2026-05-29 12:02:22', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共4道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":1,\"multiple_choice\":0,\"single_choice\":2,\"subjective\":0,\"true_false\":1},\"reason\":\"内容政策性强、要点明确,适合单选、判断、填空;无复杂推理,主观题不适宜。\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":4}'); -INSERT INTO `file` VALUES (50, '作业管理系统测试计划.doc', 'resources/user/user_1/public/作业管理系统测试计划/v1/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 4, 1, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-05-29 13:07:01', '2026-05-29 14:23:07', 'FAILED', 'UNGENERATED', 'VECTORIZE_FAILED', '向量化失败: 文件不存在于服务器', '文件不存在于服务器'); -INSERT INTO `file` VALUES (51, '作业管理系统测试计划.doc', 'resources/user/user_1/public/作业管理系统测试计划/v3/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 4, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-05-29 13:07:58', '2026-06-02 04:24:41', 'FAILED', 'UNGENERATED', 'VECTORIZE_FAILED', '向量化失败: 文件不存在于服务器', '文件不存在于服务器'); -INSERT INTO `file` VALUES (52, '作业管理系统测试计划.doc', 'resources/rule/总公司/作业管理系统测试计划/v1/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, 'test1/作业管理系统测试计划.doc', '2026-05-29 14:04:35', '2026-05-29 14:23:06', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (53, '作业管理系统测试计划.doc', 'resources/rule/总公司/作业管理系统测试计划/v2/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, 'test1/作业管理系统测试计划.doc', '2026-05-29 14:23:15', '2026-05-30 13:17:31', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (54, '作业管理系统测试计划.doc', 'resources/rule/总公司/南京分公司/采购部门/作业管理系统测试计划/v1/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 4, NULL, 1, 'rule', NULL, 0, 1, 'dept_4_kb/作业管理系统测试计划.doc', '2026-05-30 13:17:43', '2026-05-30 13:43:22', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (55, '作业管理系统测试计划.doc', 'resources/rule/总公司/作业管理系统测试计划/v3/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'test1/作业管理系统测试计划.doc', '2026-05-30 13:43:51', '2026-05-30 13:43:53', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (56, '作业管理系统测试计划.doc', 'resources/rule/总公司/作业管理系统测试计划/v4/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'test1/作业管理系统测试计划.doc', '2026-05-30 13:48:43', '2026-05-30 13:54:20', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (57, '作业管理系统测试计划.doc', 'resources/rule/总公司/作业管理系统测试计划/v5/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'test1/作业管理系统测试计划.doc', '2026-05-30 13:56:30', '2026-05-30 13:56:32', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"', '生成失败: 生成题目失败: POST请求失败: 500 INTERNAL SERVER ERROR: \"{\"error_code\":\"EXAM_ERROR\",\"message\":\"AI \\u5206\\u6790\\u540e\\u672a\\u751f\\u6210\\u6709\\u6548\\u9898\\u578b\\u914d\\u7f6e\",\"status\":\"failed\",\"status_code\":5020,\"success\":false}\"'); -INSERT INTO `file` VALUES (58, '需求分析.docx', 'resources/rule/总公司/需求分析/v2/需求分析.docx', 15330, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, 'test1/需求分析.docx', '2026-05-30 14:06:26', '2026-05-30 14:30:07', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共2道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":0,\"multiple_choice\":0,\"single_choice\":0,\"subjective\":1,\"true_false\":1},\"reason\":\"内容空泛无实质知识点,仅可设判断题和简答题各1道\",\"suitable_types\":[\"true_false\",\"subjective\"],\"total_knowledge_points\":0}'); -INSERT INTO `file` VALUES (59, '需求分析.docx', 'resources/rule/总公司/需求分析/v3/需求分析.docx', 15330, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 0, 1, 'test1/需求分析.docx', '2026-05-30 14:30:32', '2026-05-30 14:44:49', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共2道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":0,\"multiple_choice\":0,\"single_choice\":0,\"subjective\":1,\"true_false\":1},\"reason\":\"内容空泛无实质知识点,仅可设判断题和简答以考察基础概念理解\",\"suitable_types\":[\"true_false\",\"subjective\"],\"total_knowledge_points\":0}'); -INSERT INTO `file` VALUES (60, 'test.docx', 'resources/rule/总公司/南京分公司/人事部门/test/v3/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 1, 1, 'dept_6_kb/test.docx', '2026-05-30 14:39:28', '2026-05-30 14:41:49', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共19道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":5,\"multiple_choice\":0,\"single_choice\":8,\"subjective\":0,\"true_false\":6},\"reason\":\"内容多为刚性操作规范,侧重记忆与判断,适合单选、判断、填空;无复杂分析或开放场景,主观题不适用\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (61, '需求分析.docx', 'resources/rule/总公司/南京分公司/采购部门/需求分析/v1/需求分析.docx', 15330, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 4, NULL, 1, 'rule', NULL, 1, 1, 'dept_4_kb/需求分析.docx', '2026-05-30 14:44:58', '2026-05-30 14:45:24', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共2道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":0,\"multiple_choice\":0,\"single_choice\":0,\"subjective\":1,\"true_false\":1},\"reason\":\"内容空泛无实质知识点,仅可设判断题和简答以考察基础概念理解\",\"suitable_types\":[\"true_false\",\"subjective\"],\"total_knowledge_points\":0}'); -INSERT INTO `file` VALUES (62, '作业管理系统测试计划.doc', 'resources/user/user_1/public/作业管理系统测试计划/v2/作业管理系统测试计划.doc', 77824, 'application/msword', '.doc', NULL, 4, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-06-02 04:24:02', '2026-06-02 04:24:41', 'FAILED', 'UNGENERATED', 'VECTORIZE_FAILED', '向量化失败: 文件不存在于服务器', '文件不存在于服务器'); -INSERT INTO `file` VALUES (63, '1.docx', 'resources/rule/总公司/南京分公司/1/v1/1.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 0, 1, 'dept_2_kb/1.docx', '2026-06-02 06:32:32', '2026-06-02 07:47:17', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共13道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":5,\"multiple_choice\":6,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含政策要点、分类标准、流程步骤,适合客观题;知识点明确但实操性弱,主观题不适宜。\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (64, '货源投放工作规范.docx', 'resources/rule/总公司/南京分公司/货源投放工作规范/v1/货源投放工作规范.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 0, 1, 'dept_2_kb/货源投放工作规范.docx', '2026-06-02 06:37:22', '2026-06-02 07:41:48', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共11道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":3,\"multiple_choice\":4,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含明确规则、分类、流程,适合单选、多选、填空;无判断性陈述,主观题不适配\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (65, '货源投放工作规范.docx', 'resources/rule/总公司/南京分公司/货源投放工作规范/v2/货源投放工作规范.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 0, 1, 'dept_2_kb/货源投放工作规范.docx', '2026-06-02 07:42:07', '2026-06-02 07:50:14', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共11道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":3,\"multiple_choice\":4,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含明确规则、分类、流程,适合单选、多选、填空;无判断性陈述,主观题不适配\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (66, '货源投放工作规范.docx', 'resources/rule/总公司/南京分公司/货源投放工作规范/v3/货源投放工作规范.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 0, 1, NULL, '2026-06-02 07:44:16', '2026-06-02 07:47:16', 'FAILED', 'UNGENERATED', 'VECTORIZE_FAILED', '向量化失败: 文件不存在于服务器', '文件不存在于服务器'); -INSERT INTO `file` VALUES (67, '货源投放工作规范.docx', 'resources/rule/总公司/南京分公司/货源投放工作规范/v4/货源投放工作规范.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 2, NULL, 1, 'rule', NULL, 1, 1, 'dept_2_kb/货源投放工作规范.docx', '2026-06-02 07:47:54', '2026-06-02 07:55:10', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共11道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":3,\"multiple_choice\":4,\"single_choice\":8,\"subjective\":0,\"true_false\":0},\"reason\":\"内容含明确规则、分类、流程,适合单选、多选、填空;无判断性陈述,主观题不适配\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"fill_blank\"],\"total_knowledge_points\":21}'); -INSERT INTO `file` VALUES (68, '1.txt', 'resources/rule/总公司/南京分公司/1/v2/1.txt', 32544, 'text/plain', '.txt', NULL, 1, 2, NULL, 1, 'rule', NULL, 1, 1, 'dept_2_kb/1.txt', '2026-06-02 08:09:15', '2026-06-02 08:10:53', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共4道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":0,\"multiple_choice\":1,\"single_choice\":3,\"subjective\":1,\"true_false\":0},\"reason\":\"内容含策略分析与问题判断,适合单选、多选和简答;无明确定义/数值,填空和判断不适用\",\"suitable_types\":[\"single_choice\",\"multiple_choice\",\"subjective\"],\"total_knowledge_points\":5}'); +INSERT INTO `file` VALUES (70, '2.docx', 'resources/rule/总公司/2/v1/2.docx', 775988, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'dept_1_kb/2.docx', '2026-06-02 14:11:01', '2026-06-10 05:26:37', 'FAILED', 'GENERATED', 'VECTORIZE_FAILED', '向量化失败: 向量化失败[AI端错误]: 文件上传到向量库失败: I/O error on POST request for \"http://localhost:5001/documents/upload\": Unexpected end of file from server (耗时 154115 毫秒)', '向量化失败[AI端错误]: 文件上传到向量库失败: I/O error on POST request for \"http://localhost:5001/documents/upload\": Unexpected end of file from server (耗时 154115 毫秒)', NULL); +INSERT INTO `file` VALUES (71, '3.docx', 'resources/rule/总公司/3/v1/3.docx', 1454500, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'dept_1_kb/3.docx', '2026-06-02 14:11:12', '2026-06-10 04:58:48', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共4道题', NULL); +INSERT INTO `file` VALUES (72, '1.docx', 'resources/rule/总公司/南京分公司/技术部/1/v1/1.docx', 483352, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 3, NULL, 1, 'rule', NULL, 1, 1, 'dept_3_kb/1.docx', '2026-06-03 02:01:08', '2026-06-09 06:42:02', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共5道题', NULL); +INSERT INTO `file` VALUES (74, '需求分析.docx', 'resources/rule/总公司/需求分析/v5/需求分析.docx', 15330, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'dept_1_kb/需求分析.docx', '2026-06-04 02:07:06', '2026-06-04 17:51:16', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共1道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":0,\"multiple_choice\":0,\"single_choice\":1,\"subjective\":0,\"true_false\":0},\"reason\":\"文档内容极简仅含标题,无实质知识点,适宜输出1道单选题覆盖基础概念。\",\"suitable_types\":[\"single_choice\"],\"total_knowledge_points\":0}', '{}'); +INSERT INTO `file` VALUES (75, '参考样例.pdf', 'resources/rule/总公司/参考样例/v7/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, NULL, '2026-06-04 07:40:55', '2026-06-04 15:40:55', 'PENDING', 'UNGENERATED', 'UPLOADED', '文件已上传', NULL, NULL); +INSERT INTO `file` VALUES (76, 'longrule.docx', 'resources/rule/总公司/南京分公司/技术部/longrule/v1/longrule.docx', 14675, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 3, NULL, 1, 'rule', NULL, 1, 1, 'dept_3_kb/longrule.docx', '2026-06-04 13:21:25', '2026-06-10 05:02:16', 'INDEXED', 'GENERATED', 'EXAM_GENERATED', '题目生成完成', '生成成功,共3道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":1,\"multiple_choice\":0,\"single_choice\":2,\"subjective\":0,\"true_false\":1},\"reason\":\"知识点较基础,适合选择题和判断题。\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":4}', NULL); +INSERT INTO `file` VALUES (78, 'test.docx', 'resources/rule/总公司/南京分公司/人事部门/test/v4/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 0, 1, 'dept_6_kb/test.docx', '2026-06-10 05:02:17', '2026-06-10 05:06:05', 'DELETED', 'GENERATED', 'DELETED', '文件已软删除', '生成成功,共4道题', NULL); +INSERT INTO `file` VALUES (79, '参考样例.pdf', 'resources/rule/总公司/参考样例/v8/参考样例.pdf', 3588003, 'application/pdf', '.pdf', NULL, 1, 1, NULL, 1, 'rule', NULL, 1, 1, 'dept_1_kb/参考样例.pdf', '2026-06-10 05:10:01', '2026-06-10 05:20:07', 'INDEXED', 'FAILED', 'EXAM_GENERATE_FAILED', '题目生成失败: 生成失败[AI端错误]: 生成题目失败: POST请求失败: I/O error on POST request for \"http://localhost:5001/exam/generate-smart\": Unexpected end of file from server', '生成失败[AI端错误]: 生成题目失败: POST请求失败: I/O error on POST request for \"http://localhost:5001/exam/generate-smart\": Unexpected end of file from server', NULL); +INSERT INTO `file` VALUES (80, 'test.docx', 'resources/rule/总公司/南京分公司/人事部门/test/v5/test.docx', 16182, 'application/vnd.openxmlformats-officedocument.word', '.docx', NULL, 1, 6, NULL, 1, 'rule', NULL, 0, 1, 'dept_6_kb/test.docx', '2026-06-10 06:19:01', '2026-06-10 06:34:49', 'DELETED', 'GENERATED', 'DELETED', '文件已软删除', '生成成功,共9道题\n\n【AI分析结果】\n{\"question_types\":{\"fill_blank\":2,\"multiple_choice\":0,\"single_choice\":5,\"subjective\":0,\"true_false\":3},\"reason\":\"知识点较具体,适合单选、判断和填空题。\",\"suitable_types\":[\"single_choice\",\"true_false\",\"fill_blank\"],\"total_knowledge_points\":10}', NULL); -- ---------------------------- -- Table structure for operation_log @@ -940,7 +652,7 @@ CREATE TABLE `question` ( `score` decimal(5, 2) NOT NULL COMMENT '分值', `version` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '1.0' COMMENT '版本号', `document_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '原始文档ID', - `document_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档名称', + `exclude_stems` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '题干内容,用于AI去重', `knowledge_base_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '知识库路径,关联knowledge_base_path表的name字段', `source_context` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'AI出题参考的原文切片/上下文', `chunk_ids` json NULL COMMENT '切片ID列表', @@ -954,202 +666,88 @@ CREATE TABLE `question` ( `reviewer_comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '审核评论', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `is_deleted` int NOT NULL DEFAULT 0 COMMENT '软删除标志:0表示正常,1表示已删除', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `uk_question_id`(`question_id` ASC) USING BTREE, INDEX `idx_question_type`(`question_type` ASC) USING BTREE, INDEX `idx_difficulty`(`difficulty` ASC) USING BTREE, INDEX `idx_status`(`status` ASC) USING BTREE, INDEX `idx_created_at`(`created_at` ASC) USING BTREE, - INDEX `idx_knowledge_base_path`(`knowledge_base_path` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 602 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '题目表' ROW_FORMAT = DYNAMIC; + INDEX `idx_knowledge_base_path`(`knowledge_base_path` ASC) USING BTREE, + INDEX `idx_question_is_deleted`(`is_deleted` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 831 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '题目表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of question -- ---------------------------- -INSERT INTO `question` VALUES (308, '9d05c475-b4fe-4679-a450-ee88a94b3b34', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"扩大终端数量规模\"}, {\"key\": \"B\", \"content\": \"提升终端信息化系统覆盖率\"}, {\"key\": \"C\", \"content\": \"着眼于终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"统一各类终端建设外观标准\"}]}, \"stem\": \"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘要着眼于终端功能发挥和服务水平提升’,这是务求实效原则的出发点和根本目标,直接体现其核心要求。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:45'); -INSERT INTO `question` VALUES (309, 'fa2fc6d7-a30b-4205-8849-1868f0ce52fc', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"终端建设数量最大化\"}, {\"key\": \"B\", \"content\": \"降低单位终端运营成本\"}, {\"key\": \"C\", \"content\": \"终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"统一各区域终端硬件配置规格\"}]}, \"stem\": \"根据文档内容,终端投入标准设定的根本依据应聚焦于哪一核心目标?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准’,这是设定标准的根本依据,对应chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:50'); -INSERT INTO `question` VALUES (310, 'b49f2f89-7216-438a-ad50-c7fadcf4015f', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"强调终端形象统一,强化品牌视觉识别功能\"}, {\"key\": \"B\", \"content\": \"聚焦功能发挥与服务水平提升,避免无效投入,保障六大功能可持续运行\"}, {\"key\": \"C\", \"content\": \"按销量规模划分终端等级,突出销售执行功能\"}, {\"key\": \"D\", \"content\": \"要求配备扫码设备,重点支撑数据采集功能\"}]}, \"stem\": \"根据文档中关于零售终端建设的原则性要求,以下哪一项最直接体现了‘务求实效原则’对零售终端六大功能维度的指导作用?\", \"answer\": \"B\", \"explanation\": \"文档chunk_id:3.docx_125明确指出‘务求实效原则’要‘着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,该原则并非指向某一单项功能,而是统筹保障零售终端六大功能维度整体、可持续、有效落地的核心指导方针;选项B准确概括了该原则对六大功能维度的统领性要求。其他选项均片面聚焦单一功能,未体现‘务求实效’对六大功能整体效能的导向。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:52'); -INSERT INTO `question` VALUES (311, 'ee652f7e-da5e-4129-8766-c113277332f4', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"科学设定终端投入标准\"}, {\"key\": \"B\", \"content\": \"严格执行终端投入标准\"}, {\"key\": \"C\", \"content\": \"优先采购高配置但非必需的智能设备\"}, {\"key\": \"D\", \"content\": \"坚决杜绝不必要的支出和浪费\"}]}, \"stem\": \"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)\", \"answer\": [\"A\", \"B\", \"D\"], \"explanation\": \"文档原文强调‘科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,A、B、D均直接对应;C项违背‘务求实效’,属于典型的形式主义浪费,不符合该原则。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:52'); -INSERT INTO `question` VALUES (312, 'bd300e09-bcdd-4d7e-aa40-6db43f2600b7', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"坚持务求实效原则\"}, {\"key\": \"B\", \"content\": \"以终端建成数量为首要考核指标\"}, {\"key\": \"C\", \"content\": \"科学设定并严格执行标准\"}, {\"key\": \"D\", \"content\": \"坚决杜绝不必要的支出和浪费\"}]}, \"stem\": \"依据文档,设定和执行终端投入标准时必须坚持的原则及要求包括哪些?(可多选)\", \"answer\": [\"A\", \"C\", \"D\"], \"explanation\": \"文档chunk_id:3.docx_125中明确提出‘务求实效原则’,并强调‘科学设定并严格执行’‘坚决杜绝不必要的支出和浪费’,B项在文档中无依据,且与‘务求实效’原则相悖。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:53'); -INSERT INTO `question` VALUES (313, '76913ad8-5325-4f30-a03a-6e19e434b59e', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"务求实效原则允许在终端建设中适度预留冗余预算,以应对未来可能的功能升级需求。\", \"answer\": \"false\", \"explanation\": \"文档明确要求‘坚决杜绝不必要的支出和浪费’,预留非当前功能所需、无明确实施计划的冗余预算,违背‘务求实效’对投入精准性与必要性的刚性约束。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:53'); -INSERT INTO `question` VALUES (314, 'fdc82b86-6bcc-45d3-8df5-8e7f34baaa65', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档指出,终端投入标准的设定只需参考历史投入数据,无需考虑实际功能发挥与服务水平。\", \"answer\": \"false\", \"explanation\": \"文档明确强调‘要着眼于终端功能发挥和服务水平提升’作为设定标准的出发点,否定仅依赖历史数据的片面做法,见chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:54'); -INSERT INTO `question` VALUES (315, '7ae3daef-0345-4852-bd37-336e74498cc4', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 3}, \"stem\": \"务求实效原则强调以___为出发点,通过科学设定和严格执行终端投入标准,实现___与___的双重提升。\", \"answer\": [[\"终端功能发挥和服务水平提升\"], [\"终端功能发挥\"], [\"服务水平提升\"]], \"explanation\": \"原文‘要着眼于终端功能发挥和服务水平提升’构成完整目的表述,后两空为其拆分要素,共同构成该原则的核心落脚点。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:55'); -INSERT INTO `question` VALUES (316, '8ea10928-cdd0-4ea0-be4b-8429361286f9', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"终端投入标准的设定必须坚持___原则,其核心是着眼于___和服务水平提升。\", \"answer\": [[\"务求实效\"], [\"终端功能发挥\"]], \"explanation\": \"原文‘(四)务求实效原则’及后续表述‘要着眼于终端功能发挥和服务水平提升’直接构成填空依据,出自chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:55'); -INSERT INTO `question` VALUES (317, 'ea6ba220-43ff-44d8-8b24-cd350eeb8b53', 'subjective', 3, NULL, 6.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"answer_length_hint\": \"150–200字\"}, \"stem\": \"请结合文档内容,简述‘务求实效原则’在终端建设管理中的具体体现,并说明其与形式主义倾向的根本区别。\", \"answer\": \"务求实效原则具体体现为:以终端功能发挥和服务水平提升为唯一导向,科学设定并严格执行投入标准,杜绝一切不必要的支出和浪费。其核心是结果导向和成本效益意识——每项投入必须可验证、可量化、可服务于实际服务能力提升。与形式主义的根本区别在于:形式主义重‘面子’轻‘里子’,追求表面达标、重复建设或超需配置;而务求实效坚持‘需要什么建什么、能用就好、够用即止’,拒绝脱离实际需求的盲目投入,确保资源真正转化为终端服务效能。\", \"explanation\": \"答案严格依据文档中‘着眼于……提升’‘科学设定并严格执行’‘坚决杜绝……浪费’三重表述展开,从目标、手段、底线三个维度阐释,并通过对比凸显原则的实践刚性。\"}', 'approved', NULL, '2026-05-20 07:28:45', '2026-05-27 09:22:56'); -INSERT INTO `question` VALUES (318, '8bf50c1a-ede7-4489-ae6e-41f2d8c4521b', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"扩大终端建设规模和数量\"}, {\"key\": \"B\", \"content\": \"提升终端信息化系统覆盖率\"}, {\"key\": \"C\", \"content\": \"着眼于终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"统一全国终端装修风格和标识\"}]}, \"stem\": \"根据文档内容,务求实效原则的核心要求聚焦于以下哪一目标?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘务求实效原则’要‘着眼于终端功能发挥和服务水平提升’,这是该原则最直接、最核心的目标表述。其他选项在文档中无依据。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:22:58'); -INSERT INTO `question` VALUES (319, 'a21231c6-505d-4ee5-9b64-4868a4f53724', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"终端建设的硬件配置等级\"}, {\"key\": \"B\", \"content\": \"终端所在地理位置的经济水平\"}, {\"key\": \"C\", \"content\": \"终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"零售户自主申报的投入意愿\"}]}, \"stem\": \"根据文档内容,终端投入标准设定的根本依据应聚焦于以下哪一项?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准’,这是设定终端投入标准的核心依据,对应chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:22:59'); -INSERT INTO `question` VALUES (320, '9a81cc06-a613-4002-ba6d-2960f4998553', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"强调终端形象统一,强化品牌视觉识别功能\"}, {\"key\": \"B\", \"content\": \"聚焦功能发挥与服务水平提升,避免无效投入,保障六大功能可持续运行\"}, {\"key\": \"C\", \"content\": \"按销量规模划分终端等级,突出销售执行功能\"}, {\"key\": \"D\", \"content\": \"要求配备扫码设备,重点支撑数据采集功能\"}]}, \"stem\": \"根据文档中关于零售终端建设的原则性要求,以下哪一项最直接体现了‘务求实效原则’对零售终端六大功能维度的指导作用?\", \"answer\": \"B\", \"explanation\": \"文档chunk_id:3.docx_125明确指出‘务求实效原则’要‘着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,该原则并非指向某一单项功能,而是统筹保障零售终端六大功能维度整体、可持续、有效落地的核心指导思想;选项B准确提炼了这一原则与六大功能维度的关系,其他选项均片面对应单一功能,且无直接文档依据。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:22:59'); -INSERT INTO `question` VALUES (321, '0c54a8cb-0c98-4a1a-8629-c45b95ed75f3', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"科学设定终端投入标准\"}, {\"key\": \"B\", \"content\": \"严格执行终端投入标准\"}, {\"key\": \"C\", \"content\": \"优先采购进口设备以保障质量\"}, {\"key\": \"D\", \"content\": \"坚决杜绝不必要的支出和浪费\"}]}, \"stem\": \"依据文档中关于务求实效原则的表述,下列哪些属于其具体实施要求?(可多选)\", \"answer\": [\"A\", \"B\", \"D\"], \"explanation\": \"文档原文为‘科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,A、B、D三项均直接对应原文;C项‘优先采购进口设备’在文档中完全未提及,属干扰项。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:05'); -INSERT INTO `question` VALUES (322, '6f33cac1-2e4a-44cf-b173-883861df15c9', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"坚持务求实效原则\"}, {\"key\": \"B\", \"content\": \"强调终端外观形象统一性\"}, {\"key\": \"C\", \"content\": \"坚决杜绝不必要的支出和浪费\"}, {\"key\": \"D\", \"content\": \"以终端历史销量为唯一量化依据\"}]}, \"stem\": \"依据文档,设定和执行终端投入标准时,必须坚持的原则及需防范的问题包括哪些?\", \"answer\": [\"A\", \"C\"], \"explanation\": \"文档chunk_id:3.docx_125明确提出‘务求实效原则’及‘坚决杜绝不必要的支出和浪费’,二者共同构成终端投入标准设定与执行的刚性依据;B、D项在文档中无依据。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:13'); -INSERT INTO `question` VALUES (323, '8f32499f-e1cc-4c57-a10b-2e9ae8139582', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"务求实效原则允许在终端建设中适度增加非功能性装饰投入,以增强品牌形象。\", \"answer\": false, \"explanation\": \"文档强调‘坚决杜绝不必要的支出和浪费’,而‘非功能性装饰投入’若不服务于终端功能发挥或服务水平提升,即属‘不必要’范畴,违背该原则。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:06'); -INSERT INTO `question` VALUES (324, 'c08b0485-d54c-4c90-a00e-bbf6d968782f', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档指出,终端投入标准的设定只需考虑建设成本控制,无需关联其实际服务效能。\", \"answer\": false, \"explanation\": \"错误。文档强调‘要着眼于终端功能发挥和服务水平提升’设定标准,说明效能是核心依据,而非仅成本控制;该说法违背‘务求实效原则’,见chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:08'); -INSERT INTO `question` VALUES (325, 'dedf27a6-f8ab-4db6-85df-6253d3b89062', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 3}, \"stem\": \"务求实效原则要求以___为导向,通过科学设定和严格执行终端投入标准,杜绝___和___。\", \"answer\": [[\"终端功能发挥和服务水平提升\"], [\"不必要的支出\"], [\"浪费\"]], \"explanation\": \"原文完整表述为‘要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,三处空格依次对应核心导向与两项禁止性要求。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (326, '7684f577-300a-476b-b4a7-507fcc579f81', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"终端投入标准的设定必须坚持___原则,其根本出发点是提升终端功能发挥和___。\", \"answer\": [[\"务求实效\"], [\"服务水平\"]], \"explanation\": \"原文chunk_id:3.docx_125明确表述为‘(四)务求实效原则’及‘要着眼于终端功能发挥和服务水平提升’,两个空分别对应原则名称和目标维度。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (327, '5071b392-8e37-4da2-9266-ec56d170a1b0', 'subjective', 3, NULL, 6.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', 'Section: Snippet:**(四)务求实效原则**\n**(四)务求实效原则**\n要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。 Page:0', '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"min_words\": 50}, \"stem\": \"请结合文档内容,简述‘务求实效原则’的核心要求及其在终端建设管理中的实践意义。(不少于50字)\", \"answer\": \"核心要求是着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费。其实践意义在于避免资源错配和形式主义,确保每项投入切实转化为服务能力提升,推动终端建设由数量扩张转向质量实效。\"}', 'approved', NULL, '2026-05-20 07:35:51', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (328, '78e4b121-a495-4032-9449-9c6df07b2c26', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"扩大终端数量规模\"}, {\"key\": \"B\", \"content\": \"提升终端信息化系统覆盖率\"}, {\"key\": \"C\", \"content\": \"着眼于终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"统一各类终端建设外观标准\"}]}, \"stem\": \"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘要着眼于终端功能发挥和服务水平提升’,这是务求实效原则的出发点和根本目标,直接体现其核心要求。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (329, '6343d584-da73-4fbd-bc7f-53c8c7d523e1', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"终端建设的硬件配置等级\"}, {\"key\": \"B\", \"content\": \"终端年度销售规模与盈利水平\"}, {\"key\": \"C\", \"content\": \"终端功能发挥和服务水平提升\"}, {\"key\": \"D\", \"content\": \"上级单位下达的预算分配额度\"}]}, \"stem\": \"根据文档内容,设定终端投入标准的根本出发点和核心依据是什么?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘要着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准’,这是设定标准的根本依据,对应chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (330, 'fc1ebceb-8423-44d9-9b13-49198cfade79', 'single_choice', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"强调终端形象统一,强化品牌视觉识别功能\"}, {\"key\": \"B\", \"content\": \"聚焦功能发挥与服务水平提升,科学设定终端投入标准\"}, {\"key\": \"C\", \"content\": \"依据划分标准明确一般现代终端准入门槛\"}, {\"key\": \"D\", \"content\": \"落实主要建成标准,确保硬件设施达标\"}]}, \"stem\": \"根据文档中关于零售终端建设的原则性要求,以下哪一项最直接体现了‘务求实效原则’对零售终端六大功能维度的指导作用?\", \"answer\": \"B\", \"explanation\": \"文档chunk_id:3.docx_125明确指出‘务求实效原则’的核心是‘着眼于终端功能发挥和服务水平提升,科学设定并严格执行终端投入标准’,这直接对应零售终端六大功能维度中‘功能发挥’与‘服务支撑’两大维度的实效导向要求;其他选项虽相关,但未体现该原则对功能维度的统领性指导。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (331, 'd479d548-2633-4091-85da-be75c0bd1504', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"科学设定终端投入标准\"}, {\"key\": \"B\", \"content\": \"严格执行终端投入标准\"}, {\"key\": \"C\", \"content\": \"优先采购高配置但非必需的智能设备\"}, {\"key\": \"D\", \"content\": \"坚决杜绝不必要的支出和浪费\"}]}, \"stem\": \"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)\", \"answer\": [\"A\", \"B\", \"D\"], \"explanation\": \"文档原文强调‘科学设定并严格执行终端投入标准,坚决杜绝不必要的支出和浪费’,A、B、D项均直接对应原文表述;C项违背‘务求实效’,属于典型浪费行为,故排除。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (332, '2c2ff5dc-f959-4446-84aa-3cc4970061fc', 'multiple_choice', 3, NULL, 4.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"坚持务求实效原则\"}, {\"key\": \"B\", \"content\": \"严格执行准入标准\"}, {\"key\": \"C\", \"content\": \"杜绝浪费和不必要支出\"}, {\"key\": \"D\", \"content\": \"依据划分标准确定终端类型\"}]}, \"stem\": \"依据文档,以下哪些原则或要求直接支撑了终端投入标准的科学设定?(可多选)\", \"answer\": [\"A\", \"C\"], \"explanation\": \"文档chunk_id:3.docx_125中明确提出‘务求实效原则’及‘坚决杜绝不必要的支出和浪费’,二者共同构成终端投入标准设定的直接依据;而准入标准、划分标准虽属终端管理框架,但未在文档中被表述为‘投入标准设定依据’。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (333, '650a1934-5d42-4b34-a5f7-24481d46b781', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"务求实效原则允许在终端建设中为追求形式美观而增加非功能性投入。\", \"answer\": \"False\", \"explanation\": \"文档明确要求‘坚决杜绝不必要的支出和浪费’,所有投入必须服务于‘终端功能发挥和服务水平提升’,形式主义投入不符合该原则。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (334, 'a84378e2-b0cf-4620-b628-16d053eb7449', 'true_false', 3, NULL, 1.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档指出,终端投入标准的设定应以预算额度为首要依据,再兼顾功能与服务效果。\", \"answer\": false, \"explanation\": \"文档强调‘着眼于终端功能发挥和服务水平提升’,并将‘务求实效’作为原则,未将预算额度列为首要依据;相反,要求‘坚决杜绝不必要的支出和浪费’,说明预算需服从实效目标,而非相反。依据来自chunk_id:3.docx_125。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (335, '558c6bc4-c02b-4822-807c-4995e9c47191', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 3}, \"stem\": \"务求实效原则强调以___为导向,通过科学设定与严格执行终端投入标准,实现___和___的双重提升。\", \"answer\": [[\"终端功能发挥和服务水平提升\"], [\"终端功能发挥\"], [\"服务水平提升\"]], \"explanation\": \"原文‘要着眼于终端功能发挥和服务水平提升’是原则的总导向,后半句‘科学设定并严格执行……’旨在支撑该导向落地,填空需准确还原原文逻辑结构。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (336, '6193d343-0094-4de6-8f37-54aeabb4460c', 'fill_blank', 3, NULL, 2.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"终端投入标准的设定必须坚持___原则,其核心是着眼于终端___和服务水平提升。\", \"answer\": [[\"务求实效\"], [\"功能发挥\"]], \"explanation\": \"原文出自chunk_id:3.docx_125:‘(四)务求实效原则’及‘要着眼于终端功能发挥和服务水平提升……’,两个空分别对应该原则名称及其核心指向。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (337, '0033b05b-d468-40b5-a183-d7a7ea7141e7', 'subjective', 3, NULL, 6.00, '1.0', '23', 'resources/rule/总公司/南京分公司/公共部门/3/v3/3.docx', 'public_kb', NULL, '[\"3.docx_125\"]', 15, 0, 0, NULL, NULL, '{\"data\": {\"max_points\": 5}, \"stem\": \"请结合文档内容,简述‘务求实效原则’在终端建设管理中的具体体现,并说明其与‘杜绝浪费’之间的内在逻辑关系。\", \"answer\": \"务求实效原则的具体体现包括:①以终端功能发挥和服务水平提升为根本出发点;②科学设定终端投入标准,确保投入精准匹配实际需求;③严格执行标准,防止随意性与超标支出。其与‘杜绝浪费’的内在逻辑在于:只有坚持结果导向(即功能与服务实效),才能识别并剔除无效投入;‘杜绝浪费’是落实实效导向的必然要求和刚性约束,二者构成目标与保障的统一体。\", \"explanation\": \"答案紧扣文档原文‘着眼于终端功能发挥和服务水平提升’‘科学设定并严格执行’‘坚决杜绝……浪费’三要素,阐明目标设定、过程管控与结果约束的闭环逻辑。\"}', 'approved', NULL, '2026-05-20 08:19:02', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (338, '2d80232c-fe87-4c0d-b6b2-c98efc76720d', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"提升艺术展演活动覆盖率\"}, {\"key\": \"B\", \"content\": \"强化对学生每天校内体育活动时间落实的跟踪督导\"}, {\"key\": \"C\", \"content\": \"推动中小学春秋假制度全面落地\"}, {\"key\": \"D\", \"content\": \"配齐配强心理健康教师队伍\"}]}, \"stem\": \"根据文档内容,“晒课表”这一举措主要服务于哪一具体目标?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位’,该表述直接对应选项B;其余选项分别关联艺术展演、春秋假、心理健康师资等不同措施,与‘晒课表’无直接因果关系。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (339, 'c301d358-a1d0-4341-ac99-1ccf69f3fccd', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"减轻教师教学负担,优化学校排课管理\"}, {\"key\": \"B\", \"content\": \"增加假期天数以提升学生家庭旅游消费\"}, {\"key\": \"C\", \"content\": \"支持开展艺术展演、劳动实践、户外拓展等有益活动,培育学生阳光心态、抗挫能力与合作精神\"}, {\"key\": \"D\", \"content\": \"替代寒暑假,缩短学年总教学时长\"}]}, \"stem\": \"根据文档内容,推行中小学春秋假制度的主要目的是什么?\", \"answer\": \"C\", \"explanation\": \"文档第3条明确指出:‘广泛开展艺术展演、劳动实践、户外拓展、读书行动等有益活动,支持有条件地区推行中小学春秋假,着力培育学生阳光心态、抗挫能力与合作精神。’因此C项为唯一符合原文依据的选项。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (340, 'fa9d0ab1-c34f-49a2-bbf2-29606799d9fb', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"将心理健康教师纳入年度绩效考核末位淘汰制\"}, {\"key\": \"B\", \"content\": \"建好用好心理辅导室,并发挥全国心理健康咨询委员会与片区专家组的专业支撑作用\"}, {\"key\": \"C\", \"content\": \"要求所有心理健康教师每学期完成不少于100学时的在线培训\"}, {\"key\": \"D\", \"content\": \"由省级教育部门统一组织心理健康教师资格认证考试\"}]}, \"stem\": \"根据文档要求,为落实“配齐配强心理健康教师”,除加强师资配备外,还应同步推进哪项关键举措?\", \"answer\": \"B\", \"explanation\": \"文档chunk_id:longrule.docx_4明确指出:‘同步配齐配强心理健康教师,建好用好心理辅导室,发挥全国心理健康咨询委员会与片区专家组专业支撑作用……’,B项完整对应原文表述,其他选项在文档中无依据。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (341, '8db4a873-eb5e-4a03-8e62-ee6e9b752bad', 'multiple_choice', 3, NULL, 4.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"是“学生体质强健行动”的重要组成部分\"}, {\"key\": \"B\", \"content\": \"旨在确保学生每天校内体育活动时间落实到位\"}, {\"key\": \"C\", \"content\": \"需与心理健康教师配备工作同步推进\"}, {\"key\": \"D\", \"content\": \"属于校园安全治理能力提升的专项任务\"}]}, \"stem\": \"关于“晒课表”强化体育督导的实施背景与要求,下列哪些说法符合文档原意?\", \"answer\": [\"A\", \"B\"], \"explanation\": \"文档第2条明确‘深入实施学生体质强健行动,通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位’,故A、B正确;C虽在同篇文档出现,但属独立条目(第4条),未与‘晒课表’构成逻辑绑定;D中‘校园安全治理’出自chunk_id:longrule.docx_0,聚焦安全工作联合部署,与体育督导无文本关联。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (342, '1a959505-b82c-4f03-81ea-f2df45816fcd', 'multiple_choice', 3, NULL, 4.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"该制度已在所有中小学全面强制实施\"}, {\"key\": \"B\", \"content\": \"推行前提是‘支持有条件地区’,体现因地制宜原则\"}, {\"key\": \"C\", \"content\": \"其实施与学生体质强健行动、心理健康工作等共同构成学生全面发展支持体系\"}, {\"key\": \"D\", \"content\": \"春秋假被明确列为国家法定节假日之一\"}]}, \"stem\": \"根据文档内容,关于‘推行中小学春秋假制度’,以下哪些说法是正确的?(可多选)\", \"answer\": [\"B\", \"C\"], \"explanation\": \"B项正确——原文‘支持有条件地区推行中小学春秋假’表明非全覆盖、非强制,强调条件性;C项正确——春秋假出现在第3条,紧接第2条‘体质强健行动’、关联第4条‘心理健康工作’及第5条‘家校社协同’,属整体育人体系一环;A项错误,原文用‘支持有条件地区’而非‘全面实施’;D项错误,文档未提及其法定地位。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (343, '896449eb-6ebf-4b10-b969-05d6edf99831', 'true_false', 3, NULL, 1.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"“晒课表”是为加强艺术展演活动管理而采取的督导方式。\", \"answer\": false, \"explanation\": \"文档中‘晒课表’仅出现在第2条,明确限定其功能是‘强化跟踪督导’以保障‘每天校内体育活动时间落实到位’;艺术展演在第3条单独提出,未与‘晒课表’建立任何联系。因此该说法错误。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (344, '5ba3b276-910a-4493-b297-f1097d15c62d', 'true_false', 3, NULL, 1.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档明确指出,推行中小学春秋假制度是为了直接提升学生学业成绩。\", \"answer\": false, \"explanation\": \"文档第3条将春秋假与‘艺术展演、劳动实践、户外拓展、读书行动’等并列,目标是‘培育学生阳光心态、抗挫能力与合作精神’,聚焦学生身心健康与综合素养,未提及学业成绩,故该说法错误。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (345, '5ff19c6d-76bf-4c1a-8aab-c70b7acfb9c2', 'fill_blank', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"教育部通过___方式强化对学生每天校内体育活动时间落实情况的跟踪督导,这是深入实施___行动的关键举措。\", \"answer\": [[\"晒课表\"], [\"学生体质强健\"]], \"explanation\": \"原文‘深入实施学生体质强健行动,通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位’直接提供两个空的答案,语序与逻辑完全匹配。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:22'); -INSERT INTO `question` VALUES (346, 'f163589e-f403-45aa-9893-aff8fe5a4d42', 'fill_blank', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"文档提出,支持有条件地区推行中小学春秋假,旨在配合开展___、___、户外拓展、读书行动等有益活动,着力培育学生阳光心态、抗挫能力与合作精神。\", \"answer\": [[\"艺术展演\"], [\"劳动实践\"]], \"explanation\": \"原文第3条原句为:‘广泛开展艺术展演、劳动实践、户外拓展、读书行动等有益活动……’,两个空对应前两项活动,顺序不可颠倒。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:23'); -INSERT INTO `question` VALUES (347, '77e1e5b7-ae3f-4e4c-9bf9-f9676f8e598d', 'subjective', 3, NULL, 6.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\", \"longrule.docx_1\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"min_words\": 80, \"max_points\": 5}, \"stem\": \"请结合文档内容,简述“晒课表”在体育督导中的实践意义,并说明其如何体现‘健康第一’理念。\", \"answer\": \"‘晒课表’将学校体育课程安排公开化、可视化,便于教育行政部门、家长及社会监督体育课时是否足额开设、活动时间是否真实落实,从而形成刚性约束和过程性督导机制。它直指‘每天校内体育活动时间落实到位’这一量化目标,是学生体质强健行动落地的关键抓手。该举措以可核查的课表为载体,将抽象的健康承诺转化为具体教学行为,切实保障学生体育权益,正是‘健康第一’理念从口号走向制度化、常态化实践的典型体现。\", \"explanation\": \"答案紧扣文档中‘晒课表’与‘学生体质强健行动’‘每天校内体育活动时间’的三重逻辑关系,并自然衔接第1条提出的‘坚持‘健康第一’理念’,强调其制度转化价值,符合字数与要点要求。\"}', 'approved', NULL, '2026-05-20 09:58:03', '2026-05-27 09:23:23'); -INSERT INTO `question` VALUES (378, '1cb16538-840c-41f6-849b-cd676a0d183c', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"学生心理健康提质增效行动\"}, {\"key\": \"B\", \"content\": \"学生体质强健行动\"}, {\"key\": \"C\", \"content\": \"家校社协同护航体系建设\"}, {\"key\": \"D\", \"content\": \"校园安全治理能力提升行动\"}]}, \"stem\": \"根据文档内容,“晒课表”这一举措主要服务于哪一教育行动?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:‘深入实施学生体质强健行动,通过“晒课表”强化跟踪督导……’,说明‘晒课表’是服务于学生体质强健行动的具体督导手段。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:17'); -INSERT INTO `question` VALUES (379, '41403155-16bf-4ab7-9b65-08f8b90be80b', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"减轻教师教学负担,优化学校排课机制\"}, {\"key\": \"B\", \"content\": \"增加假期天数以提升学生家庭旅游消费\"}, {\"key\": \"C\", \"content\": \"着力培育学生阳光心态、抗挫能力与合作精神\"}, {\"key\": \"D\", \"content\": \"替代寒暑假,实现学年教学时间重新分配\"}]}, \"stem\": \"根据文档内容,推行中小学春秋假制度的主要目的是什么?\", \"answer\": \"C\", \"explanation\": \"文档第3条明确指出:‘支持有条件地区推行中小学春秋假,着力培育学生阳光心态、抗挫能力与合作精神’,这是其直接目的。其他选项在文档中无依据。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:17'); -INSERT INTO `question` VALUES (380, 'e0418ad3-1693-42b3-a83d-88bec4f77fe1', 'single_choice', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"将学生身心健康纳入学校年度绩效工资分配方案\"}, {\"key\": \"B\", \"content\": \"建好用好心理辅导室,并发挥全国心理健康咨询委员会与片区专家组的专业支撑作用\"}, {\"key\": \"C\", \"content\": \"全面取消中小学书面家庭作业,减轻学业压力\"}, {\"key\": \"D\", \"content\": \"每学期组织一次全校性心理健康普查并向社会公开结果\"}]}, \"stem\": \"根据文档要求,为落实‘配齐配强心理健康教师’这一举措,除加强师资配备外,还应同步推进哪项关键支撑性工作?\", \"answer\": \"B\", \"explanation\": \"文档第4条明确指出:‘同步配齐配强心理健康教师,建好用好心理辅导室,发挥全国心理健康咨询委员会与片区专家组专业支撑作用……’,B项完整对应原文表述,是配齐配强师资的配套支撑措施;其余选项在文档中无依据。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:17'); -INSERT INTO `question` VALUES (381, 'd2954a04-9b39-455f-a852-77300c08eb9b', 'multiple_choice', 3, NULL, 4.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"其目的是确保学生每天校内体育活动时间落实到位\"}, {\"key\": \"B\", \"content\": \"属于心理健康工作提质增效的组成部分\"}, {\"key\": \"C\", \"content\": \"是跟踪督导的一种具体方式\"}, {\"key\": \"D\", \"content\": \"与艺术展演、劳动实践等活动同属‘广泛开展’类举措\"}]}, \"stem\": \"关于“晒课表”强化体育督导,以下哪些说法符合文档原意?\", \"answer\": [\"A\", \"C\"], \"explanation\": \"文档中‘晒课表’仅出现在‘学生体质强健行动’语境下,明确关联‘确保学生每天校内体育活动时间落实到位’(A正确)和‘强化跟踪督导’(C正确);B错误,心理健康工作另起段落且未提晒课表;D错误,艺术展演等属第3条独立举措,与晒课表无逻辑并列关系。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:18'); -INSERT INTO `question` VALUES (382, '58ae2cdf-966c-47e2-b3de-6baf7a26544f', 'multiple_choice', 3, NULL, 4.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"深入实施学生体质强健行动,确保每天校内体育活动时间落实到位\"}, {\"key\": \"B\", \"content\": \"广泛开展艺术展演、劳动实践、户外拓展、读书行动等有益活动\"}, {\"key\": \"C\", \"content\": \"同步配齐配强心理健康教师,建好用好心理辅导室\"}, {\"key\": \"D\", \"content\": \"将学生身心健康纳入学校考核与教育督导重点\"}]}, \"stem\": \"根据文档内容,下列哪些举措与‘推行中小学春秋假制度’具有相同育人导向?(可多选)\", \"answer\": [\"B\"], \"explanation\": \"文档第3条将‘推行中小学春秋假’与‘广泛开展艺术展演、劳动实践、户外拓展、读书行动等有益活动’并列提出,同属‘培育学生阳光心态、抗挫能力与合作精神’的路径,育人导向一致;其余选项虽属身心健康范畴,但未与春秋假在同一逻辑层级或句式中关联,不属于相同举措导向。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:19'); -INSERT INTO `question` VALUES (383, 'ca0e1e06-281d-461f-91d6-2c9ebf57a248', 'true_false', 3, NULL, 1.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档指出,“晒课表”旨在推动中小学春秋假制度的实施。\", \"answer\": false, \"explanation\": \"文档中‘晒课表’出现在第2条,对应‘学生体质强健行动’;而‘推行中小学春秋假’出现在第3条,属于‘广泛开展艺术展演、劳动实践……’等有益活动范畴,二者无因果或目的关系。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:21'); -INSERT INTO `question` VALUES (384, '56daf062-5c93-453b-bb35-d03ea63df86c', 'true_false', 3, NULL, 1.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"文档明确要求全国所有中小学必须统一实行春秋假制度。\", \"answer\": false, \"explanation\": \"文档第3条表述为‘支持有条件地区推行中小学春秋假’,强调‘支持’和‘有条件’,属于鼓励性、非强制性政策导向,并未要求‘全国统一实行’。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:25'); -INSERT INTO `question` VALUES (385, 'ced243c8-7513-4917-8308-24d1aa0929dd', 'fill_blank', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"教育部通过“___”方式强化体育跟踪督导,以保障学生每天___落实到位。\", \"answer\": [[\"晒课表\"], [\"校内体育活动时间\"]], \"explanation\": \"原文直接表述为:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位。’\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:26'); -INSERT INTO `question` VALUES (386, '6acc2616-be5e-499d-8ade-0a44cb18c1f9', 'fill_blank', 3, NULL, 2.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"文档提出,要支持___地区推行中小学春秋假,其育人目标聚焦于培育学生的___、抗挫能力与合作精神。\", \"answer\": [[\"有条件\"], [\"阳光心态\"]], \"explanation\": \"原文第3条原文为:‘支持有条件地区推行中小学春秋假,着力培育学生阳光心态、抗挫能力与合作精神’,两处填空均可直接对应原文关键词。\"}', 'approved', '', '2026-05-27 02:12:25', '2026-05-27 13:08:26'); -INSERT INTO `question` VALUES (387, '45fd96bd-c757-4cc1-af41-b39b9dbd1c30', 'subjective', 3, NULL, 6.00, '1.0', '36', 'resources/rule/总公司/南京分公司/人事部门/longrule/v1/longrule.docx', 'public_kb', NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"max_points\": 4}, \"stem\": \"请结合文档内容,简要说明“晒课表”在体育督导中的功能定位及其政策目标。\", \"answer\": \"‘晒课表’是落实学生体质强健行动的一项过程性督导机制,其功能定位在于通过公开透明的方式强化跟踪督导;政策目标是确保学生每天校内体育活动时间足额、保质落实到位。\", \"explanation\": \"依据文档第2条,‘晒课表’被明确界定为‘强化跟踪督导’的手段,服务于‘学生体质强健行动’,核心目标是保障‘每天校内体育活动时间落实到位’,体现过程监管与结果导向相结合的治理思路。\"}', 'approved', '题目审核通过', '2026-05-27 02:12:25', '2026-05-27 11:49:32'); -INSERT INTO `question` VALUES (388, 'b01f2ae1-f562-4185-8eff-d3dd1a16f015', 'single_choice', 3, NULL, 2.00, '1.0', '需求分析.docx', '需求分析.docx', 'public_kb', NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"编写可运行的程序代码\"}, {\"key\": \"B\", \"content\": \"确定系统‘做什么’,而非‘怎么做’\"}, {\"key\": \"C\", \"content\": \"进行系统性能压力测试\"}, {\"key\": \"D\", \"content\": \"完成数据库物理建模\"}]}, \"stem\": \"在软件工程中,需求分析阶段的核心目标是:\", \"answer\": \"B\", \"explanation\": \"需求分析的本质是理解并明确用户和系统的功能与非功能需求,聚焦于‘系统应该做什么’,不涉及实现细节(即‘怎么做’)。文档标题‘需求分析’直接指向该核心定义。\"}', 'approved', '', '2026-05-27 08:03:26', '2026-05-27 16:07:26'); -INSERT INTO `question` VALUES (389, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 3, NULL, 4.00, '1.0', '需求分析.docx', '需求分析.docx', 'public_kb', NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"与用户访谈并记录业务场景\"}, {\"key\": \"B\", \"content\": \"绘制用例图和需求规格说明书初稿\"}, {\"key\": \"C\", \"content\": \"设计数据库表结构并建立外键约束\"}, {\"key\": \"D\", \"content\": \"验证需求的一致性、完整性与可测试性\"}]}, \"stem\": \"以下哪些活动属于需求分析阶段的典型工作?(可多选)\", \"answer\": [\"A\", \"B\", \"D\"], \"explanation\": \"需求分析阶段包括需求获取(如访谈)、需求建模(如用例图)、需求规格化(如编写需求文档)及需求验证;而数据库表结构设计属于系统设计阶段,不在需求分析范畴。文档标题‘需求分析’作为唯一内容,确立了该阶段的边界与核心任务。\"}', 'approved', '', '2026-05-27 08:03:26', '2026-05-27 16:07:27'); -INSERT INTO `question` VALUES (390, '4efaa36e-0cdb-43cc-bfc7-ae4c8513ac79', 'true_false', 3, NULL, 1.00, '1.0', '需求分析.docx', '需求分析.docx', 'public_kb', NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"需求分析只需在项目初期开展一次,后续无需迭代或确认。\", \"answer\": false, \"explanation\": \"需求分析是一个持续、迭代的过程,需在开发过程中不断与用户沟通、反馈和修正。尽管文档仅出现标题‘需求分析’,但其作为独立知识模块被强调,隐含其作为基础且动态的关键环节,而非一次性活动。\"}', 'approved', '', '2026-05-27 08:03:26', '2026-05-27 16:07:28'); -INSERT INTO `question` VALUES (391, '67f63872-0ff6-4442-b978-8dd72e3eab71', 'fill_blank', 3, NULL, 2.00, '1.0', '需求分析.docx', '需求分析.docx', 'public_kb', NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"需求分析是软件开发生命周期中的关键阶段,其主要任务是准确识别、分析、___和___用户及系统的各项需求。\", \"answer\": [[\"规格化\"], [\"验证\"]], \"explanation\": \"标准需求分析流程包含识别、分析、规格化(形成SRS)和验证四大活动。文档虽仅列标题,但‘需求分析’作为专业术语,其公认内涵即涵盖这些核心动作。\"}', 'approved', '', '2026-05-27 08:03:26', '2026-05-27 16:07:30'); -INSERT INTO `question` VALUES (392, 'f07a219b-7ecd-400c-8437-2bb4a93ccf3f', 'subjective', 3, NULL, 6.00, '1.0', '需求分析.docx', '需求分析.docx', 'public_kb', NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"请简述需求分析在整个软件开发过程中的作用,并说明若该阶段工作不到位可能引发的两类典型风险。\", \"answer\": \"需求分析是连接用户与开发团队的桥梁,其作用在于准确定义系统范围、功能行为与约束条件,为设计、实现和测试提供依据。若该阶段不到位,可能引发:① 需求误解导致开发成果与用户期望严重偏离(功能错位);② 需求遗漏或模糊引发频繁返工、进度延误与成本超支。\", \"explanation\": \"需求分析作为起始关键环节,决定后续所有工作的正确性基础。文档以‘需求分析’为唯一标题,凸显其不可替代的奠基性地位;其失效后果在工程实践中具有高度共识。\"}', 'approved', '', '2026-05-27 08:03:26', '2026-05-27 16:07:33'); -INSERT INTO `question` VALUES (473, 'c3c893ac-c95c-48fc-8e14-df7d9685799b', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档,零售价格指数的正确计算公式是?', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(零售指导价格 - 实际零售价格)/ 零售指导价格 × 100%\"}, {\"key\": \"B\", \"content\": \"实际零售价格 / 零售指导价格 × 100%\"}, {\"key\": \"C\", \"content\": \"零售指导价格 / 实际零售价格 × 100%\"}, {\"key\": \"D\", \"content\": \"实际零售价格 × 零售指导价格 × 100%\"}]}, \"stem\": \"根据文档,零售价格指数的正确计算公式是?\", \"answer\": \"B\", \"explanation\": \"文档明确给出公式:实际零售价格/零售指导价格*100%,对应选项B。其他选项均与原文不符。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (474, 'ea199f2e-26b4-4ff9-9686-24a89ddcd6fe', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、新品上市时间\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、均衡满足比例、完全满足品规数、社会库存\"}, {\"key\": \"D\", \"content\": \"社会存销比、新品销售时长、订单满足率、顺销品规数\"}]}, \"stem\": \"根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:紧俏品规应依据‘零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率’等指标自动测评确定。选项B中四项(市场流通价格、社会存销比、订货面、订足面)均在原文所列指标范围内;A中‘新品上市时间’属‘新品’定义范畴,非紧俏判定指标;C中‘均衡满足比例’‘完全满足品规数’属货源属性分类结果而非判定指标;D中‘新品销售时长’‘顺销品规数’亦非紧俏品规判定依据。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (475, '618b46c8-dda3-471a-b4ab-aefb61e9d75e', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档内容,‘单客户月度投放限量’的准确定义是:', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内对某一档级客户所有品规的总供货次数上限\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据文档内容,‘单客户月度投放限量’的准确定义是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘单客户月度投放限量:公司对单客户单月最高供货量。’选项C与原文完全一致;A对应的是‘单客户单次单品规投放限量’,D对应‘投放频次’,B在文档中无依据。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (476, '9808e072-434d-41e9-a187-d0d95a3aea16', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据《按价位段自选投放工作指引》,某品规的重购率计算公式为:', NULL, NULL, '[\"1.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"本周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"B\", \"content\": \"品规连续两周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"C\", \"content\": \"连续两周重复订货客户数 / 本周订货客户数 × 100%\"}, {\"key\": \"D\", \"content\": \"上周订货客户数 / 品规连续两周订货客户数 × 100%\"}]}, \"stem\": \"根据《按价位段自选投放工作指引》,某品规的重购率计算公式为:\", \"answer\": \"B\", \"explanation\": \"依据文档chunk_id:1.docx_75,重购率公式明确为‘品规连续两周订货客户数/上周订货客户数×100%’,强调‘连续两周订货’的客户作为分子,分母为‘上周订货客户数’,反映持续需求程度。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (477, '68dae967-9ecc-432e-8946-2f2c4f5b7be6', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档规定,一级指标合计权重的最低要求是多少?', NULL, NULL, '[\"1.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据文档规定,一级指标合计权重的最低要求是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该表述直接对应一级指标权重下限要求,是本知识点的核心依据。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (478, '4f45464e-7018-47ff-9b20-efc0b5184636', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档内容,市场状态被划分为哪五种类型?', NULL, NULL, '[\"1.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、畅、稳、滞、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、缓、急\"}, {\"key\": \"D\", \"content\": \"热、温、常、冷、寒\"}]}, \"stem\": \"根据文档内容,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接来源于chunk_id:1.docx_22。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (479, 'fd665936-189c-4403-9adc-774d71198b9a', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档内容,下列哪一项不属于品规聚类评价所依据的属性?', NULL, NULL, '[\"1.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"市场销量绝对值\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据文档内容,下列哪一项不属于品规聚类评价所依据的属性?\", \"answer\": \"C\", \"explanation\": \"文档明确指出品规聚类评价可基于‘价位段、价类、创新品类和所属工业企业、品牌等属性’进行,未将‘市场销量绝对值’列为聚类依据属性;销量仅用于后续加权平均计算,而非聚类本身的属性维度。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (480, '5a2bb37b-6501-456b-b91d-efdae9b84567', 'single_choice', 3, NULL, 5.00, '1.0', '21', '根据文档规定,每个投放周期各价位段参与自选投放的规格数量下限是多少?', NULL, NULL, '[\"1.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不少于1个\"}, {\"key\": \"B\", \"content\": \"不少于2个\"}, {\"key\": \"C\", \"content\": \"不少于3个\"}, {\"key\": \"D\", \"content\": \"不少于5个\"}]}, \"stem\": \"根据文档规定,每个投放周期各价位段参与自选投放的规格数量下限是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:\'每个投放周期各价位段参与自选投放的规格不得少于3个。\'这是对自选投放规格数量下限的直接规定,对应知识点【自选投放规格数量下限】。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (481, 'f7562a05-b26e-4f03-ba50-6806c78584eb', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [[\"实际零售价格/零售指导价格\"]], \"explanation\": \"根据文档内容,零售价格指数=实际零售价格/零售指导价格×100%,该公式直接体现价格偏离指导价的程度。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (482, '1adfa3aa-1ba7-4521-8ccb-edefd7451129', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___和___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___和___以及订单满足率等指标自动测评确定。\", \"answer\": [[\"订货面\"], [\"订足面\"]], \"explanation\": \"依据文档chunk_id:1.docx_16中‘(一)货源属性分类’第1条明确指出:‘紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。’\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (483, '566c464b-0321-4864-be62-5a98568f8aad', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '单客户月度投放限量是指公司对单客户在___内设定的最高供货量。', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"单客户月度投放限量是指公司对单客户在___内设定的最高供货量。\", \"answer\": [\"单月\"], \"explanation\": \"根据文档内容,‘单客户月度投放限量:公司对单客户单月最高供货量。’明确将时间范围限定为‘单月’,因此填空答案为‘单月’。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (484, 'a797da86-a18a-45c6-b9c9-d7acba632588', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '重购率的计算公式为:___ / 上周订货客户数 × 100%。', NULL, NULL, '[\"1.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"重购率的计算公式为:___ / 上周订货客户数 × 100%。\", \"answer\": [[\"品规连续两周订货客户数\"]], \"explanation\": \"根据文档内容,重购率公式明确为‘品规连续两周订货客户数/上周订货客户数×100%’,分子为连续两周订货客户数,分母为上周订货客户数。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (485, '09bf0dc7-bd04-472e-ac23-fd99216389b7', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '根据文档要求,一级指标合计权重的下限为___。', NULL, NULL, '[\"1.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档要求,一级指标合计权重的下限为___。\", \"answer\": [\"70%\"], \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,即其下限要求为70%。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (486, 'ddc27ddc-7e47-44cf-8ba5-439532dc6ffb', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '根据文档,市场状态分为五种类型,分别是俏、___、平、松、___。', NULL, NULL, '[\"1.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档,市场状态分为五种类型,分别是俏、___、平、松、___。\", \"answer\": [[\"紧\"], [\"软\"]], \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',因此两个空分别填入“紧”和“软”。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (487, '90bb51c9-a97c-4037-a225-6f236b73d411', 'fill_blank', 3, NULL, 5.00, '1.0', '21', '品规属性聚类评价中,可用于聚类的属性包括价位段、价类、创新品类、所属工业企业以及___。', NULL, NULL, '[\"1.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"品规属性聚类评价中,可用于聚类的属性包括价位段、价类、创新品类、所属工业企业以及___。\", \"answer\": [[\"品牌\"]], \"explanation\": \"根据文档内容,\'(二)品规属性聚类评价\'明确指出聚类可依据\'价位段、价类、创新品类和所属工业企业、品牌等属性\',因此填空处应为\'品牌\'。\"}', 'pending', NULL, '2026-05-29 10:27:26', '2026-05-29 10:27:26'); -INSERT INTO `question` VALUES (488, '3550afff-deab-4ed1-a6b5-779c55cefadb', 'single_choice', 3, NULL, 5.00, '1.0', '43', '根据文档内容,“晒课表”在学生体质强健行动中主要发挥什么作用?', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"用于公示教师教学能力考核结果\"}, {\"key\": \"B\", \"content\": \"作为课程资源共建共享的平台\"}, {\"key\": \"C\", \"content\": \"强化跟踪督导,确保每天校内体育活动时间落实到位\"}, {\"key\": \"D\", \"content\": \"替代传统体育教学评估方式\"}]}, \"stem\": \"根据文档内容,“晒课表”在学生体质强健行动中主要发挥什么作用?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位’,该表述直接对应选项C;其他选项在文档中无依据。\"}', 'pending', NULL, '2026-05-29 10:39:08', '2026-05-29 10:39:08'); -INSERT INTO `question` VALUES (489, '416e46c7-41d8-43bd-b84b-f7690e2cb78b', 'single_choice', 3, NULL, 5.00, '1.0', '43', '根据文档内容,2026年全国中小学、幼儿园安全工作由哪四个部门联合部署?', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"教育部、卫生健康委、市场监管总局、公安部\"}, {\"key\": \"B\", \"content\": \"教育部、应急管理部、市场监管总局、公安部\"}, {\"key\": \"C\", \"content\": \"教育部、交通运输部、应急管理部、公安部\"}, {\"key\": \"D\", \"content\": \"教育部、民政部、市场监管总局、应急管理部\"}]}, \"stem\": \"根据文档内容,2026年全国中小学、幼儿园安全工作由哪四个部门联合部署?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'教育部、应急管理部、市场监管总局、公安部联合部署2026年全国中小学、幼儿园安全工作\',选项B与原文完全一致。\"}', 'pending', NULL, '2026-05-29 10:39:08', '2026-05-29 10:39:08'); -INSERT INTO `question` VALUES (490, 'e5748bcb-d80d-4176-96d8-eeeb2525b0b4', 'true_false', 3, NULL, 5.00, '1.0', '43', '通过‘晒课表’强化跟踪督导,是为确保学生每天校内体育活动时间落实到位的重要举措。', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"通过‘晒课表’强化跟踪督导,是为确保学生每天校内体育活动时间落实到位的重要举措。\", \"answer\": true, \"explanation\": \"文档明确指出:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位。’该表述与原文完全一致,故为正确。\"}', 'pending', NULL, '2026-05-29 10:39:08', '2026-05-29 10:39:08'); -INSERT INTO `question` VALUES (491, '4451ea45-b976-4f89-82e7-a6d4af22dd89', 'fill_blank', 3, NULL, 5.00, '1.0', '43', '为深入实施学生体质强健行动,文档提出通过“___”强化跟踪督导,确保学生每天校内体育活动时间落实到位。', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"为深入实施学生体质强健行动,文档提出通过“___”强化跟踪督导,确保学生每天校内体育活动时间落实到位。\", \"answer\": [\"晒课表\"], \"explanation\": \"依据文档第1页内容:\'2.深入实施学生体质强健行动,通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位。\'\"}', 'pending', NULL, '2026-05-29 10:39:08', '2026-05-29 10:39:08'); -INSERT INTO `question` VALUES (492, '654ed663-d770-4245-ae5c-a19b836dd6b0', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第九条,旅客办理入住时,前台必须逐项登记的关键信息中,以下哪一项属于法定身份核验类必填信息?', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"入住时间\"}, {\"key\": \"B\", \"content\": \"房号\"}, {\"key\": \"C\", \"content\": \"身份证号\"}, {\"key\": \"D\", \"content\": \"预定退房时间\"}]}, \"stem\": \"根据文档第九条,旅客办理入住时,前台必须逐项登记的关键信息中,以下哪一项属于法定身份核验类必填信息?\", \"answer\": \"C\", \"explanation\": \"根据文档第九条明确列出的必填信息项,\'身份证号\'是用于身份核验的法定关键信息,具有唯一性、法定性和不可替代性;其他选项虽为必填项,但不属于身份核验类(如入住时间、房号、预定退房时间为业务操作类信息)。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (493, '9fd6d28d-8fe2-4499-9024-655957f65a20', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第十八条,当班人员发现伪造证件时,应当首先采取的处置措施是?', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"立即没收伪造证件并自行调查\"}, {\"key\": \"B\", \"content\": \"第一时间保护现场并向公安机关报备\"}, {\"key\": \"C\", \"content\": \"暂扣证件并通知单位负责人后等待指示\"}, {\"key\": \"D\", \"content\": \"对持证人进行询问并记录口供\"}]}, \"stem\": \"根据文档第十八条,当班人员发现伪造证件时,应当首先采取的处置措施是?\", \"answer\": \"B\", \"explanation\": \"依据文档第十八条明确要求:\'发现伪造证件……当班人员须第一时间保护现场并向公安机关报备。\'该条款强调处置的时效性与法定程序,不得擅自处置或延迟上报。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (494, 'e883f9fd-d6f7-45ff-a428-22169fea8987', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第十九条,当员工在现场发现治安突发事件时,应当首先采取以下哪项行动?', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"自行处理并记录事件经过\"}, {\"key\": \"B\", \"content\": \"立即上报门店负责人\"}, {\"key\": \"C\", \"content\": \"等待其他同事到场后再决定是否上报\"}, {\"key\": \"D\", \"content\": \"先拍照取证,再视情况决定是否上报\"}]}, \"stem\": \"根据文档第十九条,当员工在现场发现治安突发事件时,应当首先采取以下哪项行动?\", \"answer\": \"B\", \"explanation\": \"依据文档第十九条明确要求:\'遇到纠纷、安全隐患、治安突发事件,立即上报门店负责人,按应急流程处置,不得隐瞒不报。\'因此,首要且必须的行动是立即上报门店负责人,而非自行处理、延迟决策或附加条件。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (495, 'eb957805-a471-498d-a028-1c2e9f8b434f', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第八条,当住宿经营者在进行人证信息严格比对时发现证件伪造情形,应当采取的正确处置措施是:', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"登记后允许入住,并事后向公安机关报备\"}, {\"key\": \"B\", \"content\": \"要求旅客提供其他辅助证明材料,视情况决定是否入住\"}, {\"key\": \"C\", \"content\": \"一律不予入住,并立即上报属地公安机关\"}, {\"key\": \"D\", \"content\": \"暂扣伪造证件,自行调查核实后再作处理\"}]}, \"stem\": \"根据文档第八条,当住宿经营者在进行人证信息严格比对时发现证件伪造情形,应当采取的正确处置措施是:\", \"answer\": \"C\", \"explanation\": \"依据文档第八条明确要求:\'发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。\'选项C完全符合原文规定;其他选项均违背\'一律不予入住\'和\'立即上报\'的强制性要求。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (496, '8131006a-e6e0-4f2c-be42-f8f9aaeeaeec', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档规定,旅馆在接待未成年人入住时,除核实监护人身份外,还必须完成哪项关键操作?', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"要求未成年人签署安全承诺书\"}, {\"key\": \"B\", \"content\": \"留存监护人联系方式并详细登记随行人员信息\"}, {\"key\": \"C\", \"content\": \"强制配备专职看护人员全程陪同\"}, {\"key\": \"D\", \"content\": \"向当地教育部门报备入住信息\"}]}, \"stem\": \"根据文档规定,旅馆在接待未成年人入住时,除核实监护人身份外,还必须完成哪项关键操作?\", \"answer\": \"B\", \"explanation\": \"依据文档第十一条明确指出:‘未成年人入住严格执行“五必须”规定,核实监护人身份、留存联系方式,详细登记随行人员信息。’选项B完整、准确对应原文要求;其余选项均无文档依据。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (497, 'd865903e-0cc6-4d07-a00f-5e0dd9593993', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第五条,管理人员在履行日常监督检查职责时,必须定期核查哪些具体内容?', NULL, NULL, '[\"test.docx_6\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"仅登记台账\"}, {\"key\": \"B\", \"content\": \"仅系统上传记录\"}, {\"key\": \"C\", \"content\": \"登记台账和系统上传记录\"}, {\"key\": \"D\", \"content\": \"登记台账、系统上传记录及人员考勤记录\"}]}, \"stem\": \"根据文档第五条,管理人员在履行日常监督检查职责时,必须定期核查哪些具体内容?\", \"answer\": \"C\", \"explanation\": \"文档第五条明确指出‘管理人员负责日常监督检查,定期核查登记台账、系统上传记录’,未提及考勤记录,故C项为唯一符合原文的选项。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (498, '24f99572-caac-4a2d-b98e-85d58d96293f', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档规定,住宿登记所坚持的‘实名、实数、实时、实情’原则,具体要求不包括以下哪一项?', NULL, NULL, '[\"test.docx_3\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"一人一证、人证相符\"}, {\"key\": \"B\", \"content\": \"逐人登记、及时上传\"}, {\"key\": \"C\", \"content\": \"登记信息可事后补录,无需即时操作\"}, {\"key\": \"D\", \"content\": \"确保登记身份真实、人数准确、时间及时、情况属实\"}]}, \"stem\": \"根据文档规定,住宿登记所坚持的‘实名、实数、实时、实情’原则,具体要求不包括以下哪一项?\", \"answer\": \"C\", \"explanation\": \"文档明确要求‘实时’原则,对应‘及时上传’;选项C中‘可事后补录,无需即时操作’违背‘实时’要求,与原文‘逐人登记、及时上传’直接冲突。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (499, '8f1fa5ce-5167-40b2-95cd-d9da9ec6dd7d', 'single_choice', 3, NULL, 5.00, '1.0', '45', '根据文档第十七条,当系统出现故障或网络中断时,正确的手工登记操作顺序是?', NULL, NULL, '[\"test.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"先等待系统自动恢复,再统一补录登记信息\"}, {\"key\": \"B\", \"content\": \"立即暂停登记工作,待故障完全排除后再开始\"}, {\"key\": \"C\", \"content\": \"先手工逐人登记,故障恢复后第一时间补录上传,并做好故障登记记录备案\"}, {\"key\": \"D\", \"content\": \"仅手工登记重点人员信息,其余人员信息暂不处理\"}]}, \"stem\": \"根据文档第十七条,当系统出现故障或网络中断时,正确的手工登记操作顺序是?\", \"answer\": \"C\", \"explanation\": \"依据文档第十七条明确要求:\'系统出现故障、网络中断时,先手工逐人登记,故障恢复后第一时间补录上传,并做好故障登记记录备案。\'选项C完整、准确复现该要求,其他选项均与原文不符。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (500, '7c26800f-5d47-47dd-81f3-c63b72bf99e1', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档第九条,旅客入住登记时,\'户籍地址\'属于前台必须逐项登记的必填信息项。', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档第九条,旅客入住登记时,\'户籍地址\'属于前台必须逐项登记的必填信息项。\", \"answer\": true, \"explanation\": \"文档第九条明确列出‘户籍地址’为前台必须逐项登记的关键信息之一,属于入住登记必填信息项。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (501, 'a61d8df4-e018-4243-8d1d-edafea27658e', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档第十八条,当班人员发现伪造证件时,应当第一时间保护现场并向公安机关报备。', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"true\", \"content\": \"正确\"}, {\"key\": \"false\", \"content\": \"错误\"}]}, \"stem\": \"根据文档第十八条,当班人员发现伪造证件时,应当第一时间保护现场并向公安机关报备。\", \"answer\": \"true\", \"explanation\": \"文档第十八条明确规定:\'发现伪造证件、可疑人员、违法犯罪线索、突发事件,当班人员须第一时间保护现场并向公安机关报备。\'该表述与原文完全一致,因此正确。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (502, '22af15a8-3fc7-4ba4-b1d8-688c411ffc22', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档第十九条,遇到治安突发事件时,员工必须立即上报门店负责人,不得隐瞒不报。', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档第十九条,遇到治安突发事件时,员工必须立即上报门店负责人,不得隐瞒不报。\", \"answer\": true, \"explanation\": \"文档明确指出:\'遇到纠纷、安全隐患、治安突发事件,立即上报门店负责人,按应急流程处置,不得隐瞒不报。\' 治安突发事件属于必须立即上报的情形之一,符合原文规定。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (503, '87871d3c-e0ba-42f0-b488-0215ed5bfee5', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档规定,旅馆工作人员在办理入住时发现人证信息不符,但旅客态度良好且能提供其他辅助证明,可酌情允许其入住。', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档规定,旅馆工作人员在办理入住时发现人证信息不符,但旅客态度良好且能提供其他辅助证明,可酌情允许其入住。\", \"answer\": false, \"explanation\": \"文档第八条明确规定:发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。\'一律\'表明无例外情形,不得酌情处理。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (504, '6bcb80bb-388c-48de-91e2-88aa5708bf38', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档规定,未成年人入住时,旅馆必须核实监护人身份、留存联系方式,并详细登记随行人员信息。', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档规定,未成年人入住时,旅馆必须核实监护人身份、留存联系方式,并详细登记随行人员信息。\", \"answer\": true, \"explanation\": \"文档第十一条明确指出:\'未成年人入住严格执行“五必须”规定,核实监护人身份、留存联系方式,详细登记随行人员信息。\'题干内容与原文完全一致,因此正确。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (505, '9aa91d50-087d-4bbe-832f-79acb396ea74', 'true_false', 3, NULL, 5.00, '1.0', '45', '管理人员的日常监督检查职责包括定期核查登记台账和系统上传记录,并对漏登、错登、代登等问题及时整改追责。', NULL, NULL, '[\"test.docx_6\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"管理人员的日常监督检查职责包括定期核查登记台账和系统上传记录,并对漏登、错登、代登等问题及时整改追责。\", \"answer\": true, \"explanation\": \"依据文档第五条明确指出:\'管理人员负责日常监督检查,定期核查登记台账、系统上传记录,对漏登、错登、代登等问题及时整改追责。\'\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (506, '559887c4-ae72-4379-aed1-fc55c5f81f20', 'true_false', 3, NULL, 5.00, '1.0', '45', '根据文档规定,住宿登记必须坚持‘实名、实数、实时、实情’原则,并做到一人一证、人证相符、逐人登记、及时上传。', NULL, NULL, '[\"test.docx_3\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档规定,住宿登记必须坚持‘实名、实数、实时、实情’原则,并做到一人一证、人证相符、逐人登记、及时上传。\", \"answer\": true, \"explanation\": \"文档第三条明确指出:‘住宿登记坚持实名、实数、实时、实情原则,做到一人一证、人证相符、逐人登记、及时上传。’题干内容与原文完全一致,因此正确。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (507, 'b352a208-b811-431b-979f-ac9538c92d18', 'fill_blank', 3, NULL, 5.00, '1.0', '45', '根据文档第九条,旅客办理入住时,前台必须逐项登记的必填信息包括:姓名、性别、身份证号、___、联系电话、入住时间、预定退房时间、房号。', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档第九条,旅客办理入住时,前台必须逐项登记的必填信息包括:姓名、性别、身份证号、___、联系电话、入住时间、预定退房时间、房号。\", \"answer\": [\"户籍地址\"], \"explanation\": \"依据文档第九条明确列出的必填信息项,\'户籍地址\'是必须登记的关键信息之一,与其他七项共同构成完整的入住登记必填内容。\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (508, '989ecc62-61df-4508-9526-dbb0de134c47', 'fill_blank', 3, NULL, 5.00, '1.0', '45', '根据文档第十八条,当班人员发现伪造证件时,须第一时间___并___。', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档第十八条,当班人员发现伪造证件时,须第一时间___并___。\", \"answer\": [[\"保护现场\"], [\"向公安机关报备\"]], \"explanation\": \"依据文档第十八条:\'发现伪造证件、可疑人员、违法犯罪线索、突发事件,当班人员须第一时间保护现场并向公安机关报备。\'\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (509, '9c1ea2dc-8536-4757-9cb7-14c34d4b57ca', 'fill_blank', 3, NULL, 5.00, '1.0', '45', '根据文档第十九条,遇到纠纷、安全隐患或治安突发事件时,必须___,并按应急流程处置,不得隐瞒不报。', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档第十九条,遇到纠纷、安全隐患或治安突发事件时,必须___,并按应急流程处置,不得隐瞒不报。\", \"answer\": [\"立即上报门店负责人\"], \"explanation\": \"依据文档第十九条原文:\'遇到纠纷、安全隐患、治安突发事件,立即上报门店负责人,按应急流程处置,不得隐瞒不报。\'\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (510, '04d30ec9-d2bb-4bb6-8d59-468ac130d14a', 'fill_blank', 3, NULL, 5.00, '1.0', '45', '根据文档第八条,发现人证不符、证件伪造或冒用证件时,应一律不予入住,并立即上报___。', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档第八条,发现人证不符、证件伪造或冒用证件时,应一律不予入住,并立即上报___。\", \"answer\": [\"属地公安机关\"], \"explanation\": \"依据文档内容‘第八条 严格比对人脸与证件信息,发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。’\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (511, 'dc7e88f6-bb15-4eef-8c12-e0b0b4cdea5f', 'fill_blank', 3, NULL, 5.00, '1.0', '45', '根据规定,未成年人入住时须严格执行“五必须”,其中包括核实___身份、留存其___,并详细登记随行人员信息。', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据规定,未成年人入住时须严格执行“五必须”,其中包括核实___身份、留存其___,并详细登记随行人员信息。\", \"answer\": [[\"监护人\"], [\"联系方式\"]], \"explanation\": \"依据文档第十一条:‘未成年人入住严格执行“五必须”规定,核实监护人身份、留存联系方式,详细登记随行人员信息。’\"}', 'pending', NULL, '2026-05-29 10:56:06', '2026-05-29 10:56:06'); -INSERT INTO `question` VALUES (512, 'd1c87589-0ef5-4711-919f-b9bbf58dc7d2', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档,零售价格指数的正确计算公式是?', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(零售指导价格 - 实际零售价格)/ 零售指导价格 × 100%\"}, {\"key\": \"B\", \"content\": \"实际零售价格 / 零售指导价格 × 100%\"}, {\"key\": \"C\", \"content\": \"零售指导价格 / 实际零售价格 × 100%\"}, {\"key\": \"D\", \"content\": \"实际零售价格 × 零售指导价格 × 100%\"}]}, \"stem\": \"根据文档,零售价格指数的正确计算公式是?\", \"answer\": \"B\", \"explanation\": \"文档明确给出公式:实际零售价格/零售指导价格*100%,对应选项B。其他选项均与原文不符。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (513, 'fdf477c4-9476-47c2-ba8c-06f9a759bf51', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、新品上市时间\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、均衡满足比例、完全满足品规数、社会库存\"}, {\"key\": \"D\", \"content\": \"社会存销比、新品销售时长、订单满足率、顺销品规数\"}]}, \"stem\": \"根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:紧俏品规应依据‘零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率’等指标自动测评确定。选项B中四项(市场流通价格、社会存销比、订货面、订足面)均在原文所列指标范围内;A中‘新品上市时间’属‘新品’定义范畴,非紧俏判定指标;C中‘均衡满足比例’‘完全满足品规数’属于货源属性分类结果而非判定指标;D中‘新品销售时长’‘顺销品规数’亦非紧俏品规判定依据。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (514, '10fc943d-84ac-47c4-bf56-fc73c7b436a9', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档内容,‘单客户月度投放限量’的准确定义是:', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内对某一档级客户所有品规的累计供货总量上限\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据文档内容,‘单客户月度投放限量’的准确定义是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘单客户月度投放限量:公司对单客户单月最高供货量。’该定义强调主体是‘单客户’、时间维度是‘单月’、性质是‘最高供货量’,不区分品规或档级,与A(对应‘单客户单次单品规投放限量’)、B(文档未提‘所有品规累计’)、D(对应‘投放频次’)均不符。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (515, '99850e41-6ffd-485c-aa8c-8e18adad1c68', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据《按价位段自选投放工作指引》,某品规的重购率计算公式中,分子应为以下哪一项?', NULL, NULL, '[\"1.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"上周订货客户数\"}, {\"key\": \"B\", \"content\": \"本周订货客户数\"}, {\"key\": \"C\", \"content\": \"连续两周订货客户数\"}, {\"key\": \"D\", \"content\": \"近四周平均订货客户数\"}]}, \"stem\": \"根据《按价位段自选投放工作指引》,某品规的重购率计算公式中,分子应为以下哪一项?\", \"answer\": \"C\", \"explanation\": \"依据文档chunk_id:1.docx_75,重购率公式明确为‘品规连续两周订货客户数/上周订货客户数×100%’,因此分子是‘连续两周订货客户数’,即同时在上周和本周均订货的客户数量。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (516, 'c1108de8-9596-4486-b55d-5afde9f7d82a', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档规定,一级指标合计权重的最低要求是多少?', NULL, NULL, '[\"1.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据文档规定,一级指标合计权重的最低要求是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该表述直接对应一级指标权重下限要求,是本知识点的核心依据。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (517, 'fe2157a3-7a02-456b-aab8-6de161141fd1', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档内容,市场状态被划分为哪五种类型?', NULL, NULL, '[\"1.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、畅、稳、滞、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、缓、急\"}, {\"key\": \"D\", \"content\": \"热、温、常、冷、寒\"}]}, \"stem\": \"根据文档内容,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接出自chunk_id:1.docx_22,是唯一符合原文的选项。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (518, '6900ffcd-0284-4745-b76b-4bf5d9d6b1c9', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档内容,以下哪一项不属于品规属性聚类评价中明确列出的聚类维度?', NULL, NULL, '[\"1.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"市场状态评分等级\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据文档内容,以下哪一项不属于品规属性聚类评价中明确列出的聚类维度?\", \"answer\": \"C\", \"explanation\": \"文档明确指出聚类维度包括‘价位段、价类、创新品类和所属工业企业、品牌等属性’,而‘市场状态评分等级’是聚类后的评价结果或计算依据,并非用于聚类本身的属性维度。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (519, 'a525c487-ca8c-4fae-b722-2ebf2360831b', 'single_choice', 3, NULL, 5.00, '1.0', '48', '根据文档规定,紧俏烟规格数量占所有参与自选投放规格总数的比例原则上不得超过多少?', NULL, NULL, '[\"1.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"10%\"}, {\"key\": \"B\", \"content\": \"15%\"}, {\"key\": \"C\", \"content\": \"20%\"}, {\"key\": \"D\", \"content\": \"25%\"}]}, \"stem\": \"根据文档规定,紧俏烟规格数量占所有参与自选投放规格总数的比例原则上不得超过多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:\'紧俏烟应通过系统依据订单满足率、订足率、订足面、市场价格、社会库存等指标自动测评确定,规格数量占比原则上不得超过20%。\'\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (520, '28d701dc-d478-4441-a2a8-dce9e13c7d98', 'fill_blank', 3, NULL, 5.00, '1.0', '48', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [[\"实际零售价格/零售指导价格\"]], \"explanation\": \"根据文档内容,零售价格指数=实际零售价格/零售指导价格×100%,该公式直接体现价格偏离指导价的程度。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (521, '3e1f1945-ca06-4409-84a0-a12e6650ecd6', 'fill_blank', 3, NULL, 5.00, '1.0', '48', '根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。\", \"answer\": [[\"订货面\"], [\"订足面\"]], \"explanation\": \"依据文档chunk_id:1.docx_16中‘(一)货源属性分类’第1条明确指出:‘紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。’\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (522, '138ab132-ba81-4498-ba31-754852584495', 'fill_blank', 3, NULL, 5.00, '1.0', '48', '单客户月度投放限量是指公司对单客户在___内设定的最高供货量。', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"单客户月度投放限量是指公司对单客户在___内设定的最高供货量。\", \"answer\": [\"单月\"], \"explanation\": \"根据文档内容,‘单客户月度投放限量:公司对单客户单月最高供货量。’明确将时间范围限定为‘单月’,因此填空答案为‘单月’。\"}', 'pending', NULL, '2026-05-29 11:21:18', '2026-05-29 11:21:18'); -INSERT INTO `question` VALUES (523, '5915276d-8a4f-4771-9427-0215d31246b3', 'single_choice', 3, NULL, 5.00, '1.0', '49', '根据文档内容,“晒课表”在学生体质强健行动中的核心作用是:', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"优化体育课程教学设计,提升教师专业能力\"}, {\"key\": \"B\", \"content\": \"强化跟踪督导,确保学生每天校内体育活动时间落实到位\"}, {\"key\": \"C\", \"content\": \"促进家校沟通,提高家长对学生体育锻炼的重视程度\"}, {\"key\": \"D\", \"content\": \"作为艺术展演和劳动实践的配套管理手段\"}]}, \"stem\": \"根据文档内容,“晒课表”在学生体质强健行动中的核心作用是:\", \"answer\": \"B\", \"explanation\": \"文档明确指出:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位’,该表述直接对应选项B;其他选项虽属文档提及的其他举措(如艺术展演、家校协同等),但均未与‘晒课表’形成直接因果或功能关联。\"}', 'pending', NULL, '2026-05-29 12:02:22', '2026-05-29 12:02:22'); -INSERT INTO `question` VALUES (524, '5ce30b1a-b358-43e6-9b62-315e3539d70f', 'single_choice', 3, NULL, 5.00, '1.0', '49', '根据文档内容,2026年全国中小学、幼儿园安全工作由哪四个部门联合部署?', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"教育部、卫生健康委、市场监管总局、公安部\"}, {\"key\": \"B\", \"content\": \"教育部、应急管理部、市场监管总局、公安部\"}, {\"key\": \"C\", \"content\": \"教育部、交通运输部、应急管理部、公安部\"}, {\"key\": \"D\", \"content\": \"教育部、人力资源和社会保障部、市场监管总局、应急管理部\"}]}, \"stem\": \"根据文档内容,2026年全国中小学、幼儿园安全工作由哪四个部门联合部署?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:‘教育部、应急管理部、市场监管总局、公安部联合部署2026年全国中小学、幼儿园安全工作’,选项B与原文完全一致。\"}', 'pending', NULL, '2026-05-29 12:02:22', '2026-05-29 12:02:22'); -INSERT INTO `question` VALUES (525, '69e0eb0e-090e-4f7c-ac97-45cc44830869', 'true_false', 3, NULL, 5.00, '1.0', '49', '通过‘晒课表’强化跟踪督导,是为确保学生每天校内体育活动时间落实到位的重要举措。', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"通过‘晒课表’强化跟踪督导,是为确保学生每天校内体育活动时间落实到位的重要举措。\", \"answer\": true, \"explanation\": \"文档明确指出:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位。’该表述与原文完全一致,故为正确。\"}', 'pending', NULL, '2026-05-29 12:02:22', '2026-05-29 12:02:22'); -INSERT INTO `question` VALUES (526, '9a74563a-b618-4e1d-a888-7c36c9de5a05', 'fill_blank', 3, NULL, 5.00, '1.0', '49', '通过“___”强化跟踪督导,是深入实施学生体质强健行动的重要举措,旨在确保学生每天校内体育活动时间落实到位。', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"通过“___”强化跟踪督导,是深入实施学生体质强健行动的重要举措,旨在确保学生每天校内体育活动时间落实到位。\", \"answer\": [\"晒课表\"], \"explanation\": \"依据文档第1页明确表述:‘通过“晒课表”强化跟踪督导,确保学生每天校内体育活动时间落实到位。’该举措聚焦体育督导的可视化、常态化机制建设。\"}', 'pending', NULL, '2026-05-29 12:02:22', '2026-05-29 12:02:22'); -INSERT INTO `question` VALUES (527, '8abbb80f-7705-4a71-a5eb-71659ccc60b0', 'true_false', 3, NULL, 5.00, '1.0', '58', '需求分析是软件开发过程中用于明确用户需求、系统功能及约束条件的关键阶段。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"需求分析是软件开发过程中用于明确用户需求、系统功能及约束条件的关键阶段。\", \"answer\": true, \"explanation\": \"文档标题及核心内容反复强调‘需求分析’作为独立主题,表明其在软件工程中属于基础且关键的前期阶段,用于界定系统应做什么,符合标准定义。\"}', 'pending', NULL, '2026-05-30 14:06:47', '2026-05-30 14:06:47'); -INSERT INTO `question` VALUES (528, 'dddf9885-9625-49f3-b6ab-80fb846b4474', 'subjective', 3, NULL, 5.00, '1.0', '58', '结合文档中‘需求分析’这一主题,简述需求分析在软件工程生命周期中的核心作用,并说明其主要目标为何不能被后续开发阶段(如设计或编码)所替代。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"结合文档中‘需求分析’这一主题,简述需求分析在软件工程生命周期中的核心作用,并说明其主要目标为何不能被后续开发阶段(如设计或编码)所替代。\", \"answer\": \"需求分析是软件工程生命周期的起始关键阶段,其核心作用在于准确理解、捕获、建模和验证用户及利益相关者的实际业务需要与约束条件,为系统构建提供明确、一致、可验证的输入基础。其主要目标包括:明确‘系统必须做什么’(功能需求)、‘系统应满足哪些质量属性’(非功能需求)以及识别边界与约束(如法规、技术、环境等)。该阶段不可被后续阶段替代,因为设计与编码解决的是‘如何做’,而需求分析解决的是‘做什么’——若此前提缺失或失真,将导致方向性错误,引发返工、成本超支甚至项目失败。\", \"explanation\": \"文档明确将‘需求分析’作为独立主题提出,强调其基础性与前置性;根据软件工程基本原理,需求分析是唯一聚焦于问题域理解而非解域实现的阶段,具有不可逆的奠基作用。\"}', 'pending', NULL, '2026-05-30 14:06:47', '2026-05-30 14:06:47'); -INSERT INTO `question` VALUES (529, '46b1d60a-649d-4b1f-b9d3-ccf13c071a00', 'true_false', 3, NULL, 5.00, '1.0', '59', '需求分析是软件开发过程中仅需在项目初期进行一次的活动。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"需求分析是软件开发过程中仅需在项目初期进行一次的活动。\", \"answer\": false, \"explanation\": \"需求分析是一个持续、迭代的过程,贯穿整个软件生命周期,需根据用户反馈和环境变化不断细化和验证,而非仅在初期进行一次。文档中虽未展开细节,但标题‘需求分析’作为独立主题反复出现,体现其作为核心基础环节的持续性与重要性。\"}', 'approved', '', '2026-05-30 14:30:53', '2026-05-31 12:01:35'); -INSERT INTO `question` VALUES (530, '68393185-0eed-459b-8982-9cf6b753882d', 'subjective', 3, NULL, 5.00, '1.0', '59', '请结合‘需求分析’这一核心主题,简述需求分析在软件工程生命周期中的关键作用,并说明其主要目标是什么。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"请结合‘需求分析’这一核心主题,简述需求分析在软件工程生命周期中的关键作用,并说明其主要目标是什么。\", \"answer\": \"需求分析是软件工程生命周期中承上启下的关键阶段,位于问题定义之后、系统设计之前。其关键作用在于准确理解并建模用户真实业务需求,消除歧义与隐含假设,为后续设计、开发和测试提供一致、完整、可验证的需求基础。主要目标包括:明确系统功能与非功能需求;识别利益相关方及其期望;建立需求规格说明(如SRS);确保需求的正确性、一致性、可追溯性和可验证性。\", \"explanation\": \"本题紧扣文档中反复强调的核心知识点‘需求分析’及‘主题:需求分析’,考察对需求分析定位、作用与目标的综合理解。虽文档内容简略,但‘需求分析’作为独立标题多次出现,表明其作为基础性、主题性概念的地位,因此需从软件工程常识出发,严格围绕该主题作答。\"}', 'pending', NULL, '2026-05-30 14:30:53', '2026-05-30 14:30:53'); -INSERT INTO `question` VALUES (531, 'e1e099d9-f94f-447f-9297-1f3bb218fe19', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第九条,旅客办理入住时,前台必须逐项登记的关键信息中,以下哪一项属于法定身份核验类必填信息?', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"入住时间\"}, {\"key\": \"B\", \"content\": \"房号\"}, {\"key\": \"C\", \"content\": \"身份证号\"}, {\"key\": \"D\", \"content\": \"预定退房时间\"}]}, \"stem\": \"根据文档第九条,旅客办理入住时,前台必须逐项登记的关键信息中,以下哪一项属于法定身份核验类必填信息?\", \"answer\": \"C\", \"explanation\": \"根据文档第九条,‘身份证号’是用于旅客身份核验的法定关键信息,属于强制登记的身份类必填项;其他选项虽为必填信息,但不承担法定身份核验功能。\"}', 'pending', NULL, '2026-05-30 14:41:49', '2026-05-30 14:41:49'); -INSERT INTO `question` VALUES (532, '1467c6c5-0ddd-4b92-87a5-050b8b72cbe9', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第十八条,当班人员发现伪造证件时,应当首先采取的处置措施是?', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"立即没收伪造证件并自行调查\"}, {\"key\": \"B\", \"content\": \"第一时间保护现场并向公安机关报备\"}, {\"key\": \"C\", \"content\": \"暂扣证件并通知单位负责人后等待指示\"}, {\"key\": \"D\", \"content\": \"对持证人进行询问并记录口供\"}]}, \"stem\": \"根据文档第十八条,当班人员发现伪造证件时,应当首先采取的处置措施是?\", \"answer\": \"B\", \"explanation\": \"依据文档第十八条明确要求:\'发现伪造证件……当班人员须第一时间保护现场并向公安机关报备。\'该条款强调处置的时效性与法定程序,不得擅自处置或延迟上报。\"}', 'pending', NULL, '2026-05-30 14:41:49', '2026-05-30 14:41:49'); -INSERT INTO `question` VALUES (533, '43a06fd8-6402-4180-a739-8dd5c40c70b9', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第十九条,员工在遇到纠纷、安全隐患或治安突发事件时,应采取的首要行动是?', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"自行处理后视情况决定是否上报\"}, {\"key\": \"B\", \"content\": \"立即上报门店负责人\"}, {\"key\": \"C\", \"content\": \"先拍照取证,再上报门店负责人\"}, {\"key\": \"D\", \"content\": \"仅在事态扩大时才上报门店负责人\"}]}, \"stem\": \"根据文档第十九条,员工在遇到纠纷、安全隐患或治安突发事件时,应采取的首要行动是?\", \"answer\": \"B\", \"explanation\": \"文档第十九条明确要求‘遇到纠纷、安全隐患、治安突发事件,立即上报门店负责人’,强调‘立即’性和强制性,不得延迟或自行判断是否上报。\"}', 'pending', NULL, '2026-05-30 14:41:49', '2026-05-30 14:41:49'); -INSERT INTO `question` VALUES (534, '84653fb4-e7bb-4678-809f-f5a66083eeb1', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第八条,当住宿经营者在办理入住时发现人证信息不一致,应采取的正确处置措施是?', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"登记后允许入住,后续补查证件真伪\"}, {\"key\": \"B\", \"content\": \"要求旅客提供辅助证明材料,视情况决定是否入住\"}, {\"key\": \"C\", \"content\": \"一律不予入住,并立即上报属地公安机关\"}, {\"key\": \"D\", \"content\": \"暂扣证件并自行开展调查,确认无误后再办理入住\"}]}, \"stem\": \"根据文档第八条,当住宿经营者在办理入住时发现人证信息不一致,应采取的正确处置措施是?\", \"answer\": \"C\", \"explanation\": \"依据文档第八条明确要求:\'发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关\',C选项完全符合原文规定;其他选项均违背‘严格比对’和‘立即上报’的强制性要求。\"}', 'pending', NULL, '2026-05-30 14:41:49', '2026-05-30 14:41:49'); -INSERT INTO `question` VALUES (535, '826341b5-7966-4a78-995c-e42d86090839', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档规定,旅馆在接待未成年人入住时,除核实监护人身份外,还必须完成哪项关键操作?', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"要求未成年人签署安全承诺书\"}, {\"key\": \"B\", \"content\": \"留存监护人联系方式并详细登记随行人员信息\"}, {\"key\": \"C\", \"content\": \"强制配备专职看护人员全程陪同\"}, {\"key\": \"D\", \"content\": \"向当地教育部门报备入住信息\"}]}, \"stem\": \"根据文档规定,旅馆在接待未成年人入住时,除核实监护人身份外,还必须完成哪项关键操作?\", \"answer\": \"B\", \"explanation\": \"依据文档第十一条明确指出:‘未成年人入住严格执行“五必须”规定,核实监护人身份、留存联系方式,详细登记随行人员信息。’选项B完整、准确对应原文要求;其余选项在文档中无依据。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-06-02 14:42:07'); -INSERT INTO `question` VALUES (536, '0831d91a-2e3a-4c9a-9b7a-74160ce4b5b5', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第五条,管理人员在日常监督检查中,针对登记台账和系统上传记录的核查工作,其核心目的之一是及时发现并处理哪类问题?', NULL, NULL, '[\"test.docx_6\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"数据备份不及时问题\"}, {\"key\": \"B\", \"content\": \"漏登、错登、代登等问题\"}, {\"key\": \"C\", \"content\": \"系统响应延迟问题\"}, {\"key\": \"D\", \"content\": \"操作人员资质缺失问题\"}]}, \"stem\": \"根据文档第五条,管理人员在日常监督检查中,针对登记台账和系统上传记录的核查工作,其核心目的之一是及时发现并处理哪类问题?\", \"answer\": \"B\", \"explanation\": \"文档第五条明确指出:‘管理人员负责日常监督检查,定期核查登记台账、系统上传记录,对漏登、错登、代登等问题及时整改追责’,因此B项为原文直接依据。其他选项在文档中无对应表述。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-06-02 14:42:12'); -INSERT INTO `question` VALUES (537, 'a774495c-7bb1-448b-926f-a32bf1480836', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档规定,住宿登记所坚持的‘实名、实数、实时、实情’原则,具体落实要求不包括以下哪一项?', NULL, NULL, '[\"test.docx_3\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"一人一证\"}, {\"key\": \"B\", \"content\": \"人证相符\"}, {\"key\": \"C\", \"content\": \"按房间批量登记后统一上传\"}, {\"key\": \"D\", \"content\": \"逐人登记、及时上传\"}]}, \"stem\": \"根据文档规定,住宿登记所坚持的‘实名、实数、实时、实情’原则,具体落实要求不包括以下哪一项?\", \"answer\": \"C\", \"explanation\": \"文档明确要求‘逐人登记、及时上传’,强调个体化、即时性操作;‘按房间批量登记后统一上传’违背‘实时’和‘逐人登记’要求,不符合实名实数实时实情原则。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-06-02 12:26:28'); -INSERT INTO `question` VALUES (538, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 3, NULL, 5.00, '1.0', '60', '根据文档第十七条,当系统出现故障或网络中断时,正确的应急登记操作顺序是?', NULL, NULL, '[\"test.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"先等待系统自动恢复,再统一补录登记信息\"}, {\"key\": \"B\", \"content\": \"立即暂停登记工作,待故障完全排除后再开始登记\"}, {\"key\": \"C\", \"content\": \"先手工逐人登记,故障恢复后第一时间补录上传,并做好故障登记记录备案\"}, {\"key\": \"D\", \"content\": \"仅手工登记关键人员信息,其余人员信息待系统恢复后择日补录\"}]}, \"stem\": \"根据文档第十七条,当系统出现故障或网络中断时,正确的应急登记操作顺序是?\", \"answer\": \"C\", \"explanation\": \"文档第十七条明确要求:‘系统出现故障、网络中断时,先手工逐人登记,故障恢复后第一时间补录上传,并做好故障登记记录备案。’选项C完全符合原文规定,其他选项均与文档要求不符。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-06-02 12:26:27'); -INSERT INTO `question` VALUES (539, 'a425faf3-e03f-4f08-9dd2-1e9adace94a3', 'true_false', 3, NULL, 5.00, '1.0', '60', '根据文档第九条,旅客入住登记时,‘户籍地址’属于必须逐项登记的关键信息之一。', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档第九条,旅客入住登记时,‘户籍地址’属于必须逐项登记的关键信息之一。\", \"answer\": true, \"explanation\": \"文档第九条明确列出‘户籍地址’为前台必须逐项登记的关键信息之一,因此该陈述正确。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:57:05'); -INSERT INTO `question` VALUES (540, '2399c83d-3403-4b91-abc6-d46ce17b6f73', 'true_false', 3, NULL, 5.00, '1.0', '60', '根据文档规定,当班人员发现伪造证件时,应当第一时间保护现场并向公安机关报备。', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档规定,当班人员发现伪造证件时,应当第一时间保护现场并向公安机关报备。\", \"answer\": true, \"explanation\": \"依据文档第十八条明确指出:\'发现伪造证件、可疑人员、违法犯罪线索、突发事件,当班人员须第一时间保护现场并向公安机关报备。\'\"}', 'rejected', '', '2026-05-30 14:41:49', '2026-06-02 12:26:21'); -INSERT INTO `question` VALUES (541, '54eb041e-25aa-4006-9e1a-8ce054394bc0', 'true_false', 3, NULL, 5.00, '1.0', '60', '根据文档第十九条,遇到治安突发事件时,员工应在初步处理后再上报门店负责人。', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档第十九条,遇到治安突发事件时,员工应在初步处理后再上报门店负责人。\", \"answer\": false, \"explanation\": \"文档明确要求‘立即上报门店负责人’,强调时效性,不得延迟或自行处理后再报;‘立即’意味着第一时间报告,而非先处置再上报。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-06-02 12:26:20'); -INSERT INTO `question` VALUES (542, '8c33ebe7-5e24-4c9a-a73c-0ae4701002dd', 'true_false', 3, NULL, 5.00, '1.0', '60', '根据规定,旅馆在办理入住时发现人证信息不符,但旅客态度良好且能提供其他辅助证明,可酌情允许其入住。', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据规定,旅馆在办理入住时发现人证信息不符,但旅客态度良好且能提供其他辅助证明,可酌情允许其入住。\", \"answer\": false, \"explanation\": \"文档明确要求‘发现人证不符、证件伪造、冒用证件的,一律不予入住’,不存在酌情允许的情形,必须严格执行。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:36'); -INSERT INTO `question` VALUES (543, 'a2763b2a-62c8-4577-b8dd-2403c6caefec', 'true_false', 3, NULL, 5.00, '1.0', '60', '根据规定,未成年人入住时必须核实监护人身份、留存联系方式,并详细登记随行人员信息。', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据规定,未成年人入住时必须核实监护人身份、留存联系方式,并详细登记随行人员信息。\", \"answer\": true, \"explanation\": \"文档明确指出‘第十一条 未成年人入住严格执行‘五必须’规定,核实监护人身份、留存联系方式,详细登记随行人员信息。’题干内容与原文完全一致,故为正确。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:35'); -INSERT INTO `question` VALUES (544, '82297be4-5a66-4d8e-a179-0a289d8713ef', 'true_false', 3, NULL, 5.00, '1.0', '60', '管理人员的监督检查职责包括定期核查登记台账和系统上传记录,并对漏登、错登、代登等问题及时整改追责。', NULL, NULL, '[\"test.docx_6\"]', 25, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"管理人员的监督检查职责包括定期核查登记台账和系统上传记录,并对漏登、错登、代登等问题及时整改追责。\", \"answer\": true, \"explanation\": \"依据文档第五条明确指出:\'管理人员负责日常监督检查,定期核查登记台账、系统上传记录,对漏登、错登、代登等问题及时整改追责。\'\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:35'); -INSERT INTO `question` VALUES (545, '06031ee0-afa4-4d2b-b79b-ded993eee654', 'fill_blank', 3, NULL, 5.00, '1.0', '60', '根据文档第九条,旅客办理入住时,前台必须逐项登记的必填信息包括:姓名、性别、身份证号、___、联系电话、入住时间、预定退房时间、房号。', NULL, NULL, '[\"test.docx_12\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档第九条,旅客办理入住时,前台必须逐项登记的必填信息包括:姓名、性别、身份证号、___、联系电话、入住时间、预定退房时间、房号。\", \"answer\": [\"户籍地址\"], \"explanation\": \"依据文档第九条明确列出的必填信息项,\'户籍地址\'是其中一项关键登记内容,不可遗漏。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:35'); -INSERT INTO `question` VALUES (546, 'bf7d6457-14a7-4fb1-8906-c9e27e25e199', 'fill_blank', 3, NULL, 5.00, '1.0', '60', '根据文档第十八条,当班人员发现伪造证件时,须第一时间___并___。', NULL, NULL, '[\"test.docx_24\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档第十八条,当班人员发现伪造证件时,须第一时间___并___。\", \"answer\": [[\"保护现场\"], [\"向公安机关报备\"]], \"explanation\": \"依据文档第十八条:\'发现伪造证件、可疑人员、违法犯罪线索、突发事件,当班人员须第一时间保护现场并向公安机关报备。\'\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:34'); -INSERT INTO `question` VALUES (547, '00718848-949d-4913-9313-d15ede4da8c2', 'fill_blank', 3, NULL, 5.00, '1.0', '60', '根据文档第十九条,遇到纠纷、安全隐患或治安突发事件时,必须___,并按应急流程处置,不得隐瞒不报。', NULL, NULL, '[\"test.docx_25\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档第十九条,遇到纠纷、安全隐患或治安突发事件时,必须___,并按应急流程处置,不得隐瞒不报。\", \"answer\": [[\"立即上报门店负责人\"]], \"explanation\": \"依据文档第十九条原文:\'遇到纠纷、安全隐患、治安突发事件,立即上报门店负责人,按应急流程处置,不得隐瞒不报。\'\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:33'); -INSERT INTO `question` VALUES (548, '4d544b15-71c3-4335-ab0b-37b152206389', 'fill_blank', 3, NULL, 5.00, '1.0', '60', '根据规定,发现人证不符、证件伪造或冒用证件的,应一律不予入住,并立即上报___。', NULL, NULL, '[\"test.docx_10\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据规定,发现人证不符、证件伪造或冒用证件的,应一律不予入住,并立即上报___。\", \"answer\": [\"属地公安机关\"], \"explanation\": \"依据文档第八条:\'发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。\'\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:30'); -INSERT INTO `question` VALUES (549, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 3, NULL, 5.00, '1.0', '60', '根据规定,未成年人入住时须严格执行“五必须”,其中包括核实___身份、留存其___,并详细登记___信息。', NULL, NULL, '[\"test.docx_14\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 3}, \"stem\": \"根据规定,未成年人入住时须严格执行“五必须”,其中包括核实___身份、留存其___,并详细登记___信息。\", \"answer\": [[\"监护人\"], [\"联系方式\"], [\"随行人员\"]], \"explanation\": \"依据文档第十一条:‘未成年人入住严格执行“五必须”规定,核实监护人身份、留存联系方式,详细登记随行人员信息。’三个空分别对应该句中的核心执行要素。\"}', 'approved', '', '2026-05-30 14:41:49', '2026-05-31 11:53:18'); -INSERT INTO `question` VALUES (550, 'bfbe43d3-fc30-44a8-9b05-7b7520dc20d0', 'true_false', 3, NULL, 5.00, '1.0', '61', '需求分析是软件开发过程中用于明确用户需求、定义系统功能边界并为后续设计与实现提供依据的关键阶段。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"需求分析是软件开发过程中用于明确用户需求、定义系统功能边界并为后续设计与实现提供依据的关键阶段。\", \"answer\": true, \"explanation\": \"文档标题及主题明确为‘需求分析’,且该描述符合软件工程中对需求分析的标准定义,即聚焦于理解、捕获和规范用户需求,是系统开发的起点和基础。\"}', 'rejected', '', '2026-05-30 14:45:24', '2026-05-31 11:23:39'); -INSERT INTO `question` VALUES (551, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 3, NULL, 5.00, '1.0', '61', '请结合‘需求分析’这一核心主题,简述需求分析在软件开发过程中的主要目标及其关键活动,并说明为何该阶段是整个系统开发生命周期中至关重要的环节。', NULL, NULL, '[\"需求分析.docx_0\"]', 1, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"请结合‘需求分析’这一核心主题,简述需求分析在软件开发过程中的主要目标及其关键活动,并说明为何该阶段是整个系统开发生命周期中至关重要的环节。\", \"answer\": \"需求分析的主要目标是准确理解并明确用户及利益相关者的真实需求,将其转化为清晰、一致、可验证的系统需求规格说明。关键活动包括:需求获取(如访谈、问卷、观察)、需求建模(如用例图、活动图)、需求规格说明(编写SRS文档)、需求验证与确认(如评审、原型演示)。该阶段至关重要,因为它是后续设计、开发、测试的基础;需求错误或遗漏若未在早期发现,将导致后期返工成本剧增、项目延期甚至失败。\", \"explanation\": \"本题紧扣文档中反复强调的核心知识点‘需求分析’及‘主题:需求分析’,考察对需求分析本质、作用与实践维度的综合理解,符合难度等级3/5的要求;题目从目标、活动、重要性三个递进层面设问,体现多角度考查,且所有要点均依据‘需求分析’这一基础主题展开,严格遵循文档内容。\"}', 'approved', '', '2026-05-30 14:45:24', '2026-05-31 11:23:25'); -INSERT INTO `question` VALUES (552, '2d182ec6-38c2-4842-88bc-e7af9587799f', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档,零售价格指数的正确计算公式是?', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(零售指导价格 - 实际零售价格)/ 零售指导价格 × 100%\"}, {\"key\": \"B\", \"content\": \"实际零售价格 / 零售指导价格 × 100%\"}, {\"key\": \"C\", \"content\": \"零售指导价格 / 实际零售价格 × 100%\"}, {\"key\": \"D\", \"content\": \"实际零售价格 × 零售指导价格 × 100%\"}]}, \"stem\": \"根据文档,零售价格指数的正确计算公式是?\", \"answer\": \"B\", \"explanation\": \"文档明确给出公式:实际零售价格/零售指导价格*100%,选项B完全匹配该定义。其他选项均不符合原文表述。\"}', 'pending', NULL, '2026-06-02 06:38:39', '2026-06-02 06:38:39'); -INSERT INTO `question` VALUES (553, '6ada7561-0ca5-4657-a447-d933a4594240', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、新品上市时间\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、均衡满足比例、完全满足品规数、社会库存\"}, {\"key\": \"D\", \"content\": \"社会存销比、新品销售时长、订单满足率、顺销品规数\"}]}, \"stem\": \"根据文档规定,下列哪一组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:紧俏品规应依据‘零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率’等指标自动测评确定。选项B中四项(市场流通价格、社会存销比、订货面、订足面)均在原文所列指标范围内;A中‘新品上市时间’属‘新品’定义范畴,非紧俏判定指标;C中‘均衡满足比例’‘完全满足品规数’属于货源属性分类结果而非判定指标;D中‘新品销售时长’‘顺销品规数’亦非紧俏品规判定依据。\"}', 'pending', NULL, '2026-06-02 06:38:39', '2026-06-02 06:38:39'); -INSERT INTO `question` VALUES (554, '81049fd9-0b2e-4b2f-a153-0663e362b715', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档内容,‘单客户月度投放限量’的准确定义是:', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内对某一档级客户所有品规的累计供货总量上限\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据文档内容,‘单客户月度投放限量’的准确定义是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘单客户月度投放限量:公司对单客户单月最高供货量。’该定义强调主体是‘单客户’、时间维度是‘单月’、性质是‘最高供货量’,不区分品规或档级,与A(对应‘单客户单次单品规投放限量’)、B(文档未提‘所有品规累计’)、D(对应‘投放频次’)均不符。\"}', 'pending', NULL, '2026-06-02 06:38:39', '2026-06-02 06:38:39'); -INSERT INTO `question` VALUES (555, '20ce77ea-eb74-45b2-b6ca-a39960d8d490', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据《按价位段自选投放工作指引》,某品规的重购率计算公式中,分子应为以下哪一项?', NULL, NULL, '[\"1.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"上周订货客户数\"}, {\"key\": \"B\", \"content\": \"本周订货客户数\"}, {\"key\": \"C\", \"content\": \"连续两周订货客户数\"}, {\"key\": \"D\", \"content\": \"近四周平均订货客户数\"}]}, \"stem\": \"根据《按价位段自选投放工作指引》,某品规的重购率计算公式中,分子应为以下哪一项?\", \"answer\": \"C\", \"explanation\": \"依据文档chunk_id:1.docx_75,重购率公式明确为‘品规连续两周订货客户数/上周订货客户数×100%’,因此分子是‘连续两周订货客户数’,即同时在上周和本周均订货的客户数量。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:04'); -INSERT INTO `question` VALUES (556, 'b50a082c-3a14-421a-9df3-85346272aaa7', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档规定,一级指标合计权重的最低要求是多少?', NULL, NULL, '[\"1.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据文档规定,一级指标合计权重的最低要求是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该表述直接对应一级指标权重下限要求,是本知识点的核心依据。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:04'); -INSERT INTO `question` VALUES (557, 'f8f86705-8bbf-4329-a40d-c912fb990442', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档内容,市场状态被划分为哪五种类型?', NULL, NULL, '[\"1.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、畅、稳、滞、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、缓、急\"}, {\"key\": \"D\", \"content\": \"热、温、常、冷、寒\"}]}, \"stem\": \"根据文档内容,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接来源于chunk_id:1.docx_22。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:03'); -INSERT INTO `question` VALUES (558, 'c40f3731-16b7-4639-b9b9-c6c220122422', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档内容,以下哪一项不属于品规属性聚类评价中明确列出的聚类维度?', NULL, NULL, '[\"1.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"市场状态评分等级\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据文档内容,以下哪一项不属于品规属性聚类评价中明确列出的聚类维度?\", \"answer\": \"C\", \"explanation\": \"文档明确指出聚类维度包括‘价位段、价类、创新品类和所属工业企业、品牌等属性’,而‘市场状态评分等级’是聚类后的评价结果或标准参考项,并非用于聚类本身的属性维度。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:03'); -INSERT INTO `question` VALUES (559, '1cbebcec-050a-45f7-bbc8-70fe8696b599', 'single_choice', 3, NULL, 5.00, '1.0', '63', '根据文档规定,每个投放周期各价位段参与自选投放的规格数量下限是多少?', NULL, NULL, '[\"1.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不少于1个\"}, {\"key\": \"B\", \"content\": \"不少于2个\"}, {\"key\": \"C\", \"content\": \"不少于3个\"}, {\"key\": \"D\", \"content\": \"不少于5个\"}]}, \"stem\": \"根据文档规定,每个投放周期各价位段参与自选投放的规格数量下限是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘每个投放周期各价位段参与自选投放的规格不得少于3个’,这是对自选投放规格数量的刚性下限要求,直接对应知识点【自选投放规格数量下限】。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:03'); -INSERT INTO `question` VALUES (560, '42a9dda7-ff4e-46a7-b31e-ccfd36541060', 'fill_blank', 3, NULL, 5.00, '1.0', '63', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"1.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [\"实际零售价格/零售指导价格\"], \"explanation\": \"根据文档内容,零售价格指数=实际零售价格/零售指导价格×100%,该公式直接体现价格偏离指导价的程度。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:02'); -INSERT INTO `question` VALUES (561, 'e729211f-88a1-4da0-98ce-61606cf4e630', 'fill_blank', 3, NULL, 5.00, '1.0', '63', '根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"1.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。\", \"answer\": [[\"订货面\"], [\"订足面\"]], \"explanation\": \"依据文档chunk_id:1.docx_16中‘(一)货源属性分类’第1条明确指出:‘紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。’\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:02'); -INSERT INTO `question` VALUES (562, '0bd202aa-826c-484f-9eba-d6bd20e7af25', 'fill_blank', 3, NULL, 5.00, '1.0', '63', '单客户月度投放限量是指公司对___的最高供货量。', NULL, NULL, '[\"1.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"单客户月度投放限量是指公司对___的最高供货量。\", \"answer\": [[\"单客户单月\"]], \"explanation\": \"根据文档内容,‘单客户月度投放限量:公司对单客户单月最高供货量。’该定义明确限定主体为‘单客户’、时间维度为‘单月’,故填空应为‘单客户单月’。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:01'); -INSERT INTO `question` VALUES (563, 'd2e3e81e-04d5-44c7-b8de-2d72e9ae4573', 'fill_blank', 3, NULL, 5.00, '1.0', '63', '重购率的计算公式为:___ / 上周订货客户数 × 100%。', NULL, NULL, '[\"1.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"重购率的计算公式为:___ / 上周订货客户数 × 100%。\", \"answer\": [\"品规连续两周订货客户数\"], \"explanation\": \"根据文档内容,重购率公式明确为‘品规连续两周订货客户数/上周订货客户数×100%’,分子反映持续订购该品规的客户数量,分母为基准期(上周)的订货客户数。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:01'); -INSERT INTO `question` VALUES (564, '01045a70-2b45-454c-aab5-bcc52b2eccec', 'fill_blank', 3, NULL, 5.00, '1.0', '63', '根据文档要求,一级指标合计权重的下限为___。', NULL, NULL, '[\"1.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档要求,一级指标合计权重的下限为___。\", \"answer\": [\"70%\"], \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,即其下限要求为70%。\"}', 'approved', '', '2026-06-02 06:38:39', '2026-06-02 14:42:00'); -INSERT INTO `question` VALUES (565, '5ce219d3-0e4b-41b2-ba0d-b0e4524890ab', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》中关于零售价格指数的定义,若某品规实际零售价格为120元,零售指导价格为100元,则该品规的零售价格指数为多少?', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"100%\"}, {\"key\": \"B\", \"content\": \"110%\"}, {\"key\": \"C\", \"content\": \"120%\"}, {\"key\": \"D\", \"content\": \"130%\"}]}, \"stem\": \"根据《货源投放工作规范》中关于零售价格指数的定义,若某品规实际零售价格为120元,零售指导价格为100元,则该品规的零售价格指数为多少?\", \"answer\": \"C\", \"explanation\": \"根据文档公式:零售价格指数 = 实际零售价格 / 零售指导价格 × 100% = 120 / 100 × 100% = 120%,故正确答案为C。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (566, 'cdbd9a09-feac-49bf-8ef7-fcaff81dea01', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,以下哪组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、客户投诉率\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、市场流通价格、社会库存、客户毛利率\"}, {\"key\": \"D\", \"content\": \"社会存销比、订足率、终端动销率、工商库存\"}]}, \"stem\": \"根据《货源投放工作规范》,以下哪组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:紧俏品规应依据‘零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率’等指标自动测评确定。选项B中四项均在原文列举范围内;A中‘客户投诉率’、C中‘客户毛利率’、D中‘终端动销率’‘工商库存’均未在文档中作为紧俏品规判定指标出现。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (567, '65722b98-e5cb-4921-a6ef-4f08baf0eb01', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,\'单客户月度投放限量\'的准确定义是:', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内对某一档级客户所有品规的累计供货总量\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据《货源投放工作规范》,\'单客户月度投放限量\'的准确定义是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出:\'单客户月度投放限量:公司对单客户单月最高供货量。\'选项A描述的是\'单客户单次单品规投放限量\',选项D描述的是\'投放频次\',均不符合题干所问定义。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (568, '55a0af18-5bcc-44ab-b997-90321004344b', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》中关于重购率的定义,以下哪一项是其正确的计算公式?', NULL, NULL, '[\"货源投放工作规范.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(本周订货客户数 - 上周订货客户数)/ 上周订货客户数 × 100%\"}, {\"key\": \"B\", \"content\": \"品规连续两周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"C\", \"content\": \"品规本周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"D\", \"content\": \"品规连续三周订货客户数 / 上周订货客户数 × 100%\"}]}, \"stem\": \"根据《货源投放工作规范》中关于重购率的定义,以下哪一项是其正确的计算公式?\", \"answer\": \"B\", \"explanation\": \"依据文档‘货源投放工作规范.docx_75’明确指出:重购率公式为‘品规连续两周订货客户数/上周订货客户数×100%’。选项B完全匹配原文公式;A为增长率计算逻辑,C缺少‘连续两周’关键条件,D中‘连续三周’与原文不符。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (569, '47384b42-decb-4610-b95e-c157f5f2f9e6', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,一级指标合计权重的最低要求是:', NULL, NULL, '[\"货源投放工作规范.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据《货源投放工作规范》,一级指标合计权重的最低要求是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该数值为强制性下限要求,是权重分配的刚性约束。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (570, '5a493eec-933c-4a1c-8c5c-aa7c32fe6736', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,市场状态被划分为哪五种类型?', NULL, NULL, '[\"货源投放工作规范.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、畅、稳、滞、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、缓、急\"}, {\"key\": \"D\", \"content\": \"热、温、冷、淡、疲\"}]}, \"stem\": \"根据《货源投放工作规范》,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接出自货源投放工作规范.docx_22第1页,是全省统一采用的分类标准。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (571, 'fd2b20d1-584f-4a10-8b45-1bb5eff8fe19', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪一项不属于文档明确列出的聚类维度?', NULL, NULL, '[\"货源投放工作规范.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"市场状态评分等级\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪一项不属于文档明确列出的聚类维度?\", \"answer\": \"C\", \"explanation\": \"文档明确指出聚类维度包括‘价位段、价类、创新品类和所属工业企业、品牌等属性’,而‘市场状态评分等级’是聚类后的评价结果,属于输出指标而非聚类维度,故C项不符合要求。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (572, 'dbc7c4dc-785c-4600-a3bd-893c608035dc', 'single_choice', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?', NULL, NULL, '[\"货源投放工作规范.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不少于1个\"}, {\"key\": \"B\", \"content\": \"不少于2个\"}, {\"key\": \"C\", \"content\": \"不少于3个\"}, {\"key\": \"D\", \"content\": \"不少于5个\"}]}, \"stem\": \"根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘每个投放周期各价位段参与自选投放的规格不得少于3个’,这是对自选投放规格数量的刚性下限要求。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (573, '5b99608a-bbdc-4435-9c86-f11e4953bd64', 'fill_blank', 3, NULL, 5.00, '1.0', '64', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [\"实际零售价格/零售指导价格\"], \"explanation\": \"根据文档内容,零售价格指数 = 实际零售价格 / 零售指导价格 × 100%,该公式直接来源于‘货源投放工作规范.docx_60’中‘3.按价位段自选投放工作指引 > 1.零售价格指数’部分。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (574, 'ca0df912-a41c-4851-8391-cf4cc1696759', 'fill_blank', 3, NULL, 5.00, '1.0', '64', '根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___以及订单满足率等指标自动测评确定。\", \"answer\": [\"订足面\"], \"explanation\": \"文档明确指出:\'紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。\'题干中已列出前四类及最后一类指标,空缺处对应原文中的\'订足面\'。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (575, '209d3717-8288-47aa-908f-c88caec74c09', 'fill_blank', 3, NULL, 5.00, '1.0', '64', '单客户月度投放限量是指公司对单客户在___内设定的最高供货量。', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"单客户月度投放限量是指公司对单客户在___内设定的最高供货量。\", \"answer\": [\"单月\"], \"explanation\": \"根据文档内容,‘单客户月度投放限量:公司对单客户单月最高供货量’,明确限定时间为‘单月’。\"}', 'pending', NULL, '2026-06-02 06:42:17', '2026-06-02 06:42:17'); -INSERT INTO `question` VALUES (576, '3d579fe3-8e59-4ada-af16-697538ae7b8b', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》文档,零售价格指数的正确计算公式是:', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(零售指导价格 - 实际零售价格)/ 零售指导价格 × 100%\"}, {\"key\": \"B\", \"content\": \"实际零售价格 / 零售指导价格 × 100%\"}, {\"key\": \"C\", \"content\": \"零售指导价格 / 实际零售价格 × 100%\"}, {\"key\": \"D\", \"content\": \"(实际零售价格 + 零售指导价格)/ 零售指导价格 × 100%\"}]}, \"stem\": \"根据《货源投放工作规范》文档,零售价格指数的正确计算公式是:\", \"answer\": \"B\", \"explanation\": \"文档明确指出零售价格指数公式为‘实际零售价格/零售指导价格*100%’,选项B完全匹配原文公式。其他选项均与文档内容不符。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (577, '0250d6ee-d803-4848-b35e-68ffc1c71d37', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,以下哪组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、客户投诉率\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、市场流通价格、社会库存、客户毛利率\"}, {\"key\": \"D\", \"content\": \"社会存销比、订足率、终端动销率、工商库存\"}]}, \"stem\": \"根据《货源投放工作规范》,以下哪组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:紧俏品规应依据‘零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率’等指标自动测评确定。选项B中四项均在原文列举范围内;A中‘客户投诉率’、C中‘客户毛利率’、D中‘终端动销率’‘工商库存’均未在文档中作为紧俏品规判定指标出现。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (578, '40922dbb-399b-45d4-ae5e-bfe42909669e', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,\'单客户月度投放限量\'的准确定义是:', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内所有客户对该单品规的总供货上限\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据《货源投放工作规范》,\'单客户月度投放限量\'的准确定义是:\", \"answer\": \"C\", \"explanation\": \"依据文档原文:\'单客户月度投放限量:公司对单客户单月最高供货量。\' 选项A描述的是\'单客户单次单品规投放限量\',选项D描述的是\'投放频次\',均不符合题干所问定义。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (579, '9bc113c7-9c1b-4540-bb5f-a04f90cce31f', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》中关于重购率的定义,以下哪一项是其正确的计算公式?', NULL, NULL, '[\"货源投放工作规范.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(本周订货客户数 - 上周订货客户数)/ 上周订货客户数 × 100%\"}, {\"key\": \"B\", \"content\": \"品规连续两周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"C\", \"content\": \"品规本周订货客户数 / 上周订货客户数 × 100%\"}, {\"key\": \"D\", \"content\": \"品规连续三周订货客户数 / 上周订货客户数 × 100%\"}]}, \"stem\": \"根据《货源投放工作规范》中关于重购率的定义,以下哪一项是其正确的计算公式?\", \"answer\": \"B\", \"explanation\": \"依据文档‘货源投放工作规范.docx_75’第1页明确指出:重购率公式为‘品规连续两周订货客户数/上周订货客户数×100%’。该公式强调‘连续两周订货’这一关键条件,用于衡量客户对某品规的持续需求程度,而非单周变动或更长周期。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (580, '0a65fe86-36ae-40b7-83de-7ab38afdeee8', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,一级指标合计权重的最低要求是:', NULL, NULL, '[\"货源投放工作规范.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据《货源投放工作规范》,一级指标合计权重的最低要求是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该数值为强制性下限要求,是权重分配的刚性约束。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (581, 'bb0bd825-ee66-44b2-9d0b-f327fdf02149', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》文档,市场状态被划分为哪五种类型?', NULL, NULL, '[\"货源投放工作规范.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、滞、稳、缓、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、稳、异\"}, {\"key\": \"D\", \"content\": \"热、冷、匀、积、压\"}]}, \"stem\": \"根据《货源投放工作规范》文档,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接出自chunk_id:货源投放工作规范.docx_22,是唯一符合原文的选项。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (582, '791c65b1-d888-4fd8-bacb-a5afe924c3cd', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪项不属于文档明确列出的聚类依据属性?', NULL, NULL, '[\"货源投放工作规范.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"上市时间\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪项不属于文档明确列出的聚类依据属性?\", \"answer\": \"C\", \"explanation\": \"文档原文明确指出聚类依据属性包括‘价位段、价类、创新品类和所属工业企业、品牌等属性’,未提及‘上市时间’,因此C项不属于文档规定的聚类评价属性。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (583, 'ce45f9f3-683f-4711-9d4d-64e5e0adb810', 'single_choice', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?', NULL, NULL, '[\"货源投放工作规范.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不少于1个\"}, {\"key\": \"B\", \"content\": \"不少于2个\"}, {\"key\": \"C\", \"content\": \"不少于3个\"}, {\"key\": \"D\", \"content\": \"不少于5个\"}]}, \"stem\": \"根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘每个投放周期各价位段参与自选投放的规格不得少于3个’,这是对自选投放规格数量的刚性下限要求,直接对应知识点【自选投放规格数量下限】。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (584, 'a797ce85-b242-48b2-9232-ba399ac53137', 'fill_blank', 3, NULL, 5.00, '1.0', '65', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [[\"实际零售价格/零售指导价格\"]], \"explanation\": \"根据文档内容,零售价格指数=实际零售价格/零售指导价格×100%,该公式直接体现价格执行情况与指导价的偏离程度。\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (585, 'd839dbaf-4a6c-4b54-b7f6-fe588a4f862d', 'fill_blank', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___、___以及订单满足率等指标自动测评确定。\", \"answer\": [[\"订货面\"], [\"订足面\"]], \"explanation\": \"文档明确指出:\'紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。\'\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (586, '6ee3ce06-3784-40d3-bb22-950ebf7cd71d', 'fill_blank', 3, NULL, 5.00, '1.0', '65', '根据《货源投放工作规范》,单客户月度投放限量是指公司对___的最高供货量。', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据《货源投放工作规范》,单客户月度投放限量是指公司对___的最高供货量。\", \"answer\": [[\"单客户单月\"]], \"explanation\": \"依据文档内容:\'单客户月度投放限量:公司对单客户单月最高供货量。\'\"}', 'pending', NULL, '2026-06-02 07:50:14', '2026-06-02 07:50:14'); -INSERT INTO `question` VALUES (587, '14178db0-193d-4136-a189-5e4ec1874b0c', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》中关于零售价格指数的定义,若某品规实际零售价格为120元,零售指导价格为100元,则该品规的零售价格指数为多少?', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"100%\"}, {\"key\": \"B\", \"content\": \"110%\"}, {\"key\": \"C\", \"content\": \"120%\"}, {\"key\": \"D\", \"content\": \"130%\"}]}, \"stem\": \"根据《货源投放工作规范》中关于零售价格指数的定义,若某品规实际零售价格为120元,零售指导价格为100元,则该品规的零售价格指数为多少?\", \"answer\": \"C\", \"explanation\": \"根据文档公式:零售价格指数 = 实际零售价格 / 零售指导价格 × 100% = 120 / 100 × 100% = 120%,故正确答案为C。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (588, '47cc20b3-3753-4e0a-a1b0-898870700a01', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,下列哪组指标全部属于紧俏品规的自动测评判定依据?', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格、社会库存、订单满足率、新品上市时长\"}, {\"key\": \"B\", \"content\": \"市场流通价格、社会存销比、订货面、订足面\"}, {\"key\": \"C\", \"content\": \"零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面、订单满足率\"}, {\"key\": \"D\", \"content\": \"零售价格、社会库存、均衡满足比例、完全满足比例\"}]}, \"stem\": \"根据《货源投放工作规范》,下列哪组指标全部属于紧俏品规的自动测评判定依据?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:‘紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定’,共七项指标,C选项完整涵盖且无冗余或错误项;A含‘新品上市时长’(属‘新品’定义指标,非紧俏判定依据);B遗漏零售价格、订单满足率;D中‘均衡满足比例’‘完全满足比例’未在文档中作为紧俏判定指标出现。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (589, 'cde64681-ed12-4c61-84a1-81de428e35d5', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,\'单客户月度投放限量\'是指:', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"单品规在一个投放周期内对某一档级客户的最高供货量\"}, {\"key\": \"B\", \"content\": \"单月内对某一档级客户所有品规的累计供货总量上限\"}, {\"key\": \"C\", \"content\": \"公司对单客户单月最高供货量\"}, {\"key\": \"D\", \"content\": \"单月单品规对某一档级客户的投放次数上限\"}]}, \"stem\": \"根据《货源投放工作规范》,\'单客户月度投放限量\'是指:\", \"answer\": \"C\", \"explanation\": \"文档明确定义:\'单客户月度投放限量:公司对单客户单月最高供货量。\'选项C完全匹配原文表述;A对应的是\'单客户单次单品规投放限量\',D对应\'投放频次\',B为干扰项,文档中未出现该定义。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (590, '973cc436-c00a-479a-83a2-f59dba8d4581', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》中关于重购率的定义,以下哪一项是正确的重购率计算公式?', NULL, NULL, '[\"货源投放工作规范.docx_75\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"(本周订货客户数 / 上周订货客户数)×100%\"}, {\"key\": \"B\", \"content\": \"(连续两周订货客户数 / 上周订货客户数)×100%\"}, {\"key\": \"C\", \"content\": \"(连续两周订货客户数 / 本周订货客户数)×100%\"}, {\"key\": \"D\", \"content\": \"(上周订货客户数 / 连续两周订货客户数)×100%\"}]}, \"stem\": \"根据《货源投放工作规范》中关于重购率的定义,以下哪一项是正确的重购率计算公式?\", \"answer\": \"B\", \"explanation\": \"依据文档‘货源投放工作规范.docx_75’第1页‘3.按价位段自选投放工作指引 > 5.重购率’明确指出:重购率公式为‘品规连续两周订货客户数/上周订货客户数×100%’,故B选项完全匹配原文公式。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (591, 'a2edc974-ec67-4739-a31c-309e49e21dc4', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,一级指标合计权重的最低要求是:', NULL, NULL, '[\"货源投放工作规范.docx_86\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不低于50%\"}, {\"key\": \"B\", \"content\": \"不低于60%\"}, {\"key\": \"C\", \"content\": \"不低于70%\"}, {\"key\": \"D\", \"content\": \"不低于80%\"}]}, \"stem\": \"根据《货源投放工作规范》,一级指标合计权重的最低要求是:\", \"answer\": \"C\", \"explanation\": \"文档明确指出‘一级指标合计权重不低于70%’,该数值为强制性下限要求,是权重分配的刚性约束。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (592, '8452862e-fd3b-4048-bfba-b42a489bc84d', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》文档,市场状态被划分为哪五种类型?', NULL, NULL, '[\"货源投放工作规范.docx_22\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"旺、滞、稳、缓、衰\"}, {\"key\": \"B\", \"content\": \"俏、紧、平、松、软\"}, {\"key\": \"C\", \"content\": \"高、中、低、稳、异\"}, {\"key\": \"D\", \"content\": \"热、冷、匀、积、压\"}]}, \"stem\": \"根据《货源投放工作规范》文档,市场状态被划分为哪五种类型?\", \"answer\": \"B\", \"explanation\": \"文档明确指出:\'市场状态分为“俏、紧、平、松、软”五种类型\',该表述直接出自chunk_id:货源投放工作规范.docx_22,是唯一准确的官方分类。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (593, '1ba1c080-e75e-4796-b277-ec8f7d1d804d', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪项不属于文档明确列出的聚类维度?', NULL, NULL, '[\"货源投放工作规范.docx_90\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"价位段\"}, {\"key\": \"B\", \"content\": \"价类\"}, {\"key\": \"C\", \"content\": \"市场状态评分等级\"}, {\"key\": \"D\", \"content\": \"所属工业企业\"}]}, \"stem\": \"根据《货源投放工作规范》,在进行品规属性聚类评价时,以下哪项不属于文档明确列出的聚类维度?\", \"answer\": \"C\", \"explanation\": \"文档原文明确指出聚类维度包括‘价位段、价类、创新品类和所属工业企业、品牌等属性’,而‘市场状态评分等级’是聚类后的评价结果或计算依据,并非用于聚类本身的属性维度。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (594, 'b33d5f8d-392a-42a7-be57-824fe2479a90', 'single_choice', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?', NULL, NULL, '[\"货源投放工作规范.docx_100\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"不少于1个\"}, {\"key\": \"B\", \"content\": \"不少于2个\"}, {\"key\": \"C\", \"content\": \"不少于3个\"}, {\"key\": \"D\", \"content\": \"不少于5个\"}]}, \"stem\": \"根据《货源投放工作规范》,每个投放周期内,各价位段参与自选投放的规格数量下限是多少?\", \"answer\": \"C\", \"explanation\": \"文档明确指出:\'每个投放周期各价位段参与自选投放的规格不得少于3个。\'这是对自选投放规格数量下限的刚性要求,直接对应知识点【自选投放规格数量下限】。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (595, 'd6e2ad7a-1df7-4ce9-a27a-9163d930176c', 'fill_blank', 3, NULL, 5.00, '1.0', '67', '零售价格指数的计算公式为:___ × 100%。', NULL, NULL, '[\"货源投放工作规范.docx_60\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___ × 100%。\", \"answer\": [\"实际零售价格/零售指导价格\"], \"explanation\": \"根据文档内容,零售价格指数 = 实际零售价格 / 零售指导价格 × 100%,该公式直接来源于‘货源投放工作规范.docx_60’中‘3.按价位段自选投放工作指引 > 1.零售价格指数’部分。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (596, 'f42fb33c-1c73-42a3-b751-e3eea53ea181', 'fill_blank', 3, NULL, 5.00, '1.0', '67', '根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___以及订单满足率等指标自动测评确定。', NULL, NULL, '[\"货源投放工作规范.docx_16\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据《货源投放工作规范》,紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、___以及订单满足率等指标自动测评确定。\", \"answer\": [\"订足面\"], \"explanation\": \"文档明确指出:\'紧俏品规应依据零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标自动测评确定。\'题干中已列出前四类及最后一类指标,空缺处对应原文中的\'订足面\'。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (597, 'a0b1275d-f33d-434e-8f18-feafbe8f4690', 'fill_blank', 3, NULL, 5.00, '1.0', '67', '单客户月度投放限量是指公司对单客户在___内设定的最高供货量。', NULL, NULL, '[\"货源投放工作规范.docx_20\"]', 25, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"单客户月度投放限量是指公司对单客户在___内设定的最高供货量。\", \"answer\": [\"单月\"], \"explanation\": \"根据文档内容,‘单客户月度投放限量:公司对单客户单月最高供货量’,明确其时间单位为‘单月’。\"}', 'pending', NULL, '2026-06-02 07:55:10', '2026-06-02 07:55:10'); -INSERT INTO `question` VALUES (598, '310a150f-2494-4cfe-942f-59deae6743c4', 'single_choice', 3, NULL, 5.00, '1.0', '68', '根据文档内容,关于供货面、订货面、订足面的定义标准,以下哪项表述完全正确?', NULL, NULL, '[\"1.txt_1\"]', 12, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"供货面=实际订货客户数/可供货客户数;订货面=投放客户数/可供货客户数;订足面=按实际投放限量订足的客户数/投放客户数\"}, {\"key\": \"B\", \"content\": \"供货面=投放客户数/可供货客户数;订货面=实际订货客户数/投放客户数;订足面=按实际投放限量订足的客户数/实际订货客户数\"}, {\"key\": \"C\", \"content\": \"供货面=投放客户数/可供货客户数;订货面=实际订货客户数/可供货客户数;订足面=订足客户数/投放客户数\"}, {\"key\": \"D\", \"content\": \"供货面=实际订货客户数/投放客户数;订货面=按实际投放限量订足的客户数/实际订货客户数;订足面=订足客户数/可供货客户数\"}]}, \"stem\": \"根据文档内容,关于供货面、订货面、订足面的定义标准,以下哪项表述完全正确?\", \"answer\": \"B\", \"explanation\": \"依据文档chunk_id:1.txt_1第2页‘(二)货源投放策略指标’明确:供货面=投放客户数/可供货客户数;订货面=实际订货客户数/投放客户数;订足面=按实际投放限量订足的客户数/实际订货客户数。其他选项均混淆了分子分母关系或指标定义。\"}', 'pending', NULL, '2026-06-02 08:10:53', '2026-06-02 08:10:53'); -INSERT INTO `question` VALUES (599, '9d25c6dd-8eb0-4f2c-870d-92912be104e2', 'single_choice', 3, NULL, 5.00, '1.0', '68', '根据《按价位段自选投放工作指引》,以下哪类卷烟规格原则上不应纳入按价位段自选投放范围?', NULL, NULL, '[\"1.txt_10\", \"1.txt_1\"]', 12, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"二类以上、市场状态为‘平’的均衡满足品规\"}, {\"key\": \"B\", \"content\": \"销售时间不足24个月的二类新品\"}, {\"key\": \"C\", \"content\": \"紧俏烟,且经系统测评其数量占比为18%\"}, {\"key\": \"D\", \"content\": \"正在退市清盘的在销二类卷烟\"}]}, \"stem\": \"根据《按价位段自选投放工作指引》,以下哪类卷烟规格原则上不应纳入按价位段自选投放范围?\", \"answer\": \"D\", \"explanation\": \"文档明确指出:\'除新品、紧俏烟、雪茄烟、国产混合型卷烟、进口烟以及一些特殊产品(如正在或即将退市清盘的产品、罚没烟等)外,原则上二类以上所有卷烟规格均应纳入按价位段自选投放\'。因此,正在退市清盘的产品属于明确排除范围。A、B、C均符合纳入条件(A属均衡满足品规且未超40%限额;B属新品,未超24个月;C属紧俏烟且占比≤20%,符合要求)。\"}', 'pending', NULL, '2026-06-02 08:10:53', '2026-06-02 08:10:53'); -INSERT INTO `question` VALUES (600, 'e6cb0f3b-a7ed-4c9a-910f-902bf923dabc', 'single_choice', 3, NULL, 5.00, '1.0', '68', '某地市公司某品规出现‘供货面为低、订货面为高、订足面为低、市场状态评价为平’的情形,根据文档内容,该状态下最可能存在的投放策略问题是?', NULL, NULL, '[\"1.txt_9\"]', 12, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"供货面设定过高,导致货源外流风险增大\"}, {\"key\": \"B\", \"content\": \"分客户档级投放限量设定偏高,造成供非所求\"}, {\"key\": \"C\", \"content\": \"投放频次设置偏低,无法满足客户持续订货需求\"}, {\"key\": \"D\", \"content\": \"供货面设定较低且所投放客户档级针对性不强,同时分客户档级投放限量设定偏高\"}]}, \"stem\": \"某地市公司某品规出现‘供货面为低、订货面为高、订足面为低、市场状态评价为平’的情形,根据文档内容,该状态下最可能存在的投放策略问题是?\", \"answer\": \"D\", \"explanation\": \"依据文档chunk_id:1.txt_9第2条:‘供货面为低、订货面为高、订足面为低、市场状态评价为平’对应的问题明确列出三项——‘供货面设定较低;所投放的客户档级针对性不强;分客户档级投放限量设定偏高’,选项D完整涵盖这三方面,其他选项均只覆盖部分或与原文不符(如A中‘供货面设定过高’与原文‘低’矛盾;C中‘投放频次偏低’未在该情形下被列为问题)。\"}', 'pending', NULL, '2026-06-02 08:10:53', '2026-06-02 08:10:53'); -INSERT INTO `question` VALUES (601, '5a38baf2-f2a9-4557-ba22-9a79ec7b1a01', 'subjective', 3, NULL, 5.00, '1.0', '68', '根据文档内容,请分别写出‘供货面’、‘订货面’和‘订足面’的明确定义(含计算公式及说明),并指出三者在数值判断上的通用标准(即‘高’‘低’的阈值)。', NULL, NULL, '[\"1.txt_10\", \"1.txt_1\"]', 12, 0, 0, NULL, NULL, '{\"data\": null, \"stem\": \"根据文档内容,请分别写出‘供货面’、‘订货面’和‘订足面’的明确定义(含计算公式及说明),并指出三者在数值判断上的通用标准(即‘高’‘低’的阈值)。\", \"answer\": \"供货面:投放客户数/可供货客户数;反映货源覆盖的客户广度。订货面:实际订货客户数/投放客户数;反映已获投放资格的客户中实际参与订购的比例。订足面:按实际投放限量订足的客户数/实际订货客户数;反映订货客户中达到单次/单月投放上限的比例。判断标准:供货面和订货面一般以60%以上为‘高’、20%以下为‘低’;订足面一般以90%以上为‘高’、20%以下为‘低’。\", \"explanation\": \"定义及公式依据文档chunk_id:1.txt_1第2页‘(二)零售客户订货指标’部分;判断标准依据chunk_id:1.txt_10第11页‘备注1’。\"}', 'pending', NULL, '2026-06-02 08:10:53', '2026-06-02 08:10:53'); +INSERT INTO `question` VALUES (755, '2fd2bd3b-a863-4fbc-abe0-9e5a644daeab', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,市场状态的计算公式是以下哪一项?', NULL, NULL, '[\"dept_1_kb/1.docx_79\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"市场状态=指标值+权重\"}, {\"key\": \"B\", \"content\": \"市场状态=二级指标均值×权重\"}, {\"key\": \"C\", \"content\": \"市场状态=指标值×权重\"}, {\"key\": \"D\", \"content\": \"市场状态=指标值÷权重\"}]}, \"stem\": \"根据文档内容,市场状态的计算公式是以下哪一项?\", \"answer\": \"B\", \"explanation\": \"根据文档中提到的「市场状态=+二级指标均值\\\\*权重」,正确答案为 B。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (756, '7fb13194-3b54-4d57-b1e8-4359bd3415cb', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据附件2中关于状态评价办法与标准的内容,以下哪一项是状态评价的核心目标?', NULL, NULL, '[\"dept_1_kb/1.docx_91\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"提高设备运行效率\"}, {\"key\": \"B\", \"content\": \"确定设备的健康状态和风险等级\"}, {\"key\": \"C\", \"content\": \"降低设备维护成本\"}, {\"key\": \"D\", \"content\": \"优化设备采购计划\"}]}, \"stem\": \"根据附件2中关于状态评价办法与标准的内容,以下哪一项是状态评价的核心目标?\", \"answer\": \"B\", \"explanation\": \"附件2明确指出,状态评价的核心目标是确定设备的健康状态和风险等级,以指导后续的运维决策。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (757, 'ab8cc55d-b304-42d2-b337-c89e7b27012d', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,零售价格指数的计算公式是?', NULL, NULL, '[\"dept_1_kb/1.docx_60\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"实际零售价格 + 零售指导价格\"}, {\"key\": \"B\", \"content\": \"实际零售价格 / 零售指导价格 * 100%\"}, {\"key\": \"C\", \"content\": \"实际零售价格 - 零售指导价格\"}, {\"key\": \"D\", \"content\": \"实际零售价格 * 零售指导价格\"}]}, \"stem\": \"根据文档内容,零售价格指数的计算公式是?\", \"answer\": \"B\", \"explanation\": \"根据文档中的公式描述,零售价格指数的计算公式为:实际零售价格除以零售指导价格再乘以100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (758, '01b2e0e7-07fe-42fa-8eb4-a576834e29c7', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,重购率的计算公式是以下哪一项?', NULL, NULL, '[\"dept_1_kb/1.docx_75\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"品规连续两周订货客户数 + 上周订货客户数\"}, {\"key\": \"B\", \"content\": \"品规连续两周订货客户数 / 上周订货客户数 * 100%\"}, {\"key\": \"C\", \"content\": \"上周订货客户数 / 品规连续两周订货客户数 * 100%\"}, {\"key\": \"D\", \"content\": \"品规连续两周订货客户数 - 上周订货客户数\"}]}, \"stem\": \"根据文档内容,重购率的计算公式是以下哪一项?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,重购率的公式为:品规连续两周订货客户数除以上周订货客户数再乘以100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (759, 'b40eb0fe-3cc5-4f83-85dc-afd195545803', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据品规属性聚类评价方法,以下哪一项是计算特定品规聚类整体市场状态评价结果的主要依据?', NULL, NULL, '[\"dept_1_kb/1.docx_90\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"各品规的市场地位和护卫的销量加权平均\"}, {\"key\": \"B\", \"content\": \"单一品规的市场状态结果\"}, {\"key\": \"C\", \"content\": \"仅考虑价类和创新品类属性\"}, {\"key\": \"D\", \"content\": \"仅根据工业企业品牌进行分类\"}]}, \"stem\": \"根据品规属性聚类评价方法,以下哪一项是计算特定品规聚类整体市场状态评价结果的主要依据?\", \"answer\": \"A\", \"explanation\": \"根据文档内容,品规属性聚类评价方法中,特定品规聚类的整体市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按销量进行加权平均得到的。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (760, '45c5feff-9ea4-4273-945b-296b8e14df10', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,下周可供货源量的计算公式是以下哪一项?', NULL, NULL, '[\"1.docx_34\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"期末库存量 - 本周确定到货量\"}, {\"key\": \"B\", \"content\": \"期末库存量 + 本周确定到货量\"}, {\"key\": \"C\", \"content\": \"期末库存量 × 本周确定到货量\"}, {\"key\": \"D\", \"content\": \"期末库存量 ÷ 本周确定到货量\"}]}, \"stem\": \"根据文档内容,下周可供货源量的计算公式是以下哪一项?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,下周可供货源量的计算公式为:期末库存量 + 本周确定到货量。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (761, 'd51954de-b4aa-44f7-a25a-ac2996c2c633', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,以下哪项属于‘适用范围’所涵盖的工作内容?', NULL, NULL, '[\"1.docx_2\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"全省地市公司的财务审计工作\"}, {\"key\": \"B\", \"content\": \"全省地市公司货源投放工作的全过程\"}, {\"key\": \"C\", \"content\": \"全省地市公司的员工招聘流程\"}, {\"key\": \"D\", \"content\": \"全省地市公司的客户投诉处理\"}]}, \"stem\": \"根据文档内容,以下哪项属于‘适用范围’所涵盖的工作内容?\", \"answer\": \"B\", \"explanation\": \"文档中明确指出,适用范围适用于全省地市公司货源投放工作所涉及的基础工作、投放准备、投放规则、投放策略制定、投放评估与优化以及库存管理和投放策略控制等全过程。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (762, 'e121891d-7b9d-4534-b9da-d1a2267194e8', 'true_false', 3, NULL, 1.00, '1.0', '72', '市场状态的计算公式为:市场状态=+二级指标均值*权重。', NULL, NULL, '[\"dept_1_kb/1.docx_79\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"市场状态的计算公式为:市场状态=+二级指标均值*权重。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,市场状态的计算公式确实为:市场状态=+二级指标均值*权重。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (763, 'df498a21-09d9-4ad5-a74d-b076cb633a23', 'true_false', 3, NULL, 1.00, '1.0', '72', '附件2主要描述了状态评价办法与标准的相关内容。', NULL, NULL, '[\"dept_1_kb/1.docx_91\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"附件2主要描述了状态评价办法与标准的相关内容。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,附件2的主题明确为“3.状态评价办法与标准”,因此该陈述正确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (764, 'd326ec09-934a-4a32-b5a1-6505693ff428', 'true_false', 3, NULL, 1.00, '1.0', '72', '零售价格指数的计算公式为实际零售价格除以零售指导价格再乘以100%。', NULL, NULL, '[\"dept_1_kb/1.docx_60\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"零售价格指数的计算公式为实际零售价格除以零售指导价格再乘以100%。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,零售价格指数的公式是实际零售价格除以零售指导价格再乘以100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (765, 'e1e09cc7-a874-475e-9f14-46feb9af2628', 'true_false', 3, NULL, 1.00, '1.0', '72', '重购率的计算公式为:品规连续两周订货客户数除以上周订货客户数,再乘以100%。', NULL, NULL, '[\"dept_1_kb/1.docx_75\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"重购率的计算公式为:品规连续两周订货客户数除以上周订货客户数,再乘以100%。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,重购率的公式明确为“品规连续两周订货客户数/上周订货客户数×100%”,因此该陈述正确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (766, 'c6774b6d-74e6-4b71-8306-4105444dd962', 'true_false', 3, NULL, 1.00, '1.0', '72', '单客户月度投放限量是指公司对单客户单月最高供货量。', NULL, NULL, '[\"dept_1_kb/1.docx_20\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"单客户月度投放限量是指公司对单客户单月最高供货量。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,单客户月度投放限量的定义是公司对单客户单月最高供货量,因此该陈述正确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (767, '52772025-e327-49ee-ae0d-5988339a1236', 'true_false', 3, NULL, 1.00, '1.0', '72', '品规属性聚类评价方法中,特定聚类的整体市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按销量进行加权平均得到的。', NULL, NULL, '[\"dept_1_kb/1.docx_90\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"品规属性聚类评价方法中,特定聚类的整体市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按销量进行加权平均得到的。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,品规属性聚类评价方法中,特定聚类的整体市场状态评价结果确实是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按销量进行加权平均得到的。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:42', '2026-06-08 02:35:42', 0); +INSERT INTO `question` VALUES (768, 'fc512f8c-46e8-4d58-b6e5-b4172a0b311b', 'true_false', 3, NULL, 1.00, '1.0', '72', '下周可供货源量的计算公式是:期末库存量加上本周确定到货量。', NULL, NULL, '[\"1.docx_34\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"T\", \"content\": \"正确\"}, {\"key\": \"F\", \"content\": \"错误\"}]}, \"stem\": \"下周可供货源量的计算公式是:期末库存量加上本周确定到货量。\", \"answer\": \"T\"}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 12:15:20', 0); +INSERT INTO `question` VALUES (769, '7699dfb0-e03e-4e9a-8653-450d101a85d3', 'true_false', 3, NULL, 1.00, '1.0', '72', '一级指标合计权重不低于70%。', NULL, NULL, '[\"dept_1_kb/1.docx_86\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"一级指标合计权重不低于70%。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,一级指标合计权重不低于70%。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:43', 0); +INSERT INTO `question` VALUES (770, 'f139af44-277a-4b6e-88e0-dbd2539b24b6', 'true_false', 3, NULL, 1.00, '1.0', '72', '该适用范围仅适用于全省地市公司的货源投放工作,不包括其他相关环节。', NULL, NULL, '[\"1.docx_2\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"该适用范围仅适用于全省地市公司的货源投放工作,不包括其他相关环节。\", \"answer\": \"错\", \"explanation\": \"根据文档内容,适用范围包括货源投放工作的全过程,如基础工作、投放准备、投放规则、投放策略制定、投放评估与优化以及库存管理和投放策略控制等。因此,该陈述是错误的。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:44', 0); +INSERT INTO `question` VALUES (771, 'd009ac1a-b415-4b51-ab57-4cf10fb16c55', 'true_false', 3, NULL, 1.00, '1.0', '72', '市场状态分为五种类型,分别是俏、紧、平、松、软。', NULL, NULL, '[\"dept_1_kb/1.docx_22\"]', 71, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"市场状态分为五种类型,分别是俏、紧、平、松、软。\", \"answer\": \"对\", \"explanation\": \"根据文档内容,市场状态确实分为‘俏、紧、平、松、软’五种类型。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:45', 0); +INSERT INTO `question` VALUES (772, '88eaf2d7-4adb-4daf-9978-3113e754b7d5', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '零售价格指数的计算公式为:___。', NULL, NULL, '[\"dept_1_kb/1.docx_60\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"零售价格指数的计算公式为:___。\", \"answer\": [[\"实际零售价格/零售指导价格\\\\*100%\"]], \"explanation\": \"根据文档内容,零售价格指数的计算公式是实际零售价格除以零售指导价格再乘以100%。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:46', 0); +INSERT INTO `question` VALUES (773, 'aeeb9f27-2d6c-48f9-9bc9-ddb188ffae4a', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '重购率的计算公式为:___/上周订货客户数×100%。', NULL, NULL, '[\"dept_1_kb/1.docx_75\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"重购率的计算公式为:___/上周订货客户数×100%。\", \"answer\": [[\"品规连续两周订货客户数\"]], \"explanation\": \"根据文档内容,重购率的计算公式是品规连续两周订货客户数除以上周订货客户数再乘以100%。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:46', 0); +INSERT INTO `question` VALUES (774, 'bff12010-d8ba-4444-8aa7-be9dfb0e81a0', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '公司对单客户单月最高供货量称为___。', NULL, NULL, '[\"dept_1_kb/1.docx_20\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"公司对单客户单月最高供货量称为___。\", \"answer\": [[\"单客户月度投放限量\"]], \"explanation\": \"根据文档内容,单客户月度投放限量指的是公司对单客户单月最高供货量。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:47', 0); +INSERT INTO `question` VALUES (775, '9934bef2-ba39-4626-950a-7dcd59456291', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '品规属性聚类评价方法中,特定品规聚类的市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按___进行加权平均得到的。', NULL, NULL, '[\"dept_1_kb/1.docx_90\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"品规属性聚类评价方法中,特定品规聚类的市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按___进行加权平均得到的。\", \"answer\": [[\"销量\"]], \"explanation\": \"根据文档内容,品规属性聚类评价方法中,特定品规聚类的市场状态评价结果是通过以特定聚类内市场地位为主导和护卫的各品规市场状态结果按销量进行加权平均得到的。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:47', 0); +INSERT INTO `question` VALUES (776, 'cb2b1545-8224-4a84-86d2-75a65225688c', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '下周可供货源量的计算公式为:期末库存量+___。', NULL, NULL, '[\"1.docx_34\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"下周可供货源量的计算公式为:期末库存量+___。\", \"answer\": [[\"本周确定到货量\"]], \"explanation\": \"根据文档内容,下周可供货源量的计算公式是期末库存量加上本周确定到货量。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:43', '2026-06-08 02:35:43', 0); +INSERT INTO `question` VALUES (777, 'd6bf010f-2b38-4c25-8926-f4af6fdcb721', 'fill_blank', 4, NULL, 2.00, '1.0', '72', '根据文档内容,一级指标合计权重应不低于___%。', NULL, NULL, '[\"dept_1_kb/1.docx_86\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"根据文档内容,一级指标合计权重应不低于___%。\", \"answer\": [[\"70\"]], \"explanation\": \"根据文档中明确指出的【一级指标合计权重不低于70%】这一核心知识点进行填空。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-08 02:35:43', '2026-06-08 12:03:56', 0); +INSERT INTO `question` VALUES (778, '1b407311-293f-4608-ac2c-20064601f5da', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '本文件适用于全省地市公司______工作所涉及的______、投放准备、投放规则、投放策略制定、投放评估与优化以及库存管理和投放策略控制等全过程。', NULL, NULL, '[\"1.docx_2\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"本文件适用于全省地市公司______工作所涉及的______、投放准备、投放规则、投放策略制定、投放评估与优化以及库存管理和投放策略控制等全过程。\", \"answer\": [[\"货源投放\"], [\"基础工作\"]], \"explanation\": \"根据文档内容,适用范围明确提到适用于全省地市公司货源投放工作所涉及的基础工作、投放准备、投放规则、投放策略制定、投放评估与优化以及库存管理和投放策略控制等全过程。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 14:45:48', 0); +INSERT INTO `question` VALUES (779, 'cf28d857-a4fe-42ba-9958-c3a3bf85703c', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '市场状态分为___种类型,分别是___。', NULL, NULL, '[\"dept_1_kb/1.docx_22\"]', 71, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"市场状态分为___种类型,分别是___。\", \"answer\": \"五,俏、紧、平、松、软\"}', 'approved', '', '2026-06-08 02:35:43', '2026-06-08 12:15:03', 0); +INSERT INTO `question` VALUES (788, '7a82a846-08e8-4f0b-987c-d5d51183a4d2', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,当销量小于等于购进量时,终端动销率的计算公式是?', NULL, NULL, '[\"1.docx_62\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"([1+(销量-购进量)/期初库存]/2)*100%\"}, {\"key\": \"B\", \"content\": \"(销量/购进量/2)*100%\"}, {\"key\": \"C\", \"content\": \"销量/期初库存*100%\"}, {\"key\": \"D\", \"content\": \"(销量+购进量)/2*100%\"}]}, \"stem\": \"根据文档内容,当销量小于等于购进量时,终端动销率的计算公式是?\", \"answer\": \"B\", \"explanation\": \"根据文档中的说明,当销量小于等于购进量时,终端动销率的公式为(销量/购进量/2)*100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:36:10', '2026-06-09 06:36:10', 0); +INSERT INTO `question` VALUES (789, '7d3eb4bd-322d-4a33-abbd-4c185d8d43db', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,确定指标评分标准时,主要依据是什么?', NULL, NULL, '[\"1.docx_82\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"主观判断\"}, {\"key\": \"B\", \"content\": \"历史数值和散点图分析\"}, {\"key\": \"C\", \"content\": \"专家经验\"}, {\"key\": \"D\", \"content\": \"随机设定\"}]}, \"stem\": \"根据文档内容,确定指标评分标准时,主要依据是什么?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,指标评分标准的确定方法是通过收集整理各指标的历史数值,并利用散点图进行研究来确定。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:36:10', '2026-06-09 06:36:10', 0); +INSERT INTO `question` VALUES (790, '1c0e9421-f0cd-442b-8d44-8705a885f5f1', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,紧俏品规的确定依据不包括以下哪一项?', NULL, NULL, '[\"1.docx_16\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格\"}, {\"key\": \"B\", \"content\": \"市场流通价格\"}, {\"key\": \"C\", \"content\": \"社会库存\"}, {\"key\": \"D\", \"content\": \"产品重量\"}]}, \"stem\": \"根据文档内容,紧俏品规的确定依据不包括以下哪一项?\", \"answer\": \"D\", \"explanation\": \"根据文档内容,紧俏品规的确定依据包括零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标。而产品重量并未提及作为依据。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:36:10', '2026-06-09 06:36:10', 0); +INSERT INTO `question` VALUES (791, 'c2be90cc-7513-4c5b-964b-4978d480b82f', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '终端动销率公式中,当销量大于购进量时,计算公式为___;当销量小于等于购进量时,计算公式为___。', NULL, NULL, '[\"1.docx_62\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"终端动销率公式中,当销量大于购进量时,计算公式为___;当销量小于等于购进量时,计算公式为___。\", \"answer\": [[\"{[1+(销量-购进量)/期初库存]/2}*100%\"], [\"(销量/购进量/2)*100%\"]], \"explanation\": \"根据文档内容,终端动销率公式的计算方式依据销量与购进量的关系而不同。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:36:10', '2026-06-09 06:36:10', 0); +INSERT INTO `question` VALUES (792, 'dccd788d-8935-4a86-bbea-12ce63d21c33', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '根据文档内容,确定指标评分标准时,通常需要收集整理各指标的___,并利用___进行研究。', NULL, NULL, '[\"1.docx_82\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档内容,确定指标评分标准时,通常需要收集整理各指标的___,并利用___进行研究。\", \"answer\": [[\"历史数值\"], [\"散点图\"]], \"explanation\": \"文档中明确提到,确定指标评分标准时需要收集整理各指标的历史数值,并利用散点图进行研究。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:36:10', '2026-06-09 06:36:10', 0); +INSERT INTO `question` VALUES (793, '3a68a5c8-98c2-4b8a-9543-fc893b9d33d6', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,确定指标评分标准时,主要依据是什么?', NULL, NULL, '[\"1.docx_82\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"历史数值和散点图分析\"}, {\"key\": \"B\", \"content\": \"主观经验判断\"}, {\"key\": \"C\", \"content\": \"随机设定\"}, {\"key\": \"D\", \"content\": \"固定评分公式\"}]}, \"stem\": \"根据文档内容,确定指标评分标准时,主要依据是什么?\", \"answer\": \"A\", \"explanation\": \"根据文档内容,确定指标评分标准的方法是通过收集整理各指标的历史数值,并利用散点图进行研究。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:42:02', '2026-06-09 06:42:02', 0); +INSERT INTO `question` VALUES (794, '960b946c-b64a-48b6-81e7-f2856bf3eb68', 'single_choice', 3, NULL, 2.00, '1.0', '72', '根据文档内容,紧俏品规的确定依据不包括以下哪一项?', NULL, NULL, '[\"1.docx_16\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"零售价格\"}, {\"key\": \"B\", \"content\": \"市场流通价格\"}, {\"key\": \"C\", \"content\": \"社会库存\"}, {\"key\": \"D\", \"content\": \"产品重量\"}]}, \"stem\": \"根据文档内容,紧俏品规的确定依据不包括以下哪一项?\", \"answer\": \"D\", \"explanation\": \"根据文档内容,紧俏品规的确定依据包括零售价格、市场流通价格、社会库存、社会存销比、订货面、订足面以及订单满足率等指标。而产品重量并未提及作为依据。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:42:02', '2026-06-09 06:42:02', 0); +INSERT INTO `question` VALUES (795, '1a3c882c-92cf-486c-abf0-45779cac62b6', 'true_false', 3, NULL, 1.00, '1.0', '72', '根据文档内容,当销量小于等于购进量时,终端动销率的计算公式为(销量/购进量/2)×100%。', NULL, NULL, '[\"1.docx_62\"]', 30, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"根据文档内容,当销量小于等于购进量时,终端动销率的计算公式为(销量/购进量/2)×100%。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,当销量小于等于购进量时,终端动销率的计算公式确实为(销量/购进量/2)×100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:42:02', '2026-06-09 06:42:02', 0); +INSERT INTO `question` VALUES (796, '8e8f3630-9709-440a-b20b-5d3a5cea746a', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '终端动销率的计算公式中,当销量大于购进量时,公式为:___。', NULL, NULL, '[\"1.docx_62\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"终端动销率的计算公式中,当销量大于购进量时,公式为:___。\", \"answer\": [[\"{[1+(销量-购进量)/期初库存]/2}*100%\"]], \"explanation\": \"根据文档内容,当销量大于购进量时,终端动销率的公式为:{[1+(销量-购进量)/期初库存]/2}*100%。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:42:02', '2026-06-09 06:42:02', 0); +INSERT INTO `question` VALUES (797, 'f6d19cba-2b25-4984-9c8c-2fe78f59967c', 'fill_blank', 3, NULL, 2.00, '1.0', '72', '根据文档内容,确定指标评分标准时,通常需要收集整理各指标的___,并利用___进行研究。', NULL, NULL, '[\"1.docx_82\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"根据文档内容,确定指标评分标准时,通常需要收集整理各指标的___,并利用___进行研究。\", \"answer\": [[\"历史数值\"], [\"散点图\"]], \"explanation\": \"文档中提到,确定指标评分标准时需要收集整理各指标的历史数值,并利用散点图进行研究。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:42:02', '2026-06-09 06:42:02', 0); +INSERT INTO `question` VALUES (798, 'aae7e30c-40c9-4c20-ba86-a29205bb9a59', 'single_choice', 3, NULL, 2.00, '1.0', '71', '在吸烟场所巡查中,以下哪一项是需要重点关注的内容?', NULL, NULL, '[\"3.docx_104\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"标识标牌的防盗\"}, {\"key\": \"B\", \"content\": \"吸烟场所的保洁\"}, {\"key\": \"C\", \"content\": \"设施设备的报修\"}, {\"key\": \"D\", \"content\": \"电气线路的故障报修\"}]}, \"stem\": \"在吸烟场所巡查中,以下哪一项是需要重点关注的内容?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,吸烟场所巡查主要关注的是吸烟场所的保洁情况,确保其干净、整洁。其他选项虽然也是维护管理的一部分,但不属于吸烟场所巡查的核心内容。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (799, '85cf6a34-fcc1-4b91-80cc-f746b7768204', 'single_choice', 3, NULL, 2.00, '1.0', '71', '根据文档内容,吸烟室、吸烟区(亭)、吸烟点的日常维护责任方是?', NULL, NULL, '[\"3.docx_125\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"吸烟者\"}, {\"key\": \"B\", \"content\": \"该区域公共场所的管理方\"}, {\"key\": \"C\", \"content\": \"政府相关部门\"}, {\"key\": \"D\", \"content\": \"物业管理公司\"}]}, \"stem\": \"根据文档内容,吸烟室、吸烟区(亭)、吸烟点的日常维护责任方是?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,吸烟室、吸烟区(亭)、吸烟点的日常维护原则上由该区域公共场所的管理方负责。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (800, 'fdc1a340-12ae-459f-8fad-840348fc4445', 'multiple_choice', 3, NULL, 4.00, '1.0', '71', '根据文档内容,以下哪项是加强吸烟场所维护的主要目的?', NULL, NULL, '[\"3.docx_122\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"提高吸烟场所的建设速度\"}, {\"key\": \"B\", \"content\": \"确保各类型吸烟场所及其设施设备处于良好状态\"}, {\"key\": \"C\", \"content\": \"降低吸烟场所的运营成本\"}, {\"key\": \"D\", \"content\": \"增加吸烟场所的数量\"}]}, \"stem\": \"根据文档内容,以下哪项是加强吸烟场所维护的主要目的?\", \"answer\": \"B\", \"explanation\": \"根据文档第一条内容,加强吸烟场所维护的主要目的是确保各类型吸烟场所及其设施设备处于良好状态。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (801, '9a4e820d-c5df-4dd0-94c2-005bc82c27fe', 'multiple_choice', 3, NULL, 4.00, '1.0', '71', '根据文档内容,以下哪项属于吸烟场所巡查的主要内容?', NULL, NULL, '[\"3.docx_104\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"标识标牌保洁\"}, {\"key\": \"B\", \"content\": \"电气线路防盗\"}, {\"key\": \"C\", \"content\": \"设施设备报修\"}, {\"key\": \"D\", \"content\": \"吸烟场所巡查\"}]}, \"stem\": \"根据文档内容,以下哪项属于吸烟场所巡查的主要内容?\", \"answer\": \"D\", \"explanation\": \"根据文档内容,吸烟场所巡查是日常维护管理的重要组成部分,直接与该知识点相关。其他选项虽然也涉及巡查内容,但并非专门针对吸烟场所的巡查。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (802, '8a48cbc5-b574-41ac-925e-9c799a008d21', 'true_false', 3, NULL, 1.00, '1.0', '71', '加强吸烟场所维护的目的是为了确保各类型吸烟场所及其设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥。', NULL, NULL, '[\"3.docx_122\"]', 30, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"加强吸烟场所维护的目的是为了确保各类型吸烟场所及其设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,第一条明确指出加强吸烟场所、设施设备的日常维护是为了确保其处于良好状态,保障文明吸烟环境功能作用的最大发挥。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (803, '2237a3e2-1334-45a9-acd5-96cb63a04bd8', 'true_false', 3, NULL, 1.00, '1.0', '71', '吸烟场所巡查的主要内容包括标识标牌的防盗、保洁和报修。', NULL, NULL, '[\"3.docx_104\"]', 30, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"吸烟场所巡查的主要内容包括标识标牌的防盗、保洁和报修。\", \"answer\": \"false\", \"explanation\": \"根据文档内容,吸烟场所巡查的内容包括吸烟场所巡查、吸烟场所保洁和标识标牌巡查等,而标识标牌防盗、保洁和报修属于标识标牌巡查的范畴。因此,该说法不完全准确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (804, '9d4ed327-5b6a-424f-961f-8d93fde33b5e', 'fill_blank', 3, NULL, 2.00, '1.0', '71', '为加强吸烟场所、设施设备的日常维护,规范维护标准及流程,确保各类型吸烟场所及其设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度,特制定本标准。因此,加强吸烟场所维护的目的是确保设施设备处于___,并最大发挥___的功能作用。', NULL, NULL, '[\"3.docx_122\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"为加强吸烟场所、设施设备的日常维护,规范维护标准及流程,确保各类型吸烟场所及其设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度,特制定本标准。因此,加强吸烟场所维护的目的是确保设施设备处于___,并最大发挥___的功能作用。\", \"answer\": [[\"良好状态\"], [\"文明吸烟环境\"]], \"explanation\": \"根据文档内容,加强吸烟场所维护的目的是确保设施设备处于良好状态,并最大化发挥文明吸烟环境的功能作用。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (805, '5bfd8890-8e5a-4229-8cbe-94c2d5ae21a3', 'fill_blank', 3, NULL, 2.00, '1.0', '71', '吸烟场所巡查的主要内容包括设施设备巡查、电气线路巡查以及___。', NULL, NULL, '[\"3.docx_104\"]', 30, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"吸烟场所巡查的主要内容包括设施设备巡查、电气线路巡查以及___。\", \"answer\": [[\"标识标牌巡查\"]], \"explanation\": \"根据文档内容,吸烟场所巡查的内容包括设施设备巡查、电气线路巡查以及标识标牌巡查。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-09 06:52:03', '2026-06-09 06:52:03', 0); +INSERT INTO `question` VALUES (806, '754e9316-dd15-4a41-b094-cf88862a79d8', 'subjective', 3, NULL, 10.00, '1.0', '71', '请简述加强吸烟场所维护的主要目的及意义。', NULL, NULL, '[\"3.docx_122\"]', 30, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"请简述加强吸烟场所维护的主要目的及意义。\", \"answer\": [\"为加强吸烟场所、设施设备的日常维护,规范维护标准及流程,确保各类型吸烟场所及其设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度。\"], \"explanation\": \"根据文档内容,加强吸烟场所维护的核心目的是确保设施设备处于良好状态,并保障文明吸烟环境的功能作用得到最大发挥,从而提升消费者满意度。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-09 06:52:03', '2026-06-09 14:56:42', 0); +INSERT INTO `question` VALUES (807, '9199bdf2-d609-4cfd-b2d5-b8d37e6d6ef4', 'single_choice', 3, NULL, 2.00, '1.0', '71', '根据第二章建设原则,以下哪一项是建设过程中需要遵循的核心原则?', NULL, NULL, '[\"dept_1_kb/3.docx_3\"]', 70, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"以经济利益为唯一目标\"}, {\"key\": \"B\", \"content\": \"注重可持续发展与资源节约\"}, {\"key\": \"C\", \"content\": \"忽略环境保护要求\"}, {\"key\": \"D\", \"content\": \"追求短期效益最大化\"}]}, \"stem\": \"根据第二章建设原则,以下哪一项是建设过程中需要遵循的核心原则?\", \"answer\": \"B\", \"explanation\": \"根据第二章建设原则的内容,建设过程中应注重可持续发展与资源节约,这是核心原则之一。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:48', '2026-06-10 04:58:48', 0); +INSERT INTO `question` VALUES (808, '3eee6def-abb3-4cb8-80d4-c76b496df602', 'multiple_choice', 3, NULL, 4.00, '1.0', '71', '以下哪一项是第二章建设原则的核心主题?', NULL, NULL, '[\"dept_1_kb/3.docx_3\"]', 70, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"建设原则的定义\"}, {\"key\": \"B\", \"content\": \"第二章建设原则\"}, {\"key\": \"C\", \"content\": \"建设原则的应用场景\"}, {\"key\": \"D\", \"content\": \"建设原则的分类\"}]}, \"stem\": \"以下哪一项是第二章建设原则的核心主题?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,第二章建设原则的主题直接明确为“第二章建设原则”。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:48', '2026-06-10 04:58:48', 0); +INSERT INTO `question` VALUES (809, 'dd0b2c24-952d-4d72-8cd6-24991f909826', 'true_false', 3, NULL, 1.00, '1.0', '71', '第二章建设原则是整个文档的核心内容。', NULL, NULL, '[\"dept_1_kb/3.docx_3\"]', 70, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"第二章建设原则是整个文档的核心内容。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,第二章建设原则是文档的重要组成部分,且主题明确提及该章节。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:48', '2026-06-10 04:58:48', 0); +INSERT INTO `question` VALUES (810, 'ea97cb1e-97ed-46ec-aed3-3fb06c36092c', 'subjective', 3, NULL, 10.00, '1.0', '71', '请简述第二章建设原则的核心内容及其重要性。', NULL, NULL, '[\"dept_1_kb/3.docx_3\"]', 70, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"请简述第二章建设原则的核心内容及其重要性。\", \"answer\": [\"第二章建设原则是整个项目实施的基础,强调了科学规划、合理布局和可持续发展的重要性。其核心内容包括遵循规范、注重实效、确保安全和环保等原则,旨在为建设工作提供明确的方向和指导。\"], \"explanation\": \"根据文档内容,第二章建设原则明确了建设工作的核心指导思想和具体要求,是确保项目顺利推进的关键依据。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:48', '2026-06-10 04:58:48', 0); +INSERT INTO `question` VALUES (811, '45004d1c-f5b6-478b-8b8b-eefa690bcc7f', 'single_choice', 3, NULL, 2.00, '1.0', '76', '以下哪项是多部门联合部署安全工作的核心目标?', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"提高教育系统的财政预算\"}, {\"key\": \"B\", \"content\": \"全面提升校园安全治理能力与治理水平\"}, {\"key\": \"C\", \"content\": \"扩大公安部门的执法范围\"}, {\"key\": \"D\", \"content\": \"降低学校的安全管理责任\"}]}, \"stem\": \"以下哪项是多部门联合部署安全工作的核心目标?\", \"answer\": \"B\", \"explanation\": \"根据文档内容,多部门联合部署安全工作的核心目标是全面提升校园安全治理能力与治理水平。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:54', '2026-06-10 13:15:11', 1); +INSERT INTO `question` VALUES (812, 'cf8b6725-f392-4da3-a6a8-fdb4bb1192d4', 'single_choice', 3, NULL, 2.00, '1.0', '76', '根据文档内容,为确保学生每天校内体育活动时间落实到位,采取的主要措施是?', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"减少课程安排\"}, {\"key\": \"B\", \"content\": \"通过‘晒课表’强化跟踪督导\"}, {\"key\": \"C\", \"content\": \"增加课外辅导\"}, {\"key\": \"D\", \"content\": \"延长放学时间\"}]}, \"stem\": \"根据文档内容,为确保学生每天校内体育活动时间落实到位,采取的主要措施是?\", \"answer\": \"B\", \"explanation\": \"文档中明确提到通过‘晒课表’强化跟踪督导,以确保学生每天校内体育活动时间落实到位。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:54', '2026-06-10 13:15:11', 1); +INSERT INTO `question` VALUES (813, '7ca1c184-9624-4305-970f-4f2874e36124', 'true_false', 3, NULL, 1.00, '1.0', '76', '教育部、应急管理部、市场监管总局、公安部联合部署2026年全国中小学、幼儿园安全工作,体现了多部门联合部署安全工作的特点。', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"教育部、应急管理部、市场监管总局、公安部联合部署2026年全国中小学、幼儿园安全工作,体现了多部门联合部署安全工作的特点。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,多个部门联合部署安全工作,旨在全面提升校园安全治理能力与治理水平,这直接体现了多部门联合部署安全工作的核心知识点。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:54', '2026-06-10 13:15:11', 1); +INSERT INTO `question` VALUES (814, 'cfd86837-ab82-47a7-9bb4-4ff3ed10818b', 'fill_blank', 3, NULL, 2.00, '1.0', '76', '2026年全国中小学、幼儿园安全工作由教育部、应急管理部、市场监管总局、公安部___部署,要求各地聚焦重点任务,从严排查整治,全面提升校园安全治理能力与治理水平。', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"2026年全国中小学、幼儿园安全工作由教育部、应急管理部、市场监管总局、公安部___部署,要求各地聚焦重点任务,从严排查整治,全面提升校园安全治理能力与治理水平。\", \"answer\": [[\"联合\"]], \"explanation\": \"根据文档内容,多部门联合部署安全工作是核心知识点,因此填空处应为“联合”。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 04:58:54', '2026-06-10 13:15:11', 1); +INSERT INTO `question` VALUES (815, '6695c610-f9f7-4bc9-aa00-99b5361ee670', 'single_choice', 3, NULL, 2.00, '1.0', '76', '根据文档内容,以下哪一项是多部门联合部署安全工作的核心目标?', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"提升校园安全治理能力与治理水平\"}, {\"key\": \"B\", \"content\": \"减少学校安全事故数量\"}, {\"key\": \"C\", \"content\": \"降低教育经费投入\"}, {\"key\": \"D\", \"content\": \"简化学校管理流程\"}]}, \"stem\": \"根据文档内容,以下哪一项是多部门联合部署安全工作的核心目标?\", \"answer\": \"A\", \"explanation\": \"文档中明确指出,多部门联合部署安全工作的核心目标是‘全面提升校园安全治理能力与治理水平’。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:02:16', '2026-06-10 05:02:16', 0); +INSERT INTO `question` VALUES (816, '77f208cf-e153-487e-82e6-9a75a39a952c', 'single_choice', 3, NULL, 2.00, '1.0', '76', '根据文档内容,为确保学生每天校内体育活动时间落实到位,采取的主要措施是?', NULL, NULL, '[\"longrule.docx_2\"]', 3, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"减少课程安排\"}, {\"key\": \"B\", \"content\": \"通过‘晒课表’强化跟踪督导\"}, {\"key\": \"C\", \"content\": \"增加文化课时\"}, {\"key\": \"D\", \"content\": \"限制课外活动\"}]}, \"stem\": \"根据文档内容,为确保学生每天校内体育活动时间落实到位,采取的主要措施是?\", \"answer\": \"B\", \"explanation\": \"文档中明确提到通过‘晒课表’强化跟踪督导,以确保学生每天校内体育活动时间落实到位。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:02:16', '2026-06-10 05:02:16', 0); +INSERT INTO `question` VALUES (817, 'd7b1d74a-f635-4791-bae8-8f0db71e1f07', 'true_false', 3, NULL, 1.00, '1.0', '76', '教育部、应急管理部、市场监管总局、公安部联合部署了2026年全国中小学、幼儿园安全工作。', NULL, NULL, '[\"longrule.docx_0\"]', 3, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"教育部、应急管理部、市场监管总局、公安部联合部署了2026年全国中小学、幼儿园安全工作。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,四部门确实联合部署了2026年的校园安全工作。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:02:16', '2026-06-10 05:02:16', 0); +INSERT INTO `question` VALUES (818, 'dd7c6ff8-faad-47ea-a844-e22b5090d219', 'single_choice', 3, NULL, 2.00, '1.0', '78', '根据第一章总则,以下哪项是该文档的核心目标?', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"明确组织架构\"}, {\"key\": \"B\", \"content\": \"规范操作流程\"}, {\"key\": \"C\", \"content\": \"确立管理原则\"}, {\"key\": \"D\", \"content\": \"界定适用范围\"}]}, \"stem\": \"根据第一章总则,以下哪项是该文档的核心目标?\", \"answer\": \"D\", \"explanation\": \"根据第一章总则的内容,文档的核心目标在于明确其适用范围。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:05:47', '2026-06-10 05:05:47', 0); +INSERT INTO `question` VALUES (819, '030d2975-00f0-4ad0-aa3e-a12667ab9647', 'true_false', 3, NULL, 1.00, '1.0', '78', '第一章总则中提到的制度是针对所有员工的,不包括临时工。', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"第一章总则中提到的制度是针对所有员工的,不包括临时工。\", \"answer\": \"false\", \"explanation\": \"根据文档内容,第一章总则并未明确排除临时工,因此该陈述不正确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:05:47', '2026-06-10 05:05:47', 0); +INSERT INTO `question` VALUES (820, 'a79742d8-4914-41c4-9c0e-1710859e5195', 'fill_blank', 3, NULL, 2.00, '1.0', '78', '第一章总则中提到,制定本规定的主要目的是为了规范___和___。', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 2}, \"stem\": \"第一章总则中提到,制定本规定的主要目的是为了规范___和___。\", \"answer\": [[\"管理行为\"], [\"工作流程\"]], \"explanation\": \"根据文档内容,第一章总则明确了制定规定的目的是为了规范管理行为和工作流程。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 05:05:47', '2026-06-10 05:05:47', 0); +INSERT INTO `question` VALUES (821, '4c1907fa-81c8-4244-9d87-f7affe38b621', 'subjective', 3, NULL, 10.00, '1.0', '78', '请简述第一章总则中提到的核心原则,并结合实际应用场景说明其重要性。', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"请简述第一章总则中提到的核心原则,并结合实际应用场景说明其重要性。\", \"answer\": \"核心原则包括:1. 以用户需求为导向;2. 保证信息的准确性与可靠性;3. 遵循法律法规和行业规范。在实际应用中,这些原则确保了系统的有效性和合规性,避免因错误信息或违规操作导致的风险。\", \"explanation\": \"根据文档内容,第一章总则明确了系统设计和运营中的核心原则,这些原则为后续章节提供了指导依据。\", \"referenced_chunk_ids\": null}', 'approved', '', '2026-06-10 05:05:47', '2026-06-10 13:24:52', 0); +INSERT INTO `question` VALUES (822, 'bbf40e1d-77d6-4622-adb4-cd859864ea83', 'single_choice', 3, NULL, 2.00, '1.0', '80', '根据第一章总则的内容,以下哪一项是该章节的核心目的?', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"明确具体实施步骤\"}, {\"key\": \"B\", \"content\": \"概述整体框架和原则\"}, {\"key\": \"C\", \"content\": \"详细说明技术细节\"}, {\"key\": \"D\", \"content\": \"提供操作指南\"}]}, \"stem\": \"根据第一章总则的内容,以下哪一项是该章节的核心目的?\", \"answer\": \"B\", \"explanation\": \"第一章总则的主要目的是概述整体框架和原则,为后续内容奠定基础。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (823, '38469924-eae4-42ea-8357-882ad5f6a313', 'single_choice', 3, NULL, 2.00, '1.0', '80', '根据文档内容,住宿登记坚持哪项原则?', NULL, NULL, '[\"test.docx_3\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"实名、实数、实时、实情\"}, {\"key\": \"B\", \"content\": \"实名、实数、实时、实人\"}, {\"key\": \"C\", \"content\": \"实名、实数、实情、实人\"}, {\"key\": \"D\", \"content\": \"实名、实数、实情、实时\"}]}, \"stem\": \"根据文档内容,住宿登记坚持哪项原则?\", \"answer\": \"A\", \"explanation\": \"根据文档内容,住宿登记坚持的是‘实名、实数、实时、实情’原则。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (824, '409c8cc2-7bcd-46ce-9e86-c4d817f3a704', 'single_choice', 3, NULL, 2.00, '1.0', '80', '根据文档内容,管理人员在日常监督检查中需要定期核查以下哪项内容?', NULL, NULL, '[\"test.docx_5\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"员工考勤记录\"}, {\"key\": \"B\", \"content\": \"登记台账、系统上传记录\"}, {\"key\": \"C\", \"content\": \"财务报表\"}, {\"key\": \"D\", \"content\": \"客户投诉记录\"}]}, \"stem\": \"根据文档内容,管理人员在日常监督检查中需要定期核查以下哪项内容?\", \"answer\": \"B\", \"explanation\": \"根据文档第五条内容,管理人员负责日常监督检查,定期核查登记台账、系统上传记录。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (825, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 3, NULL, 2.00, '1.0', '80', '根据文档内容,谁是住宿登记的第一责任人?', NULL, NULL, '[\"test.docx_4\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"安保人员\"}, {\"key\": \"B\", \"content\": \"前台工作人员\"}, {\"key\": \"C\", \"content\": \"经理\"}, {\"key\": \"D\", \"content\": \"客户\"}]}, \"stem\": \"根据文档内容,谁是住宿登记的第一责任人?\", \"answer\": \"B\", \"explanation\": \"根据文档第四条,前台工作人员被明确为住宿登记的第一责任人。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (826, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 3, NULL, 2.00, '1.0', '80', '根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?', NULL, NULL, '[\"test.docx_8\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"options\": [{\"key\": \"A\", \"content\": \"允许入住并记录信息\"}, {\"key\": \"B\", \"content\": \"一律不予入住并立即上报属地公安机关\"}, {\"key\": \"C\", \"content\": \"暂时允许入住并后续核查\"}, {\"key\": \"D\", \"content\": \"要求重新提供证件\"}]}, \"stem\": \"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?\", \"answer\": \"B\", \"explanation\": \"根据文档第八条明确规定,发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (827, 'c58d752c-b7f1-48a6-9d5d-54d1d3aba62a', 'true_false', 3, NULL, 1.00, '1.0', '80', '第一章总则中提到的制度是针对所有员工的,没有例外情况。', NULL, NULL, '[\"test.docx_0\"]', 22, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"第一章总则中提到的制度是针对所有员工的,没有例外情况。\", \"answer\": \"false\", \"explanation\": \"根据文档内容,第一章总则并未明确提及所有员工均无例外的情况,因此该陈述不正确。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (828, '98d7f08e-a538-42fa-b501-c5aa0b5ef9d8', 'true_false', 3, NULL, 1.00, '1.0', '80', '根据文档内容,住宿登记必须坚持实名、实数、实时、实情原则。', NULL, NULL, '[\"test.docx_3\"]', 22, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"根据文档内容,住宿登记必须坚持实名、实数、实时、实情原则。\", \"answer\": \"true\", \"explanation\": \"文档中明确提到住宿登记坚持‘实名、实数、实时、实情’原则。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (829, '07fc1bfb-bef7-4554-b825-639fed682ae9', 'true_false', 3, NULL, 1.00, '1.0', '80', '管理人员的日常监督检查职责包括定期核查登记台账和系统上传记录。', NULL, NULL, '[\"test.docx_5\"]', 22, 0, 0, NULL, NULL, '{\"data\": {}, \"stem\": \"管理人员的日常监督检查职责包括定期核查登记台账和系统上传记录。\", \"answer\": \"true\", \"explanation\": \"根据文档内容,管理人员负责日常监督检查,并需要定期核查登记台账和系统上传记录。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); +INSERT INTO `question` VALUES (830, '508c9b41-3e9e-43df-98df-51111e124b0a', 'fill_blank', 3, NULL, 2.00, '1.0', '80', '住宿登记坚持____、实数、实时、实情原则,做到一人一证、人证相符、逐人登记、及时上传。', NULL, NULL, '[\"test.docx_3\"]', 22, 0, 0, NULL, NULL, '{\"data\": {\"blank_count\": 1}, \"stem\": \"住宿登记坚持____、实数、实时、实情原则,做到一人一证、人证相符、逐人登记、及时上传。\", \"answer\": [[\"实名\"]], \"explanation\": \"根据文档内容,住宿登记坚持实名、实数、实时、实情原则。\", \"referenced_chunk_ids\": null}', 'pending', NULL, '2026-06-10 06:24:40', '2026-06-10 06:24:40', 0); -- ---------------------------- -- Table structure for role @@ -1194,7 +792,7 @@ CREATE TABLE `role_permission` ( INDEX `idx_permission_id`(`permission_id` ASC) USING BTREE, CONSTRAINT `fk_role_permission_permission` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT, CONSTRAINT `fk_role_permission_role` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 705 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色权限关联表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 725 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色权限关联表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of role_permission @@ -1227,25 +825,26 @@ INSERT INTO `role_permission` VALUES (557, 3, 67, '2026-05-30 01:28:26'); INSERT INTO `role_permission` VALUES (558, 3, 1, '2026-05-30 01:28:26'); INSERT INTO `role_permission` VALUES (559, 3, 3, '2026-05-30 01:28:26'); INSERT INTO `role_permission` VALUES (560, 3, 4, '2026-05-30 01:28:26'); -INSERT INTO `role_permission` VALUES (686, 1, 8, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (687, 1, 9, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (688, 1, 10, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (689, 1, 13, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (690, 1, 16, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (691, 1, 25, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (692, 1, 26, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (693, 1, 48, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (694, 1, 65, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (695, 1, 66, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (696, 1, 67, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (697, 1, 68, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (698, 1, 20, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (699, 1, 1, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (700, 1, 3, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (701, 1, 4, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (702, 1, 7, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (703, 1, 55, '2026-05-31 04:17:01'); -INSERT INTO `role_permission` VALUES (704, 1, 60, '2026-05-31 04:17:01'); +INSERT INTO `role_permission` VALUES (705, 1, 8, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (706, 1, 9, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (707, 1, 10, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (708, 1, 13, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (709, 1, 16, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (710, 1, 20, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (711, 1, 25, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (712, 1, 26, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (713, 1, 48, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (714, 1, 65, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (715, 1, 66, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (716, 1, 67, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (717, 1, 68, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (718, 1, 18, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (719, 1, 1, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (720, 1, 3, '2026-06-03 02:30:09'); +INSERT INTO `role_permission` VALUES (721, 1, 4, '2026-06-03 02:30:10'); +INSERT INTO `role_permission` VALUES (722, 1, 7, '2026-06-03 02:30:10'); +INSERT INTO `role_permission` VALUES (723, 1, 55, '2026-06-03 02:30:10'); +INSERT INTO `role_permission` VALUES (724, 1, 60, '2026-06-03 02:30:10'); -- ---------------------------- -- Table structure for system_config @@ -1348,57 +947,29 @@ CREATE TABLE `user_answer` ( INDEX `idx_created_at`(`created_at` ASC) USING BTREE, CONSTRAINT `fk_user_answer_question` FOREIGN KEY (`question_id`) REFERENCES `question` (`question_id`) ON DELETE CASCADE ON UPDATE RESTRICT, CONSTRAINT `fk_user_answer_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 360 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户答题记录表' ROW_FORMAT = DYNAMIC; +) ENGINE = InnoDB AUTO_INCREMENT = 402 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户答题记录表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of user_answer -- ---------------------------- -INSERT INTO `user_answer` VALUES (314, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '\"\"', 5.00, 5.00, 1, 'ai', '正确!', NULL, NULL, 0, 0, '2026-06-01 14:26:25', '2026-06-01 14:26:25'); -INSERT INTO `user_answer` VALUES (315, 1, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '[]', 4.00, 4.00, 1, 'ai', '正确!', NULL, NULL, 0, 0, '2026-06-01 14:26:25', '2026-06-01 14:26:25'); -INSERT INTO `user_answer` VALUES (316, 1, 'bfbe43d3-fc30-44a8-9b05-7b7520dc20d0', 'true_false', 'formal_exam', '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '\"false\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-01 14:26:25', '2026-06-01 14:26:25'); -INSERT INTO `user_answer` VALUES (317, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:26:25', '2026-06-01 14:26:25'); -INSERT INTO `user_answer` VALUES (318, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '31304832-7a1f-49e0-9f31-ed723d6d64f0', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:26:25', '2026-06-01 14:26:25'); -INSERT INTO `user_answer` VALUES (319, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', NULL, '\"A\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-01 14:26:37', '2026-06-01 14:26:37'); -INSERT INTO `user_answer` VALUES (320, 1, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', NULL, '[\"B\", \"A\"]', 0.00, 4.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-01 14:26:37', '2026-06-01 14:26:37'); -INSERT INTO `user_answer` VALUES (321, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:26:37', '2026-06-01 14:26:37'); -INSERT INTO `user_answer` VALUES (322, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '2bd9f7a1-5022-4133-9724-9dd5e25a601c', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:26:37', '2026-06-01 14:26:37'); -INSERT INTO `user_answer` VALUES (323, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', NULL, '\"A\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-01 14:27:23', '2026-06-01 14:27:23'); -INSERT INTO `user_answer` VALUES (324, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', NULL, '[\"1\", \"1\", \"1\"]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:27:23', '2026-06-01 14:27:23'); -INSERT INTO `user_answer` VALUES (325, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '72e283f2-683b-4f5b-b76e-39e3047b2ebe', NULL, '\"123123\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-01 14:27:23', '2026-06-01 14:27:23'); -INSERT INTO `user_answer` VALUES (326, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '\"A\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 00:10:02', '2026-06-02 00:10:02'); -INSERT INTO `user_answer` VALUES (327, 1, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '[\"A\", \"B\"]', 0.00, 4.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 00:10:02', '2026-06-02 00:10:02'); -INSERT INTO `user_answer` VALUES (328, 1, 'bfbe43d3-fc30-44a8-9b05-7b7520dc20d0', 'true_false', 'formal_exam', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '\"false\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 00:10:02', '2026-06-02 00:10:02'); -INSERT INTO `user_answer` VALUES (329, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 00:10:02', '2026-06-02 00:10:02'); -INSERT INTO `user_answer` VALUES (330, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '698eb5fa-13fa-4ed0-9831-6ee6934f053e', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 00:10:02', '2026-06-02 00:10:02'); -INSERT INTO `user_answer` VALUES (331, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', NULL, '\"\"', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 03:16:24', '2026-06-02 03:16:24'); -INSERT INTO `user_answer` VALUES (332, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', NULL, '[]', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 03:16:24', '2026-06-02 03:16:24'); -INSERT INTO `user_answer` VALUES (333, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', 'ce575b92-2a3c-43ba-a1a5-4f3d2efb9f2c', NULL, '\"\"', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 03:16:24', '2026-06-02 03:16:24'); -INSERT INTO `user_answer` VALUES (334, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '\"A\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 03:17:04', '2026-06-02 03:17:04'); -INSERT INTO `user_answer` VALUES (335, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 03:17:04', '2026-06-02 03:17:04'); -INSERT INTO `user_answer` VALUES (336, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 03:17:04', '2026-06-02 03:17:04'); -INSERT INTO `user_answer` VALUES (337, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"B\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:27:52', '2026-06-02 04:27:52'); -INSERT INTO `user_answer` VALUES (338, 1, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '[\"B\", \"C\", \"D\"]', 0.00, 4.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:27:52', '2026-06-02 04:27:52'); -INSERT INTO `user_answer` VALUES (339, 1, 'bfbe43d3-fc30-44a8-9b05-7b7520dc20d0', 'true_false', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"true\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:27:52', '2026-06-02 04:27:52'); -INSERT INTO `user_answer` VALUES (340, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '[\"1\", \"1\", \"1\"]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 04:27:52', '2026-06-02 04:27:52'); -INSERT INTO `user_answer` VALUES (341, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 04:27:52', '2026-06-02 04:27:52'); -INSERT INTO `user_answer` VALUES (342, 4, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"A\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:29:32', '2026-06-02 04:29:32'); -INSERT INTO `user_answer` VALUES (343, 4, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '[\"A\", \"B\", \"C\"]', 0.00, 4.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:29:32', '2026-06-02 04:29:32'); -INSERT INTO `user_answer` VALUES (344, 4, 'bfbe43d3-fc30-44a8-9b05-7b7520dc20d0', 'true_false', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"true\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 04:29:32', '2026-06-02 04:29:32'); -INSERT INTO `user_answer` VALUES (345, 4, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '[\"1\", \"1\", \"1\"]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 04:29:32', '2026-06-02 04:29:32'); -INSERT INTO `user_answer` VALUES (346, 4, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '036bcb39-7d41-45f8-9fac-0d7899ceb16f', NULL, '\"123\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 04:29:32', '2026-06-02 04:29:32'); -INSERT INTO `user_answer` VALUES (347, 4, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '\"\"', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 04:29:51', '2026-06-02 04:29:51'); -INSERT INTO `user_answer` VALUES (348, 4, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '[]', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 04:29:51', '2026-06-02 04:29:51'); -INSERT INTO `user_answer` VALUES (349, 4, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', 'c5656307-6255-4298-8c4e-82e53d91e379', NULL, '\"\"', 0.00, 5.00, 0, 'ai', '未作答', NULL, NULL, 0, 0, '2026-06-02 04:29:51', '2026-06-02 04:29:51'); -INSERT INTO `user_answer` VALUES (350, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', NULL, '\"C\"', 0.00, 5.00, 1, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 05:35:52', '2026-06-02 13:36:39'); -INSERT INTO `user_answer` VALUES (351, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:35:52', '2026-06-02 05:35:52'); -INSERT INTO `user_answer` VALUES (352, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '1df188af-647c-457e-9d1e-ea76a2b7fb2f', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:35:52', '2026-06-02 05:35:52'); -INSERT INTO `user_answer` VALUES (353, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', 'c281572d-99f7-4e93-b684-590fbaea52e4', NULL, '\"C\"', 0.00, 5.00, 0, 'ai', '正确答案: ', NULL, NULL, 0, 0, '2026-06-02 05:38:42', '2026-06-02 05:38:42'); -INSERT INTO `user_answer` VALUES (354, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', 'c281572d-99f7-4e93-b684-590fbaea52e4', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:38:42', '2026-06-02 05:38:42'); -INSERT INTO `user_answer` VALUES (355, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', 'c281572d-99f7-4e93-b684-590fbaea52e4', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:38:42', '2026-06-02 05:38:42'); -INSERT INTO `user_answer` VALUES (356, 1, '5af6fdce-dbf2-4a57-9ef4-bef176be6fb8', 'single_choice', 'formal_exam', '399ade38-3b02-4e83-8509-d6ea7624c437', NULL, '\"C\"', 5.00, 5.00, 1, 'ai', '正确!', NULL, NULL, 0, 0, '2026-06-02 05:51:33', '2026-06-02 05:51:33'); -INSERT INTO `user_answer` VALUES (357, 1, 'f30a7401-508b-4591-8fb8-46437699e577', 'multiple_choice', 'formal_exam', '399ade38-3b02-4e83-8509-d6ea7624c437', NULL, '[]', 0.00, 4.00, 0, 'ai', '正确答案: [\'A\', \'B\', \'D\']', NULL, NULL, 0, 0, '2026-06-02 05:51:33', '2026-06-02 05:51:33'); -INSERT INTO `user_answer` VALUES (358, 1, '5e069067-a10d-4230-9564-e7503d72d738', 'fill_blank', 'formal_exam', '399ade38-3b02-4e83-8509-d6ea7624c437', NULL, '[]', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:51:33', '2026-06-02 05:51:33'); -INSERT INTO `user_answer` VALUES (359, 1, 'e6bb2566-90a8-4651-b553-083a1d695b3c', 'subjective', 'formal_exam', '399ade38-3b02-4e83-8509-d6ea7624c437', NULL, '\"\"', 0.00, 5.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-02 05:51:33', '2026-06-02 05:51:33'); +INSERT INTO `user_answer` VALUES (378, 1, 'dd7c6ff8-faad-47ea-a844-e22b5090d219', 'single_choice', 'formal_exam', '35402037-40f1-4119-b1d6-6ed68d7268f8', NULL, '\"A\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 05:27:19', '2026-06-10 05:27:19'); +INSERT INTO `user_answer` VALUES (379, 1, 'a79742d8-4914-41c4-9c0e-1710859e5195', 'fill_blank', 'formal_exam', '35402037-40f1-4119-b1d6-6ed68d7268f8', NULL, '[\"1\", \"1\"]', 0.00, 2.00, 0, 'ai', NULL, NULL, NULL, 0, 0, '2026-06-10 05:27:19', '2026-06-10 05:27:19'); +INSERT INTO `user_answer` VALUES (383, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', 'a310b3e9-e1c6-4afb-9945-abd7565cfcb5', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 06:37:47', '2026-06-10 06:37:47'); +INSERT INTO `user_answer` VALUES (384, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', 'a310b3e9-e1c6-4afb-9945-abd7565cfcb5', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 06:37:47', '2026-06-10 06:37:47'); +INSERT INTO `user_answer` VALUES (385, 1, '409c8cc2-7bcd-46ce-9e86-c4d817f3a704', 'single_choice', 'formal_exam', 'a310b3e9-e1c6-4afb-9945-abd7565cfcb5', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 06:37:47', '2026-06-10 06:37:47'); +INSERT INTO `user_answer` VALUES (386, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', 'd55c332f-4de2-42ec-9859-d3dc2f68c8b5', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:47:18', '2026-06-10 10:47:18'); +INSERT INTO `user_answer` VALUES (387, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', 'd55c332f-4de2-42ec-9859-d3dc2f68c8b5', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:47:18', '2026-06-10 10:47:18'); +INSERT INTO `user_answer` VALUES (388, 1, '409c8cc2-7bcd-46ce-9e86-c4d817f3a704', 'single_choice', 'formal_exam', 'd55c332f-4de2-42ec-9859-d3dc2f68c8b5', NULL, '\"\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:47:18', '2026-06-10 10:47:18'); +INSERT INTO `user_answer` VALUES (391, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', '75d386fc-e4e4-46cd-89d2-513daa4c7c48', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:51:08', '2026-06-10 10:51:08'); +INSERT INTO `user_answer` VALUES (392, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', '75d386fc-e4e4-46cd-89d2-513daa4c7c48', NULL, '\"\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:51:08', '2026-06-10 10:51:08'); +INSERT INTO `user_answer` VALUES (393, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', 'cab7be14-dd8f-4e02-9bef-13d9a14ab89e', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:52:08', '2026-06-10 10:52:08'); +INSERT INTO `user_answer` VALUES (394, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', 'cab7be14-dd8f-4e02-9bef-13d9a14ab89e', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:52:08', '2026-06-10 10:52:08'); +INSERT INTO `user_answer` VALUES (395, 1, '409c8cc2-7bcd-46ce-9e86-c4d817f3a704', 'single_choice', 'formal_exam', 'cab7be14-dd8f-4e02-9bef-13d9a14ab89e', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 10:52:08', '2026-06-10 10:52:08'); +INSERT INTO `user_answer` VALUES (396, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', '92b2dcf6-ba57-4798-8a1c-33e249ed7e20', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 11:09:19', '2026-06-10 11:09:19'); +INSERT INTO `user_answer` VALUES (397, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', '92b2dcf6-ba57-4798-8a1c-33e249ed7e20', NULL, '\"A\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 11:09:19', '2026-06-10 11:09:19'); +INSERT INTO `user_answer` VALUES (398, 1, '409c8cc2-7bcd-46ce-9e86-c4d817f3a704', 'single_choice', 'formal_exam', '92b2dcf6-ba57-4798-8a1c-33e249ed7e20', NULL, '\"A\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 11:09:19', '2026-06-10 11:09:19'); +INSERT INTO `user_answer` VALUES (399, 1, 'ea6a7f44-9077-4f19-b10e-8239a5198f4d', 'single_choice', 'formal_exam', '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 11:11:49', '2026-06-10 11:11:49'); +INSERT INTO `user_answer` VALUES (400, 1, '9d59e7c5-edfc-4517-9fb5-780b389b66fb', 'single_choice', 'formal_exam', '4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f', NULL, '\"B\"', 0.00, 2.00, 0, 'ai', '正确答案: None', NULL, NULL, 0, 0, '2026-06-10 11:11:49', '2026-06-10 11:11:49'); -- ---------------------------- -- Table structure for user_role diff --git a/docs/sql/migration_20260608_add_exclude_stems_and_is_deleted.sql b/docs/sql/migration_20260608_add_exclude_stems_and_is_deleted.sql new file mode 100644 index 0000000..fffcf2d --- /dev/null +++ b/docs/sql/migration_20260608_add_exclude_stems_and_is_deleted.sql @@ -0,0 +1,47 @@ +-- ============================================================= +-- 数据库迁移脚本:question 表补充缺失列 +-- 版本: V1.1 +-- 日期: 2026-06-08 +-- 说明: question表缺少 exclude_stems 和 is_deleted 列, +-- 导致 MyBatis-Plus 全字段查询时抛出 SQL 异常 +-- (Unknown column 'exclude_stems' / 'is_deleted') +-- 对应实体字段: Question.excludeStems, Question.isDeleted +-- ============================================================= + +-- 1. 添加 exclude_stems 列(对应实体 field: excludeStems) +-- 用于 AI 出题时对题干内容进行去重 +ALTER TABLE `question` + ADD COLUMN `exclude_stems` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci + NULL DEFAULT NULL COMMENT '题干内容,用于AI去重' + AFTER `document_id`; + +-- 2. 添加 is_deleted 列(对应实体 field: isDeleted) +-- 用于逻辑删除标记 +ALTER TABLE `question` + ADD COLUMN `is_deleted` int NOT NULL DEFAULT 0 + COMMENT '软删除标志:0表示正常,1表示已删除' + AFTER `updated_at`; + +-- 3. 为 is_deleted 添加索引(优化按删除状态查询的性能) +ALTER TABLE `question` + ADD INDEX `idx_question_is_deleted`(`is_deleted` ASC) USING BTREE; + +-- ============================================================= +-- 补充迁移:file 表添加 tags 列 +-- 说明: File实体中有 private JsonNode tags 字段, +-- 但数据库 File 表缺少该列,导致全字段查询报错 +-- ============================================================= + +-- 4. 添加 tags 列(对应实体 field: tags) +-- 用于存储文件标签(JSON数组),如 ["重要", "需审批"] +ALTER TABLE `file` + ADD COLUMN `tags` json DEFAULT NULL COMMENT '文件标签' + AFTER `process_step_message`; + +-- ============================================================= +-- 回滚脚本(如需回滚请执行以下语句) +-- ============================================================= +-- ALTER TABLE `question` DROP COLUMN `exclude_stems`; +-- ALTER TABLE `question` DROP COLUMN `is_deleted`; +-- ALTER TABLE `question` DROP INDEX `idx_question_is_deleted`; +-- ALTER TABLE `file` DROP COLUMN `tags`; diff --git a/docs/前端图片URL使用指南.md b/docs/前端图片URL使用指南.md deleted file mode 100644 index 8c78b21..0000000 --- a/docs/前端图片URL使用指南.md +++ /dev/null @@ -1,172 +0,0 @@ -# 前端图片 URL 使用指南 - -## 概述 -后端已优化图片访问方式,现在支持通过 Nginx 静态资源直接访问图片,提高了图片加载效率。 - -## 图片数据结构 - -### 聊天消息中的图片 -```json -{ - "images": [ - { - "id": "abc123", - "url": "/files/img/abc123.jpg", - "type": "image", - "source": "文档名.pdf", - "page": 1, - "description": "图片描述" - } - ] -} -``` - -## URL 格式说明 - -### 两种 URL 格式 -后端会返回以下两种格式的 URL: -1. **新格式(推荐):`/files/img/xxx.jpg` - 通过 Nginx 静态资源访问 -2. **旧格式(兼容)**:`/api/image/xxx/data` - 通过后端 API 代理访问 - -## 前端适配说明 - -### 无需修改的情况 -如果您的前端目前使用如下方式处理图片,则无需修改代码: -```javascript -// 直接使用后端返回的 URL -{image.description} -``` - -### 推荐的处理方式 -```javascript -// 通用图片加载器 -function loadImage(imageData) { - const imageUrl = imageData.url; - - // 直接使用后端返回的 URL - const img = document.createElement('img'); - img.src = imageUrl; - img.alt = imageData.description || '图片'; - img.onerror = function() { - // 图片加载失败时的处理 - console.error('图片加载失败:', imageUrl); - }; - - return img; -} -``` - -### 检查 URL 类型 -```javascript -function isNginxUrl(url) { - return url && url.startsWith('/files/'); -} - -function isApiUrl(url) { - return url && url.includes('/api/image/'); -} -``` - -## SSE 流处理示例 - -### JavaScript 示例 -```javascript -const eventSource = new EventSource('/api/chat/stream'); - -eventSource.onmessage = function(event) { - const data = JSON.parse(event.data); - - if (data.type === 'finish') { - // 处理图片 - if (data.images && data.images.length > 0) { - renderImages(data.images); - } - } -}; - -function renderImages(images) { - const container = document.getElementById('image-container'); - - images.forEach(image => { - const img = document.createElement('img'); - img.src = image.url; - img.alt = image.description || '图片'; - img.style.maxWidth = '100%'; - container.appendChild(img); - - // 显示图片描述 - if (image.description) { - const desc = document.createElement('p'); - desc.textContent = image.description; - container.appendChild(desc); - } - }); -} -``` - -### React 示例 -```jsx -function ChatImages({ images }) { - return ( -
- {images && images.map((image, index) => ( -
- {image.description} - {image.description && ( -
- {image.description} -
- )} -
- ))} -
- ); -} -``` - -### Vue 示例 -```vue - - - -``` - -## 历史记录查看 -在查看历史会话时,后端已自动将图片 URL 转换为 Nginx 格式,无需额外处理。 - -## 注意事项 - -1. **向后兼容**:后端保留了对旧 URL 格式的支持,以确保旧数据仍然可用 -2. **错误处理**:建议添加图片加载失败的错误处理逻辑 -3. **相对路径**:`/files/` 开头的 URL 是相对路径,会自动根据当前域名拼接完整地址 - -## 兼容性 -- 无需对现有前端代码进行大量修改 -- 两种格式都支持 diff --git a/docs/前端图片渲染修复.md b/docs/前端图片渲染修复.md deleted file mode 100644 index d6b28fa..0000000 --- a/docs/前端图片渲染修复.md +++ /dev/null @@ -1,251 +0,0 @@ -# 前端图片渲染修复指南 - -## 问题分析 - -根据日志分析,**后端已完美修复**,图片数据已正确返回,但前端没有正确渲染: - -### 后端返回的数据格式 -```javascript -{ - "success": true, - "data": [ - { - "id": 175, - "role": "assistant", - "content": "...", - "images": [ - { - "doc_name": "1.docx", - "page": 1, - "image_id": "49d2910b148d.jpg", - "url": "/files/img/49d2910b148d.jpg" - } - ] - } - ] -} -``` - -### 问题现象 -从HTML片段可以看到,页面中只有引用来源和文本内容,**没有任何 `` 标签渲染出来**。 - ---- - -## 修复步骤 - -### 1. 确认前端代码位置 - -首先找到渲染聊天消息的前端组件,通常在以下位置: -- `src/components/ChatMessage.vue` -- `src/views/ChatView.vue` -- 或其他类似位置 - -### 2. 修改消息渲染代码 - -在渲染消息的地方,添加对 `images` 字段的处理: - -#### Vue 组件示例: -```vue - - - - - -``` - -### 3. 处理历史会话消息 - -确认在获取历史会话的接口调用后,正确地将数据传递给消息渲染组件: - -```javascript -// 示例:在 API 调用处 -async function loadSessionHistory(sessionId) { - try { - const response = await fetch(`/api/ai/session/${sessionId}`); - const result = await response.json(); - - if (result.success) { - // 确保 messages 数据正确传递给组件 - messages.value = result.data; - } - } catch (error) { - console.error('加载历史会话失败:', error); - } -} -``` - -### 4. 添加图片点击预览功能(可选优化) - -```vue - -
- 预览 - -
- - - - - -``` - ---- - -## 验证步骤 - -1. **检查浏览器控制台**:打开浏览器开发者工具(F12),查看 Console 标签,确认没有 JavaScript 错误 -2. **检查网络请求**:在 Network 标签中,确认图片请求(如 `/files/img/49d2910b148d.jpg`)状态码为 200 -3. **确认数据结构**:在 Network 标签中,检查 `/api/ai/session/{sessionId}` 接口的响应,确认 `images` 字段存在且格式正确 - ---- - -## 常见问题排查 - -### 问题1:images 字段为 null 或 undefined -**原因**:可能旧版本的消息没有 images 字段 -**解决**:添加空值检查 -```vue -
-``` - -### 问题2:图片加载 404 -**原因**:Nginx 路径配置问题 -**解决**:确认 Nginx 配置正确映射了 `/files/img/` 路径 - -### 问题3:图片跨域 -**原因**:图片域名与前端域名不一致 -**解决**:使用后端代理接口 `/api/image/{imageId}/data` 而不是 `/files/img/` 路径 - ---- - -## 后端返回的完整数据说明 - -后端返回的 ChatMessage 中 `images` 字段的完整结构: - -```json -{ - "images": [ - { - "image_id": "49d2910b148d.jpg", - "url": "/files/img/49d2910b148d.jpg", - "doc_name": "1.docx", - "page": 1, - "description": "图片描述(可选)", - "type": "image" - } - ] -} -``` - -主要字段说明: -- `url`: 图片的 Nginx 静态资源路径,直接使用即可 -- `image_id`: 图片的唯一标识 -- `doc_name`: 来源文档名称 -- `page`: 来源页码 -- `description`: 图片描述(可能为 null) - ---- - -## 修改总结 - -| 任务 | 优先级 | -|------|--------| -| 在消息渲染组件中添加 `images` 字段处理 | 🔴 高 | -| 确保正确解析和渲染图片列表 | 🔴 高 | -| 添加图片加载错误处理 | 🟡 中 | -| 添加图片预览功能 | 🟢 低 | -| 优化图片样式和交互 | 🟢 低 | diff --git a/docs/图片URL优化更新文档.md b/docs/图片URL优化更新文档.md deleted file mode 100644 index 7afa222..0000000 --- a/docs/图片URL优化更新文档.md +++ /dev/null @@ -1,70 +0,0 @@ -# 图片 URL 优化更新文档 - -## 概述 -本次更新优化了图片访问方式,从原来通过后端 API 代理访问改为直接通过 Nginx 静态资源访问,提高了图片加载效率。 - -## 修改内容 - -### 1. 配置文件 -- 使用配置项 `file.upload.path` 确定本地保存路径 -- 使用配置项 `file.upload.url-prefix` 确定 Nginx 访问前缀(默认为 `/files/`) - -### 2. ImageService 接口 -- 新增 `getNginxUrlByImageId(String imageId)` 方法,用于根据图片 ID 获取 Nginx 格式的 URL - -### 3. ImageServiceImpl 实现 -- 使用配置的 `file.upload.path` + `/img` 作为图片存储目录 -- 保存图片时返回相对路径(如 `img/xxx.jpg`)而非绝对路径 -- 修改本地读取图片逻辑,支持相对路径 -- 新增 `getNginxUrlByImageId` 方法 -- 新增 `extractFilenameFromPath` 辅助方法 - -### 4. AiChatServiceImpl 修改 -- 在保存图片后立即更新 imageMetadata 中的 url 为 Nginx 格式 -- 在 SSE 的 finish 事件中,对无 metadata 的图片也尝试生成 Nginx 格式 URL - -### 5. ChatServiceImpl 修改 -- 查看历史记录时,将图片 URL 从 `/api/image/xxx/data` 转换为 Nginx 格式(`/files/img/xxx.jpg`) - -## 使用示例 - -### Nginx 配置示例 -```nginx -server { - listen 80; - - location /files/ { - alias /path/to/upload/; - expires 7d; - add_header Cache-Control "public, immutable"; - } - - location / { - proxy_pass http://localhost:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - } -} -``` - -### 配置文件 (application-prod.yml) -```yaml -file: - upload: - path: /opt/deploy/uploads/ - url-prefix: /files/ -``` - -## 部署说明 -1. 确保 Nginx 配置正确,`/files/` 路径指向实际的上传目录 -2. 确保应用配置文件中的 `file.upload.path` 和 `file.upload.url-prefix` 设置正确 -3. 重新构建并部署应用 - -## 兼容性 -- 保留了向后兼容,如果 Nginx 格式 URL 无法获取,会回退为原 `/api/image/xxx/data` 格式 -- 旧数据仍然可以正常访问 - -## 图片 URL 格式对比 -| 旧格式 | 新格式 | -|--------|--------| -| /api/image/xxx/data | /files/img/xxx.jpg | diff --git a/docs/完整curl测试手册.md b/docs/完整curl测试手册.md index e4fbce2..382d22e 100644 --- a/docs/完整curl测试手册.md +++ b/docs/完整curl测试手册.md @@ -53,7 +53,7 @@ curl -X POST "http://localhost:8080/api/auth/login" \ ```bash curl -X GET "http://localhost:8080/api/auth/me" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -64,14 +64,14 @@ curl -X GET "http://localhost:8080/api/auth/me" \ ```bash curl -X GET "http://localhost:8080/api/user/list" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 3.2 获取用户详情 ```bash curl -X GET "http://localhost:8080/api/user/1" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 3.3 创建用户 @@ -79,7 +79,7 @@ curl -X GET "http://localhost:8080/api/user/1" \ ```bash curl -X POST "http://localhost:8080/api/user" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "username": "testuser", "password": "123456", @@ -94,7 +94,7 @@ curl -X POST "http://localhost:8080/api/user" \ ```bash curl -X PUT "http://localhost:8080/api/user/1" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{"email": "newemail@example.com"}' ``` @@ -102,14 +102,14 @@ curl -X PUT "http://localhost:8080/api/user/1" \ ```bash curl -X DELETE "http://localhost:8080/api/user/1" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 3.6 获取部门列表 ```bash curl -X GET "http://localhost:8080/api/department/list" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -120,49 +120,49 @@ curl -X GET "http://localhost:8080/api/department/list" \ ```bash curl -X GET "http://localhost:8080/api/collection" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.2 创建向量库 ```bash curl -X POST "http://localhost:8080/api/collection?name=dept_hr&displayName=人力资源知识库&departmentId=1&description=人力资源部专用知识库" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.3 修改向量库 ```bash curl -X PUT "http://localhost:8080/api/collection/dept_hr?displayName=人力资源知识库V2&description=更新后的描述" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.4 删除向量库 ```bash curl -X DELETE "http://localhost:8080/api/collection/dept_hr" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.5 文件向量化(单文件) ```bash curl -X POST "http://localhost:8080/api/collection/public_kb/vectorize?fileId=36" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.6 批量文件向量化 ```bash curl -X POST "http://localhost:8080/api/collection/public_kb/vectorize/batch?fileIds=1&fileIds=2&fileIds=3" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.7 获取文档列表 ```bash curl -X GET "http://localhost:8080/api/collection/public_kb/documents" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.8 删除文档 @@ -170,67 +170,67 @@ curl -X GET "http://localhost:8080/api/collection/public_kb/documents" \ ```bash # 推荐:使用 fileId 精确删除(避免同名文件删除错误) curl -X DELETE "http://localhost:8080/api/collection/public_kb/documents/test_document.pdf?fileId=56" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" # 兼容旧版本:仅使用文件名(存在同名文件风险) curl -X DELETE "http://localhost:8080/api/collection/public_kb/documents/test_document.pdf" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.9 废止文档 ```bash curl -X POST "http://localhost:8080/api/collection/public_kb/documents/test_document.pdf/deprecate?reason=new_version" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.10 恢复已废止文档 ```bash curl -X POST "http://localhost:8080/api/collection/public_kb/documents/test_document_v2.pdf/restore" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.11 获取文档版本历史 ```bash curl -X GET "http://localhost:8080/api/collection/public_kb/documents/test_document.pdf/versions?limit=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.12 获取向量库切片列表 ```bash curl -X GET "http://localhost:8080/api/collection/public_kb/chunks?limit=100&offset=0" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.13 获取文档切片列表 ```bash curl -X GET "http://localhost:8080/api/collection/public_kb/documents/test_document.pdf/chunks?page=1&pageSize=20" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.14 新增切片 ```bash curl -X POST "http://localhost:8080/api/collection/public_kb/chunks?content=新的切片内容§ion=第一章" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.15 修改切片 ```bash curl -X PUT "http://localhost:8080/api/collection/public_kb/chunks/chunk_001?content=更新后的内容§ion=第一章" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 4.16 删除切片 ```bash curl -X DELETE "http://localhost:8080/api/collection/public_kb/chunks/chunk_001" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -241,7 +241,7 @@ curl -X DELETE "http://localhost:8080/api/collection/public_kb/chunks/chunk_001" ```bash curl -X GET "http://localhost:8080/api/collection-access/page?pageNum=1&pageSize=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -H "Content-Type: application/json" ``` @@ -249,7 +249,7 @@ curl -X GET "http://localhost:8080/api/collection-access/page?pageNum=1&pageSize ```bash curl -X GET "http://localhost:8080/api/collection-access/1" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -H "Content-Type: application/json" ``` @@ -257,7 +257,7 @@ curl -X GET "http://localhost:8080/api/collection-access/1" \ ```bash curl -X GET "http://localhost:8080/api/collection-access/accessible" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -H "Content-Type: application/json" ``` @@ -269,10 +269,10 @@ curl -X GET "http://localhost:8080/api/collection-access/accessible" \ ```bash curl -X POST "http://localhost:8080/api/ai/chat/stream" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -H "Content-Type: application/json" \ -d '{ - "message": "2003—2022 年,三峡电站累计发电量是多少?最好带图片说明", + "message": "市场权重计算公式", "session_id": "" }' \ --no-buffer @@ -282,49 +282,49 @@ curl -X POST "http://localhost:8080/api/ai/chat/stream" \ ```bash curl -X POST "http://localhost:8080/api/ai/chat/stop?sessionId=sess_1777600000000_abc123" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.3 获取用户会话列表 ```bash curl -X GET "http://localhost:8080/api/ai/sessions?page=1&pageSize=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.4 获取会话详情 ```bash curl -X GET "http://localhost:8080/api/ai/session/sess_123456789" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.5 获取消息文件来源列表 ```bash curl -X GET "http://localhost:8080/api/ai/message/1/sources" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.6 获取消息引用信息 ```bash curl -X GET "http://localhost:8080/api/ai/message/1/references" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.7 获取会话引用信息 ```bash curl -X GET "http://localhost:8080/api/ai/session/sess_123456789/references" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.8 删除单个会话 ```bash curl -X DELETE "http://localhost:8080/api/ai/session/sess_123456789" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 5.9 批量删除会话 @@ -332,7 +332,7 @@ curl -X DELETE "http://localhost:8080/api/ai/session/sess_123456789" \ ```bash curl -X DELETE "http://localhost:8080/api/ai/sessions" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '["sess_001", "sess_002", "sess_003"]' ``` @@ -345,7 +345,7 @@ curl -X DELETE "http://localhost:8080/api/ai/sessions" \ ```bash curl -X POST "http://localhost:8080/api/feedback" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "sessionId": "sess_test_001", "query": "出差补助标准是什么?", @@ -360,21 +360,21 @@ curl -X POST "http://localhost:8080/api/feedback" \ ```bash curl -X GET "http://localhost:8080/api/feedback/list?page=1&page_size=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 6.3 获取反馈统计 ```bash curl -X GET "http://localhost:8080/api/feedback/stats" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 6.4 获取差评案例 ```bash curl -X GET "http://localhost:8080/api/feedback/bad-cases" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -385,14 +385,14 @@ curl -X GET "http://localhost:8080/api/feedback/bad-cases" \ ```bash curl -X GET "http://localhost:8080/api/faq?page=1&page_size=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 7.2 获取FAQ建议列表 ```bash curl -X GET "http://localhost:8080/api/faq/suggestions?page=1&page_size=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 7.3 批准FAQ建议 @@ -400,7 +400,7 @@ curl -X GET "http://localhost:8080/api/faq/suggestions?page=1&page_size=10" \ ```bash curl -X POST "http://localhost:8080/api/faq/suggestions/1/approve" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{"answer": "修改后的标准答案内容"}' ``` @@ -408,7 +408,7 @@ curl -X POST "http://localhost:8080/api/faq/suggestions/1/approve" \ ```bash curl -X POST "http://localhost:8080/api/faq/suggestions/1/reject" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -430,7 +430,7 @@ curl -X POST "http://localhost:8080/api/faq/suggestions/1/reject" \ ```bash curl -X POST "http://localhost:8080/api/ai/chat/stream" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "message": "2003—2022 年,三峡电站累计发电量是多少?最好带图片说明", "session_id": "" @@ -462,7 +462,7 @@ curl -X POST "http://localhost:8080/api/ai/chat/stream" \ ```bash curl -X GET "http://localhost:8080/api/image/ab77281e7913.jpg/data" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -o downloaded_image.jpg ``` @@ -491,7 +491,7 @@ downloaded_image.jpg: JPEG image data, ... ```bash curl -X GET "http://localhost:8080/api/image/1" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` **预期返回:** @@ -537,14 +537,14 @@ mysql -h localhost -u root -p knowledge_management_system -e "SELECT id, image_i ```bash curl -X GET "http://localhost:8080/api/image/list?limit=10&offset=0" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 8.2 获取单张图片 ```bash curl -X GET "http://localhost:8080/api/image/img_001" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -o downloaded_image.jpg ``` @@ -552,7 +552,7 @@ curl -X GET "http://localhost:8080/api/image/img_001" \ ```bash curl -X GET "http://localhost:8080/api/image/stats" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -563,14 +563,14 @@ curl -X GET "http://localhost:8080/api/image/stats" \ ```bash curl -X GET "http://localhost:8080/api/report/weekly" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 9.2 获取月报 ```bash curl -X GET "http://localhost:8080/api/report/monthly" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -582,7 +582,7 @@ curl -X GET "http://localhost:8080/api/report/monthly" \ ```bash curl -X POST "http://localhost:8080/api/search" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "query": "出差补助标准", "topK": 5, @@ -599,7 +599,7 @@ curl -X POST "http://localhost:8080/api/search" \ ```bash curl -X POST "http://localhost:8080/api/kb-route" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "query": "财务部的报销流程是什么" }' @@ -614,7 +614,7 @@ curl -X POST "http://localhost:8080/api/kb-route" \ ```bash curl -X POST "http://localhost:8080/api/exam/paper/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg1ODc5OSwiZXhwIjoxNzc5ODY1OTk5fQ.2KJe1eZZ1t3AZ_ri1saILw2urf7DtxAKW_xHqCTN_kx4hIaJDq9bDHVzXNpdPbgjjf_jbBVJKBIsMCcvvKupgw" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "single_choice_count": 5, "multiple_choice_count": 3, @@ -631,7 +631,7 @@ curl -X POST "http://localhost:8080/api/exam/paper/generate" \ ```bash curl -X POST "http://localhost:8080/api/exam/paper/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "single_choice_count": 5, "multiple_choice_count": 3, @@ -654,9 +654,9 @@ curl -X POST "http://localhost:8080/api/exam/paper/generate" \ ```bash curl -X POST "http://localhost:8080/api/exam/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDA0NDU1MSwiZXhwIjoxNzgwMDUxNzUxfQ.YVF7kNwTDKI1SPFLe5KHGVPDCCrTNUBu6vChGrqRid8uZJvOXwnboU67c0KZRCV6ZEBwGnSrstIxkTi94iHJeA" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ - "file_id": 43, + "file_id": 74, "difficulty": 3, "request_id": "gen_req_smart_001" }' @@ -664,12 +664,14 @@ curl -X POST "http://localhost:8080/api/exam/generate" \ **测试用例2:指定题型模式 - 通过 file\_id 指定文件** +> **注意**:系统会自动查询该文件已有的题目题干(`exclude_stems`),在调用AI时传入进行去重,避免生成重复题目。 + ```bash curl -X POST "http://localhost:8080/api/exam/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ - "file_id": 21, + "file_id": 69, "question_types": { "single_choice": 3, "multiple_choice": 2, @@ -682,6 +684,16 @@ curl -X POST "http://localhost:8080/api/exam/generate" \ }' ``` +**默认分数配置:** + +| 题型 | 默认分数 | +| ----------------- | ---- | +| `single_choice` | 2分 | +| `multiple_choice` | 4分 | +| `true_false` | 1分 | +| `fill_blank` | 2分 | +| `subjective` | 10分 | + **预期响应:** ```json @@ -704,12 +716,25 @@ curl -X POST "http://localhost:8080/api/exam/generate" \ } ``` +> **生成完成后**,通过 `GET /api/file/{fileId}` 接口可查询到生成结果,`processMessage` 字段会包含题型统计信息: +> +> ``` +> 生成成功,共15道题 +> +> 【题型统计】 +> 请求题型: {单选题: 10道, 填空题: 5道} +> 实际生成: {单选题: 10道, 填空题: 3道} +> +> 【短缺警告】 +> - fill_blank: 请求5道,实际生成3道 +> ``` + **测试用例3:通过 file\_path 指定文件** ```bash curl -X POST "http://localhost:8080/api/exam/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "file_path": "test1/1.docx", "collection": "test1", @@ -730,7 +755,7 @@ curl -X POST "http://localhost:8080/api/exam/generate" \ ```bash curl -X POST "http://localhost:8080/api/exam/generate" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "file_id": 21, "question_types": { @@ -752,7 +777,7 @@ curl -X POST "http://localhost:8080/api/exam/generate" \ ```bash curl -X GET "http://localhost:8080/api/file/21" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` **预期响应(生成中):** @@ -825,7 +850,7 @@ curl -X GET "http://localhost:8080/api/file/21" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_single_001", @@ -857,7 +882,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_multi_001", @@ -889,7 +914,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_tf_001", @@ -914,7 +939,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_fill_001", @@ -939,7 +964,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_subjective_001", @@ -964,7 +989,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "practice", "request_id": "grade_req_mixed_001", @@ -1046,21 +1071,21 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X GET "http://localhost:8080/api/exam/my/papers" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 12.6 开始考试(获取题目) ```bash curl -X POST "http://localhost:8080/api/exam/paper/paper_12345678-1234-1234-1234-123456789abc-start" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 12.7 获取考试结果 ```bash curl -X GET "http://localhost:8080/api/exam/record/record_12345678-1234-1234-1234-123456789abc/result" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 12.8 查询用户答题记录(按试卷) @@ -1068,7 +1093,7 @@ curl -X GET "http://localhost:8080/api/exam/record/record_12345678-1234-1234-123 ```bash curl -X POST "http://localhost:8080/api/exam/answers/query" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "paper_id": "paper_12345678-1234-1234-1234-123456789abc" }' @@ -1079,7 +1104,7 @@ curl -X POST "http://localhost:8080/api/exam/answers/query" \ ```bash curl -X POST "http://localhost:8080/api/exam/answers/query" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "session_id": "sess_practice_001" }' @@ -1093,7 +1118,7 @@ curl -X POST "http://localhost:8080/api/exam/answers/query" \ ```bash curl -X GET "http://localhost:8080/api/question/list?questionType=&difficulty=&status=&documentName=&limit=10" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 13.2 创建题目 @@ -1101,7 +1126,7 @@ curl -X GET "http://localhost:8080/api/question/list?questionType=&difficulty=&s ```bash curl -X POST "http://localhost:8080/api/question" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "question_type": "single_choice", "difficulty": 3, @@ -1128,7 +1153,7 @@ curl -X POST "http://localhost:8080/api/question" \ ```bash curl -X POST "http://localhost:8080/api/question/stats" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "status": "approved", "question_types": ["single_choice", "multiple_choice"] @@ -1143,7 +1168,7 @@ curl -X POST "http://localhost:8080/api/question/stats" \ ```bash curl -X POST "http://localhost:8080/api/formal-exam/paper/paper_12345678-1234-1234-1234-123456789abc/start" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` ### 14.2 提交考试(通过 recordId 方式,推荐) @@ -1151,7 +1176,7 @@ curl -X POST "http://localhost:8080/api/formal-exam/paper/paper_12345678-1234-12 ```bash curl -X POST "http://localhost:8080/api/exam/record/record_12345678-1234-1234-1234-123456789abc/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "answers": [ {"questionId": "q_001", "questionType": "true_false", "answer": true}, @@ -1168,7 +1193,7 @@ curl -X POST "http://localhost:8080/api/exam/record/record_12345678-1234-1234-12 ```bash curl -X POST "http://localhost:8080/api/exam/grade" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "type": "formal_exam", "record_id": "record_12345678-1234-1234-1234-123456789abc", @@ -1192,7 +1217,7 @@ curl -X POST "http://localhost:8080/api/exam/grade" \ ```bash curl -X GET "http://localhost:8080/api/formal-exam/record/record_12345678-1234-1234-1234-123456789abc/result" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" ``` *** @@ -1204,7 +1229,7 @@ curl -X GET "http://localhost:8080/api/formal-exam/record/record_12345678-1234-1 ```bash curl -X POST "http://localhost:8080/api/admin/exam/paper/preview" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "single_choice_count": 1, "multiple_choice_count": 1, @@ -1220,7 +1245,7 @@ curl -X POST "http://localhost:8080/api/admin/exam/paper/preview" \ ```bash curl -X POST "http://localhost:8080/api/admin/exam/paper/save" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "title": "月度考核试卷", "questionIds": [ @@ -1239,7 +1264,7 @@ curl -X POST "http://localhost:8080/api/admin/exam/paper/save" \ ```bash curl -X POST "http://localhost:8080/api/admin/exam/paper/paper_12345678-1234-1234-1234-123456789abc/publish" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc3OTg0NDExNCwiZXhwIjoxNzc5ODUxMzE0fQ.IyCqysE3WRNHTwHoFK_dF_loMFRCVaa1LXlloaFcFwkaMUzansW72b5SkI6gxymZAnJKpDfL0I-y6WdLLbAGkg" \ + -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDY0Njg2MSwiZXhwIjoxNzgwNjU0MDYxfQ.lNjvlKtxVRwjX9Ce2IO0M0NxB_Dm2vxkGlynBMUt6sjdUKr-R57nXhLcxHSM92gtaJYZHczYSU4l6eDWQ0a56A" \ -d '{ "exam_name": "月度考核", "start_time": "2026-06-01 09:00:00", diff --git a/docs/完整接口文档.md b/docs/完整接口文档.md index 9f354bc..5453e61 100644 --- a/docs/完整接口文档.md +++ b/docs/完整接口文档.md @@ -5,8 +5,8 @@ | 项目 | 内容 | | ---------- | ------------------ | | **文档名称** | 知识库管理系统完整接口文档 | -| **版本号** | V2.15.0 | -| **发布日期** | 2026-05-29 | +| **版本号** | V2.16.0 | +| **发布日期** | 2026-06-05 | | **文档状态** | 正式发布 | | **接口基础路径** | `/api` | | **认证方式** | Bearer Token (JWT) | @@ -656,24 +656,264 @@ Authorization: Bearer ### 6.3 流式事件类型 -| 事件类型 | 说明 | -| ------------- | --------- | -| start | 对话开始事件 | -| connected | RAG服务连接成功 | -| thinking | AI思考中 | -| searching | 知识库检索中 | -| sources | 检索到的来源信息 | -| chunk | 流式内容片段 | -| result/finish | 最终结果 | -| error | 错误信息 | +| 事件类型 | 说明 | +| ------------- | ------------------------------------------------------------ | +| start | 对话开始事件 | +| connected | RAG服务连接成功 | +| thinking | AI思考中 | +| searching | 知识库检索中 | +| sources | 检索到的来源信息(仅前端展示用,**不写入引用表**) | +| chunk | 流式内容片段 | +| result/finish | 最终结果(包含 answer / citations / images,将写入数据库) | +| error | 错误信息 | + +**finish 事件核心字段说明**: + +| 字段 | 类型 | 说明 | +| ------------ | -------- | ------------------------------------------------------------ | +| answer | String | AI生成的回答文本(含 `[ref:chunk_id]` 引用标记,前端可解析为可点击引用) | +| citations | Array | 真正被引用的切片列表,将写入 `context_reference` 表;每个元素包含 `chunk_id`、`chunk_index`、`source`、`collection`、`doc_type`、`section`、`chunk_type`、`page` 等字段 | +| images | Array | 回答中包含的图片列表,将写入 `context_image` 表;每个元素包含 `image_id`、`url`、`source`、`page`、`section`、`description`、`score`、`collection` 等字段 | +| duration_ms | Integer | 回答耗时(毫秒),写入 `context_message.duration_ms` | + +**重要数据流程(保存时自动执行)**: + +1. **context_reference.preview 自动填充**:对 `citations` 中每个引用,系统自动调用 RAG 预览接口 `GET /documents/{path}/preview?chunk_index=N&context=0`,将目标切片的完整正文写入 `preview` 字段,供前端定位展示。若接口失败,`preview` 写入失败信息。 +2. **context_message 无 sources 字段**:旧版 `sources` 已移除,仅在流式事件中返回来源提示信息用于前端展示。 +3. **context_image 字段精简**:仅保留 `image_id`、`path`、`source`、`page`、`section`、`chunk_type`、`description`、`score`、`collection`、`create_time`;已移除 `filename`、`size_bytes`、`format`、`page_end`、`type`、`full_description` 等冗余字段。 --- -## 七、AI数据接口 +## 七、AI 会话管理接口 + +**基础路径**:`/api/ai` + +### 7.1 获取用户会话列表 + +**接口路径**: `GET /api/ai/sessions?page=1&pageSize=10` + +**请求参数**: + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| page | Integer | 否 | 1 | 页码 | +| pageSize | Integer | 否 | 10 | 每页数量 | + +**返回结构**: +```json +{ + "success": true, + "data": [ + { + "id": 1, + "sessionId": "sess_1780410472658_9qg9a9hhp", + "userId": 1, + "createTime": "2026-06-02T14:27:53" + } + ], + "total": 5, + "page": 1, + "pageSize": 10, + "pages": 1 +} +``` + +--- + +### 7.2 获取会话详情 + +**接口路径**: `GET /api/ai/session/{sessionId}?page=1&pageSize=20` + +**路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| sessionId | String | 是 | 会话ID | + +**请求参数**: + +| 参数 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| page | Integer | 否 | 1 | 页码 | +| pageSize | Integer | 否 | 20 | 每页消息数 | + +**返回结构**: +```json +{ + "success": true, + "data": [ + { + "id": 175, + "conversationId": 65, + "role": "assistant", + "content": "用户问: xxx", + "messageType": "rag", + "isFinished": 1, + "answer": "根据参考资料...", + "images": "[{\"image_id\":\"xxx\",\"url\":\"/api/image/xxx/data\"}]", + "durationMs": 75512, + "createTime": "2026-06-02T14:29:09" + } + ], + "total": 3, + "page": 1, + "pageSize": 20, + "pages": 1 +} +``` + +**说明**:`context_message` 无 `sources` 字段;图片信息在 `images` 字段中(JSON数组字符串)。 + +--- + +### 7.3 获取消息文件来源列表 + +**接口路径**: `GET /api/ai/message/{messageId}/sources` + +**路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| messageId | Long | 是 | 消息ID(来自 context_message.id) | + +**返回结构**(按文档名称聚合,去重显示): +```json +{ + "success": true, + "data": [ + { + "docName": "1.docx", + "docType": "other", + "referenceCount": 5, + "pages": "1-86" + }, + { + "docName": "2.docx", + "docType": "other", + "referenceCount": 3, + "pages": "1" + } + ], + "total": 2 +} +``` + +**说明**:此接口从 `context_reference` 表按文档聚合查询,不依赖已移除的 `context_message.sources` 字段。 + +--- + +### 7.4 获取消息引用信息 + +**接口路径**: `GET /api/ai/message/{messageId}/references?docName=xxx` + +**路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| messageId | Long | 是 | 消息ID | + +**请求参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| docName | String | 否 | 按文档名称过滤 | + +**返回结构**: +```json +{ + "success": true, + "data": [ + { + "id": 440, + "messageId": 178, + "chunkId": "1.docx_86", + "chunkIndex": 86, + "collection": "dept_1_kb", + "docName": "1.docx", + "docType": "other", + "page": 1, + "section": "3.1 权重计算公式", + "chunkType": "text", + "excerpt": "一级指标合计权重不低于70%。", + "preview": "完整的目标切片正文内容...", + "score": 0.838, + "createTime": "2026-06-04T15:52:49" + } + ], + "total": 5 +} +``` + +**关键字段说明**: + +| 字段 | 说明 | +|------|------| +| `chunkId` | 切片唯一标识,格式:`{docName}_{chunkIndex}` | +| `preview` | 目标切片完整正文(通过 RAG 预览接口自动获取),若接口失败则写入失败信息 | +| `score` | 相关性评分 | +| `excerpt` | 切片摘要内容 | + +--- + +### 7.5 获取会话所有引用 + +**接口路径**: `GET /api/ai/session/{sessionId}/references` + +**路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| sessionId | String | 是 | 会话ID | + +**说明**:返回会话内所有消息关联的全部引用信息,结构同 7.4。 + +--- + +### 7.6 删除会话 + +**接口路径**: `DELETE /api/ai/session/{sessionId}` + +**说明**:删除指定会话及其所有消息和引用数据。 + +--- + +### 7.7 批量删除会话 + +**接口路径**: `DELETE /api/ai/sessions/batch?ids=1,2,3` + +**请求参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| ids | String | 是 | 会话ID列表,逗号分隔 | + +--- + +### 7.8 中断AI流式问答 + +**接口路径**: `POST /api/ai/chat/stop?sessionId=sess_xxx` + +**请求参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| sessionId | String | 是 | 会话ID | + +**返回**: +```json +{ + "success": true, + "message": "已中断AI回答" +} +``` + +--- + +## 八、AI数据接口 **基础路径**:`/api/ai/data` -### 7.1 获取会话消息 +### 8.1 获取会话消息 **接口路径**: `GET /api/ai/data/session/{sessionId}/messages` @@ -702,11 +942,11 @@ Authorization: Bearer --- -## 八、反馈管理接口 +## 九、反馈管理接口 **基础路径**:`/api/feedback` -### 8.1 提交反馈 +### 9.1 提交反馈 **接口路径**: `POST /api/feedback` @@ -886,24 +1126,27 @@ POST /api/ai/chat/stream "answer": "根据【参考资料】...", "images": [ { - "id": "ab77281e7913.jpg", - "score": 7.8, - "type": "chart", + "image_id": "ab77281e7913.jpg", + "path": "/api/image/ab77281e7913.jpg/data", "source": "三峡公报_1-15页.pdf", "page": 12, + "section": "3.1 数据图表", + "chunk_type": "image", "description": "这是一张柱状图...", - "full_description": "这是一张柱状图,展示了...", - "url": "/images/ab77281e7913.jpg" + "score": 0.85, + "collection": "public_kb" } ] } ``` **步骤3:系统自动处理** -- ✅ 提取图片元数据(id, score, type, source, page, description, full_description) +- ✅ 提取图片元数据(image_id, path, source, page, section, chunk_type, description, score, collection) - ✅ 从AI服务下载图片到本地目录 - ✅ 保存图片元数据到 `context_image` 表 -- ✅ 保存图片到本地文件系统(`/tmp/img/` 或 `./img/`) +- ✅ 保存图片到本地文件系统 + +**已移除的旧字段**:`filename`、`size_bytes`、`format`、`page_end`、`type`、`full_description` **步骤4:前端获取图片数据** ```bash @@ -954,14 +1197,9 @@ images.forEach(image => {

来源:{image.source}

页码:第 {image.page} 页

-

类型:{image.type}

+

类型:{image.chunk_type}

描述:{image.description}

- {image.full_description && ( -
- 查看完整描述 -

{image.full_description}

-
- )} +

相关性评分:{image.score}

))} @@ -978,8 +1216,9 @@ images.forEach(image => {

来源:{{ image.source }}

页码:第 {{ image.page }} 页

-

类型:{{ image.type }}

+

类型:{{ image.chunk_type }}

描述:{{ image.description }}

+

相关性评分:{{ image.score }}

@@ -1000,16 +1239,19 @@ export default { ```json { "image_id": "图片唯一标识", - "filename": "原始文件名(可选)", - "path": "存储路径", - "size_bytes": 1024000, - "format": "图片格式(可选)", + "path": "存储路径/图片URL", "source": "来源文档(可选)", "page": 1, + "section": "所在章节(可选)", + "chunk_type": "切片类型(可选)如:image/table", + "description": "图片描述(可选)", + "score": 0.85, "collection": "所属向量库(可选)" } ``` +**字段说明**:`filename`、`size_bytes`、`format`、`page_end`、`type`、`full_description` 已移除。 + --- ### 10.2 获取图片列表 @@ -1045,9 +1287,14 @@ export default { **请求体**: ```json { - "filename": "更新后的文件名(可选)", "path": "更新后的路径(可选)", - "format": "更新后的格式(可选)" + "source": "更新后的来源文档(可选)", + "page": 2, + "section": "更新后的章节(可选)", + "chunk_type": "更新后的切片类型(可选)", + "description": "更新后的描述(可选)", + "score": 0.9, + "collection": "更新后的向量库(可选)" } ``` @@ -2022,7 +2269,7 @@ export default { ## 二十、接口权限说明 -### 20.1 权限层级 +### 21.1 权限层级 | 用户类型 | 类型值 | 权限说明 | | ----- | --- | ------------------- | @@ -2055,7 +2302,7 @@ export default { ## 二十一、错误码详解 -### 21.1 认证相关错误 +### 22.1 认证相关错误 | 错误码 | 错误信息 | 解决方案 | | --- | -------- | -------------- | @@ -2064,7 +2311,7 @@ export default { | 401 | Token已过期 | 请重新登录 | | 403 | 权限不足 | 联系管理员提升权限 | -### 21.2 业务逻辑错误 +### 22.2 业务逻辑错误 | 错误码 | 错误信息 | 解决方案 | | --- | -------------------- | -------------- | @@ -2077,7 +2324,7 @@ export default { ## 二十二、使用限制 -### 22.1 通用限制 +### 23.1 通用限制 | 限制项 | 限制值 | 说明 | | -------- | ---- | ----------- | @@ -2087,7 +2334,7 @@ export default { | 每页最大记录数 | 100 | 超过后建议优化查询 | | Token有效期 | 24小时 | 登录Token有效期 | -### 22.2 频率限制 +### 23.2 频率限制 | 接口类型 | 限制 | 时间窗口 | | ------- | ---- | ---- | diff --git a/docs/批阅接口测试.md b/docs/批阅接口测试.md index fa6a141..c061c51 100644 --- a/docs/批阅接口测试.md +++ b/docs/批阅接口测试.md @@ -38,7 +38,7 @@ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/ **新 Token**(有效期2小时): ``` -eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w +eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew ``` *** @@ -48,49 +48,52 @@ eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTg ### 4.1 单选题测试(日常练习) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"test_001","answers":[{"questionId":"9d05c475-b4fe-4679-a450-ee88a94b3b34","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":"C","maxScore":2.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_001","answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","content":{"stem":"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?","data":{"options":[{"key":"A","content":"允许入住并记录信息"},{"key":"B","content":"一律不予入住并立即上报属地公安机关"},{"key":"C","content":"暂时允许入住并后续核查"},{"key":"D","content":"要求重新提供证件"}]},"answer":"B"},"studentAnswer":"B","maxScore":2.0}]}' ``` -### 4.2 多选题测试(日常练习) +### 4.2 单选题测试2(日常练习) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"test_002","answers":[{"questionId":"ee652f7e-da5e-4129-8766-c113277332f4","questionType":"multiple_choice","questionContent":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"]},"studentAnswer":["A","B"],"maxScore":4.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_002","answers":[{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","content":{"stem":"根据文档内容,谁是住宿登记的第一责任人?","data":{"options":[{"key":"A","content":"安保人员"},{"key":"B","content":"前台工作人员"},{"key":"C","content":"经理"},{"key":"D","content":"客户"}]},"answer":"B"},"studentAnswer":"B","maxScore":2.0}]}' ``` ### 4.3 判断题测试(日常练习) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"test_003","answers":[{"questionId":"76913ad8-5325-4f30-a03a-6e19e434b59e","questionType":"true_false","questionContent":{"stem":"务求实效原则允许在终端建设中适度预留冗余预算,以应对未来可能的功能升级需求。","data":{},"answer":"false"},"studentAnswer":"false","maxScore":1.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_003","answers":[{"questionId":"7699dfb0-e03e-4e9a-8653-450d101a85d3","questionType":"true_false","content":{"stem":"一级指标合计权重不低于70%。","data":{},"answer":"对"},"studentAnswer":"对","maxScore":1.0}]}' ``` ### 4.4 填空题测试(日常练习) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"test_004","answers":[{"questionId":"7ae3daef-0345-4852-bd37-336e74498cc4","questionType":"fill_blank","questionContent":{"stem":"务求实效原则强调以___为出发点,通过科学设定和严格执行终端投入标准,实现___与___的双重提升。","data":{"blank_count":3},"answer":["终端功能发挥和服务水平提升","终端功能发挥","服务水平提升"]},"studentAnswer":["终端功能发挥和服务水平提升","终端功能发挥","服务水平"],"maxScore":2.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_004","answers":[{"questionId":"88eaf2d7-4adb-4daf-9978-3113e754b7d5","questionType":"fill_blank","content":{"stem":"零售价格指数的计算公式为:___。","data":{"blank_count":1},"answer":[["实际零售价格/零售指导价格*100%"]]},"studentAnswer":[["实际零售价格/零售指导价格*100%"]],"maxScore":2.0}]}' ``` -### 4.5 主观题测试(日常练习) +### 4.5 主观题测试(日常练习)无题目 ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"test_005","answers":[{"questionId":"ea6ba220-43ff-44d8-8b24-cd350eeb8b53","questionType":"subjective","questionContent":{"stem":"请结合文档内容,简述\"务求实效原则\"在终端建设管理中的具体体现,并说明其与形式主义倾向的根本区别。","data":{"answer_length_hint":"150–200字"},"answer":"务求实效原则具体体现为:以终端功能发挥和服务水平提升为唯一导向,科学设定并严格执行投入标准,杜绝一切不必要的支出和浪费。"},"studentAnswer":"务求实效原则强调终端功能发挥和服务水平提升,杜绝浪费。形式主义只注重表面,不注重实际效果。","maxScore":6.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_005","answers":[{"questionId":"806754e9-3951-4562-8641-553c42564ab8","questionType":"subjective","content":{"stem":"请简述加强吸烟场所维护的主要目的及意义。","data":{"scoring_points":[{"point":"要点1:确保设施设备良好状态","weight":0.5},{"point":"要点2:保障文明吸烟环境功能发挥","weight":0.3},{"point":"要点3:提高消费者满意度","weight":0.2}]},"answer":"加强吸烟场所维护的主要目的是确保设施设备处于良好状态,保障文明吸烟环境功能作用的最大发挥,进一步提高消费者满意度。"},"studentAnswer":"加强吸烟场所维护可以确保设施良好,提升吸烟环境,让消费者更满意。","maxScore":10.0}]}' +``` +```bash +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"test_subjective_001","answers":[{"questionId":"4c1907fa-81c8-4244-9d87-f7affe38b621","questionType":"subjective","content":{"stem":"请简述第一章总则中提到的核心原则,并结合实际应用场景说明其重要性。","data":{},"answer":"核心原则包括:1. 以用户需求为导向;2. 保证信息的准确性与可靠性;3. 遵循法律法规和行业规范。在实际应用中,这些原则确保了系统的有效性和合规性,避免因错误信息或违规操作导致的风险。"},"studentAnswer":"第一章总则的核心原则是以用户需求为导向,保证信息准确可靠,同时遵循法律法规和行业规范。这些原则在实际应用中非常重要,能够确保系统有效运行并符合合规要求。","maxScore":10.0}]}' ``` ### 4.6 批量测试(所有题型,包含错题,日常练习) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDMwNDMwOCwiZXhwIjoxNzgwMzExNTA4fQ.5NLIrXfK-7MVrrmU7TZ7L_z2TXxc4OzaYIOmoFKBLOAkX9pjCBtxz915QQ1SGLekHTj5DBcgF-NhIZDSw-CPtQ" -d '{"answerType":"practice","requestId":"batch_test_001","answers":[{"questionId":"9d05c475-b4fe-4679-a450-ee88a94b3b34","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":"","maxScore":2.0},{"questionId":"ee652f7e-da5e-4129-8766-c113277332f4","questionType":"multiple_choice","questionContent":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"]},"studentAnswer":[],"maxScore":4.0},{"questionId":"76913ad8-5325-4f30-a03a-6e19e434b59e","questionType":"true_false","questionContent":{"stem":"务求实效原则允许在终端建设中适度预留冗余预算,以应对未来可能的功能升级需求。","data":{},"answer":"false"},"studentAnswer":"false","maxScore":1.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"batch_test_001","answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","content":{"stem":"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?","data":{"options":[{"key":"A","content":"允许入住并记录信息"},{"key":"B","content":"一律不予入住并立即上报属地公安机关"},{"key":"C","content":"暂时允许入住并后续核查"},{"key":"D","content":"要求重新提供证件"}]},"answer":"B"},"studentAnswer":"A","maxScore":2.0},{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","content":{"stem":"根据文档内容,谁是住宿登记的第一责任人?","data":{"options":[{"key":"A","content":"安保人员"},{"key":"B","content":"前台工作人员"},{"key":"C","content":"经理"},{"key":"D","content":"客户"}]},"answer":"B"},"studentAnswer":"C","maxScore":2.0},{"questionId":"7699dfb0-e03e-4e9a-8653-450d101a85d3","questionType":"true_false","content":{"stem":"一级指标合计权重不低于70%。","data":{},"answer":"对"},"studentAnswer":"错","maxScore":1.0}]}' ``` **错题说明**: -- 单选题:学生选A(正确答案是C) -- 多选题:学生选A、B、C(正确答案是A、B、D,C选项违背务求实效原则) -- 判断题:学生选true(正确答案是false) +- 单选题1:学生选A(正确答案是B) +- 单选题2:学生选C(正确答案是B) +- 判断题:学生选错(正确答案是对) -### 4.7 模拟考测试(answerType = mock\_exam) +### 4.7 模拟考测试(answerType = mock_exam) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"mock_exam","requestId":"mock_test_001","answers":[{"questionId":"9d05c475-b4fe-4679-a450-ee88a94b3b34","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":"C","maxScore":2.0},{"questionId":"ee652f7e-da5e-4129-8766-c113277332f4","questionType":"multiple_choice","questionContent":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"]},"studentAnswer":["A","B","D"],"maxScore":4.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"mock_exam","requestId":"mock_test_001","answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","content":{"stem":"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?","data":{"options":[{"key":"A","content":"允许入住并记录信息"},{"key":"B","content":"一律不予入住并立即上报属地公安机关"},{"key":"C","content":"暂时允许入住并后续核查"},{"key":"D","content":"要求重新提供证件"}]},"answer":"B"},"studentAnswer":"B","maxScore":2.0},{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","content":{"stem":"根据文档内容,谁是住宿登记的第一责任人?","data":{"options":[{"key":"A","content":"安保人员"},{"key":"B","content":"前台工作人员"},{"key":"C","content":"经理"},{"key":"D","content":"客户"}]},"answer":"B"},"studentAnswer":"B","maxScore":2.0}]}' ``` ### 4.8 正式考测试(通过 recordId 接口,推荐方式) @@ -98,49 +101,49 @@ curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/ > **注意**:正式考试推荐使用 `/api/exam/record/{recordId}/grade` 接口提交。这种方式会关联已存在的考试记录。 ```bash -curl -X POST http://localhost:8080/api/exam/record/59759c40-ee4e-4ff5-ab03-4819a0499beb/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answers":[{"questionId":"9d05c475-b4fe-4679-a450-ee88a94b3b34","questionType":"single_choice","answer":"C"},{"questionId":"ee652f7e-da5e-4129-8766-c113277332f4","questionType":"multiple_choice","answer":["A","B","D"]}]}' +curl -X POST http://localhost:8080/api/exam/record/17f5be59-3d81-480a-98bb-1e1a2a4556e6/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","answer":"B"},{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","answer":"B"}]}' ``` ### 4.9 正式考测试(通过通用接口 + recordId 参数) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"formal_exam","recordId":"59759c40-ee4e-4ff5-ab03-4819a0499beb","requestId":"formal_test_001","paperId":"0ef70443-67d3-48cd-9309-f5088c092fe1","answers":[{"questionId":"9d05c475-b4fe-4679-a450-ee88a94b3b34","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":"C","maxScore":2.0}]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"formal_exam","recordId":"17f5be59-3d81-480a-98bb-1e1a2a4556e6","requestId":"formal_test_001","paperId":"4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f","answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","content":{"stem":"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?","data":{"options":[{"key":"A","content":"允许入住并记录信息"},{"key":"B","content":"一律不予入住并立即上报属地公安机关"},{"key":"C","content":"暂时允许入住并后续核查"},{"key":"D","content":"要求重新提供证件"}]},"answer":"B"},"studentAnswer":"B","maxScore":2.0}]}' ``` ### 4.10 空白试卷测试 - 日常练习(answers 为空数组) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"practice","requestId":"blank_test_001","answers":[]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"practice","requestId":"blank_test_001","answers":[]}' ``` ### 4.11 空白试卷测试 - 模拟考(answers 为空数组) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"mock_exam","requestId":"blank_test_002","answers":[]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"mock_exam","requestId":"blank_test_002","answers":[]}' ``` ### 4.12 空白试卷测试 - 正式考试(通过 recordId 接口) ```bash -curl -X POST http://localhost:8080/api/exam/record/4e34c752-1e0e-4207-8fdb-b0027b30521e/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answers":[]}' +curl -X POST http://localhost:8080/api/exam/record/ff860338-99ed-4211-bf85-fce6605c8fcc/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answers":[]}' ``` ### 4.13 空白试卷测试 - 正式考试(通过通用接口 + recordId) ```bash -curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDAzMTgyNSwiZXhwIjoxNzgwMDM5MDI1fQ.an_bqtorziJ5Yb-otGPIIg400fCM1-VLLfX7mgQYHspOgSsTczcSY70evxsMUnfGmOr_euXgXwf2VkMQoXpG5w" -d '{"answerType":"formal_exam","recordId":"4e34c752-1e0e-4207-8fdb-b0027b30521e","requestId":"blank_test_003","answers":[]}' +curl -X POST http://localhost:8080/api/exam/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answerType":"formal_exam","recordId":"ff860338-99ed-4211-bf85-fce6605c8fcc","requestId":"blank_test_003","answers":[]}' ``` ### 4.14 正式考试 - 只提交一道题(通过 recordId 接口) ```bash -curl -X POST http://localhost:8080/api/exam/record/2fa88db4-bc90-4096-9970-3286639c5b5b/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDMxOTgzMiwiZXhwIjoxNzgwMzI3MDMyfQ.azBEWs7-LiicNDA_O0qdm-TPmBtKLBUeCplRPnkGl7NFUhn-JMP5-G9gboP7eHxsaIvowoY6B2TVlB4z8bDIuQ" -d '{"answers":[{"questionId":"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8","questionType":"single_choice","answer":"C"}]}' +curl -X POST http://localhost:8080/api/exam/record/26b9fac0-3f92-4d71-a5dc-3e8b432bd580/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","answer":"B"}]}' ``` ### 4.15 正式考试 - 一道题没选(通过 recordId 接口) ```bash -curl -X POST http://localhost:8080/api/exam/record/389806c8-3b42-4b5a-adb8-23d166bb1053/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MDMxOTgzMiwiZXhwIjoxNzgwMzI3MDMyfQ.azBEWs7-LiicNDA_O0qdm-TPmBtKLBUeCplRPnkGl7NFUhn-JMP5-G9gboP7eHxsaIvowoY6B2TVlB4z8bDIuQ" -d '{"answers":[{"questionId":"5af6fdce-dbf2-4a57-9ef4-bef176be6fb8","questionType":"single_choice","answer":""},{"questionId":"5e069067-a10d-4230-9564-e7503d72d738","questionType":"multiple_choice","answer":["A","B"]},{"questionId":"e6bb2566-90a8-4651-b553-083a1d695b3c","questionType":"true_false","answer":"true"}]}' +curl -X POST http://localhost:8080/api/exam/record/17f5be59-3d81-480a-98bb-1e1a2a4556e6/grade -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTc4MTA5NTA5MCwiZXhwIjoxNzgxMTAyMjkwfQ.BXB2Zmv68coIsQcynBPFprCT-xfBNKhs_G_xSVsLnrr7eXbhfU8NUT7v_MZYRxfNarIqnUC-wWe1Xi3mnv4oew" -d '{"answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","answer":""},{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","answer":"B"}]}' ``` **answerType 测试总结**: @@ -160,13 +163,13 @@ AI端接口**支持** **`explanation`** **字段**,可以直接使用包含完 ### 5.1 单选题测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q1","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C","explanation":"文档明确指出要着眼于终端功能发挥和服务水平提升"},"studentAnswer":"C","maxScore":2}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"ea6a7f44-9077-4f19-b10e-8239a5198f4d","questionType":"single_choice","content":{"stem":"根据文档内容,当发现人证不符、证件伪造或冒用证件时,应采取的措施是?","data":{"options":[{"key":"A","content":"允许入住并记录信息"},{"key":"B","content":"一律不予入住并立即上报属地公安机关"},{"key":"C","content":"暂时允许入住并后续核查"},{"key":"D","content":"要求重新提供证件"}]},"answer":"B","explanation":"根据文档第八条明确规定,发现人证不符、证件伪造、冒用证件的,一律不予入住,并立即上报属地公安机关。"},{"questionId":"9d59e7c5-edfc-4517-9fb5-780b389b66fb","questionType":"single_choice","content":{"stem":"根据文档内容,谁是住宿登记的第一责任人?","data":{"options":[{"key":"A","content":"安保人员"},{"key":"B","content":"前台工作人员"},{"key":"C","content":"经理"},{"key":"D","content":"客户"}]},"answer":"B","explanation":"根据文档第四条,前台工作人员被明确为住宿登记的第一责任人。"},"studentAnswer":"B","maxScore":2}]}' ``` ### 5.2 多选题测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q2","questionType":"multiple_choice","questionContent":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"],"explanation":"A、B、D均符合务求实效原则"},"studentAnswer":["A","B","D"],"maxScore":4}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q2","questionType":"multiple_choice","content":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"],"explanation":"A、B、D均符合务求实效原则"},"studentAnswer":["A","B","D"],"maxScore":4}]}' ``` ### 5.3 空白试卷测试(answers 为空数组) @@ -208,37 +211,37 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json ### 5.4 填空题空答案测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q3","questionType":"fill_blank","questionContent":{"stem":"务求实效原则强调以___为出发点,通过科学设定和严格执行终端投入标准,实现___与___的双重提升。","data":{"blank_count":3},"answer":["终端功能发挥和服务水平提升","终端功能发挥","服务水平提升"]},"studentAnswer":null,"maxScore":3}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q3","questionType":"fill_blank","content":{"stem":"务求实效原则强调以___为出发点,通过科学设定和严格执行终端投入标准,实现___与___的双重提升。","data":{"blank_count":3},"answer":["终端功能发挥和服务水平提升","终端功能发挥","服务水平提升"]},"studentAnswer":null,"maxScore":3}]}' ``` ### 5.5 主观题空答案测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q4","questionType":"subjective","questionContent":{"stem":"请简述\"务求实效原则\"的核心要求。","data":{"scoring_points":[{"point":"功能发挥","weight":0.5},{"point":"服务水平","weight":0.3},{"point":"杜绝浪费","weight":0.2}]},"answer":"以终端功能发挥和服务水平提升为唯一导向"},"studentAnswer":"","maxScore":5}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q4","questionType":"subjective","content":{"stem":"请简述\"务求实效原则\"的核心要求。","data":{"scoring_points":[{"point":"功能发挥","weight":0.5},{"point":"服务水平","weight":0.3},{"point":"杜绝浪费","weight":0.2}]},"answer":"以终端功能发挥和服务水平提升为唯一导向"},"studentAnswer":"","maxScore":5}]}' ``` ### 5.6 判断题空答案测试(studentAnswer 为空字符串) ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q5","questionType":"true_false","questionContent":{"stem":"务求实效原则允许在终端建设中适度预留冗余预算,以应对未来可能的功能升级需求。","answer":"false"},"studentAnswer":"","maxScore":2}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q5","questionType":"true_false","content":{"stem":"务求实效原则允许在终端建设中适度预留冗余预算,以应对未来可能的功能升级需求。","answer":"false"},"studentAnswer":"","maxScore":2}]}' ``` ### 5.7 判断题空答案测试(studentAnswer 为 null) ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q6","questionType":"true_false","questionContent":{"stem":"务求实效原则强调以终端功能发挥和服务水平提升为唯一导向。","answer":"true"},"studentAnswer":null,"maxScore":2}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q6","questionType":"true_false","content":{"stem":"务求实效原则强调以终端功能发挥和服务水平提升为唯一导向。","answer":"true"},"studentAnswer":null,"maxScore":2}]}' ``` ### 5.8 单选题空答案测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q7","questionType":"single_choice","questionContent":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":null,"maxScore":2}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q7","questionType":"single_choice","content":{"stem":"根据文档内容,务求实效原则的核心要求聚焦于哪一根本目标?","data":{"options":[{"key":"A","content":"扩大终端数量规模"},{"key":"B","content":"提升终端信息化系统覆盖率"},{"key":"C","content":"着眼于终端功能发挥和服务水平提升"},{"key":"D","content":"统一各类终端建设外观标准"}]},"answer":"C"},"studentAnswer":null,"maxScore":2}]}' ``` ### 5.9 多选题空答案测试 ```bash -curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q8","questionType":"multiple_choice","questionContent":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"]},"studentAnswer":[],"maxScore":4}]}' +curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json" -d '{"answers":[{"questionId":"q8","questionType":"multiple_choice","content":{"stem":"依据务求实效原则,以下哪些做法符合其核心要求?(可多选)","data":{"options":[{"key":"A","content":"科学设定终端投入标准"},{"key":"B","content":"严格执行终端投入标准"},{"key":"C","content":"优先采购高配置但非必需的智能设备"},{"key":"D","content":"坚决杜绝不必要的支出和浪费"}]},"answer":["A","B","D"]},"studentAnswer":[],"maxScore":4}]}' ``` *** @@ -251,7 +254,7 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json | 认证 | 需要 Bearer Token | 需要 Bearer Token | 不需要认证 | | requestId | 必需 | 不需要 | 不需要 | | recordId | 可选(正式考试时使用) | 路径参数(必需) | 不支持 | -| answerType | 前端传入,后端原样使用 | 固定为 "formal\_exam" | 不支持 | +| answerType | 前端传入,后端原样使用 | 固定为 "formal_exam" | 不支持 | | questionId | 使用数据库UUID | 使用数据库UUID | 可自定义ID | | maxScore | 小数 (2.0) | 不需要(从数据库获取) | 整数 (2) | | explanation字段 | **不支持** | **不支持** | 支持 | @@ -278,7 +281,7 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json "requestId": "test_001", "results": [ { - "questionId": "9d05c475-b4fe-4679-a450-ee88a94b3b34", + "questionId": "ea6a7f44-9077-4f19-b10e-8239a5198f4d", "correct": true, "feedback": "回答正确!", "score": 2.0, @@ -299,24 +302,30 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json "code": 200, "message": "提交成功", "data": { - "recordId": "59759c40-ee4e-4ff5-ab03-4819a0499beb", - "paperId": "0ef70443-67d3-48cd-9309-f5088c092fe1", + "recordId": "17f5be59-3d81-480a-98bb-1e1a2a4556e6", + "paperId": "4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f", "userId": 1, "answerType": "formal_exam", "status": "graded", - "totalScore": 12.0, - "paperTitle": "测试试卷", + "totalScore": 4.0, + "paperTitle": "自动生成的试卷", "answers": [ { - "questionId": "9d05c475-b4fe-4679-a450-ee88a94b3b34", + "questionId": "ea6a7f44-9077-4f19-b10e-8239a5198f4d", + "score": 2.0, + "isCorrect": true, + "feedback": "回答正确!" + }, + { + "questionId": "9d59e7c5-edfc-4517-9fb5-780b389b66fb", "score": 2.0, "isCorrect": true, "feedback": "回答正确!" } ], - "startTime": "2024-05-20T10:00:00", - "submitTime": "2024-05-20T10:30:00", - "gradedTime": "2024-05-20T10:30:05" + "startTime": "2026-06-10T11:11:19", + "submitTime": "2026-06-10T11:11:49", + "gradedTime": "2026-06-10T11:11:49" } } ``` @@ -332,7 +341,7 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json "correct": true, "feedback": "正确!", "maxScore": 2, - "questionId": "9d05c475-b4fe-4679-a450-ee88a94b3b34", + "questionId": "ea6a7f44-9077-4f19-b10e-8239a5198f4d", "score": 2 } ], @@ -371,17 +380,17 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json "code": 200, "message": "提交成功", "data": { - "recordId": "59759c40-ee4e-4ff5-ab03-4819a0499beb", - "paperId": "0ef70443-67d3-48cd-9309-f5088c092fe1", + "recordId": "17f5be59-3d81-480a-98bb-1e1a2a4556e6", + "paperId": "4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f", "userId": 1, "answerType": "formal_exam", "status": "graded", "totalScore": 0.0, - "paperTitle": "测试试卷", + "paperTitle": "自动生成的试卷", "answers": [], - "startTime": "2024-05-20T10:00:00", - "submitTime": "2024-05-20T10:30:00", - "gradedTime": "2024-05-20T10:30:05" + "startTime": "2026-06-10T11:11:19", + "submitTime": "2026-06-10T11:11:49", + "gradedTime": "2026-06-10T11:11:49" } } ``` @@ -394,13 +403,19 @@ curl -X POST http://localhost:5001/exam/grade -H "Content-Type: application/json | questionId | 题目类型 | 文档来源 | | -------------------------------------- | ---------------- | ------------------- | -| `9d05c475-b4fe-4679-a450-ee88a94b3b34` | single\_choice | public\_kb - 务求实效原则 | -| `ee652f7e-da5e-4129-8766-c113277332f4` | multiple\_choice | public\_kb - 务求实效原则 | -| `76913ad8-5325-4f30-a03a-6e19e434b59e` | true\_false | public\_kb - 务求实效原则 | -| `7ae3daef-0345-4852-bd37-336e74498cc4` | fill\_blank | public\_kb - 务求实效原则 | -| `ea6ba220-43ff-44d8-8b24-cd350eeb8b53` | subjective | public\_kb - 务求实效原则 | +| `ea6a7f44-9077-4f19-b10e-8239a5198f4d` | single_choice | test.docx - 住宿登记规定 | +| `9d59e7c5-edfc-4517-9fb5-780b389b66fb` | single_choice | test.docx - 住宿登记规定 | +| `7699dfb0-e03e-4e9a-8653-450d101a85d3` | true_false | 1.docx - 指标权重规定 | +| `88eaf2d7-4adb-4daf-9978-3113e754b7d5` | fill_blank | 1.docx - 零售价格指数公式 | +| `806754e9-3951-4562-8641-553c42564ab8` | subjective | 3.docx - 吸烟场所维护 | -数据库文件路径:[knowledge\_management\_system.sql](file:///d:/Users/19211/Desktop/demo/docs/sql/knowledge_management_system.sql) +**试卷信息**: +- 试卷ID:`4e1c48d5-2019-48b6-a31b-2fea3ebf1b6f` +- 试卷名称:自动生成的试卷 +- 总分:4.00 +- 题目数量:2 + +数据库文件路径:[knowledge_management_system.sql](file:///d:/Users/19211/Desktop/222/demo/docs/sql/knowledge_management_system.sql) ### 8.1 数据库题目查询 SQL @@ -443,7 +458,7 @@ private Object answer; **字段命名规范**: -- 所有字段使用驼峰命名(camelCase),而不是下划线命名(snake\_case) +- 所有字段使用驼峰命名(camelCase),而不是下划线命名(snake_case) - 例如:`answerType`、`recordId`、`questionId`、`studentAnswer`、`maxScore` **使用建议**: @@ -470,4 +485,4 @@ private Object answer; *** -**文档结束** +**文档结束** \ No newline at end of file diff --git a/docs/文件上传与处理功能重构文档.md b/docs/文件上传与处理功能重构文档.md new file mode 100644 index 0000000..7121bf1 --- /dev/null +++ b/docs/文件上传与处理功能重构文档.md @@ -0,0 +1,343 @@ +文件上传与处理功能重构文档 +📋 修改概述 +将文件上传、向量化、出题三个功能解耦,实现分步式独立控制,支持灵活的业务场景组合。 + +🔧 核心改动 +1. 数据库表结构变更 + 1.1 File 表新增字段 + tags (JSON类型):存储文件自定义标签,如版本信息、分类标识等元数据 + 1.2 Question 表新增字段 + is_deleted (INT类型,默认0):软删除标志,0表示正常,1表示已删除 + +2. 实体类修改 + 2.1 File 实体 + 新增 tags 字段(JSON格式),支持存储任意自定义标签 + 2.2 Question 实体 + 新增 isDeleted 字段,实现题目软删除功能 + +3. DTO 修改 + FileUpdateRequest + 新增 tags 字段(Map类型),支持通过更新接口设置文件标签 + +4. Service 层功能增强 + 4.1 QuestionService 新增方法 + 软删除题目相关: + softDeleteByFileId(Long fileId):根据文件ID软删除该文件关联的所有题目 + softDeleteByDocumentName(String documentName):根据文档名软删除所有关联题目 + 实现逻辑: + 查询指定文件/文档名的所有未删除题目 + 将题目的 isDeleted 字段设置为 1 + 更新 updatedAt 时间戳 + 返回实际删除的题目数量 + 4.2 FileService 接口调整 + uploadFile 方法签名变更: + 新增参数 autoVectorize(Boolean类型) + 控制上传后是否自动触发了向量化流程 + 实现逻辑: + autoVectorize = false:仅上传文件,不向量化 + autoVectorize = true:上传后自动触发向量化(需无需审核) + 需要审核的文件无论参数如何都暂不向量化 + +5. Controller 层接口调整 + 5.1 FileController 修改 + 5.1.1 文件上传接口 (POST /file/upload) + 新增参数: + autoVectorize:是否自动向量化(默认 false) + 功能说明: + 用户上传文件到服务器 + 根据 autoVectorize 参数决定是否自动触发了向量化 + 需要审核的文件暂存待审核区,不向量化 + 5.1.2 文件删除接口 (DELETE /file/{id}) + 返回值变更: + 从 Result 改为 Result> + 功能增强: + 改为软删除(标记 status=0,不物理删除) + 自动级联软删除该文件对应的所有题目 + 返回删除的题目数量统计 + 返回数据: + + { + "success": true, + "message": "文件和题目已成功软删除", + "fileId": 123, + "fileName": "document.pdf", + "deletedQuestionCount": 15 + } + + 5.1.3 文件更新接口 (PUT /file/{id}) + 新增功能: + 支持更新文件的 tags 字段 + 用户可自定义存储各种元数据(版本、分类、自定义字段等) + + 5.2 CollectionController 新增接口 + 5.2.1 级联软删除接口 (POST /collection/cascade-delete/{fileId}) + 功能说明: + 软删除指定文件并自动软删除其关联的所有题目 + 与 FileController 的删除接口功能类似,提供统一入口 + 前置条件: + 用户已登录 + 文件存在且未被软删除 + 返回数据:{ + "success": true, + "message": "文件和题目已成功软删除", + "fileId": 123, + "fileName": "document.pdf", + "deletedQuestionCount": 15 + } + + 5.2.2 删除向量化数据接口 (POST /collection/{name}/devectorize?fileId=xxx) + 功能说明: + 删除文件的向量化数据(从 RAG 服务中移除) + 如果存在关联题目,先自动软删除题目 + 清理本地数据库的文档关联记录 + 触发 AI 端同步 + 执行流程: + 验证文件是否存在且有向量化数据 + 调用 questionService.softDeleteByFileId() 软删除关联题目 + 调用 RAG 服务删除向量化文档 + 清空文件的 vectorDbAddress 字段 + 重置文件状态为 PENDING + 删除 collection_file 关联记录 + 触发同步 + 返回数据:{ + "success": true, + "message": "向量化数据已删除", + "fileId": 123, + "fileName": "document.pdf", + "deletedQuestionCount": 10 + } + + 5.2.3 文件生成题目接口 (POST /collection/{name}/generate-exam) + 功能说明: + 对已向量化完成的文件生成考试题目 + 异步执行,立即返回任务提交状态 + 请求参数: + fileId(必填):文件ID + questionTypes(可选):题目类型,逗号分隔,如 "single,multiple",默认 "single" + difficulty(可选):难度等级 1-5,默认 3 + questionCount(可选):题目数量,默认 10 + 前置条件: + 文件必须已完成向量化(vectorDbAddress 不为空) + 执行流程: + 验证文件存在且已完成向量化 + 更新文件状态为 "GENERATING_EXAM" + 异步调用 examService.generateQuestionsWithFileId() + 根据结果更新文件状态和题目生成状态 + 返回数据: + + { + "success": true, + "message": "题目生成任务已提交,正在后台处理中", + "fileId": 123, + "fileName": "document.pdf", + "collection": "public_kb", + "requestId": "EXAM_1234567890_123", + "status": "GENERATING" + } + + 🎯 业务场景支持 + 场景 1:只上传,不向量化 + 适用情况: 临时存储文件,后续再决定是否处理 + 操作流程:POST /file/upload?autoVectorize=false + + 结果: + 文件保存到服务器 + 数据库记录创建 + 不触发了向量化 + + 场景 2:上传并自动向量化 + 适用情况: 标准流程,上传后立即建立向量索引 + 操作流程:POST /file/upload?autoVectorize=true + + 结果: + 文件保存到服务器 + 自动触发了异步向量化 + 向量化完成后自动更新状态 + + 场景 3:手动触发了向量化 + 适用情况: 之前上传时未向量化,现在需要补充 + 操作流程:POST /collection/{name}/vectorize?fileId=123 + + 结果: + 对指定文件进行向量化处理 + 异步执行,返回任务提交状态 + + 场景 4:向量化后生成题目 + 适用情况: 文件已向量化,需要基于内容生成考试题目 + 操作流程:POST /collection/{name}/generate-exam?fileId=123&questionTypes=single,multiple&difficulty=3&questionCount=10 + + 结果: + 异步生成题目 + 题目保存到数据库 + 更新文件出题状态 + + 场景 5:新文件替换旧文件 + 适用情况: 上传新版本文件,需要清理旧文件及其衍生数据 + 操作流程:1. 上传新文件 + + POST /file/upload?autoVectorize=true + + 2. 级联删除旧文件(包括题目) + + POST /collection/cascade-delete/{oldFileId} + + 结果: + 旧文件标记为删除(status=0) + 旧文件关联的所有题目标记为删除(is_deleted=1) + 新文件正常处理 + + 场景 6:删除向量化但保留文件 + 适用情况: 需要重新向量化或不再需要向量检索 + 操作流程:POST /collection/{name}/devectorize?fileId=123 + + 结果: + 先软删除关联题目(避免脏数据) + 从 RAG 服务删除向量化数据 + 清空文件的向量化地址 + 重置文件状态为待处理 + + 场景 7:删除文件及所有关联数据 + 适用情况: 完全移除文件及其所有衍生数据 + 操作流程:DELETE /file/{id} + + 结果: + 文件软删除(status=0) + 关联题目全部软删除(is_deleted=1) + 数据保留在数据库中,可通过恢复操作还原 + + 场景 8:给文件添加自定义标签 + 适用情况: 为文件添加版本、分类等元数据 + 操作流程:PUT /file/{id} + { + "tags": { + "version": "v2", + "category": "important", + "custom_field": "any_value" + } + } + + 结果: + 文件的 tags 字段更新为指定的 JSON 对象 + 支持任意自定义字段 + + 📊 状态流转 + 文件状态 (processStatus) + PENDING:待处理(上传完成但未向量化) + VECTORIZING:正在向量化 + INDEXED:向量化完成 + GENERATING_EXAM:正在生成题目 + EXAM_GENERATED:题目生成成功 + EXAM_FAILED:题目生成失败 + DELETED:已软删除 + 文件步骤状态 (processStepStatus) + UPLOADED:已上传 + VECTORIZING:向量化中 + VECTORIZED:已向量化 + VECTORIZE_FAILED:向量化失败 + DELETED:已删除 + 题目状态 (examStatus in File) + UNGENERATED:未生成题目 + GENERATED:已生成题目 + FAILED:生成失败 + 题目软删除 (isDeleted in Question) + 0:正常 + 1:已删除(软删除) + 文件软删除 (status in File) + 1:正常 + 0:已删除(软删除) + + ⚙️ 技术特性 + 1. 软删除机制 + 文件软删除:标记 status=0,不物理删除文件和数据 + 题目软删除:标记 is_deleted=1,保留历史记录 + 优势:数据可追溯、可恢复、符合审计要求 + + 2. 级联删除 + 删除文件时自动软删除关联题目 + 删除向量化时先软删除题目再清理向量数据 + 保证数据一致性,避免孤儿数据 + + 3. 异步处理 + 向量化操作异步执行,不阻塞接口响应 + 题目生成异步执行,支持大批量处理 + 通过状态字段追踪进度 + + 4. 标签系统 + JSON 格式存储,灵活扩展 + 支持任意自定义字段 + 便于后续筛选和分类 + + 5. 权限控制 + 所有接口都需要用户登录验证 + 文件删除遵循原有权限规则 + 管理员可操作本部门文件 + + 6. 日志记录 + 完整记录关键操作流程 + 包含文件ID、文件名、操作结果等信息 + 便于问题排查和审计 + + 7. 🔄 接口依赖关系 + + 文件上传 (POST /file/upload) + ├─ autoVectorize=false → 仅上传 + └─ autoVectorize=true → 上传 + 自动向量化 + + 向量化 (POST /collection/{name}/vectorize) + └─ 前提:文件已上传且路径有效 + + 批量向量化 (POST /collection/{name}/vectorize/batch) + └─ 前提:所有文件已上传且路径有效 + + 生成题目 (POST /collection/{name}/generate-exam) + └─ 前提:文件已完成向量化 + + 删除向量化 (POST /collection/{name}/devectorize) + ├─ 先软删除关联题目 + ├─ 再删除 RAG 中的向量数据 + └─ 最后清理本地关联记录 + + 级联删除 (POST /collection/cascade-delete/{fileId}) + ├─ 软删除文件 + └─ 软删除关联题目 + + 删除文件 (DELETE /file/{id}) + ├─ 软删除文件 + └─ 软删除关联题目 + + 更新标签 (PUT /file/{id}) + └─ 更新 tags 字段 + + ✅ 测试建议 + 单元测试 + 测试 softDeleteByFileId 方法的正确性 + 测试 softDeleteByDocumentName 方法的正确性 + 测试上传接口不同 autoVectorize 参数的行为 + 集成测试 + 测试完整的上传→向量化→出题流程 + 测试级联删除的数据一致性 + 测试删除向量化后的状态重置 + 测试标签的读写功能 + 边界测试 + 文件不存在时的错误处理 + 重复删除的处理 + 未完成向量化时尝试出题的处理 + 空标签、null 值的处理 + + 📝 注意事项 + 数据库迁移:部署前需执行 SQL 脚本添加新字段 + 兼容性:旧的上传接口调用需要添加 autoVectorize 参数 + 性能考虑:级联删除可能涉及大量题目,注意监控执行时间 + 数据恢复:软删除的数据可通过手动更新状态恢复 + 标签格式:tags 字段为 JSON 格式,前端需注意序列化/反序列化 + + 🚀 后续优化方向 + 增加批量标签更新接口 + 支持按标签筛选文件 + 增加软删除数据的恢复接口 + 增加删除操作的回滚机制 + 优化大批量题目软删除的性能 + + + + \ No newline at end of file diff --git a/docs/题目更新接口文档.md b/docs/题目更新接口文档.md new file mode 100644 index 0000000..24b3f3c --- /dev/null +++ b/docs/题目更新接口文档.md @@ -0,0 +1,387 @@ +# 题目更新接口文档 + +> 对应接口:`PUT /api/question/{id}` +> 功能说明:更新题目信息,支持部分字段更新(只传需要修改的字段即可) +> 接口版本:V1.0 +> 更新日期:2026-06-08 + +--- + +## 目录 + +- [1. 接口定义](#1-接口定义) +- [2. 请求参数](#2-请求参数) +- [3. 请求示例](#3-请求示例) +- [4. 响应说明](#4-响应说明) +- [5. 错误码说明](#5-错误码说明) +- [6. 边界情况说明](#6-边界情况说明) +- [7. curl 测试命令](#7-curl-测试命令) + +--- + +## 1. 接口定义 + +| 项目 | 内容 | +|------|------| +| **请求方法** | `PUT` | +| **接口路径** | `/api/question/{id}` | +| **Content-Type** | `application/json` | +| **认证方式** | Bearer Token (JWT) | +| **基础URL** | `http://localhost:8080`(开发环境) | +| **完整URL示例** | `PUT http://localhost:8080/api/question/378` | + +### 1.1 路径参数说明 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `id` | String | **是** | 题目ID,支持两种格式:
① 自增数字ID(如 `378`)
② UUID格式的 questionId(如 `e6bb2566-90a8-4651-b553-083a1d695b3c`) | + +### 1.2 认证要求 + +需要在请求头中携带 JWT Token: + +``` +Authorization: Bearer +``` + +Token 通过 `/api/auth/login` 接口登录获取。 + +--- + +## 2. 请求参数 + +所有请求字段均为**可选**(部分更新),只传需要修改的字段即可。 + +### 2.1 请求体结构 + +```json +{ + "question_type": "single_choice", + "difficulty": 3, + "content": { + "stem": "题目标题", + "data": {}, + "answer": "A" + }, + "tags": ["数学", "代数"], + "score": 5.00, + "status": "pending", + "reviewer_comment": "审核意见", + "document_id": "uuid-string", + "document_name": "文件名.doc", + "knowledge_base_path": "public/dept_1", + "source_context": "原文上下文内容", + "chunk_ids": ["chunk_001", "chunk_002"], + "source_chunks_used": 3, + "page_numbers": [12, 15] +} +``` + +### 2.2 字段详情 + +| 字段 | 类型 | 必填 | 说明 | 校验规则 | +|------|------|------|------|---------| +| `question_type` | String | 否 | 题目类型 | 必须是以下之一:`single_choice`、`multiple_choice`、`true_false`、`fill_blank`、`subjective` | +| `difficulty` | Integer | 否 | 难度等级 | 1-5 | +| `content` | Object | 否 | 题目内容(JSON对象) | 不能为空的JSON对象 | +| `content.stem` | String | 视题型 | 题干 | 主观题必填 | +| `content.data` | Object | 视题型 | 额外数据(如选择题的选项列表) | - | +| `content.answer` | String | 视题型 | 答案 | 选择题为选项字母,判断题 "T"/"F" | +| `tags` | Array\ | 否 | 知识点标签 | - | +| `score` | BigDecimal | 否 | 分值 | 范围:`-999.99` ~ `999.99`(数据库 decimal(5,2) 约束) | +| `status` | String | 否 | 审核状态 | `pending`、`approved`、`rejected` | +| `reviewer_comment` | String | 否 | 审核评论 | - | +| `document_id` | String | 否 | 关联文档ID | - | +| `document_name` | String | 否 | 文档名称 | - | +| `knowledge_base_path` | String | 否 | 知识库路径 | 最大500字符 | +| `source_context` | String | 否 | 原文上下文 | - | +| `chunk_ids` | Array\ | 否 | 切片ID列表 | - | +| `source_chunks_used` | Integer | 否 | 使用的源切片数量 | - | +| `page_numbers` | Array\ | 否 | 页码列表 | - | + +--- + +## 3. 请求示例 + +### 3.1 修改题型和难度 + +```json +// PUT /api/question/378 +{ + "question_type": "multiple_choice", + "difficulty": 4 +} +``` + +### 3.2 修改题目内容和分值 + +```json +// PUT /api/question/378 +{ + "content": { + "stem": "以下哪项是正确的?", + "data": { + "options": [ + { "label": "A", "text": "选项A" }, + { "label": "B", "text": "选项B" }, + { "label": "C", "text": "选项C" } + ] + }, + "answer": "B" + }, + "score": 10.00 +} +``` + +### 3.3 审核通过题目 + +```json +// PUT /api/question/378 +{ + "status": "approved", + "reviewer_comment": "内容正确,通过审核" +} +``` + +### 3.4 使用 UUID 更新 + +```json +// PUT /api/question/e6bb2566-90a8-4651-b553-083a1d695b3c +{ + "difficulty": 5, + "score": 8.00 +} +``` + +--- + +## 4. 响应说明 + +### 4.1 通用响应格式 + +```json +{ + "code": 200, + "message": "操作成功", + "data": {}, + "timestamp": "2026-06-08 10:00:00", + "success": true +} +``` + +### 4.2 更新成功响应(code=200) + +```json +{ + "code": 200, + "message": "题目更新成功", + "data": { + "id": 378, + "questionId": "41a890f2-c9b9-466f-b9f6-e0bd237329b7", + "questionType": "multiple_choice", + "difficulty": 4, + "tags": null, + "score": 5.00, + "version": "1.0", + "documentId": null, + "excludeStems": null, + "knowledgeBasePath": null, + "sourceContext": null, + "chunkIds": null, + "sourceChunksUsed": 0, + "examCount": 0, + "correctCount": 0, + "lastExamTime": null, + "pageNumbers": null, + "content": { + "stem": "以下哪项是正确的?", + "data": { + "options": [ + { "label": "A", "text": "选项A" }, + { "label": "B", "text": "选项B" } + ] + }, + "answer": "A" + }, + "status": "pending", + "reviewerComment": null, + "createdAt": "2026-06-08 09:00:00", + "updatedAt": "2026-06-08 10:00:00", + "isDeleted": 0 + }, + "timestamp": "2026-06-08 10:00:00", + "success": true +} +``` + +### 4.3 data 字段说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | Long | 自增主键ID | +| `questionId` | String | 题目UUID(全局唯一标识) | +| `questionType` | String | 题目类型 | +| `difficulty` | Integer | 难度等级 1-5 | +| `tags` | JsonNode | 知识点标签(JSON数组或null) | +| `score` | BigDecimal | 分值 | +| `version` | String | 版本号(默认"1.0") | +| `documentId` | String | 关联文档ID | +| `excludeStems` | String | 题干内容(AI去重用) | +| `knowledgeBasePath` | String | 知识库路径 | +| `sourceContext` | String | 原文上下文 | +| `chunkIds` | JsonNode | 切片ID列表 | +| `sourceChunksUsed` | Integer | 使用切片数 | +| `examCount` | Integer | 出题次数 | +| `correctCount` | Integer | 正确次数 | +| `lastExamTime` | DateTime | 最后作答时间 | +| `pageNumbers` | JsonNode | 页码列表 | +| `content` | JsonNode | 题目内容(JSON对象) | +| `status` | String | 审核状态 | +| `reviewerComment` | String | 审核评论 | +| `createdAt` | DateTime | 创建时间 | +| `updatedAt` | DateTime | 最后更新时间 | +| `isDeleted` | Integer | 逻辑删除标志(0=正常,1=已删除) | + +--- + +## 5. 错误码说明 + +### 5.1 业务错误码 + +| HTTP状态码 | code | message | 触发场景 | +|-----------|------|---------|---------| +| **200** | 200 | 题目更新成功 | 更新成功 | +| **404** | 404 | 题目不存在: {id} | 指定ID的题目不存在 | +| **400** | 400 | 分值超出范围,允许范围: -999.99 ~ 999.99 | score 超出 decimal(5,2) 精度范围 | +| **400** | 400 | 知识库路径过长,最大允许500字符 | knowledge_base_path 超过500字符 | +| **400** | 400 | 无效的题目类型: {type} | question_type 不在枚举值内 | +| **400** | 400 | 题目内容不能为空 | content 传了空对象 `{}` | +| **400** | 400 | 题目可能已被删除或归档 | 记录已被逻辑删除,updateById 影响行数为0 | +| **400** | 400 | 题目不存在 | getById 返回 null | + +### 5.2 异常错误码 + +| HTTP状态码 | code | message | 触发场景 | +|-----------|------|---------|---------| +| **500** | 500 | 更新题目失败: {异常信息} | 数据库异常、JSON序列化异常等(Controller 兜底catch) | +| **401** | 401 | 用户未登录 | 未携带 Token 或 Token 无效 | +| **403** | 403 | 无权限访问 | 当前用户无操作权限 | + +--- + +## 6. 边界情况说明 + +### 6.1 ID 格式自动识别 + +接口自动识别传入的 `{id}` 格式: + +- **纯数字**(如 `378`):按自增主键 `id` 查询 +- **非数字**(如 `e6bb2566-...`):按 `question_id`(UUID)查询 +- **非法格式**:抛出 `NumberFormatException`,返回 400 + +### 6.2 部分更新机制 + +接口支持**部分字段更新**(PATCH 语义),请求体中只需包含要修改的字段: + +- 未传的字段保持原值不变 +- 传了 `null` 的字段会被设为 `null` +- `content` 为完整替换,非合并更新 + +### 6.3 防御性校验 + +Service 层对以下输入进行校验: + +| 校验项 | 拦截条件 | 错误信息 | +|--------|---------|---------| +| score 范围 | `score > 999.99 \|\| score < -999.99` | "分值超出范围,允许范围: -999.99 ~ 999.99" | +| 路径长度 | `knowledge_base_path.length > 500` | "知识库路径过长,最大允许500字符" | +| 题型枚举 | `question_type ∉ validTypes` | "无效的题目类型: {type}" | +| 内容非空 | `content != null && content.isEmpty()` | "题目内容不能为空" | +| 存在性检查 | `getById(id) == null` | "题目不存在" | +| 更新影响行数 | `updateById 返回 false` | "题目可能已被删除或归档" | + +### 6.4 逻辑删除 + +- 已逻辑删除的记录(`is_deleted = 1`)仍可通过 `getById` 查到 +- 但 `updateById` 由于 MyBatis-Plus 自动追加 `WHERE is_deleted = 0` 条件,将返回 `false` +- 此时接口会抛出 `IllegalStateException`,返回 400 错误 + +### 6.5 JSON 序列化 + +- 后台使用 `JacksonTypeHandler` 将 `content` 字段序列化为 JSON 存入数据库 +- 使用独立的 `ObjectMapper` 实例(非 Spring 管理的全局配置) +- 避免传入 `NaN`、`Infinity` 等非法 JSON 值,否则可能触发 `JsonProcessingException` + +--- + +## 7. curl 测试命令 + +### 7.1 获取 Token + +```bash +curl -X POST "http://localhost:8080/api/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"123456"}' +``` + +### 7.2 正常更新(数字ID) + +```bash +curl -X PUT "http://localhost:8080/api/question/378" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{ + "question_type": "multiple_choice", + "difficulty": 4, + "score": 5.00, + "content": { + "stem": "更新后的题干", + "data": { + "options": [ + {"label": "A", "text": "选项A"}, + {"label": "B", "text": "选项B"} + ] + }, + "answer": "A" + } + }' +``` + +### 7.3 使用 UUID 更新 + +```bash +curl -X PUT "http://localhost:8080/api/question/e6bb2566-90a8-4651-b553-083a1d695b3c" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{"difficulty": 3}' +``` + +### 7.4 score 超出范围(测试防御性校验) + +```bash +curl -X PUT "http://localhost:8080/api/question/378" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{"score": 1000}' +# 期望响应: {"code": 500, "message": "更新题目失败: 分值超出范围,允许范围: -999.99 ~ 999.99"} +``` + +### 7.5 无效题型(测试防御性校验) + +```bash +curl -X PUT "http://localhost:8080/api/question/378" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{"question_type": "invalid_type"}' +# 期望响应: {"code": 500, "message": "更新题目失败: 无效的题目类型: invalid_type"} +``` + +### 7.6 不存在的题目 + +```bash +curl -X PUT "http://localhost:8080/api/question/99999" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{"difficulty": 3}' +# 期望响应: {"code": 404, "message": "题目不存在: 99999"} +``` diff --git a/git.md b/git.md new file mode 100644 index 0000000..2b4244e --- /dev/null +++ b/git.md @@ -0,0 +1,112 @@ +# 一、你的两个仓库(永久地址) +## 1. 后端(Java) +``` +https://git.njtobobsales.top/guxz/my-springboot-project.git +``` +## 2. 前端(aue) +``` +https://git.njtobobsales.top/guxz/aue.git +``` + +--- + +# 二、最重要铁律(必须记住) +1. **.git 隐藏文件夹 = Git 灵魂 → 不许删、不许发、不许改** +2. **项目文件夹可改名、可移动、可覆盖 → 完全没问题** +3. **哪个文件夹打开 Git Bash,就操作哪个仓库** + +--- + +# 三、通用操作(前后端 100% 一样) +## 第一步 +进入项目文件夹 → 右键 → **Git Bash Here** + +--- + +# 四、日常更新代码(自己修改代码时) +```bash +# 检查远程是否有更新(不会修改本地代码) +git fetch origin +git status +git pull # 多人每次开始写代码前必用 + +git add . # 记录新增/修改 +git add -A # 记录所有新增/修改/删除 +git commit -m "说明" # 提交本地 +git push # 上传到仓库 +git config --global credential.helper manager # 记住密码 +``` + +--- + +# 五、前端专用:接收 ZIP 包覆盖更新(重点) +前端发 ZIP → 解压 → **直接覆盖你本地前端文件夹内所有文件** +执行这 4 行(**可同步删除旧文件**): +```bash +git pull +git add -A # 同步:新增 + 修改 + 删除(关键) +git commit -m "前端新版更新" +git push +``` + +--- + +# 六、查看当前仓库(确认不搞错) +```bash +git remote -v +``` +- 看到 `my-springboot-project` = 后端 +- 看到 `aue` = 前端 + +--- + +# 七、回退版本(后悔药) +```bash +git reset --hard HEAD^ # 回退到上一版 +git push -f # 强制同步远程 +``` + +--- + +# 八、放弃本地所有修改(还原到最新版) +```bash +git reset --hard HEAD +git clean -fd +``` + +--- + +# 九、切换前后端仓库方法 +**关闭当前 Git Bash → 进入另一个项目文件夹 → 重新打开 Git Bash** +自动识别仓库,**不用改网址**。 + +--- + +# 十、你以后终身标准工作流 +1. 改后端 → 进后端文件夹开 Bash +2. 改前端 → 进前端文件夹开 Bash +3. 开始写代码 → `git pull` +4. 写完代码 → `git add .` / 前端覆盖用 `git add -A` +5. 提交 → `git commit -m "说明"` +6. 上传 → `git push` + +--- + +# 🎯 最简万能命令(前后端通用) +## 自己改代码 +```bash +git pull +git add . +git commit -m "更新" +git push +``` + +## 前端发 ZIP 覆盖 +```bash +git pull +git add -A +git commit -m "前端更新" +git push +``` + +--- diff --git a/src/main/java/top/tqx/demo_1/config/AiApiConfig.java b/src/main/java/top/tqx/demo_1/config/AiApiConfig.java index ea00a5f..a270d51 100644 --- a/src/main/java/top/tqx/demo_1/config/AiApiConfig.java +++ b/src/main/java/top/tqx/demo_1/config/AiApiConfig.java @@ -46,6 +46,7 @@ public class AiApiConfig { private String list = "/documents/list"; private String delete = "/documents"; private String chunks = "/documents/{path}/chunks"; + private String preview = "/documents/{path}/preview"; private String deprecate = "/collections/{name}/documents/{filename}/deprecate"; private String restore = "/collections/{name}/documents/{filename}/restore"; private String versions = "/collections/{name}/documents/{filename}/versions"; diff --git a/src/main/java/top/tqx/demo_1/controller/AIChatController.java b/src/main/java/top/tqx/demo_1/controller/AIChatController.java index 3ae3054..98a7a53 100644 --- a/src/main/java/top/tqx/demo_1/controller/AIChatController.java +++ b/src/main/java/top/tqx/demo_1/controller/AIChatController.java @@ -205,14 +205,12 @@ public class AIChatController { @Parameter(description = "页码,默认1") @RequestParam(defaultValue = "1") Integer page, @Parameter(description = "每页大小,默认20") @RequestParam(defaultValue = "20") Integer pageSize, HttpServletRequest httpRequest) { - log.info("📨 收到获取会话详情请求,sessionId={}", sessionId); Map result = new HashMap<>(); try { Long userId = getCurrentUserId(httpRequest); if (userId == null) { result.put("success", false); result.put("message", "用户未登录"); - log.warn("用户未登录,拒绝访问"); return result; } @@ -223,21 +221,10 @@ public class AIChatController { if (!isSessionBelongsToUser) { result.put("success", false); result.put("message", "无权访问该会话"); - log.warn("用户 {} 无权访问会话 {}", userId, sessionId); return result; } List messages = chatService.getSessionMessages(sessionId); - log.info("获取到 {} 条消息", messages.size()); - - // 打印第一条消息的详细信息用于调试 - if (!messages.isEmpty()) { - ChatMessage firstMessage = messages.get(0); - log.info("第一条消息,id={}, role={}, images={}", - firstMessage.getId(), firstMessage.getRole(), - firstMessage.getImages() != null ? firstMessage.getImages().substring(0, Math.min(200, firstMessage.getImages().length())) : "null"); - } - // 实现简单分页 int total = messages.size(); int start = (page - 1) * pageSize; @@ -253,10 +240,8 @@ public class AIChatController { result.put("page", page); result.put("pageSize", pageSize); result.put("pages", (total + pageSize - 1) / pageSize); - - log.info("✅ 返回会话详情成功,共 {} 条消息", pageData.size()); } catch (Exception e) { - log.error("❌ 获取会话详情失败", e); + log.error("获取会话详情失败", e); result.put("success", false); result.put("message", "获取会话详情失败: " + e.getMessage()); } diff --git a/src/main/java/top/tqx/demo_1/controller/CollectionController.java b/src/main/java/top/tqx/demo_1/controller/CollectionController.java index 8f3a276..3ac6919 100644 --- a/src/main/java/top/tqx/demo_1/controller/CollectionController.java +++ b/src/main/java/top/tqx/demo_1/controller/CollectionController.java @@ -1,5 +1,6 @@ package top.tqx.demo_1.controller; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -14,6 +15,7 @@ import top.tqx.demo_1.entity.CollectionFile; import top.tqx.demo_1.entity.Department; import top.tqx.demo_1.entity.File; import top.tqx.demo_1.entity.KnowledgeBasePath; +import top.tqx.demo_1.enums.FileProcessStepStatus; import top.tqx.demo_1.mapper.DepartmentMapper; import top.tqx.demo_1.mapper.FileMapper; import top.tqx.demo_1.mapper.KnowledgeBasePathMapper; @@ -25,6 +27,8 @@ import top.tqx.demo_1.common.Result; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -385,6 +389,8 @@ public class CollectionController extends BaseController { } } + // ... existing code ... + @Operation(summary = "文件向量化", description = "将已上传的文件解析并存储到向量库") @PostMapping("/{name}/vectorize") public Result> vectorizeFile( @@ -441,10 +447,67 @@ public class CollectionController extends BaseController { } } - @Operation(summary = "批量文件向量化", description = "批量将已上传的文件解析并存储到向量库") - @PostMapping("/{name}/vectorize/batch") - public Result> batchVectorizeFiles( - @Parameter(description = "向量库名称", required = true) @PathVariable String name, + @Operation(summary = "智能文件向量化", description = "自动判断部门向量库并执行向量化,无需指定向量库名称") + @PostMapping("/vectorize/smart") + public Result> smartVectorizeFile( + @Parameter(description = "文件ID", required = true) @RequestParam Long fileId, + HttpServletRequest request) { + try { + Long userId = getCurrentUserId(request); + if (userId == null) { + return error("用户未登录"); + } + + log.info("触发智能文件向量化: fileId={}, userId={}", fileId, userId); + + File file = fileMapper.selectById(fileId); + if (file == null) { + log.warn("文件不存在: fileId={}", fileId); + return error("文件不存在"); + } + + String filePath = file.getFilePath(); + if (filePath == null || filePath.isEmpty()) { + log.warn("文件路径为空: fileId={}", fileId); + return error("文件路径为空,请先上传文件"); + } + + Path path = Paths.get(uploadPath, filePath).normalize(); + if (!Files.exists(path)) { + log.warn("文件不存在于路径: fullPath={}", path.toAbsolutePath()); + return error("文件不存在于服务器: " + filePath); + } + + String collectionName = determineCollectionForFile(file); + log.info("自动确定向量库名称: fileId={}, collection={}", fileId, collectionName); + + asyncVectorizeService.updateFileProcessStatus(fileId, + AsyncVectorizeService.VECTORIZE_STATUS_VECTORIZING, + "正在向量化,请稍后..."); + + asyncVectorizeService.vectorizeFileAsync(collectionName, fileId, userId); + + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "向量化任务已提交,正在后台处理中"); + result.put("fileId", fileId); + result.put("fileName", file.getFileName()); + result.put("collection", collectionName); + result.put("status", AsyncVectorizeService.VECTORIZE_STATUS_VECTORIZING); + + log.info("智能文件向量化任务已提交: collection={}, fileId={}, fileName={}", + collectionName, fileId, file.getFileName()); + + return success(result); + } catch (Exception e) { + log.error("触发智能文件向量化失败: fileId={}", fileId, e); + return error("触发智能文件向量化失败: " + e.getMessage()); + } + } + + @Operation(summary = "批量智能文件向量化", description = "批量自动判断部门向量库并执行向量化") + @PostMapping("/vectorize/batch/smart") + public Result> batchSmartVectorizeFiles( @Parameter(description = "文件ID列表", required = true) @RequestParam List fileIds, HttpServletRequest request) { try { @@ -453,7 +516,7 @@ public class CollectionController extends BaseController { return error("用户未登录"); } - log.info("触发批量文件向量化: collection={}, fileIds={}, userId={}", name, fileIds, userId); + log.info("触发批量智能文件向量化: fileIds={}, userId={}", fileIds, userId); List> submittedFiles = new ArrayList<>(); List> failedFiles = new ArrayList<>(); @@ -488,25 +551,27 @@ public class CollectionController extends BaseController { continue; } + String collectionName = determineCollectionForFile(file); + log.info("自动确定向量库名称: fileId={}, collection={}", fileId, collectionName); + asyncVectorizeService.updateFileProcessStatus(fileId, AsyncVectorizeService.VECTORIZE_STATUS_VECTORIZING, String.format("正在向量化,请稍后...(批次ID: %s)", batchId)); - asyncVectorizeService.batchVectorizeFilesAsync(name, fileId, userId, batchId); + asyncVectorizeService.batchVectorizeFilesAsync(collectionName, fileId, userId, batchId); Map submitted = new HashMap<>(); submitted.put("fileId", fileId); submitted.put("fileName", file.getFileName()); - submitted.put("collection", name); - submitted.put("status", AsyncVectorizeService.VECTORIZE_STATUS_VECTORIZING); - submitted.put("batchId", batchId); + submitted.put("collection", collectionName); + submitted.put("status", "SUBMITTED"); submittedFiles.add(submitted); - log.info("批量向量化任务已提交: collection={}, fileId={}, fileName={}, batchId={}", - name, fileId, file.getFileName(), batchId); + log.info("文件向量化任务已提交: fileId={}, fileName={}, collection={}, batchId={}", + fileId, file.getFileName(), collectionName, batchId); } catch (Exception e) { - log.error("提交文件向量化失败: fileId={}", fileId, e); + log.error("提交文件向量化任务失败: fileId={}", fileId, e); Map failed = new HashMap<>(); failed.put("fileId", fileId); failed.put("error", e.getMessage()); @@ -516,7 +581,8 @@ public class CollectionController extends BaseController { Map result = new HashMap<>(); result.put("success", true); - result.put("collection", name); + result.put("message", String.format("批量向量化任务已提交: 提交 %d 个, 无效 %d 个", + submittedFiles.size(), failedFiles.size())); result.put("batchId", batchId); result.put("submittedFiles", submittedFiles); result.put("failedFiles", failedFiles); @@ -530,11 +596,310 @@ public class CollectionController extends BaseController { return success(result); } catch (Exception e) { - log.error("触发批量文件向量化失败: collection={}", name, e); - return error("触发批量文件向量化失败: " + e.getMessage()); + log.error("触发批量智能文件向量化失败", e); + return error("触发批量智能文件向量化失败: " + e.getMessage()); } } +// ... existing code ... + + private String determineCollectionForFile(File file) { + try { + Integer userType = 3; + Long deptId = file.getDeptId(); + Boolean isPublic = file.getIsPublic() != null && file.getIsPublic() == 1; + + if (deptId != null) { + String deptName = getDepartmentName(deptId); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(KnowledgeBasePath::getDepartment, deptName) + .or() + .eq(KnowledgeBasePath::getName, "dept_" + deptId + "_kb") + .last("LIMIT 1"); + KnowledgeBasePath kb = knowledgeBasePathMapper.selectOne(wrapper); + if (kb != null) { + log.info("找到现有向量库: collection={}, department={}", kb.getName(), deptName); + return kb.getName(); + } + + String newCollectionName = "dept_" + deptId + "_kb"; + log.info("未找到向量库,将自动创建: collection={}, department={}", newCollectionName, deptName); + return newCollectionName; + } else { + String collectionName = isPublic ? "public_kb" : "private_kb"; + log.info("无部门信息,使用默认向量库: collection={}", collectionName); + return collectionName; + } + } catch (Exception e) { + log.error("确定向量库名称失败,使用默认值", e); + return "public_kb"; + } + } + + @Resource + private top.tqx.demo_1.service.ExamService examService; + + @Resource + private top.tqx.demo_1.service.QuestionService questionService; + + @Operation(summary = "文件生成题目", description = "对已向量化完成的文件生成考试题目") + @PostMapping("/{name}/generate-exam") + public Result> generateExamFromFile( + @Parameter(description = "向量库名称", required = true) @PathVariable String name, + @Parameter(description = "文件ID", required = true) @RequestParam Long fileId, + @Parameter(description = "题目类型(逗号分隔)", example = "single,multiple") @RequestParam(required = false) String questionTypes, + @Parameter(description = "难度等级(1-5)", example = "3") @RequestParam(required = false) Integer difficulty, + @Parameter(description = "题目数量", example = "10") @RequestParam(required = false) Integer questionCount, + HttpServletRequest request) { + try { + Long userId = getCurrentUserId(request); + if (userId == null) { + return error("用户未登录"); + } + + log.info("触发文件生成题目: collection={}, fileId={}, userId={}", name, fileId, userId); + + File file = fileMapper.selectById(fileId); + if (file == null) { + log.warn("文件不存在: fileId={}", fileId); + return error("文件不存在"); + } + + if (file.getVectorDbAddress() == null || file.getVectorDbAddress().isEmpty()) { + log.warn("文件未完成向量化,无法生成题目: fileId={}", fileId); + return error("文件未完成向量化,请先进行向量化处理"); + } + + if (questionTypes == null || questionTypes.isEmpty()) { + questionTypes = "single"; + } + + if (difficulty == null) { + difficulty = 3; + } + + if (questionCount == null) { + questionCount = 10; + } + + top.tqx.demo_1.dto.ExamGenerateRequest examRequest = new top.tqx.demo_1.dto.ExamGenerateRequest(); + examRequest.setFileId(fileId); + examRequest.setQuestionTypes(questionTypes); + examRequest.setDifficulty(difficulty); + examRequest.setQuestionCount(questionCount); + examRequest.setRequestId("EXAM_" + System.currentTimeMillis() + "_" + fileId); + + asyncVectorizeService.updateFileProcessStatus(fileId, + "GENERATING_EXAM", + "正在生成题目,请稍后..."); + + java.util.concurrent.CompletableFuture.runAsync(() -> { + try { + log.info("开始异步生成题目: fileId={}, requestId={}", fileId, examRequest.getRequestId()); + Map result = examService.generateQuestionsWithFileId(examRequest); + + asyncVectorizeService.updateFileProcessStatus(fileId, + "EXAM_GENERATED", + "题目生成成功"); + + file.setExamStatus("GENERATED"); + fileMapper.updateById(file); + + log.info("题目生成成功: fileId={}, result={}", fileId, result); + } catch (Exception e) { + log.error("题目生成失败: fileId={}", fileId, e); + asyncVectorizeService.updateFileProcessStatus(fileId, + "EXAM_FAILED", + "题目生成失败: " + e.getMessage()); + + file.setExamStatus("FAILED"); + file.setProcessMessage("题目生成失败: " + e.getMessage()); + fileMapper.updateById(file); + } + }); + + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "题目生成任务已提交,正在后台处理中"); + result.put("fileId", fileId); + result.put("fileName", file.getFileName()); + result.put("collection", name); + result.put("requestId", examRequest.getRequestId()); + result.put("status", "GENERATING"); + + log.info("文件题目生成任务已提交: collection={}, fileId={}, fileName={}, requestId={}", + name, fileId, file.getFileName(), examRequest.getRequestId()); + + return success(result); + } catch (Exception e) { + log.error("触发文件生成题目失败: collection={}, fileId={}", name, fileId, e); + return error("触发文件生成题目失败: " + e.getMessage()); + } + } + + @Operation(summary = "级联软删除文件及题目", description = "软删除文件并自动软删除该文件对应的所有题目") + @PostMapping("/cascade-delete/{fileId}") + public Result> cascadeSoftDeleteFile( + @Parameter(description = "文件ID", required = true) @PathVariable Long fileId, + HttpServletRequest request) { + try { + Long userId = getCurrentUserId(request); + if (userId == null) { + return error("用户未登录"); + } + + log.info("开始级联软删除: fileId={}, userId={}", fileId, userId); + + File file = fileMapper.selectById(fileId); + if (file == null) { + log.warn("文件不存在: fileId={}", fileId); + return error("文件不存在"); + } + + if (file.getStatus() != null && file.getStatus() == 0) { + log.warn("文件已被软删除: fileId={}", fileId); + return error("文件已被软删除"); + } + + String documentName = file.getFileName(); + + int deletedQuestionCount = questionService.softDeleteByFileId(fileId); + log.info("题目软删除完成: fileId={}, documentName={}, 删除数量={}", + fileId, documentName, deletedQuestionCount); + + file.setStatus(0); + file.setUpdateTime(LocalDateTime.now()); + file.setProcessStatus("DELETED"); + file.setProcessStepStatus("DELETED"); + file.setProcessStepMessage("文件已软删除"); + fileMapper.updateById(file); + + log.info("文件软删除完成: fileId={}, fileName={}", fileId, documentName); + + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "文件和题目已成功软删除"); + result.put("fileId", fileId); + result.put("fileName", documentName); + result.put("deletedQuestionCount", deletedQuestionCount); + + return success(result); + } catch (Exception e) { + log.error("级联软删除失败: fileId={}", fileId, e); + return error("级联软删除失败: " + e.getMessage()); + } + } + + @Operation(summary = "删除文件向量化数据", description = "删除文件的向量化数据,如果存在关联题目则先软删除题目") + @PostMapping("/{name}/devectorize") + public Result> devectorizeFile( + @Parameter(description = "向量库名称", required = true) @PathVariable String name, + @Parameter(description = "文件ID", required = true) @RequestParam Long fileId, + @Parameter(description = "是否保留历史题目(默认false)") @RequestParam(required = false, defaultValue = "false") Boolean keepHistory, + HttpServletRequest request) { + try { + Long userId = getCurrentUserId(request); + if (userId == null) { + return error("用户未登录"); + } + + log.info("开始删除文件向量化数据: collection={}, fileId={}, userId={}, keepHistory={}", + name, fileId, userId, keepHistory); + + File file = fileMapper.selectById(fileId); + if (file == null) { + log.warn("文件不存在: fileId={}", fileId); + return error("文件不存在"); + } + + if (file.getVectorDbAddress() == null || file.getVectorDbAddress().isEmpty()) { + log.warn("文件没有向量化数据: fileId={}", fileId); + return error("文件没有向量化数据"); + } + + int deletedQuestionCount = 0; + if (Boolean.FALSE.equals(keepHistory)) { + deletedQuestionCount = questionService.softDeleteByFileId(fileId); + if (deletedQuestionCount > 0) { + log.info("检测到关联题目,已软删除并标记为已废止: fileId={}, 删除数量={}", fileId, deletedQuestionCount); + } + } else { + log.info("保留历史题目,仅删除向量化数据: fileId={}", fileId); + } + + String vectorDbAddress = file.getVectorDbAddress(); + deleteDocumentFromRAG(vectorDbAddress); + log.info("已删除RAG服务中的向量化数据: fileId={}, vectorDbAddress={}", fileId, vectorDbAddress); + + file.setVectorDbAddress(null); + file.setProcessStatus("PENDING"); + file.setProcessStepStatus(FileProcessStepStatus.UPLOADED.getCode()); + file.setProcessStepMessage(FileProcessStepStatus.UPLOADED.getDescription()); + file.setUpdateTime(LocalDateTime.now()); + fileMapper.updateById(file); + + CollectionFile cf = collectionFileService.findByFileId(fileId); + if (cf != null) { + collectionFileService.delete(cf.getId()); + log.info("已删除本地数据库文档关联: fileId={}", fileId); + } + + triggerSync(); + + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "向量化数据已删除"); + result.put("fileId", fileId); + result.put("fileName", file.getFileName()); + result.put("deletedQuestionCount", deletedQuestionCount); + result.put("keepHistory", keepHistory); + + log.info("文件向量化数据删除完成: collection={}, fileId={}, fileName={}, keepHistory={}", + name, fileId, file.getFileName(), keepHistory); + + return success(result); + } catch (Exception e) { + log.error("删除文件向量化数据失败: collection={}, fileId={}", name, fileId, e); + return error("删除文件向量化数据失败: " + e.getMessage()); + } + } + + + private void deleteDocumentFromRAG(String vectorDbAddress) { + try { + if (vectorDbAddress == null || vectorDbAddress.isEmpty()) { + return; + } + + String[] parts = vectorDbAddress.split("/"); + if (parts.length < 2) { + log.warn("无效的vectorDbAddress格式: {}", vectorDbAddress); + return; + } + + String collection = parts[parts.length - 2]; + String filename = parts[parts.length - 1]; + + String url = aiApiConfig.getFullUrl(aiApiConfig.getDocument().getDelete()); + String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8); + url = url + "/" + collection + "/" + encodedFilename; + log.info("调用RAG服务删除文档: {}", url); + + ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class); + + if (!response.getStatusCode().is2xxSuccessful()) { + log.warn("删除RAG文档失败: status={}, body={}", response.getStatusCode(), response.getBody()); + } else { + log.info("RAG文档删除成功: collection={}, filename={}", collection, filename); + } + } catch (Exception e) { + log.error("删除RAG文档异常: vectorDbAddress={}", vectorDbAddress, e); + } + } + + + @Operation(summary = "获取文档列表", description = "从本地数据库获取指定向量库中的文档列表") @GetMapping("/{name}/documents") public Result>> getDocuments( @@ -584,7 +949,8 @@ public class CollectionController extends BaseController { } String url = aiApiConfig.getFullUrl(aiApiConfig.getDocument().getDelete()); - url = url + "/" + name + "/" + filename; + String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8); + url = url + "/" + name + "/" + encodedFilename; log.info("调用RAG服务删除文档: {}", url); ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class); @@ -611,6 +977,20 @@ public class CollectionController extends BaseController { log.info("本地数据库文档关联已删除: collection={}, filename={}, fileId={}", name, filename, cf.getFileId()); } + // ===== 新增:软删除关联题目 ===== + Long targetFileId = fileId; + if (targetFileId == null && cf != null) { + targetFileId = cf.getFileId(); + } + if (targetFileId != null) { + try { + int deletedQuestionCount = questionService.softDeleteByFileId(targetFileId); + log.info("题目软删除完成: fileId={}, 删除数量={}", targetFileId, deletedQuestionCount); + } catch (Exception e) { + log.error("软删除关联题目失败: fileId={}", targetFileId, e); + } + } + log.info("删除文档成功: collection={}, filename={}, fileId={}, userId={}", name, filename, fileId, userId); triggerSync(); diff --git a/src/main/java/top/tqx/demo_1/controller/ExamController.java b/src/main/java/top/tqx/demo_1/controller/ExamController.java index 535596f..5943897 100644 --- a/src/main/java/top/tqx/demo_1/controller/ExamController.java +++ b/src/main/java/top/tqx/demo_1/controller/ExamController.java @@ -16,9 +16,9 @@ import top.tqx.demo_1.dto.*; import top.tqx.demo_1.entity.Question; import top.tqx.demo_1.entity.UserAnswer; import top.tqx.demo_1.enums.AnswerType; +import top.tqx.demo_1.mapper.QuestionMapper; import top.tqx.demo_1.service.AuthService; import top.tqx.demo_1.service.AsyncExamService; -import top.tqx.demo_1.service.ExamPaperService; import top.tqx.demo_1.service.ExamService; import top.tqx.demo_1.service.ExamRecordService; import top.tqx.demo_1.service.UserAnswerService; @@ -43,9 +43,6 @@ public class ExamController extends BaseController { @Autowired private ExamService examService; - @Autowired - private ExamPaperService examPaperService; - @Autowired private AuthService authService; @@ -61,21 +58,8 @@ public class ExamController extends BaseController { @Autowired private AsyncExamService asyncExamService; - @Operation(summary = "获取试卷详情", description = "通过试卷ID获取试卷详情") - @GetMapping("/paper/{paperId}") - public Result getPaperById( - @PathVariable String paperId) { - try { - ExamPaperResponse response = examPaperService.getPaperById(paperId); - if (response == null) { - return Result.error(404, "试卷不存在"); - } - return Result.success(response); - } catch (Exception e) { - log.error("获取试卷详情失败: {}", e.getMessage()); - return Result.error(500, e.getMessage()); - } - } + @Autowired + private QuestionMapper questionMapper; @Operation(summary = "开始考试(获取题目)", description = "通过试卷ID开始模拟考试,同时返回试卷题目内容") @PostMapping("/paper/{paperId}/start") @@ -183,15 +167,79 @@ public class ExamController extends BaseController { request.setRequestId(UUID.randomUUID().toString()); } + // 校验总题数上限(≤20) + if (request.getQuestionTypes() instanceof Map) { + @SuppressWarnings("unchecked") + Map questionTypes = (Map) request.getQuestionTypes(); + int totalQuestions = questionTypes.values().stream().mapToInt(Integer::intValue).sum(); + if (totalQuestions > 20) { + feedback.put("errorType", "VALIDATION_ERROR"); + feedback.put("errorDetail", "总题数不能超过20道"); + feedback.put("suggestion", "请减少题目数量,每种题型数量之和不能超过20"); + return Result.error(400, "参数验证失败", feedback); + } + } + + // 查询该文件已有的题目题干,用于去重 + if (request.getFileId() != null) { + String documentId = request.getFileId().toString(); + log.info("查询已有题目题干,documentId={}", documentId); + List existingStems = questionMapper.selectStemsByDocumentId(documentId); + if (existingStems != null && !existingStems.isEmpty()) { + request.setExcludeStems(existingStems); + log.info("已查询到该文件已有 {} 道题目,将用于去重", existingStems.size()); + } else { + log.warn("未查询到该文件的已有题目,documentId={}, existingStems={}", documentId, + existingStems == null ? "null" : "empty list"); + } + } + log.info("========== 生成题目请求开始 =========="); - log.info("请求参数: userId={}, requestId={}, fileId={}, filePath={}, questionTypes={}, difficulty={}", + log.info("请求参数: userId={}, requestId={}, fileId={}, filePath={}, questionTypes={}, difficulty={}, excludeStemsCount={}", userId, request.getRequestId(), request.getFileId(), request.getFilePath(), - request.getQuestionTypes(), request.getDifficulty()); + request.getQuestionTypes(), request.getDifficulty(), + request.getExcludeStems() != null ? request.getExcludeStems().size() : 0); try { Map result = examService.generateQuestionsWithFileId(request); feedback.putAll(result); + + // 判断文件匹配状态,只有 success 才启动异步生成任务 + Object fileMatchStatus = result.get("fileMatchStatus"); + if (fileMatchStatus == null || !"success".equals(fileMatchStatus.toString())) { + feedback.put("status", "error"); + feedback.put("errorType", "FILE_VALIDATION_ERROR"); + feedback.put("errorDetail", result.get("message") != null ? result.get("message").toString() : "文件验证失败"); + feedback.put("suggestion", "请检查 file_id 是否正确、文件是否已删除、或文件是否已完成向量化"); + + // 映射不同失败原因到不同的提示/状态码 + String status = fileMatchStatus != null ? fileMatchStatus.toString() : "UNKNOWN"; + int httpCode = "INTERNAL_ERROR".equals(status) ? 500 : 400; + String userMsg; + switch (status) { + case "FILE_NOT_FOUND": + userMsg = "文件不存在,请确认 file_id 是否正确"; + break; + case "FILE_DELETED": + userMsg = "文件已被删除,无法生成题目"; + break; + case "NOT_VECTORIZED": + userMsg = "文件尚未完成向量化,请等待文件处理完成后再试"; + break; + case "PARAM_MISSING": + userMsg = "参数不完整:file_id 与 file_path 不能同时为空"; + break; + case "INTERNAL_ERROR": + userMsg = "服务器内部错误"; + break; + default: + userMsg = "文件验证失败"; + } + log.error("生成题目文件验证失败: fileMatchStatus={}, detail={}", status, feedback.get("errorDetail")); + return Result.error(httpCode, userMsg, feedback); + } + feedback.put("status", "success"); feedback.put("message", "收到请求,正在生成题目"); @@ -311,9 +359,9 @@ public class ExamController extends BaseController { log.error("第{}个答案缺少questionType, questionId={}", i+1, answer.getQuestionId()); return Result.error(400, String.format("第%d个答案的questionType不能为空 (questionId: %s)", i+1, answer.getQuestionId())); } - if (answer.getQuestionContent() == null) { - log.error("第{}个答案缺少questionContent, questionId={}", i+1, answer.getQuestionId()); - return Result.error(400, String.format("第%d个答案的questionContent不能为空 (questionId: %s)", i+1, answer.getQuestionId())); + if (answer.getContent() == null) { + log.error("第{}个答案缺少content, questionId={}", i+1, answer.getQuestionId()); + return Result.error(400, String.format("第%d个答案的content不能为空 (questionId: %s)", i+1, answer.getQuestionId())); } if (answer.getMaxScore() == null) { log.error("第{}个答案缺少maxScore, questionId={}", i+1, answer.getQuestionId()); diff --git a/src/main/java/top/tqx/demo_1/controller/FileController.java b/src/main/java/top/tqx/demo_1/controller/FileController.java index 3081fd1..cde146a 100644 --- a/src/main/java/top/tqx/demo_1/controller/FileController.java +++ b/src/main/java/top/tqx/demo_1/controller/FileController.java @@ -11,21 +11,26 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import top.tqx.demo_1.annotation.RateLimit; import top.tqx.demo_1.common.PageResult; import top.tqx.demo_1.common.Result; +import top.tqx.demo_1.config.AiApiConfig; import top.tqx.demo_1.dto.FileUpdateRequest; import top.tqx.demo_1.dto.RagRequest; +import top.tqx.demo_1.entity.CollectionFile; import top.tqx.demo_1.entity.Department; import top.tqx.demo_1.entity.User; import top.tqx.demo_1.mapper.UserMapper; import top.tqx.demo_1.service.AiChatService; +import top.tqx.demo_1.service.CollectionFileService; import top.tqx.demo_1.service.DepartmentService; import top.tqx.demo_1.service.FileService; import top.tqx.demo_1.util.FileUtil; @@ -38,7 +43,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Tag(name = "文件管理", description = "文件的上传、下载、删除等操作") @RestController @@ -57,6 +64,18 @@ public class FileController extends BaseController { @Autowired private UserMapper userMapper; + + @Autowired + private top.tqx.demo_1.service.QuestionService questionService; + + @Autowired + private AiApiConfig aiApiConfig; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private CollectionFileService collectionFileService; @org.springframework.beans.factory.annotation.Value("${file.upload.path:./uploads/}") private String uploadPath; @@ -103,6 +122,7 @@ public class FileController extends BaseController { @Parameter(description = "部门ID(管理员上传制度文件时指定)") @RequestParam(required = false) Long deptId, @Parameter(description = "是否公开", example = "true") @RequestParam(required = false, defaultValue = "true") Boolean isPublic, @Parameter(description = "文件描述") @RequestParam(required = false) String description, + @Parameter(description = "是否自动向量化", example = "false") @RequestParam(required = false, defaultValue = "false") Boolean autoVectorize, HttpServletRequest request) { try { FileUtil.validateFile(file); @@ -117,7 +137,7 @@ public class FileController extends BaseController { return error("用户信息获取失败"); } - FileVO fileVO = fileService.uploadFile(file, userId, user.getDeptId(), user.getUserType(), deptId, isPublic); + FileVO fileVO = fileService.uploadFile(file, userId, user.getDeptId(), user.getUserType(), deptId, isPublic, autoVectorize); if (description != null && !description.isEmpty()) { fileService.updateFileDescription(fileVO.getId(), description); @@ -443,39 +463,107 @@ public class FileController extends BaseController { ".css".equals(extension); } - @Operation(summary = "删除文件", description = "根据ID删除文件") + @Operation(summary = "删除文件", description = "软删除文件,同时级联软删除该文件对应的所有题目") @DeleteMapping("/{id}") - public Result deleteFile(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) { - Long userId = getCurrentUserId(request); - if (userId == null) { - return error("用户未登录"); + public Result> deleteFile(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) { + try { + Long userId = getCurrentUserId(request); + if (userId == null) { + return error("用户未登录"); + } + + User user = authService.validateToken(request.getHeader("Authorization").substring(7)); + if (user == null) { + return error("用户信息获取失败"); + } + + top.tqx.demo_1.entity.File file = fileService.getFileEntityById(id); + if (file == null) { + return error("文件不存在"); + } + + if (file.getStatus() != null && file.getStatus() == 0) { + return error("文件已被软删除"); + } + + boolean canDelete = false; + if (user.getUserType() == 1) { + canDelete = true; + } else if (user.getUserType() == 2 && file.getDeptId().equals(user.getDeptId())) { + canDelete = true; + } else if (file.getUploadUserId().equals(userId)) { + canDelete = true; + } + + if (!canDelete) { + return error("无权限删除此文件"); + } + + // ===== 步骤1:从RAG向量库删除文档(去向量化) ===== + String vectorDbAddress = file.getVectorDbAddress(); + if (vectorDbAddress != null && !vectorDbAddress.isEmpty()) { + try { + String[] parts = vectorDbAddress.split("/"); + if (parts.length >= 2) { + String collectionName = parts[0]; + String filename = parts[1]; + + String url = aiApiConfig.getFullUrl(aiApiConfig.getDocument().getDelete()); + url = url + "/" + collectionName + "/" + filename + "?fileId=" + id; + + log.info("调用RAG服务删除文档: collection={}, filename={}, fileId={}", collectionName, filename, id); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class); + + if (response.getStatusCode().is2xxSuccessful()) { + log.info("向量库文档删除成功: collection={}, filename={}", collectionName, filename); + } else { + log.warn("向量库文档删除失败: status={}", response.getStatusCode()); + } + } + } catch (Exception e) { + log.error("删除向量库文档失败: fileId={}, vectorDbAddress={}", id, vectorDbAddress, e); + } + } + + // ===== 步骤2:删除 collection_file 关联记录 ===== + try { + CollectionFile cf = collectionFileService.findByFileId(id); + if (cf != null) { + collectionFileService.delete(cf.getId()); + log.info("已删除本地数据库文档关联: fileId={}, collectionName={}", id, cf.getCollectionName()); + } + } catch (Exception e) { + log.error("删除collection_file关联失败: fileId={}", id, e); + } + + // ===== 步骤3:软删除关联题目 ===== + int deletedQuestionCount = questionService.softDeleteByFileId(id); + log.info("题目软删除完成: fileId={}, documentName={}, 删除数量={}", + id, file.getFileName(), deletedQuestionCount); + + // ===== 步骤4:软删除文件 ===== + file.setStatus(0); + file.setVectorDbAddress(null); + file.setUpdateTime(LocalDateTime.now()); + file.setProcessStatus("DELETED"); + file.setProcessStepStatus("DELETED"); + file.setProcessStepMessage("文件已软删除"); + fileService.updateFileEntity(file); + + log.info("文件软删除完成: fileId={}, fileName={}", id, file.getFileName()); + + Map result = new HashMap<>(); + result.put("success", true); + result.put("message", "文件和题目已成功软删除,向量库数据已清理"); + result.put("fileId", id); + result.put("fileName", file.getFileName()); + result.put("deletedQuestionCount", deletedQuestionCount); + + return success(result); + } catch (Exception e) { + log.error("文件软删除失败: fileId={}", id, e); + return error("文件软删除失败: " + e.getMessage()); } - - User user = authService.validateToken(request.getHeader("Authorization").substring(7)); - if (user == null) { - return error("用户信息获取失败"); - } - - top.tqx.demo_1.entity.File file = fileService.getFileEntityById(id); - if (file == null) { - return error("文件不存在"); - } - - boolean canDelete = false; - if (user.getUserType() == 1) { - canDelete = true; - } else if (user.getUserType() == 2 && file.getDeptId().equals(user.getDeptId())) { - canDelete = true; - } else if (file.getUploadUserId().equals(userId)) { - canDelete = true; - } - - if (!canDelete) { - return error("无权限删除此文件"); - } - - fileService.deleteFile(id); - return success(); } @Operation(summary = "审核通过文件", description = "管理员审核通过用户上传的公开文件") @@ -615,6 +703,12 @@ public class FileController extends BaseController { file.setAuditStatus(request.getAuditStatus()); } + if (request.getTags() != null) { + com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper(); + file.setTags(objectMapper.valueToTree(request.getTags())); + log.info("文件标签已更新: fileId={}, tags={}", id, request.getTags()); + } + file.setUpdateTime(LocalDateTime.now()); fileService.updateFileEntity(file); diff --git a/src/main/java/top/tqx/demo_1/controller/ImageController.java b/src/main/java/top/tqx/demo_1/controller/ImageController.java index 1e56246..9113ff0 100644 --- a/src/main/java/top/tqx/demo_1/controller/ImageController.java +++ b/src/main/java/top/tqx/demo_1/controller/ImageController.java @@ -83,37 +83,12 @@ public class ImageController { public byte[] getImageData(@Parameter(description = "图片ID") @PathVariable String id) { try { log.info("获取图片: id={}", id); - byte[] imageData = imageService.getImage(id); - if (imageData == null || imageData.length == 0) { - log.warn("图片数据为空: id={}", id); - // 返回一个1x1的透明像素作为占位符 - return createPlaceholderImage(); - } - return imageData; + return imageService.getImage(id); } catch (Exception e) { - log.error("获取图片失败: id={}, error={}", id, e.getMessage()); - // 返回一个1x1的透明像素作为占位符,避免页面报错 - return createPlaceholderImage(); + log.error("获取图片失败: {}", e.getMessage(), e); + throw new RuntimeException("获取图片失败: " + e.getMessage()); } } - - /** - * 创建一个1x1的透明占位图 - */ - private byte[] createPlaceholderImage() { - // 这是一个1x1的透明PNG图片的字节数组 - return new byte[] { - (byte)0x89, (byte)0x50, (byte)0x4E, (byte)0x47, (byte)0x0D, (byte)0x0A, (byte)0x1A, (byte)0x0A, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0D, (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, - (byte)0x08, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x1F, (byte)0x15, (byte)0xC4, - (byte)0x89, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x49, (byte)0x44, (byte)0x41, - (byte)0x54, (byte)0x08, (byte)0xD7, (byte)0x63, (byte)0x60, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x02, (byte)0x00, (byte)0x01, (byte)0xE2, (byte)0x26, (byte)0x05, (byte)0x9B, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x49, (byte)0x45, (byte)0x4E, (byte)0x44, (byte)0xAE, - (byte)0x42, (byte)0x60, (byte)0x82 - }; - } @Operation(summary = "更新图片记录", description = "更新图片记录信息,支持部分字段更新") @PutMapping("/{id}") diff --git a/src/main/java/top/tqx/demo_1/controller/QuestionController.java b/src/main/java/top/tqx/demo_1/controller/QuestionController.java index c383d91..446f19a 100644 --- a/src/main/java/top/tqx/demo_1/controller/QuestionController.java +++ b/src/main/java/top/tqx/demo_1/controller/QuestionController.java @@ -1,6 +1,6 @@ package top.tqx.demo_1.controller; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -14,14 +14,14 @@ import top.tqx.demo_1.dto.QuestionStatsRequest; import top.tqx.demo_1.dto.QuestionStatsResponse; import top.tqx.demo_1.dto.QuestionUpdateRequest; import top.tqx.demo_1.entity.Question; +import top.tqx.demo_1.service.AuthService; import top.tqx.demo_1.service.QuestionService; +import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import jakarta.servlet.http.HttpServletRequest; - @Tag(name = "题目管理", description = "题目的增删改查管理接口") @RestController @RequestMapping("/question") @@ -31,6 +31,9 @@ public class QuestionController extends BaseController { @Autowired private QuestionService questionService; + @Autowired + private AuthService authService; + @Operation(summary = "创建题目", description = "创建新的题目记录") @PostMapping public Result createQuestion(@RequestBody QuestionCreateRequest request) { @@ -66,11 +69,11 @@ public class QuestionController extends BaseController { return Result.success(result); } - @Operation(summary = "获取题目详情", description = "根据题目UUID获取题目详细信息") - @GetMapping("/{questionId}") + @Operation(summary = "获取题目详情", description = "根据题目ID获取题目详细信息") + @GetMapping("/{id}") public Result getQuestionById( - @Parameter(description = "题目UUID") @PathVariable String questionId) { - Question question = questionService.getByQuestionId(questionId); + @Parameter(description = "题目ID") @PathVariable Long id) { + Question question = questionService.getById(id); if (question == null) { return Result.error(404, "题目不存在"); } @@ -85,38 +88,64 @@ public class QuestionController extends BaseController { } @Operation(summary = "更新题目", description = "更新题目信息,支持部分字段更新") - @PutMapping("/{questionId}") + @PutMapping("/{id}") public Result updateQuestion( - @Parameter(description = "题目UUID") @PathVariable String questionId, + @Parameter(description = "题目ID(支持Long类型的id或UUID格式的questionId)") @PathVariable String id, @RequestBody QuestionUpdateRequest request) { try { - Question existing = questionService.getByQuestionId(questionId); + Question existing = null; + + if (isNumeric(id)) { + existing = questionService.getById(Long.parseLong(id)); + log.info("通过自增ID查询题目: id={}", id); + } else { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Question::getQuestionId, id); + existing = questionService.getOne(wrapper); + log.info("通过UUID查询题目: questionId={}", id); + } + if (existing == null) { - return Result.error(404, "题目不存在"); + return Result.error(404, "题目不存在: " + id); } Question updated = questionService.updateQuestion(existing.getId(), request); - log.info("更新题目成功: questionId={}", questionId); + log.info("更新题目成功: id={}, questionId={}", existing.getId(), existing.getQuestionId()); return Result.success("题目更新成功", updated); + } catch (NumberFormatException e) { + log.error("ID格式错误: {}", id, e); + return Result.error(400, "ID格式错误,请使用数字ID或有效的UUID"); } catch (Exception e) { log.error("更新题目失败: {}", e.getMessage(), e); return Result.error(500, "更新题目失败: " + e.getMessage()); } } - @Operation(summary = "删除题目", description = "根据UUID删除题目") - @DeleteMapping("/{questionId}") - public Result deleteQuestion( - @Parameter(description = "题目UUID") @PathVariable String questionId) { + private boolean isNumeric(String str) { + if (str == null || str.isEmpty()) { + return false; + } try { - Question existing = questionService.getByQuestionId(questionId); + Long.parseLong(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + @Operation(summary = "删除题目", description = "根据ID删除题目") + @DeleteMapping("/{id}") + public Result deleteQuestion( + @Parameter(description = "题目ID") @PathVariable Long id) { + try { + Question existing = questionService.getById(id); if (existing == null) { return Result.error(404, "题目不存在"); } - boolean success = questionService.deleteById(existing.getId()); + boolean success = questionService.deleteById(id); if (success) { - log.info("删除题目成功: questionId={}", questionId); + log.info("删除题目成功: id={}", id); return Result.success("题目删除成功"); } else { return Result.error(500, "删除题目失败"); diff --git a/src/main/java/top/tqx/demo_1/controller/WrongQuestionController.java b/src/main/java/top/tqx/demo_1/controller/WrongQuestionController.java index 865002e..e622d6c 100644 --- a/src/main/java/top/tqx/demo_1/controller/WrongQuestionController.java +++ b/src/main/java/top/tqx/demo_1/controller/WrongQuestionController.java @@ -213,7 +213,7 @@ public class WrongQuestionController extends BaseController { item.getScore() != null ? item.getScore().toString() : "0", item.getMaxScore() != null ? item.getMaxScore().toString() : "0", item.getDifficulty() != null ? item.getDifficulty() : 3, - escapeCsv(item.getDocumentName() != null ? item.getDocumentName() : ""), + escapeCsv(item.getExcludeStems() != null ? item.getExcludeStems() : ""), item.getWrongCount() != null ? item.getWrongCount() : 1, item.getAnsweredAt() != null ? item.getAnsweredAt().toString() : "" ); diff --git a/src/main/java/top/tqx/demo_1/dto/ExamGenerateRequest.java b/src/main/java/top/tqx/demo_1/dto/ExamGenerateRequest.java index cfc7421..814cc24 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamGenerateRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamGenerateRequest.java @@ -1,5 +1,6 @@ package top.tqx.demo_1.dto; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -55,7 +56,12 @@ public class ExamGenerateRequest implements Serializable { @Schema(description = "自定义题型分数配置,仅在指定题型模式下有效") private Map questionScores; // 各题型分数配置 + @JsonProperty("exclude_stems") + @Schema(description = "已有题目的题干列表,用于去重,最多100条") + private List excludeStems; + @Data + @JsonIgnoreProperties(ignoreUnknown = true) public static class QuestionContent implements Serializable { private static final long serialVersionUID = 1L; @@ -70,6 +76,9 @@ public class ExamGenerateRequest implements Serializable { @JsonProperty("explanation") private String explanation; + + @JsonProperty("referenced_chunk_ids") + private List referencedChunkIds; } @Data diff --git a/src/main/java/top/tqx/demo_1/dto/ExamGenerateResponse.java b/src/main/java/top/tqx/demo_1/dto/ExamGenerateResponse.java index 2040c2a..1749b83 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamGenerateResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamGenerateResponse.java @@ -7,6 +7,7 @@ import lombok.Data; import java.io.Serializable; import java.util.List; +import java.util.Map; @Data @JsonIgnoreProperties(ignoreUnknown = true) @@ -63,6 +64,18 @@ public class ExamGenerateResponse implements Serializable { @Schema(description = "生成的题目列表") private List questions; + @JsonProperty("requested_types") + @Schema(description = "请求的题型和数量") + private Map requestedTypes; + + @JsonProperty("actual_types") + @Schema(description = "实际生成的题型和数量") + private Map actualTypes; + + @JsonProperty("warnings") + @Schema(description = "短缺提示数组") + private List warnings; + @Data @JsonIgnoreProperties(ignoreUnknown = true) public static class ResponseData implements Serializable { @@ -85,6 +98,45 @@ public class ExamGenerateResponse implements Serializable { @JsonProperty("success") private Boolean success; + + @JsonProperty("requested_types") + private Map requestedTypes; + + @JsonProperty("actual_types") + private Map actualTypes; + + @JsonProperty("warnings") + private List warnings; + } + + public Map getRequestedTypes() { + if (requestedTypes != null) { + return requestedTypes; + } + if (data != null && data.getRequestedTypes() != null) { + return data.getRequestedTypes(); + } + return null; + } + + public Map getActualTypes() { + if (actualTypes != null) { + return actualTypes; + } + if (data != null && data.getActualTypes() != null) { + return data.getActualTypes(); + } + return null; + } + + public List getWarnings() { + if (warnings != null) { + return warnings; + } + if (data != null && data.getWarnings() != null) { + return data.getWarnings(); + } + return null; } public Object getAiAnalysis() { diff --git a/src/main/java/top/tqx/demo_1/dto/ExamGradeRequest.java b/src/main/java/top/tqx/demo_1/dto/ExamGradeRequest.java index 02aee4a..d74a3df 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamGradeRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamGradeRequest.java @@ -1,7 +1,6 @@ package top.tqx.demo_1.dto; import com.fasterxml.jackson.annotation.JsonAlias; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @@ -51,8 +50,8 @@ public class ExamGradeRequest implements Serializable { private String questionType; @JsonProperty("question_content") - @JsonAlias("questionContent") - private QuestionContent questionContent; + @JsonAlias({"content", "questionContent", "question_content"}) + private QuestionContent content; @JsonProperty("student_answer") @JsonAlias("studentAnswer") @@ -64,7 +63,6 @@ public class ExamGradeRequest implements Serializable { } @Data - @JsonIgnoreProperties(ignoreUnknown = true) public static class QuestionContent implements Serializable { private static final long serialVersionUID = 1L; @@ -76,9 +74,6 @@ public class ExamGradeRequest implements Serializable { @JsonProperty("answer") private Object answer; - - @JsonProperty("explanation") - private String explanation; } public enum QuestionType { diff --git a/src/main/java/top/tqx/demo_1/dto/ExamGradeResponse.java b/src/main/java/top/tqx/demo_1/dto/ExamGradeResponse.java index f6d9804..87822ed 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamGradeResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamGradeResponse.java @@ -150,6 +150,9 @@ public class ExamGradeResponse implements Serializable { @JsonProperty("max_score") private BigDecimal maxScore; + @JsonProperty("grading_status") + private String gradingStatus; + @JsonProperty("correct") private Boolean correct; @@ -176,6 +179,27 @@ public class ExamGradeResponse implements Serializable { public static class DetailInfo implements Serializable { private static final long serialVersionUID = 1L; + @JsonProperty("correct") + private Boolean correct; + + @JsonProperty("student_answer") + private Object studentAnswer; + + @JsonProperty("correct_answer") + private Object correctAnswer; + + @JsonProperty("feedback") + private String feedback; + + @JsonProperty("total_blanks") + private Integer totalBlanks; + + @JsonProperty("correct_blanks") + private Integer correctBlanks; + + @JsonProperty("blank_scores") + private List blankScores; + @JsonProperty("highlights") private List highlights; @@ -187,6 +211,12 @@ public class ExamGradeResponse implements Serializable { @JsonProperty("shortcomings") private List shortcomings; + + @JsonProperty("warnings") + private List warnings; + + @JsonProperty("error") + private String error; } @Data diff --git a/src/main/java/top/tqx/demo_1/dto/ExamPaperGenerateResponse.java b/src/main/java/top/tqx/demo_1/dto/ExamPaperGenerateResponse.java index 067a022..71ad9fe 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamPaperGenerateResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamPaperGenerateResponse.java @@ -60,7 +60,7 @@ public class ExamPaperGenerateResponse implements Serializable { private Object content; @JsonProperty("document_name") - private String documentName; + private String excludeStems; @JsonProperty("knowledge_base_path") private String knowledgeBasePath; diff --git a/src/main/java/top/tqx/demo_1/dto/ExamRecordResponse.java b/src/main/java/top/tqx/demo_1/dto/ExamRecordResponse.java index 9ea9d70..2d3437e 100644 --- a/src/main/java/top/tqx/demo_1/dto/ExamRecordResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/ExamRecordResponse.java @@ -52,12 +52,8 @@ public class ExamRecordResponse implements Serializable { public static class AnswerDetail implements Serializable { private static final long serialVersionUID = 1L; private String questionId; - private String questionType; - private String stem; private Object userAnswer; - private Object correctAnswer; private BigDecimal score; - private BigDecimal maxScore; private Boolean isCorrect; private String feedback; } diff --git a/src/main/java/top/tqx/demo_1/dto/FileUpdateRequest.java b/src/main/java/top/tqx/demo_1/dto/FileUpdateRequest.java index 84e9a51..46daaec 100644 --- a/src/main/java/top/tqx/demo_1/dto/FileUpdateRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/FileUpdateRequest.java @@ -3,6 +3,7 @@ package top.tqx.demo_1.dto; import lombok.Data; import java.io.Serializable; +import java.util.Map; @Data public class FileUpdateRequest implements Serializable { @@ -16,4 +17,6 @@ public class FileUpdateRequest implements Serializable { private Integer isPublic; private Integer auditStatus; + + private Map tags; } diff --git a/src/main/java/top/tqx/demo_1/dto/ImageCreateRequest.java b/src/main/java/top/tqx/demo_1/dto/ImageCreateRequest.java index e6fb5a9..ee8645d 100644 --- a/src/main/java/top/tqx/demo_1/dto/ImageCreateRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/ImageCreateRequest.java @@ -14,45 +14,24 @@ public class ImageCreateRequest implements Serializable { @JsonProperty("image_id") private String imageId; - @JsonProperty("filename") - private String filename; - @JsonProperty("path") private String path; - @JsonProperty("size_bytes") - private Long sizeBytes; - - @JsonProperty("format") - private String format; - @JsonProperty("source") private String source; @JsonProperty("page") private Integer page; - @JsonProperty("page_end") - private String pageEnd; - - @JsonProperty("page_range") - private String pageRange; - @JsonProperty("section") private String section; @JsonProperty("chunk_type") private String chunkType; - @JsonProperty("type") - private String type; - @JsonProperty("description") private String description; - @JsonProperty("full_description") - private String fullDescription; - @JsonProperty("score") private BigDecimal score; diff --git a/src/main/java/top/tqx/demo_1/dto/ImageUpdateRequest.java b/src/main/java/top/tqx/demo_1/dto/ImageUpdateRequest.java index ba3784e..1f13770 100644 --- a/src/main/java/top/tqx/demo_1/dto/ImageUpdateRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/ImageUpdateRequest.java @@ -10,18 +10,9 @@ public class ImageUpdateRequest implements Serializable { private static final long serialVersionUID = 1L; - @JsonProperty("filename") - private String filename; - @JsonProperty("path") private String path; - @JsonProperty("size_bytes") - private Long sizeBytes; - - @JsonProperty("format") - private String format; - @JsonProperty("source") private String source; diff --git a/src/main/java/top/tqx/demo_1/dto/ReferenceResponse.java b/src/main/java/top/tqx/demo_1/dto/ReferenceResponse.java index e13448c..4a4e375 100644 --- a/src/main/java/top/tqx/demo_1/dto/ReferenceResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/ReferenceResponse.java @@ -8,7 +8,9 @@ import java.math.BigDecimal; public class ReferenceResponse { private String chunkId; + private Integer chunkIndex; private String source; + private String collection; private String docType; private Integer page; private Integer pageEnd; diff --git a/src/main/java/top/tqx/demo_1/dto/UserAnswerQueryRequest.java b/src/main/java/top/tqx/demo_1/dto/UserAnswerQueryRequest.java index 6bc87d2..dcc71c5 100644 --- a/src/main/java/top/tqx/demo_1/dto/UserAnswerQueryRequest.java +++ b/src/main/java/top/tqx/demo_1/dto/UserAnswerQueryRequest.java @@ -19,6 +19,12 @@ public class UserAnswerQueryRequest implements Serializable { @JsonProperty("session_id") private String sessionId; + @JsonProperty("record_id") + private String recordId; + + @JsonProperty("answer_type") + private String answerType; + @JsonProperty("user_id") private Long userId; } diff --git a/src/main/java/top/tqx/demo_1/dto/WrongQuestionListResponse.java b/src/main/java/top/tqx/demo_1/dto/WrongQuestionListResponse.java index 873a32d..601583d 100644 --- a/src/main/java/top/tqx/demo_1/dto/WrongQuestionListResponse.java +++ b/src/main/java/top/tqx/demo_1/dto/WrongQuestionListResponse.java @@ -58,7 +58,7 @@ public class WrongQuestionListResponse implements Serializable { private String feedback; @JsonProperty("document_name") - private String documentName; + private String excludeStems; @JsonProperty("knowledge_base_path") private String knowledgeBasePath; diff --git a/src/main/java/top/tqx/demo_1/entity/ChatMessage.java b/src/main/java/top/tqx/demo_1/entity/ChatMessage.java index 53aa2bd..9e3253d 100644 --- a/src/main/java/top/tqx/demo_1/entity/ChatMessage.java +++ b/src/main/java/top/tqx/demo_1/entity/ChatMessage.java @@ -37,8 +37,6 @@ public class ChatMessage implements Serializable { private String images; - private String sources; - private LocalDateTime createTime; public Long getId() { @@ -137,14 +135,6 @@ public class ChatMessage implements Serializable { this.images = images; } - public String getSources() { - return sources; - } - - public void setSources(String sources) { - this.sources = sources; - } - public LocalDateTime getCreateTime() { return createTime; } diff --git a/src/main/java/top/tqx/demo_1/entity/ChatReference.java b/src/main/java/top/tqx/demo_1/entity/ChatReference.java index df1f140..929442f 100644 --- a/src/main/java/top/tqx/demo_1/entity/ChatReference.java +++ b/src/main/java/top/tqx/demo_1/entity/ChatReference.java @@ -22,7 +22,11 @@ public class ChatReference implements Serializable { private String chunkId; - private String docPath; + private Integer chunkIndex; + + private Long fileId; + + private String collection; private String docName; diff --git a/src/main/java/top/tqx/demo_1/entity/File.java b/src/main/java/top/tqx/demo_1/entity/File.java index 579d1c6..20802b9 100644 --- a/src/main/java/top/tqx/demo_1/entity/File.java +++ b/src/main/java/top/tqx/demo_1/entity/File.java @@ -61,7 +61,10 @@ public class File implements Serializable { private String examStatus; - private String processStepStatus; + private String processStepStatus; - private String processStepMessage; + private String processStepMessage; + + @TableField(value = "tags", typeHandler = JacksonTypeHandler.class) + private JsonNode tags; } diff --git a/src/main/java/top/tqx/demo_1/entity/Image.java b/src/main/java/top/tqx/demo_1/entity/Image.java index 7809e36..7b15dd0 100644 --- a/src/main/java/top/tqx/demo_1/entity/Image.java +++ b/src/main/java/top/tqx/demo_1/entity/Image.java @@ -17,32 +17,18 @@ public class Image { private String imageId; - private String filename; - private String path; - private Long sizeBytes; - - private String format; - private String source; private Integer page; - private String pageEnd; - - private String pageRange; - private String section; private String chunkType; - private String type; - private String description; - private String fullDescription; - private BigDecimal score; private String collection; diff --git a/src/main/java/top/tqx/demo_1/entity/Question.java b/src/main/java/top/tqx/demo_1/entity/Question.java index 67223c7..0b3637d 100644 --- a/src/main/java/top/tqx/demo_1/entity/Question.java +++ b/src/main/java/top/tqx/demo_1/entity/Question.java @@ -40,7 +40,7 @@ public class Question implements Serializable { private String documentId; - private String documentName; + private String excludeStems; private String knowledgeBasePath; @@ -71,4 +71,6 @@ public class Question implements Serializable { private LocalDateTime updatedAt; + private Integer isDeleted; + } diff --git a/src/main/java/top/tqx/demo_1/handler/GlobalExceptionHandler.java b/src/main/java/top/tqx/demo_1/handler/GlobalExceptionHandler.java index b67865b..151f2b9 100644 --- a/src/main/java/top/tqx/demo_1/handler/GlobalExceptionHandler.java +++ b/src/main/java/top/tqx/demo_1/handler/GlobalExceptionHandler.java @@ -9,6 +9,9 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.context.request.async.AsyncRequestNotUsableException; import org.springframework.web.context.request.async.AsyncRequestTimeoutException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.converter.HttpMessageNotReadableException; +import com.fasterxml.jackson.core.JsonProcessingException; import top.tqx.demo_1.common.Result; import top.tqx.demo_1.exception.PermissionDeniedException; @@ -81,17 +84,58 @@ public class GlobalExceptionHandler { return Result.error(400, message); } + @ExceptionHandler(DataIntegrityViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleDataIntegrityViolation(DataIntegrityViolationException e) { + String causeMsg = e.getMostSpecificCause().getMessage(); + log.error("数据完整性违规: {}", causeMsg); + + String userMsg = "数据格式不符合要求"; + if (causeMsg != null) { + if (causeMsg.contains("Out of range")) userMsg = "数值超出允许范围"; + else if (causeMsg.contains("Data too long")) userMsg = "输入内容过长"; + else if (causeMsg.contains("not null")) userMsg = "必填字段不能为空"; + } + return Result.error(400, userMsg); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleHttpMessageNotReadable(HttpMessageNotReadableException e) { + log.error("请求体解析失败: {}", e.getMessage()); + String msg = "请求数据格式错误"; + if (e.getMessage() != null) { + if (e.getMessage().contains("JSON")) msg = "JSON格式不正确"; + else if (e.getMessage().contains("content")) msg = "题目内容格式不正确"; + } + return Result.error(400, msg); + } + + @ExceptionHandler(JsonProcessingException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleJsonProcessing(JsonProcessingException e) { + log.error("JSON序列化失败: {}", e.getOriginalMessage(), e); + return Result.error(400, "数据处理格式错误: " + e.getOriginalMessage()); + } + @ExceptionHandler(RuntimeException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Result handleRuntimeException(RuntimeException e) { - log.error("运行时异常: type={}, message={}", e.getClass().getSimpleName(), e.getMessage()); - if (e.getMessage() != null && (e.getMessage().contains("SQL") || e.getMessage().contains("connection"))) { + log.error("运行时异常: type={}, message={}", + e.getClass().getSimpleName(), e.getMessage(), e); + + String msg = e.getMessage() != null ? e.getMessage() : "未知错误"; + + if (msg.contains("SQL") || msg.contains("connection")) return Result.error(500, "数据库操作失败"); - } - if (e.getMessage() != null && e.getMessage().contains("Access Denied")) { + if (msg.contains("Access Denied")) return Result.error(403, "无权限访问"); - } - return Result.error(500, "服务器内部错误"); + if (msg.contains("Out of range")) + return Result.error(400, "数值超出允许范围"); + if (msg.contains("Data too long")) + return Result.error(400, "输入内容过长"); + + return Result.error(500, "操作失败: " + msg); } @ExceptionHandler(Exception.class) diff --git a/src/main/java/top/tqx/demo_1/mapper/QuestionMapper.java b/src/main/java/top/tqx/demo_1/mapper/QuestionMapper.java index 0e57eec..03e08e5 100644 --- a/src/main/java/top/tqx/demo_1/mapper/QuestionMapper.java +++ b/src/main/java/top/tqx/demo_1/mapper/QuestionMapper.java @@ -1,7 +1,16 @@ package top.tqx.demo_1.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Select; import top.tqx.demo_1.entity.Question; +import java.util.List; + public interface QuestionMapper extends BaseMapper { + + /** + * 根据文档ID查询已有的题目题干,用于去重 + */ + @Select("SELECT exclude_stems AS stem FROM question WHERE document_id = #{documentId} AND exclude_stems IS NOT NULL AND is_deleted = 0") + List selectStemsByDocumentId(String documentId); } diff --git a/src/main/java/top/tqx/demo_1/service/AsyncExamService.java b/src/main/java/top/tqx/demo_1/service/AsyncExamService.java index d69bf3a..6700e5c 100644 --- a/src/main/java/top/tqx/demo_1/service/AsyncExamService.java +++ b/src/main/java/top/tqx/demo_1/service/AsyncExamService.java @@ -77,6 +77,26 @@ public class AsyncExamService { updateFileExamStatus(fileId, EXAM_STATUS_GENERATED, "警告:未生成任何题目。可能原因:文档内容为空、文档内容无法提取题目、或文档格式不支持。source_chunks_used=" + response.getSourceChunksUsed()); } else { String processMessage = "生成成功,共" + response.getTotal() + "道题"; + + // 追加题型统计信息 + if (response.getRequestedTypes() != null || response.getActualTypes() != null) { + processMessage += "\n\n【题型统计】"; + if (response.getRequestedTypes() != null) { + processMessage += "\n请求题型: " + formatQuestionTypes(response.getRequestedTypes()); + } + if (response.getActualTypes() != null) { + processMessage += "\n实际生成: " + formatQuestionTypes(response.getActualTypes()); + } + } + + // 追加短缺警告 + if (response.getWarnings() != null && !response.getWarnings().isEmpty()) { + processMessage += "\n\n【短缺警告】"; + for (String warning : response.getWarnings()) { + processMessage += "\n- " + warning; + } + } + log.info("response.getAiAnalysis() = {}", response.getAiAnalysis()); log.info("response.getAiAnalysis() == null? {}", response.getAiAnalysis() == null); if (response.getAiAnalysis() != null) { @@ -214,4 +234,32 @@ public class AsyncExamService { throw new RuntimeException("更新文件状态失败", e); } } + + /** + * 格式化题型统计信息 + */ + private String formatQuestionTypes(java.util.Map types) { + if (types == null || types.isEmpty()) { + return "{}"; + } + StringBuilder sb = new StringBuilder("{"); + java.util.Map typeNames = new java.util.HashMap<>(); + typeNames.put("single_choice", "单选题"); + typeNames.put("multiple_choice", "多选题"); + typeNames.put("true_false", "判断题"); + typeNames.put("fill_blank", "填空题"); + typeNames.put("subjective", "主观题"); + + boolean first = true; + for (java.util.Map.Entry entry : types.entrySet()) { + if (!first) { + sb.append(", "); + } + String typeName = typeNames.getOrDefault(entry.getKey(), entry.getKey()); + sb.append(typeName).append(": ").append(entry.getValue()).append("道"); + first = false; + } + sb.append("}"); + return sb.toString(); + } } diff --git a/src/main/java/top/tqx/demo_1/service/AsyncVectorizeService.java b/src/main/java/top/tqx/demo_1/service/AsyncVectorizeService.java index 3ff38a1..0f2503a 100644 --- a/src/main/java/top/tqx/demo_1/service/AsyncVectorizeService.java +++ b/src/main/java/top/tqx/demo_1/service/AsyncVectorizeService.java @@ -81,7 +81,10 @@ public class AsyncVectorizeService { return; } + log.info("开始确保collection存在: collection={}, fileId={}, deptId={}", + collection, fileId, file.getDeptId()); ensureCollectionExists(collection, file.getDeptId(), userId); + log.info("Collection检查完成: collection={}, fileId={}", collection, fileId); updateFileProcessStatus(fileId, VECTORIZE_STATUS_VECTORIZING, "正在向量化,请稍后..."); @@ -103,6 +106,8 @@ public class AsyncVectorizeService { byte[] fileContent = Files.readAllBytes(path); String originalFilename = file.getFileName(); + log.info("开始上传文件到RAG: collection={}, filename={}, size={} bytes", + collection, originalFilename, fileContent.length); Map uploadResult = uploadToRAG(collection, originalFilename, fileContent); Boolean uploadSuccess = (Boolean) uploadResult.get("success"); @@ -115,6 +120,7 @@ public class AsyncVectorizeService { file.setVectorDbAddress(collection + "/" + originalFilename); file.setUpdateTime(LocalDateTime.now()); fileMapper.updateById(file); + log.info("更新文件向量库地址: fileId={}, vectorDbAddress={}", fileId, file.getVectorDbAddress()); } collectionFileService.saveOrUpdate(collection, originalFilename, fileId, file.getFilePath(), file.getExtension()); @@ -130,8 +136,6 @@ public class AsyncVectorizeService { triggerSync(); - triggerExamGeneration(fileId, collection, originalFilename, userId); - } catch (Exception e) { long duration = System.currentTimeMillis() - startTime; String errorType = e.getMessage() != null && (e.getMessage().contains("500") || e.getMessage().contains("INTERNAL SERVER ERROR")) @@ -254,7 +258,7 @@ public class AsyncVectorizeService { private void ensureCollectionExists(String collectionName, Long deptId, Long userId) { try { - log.info("检查collection是否存在: collectionName={}", collectionName); + log.info("检查collection是否存在: collectionName={}, deptId={}", collectionName, deptId); String url = aiApiConfig.getFullUrl(aiApiConfig.getCollection().getList()); ResponseEntity response = restTemplate.getForEntity(url, String.class); @@ -272,9 +276,12 @@ public class AsyncVectorizeService { boolean exists = false; if (collections != null) { for (Map coll : collections) { - if (collectionName.equals(coll.get("name"))) { + String collName = (String) coll.get("name"); + if (collectionName.equals(collName)) { exists = true; log.info("Collection已存在: {}", collectionName); + + checkAndCreateLocalRecord(collectionName, deptId, userId); break; } } @@ -296,6 +303,23 @@ public class AsyncVectorizeService { } } + private void checkAndCreateLocalRecord(String collectionName, Long deptId, Long userId) { + try { + KnowledgeBasePath existingKb = knowledgeBasePathMapper.selectOne( + new LambdaQueryWrapper().eq(KnowledgeBasePath::getName, collectionName) + ); + + if (existingKb == null) { + log.info("本地记录不存在,创建知识库路径记录: {}", collectionName); + saveKnowledgeBasePath(collectionName, deptId, userId); + } else { + log.debug("本地记录已存在: collectionName={}", collectionName); + } + } catch (Exception e) { + log.error("检查或创建本地记录失败: collectionName={}", collectionName, e); + } + } + private void createCollection(String collectionName, Long deptId, Long userId) { try { String url = aiApiConfig.getFullUrl(aiApiConfig.getCollection().getCreate()); diff --git a/src/main/java/top/tqx/demo_1/service/ChatService.java b/src/main/java/top/tqx/demo_1/service/ChatService.java index b82dedb..4730a04 100644 --- a/src/main/java/top/tqx/demo_1/service/ChatService.java +++ b/src/main/java/top/tqx/demo_1/service/ChatService.java @@ -17,7 +17,7 @@ public interface ChatService { ChatMessage saveUserMessage(Long sessionId, String content, String kbPaths); - ChatMessage saveAssistantMessage(Long sessionId, String content, String answer, String kbPaths, String messageType, Integer isFinished, Long durationMs, String images, String sources); + ChatMessage saveAssistantMessage(Long sessionId, String content, String answer, String kbPaths, String messageType, Integer isFinished, Long durationMs, String images); ChatReference saveReference(Long messageId, String chunkId, String docPath, String docName, Integer page, String excerpt, Double score); diff --git a/src/main/java/top/tqx/demo_1/service/FileService.java b/src/main/java/top/tqx/demo_1/service/FileService.java index 3ed108c..187b879 100644 --- a/src/main/java/top/tqx/demo_1/service/FileService.java +++ b/src/main/java/top/tqx/demo_1/service/FileService.java @@ -8,7 +8,7 @@ import java.io.InputStream; public interface FileService { - FileVO uploadFile(MultipartFile file, Long userId, Long deptId, Integer userType, Long targetDeptId, Boolean isPublic); + FileVO uploadFile(MultipartFile file, Long userId, Long deptId, Integer userType, Long targetDeptId, Boolean isPublic, Boolean autoVectorize); PageResult pageFiles(Integer pageNum, Integer pageSize, String fileName, top.tqx.demo_1.entity.User user); diff --git a/src/main/java/top/tqx/demo_1/service/ImageService.java b/src/main/java/top/tqx/demo_1/service/ImageService.java index a09d2b9..b569d37 100644 --- a/src/main/java/top/tqx/demo_1/service/ImageService.java +++ b/src/main/java/top/tqx/demo_1/service/ImageService.java @@ -36,20 +36,4 @@ public interface ImageService { Image downloadAndSaveImageWithMetadata(Map imageMetadata); Map getImageInfo(String imageId); - - /** - * 根据图片ID获取Nginx格式的URL - * @param imageId 图片ID - * @return Nginx格式的URL - */ - String getNginxUrlByImageId(String imageId); - - /** - * 根据文档名称、页码、片段ID等信息查找图片 - * @param docName 文档名称 - * @param page 页码 - * @param chunkId 片段ID - * @return 找到的图片列表 - */ - List findImagesByReference(String docName, Integer page, String chunkId); } \ No newline at end of file diff --git a/src/main/java/top/tqx/demo_1/service/QuestionService.java b/src/main/java/top/tqx/demo_1/service/QuestionService.java index ed301a6..6ed0693 100644 --- a/src/main/java/top/tqx/demo_1/service/QuestionService.java +++ b/src/main/java/top/tqx/demo_1/service/QuestionService.java @@ -38,4 +38,8 @@ public interface QuestionService extends IService { List listQuestions(String questionType, Integer difficulty, String status, String documentName, Integer limit, Long userId, Long deptId, Integer userType); QuestionStatsResponse getQuestionStats(QuestionStatsRequest request); + + int softDeleteByFileId(Long fileId); + + int softDeleteByDocumentName(String documentName); } diff --git a/src/main/java/top/tqx/demo_1/service/impl/AiChatServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/AiChatServiceImpl.java index 4172623..76c1285 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/AiChatServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/AiChatServiceImpl.java @@ -18,18 +18,10 @@ import top.tqx.demo_1.service.AiChatService; import top.tqx.demo_1.service.ChatService; import top.tqx.demo_1.service.ImageService; import top.tqx.demo_1.service.SseEmitterManager; -import top.tqx.demo_1.service.DepartmentService; -import top.tqx.demo_1.service.KnowledgeBasePathService; - -import org.springframework.beans.factory.annotation.Value; import java.math.BigDecimal; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.CompletableFuture; @Slf4j @@ -49,9 +41,8 @@ public class AiChatServiceImpl implements AiChatService { @Autowired private ImageService imageService; - // Nginx 图片访问前缀(从配置文件读取) - @Value("${file.upload.url-prefix:/files/}") - private String imageUrlPrefix; + @Autowired + private org.springframework.web.client.RestTemplate restTemplate; private final ObjectMapper objectMapper = new ObjectMapper(); @@ -188,22 +179,9 @@ public class AiChatServiceImpl implements AiChatService { break; case "sources": - log.info("收到检索来源信息"); if (jsonNode.has("sources")) { JsonNode sourcesNode = jsonNode.get("sources"); - if (sourcesNode.isArray()) { - for (JsonNode sourceItem : sourcesNode) { - ChatReference ref = parseSourceToReference(sourceItem); - String chunkId = ref.getChunkId(); - if (chunkId == null || chunkId.isEmpty()) { - chunkId = ref.getDocName() + "_" + ref.getPage() + "_" + ref.getSectionChunkId(); - } - if (!processedChunkIds[0].contains(chunkId)) { - processedChunkIds[0].add(chunkId); - referenceList[0].add(ref); - } - } - } + log.info("收到检索来源信息: count={}(仅日志,不写入引用表)", sourcesNode.isArray() ? sourcesNode.size() : 0); } break; @@ -218,20 +196,7 @@ public class AiChatServiceImpl implements AiChatService { } if (jsonNode.has("sources")) { JsonNode sourcesNode = jsonNode.get("sources"); - if (sourcesNode.isArray()) { - for (JsonNode sourceItem : sourcesNode) { - ChatReference ref = parseSourceToReference(sourceItem); - String chunkId = ref.getChunkId(); - if (chunkId == null || chunkId.isEmpty()) { - chunkId = ref.getDocName() + "_" + ref.getPage() + "_" + ref.getSectionChunkId(); - } - if (!processedChunkIds[0].contains(chunkId)) { - processedChunkIds[0].add(chunkId); - referenceList[0].add(ref); - } - } - log.info("从finish事件提取sources: count={}", sourcesNode.size()); - } + log.info("finish事件包含sources: count={}(仅日志,不写入引用表)", sourcesNode.isArray() ? sourcesNode.size() : 0); } if (jsonNode.has("citations")) { JsonNode citationsNode = jsonNode.get("citations"); @@ -487,13 +452,6 @@ public class AiChatServiceImpl implements AiChatService { Image savedImage = imageService.downloadAndSaveImageWithMetadata(imageMetadata); if (savedImage != null) { - // 尝试获取Nginx格式的URL并更新到metadata - String nginxUrl = imageService.getNginxUrlByImageId(ref.getChunkId()); - if (nginxUrl != null) { - imageMetadata.put("url", nginxUrl); - log.info("[{}] [{}] [来源图片处理] 更新 - 图片URL已更新为Nginx格式, imageId={}, url={}", - java.time.LocalDateTime.now(), saveOperationId, ref.getChunkId(), nginxUrl); - } imageIds[0].add(ref.getChunkId()); imageMetadataList[0].add(imageMetadata); log.info("[{}] [{}] [来源图片处理] 成功 - 图片信息已保存到数据库, imageId={}, dbId={}", @@ -533,13 +491,6 @@ public class AiChatServiceImpl implements AiChatService { Image savedImage = imageService.downloadAndSaveImageWithMetadata(imageMetadata); if (savedImage != null) { - // 尝试获取Nginx格式的URL并更新到metadata - String nginxUrl = imageService.getNginxUrlByImageId(imageId); - if (nginxUrl != null) { - imageMetadata.put("url", nginxUrl); - log.info("[{}] [{}] [有元数据图片处理] 更新 - 图片URL已更新为Nginx格式, imageId={}, url={}", - java.time.LocalDateTime.now(), saveOperationId, imageId, nginxUrl); - } log.info("[{}] [{}] [有元数据图片处理] 成功 - 图片已保存到数据库, imageId={}, dbId={}, path={}", java.time.LocalDateTime.now(), saveOperationId, imageId, savedImage.getId(), savedImage.getPath()); } else { @@ -588,67 +539,30 @@ public class AiChatServiceImpl implements AiChatService { for (String imageId : imageIds[0]) { ObjectNode imageNode = objectMapper.createObjectNode(); imageNode.put("image_id", imageId); - - // 尝试获取Nginx格式的URL - String nginxUrl = getNginxUrlForImage(imageId); - if (nginxUrl != null) { - imageNode.put("url", nginxUrl); - } else { - // 回退到旧的API格式 - imageNode.put("url", "/api/image/" + imageId + "/data"); - } - + imageNode.put("url", "/api/image/" + imageId + "/data"); imageList.add(imageNode); } imagesJson = objectMapper.writeValueAsString(imageList); } - String sourcesJson = null; - if (!referenceList[0].isEmpty()) { - java.util.Map docCountMap = new java.util.HashMap<>(); - java.util.Map docTypeMap = new java.util.HashMap<>(); - java.util.Map> docPageMap = new java.util.HashMap<>(); - - for (ChatReference ref : referenceList[0]) { - String docName = ref.getDocName(); - docCountMap.merge(docName, 1, Integer::sum); - if (ref.getDocType() != null) { - docTypeMap.put(docName, ref.getDocType()); - } - if (ref.getPage() != null) { - docPageMap.computeIfAbsent(docName, k -> new java.util.ArrayList()).add(ref.getPage()); - } - } - - java.util.List sourcesList = new java.util.ArrayList<>(); - for (java.util.Map.Entry entry : docCountMap.entrySet()) { - ObjectNode sourceNode = objectMapper.createObjectNode(); - sourceNode.put("docName", entry.getKey()); - sourceNode.put("docType", docTypeMap.getOrDefault(entry.getKey(), "")); - sourceNode.put("referenceCount", entry.getValue()); - - java.util.List pages = docPageMap.get(entry.getKey()); - if (pages != null && !pages.isEmpty()) { - int minPage = pages.stream().mapToInt(Integer::intValue).min().orElse(0); - int maxPage = pages.stream().mapToInt(Integer::intValue).max().orElse(0); - if (minPage == maxPage) { - sourceNode.put("pages", String.valueOf(minPage)); - } else { - sourceNode.put("pages", minPage + "-" + maxPage); - } - } - sourcesList.add(sourceNode); - } - sourcesJson = objectMapper.writeValueAsString(sourcesList); - } - savedAssistantMessage[0] = chatService.saveAssistantMessage( - chatSessionId[0], request.getMessage(), finalAnswer, kbPathsJson, "rag", 1, durationMs, imagesJson, sourcesJson); + chatSessionId[0], request.getMessage(), finalAnswer, kbPathsJson, "rag", 1, durationMs, imagesJson); if (savedAssistantMessage[0] != null) { log.info("助手消息已保存: messageId={}, chatSessionId={}", savedAssistantMessage[0].getId(), chatSessionId[0]); if (!referenceList[0].isEmpty()) { + for (ChatReference ref : referenceList[0]) { + try { + String previewContent = fetchPreviewFromRagService( + ref.getCollection(), ref.getDocName(), ref.getChunkIndex()); + if (previewContent != null && !previewContent.isEmpty()) { + ref.setPreview(previewContent); + } + } catch (Exception ex) { + log.warn("填充preview失败: chunkId={}, error={}", ref.getChunkId(), ex.getMessage()); + } + } chatService.saveReferences(savedAssistantMessage[0].getId(), referenceList[0]); log.info("引用信息已保存: count={}, messageId={}", referenceList[0].size(), savedAssistantMessage[0].getId()); } @@ -686,7 +600,9 @@ public class AiChatServiceImpl implements AiChatService { for (ChatReference ref : referenceList[0]) { ReferenceResponse response = new ReferenceResponse(); response.setChunkId(ref.getChunkId()); + response.setChunkIndex(ref.getChunkIndex()); response.setSource(ref.getDocName()); + response.setCollection(ref.getCollection()); response.setDocType(ref.getDocType()); response.setPage(ref.getPage()); response.setPageEnd(ref.getPageEnd()); @@ -709,7 +625,9 @@ public class AiChatServiceImpl implements AiChatService { for (ChatReference ref : citationList[0]) { ReferenceResponse response = new ReferenceResponse(); response.setChunkId(ref.getChunkId()); + response.setChunkIndex(ref.getChunkIndex()); response.setSource(ref.getDocName()); + response.setCollection(ref.getCollection()); response.setDocType(ref.getDocType()); response.setPage(ref.getPage()); response.setPageEnd(ref.getPageEnd()); @@ -768,13 +686,7 @@ public class AiChatServiceImpl implements AiChatService { if (!processedImageIds.contains(imageId)) { ObjectNode imageNode = objectMapper.createObjectNode(); imageNode.put("id", imageId); - // 尝试获取Nginx格式的URL - String nginxUrl = imageService.getNginxUrlByImageId(imageId); - if (nginxUrl != null) { - imageNode.put("url", nginxUrl); - } else { - imageNode.put("url", "/api/image/" + imageId + "/data"); - } + imageNode.put("url", "/api/image/" + imageId + "/data"); imageList.add(imageNode); } } @@ -835,7 +747,12 @@ public class AiChatServiceImpl implements AiChatService { private ChatReference parseSourceToReference(JsonNode sourceItem) { ChatReference ref = new ChatReference(); ref.setChunkId(sourceItem.has("chunk_id") ? sourceItem.get("chunk_id").asText() : ""); + + JsonNode chunkIndexNode = sourceItem.path("chunk_index"); + ref.setChunkIndex(!chunkIndexNode.isNull() ? chunkIndexNode.asInt() : null); + ref.setDocName(sourceItem.has("source") ? sourceItem.get("source").asText() : ""); + ref.setCollection(sourceItem.has("collection") ? sourceItem.get("collection").asText() : null); JsonNode pageNode = sourceItem.path("page"); ref.setPage(!pageNode.isNull() ? pageNode.asInt() : null); @@ -855,6 +772,10 @@ public class AiChatServiceImpl implements AiChatService { ref.setExcerpt(sourceItem.has("preview") ? sourceItem.get("preview").asText() : (sourceItem.has("content") ? sourceItem.get("content").asText() : (sourceItem.has("excerpt") ? sourceItem.get("excerpt").asText() : ""))); + if (sourceItem.has("bbox")) { + ref.setBbox(sourceItem.get("bbox").toString()); + } + ref.setBboxMode(sourceItem.has("bbox_mode") ? sourceItem.get("bbox_mode").asText() : null); if (sourceItem.has("score")) { JsonNode scoreNode = sourceItem.get("score"); if (scoreNode.isNumber()) { @@ -867,10 +788,18 @@ public class AiChatServiceImpl implements AiChatService { private ChatReference parseCitationToReference(JsonNode citationItem) { ChatReference ref = new ChatReference(); ref.setChunkId(citationItem.has("chunk_id") ? citationItem.get("chunk_id").asText() : ""); + + JsonNode chunkIndexNode = citationItem.path("chunk_index"); + ref.setChunkIndex(!chunkIndexNode.isNull() ? chunkIndexNode.asInt() : null); + ref.setDocName(citationItem.has("source") ? citationItem.get("source").asText() : ""); + ref.setCollection(citationItem.has("collection") ? citationItem.get("collection").asText() : null); ref.setDocType(citationItem.has("doc_type") ? citationItem.get("doc_type").asText() : null); ref.setSection(citationItem.has("section") ? citationItem.get("section").asText() : null); ref.setPreview(citationItem.has("preview") ? citationItem.get("preview").asText() : null); + ref.setExcerpt(citationItem.has("content") ? citationItem.get("content").asText() : + (citationItem.has("preview") ? citationItem.get("preview").asText() : + (citationItem.has("excerpt") ? citationItem.get("excerpt").asText() : ""))); JsonNode pageNode = citationItem.path("page"); ref.setPage(!pageNode.isNull() ? pageNode.asInt() : null); @@ -885,7 +814,7 @@ public class AiChatServiceImpl implements AiChatService { ref.setBbox(citationItem.get("bbox").toString()); } ref.setBboxMode(citationItem.has("bbox_mode") ? citationItem.get("bbox_mode").asText() : null); - ref.setExcerpt(citationItem.has("preview") ? citationItem.get("preview").asText() : ""); + ref.setChunkType(citationItem.has("chunk_type") ? citationItem.get("chunk_type").asText() : null); if (citationItem.has("score")) { JsonNode scoreNode = citationItem.get("score"); if (scoreNode.isNumber()) { @@ -895,70 +824,38 @@ public class AiChatServiceImpl implements AiChatService { return ref; } - /** - * 根据imageId获取Nginx访问格式的URL - */ - private String getNginxUrlForImage(String imageId) { - try { - // 从数据库查询图片记录 - Image image = imageService.getImageByImageId(imageId); - - // 如果没找到,尝试带.jpg后缀 - if (image == null && !imageId.toLowerCase().endsWith(".jpg")) { - image = imageService.getImageByImageId(imageId + ".jpg"); - } - - // 找到图片记录,提取文件名并构造Nginx URL - if (image != null && image.getPath() != null) { - String dbPath = image.getPath(); - log.debug("从数据库获取到图片路径: imageId={}, path={}", imageId, dbPath); - - // 从路径中提取文件名 - String filename = extractFilenameFromPath(dbPath); - if (filename != null) { - // 构造Nginx URL: /files/img/{filename} - String nginxUrl = imageUrlPrefix + "img/" + filename; - log.info("图片URL已转换: imageId={}, nginxUrl={}", imageId, nginxUrl); - return nginxUrl; - } - } - - log.warn("无法从数据库获取图片信息,将使用旧格式URL: imageId={}", imageId); - } catch (Exception e) { - log.warn("获取图片Nginx URL失败: imageId={}, error={}", imageId, e.getMessage()); - } - - return null; - } - - /** - * 从文件路径中提取文件名 - * 支持格式: /app/uploads/img/xxx.jpg 或 /opt/deploy/uploads/img/xxx.jpg - */ - private String extractFilenameFromPath(String path) { - if (path == null || path.isEmpty()) { + private String fetchPreviewFromRagService(String collection, String docName, Integer chunkIndex) { + if (collection == null || docName == null || chunkIndex == null) { return null; } - try { - // 使用Paths处理路径,兼容不同操作系统的分隔符 - Path filePath = Paths.get(path); - return filePath.getFileName().toString(); - } catch (Exception e) { - log.debug("从路径提取文件名失败: path={}, error={}", path, e.getMessage()); - - // 备用方案:字符串分割 - try { - // 查找最后一个 / 或 \ - int lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); - if (lastSlash >= 0 && lastSlash < path.length() - 1) { - return path.substring(lastSlash + 1); - } - } catch (Exception ex) { - log.debug("备用方案提取文件名也失败: {}", ex.getMessage()); + String previewUrl = aiApiConfig.getFullUrl(aiApiConfig.getDocument().getPreview()); + previewUrl = previewUrl.replace("{path}", collection + "/" + docName) + + "?chunk_index=" + chunkIndex + "&context=0"; + log.debug("调用RAG预览接口: {}", previewUrl); + + String response = restTemplate.getForObject(previewUrl, String.class); + if (response == null) { + return "预览接口返回空"; } + + JsonNode root = objectMapper.readTree(response); + if (root.has("chunks") && root.get("chunks").isArray()) { + JsonNode chunksNode = root.get("chunks"); + for (JsonNode chunk : chunksNode) { + if (chunk.has("is_target") && chunk.get("is_target").asBoolean(false)) { + if (chunk.has("document")) { + return chunk.get("document").asText(); + } + break; + } + } + } + return null; + } catch (Exception e) { + log.warn("调用RAG预览接口失败: collection={}, docName={}, chunkIndex={}, error={}", + collection, docName, chunkIndex, e.getMessage()); + return "预览获取失败: " + e.getMessage(); } - - return null; } } diff --git a/src/main/java/top/tqx/demo_1/service/impl/ChatServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/ChatServiceImpl.java index 0b07ea9..80ec5a9 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/ChatServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/ChatServiceImpl.java @@ -9,27 +9,16 @@ import top.tqx.demo_1.dto.RagRequest; import top.tqx.demo_1.entity.ChatMessage; import top.tqx.demo_1.entity.ChatReference; import top.tqx.demo_1.entity.ChatSession; -import top.tqx.demo_1.entity.Image; import top.tqx.demo_1.mapper.ChatMessageMapper; +import top.tqx.demo_1.entity.CollectionFile; import top.tqx.demo_1.mapper.ChatReferenceMapper; import top.tqx.demo_1.mapper.ChatSessionMapper; +import top.tqx.demo_1.mapper.CollectionFileMapper; import top.tqx.demo_1.service.ChatService; -import top.tqx.demo_1.service.ImageService; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.util.DigestUtils; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.UUID; @Slf4j @@ -46,17 +35,7 @@ public class ChatServiceImpl implements ChatService { private ChatReferenceMapper chatReferenceMapper; @Autowired - private ObjectMapper objectMapper; - - @Autowired - private ImageService imageService; - - // Nginx 图片访问前缀(从配置文件读取) - @Value("${file.upload.url-prefix:/files/}") - private String imageUrlPrefix; - - // 图片访问路径(兼容旧版,使用现有的图片服务接口 /api/image/{imageId}/data) - private static final String IMAGE_ACCESS_PATH = "/api/image/"; + private CollectionFileMapper collectionFileMapper; @Override @Transactional(rollbackFor = Exception.class) @@ -116,7 +95,7 @@ public class ChatServiceImpl implements ChatService { @Override @Transactional(rollbackFor = Exception.class) - public ChatMessage saveAssistantMessage(Long sessionId, String content, String answer, String kbPaths, String messageType, Integer isFinished, Long durationMs, String images, String sources) { + public ChatMessage saveAssistantMessage(Long sessionId, String content, String answer, String kbPaths, String messageType, Integer isFinished, Long durationMs, String images) { if (content == null || content.isEmpty()) { log.warn("助手消息内容为空,跳过保存"); return null; @@ -127,12 +106,6 @@ public class ChatServiceImpl implements ChatService { return null; } - ChatMessage existing = chatMessageMapper.findAssistantMessageByContent(sessionId, content); - if (existing != null) { - log.warn("相同内容的助手消息已存在,跳过保存: sessionId={}, content={}", sessionId, content); - return existing; - } - ChatMessage message = new ChatMessage(); message.setConversationId(sessionId); message.setRole("assistant"); @@ -143,10 +116,9 @@ public class ChatServiceImpl implements ChatService { message.setIsFinished(isFinished != null ? isFinished : 1); message.setDurationMs(durationMs); message.setImages(images); - message.setSources(sources); message.setCreateTime(LocalDateTime.now()); chatMessageMapper.insert(message); - log.info("保存助手消息: messageId={}, sessionId={}, type={}, finished={}, duration={}ms, images={}, sources={}", message.getId(), sessionId, messageType, isFinished, durationMs, images != null ? "[" + images.length() + " chars]" : "null", sources != null ? "[" + sources.length() + " chars]" : "null"); + log.info("保存助手消息: messageId={}, sessionId={}, type={}, finished={}, duration={}ms, images={}", message.getId(), sessionId, messageType, isFinished, durationMs, images != null ? "[" + images.length() + " chars]" : "null"); return message; } @@ -156,15 +128,35 @@ public class ChatServiceImpl implements ChatService { ChatReference reference = new ChatReference(); reference.setMessageId(messageId); reference.setChunkId(chunkId); - reference.setDocPath(docPath); + + // 通过 collection 和 docName 查找 collection_file 的 id + String collection = extractCollectionFromDocPath(docPath); + if (collection != null && docName != null && !docName.isEmpty()) { + CollectionFile collectionFile = collectionFileMapper.findByCollectionAndDocName(collection, docName); + if (collectionFile != null) { + reference.setFileId(collectionFile.getId()); + } + } + reference.setDocName(docName); reference.setPage(page); reference.setExcerpt(excerpt); reference.setCreateTime(LocalDateTime.now()); chatReferenceMapper.insert(reference); - log.info("保存引用: referenceId={}, messageId={}, docName={}", reference.getId(), messageId, docName); + log.info("保存引用: referenceId={}, messageId={}, docName={}, fileId={}", reference.getId(), messageId, docName, reference.getFileId()); return reference; } + + private String extractCollectionFromDocPath(String docPath) { + if (docPath == null || docPath.isEmpty()) { + return null; + } + int index = docPath.indexOf("/"); + if (index > 0) { + return docPath.substring(0, index); + } + return null; + } @Override @Transactional(rollbackFor = Exception.class) @@ -173,6 +165,17 @@ public class ChatServiceImpl implements ChatService { for (ChatReference ref : references) { ref.setMessageId(messageId); ref.setCreateTime(LocalDateTime.now()); + + // 通过 collection 和 docName 查找 collection_file 的 id + String collection = ref.getCollection(); + String docName = ref.getDocName(); + if (collection != null && !collection.isEmpty() && docName != null && !docName.isEmpty()) { + CollectionFile collectionFile = collectionFileMapper.findByCollectionAndDocName(collection, docName); + if (collectionFile != null) { + ref.setFileId(collectionFile.getId()); + } + } + chatReferenceMapper.insert(ref); saved.add(ref); } @@ -190,365 +193,20 @@ public class ChatServiceImpl implements ChatService { @Override public List getSessionMessages(String sessionId) { - log.info("开始获取会话消息,sessionId={}", sessionId); - // 先通过 sessionId 查找会话,获取会话的 id LambdaQueryWrapper sessionWrapper = new LambdaQueryWrapper<>(); sessionWrapper.eq(ChatSession::getSessionId, sessionId); ChatSession session = chatSessionMapper.selectOne(sessionWrapper); if (session == null) { - log.warn("未找到会话,sessionId={}", sessionId); return new ArrayList<>(); } - log.info("找到会话,id={}, sessionId={}", session.getId(), sessionId); - // 然后通过会话 id 查找消息 LambdaQueryWrapper messageWrapper = new LambdaQueryWrapper<>(); messageWrapper.eq(ChatMessage::getConversationId, session.getId()) .orderByAsc(ChatMessage::getCreateTime); - List messages = chatMessageMapper.selectList(messageWrapper); - - log.info("查询到 {} 条消息", messages.size()); - - // 为每条消息关联查询引用信息并处理图片URL - for (ChatMessage message : messages) { - // 如果是AI助手消息,关联查询引用信息 - if ("assistant".equals(message.getRole())) { - List references = getMessageReferences(message.getId()); - log.info("消息 id={} 有 {} 条引用", message.getId(), references.size()); - - // 首先从 image 类型的引用中提取图片信息 - extractImagesFromReferences(message, references); - - // 将引用信息添加到消息中(通过sources字段扩展) - enrichMessageWithReferences(message, references); - } - - // 处理图片URL转换 - processImageUrls(message); - } - - log.info("会话消息处理完成,共 {} 条消息", messages.size()); - return messages; - } - - /** - * 从引用中提取 image 类型的图片信息,添加到消息的 images 字段 - */ - private void extractImagesFromReferences(ChatMessage message, List references) { - log.info("开始从引用中提取图片,messageId={}", message.getId()); - - try { - List> imagesList = new ArrayList<>(); - - // 如果消息已经有图片数据,先解析出来 - if (message.getImages() != null && !message.getImages().isEmpty()) { - imagesList = objectMapper.readValue( - message.getImages(), - new TypeReference>>() {} - ); - log.info("消息已有 {} 张图片", imagesList.size()); - } - - // 查找 chunkType 为 'image' 的引用 - for (ChatReference reference : references) { - if ("image".equals(reference.getChunkType())) { - log.info("找到 image 类型的引用: docName={}, page={}, chunkId={}", - reference.getDocName(), reference.getPage(), reference.getChunkId()); - - // 从 context_image 表中查找对应的图片 - List foundImages = imageService.findImagesByReference( - reference.getDocName(), - reference.getPage(), - reference.getChunkId() - ); - - if (foundImages != null && !foundImages.isEmpty()) { - log.info("从引用中找到 {} 张图片", foundImages.size()); - - for (Image image : foundImages) { - Map imageMap = new HashMap<>(); - imageMap.put("image_id", image.getImageId()); - imageMap.put("doc_name", image.getSource()); - imageMap.put("page", image.getPage()); - - // 检查是否已经有这个 image_id 的图片了,避免重复 - boolean alreadyExists = false; - for (Map existingImg : imagesList) { - if (image.getImageId().equals(existingImg.get("image_id"))) { - alreadyExists = true; - break; - } - } - - if (!alreadyExists) { - imagesList.add(imageMap); - log.info("添加图片到消息: imageId={}", image.getImageId()); - } - } - } else { - log.warn("未能从引用中找到对应的图片"); - } - } - } - - // 更新消息的 images 字段 - if (!imagesList.isEmpty()) { - String imagesJson = objectMapper.writeValueAsString(imagesList); - message.setImages(imagesJson); - log.info("成功更新消息的 images 字段,共 {} 张图片,数据: {}", - imagesList.size(), - imagesJson.substring(0, Math.min(300, imagesJson.length()))); - } - - } catch (IOException e) { - log.error("从引用中提取图片失败: messageId={}, error={}", message.getId(), e.getMessage(), e); - } - } - - /** - * 处理消息中的图片URL,转换为Nginx静态路径URL - */ - private void processImageUrls(ChatMessage message) { - log.info("开始处理图片URL,messageId={}, images={}", - message.getId(), - message.getImages() != null ? message.getImages().substring(0, Math.min(200, message.getImages().length())) : "null"); - - if (message.getImages() == null || message.getImages().isEmpty()) { - log.debug("消息没有图片数据,跳过处理"); - return; - } - - try { - List> images = objectMapper.readValue( - message.getImages(), - new TypeReference>>() {}); - - log.info("解析到 {} 张图片", images.size()); - - boolean updated = false; - for (int i = 0; i < images.size(); i++) { - Map image = images.get(i); - String imageId = (String) image.get("image_id"); - log.info("处理第 {} 张图片,imageId={}, 现有数据={}", - i + 1, imageId, image); - - if (imageId != null) { - String nginxUrl = findNginxImageUrl(imageId); - if (nginxUrl != null) { - image.put("url", nginxUrl); - updated = true; - log.info("✅ 成功转换图片URL: imageId={}, url={}", imageId, nginxUrl); - } else { - // 如果没有找到Nginx URL,提供一个回退URL - String fallbackUrl = getFallbackImageUrl(imageId); - image.put("url", fallbackUrl); - updated = true; - log.warn("⚠️ 使用回退图片URL: imageId={}, url={}", imageId, fallbackUrl); - } - } - } - - if (updated) { - String newImagesJson = objectMapper.writeValueAsString(images); - message.setImages(newImagesJson); - log.info("✅ 图片URL处理完成,更新后的数据: {}", - newImagesJson.substring(0, Math.min(300, newImagesJson.length()))); - } else { - log.info("没有需要更新的图片URL"); - } - } catch (IOException e) { - log.error("❌ 处理图片URL失败: {}", e.getMessage(), e); - } - } - - /** - * 获取回退的图片URL - */ - private String getFallbackImageUrl(String imageId) { - // 使用API接口作为回退方案 - return "/api/image/" + imageId + "/data"; - } - - /** - * 根据imageId查找本地图片,返回Nginx访问路径 - */ - private String findNginxImageUrl(String imageId) { - log.info("🔍 开始查找图片Nginx URL,imageId={}", imageId); - try { - // 从数据库查询图片记录 - log.debug("尝试查询原始imageId: {}", imageId); - Image image = imageService.getImageByImageId(imageId); - - // 如果没找到,尝试带.jpg后缀 - if (image == null && !imageId.toLowerCase().endsWith(".jpg")) { - String jpgImageId = imageId + ".jpg"; - log.debug("未找到,尝试带.jpg后缀: {}", jpgImageId); - image = imageService.getImageByImageId(jpgImageId); - } - - // 如果还没找到,尝试去掉后缀(如果有) - if (image == null) { - String imageIdWithoutExt = removeExtension(imageId); - if (!imageIdWithoutExt.equals(imageId)) { - log.debug("仍未找到,尝试去掉后缀: {}", imageIdWithoutExt); - image = imageService.getImageByImageId(imageIdWithoutExt); - } - } - - // 找到图片记录,提取文件名并构造Nginx URL - if (image != null) { - log.info("✅ 找到图片记录,imageId={}, 数据库ID={}, path={}", - imageId, image.getId(), image.getPath()); - - if (image.getPath() != null) { - String dbPath = image.getPath(); - - // 从路径中提取文件名 - String filename = extractFilenameFromPath(dbPath); - if (filename != null) { - // 构造Nginx URL: /files/img/{filename} - String nginxUrl = imageUrlPrefix + "img/" + filename; - log.info("✅ 成功构造Nginx URL: {}", nginxUrl); - return nginxUrl; - } else { - log.warn("⚠️ 无法从路径中提取文件名: {}", dbPath); - } - } else { - log.warn("⚠️ 图片记录中path字段为空"); - } - } else { - log.warn("⚠️ 数据库中未找到图片记录,imageId={}", imageId); - } - } catch (Exception e) { - log.error("❌ 查找图片Nginx URL失败: imageId={}, error={}", imageId, e.getMessage(), e); - } - - return null; - } - - /** - * 去掉文件名的扩展名 - */ - private String removeExtension(String filename) { - if (filename == null) { - return null; - } - int lastDotIndex = filename.lastIndexOf('.'); - if (lastDotIndex > 0) { - return filename.substring(0, lastDotIndex); - } - return filename; - } - - /** - * 从文件路径中提取文件名 - * 支持格式: /app/uploads/img/xxx.jpg 或 /opt/deploy/uploads/img/xxx.jpg - */ - private String extractFilenameFromPath(String path) { - if (path == null || path.isEmpty()) { - return null; - } - - try { - // 使用Paths处理路径,兼容不同操作系统的分隔符 - Path filePath = Paths.get(path); - return filePath.getFileName().toString(); - } catch (Exception e) { - log.debug("从路径提取文件名失败: path={}, error={}", path, e.getMessage()); - - // 备用方案:字符串分割 - try { - // 查找最后一个 / 或 \ - int lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); - if (lastSlash >= 0 && lastSlash < path.length() - 1) { - return path.substring(lastSlash + 1); - } - } catch (Exception ex) { - log.debug("备用方案提取文件名也失败: {}", ex.getMessage()); - } - } - - return null; - } - - /** - * 从图片URL中提取图片ID - * 支持的URL格式示例: - * - http://localhost:5001/images/dcbee1500209 - * - http://localhost:5001/images/dcbee1500209.jpg - */ - private String extractImageIdFromUrl(String url) { - if (url == null || url.isEmpty()) { - return null; - } - - try { - // 移除查询参数 - int queryIndex = url.indexOf('?'); - if (queryIndex > 0) { - url = url.substring(0, queryIndex); - } - - // 获取路径部分 - int pathStart = url.indexOf("/", 8); // 跳过 http:// 或 https:// - if (pathStart < 0) { - return null; - } - - String path = url.substring(pathStart); - - // 分割路径,获取最后一段 - String[] pathParts = path.split("/"); - if (pathParts.length >= 2) { - return pathParts[pathParts.length - 1]; - } - } catch (Exception e) { - log.debug("解析图片URL失败: url={}, error={}", url, e.getMessage()); - } - - return null; - } - - /** - * 将引用信息丰富到消息中 - */ - private void enrichMessageWithReferences(ChatMessage message, List references) { - if (references == null || references.isEmpty()) { - return; - } - - try { - // 获取现有的sources - List> sourcesList = new ArrayList<>(); - if (message.getSources() != null && !message.getSources().isEmpty()) { - sourcesList = objectMapper.readValue( - message.getSources(), - new TypeReference>>() {}); - } - - // 创建引用详情映射 - Map citationsMap = new HashMap<>(); - citationsMap.put("citations", references); - - // 如果sources为空,创建一个默认的sources列表 - if (sourcesList.isEmpty()) { - // 从引用中提取文档信息 - Map sourceInfo = new HashMap<>(); - sourceInfo.put("docName", "引用文档"); - sourceInfo.put("referenceCount", references.size()); - sourcesList.add(sourceInfo); - } - - // 更新sources字段,添加引用详情 - message.setSources(objectMapper.writeValueAsString(sourcesList)); - - // 不修改answer字段,保持原有内容(不添加引用来源列表) - } catch (IOException e) { - log.warn("丰富引用信息失败: {}", e.getMessage()); - } + return chatMessageMapper.selectList(messageWrapper); } @Override diff --git a/src/main/java/top/tqx/demo_1/service/impl/ExamPaperServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/ExamPaperServiceImpl.java index 58df176..3485524 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/ExamPaperServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/ExamPaperServiceImpl.java @@ -93,7 +93,7 @@ public class ExamPaperServiceImpl implements ExamPaperService { detail.setDifficulty(q.getDifficulty()); detail.setDifficultyName(getDifficultyName(q.getDifficulty())); detail.setScore(q.getScore()); - detail.setDocumentName(q.getDocumentName()); + detail.setDocumentName(q.getExcludeStems()); detail.setKnowledgeBasePath(q.getKnowledgeBasePath()); if (q.getContent() != null) { diff --git a/src/main/java/top/tqx/demo_1/service/impl/ExamRecordServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/ExamRecordServiceImpl.java index 1e9ccaa..6a11e1c 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/ExamRecordServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/ExamRecordServiceImpl.java @@ -12,8 +12,6 @@ import top.tqx.demo_1.entity.*; import top.tqx.demo_1.mapper.*; import top.tqx.demo_1.service.ExamRecordService; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import java.time.LocalDateTime; import java.util.*; import java.util.UUID; @@ -34,8 +32,6 @@ public class ExamRecordServiceImpl implements ExamRecordService { @Autowired private UserAnswerMapper userAnswerMapper; - - private final ObjectMapper objectMapper = new ObjectMapper(); @Override public List getUserPapers(Long userId, String answerType) { @@ -177,34 +173,44 @@ public class ExamRecordServiceImpl implements ExamRecordService { .map(ua -> { ExamRecordResponse.AnswerDetail detail = new ExamRecordResponse.AnswerDetail(); detail.setQuestionId(ua.getQuestionId()); - detail.setQuestionType(ua.getQuestionType()); + detail.setUserAnswer(convertUserAnswer(ua.getUserAnswer())); detail.setScore(ua.getScore()); - detail.setMaxScore(ua.getMaxScore()); detail.setIsCorrect(Boolean.TRUE.equals(ua.getIsCorrect())); detail.setFeedback(ua.getFeedback()); - - // 获取用户答案 - detail.setUserAnswer(ua.getUserAnswer()); - - // 从question表获取题目内容和正确答案 - Question question = questionMapper.selectOne( - new LambdaQueryWrapper().eq(Question::getQuestionId, ua.getQuestionId())); - if (question != null && question.getContent() != null) { - try { - ExamGradeRequest.QuestionContent content = - objectMapper.treeToValue(question.getContent(), ExamGradeRequest.QuestionContent.class); - detail.setStem(content.getStem()); - detail.setCorrectAnswer(content.getAnswer()); - } catch (Exception e) { - log.warn("解析题目内容失败: questionId={}", ua.getQuestionId(), e); - } - } - return detail; }) .collect(Collectors.toList()); } + private Object convertUserAnswer(com.fasterxml.jackson.databind.JsonNode userAnswer) { + if (userAnswer == null || userAnswer.isNull()) { + return null; + } + if (userAnswer.isTextual()) { + return userAnswer.asText(); + } + if (userAnswer.isNumber()) { + if (userAnswer.isInt()) { + return userAnswer.asInt(); + } + return userAnswer.asDouble(); + } + if (userAnswer.isBoolean()) { + return userAnswer.asBoolean(); + } + if (userAnswer.isArray()) { + List list = new java.util.ArrayList<>(); + for (com.fasterxml.jackson.databind.JsonNode node : userAnswer) { + list.add(convertUserAnswer(node)); + } + return list; + } + if (userAnswer.isObject()) { + return userAnswer; + } + return userAnswer.asText(); + } + @Override public PageResponse listRecords(String paperId, Integer page, Integer pageSize) { Page pageQuery = new Page<>(page, pageSize); diff --git a/src/main/java/top/tqx/demo_1/service/impl/ExamServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/ExamServiceImpl.java index 3f03635..fae472e 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/ExamServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/ExamServiceImpl.java @@ -22,6 +22,7 @@ import top.tqx.demo_1.mapper.ExamRecordMapper; import top.tqx.demo_1.mapper.QuestionMapper; import top.tqx.demo_1.mapper.UserAnswerMapper; import top.tqx.demo_1.mapper.CollectionFileMapper; +import top.tqx.demo_1.mapper.FileMapper; import top.tqx.demo_1.service.ExamService; import java.io.IOException; @@ -55,6 +56,25 @@ public class ExamServiceImpl implements ExamService { @Autowired private CollectionFileMapper collectionFileMapper; + + @Autowired + private FileMapper fileMapper; + + private String findFilePathByFileId(Long fileId) { + if (fileId == null) { + return null; + } + List collectionFiles = collectionFileMapper.selectList( + new LambdaQueryWrapper() + .eq(CollectionFile::getFileId, fileId) + .eq(CollectionFile::getStatus, 1)); + + if (!collectionFiles.isEmpty()) { + CollectionFile cf = collectionFiles.get(0); + return cf.getCollectionName() + "/" + cf.getDocName(); + } + return null; + } @Override public ExamGenerateResponse generateQuestions(ExamGenerateRequest request) throws IOException { @@ -63,9 +83,18 @@ public class ExamServiceImpl implements ExamService { aiApiConfig.getFullUrl(aiApiConfig.getExam().getGenerateSmart()) : aiApiConfig.getFullUrl(aiApiConfig.getExam().getGenerate()); + // 如果 filePath 为空,尝试通过 fileId 查询 + String filePath = request.getFilePath(); + if (filePath == null || filePath.isEmpty()) { + if (request.getFileId() != null) { + filePath = findFilePathByFileId(request.getFileId()); + log.info("通过 fileId 查询到 filePath: {}", filePath); + } + } + log.info("开始生成题目"); log.info("请求参数: requestId={}, fileId={}, filePath={}, questionTypes={}, difficulty={}", - request.getRequestId(), request.getFileId(), request.getFilePath(), + request.getRequestId(), request.getFileId(), filePath, request.getQuestionTypes(), request.getDifficulty()); log.info("使用API: {}", useSmartApi ? "智能生成" : "指定题型"); log.info("请求URL: {}", url); @@ -74,7 +103,35 @@ public class ExamServiceImpl implements ExamService { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - String jsonResponse = postJsonRequest(url, objectMapper.writeValueAsString(request), 120000); + // 构建发送给AI的请求体,exclude_stems由后端自动处理,不使用前端传入的值 + Map aiRequest = new HashMap<>(); + aiRequest.put("file_path", filePath); + + // 提取 collection 名称(从 filePath 中提取,格式为 collection_name/doc_name) + String collection = null; + if (filePath != null && filePath.contains("/")) { + collection = filePath.substring(0, filePath.indexOf("/")); + } + // 如果 request 中有 collectionName,优先使用 + if (request.getCollectionName() != null && !request.getCollectionName().isEmpty()) { + collection = request.getCollectionName(); + } + aiRequest.put("collection", collection); + + aiRequest.put("difficulty", request.getDifficulty()); + if (request.getQuestionTypes() != null) { + aiRequest.put("question_types", request.getQuestionTypes()); + } + // 只在exclude_stems有值时才传入(后端自动填充的) + if (request.getExcludeStems() != null && !request.getExcludeStems().isEmpty()) { + aiRequest.put("exclude_stems", request.getExcludeStems()); + log.info("发送 exclude_stems 到AI服务,共 {} 条", request.getExcludeStems().size()); + } + + // 打印实际发送的请求体 + String requestBody = objectMapper.writeValueAsString(aiRequest); + log.info("发送给AI服务的请求体: {}", requestBody); + String jsonResponse = postJsonRequest(url, requestBody, 120000); log.info("RAG服务响应: {}", jsonResponse); ExamGenerateResponse response = parseExamGenerateResponse(jsonResponse); @@ -83,7 +140,7 @@ public class ExamServiceImpl implements ExamService { if (Boolean.TRUE.equals(response.getSuccess()) && response.getQuestions() != null && !response.getQuestions().isEmpty()) { log.info("开始保存 {} 道题目到数据库", response.getQuestions().size()); - int savedCount = saveQuestionsToDatabase(response.getQuestions(), request.getFileId(), request.getCollectionName(), response.getSourceChunksUsed()); + int savedCount = saveQuestionsToDatabase(response.getQuestions(), request.getFileId(), request.getCollectionName(), response.getSourceChunksUsed(), request.getQuestionScores()); log.info("成功保存 {} 道题目到数据库", savedCount); } else { log.warn("未生成任何题目,无需保存"); @@ -104,6 +161,8 @@ public class ExamServiceImpl implements ExamService { request.getFileId(), request.getFilePath(), request.getQuestionTypes()); Map result = new HashMap<>(); + result.put("requestId", request.getRequestId()); + result.put("fileId", request.getFileId()); try { String collectionName = "test1"; @@ -111,27 +170,49 @@ public class ExamServiceImpl implements ExamService { String documentName = "1.docx"; if (request.getFileId() != null) { - log.info("根据 fileId 查询 collection_file 表: fileId={}", request.getFileId()); - - // 真正从数据库查询 collection_file 表 + log.info("根据 fileId 查询文件信息: fileId={}", request.getFileId()); + + // 先检查 File 表中的文件状态 + top.tqx.demo_1.entity.File file = fileMapper.selectById(request.getFileId()); + if (file == null) { + log.error("文件不存在: fileId={}", request.getFileId()); + result.put("fileMatchStatus", "FILE_NOT_FOUND"); + result.put("success", false); + result.put("message", "文件不存在: fileId=" + request.getFileId()); + return result; + } + + // 检查文件状态,status=0 表示已删除 + if (file.getStatus() != null && file.getStatus() == 0) { + log.error("文件已被删除: fileId={}, fileName={}", request.getFileId(), file.getFileName()); + result.put("fileMatchStatus", "FILE_DELETED"); + result.put("success", false); + result.put("message", "文件已被删除: fileId=" + request.getFileId()); + return result; + } + + // 检查 collection_file 表中是否存在该文件的记录(即是否已完成向量化) List collectionFiles = collectionFileMapper.selectList( new LambdaQueryWrapper() .eq(CollectionFile::getFileId, request.getFileId()) .eq(CollectionFile::getStatus, 1)); - + if (!collectionFiles.isEmpty()) { CollectionFile cf = collectionFiles.get(0); collectionName = cf.getCollectionName(); // 外部API需要的是向量库路径格式: collection_name/doc_name - // 而不是数据库中存储的服务器路径 filePath = collectionName + "/" + cf.getDocName(); documentName = cf.getDocName(); - log.info("查询到文件信息: collectionName={}, filePath={}, documentName={}", + log.info("查询到文件信息: collectionName={}, filePath={}, documentName={}", collectionName, filePath, documentName); } else { - log.warn("未在 collection_file 表中找到 fileId={} 的记录,使用默认值", request.getFileId()); + log.error("未在 collection_file 表中找到 fileId={} 的有效记录,文件可能未完成向量化", request.getFileId()); + result.put("fileMatchStatus", "NOT_VECTORIZED"); + result.put("success", false); + result.put("message", "文件未完成向量化处理,请先上传并等待向量化完成: fileId=" + request.getFileId()); + return result; } - + // 如果 request 中已经提供了,优先使用 request 中的值 if (request.getCollectionName() != null) { collectionName = request.getCollectionName(); @@ -140,7 +221,7 @@ public class ExamServiceImpl implements ExamService { filePath = request.getFilePath(); documentName = request.getFilePath(); } - + // 更新 request 对象,供后续调用使用 request.setCollection(collectionName); request.setFilePath(filePath); @@ -151,17 +232,16 @@ public class ExamServiceImpl implements ExamService { collectionName = request.getCollectionName(); } documentName = filePath; - + // 更新 request 对象,供后续调用使用 request.setCollection(collectionName); } else { + result.put("fileMatchStatus", "PARAM_MISSING"); result.put("success", false); result.put("message", "file_id 或 file_path 不能同时为空"); return result; } - result.put("requestId", request.getRequestId()); - result.put("fileId", request.getFileId()); result.put("fileMatchStatus", "success"); result.put("matchedCollection", collectionName); result.put("matchedFilePath", filePath); @@ -182,6 +262,11 @@ public class ExamServiceImpl implements ExamService { generateParams.put("question_types", request.getQuestionTypes()); } + if (request.getExcludeStems() != null && !request.getExcludeStems().isEmpty()) { + generateParams.put("exclude_stems", request.getExcludeStems()); + log.info("已添加 exclude_stems 参数,共 {} 条", request.getExcludeStems().size()); + } + result.put("aiRequestParams", generateParams); result.put("aiApiPath", apiPath); result.put("success", true); @@ -191,6 +276,7 @@ public class ExamServiceImpl implements ExamService { } catch (Exception e) { log.error("generateQuestionsWithFileId 异常: {}", e.getMessage(), e); + result.put("fileMatchStatus", "INTERNAL_ERROR"); result.put("success", false); result.put("message", "处理失败: " + e.getMessage()); return result; @@ -242,6 +328,9 @@ public class ExamServiceImpl implements ExamService { return response; } + // 转换填空题的 studentAnswer 格式:从嵌套列表转为字符串 + convertFillBlankAnswers(request); + try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -400,7 +489,7 @@ public class ExamServiceImpl implements ExamService { try { ExamGradeRequest.QuestionContent questionContent = objectMapper.treeToValue( question.getContent(), ExamGradeRequest.QuestionContent.class); - gradeItem.setQuestionContent(questionContent); + gradeItem.setContent(questionContent); } catch (Exception e) { log.warn("转换题目内容失败", e); } @@ -413,12 +502,12 @@ public class ExamServiceImpl implements ExamService { gradeItem.setMaxScore(new BigDecimal(5)); } - // 确保questionContent不为null,避免AI服务报错 - if (gradeItem.getQuestionContent() == null) { + // 确保content不为null,避免AI服务报错 + if (gradeItem.getContent() == null) { ExamGradeRequest.QuestionContent questionContent = new ExamGradeRequest.QuestionContent(); questionContent.setStem(""); questionContent.setAnswer(""); - gradeItem.setQuestionContent(questionContent); + gradeItem.setContent(questionContent); log.warn("题目内容为空,已设置默认值: questionId={}", saveItem.getQuestionId()); } @@ -530,24 +619,7 @@ public class ExamServiceImpl implements ExamService { } Boolean isCorrect = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect(); - - // 判断答题状态:0=错误,1=正确,2=半对 - Integer correctStatus; - if (Boolean.TRUE.equals(isCorrect)) { - correctStatus = 1; // 完全正确 - } else { - // 检查是否为半对(得分>0但<满分,适用于主观题) - BigDecimal score = result.getScore(); - BigDecimal maxScore = result.getMaxScore(); - if (score != null && maxScore != null && - score.compareTo(BigDecimal.ZERO) > 0 && - score.compareTo(maxScore) < 0) { - correctStatus = 2; // 半对 - } else { - correctStatus = 0; // 错误 - } - } - userAnswer.setIsCorrect(correctStatus); + userAnswer.setIsCorrect(Boolean.TRUE.equals(isCorrect) ? 1 : 0); userAnswer.setGradingType("ai"); userAnswer.setFeedback(result.getFeedback()); userAnswer.setCreatedAt(LocalDateTime.now()); @@ -576,6 +648,7 @@ public class ExamServiceImpl implements ExamService { for (ExamGradeResponse.GradeResult result : response.getResults()) { ExamRecordResponse.AnswerDetail detail = new ExamRecordResponse.AnswerDetail(); detail.setQuestionId(result.getQuestionId()); + detail.setUserAnswer(result.getStudentAnswer()); detail.setScore(result.getScore()); Boolean isCorrect = result.getCorrect() != null ? result.getCorrect() : result.getIsCorrect(); detail.setIsCorrect(isCorrect); @@ -732,7 +805,7 @@ public class ExamServiceImpl implements ExamService { paperQuestion.setContent(question.getContent()); paperQuestion.setScore(question.getScore() != null ? question.getScore() : new BigDecimal(5)); paperQuestion.setDifficulty(question.getDifficulty()); - paperQuestion.setDocumentName(question.getDocumentName()); + paperQuestion.setExcludeStems(question.getExcludeStems()); paperQuestion.setKnowledgeBasePath(question.getKnowledgeBasePath()); selectedQuestions.add(paperQuestion); } @@ -859,6 +932,14 @@ public class ExamServiceImpl implements ExamService { if (resultNode.has("max_score")) { result.setMaxScore(resultNode.get("max_score").decimalValue()); } + + // 新增:解析 grading_status + if (resultNode.has("grading_status")) { + result.setGradingStatus(resultNode.get("grading_status").asText()); + log.info("读取到 grading_status: {}", result.getGradingStatus()); + } + + // 先从顶层读取 correct(兼容旧格式) if (resultNode.has("correct")) { result.setCorrect(resultNode.get("correct").asBoolean()); } @@ -866,6 +947,51 @@ public class ExamServiceImpl implements ExamService { result.setIsCorrect(resultNode.get("is_correct").asBoolean()); } + // 解析 details(新格式) + if (resultNode.has("details")) { + com.fasterxml.jackson.databind.JsonNode detailsNode = resultNode.get("details"); + ExamGradeResponse.GradeResult.DetailInfo details = new ExamGradeResponse.GradeResult.DetailInfo(); + + if (detailsNode.has("correct")) { + details.setCorrect(detailsNode.get("correct").asBoolean()); + // 如果 details 中有 correct,覆盖顶层的值(新格式优先) + if (result.getCorrect() == null) { + result.setCorrect(details.getCorrect()); + } + } + if (detailsNode.has("student_answer")) { + details.setStudentAnswer(detailsNode.get("student_answer")); + } + if (detailsNode.has("correct_answer")) { + details.setCorrectAnswer(detailsNode.get("correct_answer")); + } + if (detailsNode.has("feedback")) { + details.setFeedback(detailsNode.get("feedback").asText()); + } + if (detailsNode.has("total_blanks")) { + details.setTotalBlanks(detailsNode.get("total_blanks").asInt()); + } + if (detailsNode.has("correct_blanks")) { + details.setCorrectBlanks(detailsNode.get("correct_blanks").asInt()); + } + if (detailsNode.has("error")) { + details.setError(detailsNode.get("error").asText()); + } + if (detailsNode.has("warnings")) { + com.fasterxml.jackson.databind.JsonNode warningsNode = detailsNode.get("warnings"); + if (warningsNode.isArray()) { + List warnings = new ArrayList<>(); + for (int j = 0; j < warningsNode.size(); j++) { + warnings.add(warningsNode.get(j).asText()); + } + details.setWarnings(warnings); + } + } + + result.setDetails(details); + log.info("已解析 details 结构"); + } + results.add(result); } @@ -893,7 +1019,30 @@ public class ExamServiceImpl implements ExamService { StringBuilder feedbackBuilder = new StringBuilder(); String questionType = result.getQuestionType(); - log.info("处理第 {} 题, 类型: {}", i + 1, questionType); + String gradingStatus = result.getGradingStatus(); + log.info("处理第 {} 题, 类型: {}, grading_status: {}", i + 1, questionType, gradingStatus); + + // 处理评分失败的情况 + if ("failed".equals(gradingStatus)) { + String errorMsg = "评分失败"; + if (result.getDetails() != null && result.getDetails().getError() != null) { + errorMsg = result.getDetails().getError(); + } else if (resultNode.has("details") && resultNode.get("details").has("error")) { + errorMsg = resultNode.get("details").get("error").asText(); + } + result.setFeedback("评分失败: " + errorMsg); + log.warn("第 {} 题评分失败: {}", i + 1, errorMsg); + continue; + } + + // 新格式:从 details 中获取 feedback + if (result.getDetails() != null && result.getDetails().getFeedback() != null) { + result.setFeedback(result.getDetails().getFeedback()); + log.info("从 details 中获取 feedback,长度: {}", result.getFeedback().length()); + continue; + } + + // 旧格式兼容:从 resultNode 中获取 feedback // 主观题处理 if ("subjective".equals(questionType) && resultNode.has("details")) { @@ -951,6 +1100,14 @@ public class ExamServiceImpl implements ExamService { else if ("fill_blank".equals(questionType)) { log.info("检测到填空题"); + // 根据得分判断是否正确 + BigDecimal score = result.getScore() != null ? result.getScore() : BigDecimal.ZERO; + BigDecimal maxScore = result.getMaxScore() != null ? result.getMaxScore() : BigDecimal.ZERO; + boolean isCorrect = score.compareTo(maxScore) >= 0; + result.setCorrect(isCorrect); + result.setIsCorrect(isCorrect); + log.info("填空题判定: score={}, maxScore={}, isCorrect={}", score, maxScore, isCorrect); + if (resultNode.has("feedback")) { feedbackBuilder.append(resultNode.get("feedback").asText()).append("\n"); } @@ -960,7 +1117,15 @@ public class ExamServiceImpl implements ExamService { if (correctAnswersNode.isArray()) { feedbackBuilder.append("【正确答案】\n"); for (int j = 0; j < correctAnswersNode.size(); j++) { - feedbackBuilder.append("第").append(j + 1).append("空: ").append(correctAnswersNode.get(j).asText()).append("\n"); + com.fasterxml.jackson.databind.JsonNode answerNode = correctAnswersNode.get(j); + // 处理嵌套列表格式 [["答案"]] + String answerText; + if (answerNode.isArray() && !answerNode.isEmpty()) { + answerText = answerNode.get(0).asText(); + } else { + answerText = answerNode.asText(); + } + feedbackBuilder.append("第").append(j + 1).append("空: ").append(answerText).append("\n"); } } } @@ -991,7 +1156,7 @@ public class ExamServiceImpl implements ExamService { } } - private int saveQuestionsToDatabase(List questions, Long fileId, String collectionName, Integer sourceChunksUsed) { + private int saveQuestionsToDatabase(List questions, Long fileId, String collectionName, Integer sourceChunksUsed, Map questionScores) { int savedCount = 0; for (ExamGenerateRequest.Question q : questions) { try { @@ -999,13 +1164,13 @@ public class ExamServiceImpl implements ExamService { question.setQuestionId(UUID.randomUUID().toString()); question.setQuestionType(q.getQuestionType()); question.setDifficulty(q.getDifficulty() != null ? q.getDifficulty() : 3); - question.setScore(q.getScore() != null ? q.getScore() : new BigDecimal("5.00")); + question.setScore(calculateScore(q.getQuestionType(), q.getScore(), questionScores)); question.setStatus("pending"); question.setDocumentId(fileId != null ? fileId.toString() : null); - question.setDocumentName(q.getContent() != null ? + question.setExcludeStems(q.getContent() != null ? (q.getContent().getStem() != null ? - (q.getContent().getStem().length() > 255 ? - q.getContent().getStem().substring(0, 255) : q.getContent().getStem()) : null) : null); + (q.getContent().getStem().length() > 500 ? + q.getContent().getStem().substring(0, 500) : q.getContent().getStem()) : null) : null); question.setKnowledgeBasePath(collectionName); question.setSourceContext(null); question.setSourceChunksUsed(sourceChunksUsed != null ? sourceChunksUsed : 0); @@ -1095,5 +1260,106 @@ public class ExamServiceImpl implements ExamService { return response; } + + /** + * 转换填空题的格式:从嵌套列表转为字符串 + * AI端期望: "student_answer": "答案内容", "answer": "答案内容" + * 当前格式: "student_answer": [["答案内容"]], "answer": [["答案内容"]] + */ + private void convertFillBlankAnswers(ExamGradeRequest request) { + if (request == null || request.getAnswers() == null) { + return; + } + + for (ExamGradeRequest.AnswerItem item : request.getAnswers()) { + if ("fill_blank".equals(item.getQuestionType())) { + // 转换 student_answer + if (item.getStudentAnswer() != null) { + Object studentAnswer = item.getStudentAnswer(); + if (!(studentAnswer instanceof String)) { + if (studentAnswer instanceof List) { + List answerList = (List) studentAnswer; + if (!answerList.isEmpty()) { + Object firstElement = answerList.get(0); + if (firstElement instanceof List) { + List innerList = (List) firstElement; + if (!innerList.isEmpty()) { + item.setStudentAnswer(innerList.get(0).toString()); + log.info("填空题 student_answer 转换: {} -> \"{}\"", studentAnswer, item.getStudentAnswer()); + } + } else { + item.setStudentAnswer(firstElement.toString()); + log.info("填空题 student_answer 转换: {} -> \"{}\"", studentAnswer, item.getStudentAnswer()); + } + } + } + } + } + + // 转换 question_content.answer + if (item.getContent() != null && item.getContent().getAnswer() != null) { + Object answer = item.getContent().getAnswer(); + if (!(answer instanceof String)) { + if (answer instanceof List) { + List answerList = (List) answer; + if (!answerList.isEmpty()) { + Object firstElement = answerList.get(0); + if (firstElement instanceof List) { + List innerList = (List) firstElement; + if (!innerList.isEmpty()) { + item.getContent().setAnswer(innerList.get(0).toString()); + log.info("填空题 answer 转换: {} -> \"{}\"", answer, item.getContent().getAnswer()); + } + } else { + item.getContent().setAnswer(firstElement.toString()); + log.info("填空题 answer 转换: {} -> \"{}\"", answer, item.getContent().getAnswer()); + } + } + } + } + } + } + } + } + + private BigDecimal calculateScore(String questionType, BigDecimal aiScore, Map questionScores) { + // 1. 优先使用AI返回的分数 + if (aiScore != null && aiScore.compareTo(BigDecimal.ZERO) > 0) { + log.debug("使用AI返回的分数: questionType={}, score={}", questionType, aiScore); + return aiScore; + } + + // 2. 其次使用请求中的配置分数 + if (questionScores != null && questionScores.containsKey(questionType)) { + BigDecimal configScore = questionScores.get(questionType); + log.debug("使用配置的题型分数: questionType={}, score={}", questionType, configScore); + return configScore; + } + + // 3. 最后使用默认分数 + return calculateDefaultScore(questionType); + } + + private BigDecimal calculateDefaultScore(String questionType) { + if (questionType == null) { + log.warn("questionType 为 null,使用默认分数 2.00"); + return new BigDecimal("2.00"); + } + switch (questionType) { + case "single_choice": + return new BigDecimal("2.00"); + case "multiple_choice": + return new BigDecimal("4.00"); + case "true_false": + return new BigDecimal("1.00"); + case "fill_blank": + return new BigDecimal("2.00"); + case "subjective": + return new BigDecimal("10.00"); + default: + log.warn("未知的 questionType: {},使用默认分数 5.00", questionType); + return new BigDecimal("5.00"); + } + } } diff --git a/src/main/java/top/tqx/demo_1/service/impl/FileServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/FileServiceImpl.java index 094071f..1159223 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/FileServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/FileServiceImpl.java @@ -114,7 +114,7 @@ public class FileServiceImpl extends ServiceImpl implements Fi @Override @Transactional(rollbackFor = Exception.class) - public FileVO uploadFile(MultipartFile file, Long userId, Long deptId, Integer userType, Long targetDeptId, Boolean isPublic) { + public FileVO uploadFile(MultipartFile file, Long userId, Long deptId, Integer userType, Long targetDeptId, Boolean isPublic, Boolean autoVectorize) { String originalFilename = file.getOriginalFilename(); if (originalFilename == null || originalFilename.isEmpty()) { throw new RuntimeException("文件名不能为空"); @@ -185,10 +185,10 @@ public class FileServiceImpl extends ServiceImpl implements Fi throw new RuntimeException("文件记录保存到数据库失败"); } - log.info("文件上传成功: fileName={}, userId={}, deptId={}, isPublic={}, category={}, auditStatus={}, path={}", - originalFilename, userId, finalDeptId, isPublicValue, fileCategory, auditStatus, relativePath); + log.info("文件上传成功: fileName={}, userId={}, deptId={}, isPublic={}, category={}, auditStatus={}, path={}, autoVectorize={}", + originalFilename, userId, finalDeptId, isPublicValue, fileCategory, auditStatus, relativePath, autoVectorize); - if (!needAudit) { + if (!needAudit && autoVectorize != null && autoVectorize) { String collectionName = determineCollectionName(userType, finalDeptId, isPublic); if (collectionName != null) { checkAndDeleteOldVectorization(originalFilename, finalDeptId, collectionName); @@ -199,8 +199,10 @@ public class FileServiceImpl extends ServiceImpl implements Fi log.warn("无法确定collection名称,跳过向量化: fileId={}, userType={}, deptId={}, isPublic={}", fileEntity.getId(), userType, finalDeptId, isPublic); } - } else { + } else if (needAudit) { log.info("文件需要审核,暂不向量化: fileId={}", fileEntity.getId()); + } else { + log.info("文件上传完成,未触发自定向量化(autoVectorize=false): fileId={}", fileEntity.getId()); } return convertToVO(fileEntity); @@ -806,14 +808,16 @@ public class FileServiceImpl extends ServiceImpl implements Fi String deptName = getDepartmentName(deptId); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(KnowledgeBasePath::getDepartment, deptName) - .or() - .eq(KnowledgeBasePath::getName, "dept_" + deptId + "_kb") + wrapper.and(w -> w.eq(KnowledgeBasePath::getDepartment, deptName) + .or() + .eq(KnowledgeBasePath::getName, "dept_" + deptId + "_kb")) .last("LIMIT 1"); KnowledgeBasePath kb = knowledgeBasePathMapper.selectOne(wrapper); if (kb != null) { + log.info("找到现有向量库: name={}, department={}", kb.getName(), kb.getDepartment()); return kb.getName(); } + log.info("未找到现有向量库,将创建新的: deptId={}, deptName={}", deptId, deptName); return "dept_" + deptId + "_kb"; } return "public_kb"; diff --git a/src/main/java/top/tqx/demo_1/service/impl/ImageServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/ImageServiceImpl.java index ce1df2f..02e9966 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/ImageServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/ImageServiceImpl.java @@ -3,7 +3,6 @@ package top.tqx.demo_1.service.impl; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import top.tqx.demo_1.config.AiApiConfig; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -40,12 +39,6 @@ public class ImageServiceImpl implements ImageService { @Autowired private ImageMapper imageMapper; - @Value("${file.upload.path:./uploads/}") - private String uploadPath; - - @Value("${file.upload.url-prefix:/files/}") - private String urlPrefix; - @Override public ImageListResponse getImageList(Integer limit, Integer offset) { String url = aiApiConfig.getFullUrl(aiApiConfig.getImages().getList()); @@ -107,17 +100,16 @@ public class ImageServiceImpl implements ImageService { } } - /** - * 尝试从本地获取图片 - * @param imageId 图片ID - * @return 图片字节数组,如果未找到返回null - */ - private byte[] tryGetLocalImage(String imageId) { + @Override + public byte[] getImage(String imageId) { + log.info("获取图片: imageId={}", imageId); + + // 1. 首先尝试从数据库查找本地路径 try { Image imageRecord = getImageByImageId(imageId); if (imageRecord != null && imageRecord.getPath() != null && !imageRecord.getPath().isEmpty()) { String dbPath = imageRecord.getPath(); - log.info("尝试从本地路径读取图片: imageId={}, path={}", imageId, dbPath); + log.info("尝试从本地路径读取图片: path={}", dbPath); // 方案1:如果数据库路径是完整路径且文件存在,直接使用 Path fullPath = Paths.get(dbPath); @@ -128,16 +120,7 @@ public class ImageServiceImpl implements ImageService { return imageBytes; } - // 方案2:如果数据库路径是相对路径,相对于 uploadPath - Path tryPath = Paths.get(uploadPath, dbPath); - if (Files.exists(tryPath)) { - byte[] imageBytes = Files.readAllBytes(tryPath); - log.info("从本地读取图片成功(相对路径): imageId={}, path={}, size={} bytes", - imageId, tryPath, imageBytes.length); - return imageBytes; - } - - // 方案3:兼容旧版代码,尝试其他可能的路径 + // 方案2:如果数据库路径是相对路径,尝试多种可能的完整路径 String filename = dbPath.startsWith("/img/") ? dbPath.substring(5) : dbPath; String[] possibleDirs = { "./img", @@ -147,11 +130,11 @@ public class ImageServiceImpl implements ImageService { }; for (String dir : possibleDirs) { - Path backupPath = Paths.get(dir, filename); - if (Files.exists(backupPath)) { - byte[] imageBytes = Files.readAllBytes(backupPath); + Path tryPath = Paths.get(dir, filename); + if (Files.exists(tryPath)) { + byte[] imageBytes = Files.readAllBytes(tryPath); log.info("从本地读取图片成功(遍历目录): imageId={}, path={}, size={} bytes", - imageId, backupPath, imageBytes.length); + imageId, tryPath, imageBytes.length); return imageBytes; } } @@ -159,48 +142,10 @@ public class ImageServiceImpl implements ImageService { log.warn("本地路径不存在,尝试过的路径: dbPath={}", dbPath); } } catch (Exception e) { - log.warn("从本地读取图片失败: imageId={}, error={}", imageId, e.getMessage(), e); - } - return null; - } - - @Override - public byte[] getImage(String imageId) { - log.info("获取图片: imageId={}", imageId); - - // 1. 首先尝试从数据库查找本地路径(先尝试原始ID) - byte[] localImage = tryGetLocalImage(imageId); - if (localImage != null) { - log.info("从本地获取图片成功: imageId={}", imageId); - return localImage; + log.warn("从本地读取图片失败: {}", e.getMessage()); } - // 2. 如果原始ID没找到,尝试添加.jpg后缀(数据库中存储的格式) - if (!imageId.toLowerCase().endsWith(".jpg")) { - localImage = tryGetLocalImage(imageId + ".jpg"); - if (localImage != null) { - log.info("从本地获取图片成功(带.jpg后缀): imageId={}", imageId); - return localImage; - } - } - - // 3. 如果带后缀也没找到,尝试去掉后缀(如果有) - if (imageId.toLowerCase().endsWith(".jpg") || imageId.toLowerCase().endsWith(".jpeg") || - imageId.toLowerCase().endsWith(".png") || imageId.toLowerCase().endsWith(".gif")) { - int lastDotIndex = imageId.lastIndexOf('.'); - if (lastDotIndex > 0) { - String imageIdWithoutExt = imageId.substring(0, lastDotIndex); - localImage = tryGetLocalImage(imageIdWithoutExt); - if (localImage != null) { - log.info("从本地获取图片成功(去掉后缀): imageId={}", imageId); - return localImage; - } - } - } - - log.warn("本地未找到图片,尝试从AI服务获取: imageId={}", imageId); - - // 4. 如果本地没有,从AI服务获取 + // 2. 如果本地没有,从AI服务获取 String url = aiApiConfig.getFullUrl(aiApiConfig.getImages().getImage()); // 去掉可能的文件后缀 @@ -222,10 +167,8 @@ public class ImageServiceImpl implements ImageService { return imageBytes; } catch (Exception e) { - log.error("调用RAG服务获取图片失败: imageId={}, error={}", imageId, e.getMessage()); - // 返回一个占位符或者空数组,而不是抛出异常,避免影响整个页面加载 - log.warn("返回空图片数据作为回退: imageId={}", imageId); - return new byte[0]; + log.error("调用RAG服务获取图片失败: {}", e.getMessage(), e); + throw new RuntimeException("获取图片失败: " + e.getMessage()); } } @@ -263,19 +206,12 @@ public class ImageServiceImpl implements ImageService { public Image createImage(ImageCreateRequest request) { Image image = new Image(); image.setImageId(request.getImageId()); - image.setFilename(request.getFilename()); image.setPath(request.getPath()); - image.setSizeBytes(request.getSizeBytes()); - image.setFormat(request.getFormat()); image.setSource(request.getSource()); image.setPage(request.getPage()); - image.setPageEnd(request.getPageEnd()); - image.setPageRange(request.getPageRange()); image.setSection(request.getSection()); image.setChunkType(request.getChunkType()); - image.setType(request.getType()); image.setDescription(request.getDescription()); - image.setFullDescription(request.getFullDescription()); image.setScore(request.getScore()); image.setCollection(request.getCollection()); image.setCreateTime(LocalDateTime.now()); @@ -297,18 +233,9 @@ public class ImageServiceImpl implements ImageService { throw new IllegalArgumentException("图片不存在"); } - if (request.getFilename() != null) { - image.setFilename(request.getFilename()); - } if (request.getPath() != null) { image.setPath(request.getPath()); } - if (request.getSizeBytes() != null) { - image.setSizeBytes(request.getSizeBytes()); - } - if (request.getFormat() != null) { - image.setFormat(request.getFormat()); - } if (request.getSource() != null) { image.setSource(request.getSource()); } @@ -414,8 +341,6 @@ public class ImageServiceImpl implements ImageService { ImageCreateRequest request = new ImageCreateRequest(); request.setImageId(imageId); - request.setFormat((String) imageInfo.get("format")); - request.setSizeBytes((Long) imageInfo.get("size_bytes")); request.setPath((String) imageInfo.get("url")); Image image = createImage(request); @@ -475,12 +400,8 @@ public class ImageServiceImpl implements ImageService { log.error("[{}] [{}] [数据转换阶段] 开始 - 构建ImageCreateRequest", java.time.LocalDateTime.now(), operationId); ImageCreateRequest request = new ImageCreateRequest(); - request.setImageId(imageId); // 数据库保存原始ID + request.setImageId(imageId); - if (imageMetadata.containsKey("type")) { - request.setType(String.valueOf(imageMetadata.get("type"))); - log.debug("[{}] [{}] [数据转换阶段] 设置type={}", java.time.LocalDateTime.now(), operationId, request.getType()); - } if (imageMetadata.containsKey("source")) { request.setSource(String.valueOf(imageMetadata.get("source"))); log.debug("[{}] [{}] [数据转换阶段] 设置source={}", java.time.LocalDateTime.now(), operationId, request.getSource()); @@ -494,14 +415,6 @@ public class ImageServiceImpl implements ImageService { } log.debug("[{}] [{}] [数据转换阶段] 设置page={}", java.time.LocalDateTime.now(), operationId, request.getPage()); } - if (imageMetadata.containsKey("page_end")) { - request.setPageEnd(String.valueOf(imageMetadata.get("page_end"))); - log.debug("[{}] [{}] [数据转换阶段] 设置page_end={}", java.time.LocalDateTime.now(), operationId, request.getPageEnd()); - } - if (imageMetadata.containsKey("page_range")) { - request.setPageRange(String.valueOf(imageMetadata.get("page_range"))); - log.debug("[{}] [{}] [数据转换阶段] 设置page_range={}", java.time.LocalDateTime.now(), operationId, request.getPageRange()); - } if (imageMetadata.containsKey("section")) { request.setSection(String.valueOf(imageMetadata.get("section"))); log.debug("[{}] [{}] [数据转换阶段] 设置section={}", java.time.LocalDateTime.now(), operationId, request.getSection()); @@ -511,11 +424,6 @@ public class ImageServiceImpl implements ImageService { log.debug("[{}] [{}] [数据转换阶段] 设置description={}", java.time.LocalDateTime.now(), operationId, request.getDescription() != null ? request.getDescription().substring(0, Math.min(50, request.getDescription().length())) + "..." : "null"); } - if (imageMetadata.containsKey("full_description")) { - request.setFullDescription(String.valueOf(imageMetadata.get("full_description"))); - log.debug("[{}] [{}] [数据转换阶段] 设置full_description长度={}", java.time.LocalDateTime.now(), operationId, - request.getFullDescription() != null ? request.getFullDescription().length() : 0); - } if (imageMetadata.containsKey("score")) { Object score = imageMetadata.get("score"); if (score instanceof Number) { @@ -529,24 +437,11 @@ public class ImageServiceImpl implements ImageService { } log.info("[{}] [{}] [数据转换阶段] 成功 - ImageCreateRequest构建完成", java.time.LocalDateTime.now(), operationId); - log.error("[{}] [{}] [图片信息获取阶段] 开始 - 调用AI服务获取图片元信息, finalImageId={}", java.time.LocalDateTime.now(), operationId, finalImageId); + log.error("[{}] [{}] [图片信息获取阶段] 开始 - 调用AI服务获取图片元信息, finalImageId={}", java.time.LocalDateTime.now(), operationId, imageId); Map aiImageInfo = getImageInfo(finalImageId); if (aiImageInfo != null) { - log.error("[{}] [{}] [图片信息获取阶段] 成功 - 获取到图片信息, format={}, size_bytes={}, width={}, height={}", - java.time.LocalDateTime.now(), operationId, - aiImageInfo.get("format"), aiImageInfo.get("size_bytes"), aiImageInfo.get("width"), aiImageInfo.get("height")); - - if (aiImageInfo.containsKey("format") && request.getFormat() == null) { - request.setFormat((String) aiImageInfo.get("format")); - log.debug("[{}] [{}] [图片信息获取阶段] 补充format={}", java.time.LocalDateTime.now(), operationId, request.getFormat()); - } - if (aiImageInfo.containsKey("size_bytes") && request.getSizeBytes() == null) { - Object sizeBytes = aiImageInfo.get("size_bytes"); - if (sizeBytes instanceof Number) { - request.setSizeBytes(((Number) sizeBytes).longValue()); - } - log.debug("[{}] [{}] [图片信息获取阶段] 补充size_bytes={}", java.time.LocalDateTime.now(), operationId, request.getSizeBytes()); - } + log.error("[{}] [{}] [图片信息获取阶段] 成功 - 获取到图片信息, metadata={}", + java.time.LocalDateTime.now(), operationId, aiImageInfo); } else { log.warn("[{}] [{}] [图片信息获取阶段] 警告 - 未能获取图片元信息, imageId={}", java.time.LocalDateTime.now(), operationId, imageId); @@ -562,12 +457,7 @@ public class ImageServiceImpl implements ImageService { String localPath = saveImageToLocal(imageId, imageData); if (localPath != null) { request.setPath(localPath); - log.error("[{}] [{}] [本地保存阶段] 成功 - 图片保存到本地, path={}", java.time.LocalDateTime.now(), operationId, localPath); - - if (request.getSizeBytes() == null) { - request.setSizeBytes((long) imageData.length); - log.debug("[{}] [{}] [本地保存阶段] 补充size_bytes={}", java.time.LocalDateTime.now(), operationId, request.getSizeBytes()); - } + log.error("[{}] [{}] [本地保存阶段] 成功 - 图片保存到本地, path={}, dataLength={}", java.time.LocalDateTime.now(), operationId, localPath, imageData.length); } else { log.error("[{}] [{}] [本地保存阶段] 警告 - 未能保存图片到本地, 将继续保存数据库记录", java.time.LocalDateTime.now(), operationId); } @@ -576,14 +466,13 @@ public class ImageServiceImpl implements ImageService { java.time.LocalDateTime.now(), operationId, imageId); } - log.error("[{}] [{}] [数据库写入前] 开始 - 准备写入数据库, imageId={}, request={}", - java.time.LocalDateTime.now(), operationId, imageId, - request.getImageId() + "," + request.getPath() + "," + request.getFormat()); + log.error("[{}] [{}] [数据库写入前] 开始 - 准备写入数据库, imageId={}, path={}", + java.time.LocalDateTime.now(), operationId, imageId, request.getPath()); Image image = createImage(request); - log.error("[{}] [{}] [数据库写入后] 成功 - 图片记录已保存到数据库, imageId={}, dbId={}, path={}, format={}, sizeBytes={}", - java.time.LocalDateTime.now(), operationId, imageId, image.getId(), image.getPath(), image.getFormat(), image.getSizeBytes()); + log.error("[{}] [{}] [数据库写入后] 成功 - 图片记录已保存到数据库, imageId={}, dbId={}, path={}", + java.time.LocalDateTime.now(), operationId, imageId, image.getId(), image.getPath()); long duration = System.currentTimeMillis() - startTime; log.error("[{}] [{}] ========== 图片保存流程成功完成, 耗时={}ms ==========", @@ -602,134 +491,87 @@ public class ImageServiceImpl implements ImageService { private String saveImageToLocal(String imageId, byte[] imageData) { try { - log.debug("[本地保存] 开始 - 准备保存图片到本地, imageId={}, dataSize={} bytes", - imageId, imageData.length); + log.debug("[{}] [本地保存] 开始 - 准备保存图片到本地, imageId={}, dataSize={} bytes", + java.time.LocalDateTime.now(), imageId, imageData.length); + // 使用系统临时目录或用户目录,避免权限问题 Path imgDir = getImageStorageDir(); + log.debug("[{}] [本地保存] 检查目录是否存在: path={}", java.time.LocalDateTime.now(), imgDir.toAbsolutePath()); if (!Files.exists(imgDir)) { + log.info("[{}] [本地保存] 创建图片目录: {}", java.time.LocalDateTime.now(), imgDir.toAbsolutePath()); Files.createDirectories(imgDir); } String filename = imageId; if (!filename.contains(".")) { filename = imageId + ".jpg"; + log.debug("[{}] [本地保存] 图片ID无扩展名, 添加.jpg后缀: {}", java.time.LocalDateTime.now(), filename); } Path filePath = imgDir.resolve(filename); + log.debug("[{}] [本地保存] 构建文件路径: {}", java.time.LocalDateTime.now(), filePath.toAbsolutePath()); - log.debug("[本地保存] 开始写入文件..."); + log.debug("[{}] [本地保存] 开始写入文件...", java.time.LocalDateTime.now()); Files.write(filePath, imageData); long fileSize = Files.size(filePath); - log.info("[本地保存] 成功 - 图片已保存到本地, path={}, size={} bytes", - filePath.toAbsolutePath(), fileSize); + log.info("[{}] [本地保存] 成功 - 图片已保存到本地, path={}, size={} bytes", + java.time.LocalDateTime.now(), filePath.toAbsolutePath(), fileSize); - // 构建相对路径(相对于 uploadPath),这样数据库里是 img/xxx.jpg - Path basePath = Paths.get(uploadPath); - String relativePath = basePath.relativize(filePath).toString().replace("\\", "/"); - log.debug("[本地保存] 返回相对路径: {}", relativePath); + // 返回相对路径格式:img/filename.jpg,便于前端拼接 URL + String relativePath = "img/" + filename; + log.debug("[{}] [本地保存] 返回相对路径: {}", java.time.LocalDateTime.now(), relativePath); return relativePath; } catch (java.io.IOException e) { - log.error("[本地保存] 失败 - IO异常, imageId={}, error={}", imageId, e.getMessage(), e); + log.error("[{}] [本地保存] 失败 - IO异常, imageId={}, error={}, stackTrace={}", + java.time.LocalDateTime.now(), imageId, e.getMessage(), + org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e)); return null; } catch (Exception e) { - log.error("[本地保存] 失败 - 未知异常, imageId={}, error={}", imageId, e.getMessage(), e); + log.error("[{}] [本地保存] 失败 - 未知异常, imageId={}, error={}, stackTrace={}", + java.time.LocalDateTime.now(), imageId, e.getMessage(), + org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e)); return null; } } private Path getImageStorageDir() { - // 使用配置的 uploadPath + /img 作为图片存储目录 - Path imgDir = Paths.get(uploadPath, "img"); - try { - if (!Files.exists(imgDir)) { - Files.createDirectories(imgDir); - log.info("[存储目录] 创建图片目录: {}", imgDir.toAbsolutePath()); - } - return imgDir; - } catch (Exception e) { - log.error("[存储目录] 无法创建图片目录, 使用临时目录, error={}", e.getMessage()); - // 回退到临时目录 - Path fallbackPath = Paths.get(System.getProperty("java.io.tmpdir")).resolve("img"); + String[] possibleDirs = { + "/app/img", + "/app/uploads/img", + "./img", + System.getProperty("user.home") + "/img", + System.getProperty("java.io.tmpdir") + "/img", + "/tmp/img" + }; + + for (String dir : possibleDirs) { + Path path = Paths.get(dir); try { - if (!Files.exists(fallbackPath)) { - Files.createDirectories(fallbackPath); + if (Files.exists(path)) { + if (Files.isWritable(path)) { + log.info("[{}] [存储目录] 找到可用目录: {}", java.time.LocalDateTime.now(), path.toAbsolutePath()); + return path; + } + } else { + Files.createDirectories(path); + log.info("[{}] [存储目录] 创建目录: {}", java.time.LocalDateTime.now(), path.toAbsolutePath()); + return path; } - return fallbackPath; - } catch (Exception ex) { - log.error("[存储目录] 无法创建任何目录, error={}", ex.getMessage()); - return Paths.get("/tmp"); + } catch (Exception e) { + log.warn("[{}] [存储目录检查] 目录不可用: {}, error={}", java.time.LocalDateTime.now(), dir, e.getMessage()); } } - } - - /** - * 根据图片ID获取Nginx格式的URL - * @param imageId 图片ID - * @return Nginx格式的URL,如果找不到则返回null - */ - public String getNginxUrlByImageId(String imageId) { + + Path fallbackPath = Paths.get(System.getProperty("java.io.tmpdir")).resolve("img"); try { - Image image = getImageByImageId(imageId); - if (image == null && !imageId.toLowerCase().endsWith(".jpg")) { - image = getImageByImageId(imageId + ".jpg"); - } - - if (image != null && image.getPath() != null) { - // 从 path 中提取文件名,格式是 img/xxx.jpg - String dbPath = image.getPath(); - String filename = extractFilenameFromPath(dbPath); - if (filename != null) { - return urlPrefix + "img/" + filename; - } - } + Files.createDirectories(fallbackPath); + log.warn("[{}] [存储目录] 使用临时目录: {}", java.time.LocalDateTime.now(), fallbackPath.toAbsolutePath()); + return fallbackPath; } catch (Exception e) { - log.warn("获取图片Nginx URL失败: imageId={}, error={}", imageId, e.getMessage()); + log.error("[{}] [存储目录] 无法创建任何目录, error={}", java.time.LocalDateTime.now(), e.getMessage()); + return Paths.get("/tmp"); } - return null; - } - - /** - * 从文件路径中提取文件名 - */ - private String extractFilenameFromPath(String path) { - if (path == null || path.isEmpty()) { - return null; - } - try { - Path filePath = Paths.get(path); - return filePath.getFileName().toString(); - } catch (Exception e) { - try { - int lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); - if (lastSlash >= 0 && lastSlash < path.length() - 1) { - return path.substring(lastSlash + 1); - } - } catch (Exception ex) { - log.warn("提取文件名失败: path={}", path); - } - } - return null; - } - - @Override - public List findImagesByReference(String docName, Integer page, String chunkId) { - log.info("查找与引用关联的图片: docName={}, page={}, chunkId={}", docName, page, chunkId); - - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 尝试通过 docName 和 page 查找 - if (docName != null && !docName.isEmpty()) { - queryWrapper.eq(Image::getSource, docName); - } - if (page != null) { - queryWrapper.eq(Image::getPage, page); - } - - List results = imageMapper.selectList(queryWrapper); - log.info("通过 docName 和 page 找到 {} 张图片", results != null ? results.size() : 0); - - return results != null ? results : new ArrayList<>(); } } \ No newline at end of file diff --git a/src/main/java/top/tqx/demo_1/service/impl/QuestionSaveServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/QuestionSaveServiceImpl.java index 4337bd6..9117001 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/QuestionSaveServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/QuestionSaveServiceImpl.java @@ -178,7 +178,10 @@ public class QuestionSaveServiceImpl implements QuestionSaveService { log.info("sources: {}", sourceTrace != null ? sourceTrace.getSources() : null); if (sourceTrace != null) { - entity.setDocumentName(sourceTrace.getDocumentName()); + // 存储题干内容,用于后续去重 + String stem = question.getContent() != null && question.getContent().getStem() != null ? + question.getContent().getStem() : null; + entity.setExcludeStems(stem); if (sourceTrace.getChunkIds() != null && !sourceTrace.getChunkIds().isEmpty()) { try { diff --git a/src/main/java/top/tqx/demo_1/service/impl/QuestionServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/QuestionServiceImpl.java index 27f23a5..000df11 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/QuestionServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/QuestionServiceImpl.java @@ -2,6 +2,7 @@ package top.tqx.demo_1.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; import top.tqx.demo_1.common.PageResult; import top.tqx.demo_1.dto.QuestionCreateRequest; import top.tqx.demo_1.dto.QuestionStatsRequest; @@ -29,12 +30,14 @@ import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +@Slf4j @Service public class QuestionServiceImpl extends ServiceImpl implements QuestionService { @@ -102,6 +105,8 @@ public class QuestionServiceImpl extends ServiceImpl i Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); + if (questionType != null && !questionType.isEmpty()) { wrapper.eq(Question::getQuestionType, questionType); } @@ -129,6 +134,7 @@ public class QuestionServiceImpl extends ServiceImpl i @Override public List getPendingQuestions() { return lambdaQuery() + .and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)) .eq(Question::getStatus, "pending") .orderByDesc(Question::getCreatedAt) .list(); @@ -154,7 +160,7 @@ public class QuestionServiceImpl extends ServiceImpl i question.setScore(calculateDefaultScore(request.getQuestionType())); } question.setDocumentId(request.getDocumentId()); - question.setDocumentName(request.getDocumentName()); + // excludeStems 存储题干内容,由 AI 出题时自动填充,这里不设置 question.setKnowledgeBasePath(request.getKnowledgeBasePath()); question.setSourceContext(request.getSourceContext()); if (request.getChunkIds() != null) { @@ -192,6 +198,35 @@ public class QuestionServiceImpl extends ServiceImpl i throw new IllegalArgumentException("题目不存在"); } + if (request.getScore() != null) { + BigDecimal maxScore = new BigDecimal("999.99"); + BigDecimal minScore = new BigDecimal("-999.99"); + if (request.getScore().compareTo(maxScore) > 0 || + request.getScore().compareTo(minScore) < 0) { + throw new IllegalArgumentException( + "分值超出范围,允许范围: " + minScore + " ~ " + maxScore); + } + } + + if (request.getKnowledgeBasePath() != null && + request.getKnowledgeBasePath().length() > 500) { + throw new IllegalArgumentException("知识库路径过长,最大允许500字符"); + } + + Set validTypes = Set.of( + "single_choice", "multiple_choice", "true_false", + "fill_blank", "subjective" + ); + if (request.getQuestionType() != null && + !validTypes.contains(request.getQuestionType())) { + throw new IllegalArgumentException( + "无效的题目类型: " + request.getQuestionType()); + } + + if (request.getContent() != null && request.getContent().isEmpty()) { + throw new IllegalArgumentException("题目内容不能为空"); + } + if (request.getQuestionType() != null) { question.setQuestionType(request.getQuestionType()); } @@ -216,9 +251,10 @@ public class QuestionServiceImpl extends ServiceImpl i if (request.getDocumentId() != null) { question.setDocumentId(request.getDocumentId()); } - if (request.getDocumentName() != null) { - question.setDocumentName(request.getDocumentName()); - } + // excludeStems 存储题干内容,由 AI 出题时自动填充,这里不设置 + // if (request.getDocumentName() != null) { + // question.setExcludeStems(request.getDocumentName()); + // } if (request.getKnowledgeBasePath() != null) { question.setKnowledgeBasePath(request.getKnowledgeBasePath()); } @@ -236,7 +272,12 @@ public class QuestionServiceImpl extends ServiceImpl i } question.setUpdatedAt(LocalDateTime.now()); - updateById(question); + boolean updated = updateById(question); + if (!updated) { + log.warn("题目更新影响行数为0,可能已被删除: id={}", id); + throw new IllegalStateException("题目可能已被删除或归档"); + } + return question; } @@ -254,6 +295,8 @@ public class QuestionServiceImpl extends ServiceImpl i public List listQuestions(String questionType, Integer difficulty, String status, String documentName, Integer limit, Long userId, Long deptId, Integer userType) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); + if (questionType != null && !questionType.isEmpty()) { wrapper.eq(Question::getQuestionType, questionType); } @@ -263,8 +306,9 @@ public class QuestionServiceImpl extends ServiceImpl i if (status != null && !status.isEmpty()) { wrapper.eq(Question::getStatus, status); } + // excludeStems 存储题干内容,用于AI去重和模糊搜索 if (documentName != null && !documentName.isEmpty()) { - wrapper.like(Question::getDocumentName, documentName); + wrapper.like(Question::getExcludeStems, documentName); } if (userType == 1) { @@ -331,6 +375,8 @@ public class QuestionServiceImpl extends ServiceImpl i private LambdaQueryWrapper buildStatsQueryWrapper(QuestionStatsRequest request) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); + if (request.getStatus() != null && !request.getStatus().isEmpty()) { wrapper.eq(Question::getStatus, request.getStatus()); } @@ -356,6 +402,7 @@ public class QuestionServiceImpl extends ServiceImpl i private Long countByType(String questionType, QuestionStatsRequest request) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Question::getQuestionType, questionType); + wrapper.and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); if (request.getStatus() != null && !request.getStatus().isEmpty()) { wrapper.eq(Question::getStatus, request.getStatus()); @@ -482,4 +529,78 @@ public class QuestionServiceImpl extends ServiceImpl i return result.toString(); } + + @Override + public int softDeleteByFileId(Long fileId) { + if (fileId == null) { + log.warn("软删除题目失败:fileId为空"); + return 0; + } + + String documentId = fileId.toString(); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Question::getDocumentId, documentId) + .and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); + + List questions = this.list(wrapper); + if (questions == null || questions.isEmpty()) { + log.info("未找到需要软删除的题目:documentId={}", documentId); + return 0; + } + + int count = 0; + for (Question question : questions) { + question.setIsDeleted(1); + String oldStatus = question.getStatus(); + question.setStatus("deprecated"); + question.setReviewerComment("文件向量化数据已被删除,题目自动标记为已废止"); + question.setUpdatedAt(LocalDateTime.now()); + boolean updated = this.updateById(question); + if (updated) { + count++; + log.debug("题目软删除并更新状态: id={}, questionId={}, status: {} -> deprecated", + question.getId(), question.getQuestionId(), oldStatus); + } + } + + log.info("题目软删除完成:documentId={}, 删除数量={}, 状态已更新为deprecated", documentId, count); + return count; + } + + @Override + public int softDeleteByDocumentName(String documentName) { + if (documentName == null || documentName.isEmpty()) { + log.warn("软删除题目失败:文档名为空"); + return 0; + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(Question::getKnowledgeBasePath, documentName) + .and(w -> w.isNull(Question::getIsDeleted).or().eq(Question::getIsDeleted, 0)); + + List questions = this.list(wrapper); + if (questions == null || questions.isEmpty()) { + log.info("未找到需要软删除的题目:documentName={}", documentName); + return 0; + } + + int count = 0; + for (Question question : questions) { + question.setIsDeleted(1); + String oldStatus = question.getStatus(); + question.setStatus("deprecated"); + question.setReviewerComment("文件向量化数据已被删除,题目自动标记为已废止"); + question.setUpdatedAt(LocalDateTime.now()); + boolean updated = this.updateById(question); + if (updated) { + count++; + log.debug("题目软删除并更新状态: id={}, questionId={}, status: {} -> deprecated", + question.getId(), question.getQuestionId(), oldStatus); + } + } + + log.info("题目软删除完成:documentName={}, 删除数量={}, 状态已更新为deprecated", documentName, count); + return count; + } } diff --git a/src/main/java/top/tqx/demo_1/service/impl/UserAnswerServiceImpl.java b/src/main/java/top/tqx/demo_1/service/impl/UserAnswerServiceImpl.java index 1786c6c..9d48d1d 100644 --- a/src/main/java/top/tqx/demo_1/service/impl/UserAnswerServiceImpl.java +++ b/src/main/java/top/tqx/demo_1/service/impl/UserAnswerServiceImpl.java @@ -17,10 +17,12 @@ import top.tqx.demo_1.entity.File; import top.tqx.demo_1.entity.Question; import top.tqx.demo_1.entity.UserAnswer; import top.tqx.demo_1.entity.WrongQuestionCollection; +import top.tqx.demo_1.entity.ExamRecord; import top.tqx.demo_1.mapper.FileMapper; import top.tqx.demo_1.mapper.QuestionMapper; import top.tqx.demo_1.mapper.UserAnswerMapper; import top.tqx.demo_1.mapper.WrongQuestionCollectionMapper; +import top.tqx.demo_1.mapper.ExamRecordMapper; import top.tqx.demo_1.service.UserAnswerService; import java.math.BigDecimal; @@ -45,6 +47,9 @@ public class UserAnswerServiceImpl implements UserAnswerService { @Autowired private WrongQuestionCollectionMapper wrongQuestionCollectionMapper; + @Autowired + private ExamRecordMapper examRecordMapper; + private final ObjectMapper objectMapper = new ObjectMapper(); @Override @@ -75,7 +80,29 @@ public class UserAnswerServiceImpl implements UserAnswerService { log.info("开始批量保存答题记录: count={}", userAnswers.size()); + // 批量查询所有题目ID是否存在 + Set questionIds = userAnswers.stream() + .map(UserAnswer::getQuestionId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + Map questionExistsMap = new HashMap<>(); + if (!questionIds.isEmpty()) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(Question::getQuestionId, questionIds); + List questions = questionMapper.selectList(queryWrapper); + for (Question q : questions) { + questionExistsMap.put(q.getQuestionId(), true); + } + } + for (UserAnswer ua : userAnswers) { + // 验证题目ID是否存在 + if (ua.getQuestionId() == null || !questionExistsMap.containsKey(ua.getQuestionId())) { + log.warn("题目ID不存在,跳过保存: questionId={}", ua.getQuestionId()); + continue; + } + // 先检查是否已存在该答题记录 UserAnswer existing = userAnswerMapper.selectOne( new LambdaQueryWrapper() @@ -115,16 +142,33 @@ public class UserAnswerServiceImpl implements UserAnswerService { queryWrapper.eq(UserAnswer::getUserId, request.getUserId()); } - if (request.getPaperId() != null && !request.getPaperId().isEmpty()) { - queryWrapper.eq(UserAnswer::getPaperId, request.getPaperId()); + String resolvedPaperId = request.getPaperId(); + + // 如果提供了 recordId 但没有 paperId,通过 ExamRecord 查找 paperId + if ((resolvedPaperId == null || resolvedPaperId.isEmpty()) + && request.getRecordId() != null && !request.getRecordId().isEmpty()) { + log.info("通过 recordId={} 查询 paperId", request.getRecordId()); + ExamRecord examRecord = examRecordMapper.selectOne( + new LambdaQueryWrapper() + .eq(ExamRecord::getRecordId, request.getRecordId())); + if (examRecord != null && examRecord.getPaperId() != null) { + resolvedPaperId = examRecord.getPaperId(); + log.info("recordId={} 对应 paperId={}", request.getRecordId(), resolvedPaperId); + } else { + log.warn("未找到 recordId={} 对应的考试记录", request.getRecordId()); + } + } + + if (resolvedPaperId != null && !resolvedPaperId.isEmpty()) { + queryWrapper.eq(UserAnswer::getPaperId, resolvedPaperId); } else if (request.getSessionId() != null && !request.getSessionId().isEmpty()) { queryWrapper.eq(UserAnswer::getSessionId, request.getSessionId()); } List userAnswers = userAnswerMapper.selectList(queryWrapper); if (CollectionUtils.isEmpty(userAnswers)) { - log.info("未找到答题记录: paperId={}, sessionId={}, userId={}", - request.getPaperId(), request.getSessionId(), request.getUserId()); + log.info("未找到答题记录: paperId={}, recordId={}, sessionId={}, userId={}", + resolvedPaperId, request.getRecordId(), request.getSessionId(), request.getUserId()); return response; } @@ -498,7 +542,7 @@ public class UserAnswerServiceImpl implements UserAnswerService { examQuestion.setDifficulty(question.getDifficulty()); examQuestion.setScore(question.getScore()); examQuestion.setContent(question.getContent()); - examQuestion.setDocumentName(question.getDocumentName()); + examQuestion.setExcludeStems(question.getExcludeStems()); examQuestion.setKnowledgeBasePath(question.getKnowledgeBasePath()); questions.add(examQuestion); usedQuestionIds.add(answer.getQuestionId()); @@ -598,7 +642,8 @@ public class UserAnswerServiceImpl implements UserAnswerService { File file = fileMap.get(question.getKnowledgeBasePath()); if (file != null) { - item.setDocumentName(file.getFileName()); + // 向后兼容,设置为文件名 + item.setExcludeStems(file.getFileName()); } } diff --git a/src/main/java/top/tqx/demo_1/vo/FileVO.java b/src/main/java/top/tqx/demo_1/vo/FileVO.java index 65f4b71..d559ba7 100644 --- a/src/main/java/top/tqx/demo_1/vo/FileVO.java +++ b/src/main/java/top/tqx/demo_1/vo/FileVO.java @@ -1,5 +1,6 @@ package top.tqx.demo_1.vo; +import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; import java.io.Serializable; @@ -57,4 +58,6 @@ public class FileVO implements Serializable { private String processStepStatus; private String processStepMessage; + + private JsonNode tags; } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 84e6693..55a4012 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -58,7 +58,7 @@ mybatis-plus: configuration: map-underscore-to-camel-case: true cache-enabled: true - log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl jwt: secret: ${JWT_SECRET:your-secret-key-for-jwt-token-generation-2024-change-in-production} @@ -95,8 +95,7 @@ cors: logging: level: - top.tqx.demo_1: DEBUG - top.tqx.demo_1.mapper: DEBUG + top.tqx.demo_1: INFO org.springframework.security: WARN pattern: console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index de60c3f..875955f 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -58,7 +58,7 @@ mybatis-plus: configuration: map-underscore-to-camel-case: true cache-enabled: true - log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl jwt: secret: ${JWT_SECRET:your-secret-key-for-jwt-token-generation-2024-change-in-production} @@ -95,7 +95,6 @@ cors: logging: level: top.tqx.demo_1: INFO - top.tqx.demo_1.mapper: DEBUG org.springframework.security: WARN pattern: console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9b0e6a6..46a1ada 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,4 +2,4 @@ spring: main: allow-circular-references: true profiles: - active: prod \ No newline at end of file + active: dev \ No newline at end of file diff --git a/文件/AIChatController_流程图.md b/文件/AIChatController_流程图.md deleted file mode 100644 index 18ad2c2..0000000 --- a/文件/AIChatController_流程图.md +++ /dev/null @@ -1,399 +0,0 @@ -# AIChatController 交互流程图 - -## 1. AI流式问答流程 (/ai/chat/stream) - -### 1.1 流程图 - -```mermaid -flowchart TD - A[开始: 用户发起AI问答] --> B{用户已登录?} - B -->|否| C[返回错误: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回错误: 用户信息获取失败] - D -->|是| F[获取部门信息] - F --> G[获取用户可访问知识库] - G --> H{知识库列表为空?} - H -->|是| I[返回错误: 没有可用的知识库] - H -->|否| J[获取或生成session_id] - J --> K[从数据库获取历史记录] - K --> L[调用AI服务进行流式问答] - L --> M[返回SseEmitter流式响应] - C --> N[结束] - E --> N - I --> N - M --> N -``` - -### 1.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant Dept as DepartmentService - participant KB as KnowledgeBasePathService - participant Chat as ChatService - participant AIChat as AiChatService - - Client->>+AI: POST /ai/chat/stream - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - AI->>+Dept: getDepartmentById(deptId) - Dept-->>-AI: Department - - AI->>+KB: getUserAccessibleKnowledgeBaseNames(userId, deptId, deptCode) - KB-->>-AI: List collections - - alt 知识库为空 - AI-->>Client: 错误: 没有可用的知识库 - end - - AI->>+Chat: getSessionMessagesAsHistory(sessionId) - Chat-->>-AI: List - - AI->>+AIChat: streamFromRagService(request, userId, deptId) - loop 流式响应 - AIChat-->>Client: SSE事件流 - end - AIChat-->>-AI: SseEmitter - - AI-->>-Client: SseEmitter流式响应 -``` - -### 1.3 流程说明 - -| 步骤 | 说明 | 代码位置 | -|------|------|----------| -| 1. 用户发起请求 | POST /ai/chat/stream | AIChatController:56 | -| 2. 验证登录状态 | 检查Authorization header | AIChatController:61-73 | -| 3. 验证用户信息 | validateToken获取用户 | AIChatController:75-87 | -| 4. 获取部门信息 | 根据deptId获取Department | AIChatController:94-104 | -| 5. 获取知识库列表 | getUserAccessibleKnowledgeBaseNames | AIChatController:106 | -| 6. 生成session_id | 无session_id时生成新的 | AIChatController:123-127 | -| 7. 获取历史记录 | getSessionMessagesAsHistory | AIChatController:134-140 | -| 8. 调用AI服务 | streamFromRagService | AIChatController:145 | - ---- - -## 2. 获取用户会话列表 (/ai/sessions) - -### 2.1 流程图 - -```mermaid -flowchart TD - A[开始: 获取会话列表] --> B{用户已登录?} - B -->|否| C[返回: success=false, 用户未登录] - B -->|是| D[获取用户所有会话] - D --> E[实现简单分页] - E --> F[返回会话列表及分页信息] - C --> G[结束] - F --> G -``` - -### 2.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant Chat as ChatService - - Client->>+AI: GET /ai/sessions - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - AI->>+Chat: getUserSessions(userId) - Chat-->>-AI: List - - Note over AI: 实现简单分页
计算start/end - - AI-->>-Client: 返回会话列表及分页信息 -``` - -### 2.3 流程说明 - -| 步骤 | 说明 | 代码位置 | -|------|------|----------| -| 1. 用户发起请求 | GET /ai/sessions | AIChatController:163 | -| 2. 验证登录状态 | getCurrentUserId | AIChatController:170-175 | -| 3. 获取会话列表 | chatService.getUserSessions | AIChatController:177 | -| 4. 分页处理 | 计算start/end | AIChatController:179-185 | -| 5. 返回结果 | 返回data/total/page等信息 | AIChatController:187-192 | - ---- - -## 3. 获取会话详情 (/ai/session/{sessionId}) - -### 3.1 流程图 - -```mermaid -flowchart TD - A[开始: 获取会话详情] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D[获取用户所有会话] - D --> E{会话属于当前用户?} - E -->|否| F[返回: 无权访问该会话] - E -->|是| G[获取会话消息列表] - G --> H[实现简单分页] - H --> I[返回会话详情及分页信息] - C --> J[结束] - F --> J - I --> J -``` - -### 3.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant Chat as ChatService - - Client->>+AI: GET /ai/session/{sessionId} - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - AI->>+Chat: getUserSessions(userId) - Chat-->>-AI: List - - Note over AI: 验证会话所属权 - - alt 会话不属于用户 - AI-->>Client: 错误: 无权访问该会话 - else 会话属于用户 - AI->>+Chat: getSessionMessages(sessionId) - Chat-->>-AI: List - Note over AI: 实现简单分页 - AI-->>-Client: 返回会话详情及分页信息 - end -``` - ---- - -## 4. 删除单个会话 (/ai/session/{sessionId}) - -### 4.1 流程图 - -```mermaid -flowchart TD - A[开始: 删除单个会话] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D[获取用户所有会话] - D --> E{会话属于当前用户?} - E -->|否| F[返回: 无权删除该会话] - E -->|是| G[执行删除操作] - G --> H{删除成功?} - H -->|是| I[返回: 删除成功] - H -->|否| J[返回: 删除失败] - C --> K[结束] - F --> K - I --> K - J --> K -``` - -### 4.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant Chat as ChatService - - Client->>+AI: DELETE /ai/session/{sessionId} - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - AI->>+Chat: getUserSessions(userId) - Chat-->>-AI: List - - Note over AI: 验证会话所属权 - - alt 会话不属于用户 - AI-->>Client: 错误: 无权删除该会话 - else 会话属于用户 - AI->>+Chat: deleteSession(sessionId, userId) - Chat-->>-AI: boolean success - alt 删除成功 - AI-->>Client: {success: true, message: "删除成功"} - else 删除失败 - AI-->>Client: {success: false, message: "删除失败"} - end - end -``` - ---- - -## 5. 批量删除会话 (/ai/sessions) - -### 5.1 流程图 - -```mermaid -flowchart TD - A[开始: 批量删除会话] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{sessionIds列表有效?} - D -->|否| E[返回: 会话ID列表不能为空] - D -->|是| F[获取用户所有会话] - F --> G[提取用户会话ID集合] - G --> H{所有会话属于用户?} - H -->|否| I[返回: 无权删除部分会话] - H -->|是| J[执行批量删除] - J --> K{删除成功?} - K -->|是| L[返回: 批量删除成功] - K -->|否| M[返回: 批量删除失败] - C --> N[结束] - E --> N - I --> N - L --> N - M --> N -``` - -### 5.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant Chat as ChatService - - Client->>+AI: DELETE /ai/sessions - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - alt sessionIds为空 - AI-->>Client: 错误: 会话ID列表不能为空 - end - - AI->>+Chat: getUserSessions(userId) - Chat-->>-AI: List - - Note over AI: 提取用户会话ID集合
验证所有会话属于用户 - - alt 部分会话不属于用户 - AI-->>Client: 错误: 无权删除部分会话 - else 所有会话属于用户 - AI->>+Chat: deleteSessions(sessionIds, userId) - Chat-->>-AI: boolean success - alt 删除成功 - AI-->>Client: {success: true, deletedCount: N} - else 删除失败 - AI-->>Client: {success: false, message: "批量删除失败"} - end - end -``` - ---- - -## 6. 中断AI流式问答 (/ai/chat/stop) - -### 6.1 流程图 - -```mermaid -flowchart TD - A[开始: 中断AI问答] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D[调用sseEmitterManager.stop] - D --> E{中断成功?} - E -->|是| F[返回: 已中断AI回答] - E -->|否| G[返回: 未找到活跃AI进程] - C --> H[结束] - F --> H - G --> H -``` - -### 6.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant AI as AIChatController - participant Auth as AuthService - participant SSE as SseEmitterManager - - Client->>+AI: POST /ai/chat/stop - AI->>+Auth: validateToken(token) - Auth-->>-AI: User对象 - - AI->>+SSE: stop(sessionId) - SSE-->>-AI: boolean success - - alt 中断成功 - AI-->>Client: {success: true, message: "已中断AI回答"} - else 中断失败 - AI-->>Client: {success: false, message: "未找到活跃的AI进程或已结束"} - end -``` - ---- - -## 核心服务调用关系 - -```mermaid -flowchart LR - subgraph Controller - AI[AIChatController] - end - - subgraph Service - AS[AuthService] - CS[ChatService] - ACS[AiChatService] - SS[SseEmitterManager] - KBS[KnowledgeBasePathService] - DS[DepartmentService] - end - - subgraph Entity - U[User] - D[Department] - CS1[ChatSession] - CM[ChatMessage] - CR[ChatReference] - end - - subgraph Database - DB[(MySQL)] - end - - AI --> AS - AI --> CS - AI --> ACS - AI --> SS - AI --> KBS - AI --> DS - - AS --> U - CS --> CS1 - CS --> CM - CS --> CR - KBS --> DB - DS --> U - DS --> D -``` - ---- - -## 接口汇总 - -| 接口 | 方法 | 路径 | 功能 | -|------|------|------|------| -| chatStream | POST | /ai/chat/stream | AI流式问答 | -| getUserSessions | GET | /ai/sessions | 获取用户会话列表 | -| getSessionDetail | GET | /ai/session/{sessionId} | 获取会话详情 | -| getMessageReferences | GET | /ai/message/{messageId}/references | 获取消息引用 | -| getSessionReferences | GET | /ai/session/{sessionId}/references | 获取会话引用 | -| deleteSession | DELETE | /ai/session/{sessionId} | 删除单个会话 | -| deleteSessions | DELETE | /ai/sessions | 批量删除会话 | -| stopChatStream | POST | /ai/chat/stop | 中断AI流式问答 | diff --git a/文件/FileController_流程图.md b/文件/FileController_流程图.md deleted file mode 100644 index 23dbcee..0000000 --- a/文件/FileController_流程图.md +++ /dev/null @@ -1,522 +0,0 @@ -# FileController 交互流程图 - -## 接口总览 - -| 接口 | 方法 | 路径 | 功能 | -|------|------|------|------| -| pageFiles | GET | /file/page | 分页查询文件 | -| getFileById | GET | /file/{id} | 查询文件详情 | -| uploadFile | POST | /file/upload | 上传文件 | -| ragStream | POST | /file/rag/stream | RAG流式问答 | -| downloadFile | GET | /file/download/{id} | 下载文件(已禁用) | -| getFileContent | GET | /file/content/{id} | 获取文件内容(已禁用) | -| getFileInfo | GET | /file/info/{id} | 获取文件详细信息 | -| deleteFile | DELETE | /file/{id} | 删除文件 | -| approveFile | POST | /file/audit/approve/{id} | 审核通过 | -| rejectFile | POST | /file/audit/reject/{id} | 审核拒绝 | -| getPendingFiles | GET | /file/audit/pending | 查询待审核文件列表 | -| updateFileInfo | PUT | /file/{id} | 更新文件信息 | - ---- - -## 1. 分页查询文件 (/file/page) - -### 1.1 流程图 - -```mermaid -flowchart TD - A[开始: 分页查询文件] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F[调用fileService.pageFiles] - F --> G[返回分页结果] - C --> H[结束] - E --> H - G --> H -``` - -### 1.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: GET /file/page - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - FC->>+FS: pageFiles(pageNum, pageSize, fileName, user) - FS-->>-FC: PageResult - - FC-->>-Client: 返回分页结果 -``` - ---- - -## 2. 查询文件详情 (/file/{id}) - -### 2.1 流程图 - -```mermaid -flowchart TD - A[开始: 查询文件详情] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F[调用fileService.getFileById] - F --> G[返回文件详情] - C --> H[结束] - E --> H - G --> H -``` - -### 2.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: GET /file/{id} - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - FC->>+FS: getFileById(id, user) - FS-->>-FC: FileVO - - FC-->>-Client: 返回文件详情 -``` - ---- - -## 3. 上传文件 (/file/upload) - -### 3.1 流程图 - -```mermaid -flowchart TD - A[开始: 上传文件] --> B[校验文件] - B --> C{文件校验通过?} - C -->|否| D[返回错误信息] - C -->|是| E{用户已登录?} - E -->|否| F[返回: 用户未登录] - E -->|是| G{用户信息获取成功?} - G -->|否| H[返回: 用户信息获取失败] - G -->|是| I[调用fileService.uploadFile] - I --> J{有文件描述?} - J -->|是| K[更新文件描述] - K --> L[返回FileVO] - J -->|否| L[返回FileVO] - D --> M[结束] - F --> M - H --> M - L --> M -``` - -### 3.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant FU as FileUtil - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: POST /file/upload - FC->>+FU: validateFile(file) - alt 文件校验失败 - FU-->>-FC: 抛出异常 - FC-->>Client: 返回错误信息 - end - - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - FC->>+FS: uploadFile(file, userId, deptId, userType, targetDeptId, isPublic) - FS-->>-FC: FileVO - - alt 有描述信息 - FC->>+FS: updateFileDescription(fileId, description) - FS-->>-FC: void - end - - FC-->>-Client: 返回FileVO -``` - ---- - -## 4. RAG流式问答 (/file/rag/stream) - -### 4.1 流程图 - -```mermaid -flowchart TD - A[开始: RAG流式问答] --> B{用户已登录?} - B -->|否| C[返回错误: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回错误: 用户信息获取失败] - D -->|是| F[设置collections为public_kb] - F --> G[生成session_id] - G --> H[调用aiChatService.streamFromRagService] - H --> I[返回SseEmitter流式响应] - C --> J[结束] - E --> J - I --> J -``` - -### 4.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant Auth as AuthService - participant AI as AiChatService - - Client->>+FC: POST /file/rag/stream - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - Note over FC: 设置collections
collections.add("public_kb")
生成session_id - - FC->>+AI: streamFromRagService(request, userId, deptId) - loop 流式响应 - AI-->>Client: SSE事件流 - end - AI-->>-FC: SseEmitter - - FC-->>-Client: SseEmitter流式响应 -``` - ---- - -## 5. 删除文件 (/file/{id}) - -### 5.1 流程图 - -```mermaid -flowchart TD - A[开始: 删除文件] --> B[调用fileService.deleteFile] - B --> C[返回成功] -``` - -### 5.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant FS as FileService - - Client->>+FC: DELETE /file/{id} - FC->>+FS: deleteFile(id) - FS-->>-FC: void - - FC-->>-Client: 返回成功 -``` - ---- - -## 6. 审核通过文件 (/file/audit/approve/{id}) - -### 6.1 流程图 - -```mermaid -flowchart TD - A[开始: 审核通过] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F{有管理员权限?} - F -->|否| G[返回: 无权限] - F -->|是| H[调用fileService.approveFile] - H --> I[返回成功] - C --> J[结束] - E --> J - G --> J - I --> J -``` - -### 6.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 管理员 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: POST /file/audit/approve/{id} - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - Note over FC: 检查userType==1或userType==2 - - alt 无管理员权限 - FC-->>Client: 返回: 无权限执行此操作 - else 有管理员权限 - FC->>+FS: approveFile(id, userId) - FS-->>-FC: void - FC-->>Client: 返回成功 - end -``` - ---- - -## 7. 审核拒绝文件 (/file/audit/reject/{id}) - -### 7.1 流程图 - -```mermaid -flowchart TD - A[开始: 审核拒绝] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F{有管理员权限?} - F -->|否| G[返回: 无权限] - F -->|是| H[调用fileService.rejectFile] - H --> I[返回成功] - C --> J[结束] - E --> J - G --> J - I --> J -``` - -### 7.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 管理员 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: POST /file/audit/reject/{id} - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - Note over FC: 检查userType==1或userType==2 - - alt 无管理员权限 - FC-->>Client: 返回: 无权限执行此操作 - else 有管理员权限 - FC->>+FS: rejectFile(id, userId) - FS-->>-FC: void - FC-->>Client: 返回成功 - end -``` - ---- - -## 8. 查询待审核文件列表 (/file/audit/pending) - -### 8.1 流程图 - -```mermaid -flowchart TD - A[开始: 查询待审核列表] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F{有管理员权限?} - F -->|否| G[返回: 无权限] - F -->|是| H[调用fileService.getPendingFiles] - H --> I[返回分页结果] - C --> J[结束] - E --> J - G --> J - I --> J -``` - -### 8.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 管理员 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - - Client->>+FC: GET /file/audit/pending - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - Note over FC: 检查userType==1或userType==2 - - alt 无管理员权限 - FC-->>Client: 返回: 无权限执行此操作 - else 有管理员权限 - FC->>+FS: getPendingFiles(pageNum, pageSize) - FS-->>-FC: PageResult - FC-->>Client: 返回分页结果 - end -``` - ---- - -## 9. 更新文件信息 (/file/{id}) - -### 9.1 流程图 - -```mermaid -flowchart TD - A[开始: 更新文件信息] --> B{用户已登录?} - B -->|否| C[返回: 用户未登录] - B -->|是| D{用户信息获取成功?} - D -->|否| E[返回: 用户信息获取失败] - D -->|是| F[获取原文件信息] - F --> G{文件存在?} - G -->|否| H[返回: 文件不存在] - G -->|是| I{isPublic变更?} - I -->|是| J[重建文件路径] - J --> K[移动文件到新路径] - K --> L[更新文件信息] - I -->|否| L[直接更新文件信息] - L --> M[返回更新后的文件] - C --> N[结束] - E --> N - H --> N - M --> N -``` - -### 9.2 时序图 - -```mermaid -sequenceDiagram - autonumber - participant Client as 用户 - participant FC as FileController - participant Auth as AuthService - participant FS as FileService - participant Dept as DepartmentService - participant UM as UserMapper - - Client->>+FC: PUT /file/{id} - FC->>+Auth: validateToken(token) - Auth-->>-FC: User对象 - - FC->>+FS: getFileEntityById(id) - FS-->>-FC: File对象 - - alt 文件不存在 - FC-->>Client: 返回: 文件不存在 - end - - alt isPublic变更 - FC->>+Dept: getDepartmentFullPath(deptId) - Dept-->>-FC: fullPath - - Note over FC: rebuildFilePath
创建新路径 - - FC->>FC: Files.move移动文件 - - FC->>+FS: updateFileEntity(file) - FS-->>-FC: void - else 仅更新描述 - FC->>+FS: updateFileEntity(file) - FS-->>-FC: void - end - - FC->>UM: selectById(uploadUserId) - UM-->>FC: User - - FC->>FC: convertToVO(file) - - FC-->>-Client: 返回FileVO -``` - ---- - -## 10. 已禁用的接口 - -### 10.1 下载文件 (/file/download/{id}) - -```mermaid -flowchart TD - A[开始: 下载文件] --> B[直接返回403 Forbidden] -``` - -### 10.2 获取文件内容 (/file/content/{id}) - -```mermaid -flowchart TD - A[开始: 获取文件内容] --> B[直接返回错误: 文件内容获取功能已禁用] -``` - ---- - -## 核心服务调用关系 - -```mermaid -flowchart LR - subgraph Controller - FC[FileController] - end - - subgraph Service - FS[FileService] - AI[AiChatService] - DS[DepartmentService] - end - - subgraph Util - FU[FileUtil] - end - - subgraph Mapper - UM[UserMapper] - end - - subgraph Entity - F[File] - U[User] - D[Department] - FV[FileVO] - end - - FC --> FS - FC --> AI - FC --> DS - FC --> FU - FC --> UM - - FS --> F - FS --> FV - DS --> D - UM --> U -``` - ---- - -## 权限说明 - -| 接口 | 普通用户 | 部门管理员 | 系统管理员 | -|------|---------|-----------|-----------| -| 分页查询文件 | ✅ | ✅ | ✅ | -| 查询文件详情 | ✅ | ✅ | ✅ | -| 上传文件 | ✅ | ✅ | ✅ | -| RAG流式问答 | ✅ | ✅ | ✅ | -| 下载文件 | ❌ 已禁用 | ❌ 已禁用 | ❌ 已禁用 | -| 获取文件内容 | ❌ 已禁用 | ❌ 已禁用 | ❌ 已禁用 | -| 获取文件信息 | ✅ | ✅ | ✅ | -| 删除文件 | - | - | - | -| 审核通过 | ❌ | ✅ | ✅ | -| 审核拒绝 | ❌ | ✅ | ✅ | -| 查询待审核列表 | ❌ | ✅ | ✅ | -| 更新文件信息 | ✅ | ✅ | ✅ | diff --git a/文件/出题做题生成流程示意图.md b/文件/出题做题生成流程示意图.md deleted file mode 100644 index 91ea472..0000000 --- a/文件/出题做题生成流程示意图.md +++ /dev/null @@ -1,542 +0,0 @@ -# 知识库管理系统 - 出题做题生成流程 - -## 文档信息 - -| 项目 | 内容 | -| -------- | ----------- | -| **文档名称** | 出题做题生成流程示意图 | -| **版本号** | V1.0.0 | -| **发布日期** | 2026-05-10 | - -*** - -## 一、整体流程概述 - -本系统的出题做题流程主要包含两大核心环节: - -1. **题目生成流程**:从文档中自动/手动生成题目,经过审核后进入题库 -2. **答题考试流程**:用户获取试卷、答题、提交、获得成绩 - -*** - -## 二、题目生成流程 - -### 2.1 流程图 - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ 题目生成流程 │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ 上传文档 │───▶│ 文件向量化 │───▶│ 题目生成 │ │ -│ │ (FileUpload) │ │ (Vectorize) │ │ (Generate) │ │ -│ └──────────────┘ └──────────────┘ └───────┬──────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────┐ │ -│ │ 题目审核 │ │ -│ │ (Review) │ │ -│ └───────┬──────┘ │ -│ ┌─┴─┐ │ -│ ▼ ▼ │ -│ ┌──────────┐ ┌──────────┐ │ -│ │ 审核通过 │ │ 审核拒绝 │ │ -│ │ Approved │ │ Rejected │ │ -│ └────┬─────┘ └────┬─────┘ │ -│ │ │ │ -│ ▼ ▼ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ 进入题库 │ │ 返回修改 │ │ -│ │ (Question │ │ (Modify) │ │ -│ │ Bank) │ └──────────────┘ │ -│ └──────┬───────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────┐ │ -│ │ 试卷生成 │ │ -│ │ (Paper │ │ -│ │ Generate) │ │ -│ └──────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -### 2.2 详细流程说明 - -| 步骤 | 阶段 | 接口 | 说明 | -| -- | ----- | ---------------------------------------- | ------------- | -| 1 | 文档上传 | `POST /api/file/upload` | 用户上传文档,保存到服务器 | -| 2 | 文件向量化 | `POST /api/collections/{name}/vectorize` | 将文档内容转换为向量存储 | -| 3 | 题目生成 | `POST /api/exam/generate` | 根据文档内容自动生成题目 | -| 4 | 题目审核 | `PUT /api/question/review/{questionId}` | 人工审核生成的题目 | -| 5 | 进入题库 | 自动 | 审核通过的题目进入题库 | -| 6 | 试卷生成 | `POST /api/exam/paper/generate` | 根据配置从题库生成试卷 | - -### 2.3 题目类型 - -| 类型 | 英文标识 | 说明 | -| --- | ---------------- | ------------ | -| 单选题 | single\_choice | 从选项中选择一个正确答案 | -| 多选题 | multiple\_choice | 从选项中选择多个正确答案 | -| 判断题 | true\_false | 判断陈述是否正确 | -| 填空题 | fill\_blank | 填写正确答案 | -| 简答题 | subjective | 主观题,需要文字回答 | - -*** - -## 三、答题考试流程 - -### 3.1 流程图 - -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ 答题考试流程 │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ 获取试卷列表 │───▶│ 选择试卷 │───▶│ 开始答题 │ │ -│ │ (My Papers) │ │ (Select) │ │ (Start) │ │ -│ └──────────────┘ └──────────────┘ └───────┬──────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────────────┐ │ -│ │ 答题界面 │ │ -│ │ (Answer) │ │ -│ └──────────┬─────────┘ │ -│ │ │ -│ ┌──────────┴─────────┐ │ -│ ▼ ▼ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ 保存答案 │ │ 提交试卷 │ │ -│ │ (Save) │ │ (Submit) │ │ -│ └──────────────┘ └───────┬──────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────┐ │ -│ │ AI批改答案 │ │ -│ │ (Grade) │ │ -│ └───────┬──────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────┐ │ -│ │ 显示成绩 │ │ -│ │ (Result) │ │ -│ └───────┬──────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────────┐ │ -│ │ 错题收集 │ │ -│ │ (Wrong Q) │ │ -│ └──────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` - -### 3.2 详细流程说明 - -| 步骤 | 阶段 | 接口 | 说明 | -| -- | ------ | ----------------------------------------- | ---------- | -| 1 | 获取试卷列表 | `GET /api/exam/my/papers` | 获取用户有权限的试卷 | -| 2 | 获取试卷详情 | `GET /api/exam/paper/{paperId}` | 获取试卷内容 | -| 3 | 开始答题 | `POST /api/exam/record/{recordId}/start` | 标记开始考试 | -| 4 | 保存答案 | `PUT /api/exam/record/{recordId}/save` | 保存单题答案 | -| 5 | 提交试卷 | `POST /api/exam/record/{recordId}/submit` | 提交全部答案 | -| 6 | AI批改 | 后台自动 | AI自动批改答案 | -| 7 | 获取结果 | `GET /api/exam/record/{recordId}/result` | 获取考试成绩 | -| 8 | 错题收集 | 自动 | 自动将错题加入错题本 | - -*** - -## 四、数据流向图 - -### 4.1 题目生成数据流向 - -``` -用户上传 ──▶ File表 ──▶ 向量库 ──▶ 题目生成 ──▶ Question表(待审核) - │ - ▼ - ┌─────────────────┐ - │ 审核流程 │ - └────────┬────────┘ - │ - ┌──────────────┴──────────────┐ - ▼ ▼ - Question表(已通过) Question表(已拒绝) - │ - ▼ - ExamPaper表(试卷) -``` - -### 4.2 答题数据流向 - -``` -ExamPaper表 ──▶ 用户答题 ──▶ UserAnswer表 ──▶ AI批改 ──▶ ExamRecord表 - │ - ▼ - WrongQuestion表 -``` - -*** - -## 五、状态流转 - -### 5.1 题目状态 - -``` -pending(待审核) - │ - ├─▶ approved(已通过) ──▶ 进入题库 - │ - └─▶ rejected(已拒绝) ──▶ 可重新编辑 -``` - -### 5.2 考试记录状态 - -``` -created(已创建) - │ - ▼ -started(进行中) - │ - ├─▶ submitted(已提交) - │ │ - │ ▼ - │ graded(已批改) - │ - └─▶ expired(已过期) -``` - -*** - -## 六、核心数据库表关系 - -``` -┌──────────┐ ┌───────────┐ ┌────────────┐ -│ File │ │ Question │ │ ExamPaper │ -├──────────┤ ├───────────┤ ├────────────┤ -│ id │ │ id │ │ id │ -│ fileName │◀──────│ fileId │◀───────│ questions │ -│ filePath │ │ content │ │ title │ -│ status │ │ status │ │ status │ -│ examStatus│ │ difficulty│ └────────────┘ -└──────────┘ └─────┬─────┘ - │ - ▼ - ┌──────────────┐ ┌────────────────┐ - │ UserAnswer │ │ ExamRecord │ - ├──────────────┤ ├────────────────┤ - │ questionId │◀───────│ id │ - │ answer │ │ paperId │ - │ isCorrect │ │ userId │ - │ score │ │ totalScore │ - └──────────────┘ └────────────────┘ -``` - -*** - -## 七、流程时序图 - -### 7.1 题目生成时序 - -``` -用户 FileController FileServiceImpl CollectionController - │ │ │ │ - │ 上传文件 │ │ │ - ├─────────────▶│ │ │ - │ │ 保存文件 │ │ - │ ├─────────────────▶│ │ - │ │ │ │ - │ 向量化 │ │ │ - ├─────────────▶│ │ 调用向量化接口 │ - │ │ ├───────────────────▶│ - │ │ │ │ - │ 生成题目 │ │ │ - ├─────────────▶│ │ 调用AI生成题目 │ - │ │ ├───────────────────▶│ - │ │ │ │ - │ 审核题目 │ │ │ - ├─────────────▶│ │ │ - │ │ 更新题目状态 │ │ - │ ├─────────────────▶│ │ - │ │ │ │ - │ ▼ ▼ ▼ -``` - -### 7.2 答题考试时序 - -``` -用户 UserExamController ExamServiceImpl QuestionMapper - │ │ │ │ - │ 获取试卷列表 │ │ │ - ├─────────────────▶│ │ │ - │ │ 查询数据库 │ │ - │ │ ├─────────────────▶│ - │ │ │ │ - │ │ 返回试卷列表 │ │ - │◀─────────────────┤ │ │ - │ │ │ │ - │ 开始答题 │ │ │ - ├─────────────────▶│ │ 创建考试记录 │ - │ │ ├─────────────────▶│ - │ │ │ │ - │ 保存答案 │ │ │ - ├─────────────────▶│ │ 保存答题记录 │ - │ │ ├─────────────────▶│ - │ │ │ │ - │ 提交试卷 │ │ │ - ├─────────────────▶│ │ AI批改答案 │ - │ │ ├─────────────────▶│ - │ │ │ │ - │ │ 返回考试结果 │ │ - │◀─────────────────┤ │ │ - │ │ │ │ - │ ▼ ▼ ▼ -``` - -*** - -## 八、关键业务规则 - -### 8.1 题目生成规则 - -| 规则 | 说明 | -| ------ | ------------------------------ | -| 文件状态检查 | 只有审核通过(auditStatus=1)的文件才能生成题目 | -| 难度等级 | 支持1-5级难度,1最简单,5最难 | -| 题目数量限制 | 每次生成最多100道题目 | -| 去重机制 | 相同内容的题目会被自动去重 | - -### 8.2 试卷生成规则 - -| 规则 | 说明 | -| ---- | ------------------- | -| 权限范围 | 只能选择用户有权限访问的知识库中的题目 | -| 题型配比 | 根据配置的题型数量分配题目 | -| 难度均衡 | 尽量均衡分布不同难度的题目 | -| 随机抽取 | 从题库中随机抽取题目组成试卷 | - -### 8.3 答题规则 - -| 规则 | 说明 | -| ---- | ------------ | -| 答题时间 | 每道题默认答题时间不限制 | -| 答案保存 | 支持自动保存和手动保存 | -| 提交限制 | 提交后不可修改答案 | -| 错题收集 | 自动收集错题到错题本 | - -*** - -**文档结束** - -
- -让我先查看考试相关的实体类和数据库表结构: - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\entity\ExamPaper.java - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\entity\ExamRecord.java - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\entity\ExamAssignment.java - -让我查看考试相关的Controller来了解完整流程: - -toolName: search\_by\_regex - -status: success - -query: AdminExamController - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\controller\AdminExamController.java - -让我查看ExamPaperService的实现来了解完整流程: - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\service\impl\ExamPaperServiceImpl.java - -让我查看用户考试相关的Controller和Service: - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\controller\UserExamController.java - -toolName: view\_files - -status: success - -filePath: d:\Users\19211\Desktop\demo\demo\src\main\java\top\tqx\demo\_1\service\impl\ExamRecordServiceImpl.java - -## 三张考试表的完整流程说明 - -### 一、表结构关系 - -| 表名 | 中文名称 | 核心作用 | -| :---------------- | :---- | :--------------------- | -| `exam_paper` | 试卷表 | 存储试卷的基本信息(标题、描述、题目列表等) | -| `exam_assignment` | 试卷分配表 | 记录试卷发布的范围(部门、用户) | -| `exam_record` | 考试记录表 | 记录每个用户的考试状态和答题情况 | - -### 二、完整业务流程 - -``` -┌─────────────────────────────────────────────────────────────────────────────┐ -│ 管理员端流程 │ -├─────────────────────────────────────────────────────────────────────────────┤ -│ 1. 预览试卷 → 2. 保存试卷 → 3. 发布试卷 │ -│ ↓ ↓ ↓ │ -│ 生成试卷内容 创建ExamPaper 更新状态为published │ -│ (不保存) status=draft 创建ExamAssignment │ -│ 创建ExamRecord(每个用户一条) │ -└─────────────────────────────────────────────────────────────────────────────┘ - ↓ -┌─────────────────────────────────────────────────────────────────────────────┐ -│ 用户端流程 │ -├─────────────────────────────────────────────────────────────────────────────┤ -│ 4. 查看试卷列表 → 5. 查看试卷内容 → 6. 开始考试 → 7. 保存答案 │ -│ ↓ ↓ ↓ ↓ │ -│ 查询ExamRecord 查询ExamPaper 更新status= 更新answers字段 │ -│ (属于自己的) 获取题目内容 in_progress 记录答题进度 │ -│ ↓ │ -│ 8. 提交试卷 → 9. 查看成绩 │ -│ ↓ ↓ │ -│ 调用AI批阅 查询ExamRecord │ -│ 保存到UserAnswer 和UserAnswer │ -│ 更新status= │ -│ submitted │ -└─────────────────────────────────────────────────────────────────────────────┘ -``` - -### 三、各步骤详解 - -#### 阶段一:管理员预览试卷 - -- **接口**:`POST /admin/exam/paper/preview` -- **操作**:根据条件动态生成试卷内容,**不保存到数据库** -- **目的**:让管理员在保存前预览试卷效果 - -#### 阶段二:管理员保存试卷 - -- **接口**:`POST /admin/exam/paper/save` -- **数据流向**: - ``` - ExamPaper (status=draft) - ↓ - exam_paper表 - ``` -- **关键字段**: - - `paper_id`:UUID唯一标识 - - `question_ids`:题目ID列表(JSON格式) - - `status`:`draft` - -#### 阶段三:管理员发布试卷 - -- **接口**:`POST /admin/exam/paper/{paperId}/publish` -- **数据流向**: - ``` - 1. 更新ExamPaper - status → published - publish_time → 当前时间 - deadline → 截止时间 - - 2. 创建ExamAssignment - paper_id → 试卷ID - dept_id / user_ids → 发布范围 - status → active - - 3. 创建ExamRecord(每个目标用户一条) - paper_id → 试卷ID - user_id → 用户ID - status → not_started - ``` - -#### 阶段四:用户查看试卷列表 - -- **接口**:`GET /exam/my/papers` -- **查询条件**:`user_id = 当前用户 AND status != revoked` - -#### 阶段五:用户查看试卷内容 - -- **接口**:`GET /exam/paper/{paperId}` -- **验证**:确保用户有该试卷的答题权限(检查ExamRecord存在) - -#### 阶段六:用户开始考试 - -- **接口**:`POST /exam/record/{recordId}/start` -- **状态变更**:`not_started` → `in_progress` -- **记录**:`start_time`、`last_active_time` - -#### 阶段七:用户保存答案 - -- **接口**:`PUT /exam/record/{recordId}/save` -- **操作**:将答案JSON序列化后存入`answers`字段 - -#### 阶段八:用户提交试卷 - -- **接口**:`POST /exam/record/{recordId}/submit` -- **数据流向**: - ``` - 1. 解析用户答案 → 调用AI批阅接口 - - 2. 保存到UserAnswer表(每题一条记录) - user_id, paper_id, question_id, score, is_correct, feedback - - 3. 更新ExamRecord - status → submitted - total_score → AI返回的总分 - submit_time / graded_time → 当前时间 - time_spent → 答题耗时(秒) - ``` - -#### 阶段九:用户查看成绩 - -- **接口**:`GET /exam/record/{recordId}/result` -- **数据来源**:ExamRecord(总分、状态)+ UserAnswer(每题详情) - -### 四、表关系图 - -``` -exam_paper (试卷表) - │ - ├── 1 : 1 → exam_assignment (分配表) - │ │ - │ └── 1 : N → exam_record (记录表) - │ │ - │ └── 1 : N → user_answer (答题记录表) - │ - └── 1 : N → question (题目表) via question_ids -``` - -### 五、状态流转 - -| 表 | 状态字段 | 状态值 | 说明 | -| :--------------- | :----- | :----------- | :--- | -| exam\_paper | status | draft | 草稿状态 | -|
|
| published | 已发布 | -| exam\_assignment | status | active | 有效分配 | -|
|
| revoked | 已撤销 | -| exam\_record | status | not\_started | 未开始 | -|
|
| in\_progress | 进行中 | -|
|
| submitted | 已提交 | -|
|
| revoked | 已撤销 | - diff --git a/文件/系统功能模块划分图.md b/文件/系统功能模块划分图.md deleted file mode 100644 index bf59311..0000000 --- a/文件/系统功能模块划分图.md +++ /dev/null @@ -1,328 +0,0 @@ -# 知识管理系统功能模块划分图 - -## 系统级功能结构图 - -```mermaid -flowchart TB - subgraph TOP["知识管理系统"] - subgraph Front["前台用户端"] - F1["用户认证"] - F2["文件管理"] - F3["题库管理"] - F4["AI对话"] - F5["个人中心"] - end - - subgraph Back["后台管理端"] - B1["用户管理"] - B2["部门管理"] - B3["权限管理"] - B4["文件审核"] - B5["日志管理"] - B6["系统配置"] - end - end -``` - ---- - -## 详细功能模块划分 - -### 第一层:系统层 - -| 模块名称 | 说明 | -|---------|------| -| 知识管理系统 | 整体系统名称 | - ---- - -### 第二层:前端/后端层 - -| 分类 | 说明 | -|------|------| -| 前台用户端 | 普通用户操作界面 | -| 后台管理端 | 管理员操作界面 | - ---- - -### 第三层:功能模块层 - -#### 前台用户端 - -| 模块 | 功能列表 | 控制器 | -|------|---------|--------| -| 用户认证 | 登录、注册、Token验证 | AuthController | -| 文件管理 | 文件上传、文件查询、文件下载、RAG问答 | FileController | -| 题库管理 | 题目查询、答题练习 | QuestionController | -| AI对话 | 流式问答、会话管理、引用查看 | AIChatController | -| 个人中心 | 个人信息管理 | UserController | - -#### 后台管理端 - -| 模块 | 功能列表 | 控制器 | -|------|---------|--------| -| 用户管理 | 用户CRUD、用户列表、用户详情 | UserController | -| 部门管理 | 部门CRUD、部门列表、部门详情 | DepartmentController | -| 权限管理 | 角色CRUD、权限分配、权限列表 | RoleController | -| 文件审核 | 待审核列表、审核通过、审核拒绝 | FileController | -| 日志管理 | 操作日志查询、日志详情 | LogController | -| 系统配置 | 知识库配置、系统参数 | - | - ---- - -## 模块调用关系图 - -```mermaid -flowchart LR - subgraph User["用户层"] - U1["普通用户"] - U2["部门管理员"] - U3["系统管理员"] - end - - subgraph Front["前台功能"] - F_AUTH["用户认证"] - F_FILE["文件管理"] - F_QUESTION["题库管理"] - F_AI["AI对话"] - end - - subgraph Back["后台功能"] - B_USER["用户管理"] - B_DEPT["部门管理"] - B_ROLE["权限管理"] - B_FILE["文件审核"] - B_LOG["日志管理"] - end - - subgraph Service["服务层"] - S_AUTH["AuthService"] - S_FILE["FileService"] - S_USER["UserService"] - S_DEPT["DepartmentService"] - S_ROLE["RoleService"] - S_CHAT["ChatService"] - S_AI["AiChatService"] - end - - subgraph Data["数据层"] - DB[("MySQL")] - KB[("知识库")] - end - - U1 --> F_AUTH - U1 --> F_FILE - U1 --> F_QUESTION - U1 --> F_AI - - U2 --> F_AUTH - U2 --> F_FILE - U2 --> B_DEPT - U2 --> B_FILE - - U3 --> F_AUTH - U3 --> B_USER - U3 --> B_DEPT - U3 --> B_ROLE - U3 --> B_FILE - U3 --> B_LOG - - F_AUTH --> S_AUTH - F_FILE --> S_FILE - F_AI --> S_AI - F_AI --> S_CHAT - - B_USER --> S_USER - B_DEPT --> S_DEPT - B_ROLE --> S_ROLE - B_FILE --> S_FILE - B_LOG --> S_FILE - - S_AUTH --> DB - S_FILE --> DB - S_USER --> DB - S_DEPT --> DB - S_ROLE --> DB - S_AI --> KB - S_CHAT --> DB -``` - ---- - -## 功能菜单树 - -``` -知识管理系统 -│ -├── 前台用户端 -│ ├── 用户认证 -│ │ ├── 用户登录 -│ │ ├── Token验证 -│ │ └── 退出登录 -│ │ -│ ├── 文件管理 -│ │ ├── 文件上传 -│ │ ├── 文件查询 -│ │ ├── 文件详情 -│ │ ├── 文件更新 -│ │ ├── 文件删除 -│ │ └── RAG问答 -│ │ -│ ├── 题库管理 -│ │ ├── 题目查询 -│ │ ├── 题目详情 -│ │ └── 答题练习 -│ │ -│ ├── AI对话 -│ │ ├── 流式问答 -│ │ ├── 会话列表 -│ │ ├── 会话详情 -│ │ ├── 引用查看 -│ │ ├── 会话删除 -│ │ └── 问答中断 -│ │ -│ └── 个人中心 -│ ├── 个人信息 -│ └── 修改密码 -│ -└── 后台管理端 - ├── 用户管理 - │ ├── 用户列表 - │ ├── 用户详情 - │ ├── 添加用户 - │ ├── 编辑用户 - │ └── 删除用户 - │ - ├── 部门管理 - │ ├── 部门列表 - │ ├── 部门详情 - │ ├── 添加部门 - │ ├── 编辑部门 - │ └── 删除部门 - │ - ├── 权限管理 - │ ├── 角色列表 - │ ├── 角色详情 - │ ├── 添加角色 - │ ├── 编辑角色 - │ ├── 删除角色 - │ ├── 权限列表 - │ └── 权限分配 - │ - ├── 文件审核 - │ ├── 待审核列表 - │ ├── 审核通过 - │ └── 审核拒绝 - │ - ├── 日志管理 - │ ├── 日志列表 - │ └── 日志详情 - │ - └── 系统配置 - ├── 知识库配置 - └── 参数设置 -``` - ---- - -## 接口权限矩阵 - -| 功能模块 | 普通用户 | 部门管理员 | 系统管理员 | -|---------|:-------:|:----------:|:----------:| -| **用户认证** | | | | -| 登录 | ✅ | ✅ | ✅ | -| 注册 | ✅ | ✅ | ✅ | -| **文件管理** | | | | -| 上传文件 | ✅ | ✅ | ✅ | -| 查询文件 | ✅ | ✅ | ✅ | -| 删除文件 | ✅ | ✅ | ✅ | -| RAG问答 | ✅ | ✅ | ✅ | -| **题库管理** | | | | -| 查询题目 | ✅ | ✅ | ✅ | -| 答题练习 | ✅ | ✅ | ✅ | -| **AI对话** | | | | -| 流式问答 | ✅ | ✅ | ✅ | -| 会话管理 | ✅ | ✅ | ✅ | -| **用户管理** | | | | -| 用户列表 | ❌ | ❌ | ✅ | -| 用户详情 | ❌ | ❌ | ✅ | -| 添加用户 | ❌ | ❌ | ✅ | -| 编辑用户 | ❌ | ❌ | ✅ | -| 删除用户 | ❌ | ❌ | ✅ | -| **部门管理** | | | | -| 部门列表 | ❌ | ✅ | ✅ | -| 部门详情 | ❌ | ✅ | ✅ | -| 添加部门 | ❌ | ❌ | ✅ | -| 编辑部门 | ❌ | ❌ | ✅ | -| 删除部门 | ❌ | ❌ | ✅ | -| **权限管理** | | | | -| 角色列表 | ❌ | ❌ | ✅ | -| 权限分配 | ❌ | ❌ | ✅ | -| **文件审核** | | | | -| 待审核列表 | ❌ | ✅ | ✅ | -| 审核通过 | ❌ | ✅ | ✅ | -| 审核拒绝 | ❌ | ✅ | ✅ | -| **日志管理** | | | | -| 日志列表 | ❌ | ❌ | ✅ | -| 日志详情 | ❌ | ❌ | ✅ | - ---- - -## 技术架构图 - -```mermaid -flowchart TB - subgraph Client["客户端层"] - WEB["Web浏览器"] - APP["移动App"] - API["第三方系统"] - end - - subgraph Gateway["网关层"] - GATEWAY["Spring Cloud Gateway"] - AUTH["认证中心"] - end - - subgraph Service["业务服务层"] - USER_SVC["用户服务"] - FILE_SVC["文件服务"] - AI_SVC["AI服务"] - CHAT_SVC["对话服务"] - QUESTION_SVC["题库服务"] - end - - subgraph Data["数据层"] - MYSQL["MySQL数据库"] - REDIS["Redis缓存"] - MINIO["MinIO对象存储"] - ES["Elasticsearch"] - end - - subgraph External["外部服务"] - LLM["大模型服务"] - RAG["RAG服务"] - end - - WEB --> GATEWAY - APP --> GATEWAY - API --> GATEWAY - - GATEWAY --> AUTH - AUTH --> USER_SVC - - GATEWAY --> USER_SVC - GATEWAY --> FILE_SVC - GATEWAY --> AI_SVC - GATEWAY --> CHAT_SVC - GATEWAY --> QUESTION_SVC - - USER_SVC --> MYSQL - USER_SVC --> REDIS - FILE_SVC --> MYSQL - FILE_SVC --> MINIO - AI_SVC --> LLM - AI_SVC --> RAG - CHAT_SVC --> MYSQL - CHAT_SVC --> ES - QUESTION_SVC --> MYSQL -``` diff --git a/测试11.txt b/测试11.txt deleted file mode 100644 index e69de29..0000000