From b6abb535703cb969804379b825fe846782306b46 Mon Sep 17 00:00:00 2001 From: Seven <1530011482@qq.com> Date: Wed, 30 Sep 2026 16:22:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E8=AF=B7=E6=B1=82=E7=9A=84=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E3=80=81=E6=8A=A5=E9=94=99=E6=8F=90=E7=A4=BA=E5=9C=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=83=A8=E5=88=86=E5=81=9A=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DESIGN.md | 4 ++-- src/pages/index/ChatPage.vue | 24 ++++++++++++------------ src/pages/login/LoginPage.vue | 6 +++--- src/pages/login/RegisterPage.vue | 2 +- src/utils/request.js | 32 +++++++++++++++++++++++++++++--- 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 9d1681a..318a687 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -193,8 +193,8 @@ HTTP 401 会清理认证状态并导航至登录页。用户主动退出会先 2. **认证状态持久性**:token 会持久化,但 username 不持久化;刷新后需由用户信息接口恢复展示状态。还应评估 localStorage 对 token 的安全取舍及 token 过期刷新方案。(username已删除,token问题待解决) 3. **WebSocket 健壮性**:当前没有断线重连、心跳、待发送队列或连接状态 UI;发送前应明确连接不可用的反馈,并评估 ACK 超时及重复消息处理。 4. **会话切换与分页状态**:`loadEnd` 等分页标志需要在联系人切换时明确重置;异步消息请求也应避免旧联系人响应覆盖新联系人视图。(已解决) -5. **实时会话一致性**:收到当前联系人消息时会更新消息区,但当前实现没有同步刷新最近会话预览;接收新消息的未读判断及空会话创建逻辑也值得通过业务用例确认。 -6. **响应契约与错误处理**:页面依赖响应中存在 `data` 字段。建议与服务端定义统一响应 DTO,并区分网络错误、认证错误、业务错误;当前错误主要由页面提示。 +5. **实时会话一致性**:收到当前联系人消息时会更新消息区,但当前实现没有同步刷新最近会话预览;接收新消息的未读判断及空会话创建逻辑也值得通过业务用例确认。(已解决) +6. **响应契约与错误处理**:页面依赖响应中存在 `data` 字段。建议与服务端定义统一响应 DTO,并区分网络错误、认证错误、业务错误;当前错误主要由页面提示。(已解决) 7. **UI 菜单与能力范围**:侧栏存在设置入口,但当前点击后主要改变菜单状态,未形成独立设置页;工具栏的表情和附件按钮也尚未绑定完整功能。 8. **移动端适配与无障碍**:聊天页最小宽度为 980px;联系人条目以鼠标点击交互为主。若支持移动设备或键盘操作,需补充响应式布局、语义按钮和焦点管理。 9. **自动化验证**:当前仓库配置了 lint/build 脚本,但未看到专门的单元测试或端到端测试。可优先为认证守卫、消息收发分流、未读计数和历史分页补充测试。 \ No newline at end of file diff --git a/src/pages/index/ChatPage.vue b/src/pages/index/ChatPage.vue index 2ea338e..811ac45 100644 --- a/src/pages/index/ChatPage.vue +++ b/src/pages/index/ChatPage.vue @@ -320,14 +320,14 @@ export default { getCurrentUser() { // 获取当前登录用户信息 getUserInfo() - .then((response) => { - this.currentUser = response.data; + .then((data) => { + this.currentUser = data; this.getRecentMessageList(); this.getContactList(); }) .catch((error) => { console.error(error); - this.$message.error("获取用户信息失败,请重新登录"); + this.$message.error(error.message); }); }, @@ -335,13 +335,13 @@ export default { getRecentMessageList() { if (!this.currentUser) return; getRecentMessages() - .then((response) => { - this.recentChats = response.data.recentChats || []; + .then((data) => { + this.recentChats = data.recentChats || []; this.selectFirstContact(); }) .catch((error) => { console.error(error); - this.$message.error("获取消息列表失败"); + this.$message.error(error.message); }); }, @@ -376,14 +376,14 @@ export default { async getContactMessageList(contactName, limit, offset) { try { // 获取当前联系人的消息列表 - const response = await getContactMessages({ + const data = await getContactMessages({ contactName: contactName, limit: limit, offset: offset, }); const contactMessages = []; - const messages = response.data.messages || []; + const messages = data.messages || []; messages.forEach((item) => { contactMessages.push({ ...item, @@ -399,22 +399,22 @@ export default { console.log("contactMessages", contactMessages); } catch (error) { console.error(error); - this.$message.error("获取消息列表失败"); + this.$message.error(error.message); } }, // 获取联系人列表 getContactList() { getContactInfo() - .then((response) => { - this.contactList = response.data.contacts.map((contact) => ({ + .then((data) => { + this.contactList = data.contacts.map((contact) => ({ ...contact, unreadCount: contact.unreadCount || 0, })); }) .catch((error) => { console.error(error); - this.$message.error("获取联系人信息失败"); + this.$message.error(error.message); }); }, diff --git a/src/pages/login/LoginPage.vue b/src/pages/login/LoginPage.vue index 888fc9e..e3b4f03 100644 --- a/src/pages/login/LoginPage.vue +++ b/src/pages/login/LoginPage.vue @@ -54,14 +54,14 @@ export default { username: this.username, password: this.password, }) - .then((response) => { - const token = response.data.token; + .then((data) => { + const token = data.token; this.$store.commit("SET_TOKEN", token); this.$router.push("/chat"); }) .catch((error) => { console.error(error); - this.$message.error("账号或密码错误"); + this.$message.error(error.message); }); } else { this.$message.error("请输入账号和密码"); diff --git a/src/pages/login/RegisterPage.vue b/src/pages/login/RegisterPage.vue index 43c9041..761ecad 100644 --- a/src/pages/login/RegisterPage.vue +++ b/src/pages/login/RegisterPage.vue @@ -69,7 +69,7 @@ export default { this.$router.push('/login') }).catch((error) => { console.error(error) - this.$message.error('注册失败,请重试') + this.$message.error(error.message) }) } } diff --git a/src/utils/request.js b/src/utils/request.js index e9d7a01..bd43cda 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -47,15 +47,41 @@ request.interceptors.request.use( request.interceptors.response.use( (response) => { - return response.data; + const result = response.data; + + // HTTP 请求成功,但业务失败 + if (result.code !== 200) { + return Promise.reject({ + type: "business", + message: result.message + }); + } + return result.data; }, (error) => { + if (!error.response) { + // 网络错误 + return Promise.reject({ + type: "network", + message: "网络连接失败,请检查网络" + }); + } + if (error.response && error.response.status === 401) { // 如果返回401,说明token过期或无效,清除token并跳转到登录页 store.commit('SET_TOKEN', ''); redirectToLogin(); - } - return Promise.reject(error); + + return Promise.reject({ + type: "auth", + message: "登录已过期,请重新登录" + }); + }; + + return Promise.reject({ + type: "server", + message: "服务器异常,请稍后重试" + }); } );