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

+305
View File
@@ -0,0 +1,305 @@
<template>
<div class="ep" :class="'ep--' + tone">
<!-- 顶部渐变头图:品牌 + 大号状态码,延续首页 hero 的视觉语言 -->
<header class="ep-hero">
<div class="ep-hero-inner">
<div class="ep-brand">
<a-avatar shape="square" :size="26" src="/youjia.svg" />
<span>{{ siteTitle }}</span>
</div>
<div class="ep-code">{{ code }}</div>
<div class="ep-tag">{{ badge }}</div>
</div>
</header>
<!-- 悬浮卡片:图标 + 说明 + 可能原因 + 操作 -->
<section class="ep-card">
<div class="ep-icon">
<slot name="icon" />
</div>
<h1 class="ep-title">{{ title }}</h1>
<p class="ep-desc">{{ description }}</p>
<div v-if="reasons && reasons.length" class="ep-reasons">
<div class="ep-reasons-title">可能的原因</div>
<ul>
<li v-for="(item, i) in reasons" :key="i">{{ item }}</li>
</ul>
</div>
<p v-if="from" class="ep-from">
出错的地址:<code>{{ from }}</code>
</p>
<div class="ep-actions">
<slot name="actions" />
</div>
<p v-if="hint" class="ep-hint">{{ hint }}</p>
</section>
<footer class="ep-footer">
<span>{{ copy }}</span>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">{{ beian }}</a>
</footer>
</div>
</template>
<script lang="ts" setup>
import { WebSitePolicy } from "@/policy/custom/webSitePolicy";
/**
* 错误页通用外壳(401 / 403 / 404 共用)。
* 只负责排版与主题,具体文案、图标、按钮由三个错误页各自提供。
*/
withDefaults(
defineProps<{
/** 状态码,如 401 */
code: string;
/** 状态码下方的短标签,如「未认证」 */
badge?: string;
/** 主题色:blue(品牌蓝青,默认)/ amber(警示)/ violet(找不到) */
tone?: "blue" | "amber" | "violet";
/** 主标题:一句话说清出了什么问题 */
title: string;
/** 副标题:补充说明 */
description?: string;
/** 可能的原因清单 */
reasons?: string[];
/** 出错的地址(404 用 ?from= 带过来) */
from?: string;
/** 兜底提示,如「如需权限请联系管理员」 */
hint?: string;
}>(),
{ badge: "", tone: "blue", description: "", reasons: () => [], from: "", hint: "" },
);
const siteTitle = WebSitePolicy.Title;
const copy = WebSitePolicy.Copy;
const beian = WebSitePolicy.Beian;
</script>
<style lang="less" scoped>
.ep {
/* 主题色:默认品牌蓝→青渐变,amber / violet 用于区分不同错误类型 */
--ep-from: #1677ff;
--ep-to: #36cfc9;
--ep-shadow: rgba(22, 119, 255, 0.18);
display: flex;
flex-direction: column;
min-height: 100vh;
min-height: 100dvh;
background: #f5f6f8;
-webkit-tap-highlight-color: transparent;
}
.ep--amber {
--ep-from: #fa8c16;
--ep-to: #ffc53d;
--ep-shadow: rgba(250, 140, 22, 0.18);
}
.ep--violet {
--ep-from: #722ed1;
--ep-to: #b37feb;
--ep-shadow: rgba(114, 46, 209, 0.18);
}
/* ---------- 头图 ---------- */
.ep-hero {
padding: 16px 16px 44px;
border-radius: 0 0 22px 22px;
background: linear-gradient(135deg, var(--ep-from) 0%, var(--ep-to) 100%);
color: #fff;
box-shadow: 0 6px 18px var(--ep-shadow);
}
.ep-hero-inner {
width: 100%;
max-width: 900px;
margin: 0 auto;
}
.ep-brand {
display: flex;
align-items: center;
gap: 8px;
font-size: 15px;
font-weight: 600;
opacity: 0.95;
}
.ep-code {
margin-top: 8px;
font-size: 52px;
font-weight: 800;
line-height: 1;
letter-spacing: 2px;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}
.ep-tag {
margin-top: 6px;
font-size: 12px;
letter-spacing: 1px;
opacity: 0.9;
}
/* ---------- 悬浮卡片 ---------- */
.ep-card {
flex: 0 0 auto;
margin: -28px 16px 18px;
padding: 18px 16px 20px;
border-radius: 20px;
background: #fff;
box-shadow: 0 8px 24px rgba(15, 35, 60, 0.08);
}
.ep-icon {
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
margin-bottom: 12px;
border-radius: 14px;
font-size: 24px;
color: #fff;
background: linear-gradient(135deg, var(--ep-from) 0%, var(--ep-to) 100%);
box-shadow: 0 2px 8px var(--ep-shadow);
}
.ep-title {
margin: 0;
font-size: 18px;
font-weight: 700;
line-height: 1.4;
color: #1f2329;
}
.ep-desc {
margin: 6px 0 0;
font-size: 13.5px;
line-height: 1.65;
color: #646a73;
}
.ep-reasons {
margin-top: 14px;
padding: 12px 12px 10px;
border: 1px solid #eef0f4;
border-radius: 14px;
background: #f7f9fc;
}
.ep-reasons-title {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 6px;
font-size: 13px;
font-weight: 600;
color: #1f2329;
}
.ep-reasons-title::before {
content: "";
width: 3px;
height: 12px;
border-radius: 2px;
background: var(--ep-from);
}
.ep-reasons ul {
margin: 0;
padding-left: 18px;
}
.ep-reasons li {
margin: 4px 0;
font-size: 13px;
line-height: 1.6;
color: #646a73;
}
.ep-from {
margin: 12px 0 0;
font-size: 12px;
line-height: 1.6;
color: #8a919f;
word-break: break-all;
}
.ep-from code {
padding: 1px 6px;
border-radius: 6px;
background: #f2f4f8;
color: #1f2329;
font-size: 12px;
}
.ep-actions {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 18px;
}
.ep-hint {
margin: 14px 0 0;
font-size: 12px;
line-height: 1.6;
color: #8a919f;
}
/* ---------- 底部信息 ---------- */
.ep-footer {
flex: 1 1 auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
gap: 4px;
padding: 0 16px 14px;
font-size: 11px;
line-height: 16px;
color: #8a919f;
text-align: center;
}
.ep-footer a {
color: #8a919f;
text-decoration: none;
&:hover {
color: #1677ff;
}
}
/* ---------- 宽屏(手机优先,这里只是放大与居中) ---------- */
@media (min-width: 576px) {
.ep-hero {
padding: 22px 24px 56px;
}
.ep-code {
font-size: 64px;
}
.ep-card {
width: 100%;
max-width: 460px;
margin: -34px auto 20px;
padding: 22px 22px 24px;
}
/* 宽屏按钮横排,主操作在左,更符合桌面习惯 */
.ep-actions {
flex-direction: row;
justify-content: flex-start;
gap: 12px;
}
}
</style>