diff --git a/.trae/TODO.md b/.trae/TODO.md new file mode 100644 index 0000000..3846d80 --- /dev/null +++ b/.trae/TODO.md @@ -0,0 +1,7 @@ +# TODO: + +- [x] 1: 分析控制台输出,确定API返回数据的正确结构 (priority: High) +- [x] 2: 修复initChat方法中AI消息内容的数据映射 (priority: High) +- [x] 3: 修复loadMoreHistory方法中的数据映射 (priority: High) +- [x] 4: 移除调试代码,恢复正常UI显示 (priority: Medium) +- [x] 5: 测试修复后的AI消息显示功能 (priority: Medium) diff --git a/api/aiChat/ai_index.js b/api/aiChat/ai_index.js index 9a813c5..0391abe 100644 --- a/api/aiChat/ai_index.js +++ b/api/aiChat/ai_index.js @@ -1,38 +1,78 @@ -// src/api/index.js +// src/api/ai_index.js // import request from '@/utils/ai_request.js' -import request from "../../utils/ai_request"; +import request from "@/utils/ai_request.js"; // 获取历史 export const getHistory = ({ conversationId, user, - limit = 20 + limit = 20, + beforeId }) => { + const params = { + conversationId, + user, + limit + }; + + // 如果有beforeId参数,添加到请求中 + if (beforeId) { + params.beforeId = beforeId; + } + return request({ url: '/aitutor/aichat/getMessagesToUser', method: 'get', - params: { - conversationId, - user, - limit - } - // headers: { - // Authorization: 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjBmMTY3NmY2LTgwOGMtNGUwMC04NDJjLWIwNmY1ZTM5NzJlNCJ9.VVc6OwQ-Xn9pxzYbPhlCpvDp6TwESS00gJi9IXUEIbFw4RFACZDmYCYjQ7voTM4fppy9SAMJCWT-L7Uy-K1eqw' - // } + params }); }; + +// export const getHistory = ({ +// conversationId, +// user, +// limit = 20 +// }) => { +// return request({ +// url: '/aitutor/aichat/getMessagesToUser', +// method: 'get', +// params: { +// conversationId, +// user, +// limit +// } +// // headers: { +// // Authorization: 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjBmMTY3NmY2LTgwOGMtNGUwMC04NDJjLWIwNmY1ZTM5NzJlNCJ9.VVc6OwQ-Xn9pxzYbPhlCpvDp6TwESS00gJi9IXUEIbFw4RFACZDmYCYjQ7voTM4fppy9SAMJCWT-L7Uy-K1eqw' +// // } +// }); +// }; + // 点赞/点踩 action: 1 点赞 0 点踩 export const sendFeedback = ({ messageId, - action + action, + user }) => { return request({ - url: '/api/chat/feedback', + url: '/aitutor/aichat/feedback', method: 'post', data: { - messageId, - action + message_id: messageId, + rating: action === 1 ? 'like' : 'dislike', // 添加rating参数 + user } }); -}; \ No newline at end of file +}; +// export const sendFeedback = ({ +// messageId, +// action +// }) => { +// return request({ +// url: '/api/chat/feedback', +// method: 'post', +// data: { +// messageId, +// action +// } +// }); +// }; \ No newline at end of file diff --git a/components/aiChat/HistoryDrawer.vue b/components/aiChat/HistoryDrawer.vue index d8bd244..294c588 100644 --- a/components/aiChat/HistoryDrawer.vue +++ b/components/aiChat/HistoryDrawer.vue @@ -50,362 +50,350 @@ \ No newline at end of file diff --git a/pages/aiChat/ai_index.vue b/pages/aiChat/ai_index.vue index eb85b4b..51c19b0 100644 --- a/pages/aiChat/ai_index.vue +++ b/pages/aiChat/ai_index.vue @@ -1,8 +1,5 @@ - \ No newline at end of file diff --git a/static/scss/ai_index.css b/static/scss/ai_index.css index b3da404..ef69e80 100644 --- a/static/scss/ai_index.css +++ b/static/scss/ai_index.css @@ -8,7 +8,7 @@ width: 100%; overflow: hidden; position: relative; - background-color: #F5F5F5; + background-color: #f5f5f5; padding-top: 10px; /* 为固定导航栏预留空间 */ box-sizing: border-box; @@ -45,6 +45,7 @@ color: #333; text-align: center; flex: 1; + margin-right: 45px; } .nav-icon { @@ -166,7 +167,7 @@ background-color: #fff; border-top: 1px solid #eee; position: fixed; - bottom: 0; + bottom: -1px; left: 0; width: 100%; z-index: 10; @@ -260,10 +261,9 @@ padding-left: 1em; } - /* 可点击文档名 */ .doc-name-link { - color: #007AFF; + color: #007aff; text-decoration: underline; margin-right: 16rpx; font-size: 10rpx; @@ -301,7 +301,7 @@ } .doc-name-link { - color: #007AFF; + color: #007aff; text-decoration: underline; margin-right: 16rpx; font-size: clamp(13px, 3vw, 15px); @@ -344,6 +344,28 @@ transform: scale(0.95); } +.loading-history { + text-align: center; + padding: 20rpx; + color: #999; + font-size: 28rpx; +} + +.no-more-history { + text-align: center; + padding: 20rpx; + color: #ccc; + font-size: 24rpx; +} + +.debug-info { + color: #888; + font-size: 12px; + margin-top: 5px; + border-top: 1px dashed #eee; + padding-top: 5px; +} + /* ============= 小屏设备适配 ============= */ @media (max-width: 600px) { .message-content { diff --git a/utils/ai_request.js b/utils/ai_request.js index 35b6a55..6ed62ee 100644 --- a/utils/ai_request.js +++ b/utils/ai_request.js @@ -6,9 +6,13 @@ import { const service = axios.create({ // baseURL: 'http://localhost:9090/dev-api/aitutor/aichat', - baseURL: 'http://localhost:8088/aitutor/aichat', + // baseURL: 'http://localhost:8088/aitutor/aichat', // baseURL: 'http://localhost:8080/aitutor/aichat', + baseURL: 'http://localhost:8088', timeout: 15000, + headers: { + 'Content-Type': 'application/json' + } }) // 请求拦截器:统一加 token diff --git a/utils/ai_stream.js b/utils/ai_stream.js index e42ab93..ea8fd00 100644 --- a/utils/ai_stream.js +++ b/utils/ai_stream.js @@ -1,4 +1,4 @@ -// src/utils/ai_stream.js (H5 优化版) +// src/utils/ai_stream.js import { getToken } from '@/utils/auth'; @@ -23,7 +23,6 @@ export function createChatStream(params) { const fetchPromise = fetch(url, { method: 'POST', headers: { - 'Accept': 'text/event-stream', 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'X-Request-ID': requestId @@ -32,26 +31,27 @@ export function createChatStream(params) { query: params.prompt, user_id: params.userId, user_name: params.userName, - user_token: params.user_token || '123', + user_token: params.user_token || '123', user_role: 'student', - conversation_id: params.conversationId || null, + conversation_id: params.conversationId || null, }), signal: controller.signal }) - .then(resp => { - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - if (!resp.body) throw new Error('Response body is null'); - return resp.body; + .then(response => { + if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.body) throw new Error('Response body is null'); + return { + reader: response.body.getReader(), + decoder: new TextDecoder('utf-8') + }; }); - return fetchPromise.then(body => ({ - stream: Promise.resolve({ - reader: body.getReader(), - decoder: new TextDecoder('utf-8') - }), - cancel: reason => !controller.signal.aborted && controller.abort(reason) - })).catch(err => ({ - stream: Promise.reject(err), - cancel: () => {} - })); + return { + stream: fetchPromise, + cancel: (reason) => { + if (!controller.signal.aborted) { + controller.abort(reason); + } + } + }; } \ No newline at end of file