This commit is contained in:
itcsx committed 2026-09-22 15:59:05 +08:00
1 parent d5d4a6f3bf
commit fb1a79a3e9
27 files changed
+708 -75

No files matched your search

+51 -2
View File
@@ -1,2 +1,51 @@
<template>error 401</template>
<script setup lang="ts"></script>
<template>
<ErrorPanel code="401" badge="UNAUTHORIZED · 未认证" tone="blue" title="需要登录后才能访问"
description="你的登录状态已经失效,或者还没有登录。重新登录一次即可继续。" :reasons="reasons" :from="fromPath" hint="提示:登录后在其它设备退出登录,也会让当前设备失效。">
<template #icon>
<LockOutlined />
</template>
<template #actions>
<a-button type="primary" size="large" block @click="goLogin">
<template #icon><LoginOutlined /></template>
去登录
</a-button>
<a-button size="large" block @click="goBack">
<template #icon><ArrowLeftOutlined /></template>
返回上一页
</a-button>
</template>
</ErrorPanel>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ArrowLeftOutlined, LockOutlined, LoginOutlined } from "@ant-design/icons-vue";
import ErrorPanel from "@/components/basic/ErrorPanel.vue";
const route = useRoute();
const router = useRouter();
/** 出错的地址:由守卫/拦截器跳转时用 ?from= 带过来 */
const fromPath = computed(() =>
typeof route.query.from === "string" ? route.query.from : ""
);
const reasons = [
"登录已过期:长时间没有操作,或访问令牌到期",
"在其它设备或标签页退出了登录,当前设备随之失效",
"浏览器清理了本地数据(无痕模式、清理缓存、换浏览器)",
"管理员刚修改过你的账号信息(如密码、手机号)",
];
/** 去登录:带上原地址,登录成功后能直接回到这里 */
const goLogin = () => {
const redirect = fromPath.value || "/dashboard";
router.replace({ path: "/login", query: { redirect } });
};
const goBack = () => {
if (window.history.length > 1) router.back();
else router.replace("/login");
};
</script>
+49 -2
View File
@@ -1,2 +1,49 @@
<template>error 403</template>
<script setup lang="ts"> </script>
<template>
<ErrorPanel code="403" badge="FORBIDDEN · 无权限" tone="amber" title="你没有这个页面的访问权限"
description="账号是正常的,但你所在的角色/权限组没有被授予这个功能。" :reasons="reasons" :from="fromPath" hint="提示:权限由管理员分配,变更后需要重新登录才会生效。">
<template #icon>
<SafetyCertificateOutlined />
</template>
<template #actions>
<a-button type="primary" size="large" block @click="goRelogin">
<template #icon><LoginOutlined /></template>
重新登录
</a-button>
<a-button size="large" block @click="goHome">
<template #icon><HomeOutlined /></template>
返回首页
</a-button>
</template>
</ErrorPanel>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { HomeOutlined, LoginOutlined, SafetyCertificateOutlined } from "@ant-design/icons-vue";
import ErrorPanel from "@/components/basic/ErrorPanel.vue";
const route = useRoute();
const router = useRouter();
const fromPath = computed(() =>
typeof route.query.from === "string" ? route.query.from : ""
);
const reasons = [
"当前账号所属的角色 / 权限组没有该功能的权限",
"该功能还没在后台授权,虽然能看到入口但打不开",
"权限刚被调整过,浏览器里还是旧的权限数据",
"把别人的链接发给了你,而你的账号没有对应权限",
];
/** 重新登录:拿一次最新权限(权限变更后必须重登才生效) */
const goRelogin = () => {
router.replace({ path: "/login", query: fromPath.value ? { redirect: fromPath.value } : undefined });
};
/** 回首页:首页与菜单是匿名接口,即使没权限也能正常打开 */
const goHome = () => {
router.replace(router.hasRoute("dashboard") ? "/dashboard" : "/");
};
</script>
+49 -2
View File
@@ -1,2 +1,49 @@
<template>error 404</template>
<script setup lang="ts"> </script>
<template>
<ErrorPanel code="404" badge="NOT FOUND · 找不到页面" tone="violet" title="这个页面不存在"
description="地址可能写错了,或者对应的页面已经不在系统里。" :reasons="reasons" :from="fromPath" hint="提示:没有权限的功能不会出现在菜单里,地址直接打开也会落到这里。">
<template #icon>
<CompassOutlined />
</template>
<template #actions>
<a-button type="primary" size="large" block @click="goHome">
<template #icon><HomeOutlined /></template>
返回首页
</a-button>
<a-button size="large" block @click="goBack">
<template #icon><ArrowLeftOutlined /></template>
返回上一页
</a-button>
</template>
</ErrorPanel>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ArrowLeftOutlined, CompassOutlined, HomeOutlined } from "@ant-design/icons-vue";
import ErrorPanel from "@/components/basic/ErrorPanel.vue";
const route = useRoute();
const router = useRouter();
/** 出错的地址:路由兜底跳转时用 ?from= 带过来 */
const fromPath = computed(() =>
typeof route.query.from === "string" ? route.query.from : ""
);
const reasons = [
"地址拼错了,或从聊天/邮件里复制时被截断",
"该功能没有在菜单里开放(系统里查不到这条路由)",
"页面已下线或改名,收藏夹里还是旧地址",
"服务器刚重启、菜单还没加载出来,刷新一次即可",
];
const goHome = () => {
router.replace(router.hasRoute("dashboard") ? "/dashboard" : "/");
};
const goBack = () => {
if (window.history.length > 1) router.back();
else router.replace(router.hasRoute("dashboard") ? "/dashboard" : "/");
};
</script>
+10 -3
View File
@@ -75,7 +75,7 @@
</template>
<script setup lang="ts">
import { reactive, ref, computed, watch } from 'vue'
import { useRouter } from "vue-router";
import { useRoute, useRouter } from "vue-router";
import { UserOutlined, LockOutlined } from "@ant-design/icons-vue";
import authService from "@/service/security/authService";
import { LoginData } from "@/data/auto/loginData";
@@ -95,8 +95,15 @@ const { t } = i18n.global;
//const props = defineProps(['id'])
const router = useRouter();
const route = useRoute();
const userLoginProfile = useLoginProfileStore();
/** 登录成功后的落点:路由守卫拦截时会带上 ?redirect=,没有就回首页 */
const afterLoginPath = (): string =>
typeof route.query.redirect === "string" && route.query.redirect
? route.query.redirect
: "/dashboard";
const state = reactive({
loading: false,
LoginData: {
@@ -149,7 +156,7 @@ const handleSubmit = async () => {
userLoginProfile.updateLoginProfile(profile);
router.push({ path: "/dashboard" });
router.push(afterLoginPath());
} catch (error) {
} finally {
state.loading = false;
@@ -281,7 +288,7 @@ const onBiometricLogin = async () => {
// same call LoginView makes after a successful password login.
userLoginProfile.updateLoginProfile(profile);
router.push({ path: "/dashboard" });
router.push(afterLoginPath());
} catch (err: any) {
// Best-effort error extraction — handles ALL of:
// 1. Axios error: err.response.data is the server body (string or object)
@@ -11,7 +11,8 @@
<a-button type="primary" :disabled="isEdit" :icon="h(FileSearchOutlined)"
@click.prevent="onSearch">查询</a-button>
<a-button :disabled="isEdit" :icon="h(ClearOutlined)" @click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)" @click.prevent="onCreate">新增</a-button>
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</div>
</div>
<div class="page-main ft-page" :class="{ 'ft-readonly': !isEdit }" :style="{ height: resultH }">
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -50,6 +50,7 @@
>
<a-button
type="primary"
v-if="canCreate"
:disabled="isEdit"
:icon="h(FileAddOutlined)"
@click.prevent="onCreate"
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
+1 -1
View File
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
+1 -1
View File
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -47,7 +47,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>
+1 -1
View File
@@ -23,7 +23,7 @@
@click.prevent="onSearch">查询</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(ClearOutlined)"
@click.prevent="onReset">重置</a-button>
<a-button type="primary" :disabled="isEdit" :icon="h(FileAddOutlined)"
<a-button type="primary" v-if="canCreate" :disabled="isEdit" :icon="h(FileAddOutlined)"
@click.prevent="onCreate">新增</a-button>
</a-space>
</a-col>