Skip to content

优化错误预览组件及相关内容 #2057

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

Merged
merged 2 commits into from
Jul 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions server/middleware/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func JWTAuth() gin.HandlerFunc {
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
token := utils.GetToken(c)
if token == "" {
response.NoAuth("未登录或非法访问", c)
response.NoAuth("未登录或非法访问,请登录", c)
c.Abort()
return
}
Expand All @@ -32,7 +32,7 @@ func JWTAuth() gin.HandlerFunc {
claims, err := j.ParseToken(token)
if err != nil {
if errors.Is(err, utils.TokenExpired) {
response.NoAuth("授权已过期", c)
response.NoAuth("登录已过期,请重新登录", c)
utils.ClearToken(c)
c.Abort()
return
Expand Down
58 changes: 30 additions & 28 deletions web/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
<template>
<div
id="app"
class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800"
>
<div id="app" class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800">
<el-config-provider :locale="zhCn">
<router-view />
<Application />
</el-config-provider>
</div>
</template>

<script setup>
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import { useAppStore } from '@/pinia'
useAppStore()
defineOptions({
name: 'App'
})
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import Application from '@/components/application/index.vue'
import { useAppStore } from '@/pinia'

useAppStore()
defineOptions({
name: 'App'
})
</script>
<style lang="scss">
// 引入初始化样式
#app {
height: 100vh;
overflow: hidden;
font-weight: 400 !important;
}
.el-button {
font-weight: 400 !important;
}
// 引入初始化样式
#app {
height: 100vh;
overflow: hidden;
font-weight: 400 !important;
}

.el-button {
font-weight: 400 !important;
}

.gva-body-h {
min-height: calc(100% - 3rem);
}

.gva-body-h {
min-height: calc(100% - 3rem);
}
.gva-container {
height: calc(100% - 2.5rem);
}

.gva-container {
height: calc(100% - 2.5rem);
}
.gva-container2 {
height: calc(100% - 4.5rem);
}
.gva-container2 {
height: calc(100% - 4.5rem);
}
</style>
1 change: 1 addition & 0 deletions web/src/assets/icons/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions web/src/assets/icons/idea.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions web/src/assets/icons/lock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions web/src/assets/icons/server.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions web/src/assets/icons/warn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions web/src/components/application/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<error-preview v-if="showError" :error-data="errorInfo" @close="handleClose" @confirm="handleConfirm" />
</template>

<script setup>
import { ref, onUnmounted } from 'vue'
import { emitter } from '@/utils/bus'
import ErrorPreview from '@/components/errorPreview/index.vue'

const showError = ref(false)
const errorInfo = ref(null)
let cb = null

const showErrorDialog = (data) => {
// 这玩意同时只允许存在一个
if(showError.value) return

errorInfo.value = data
showError.value = true
cb = data?.fn || null
}

const handleClose = () => {
showError.value = false
errorInfo.value = null
cb = null
}

const handleConfirm = (code) => {
cb && cb(code)
handleClose()
}

emitter.on('show-error', showErrorDialog)

onUnmounted(() => {
emitter.off('show-error', showErrorDialog)
})
</script>
126 changes: 126 additions & 0 deletions web/src/components/errorPreview/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<template>
<div
class="fixed inset-0 bg-black/40 flex items-center justify-center z-[999]"
@click.self="closeModal"
>
<div class="bg-white rounded-xl shadow-dialog w-full max-w-md mx-4 transform transition-all duration-300 ease-in-out">
<!-- 弹窗头部 -->
<div class="p-5 border-b border-gray-100 flex justify-between items-center">
<h3 class="text-lg font-semibold text-gray-800">{{ displayData.title }}</h3>
<button class="text-gray-400 hover:text-gray-600 transition-colors" @click="closeModal">
<close />
</button>
</div>

<!-- 弹窗内容 -->
<div class="p-6">
<!-- 错误类型 -->
<div class="mb-4">
<div class="text-xs font-medium text-gray-500 uppercase mb-2">错误类型</div>
<div class="flex items-center gap-2">
<lock v-if="displayData.icon === 'lock'" class="text-red-500 w-5 h-5" />
<warn v-if="displayData.icon === 'warn'" class="text-red-500 w-5 h-5" />
<server v-if="displayData.icon === 'server'" class="text-red-500 w-5 h-5" />
<span class="font-medium text-gray-800">{{ displayData.type }}</span>
</div>
</div>

<!-- 具体错误 -->
<div class="mb-6">
<div class="text-xs font-medium text-gray-500 uppercase mb-2">具体错误</div>
<div class="bg-gray-100 rounded-lg p-3 text-sm text-gray-700 leading-relaxed">
{{ displayData.message }}
</div>
</div>

<!-- 提示信息 -->
<div v-if="displayData.tips">
<div class="text-xs font-medium text-gray-500 uppercase mb-2">提示</div>
<div class="flex items-center gap-2">
<idea class="text-blue-500 w-5 h-5" />
<p class="text-sm text-gray-600">{{ displayData.tips }}</p>
</div>
</div>
</div>

<!-- 弹窗底部 -->
<div class="py-2 px-4 border-t border-gray-100 flex justify-end">
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium text-sm shadow-sm" @click="handleConfirm">
确定
</button>
</div>
</div>
</div>
</template>

<script setup>
import { defineProps, defineEmits, ref, computed, onMounted } from 'vue';

const props = defineProps({
errorData: {
type: Object,
required: true
}
});

const emits = defineEmits(['close', 'confirm']);

const presetErrors = {
500: {
title: '检测到接口错误',
type: '服务器发生内部错误',
icon: 'server',
color: 'text-red-500',
tips: '此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存'
},
404: {
title: '资源未找到',
type: 'Not Found',
icon: 'warn',
color: 'text-orange-500',
tips: '此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格'
},
401: {
title: '身份认证失败',
type: '身份令牌无效',
icon: 'lock',
color: 'text-purple-500',
tips: '您的身份认证已过期或无效,请重新登录。'
},
'network': {
title: '网络错误',
type: 'Network Error',
icon: 'fa-wifi-slash',
color: 'text-gray-500',
tips: '无法连接到服务器,请检查您的网络连接。'
}
};

const displayData = computed(() => {
const preset = presetErrors[props.errorData.code];
if (preset) {
return {
...preset,
message: props.errorData.message || '没有提供额外信息。'
};
}

return {
title: '未知错误',
type: '检测到请求错误',
icon: 'fa-question-circle',
color: 'text-gray-400',
message: props.errorData.message || '发生了一个未知错误。',
tips: '请检查控制台获取更多信息。'
};
});

const closeModal = () => {
emits('close')
};

const handleConfirm = () => {
emits('confirm', props.errorData.code);
closeModal();
};
</script>
2 changes: 1 addition & 1 deletion web/src/style/reset.scss
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ fieldset,
table,
th,
td {
border: none;
// border: none;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
font-size: 14px;
Expand Down
Loading