Repository navigation
feat: error page #7923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: error page #7923
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <script setup lang="ts"> | ||
| defineOptions({ name: 'NotFoundPage' }) | ||
| </script> | ||
|
|
||
| <template> | ||
| <div class="flex-center mt-24"> | ||
| <div> | ||
| <img src="@/assets/error/404.png" width="250" alt="" /> | ||
| <h4 class="text-center">404</h4> | ||
| </div> | ||
| </div> | ||
| </template> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <template> | ||
| <div class="flex-center min-h-screen"> | ||
| <div> | ||
| <img src="@/assets/error/500.png" width="250" alt="" /> | ||
| <h4 class="text-center">暂时无法访问服务</h4> | ||
| </div> | ||
| </div> | ||
| </template> |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,30 @@ | ||
| <script setup lang="ts"> | ||
| import { watch } from 'vue' | ||
| import { computed, watch } from 'vue' | ||
| import { useRoute } from 'vue-router' | ||
| import NoService from '@/views/chat/error/NoService.vue' | ||
| import ConversationChat from '@/conversation-panel/view/chat/index.vue' | ||
| import { useStore } from '@/stores/chat' | ||
|
|
||
| defineOptions({ name: 'ChatApplication' }) | ||
|
|
||
| // 单应用对话:智能体 ID 与会话地址同步由对话面板 chat 模式处理,页面只加载侧栏所需的当前用户 | ||
| const { auth, user } = useStore() | ||
| const route = useRoute() | ||
| const unavailable = computed(() => auth.unavailablePath === route.fullPath) | ||
|
|
||
| // 当前用户随 token 变化:认证 Store 切换 token 时会清除用户档案,这里重新加载 | ||
| watch( | ||
| () => auth.token, | ||
| (token) => { | ||
| if (token && !user.chatUserProfile) user.loadCurrentUser() | ||
| [() => auth.token, unavailable], | ||
| ([token, serviceUnavailable]) => { | ||
| if (!serviceUnavailable && token && !user.chatUserProfile) user.loadCurrentUser() | ||
| }, | ||
| { immediate: true }, | ||
| ) | ||
| </script> | ||
|
|
||
| <template> | ||
| <main class="h-screen bg-white"> | ||
| <NoService v-if="unavailable" /> | ||
| <main v-else class="h-screen bg-white"> | ||
| <!-- token 变化(重新认证或登录)时重建面板,重新加载智能体与会话数据;token 清除后等待重新认证 --> | ||
| <ConversationChat v-if="auth.token" :key="auth.token" /> | ||
| </main> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code ReviewOverall the change is sound. Below are observations, potential issues, and suggestions. Correctness / Logic
Template / Rendering
Minor / Style
Suggested refined versionconst route = useRoute()
const isServiceUnavailable = computed(
() => auth.unavailablePath === route.path, // or normalized fullPath
)
watch(
() => [auth.token, isServiceUnavailable.value] as const,
async ([token, serviceUnavailable]) => {
if (serviceUnavailable || !token || user.chatUserProfile) return
try {
await user.loadCurrentUser()
} catch (err) {
console.error('[ChatApplication] failed to load current user', err)
}
},
{ immediate: true },
)Template: <template>
<main class="h-screen bg-white">
<NoService v-if="isServiceUnavailable" />
<ConversationChat
v-else-if="auth.token"
:key="auth.token"
/>
</main>
</template>Summary of priorities
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <script setup lang="ts"> | ||
| defineOptions({ name: 'NotFoundPage' }) | ||
| </script> | ||
|
|
||
| <template> | ||
| <div class="flex-center mt-24"> | ||
| <div> | ||
| <img src="@/assets/error/404.png" width="250" alt="" /> | ||
| <h4 class="text-center">404</h4> | ||
| </div> | ||
| </div> | ||
| </template> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <template> | ||
| <div class="flex-center mt-24"> | ||
| <div> | ||
| <img src="@/assets/error/500.png" width="250" alt="" /> | ||
| <h4 class="text-center">当前用户暂无权限访问,请联系管理员</h4> | ||
| </div> | ||
| </div> | ||
| </template> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <template> | ||
| <div class="flex-center mt-24"> | ||
| <div> | ||
| <img src="@/assets/error/500.png" width="250" alt="" /> | ||
| <h4 class="text-center">暂时无法访问服务</h4> | ||
| </div> | ||
| </div> | ||
| </template> |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,30 @@ | ||
| <script setup lang="ts"> | ||
| import { watch } from 'vue' | ||
| import { computed, watch } from 'vue' | ||
| import { useRoute } from 'vue-router' | ||
| import NoService from '@/views/chat/error/NoService.vue' | ||
| import PortalConversation from '@/conversation-panel/view/portal/index.vue' | ||
| import { useStore } from '@/stores/chat' | ||
|
|
||
| defineOptions({ name: 'PortalApplicationChat' }) | ||
|
|
||
| // 门户对话:智能体与会话地址同步由对话面板 portal 模式处理,页面只加载侧栏所需的当前用户 | ||
| const { auth, user } = useStore() | ||
| const route = useRoute() | ||
| const unavailable = computed(() => auth.unavailablePath === route.fullPath) | ||
|
|
||
| // 当前用户随 token 变化:认证 Store 切换 token 时会清除用户档案,这里重新加载 | ||
| watch( | ||
| () => auth.token, | ||
| (token) => { | ||
| if (token && !user.chatUserProfile) user.loadCurrentUser() | ||
| [() => auth.token, unavailable], | ||
| ([token, serviceUnavailable]) => { | ||
| if (!serviceUnavailable && token && !user.chatUserProfile) user.loadCurrentUser() | ||
| }, | ||
| { immediate: true }, | ||
| ) | ||
| </script> | ||
|
|
||
| <template> | ||
| <main class="h-screen bg-white"> | ||
| <NoService v-if="unavailable" /> | ||
| <main v-else class="h-screen bg-white"> | ||
| <!-- token 变化(重新认证或登录)时重建面板,重新加载智能体与会话数据;token 清除后等待重新认证 --> | ||
| <PortalConversation v-if="auth.token" :key="auth.token" /> | ||
| </main> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issues / irregularities:
Optimization suggestions:
Summary: Logic is sound; main risks are unhandled promise rejection and missing reload when only the route path leaves the unavailable state without token/profile changes. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review Findings
🔴 Potential Issues
1. Returning
trueallows navigation to a route that may not exist / shouldn't renderPreviously, on auth failure the code redirected to a dedicated 404 route. Now it sets
auth.unavailablePathand returnstrue, letting the original route proceed to render. If downstream components assume an authenticated user or valid app context, they may crash or leak internal error states. You rely entirely on some other component watchingunavailablePathto intercept rendering — this coupling is implicit and fragile.unavailablePathand renders an "unavailable" view instead of the normal component tree. Document this contract./service-unavailableroute as a fallback if no such guard exists.2. Mutating shared state (
auth.unavailablePath) inside a navigation guardWriting to global reactive state during
beforeEachcan cause race conditions with concurrent navigations. If two navigations happen in-flight, the second may overwriteunavailablePathset by the first.unavailablePathat the start ofbeforeEach(or when navigation resolves successfully), and consider using route meta / query to carry the reason instead of a shared mutable field.3.
to.fullPathmay include hash/query that leaks sensitive dataStoring the full path (including tokens in query, e.g.
accessToken) into persistent/reactive state could expose credentials in the UI or logs.to.path.4. Removed
getNotFoundRoute— confirm no other callersThe diff removes the helper but there might be other references elsewhere; ensure it's fully cleaned up (no dangling imports/usages).
🟡 Minor / Style
5. Inconsistent
replace: truehandlingIn the earlier block you use
{ ..., replace: true }for redirects, but when returningtruehere navigation semantics differ. Confirm whether prior history entries should be replaced to avoid "back button" returning to a broken page.6. Comment says "在原地址展示服务不可用页面" but code just returns
trueThe behavior described (render unavailable page at original URL) is not implemented in this diff — it depends on external logic. The comment overstates what the patch does; clarify.
🟢 Optimization
7. Duplicate auth-failure handling
The same
try/catch → set unavailablePath → return truepattern appears twice. Extract a small helper:8. Early
unavailablePathresetAdd
auth.unavailablePath = undefinednear the top ofbeforeEachso stale values don't persist across successful navigations.Summary
The main risk is that returning
trueon auth failure lets unauthenticated/failed-context requests reach application routes without an explicit render-intercept guarantee. Verify the consuming guard exists, sanitize stored paths, and reset shared state per-navigation.