新增 有家相册 uni-app 前端(uniapp/youjiala,H5 / 微信小程序 / App 三端)
从旧 WebVue 移植的地基部分: - 登录页(RSA+MD5 密码加密、redirect 回跳、中英文切换)与登录后落地页 - 401 / 403 / 404 错误页 + error-panel 通用外壳(文案走 ErrorPage 语言包) - 登录守卫双链路:uni.addInterceptor 拦站内跳转,页面级 onShow 复核冷启动深链 - 单一请求链路 common/http.interceptor:JWT 唯一来源、401 并发刷新单例、 业务异常识别、HTTP 403 跳无权限页 - H5 干净短地址:initRouter 前向 __uniRoutes 追加克隆记录(router/h5-clean-url) - 路由登记表 router/routes.ts(PAGE_PATHS / pageUrl / PAGE_PERMISSIONS) 与新增页面四步登记约定(src/md/page-routing.md) - i18n:uView Pro 语言包 + 后端词条合并,双取值(后端 zh-cn/en,包名 zh-CN/en-US) - 后端接口层 service/ 与数据模型 data/auto/ 为生成器产物,不手改 不入库的内容: - 摘除脚手架残留的 Harmony 签名密码(manifest.json signingConfigs 与 harmony-configs/build-profile.json5 的 keyPassword / storePassword 已置空) - 忽略 node_modules、dist、unpackage、.hbuilderx、.agents、pnpm-lock.yaml 及根目录临时截图
This commit is contained in:
1 parent
74757f9eb4
commit
6a8258ac4b
274 files changed
+30291
No files matched your search
@@ -0,0 +1,316 @@
|
||||
<script setup lang="ts">
|
||||
import type { PropType } from "vue";
|
||||
import { useLocale } from "uview-pro";
|
||||
import { WebSitePolicy } from "@/policy/custom/webSitePolicy";
|
||||
|
||||
/**
|
||||
* 错误页通用外壳(401 / 403 / 404 共用),移植自旧 WebVue 的 components/basic/ErrorPanel.vue。
|
||||
* 只负责排版与配色,具体文案、图标、按钮由各错误页提供。
|
||||
* 旧版用 ant-design 图标 + <a> 链接,这里换成 uView Pro 的 u-icon 与纯文本,跨端可用。
|
||||
*/
|
||||
defineProps({
|
||||
/** 状态码,如 401 */
|
||||
code: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/** 状态码下方的短标签,如「UNAUTHORIZED · 未认证」 */
|
||||
badge: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
/** 主题色:blue(默认)/ amber(无权限)/ violet(找不到页面) */
|
||||
tone: {
|
||||
type: String as PropType<"blue" | "amber" | "violet">,
|
||||
default: "blue",
|
||||
},
|
||||
/** 主标题:一句话说清出了什么问题 */
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/** 副标题:补充说明 */
|
||||
description: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
/** 可能的原因清单 */
|
||||
reasons: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
/** 出错的地址(守卫跳页时用 ?from= 带过来) */
|
||||
from: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
/** 兜底提示 */
|
||||
hint: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
// 「可能的原因」「出错的地址:」是组件自己的固定标签,走语言包;业务文案仍由各错误页传入
|
||||
const { t } = useLocale();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="ep" :class="`ep--${tone}`">
|
||||
<!-- 顶部渐变头图:品牌 + 大号状态码 -->
|
||||
<view class="ep-hero">
|
||||
<view class="ep-brand">
|
||||
<image class="ep-brand__logo" src="/static/logo.png" mode="aspectFill" />
|
||||
<text class="ep-brand__name">
|
||||
{{ WebSitePolicy.Title }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="ep-code">
|
||||
{{ code }}
|
||||
</view>
|
||||
<view class="ep-tag">
|
||||
{{ badge }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 悬浮卡片:图标 + 说明 + 可能原因 + 操作 -->
|
||||
<view class="ep-card">
|
||||
<view class="ep-icon">
|
||||
<slot name="icon" />
|
||||
</view>
|
||||
|
||||
<view class="ep-title">
|
||||
{{ title }}
|
||||
</view>
|
||||
<view v-if="description" class="ep-desc">
|
||||
{{ description }}
|
||||
</view>
|
||||
|
||||
<view v-if="reasons && reasons.length" class="ep-reasons">
|
||||
<view class="ep-reasons__title">
|
||||
<text>{{ t('ErrorPage.reasonsTitle') }}</text>
|
||||
</view>
|
||||
<view v-for="(item, i) in reasons" :key="i" class="ep-reasons__item">
|
||||
<text class="ep-reasons__dot">
|
||||
•
|
||||
</text>
|
||||
<text class="ep-reasons__text">
|
||||
{{ item }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="from" class="ep-from">
|
||||
<text>{{ t('ErrorPage.fromLabel') }}</text>
|
||||
<text class="ep-from__code">
|
||||
{{ from }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="ep-actions">
|
||||
<slot name="actions" />
|
||||
</view>
|
||||
|
||||
<view v-if="hint" class="ep-hint">
|
||||
{{ hint }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="ep-footer">
|
||||
<text class="ep-footer__line">
|
||||
{{ WebSitePolicy.Copy }}
|
||||
</text>
|
||||
<text class="ep-footer__line">
|
||||
{{ WebSitePolicy.Beian }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" 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;
|
||||
background-color: $u-bg-white;
|
||||
}
|
||||
|
||||
.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 {
|
||||
/* 状态栏高度:navigationStyle 为 custom,页面顶部会被状态栏压住 */
|
||||
padding: calc(var(--status-bar-height) + 32rpx) 32rpx 88rpx;
|
||||
border-radius: 0 0 44rpx 44rpx;
|
||||
background-image: linear-gradient(135deg, var(--ep-from) 0%, var(--ep-to) 100%);
|
||||
box-shadow: 0 12rpx 36rpx var(--ep-shadow);
|
||||
color: $u-bg-white;
|
||||
}
|
||||
|
||||
.ep-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ep-brand__logo {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: rgba(255, 255, 255, 0.24);
|
||||
}
|
||||
|
||||
.ep-brand__name {
|
||||
margin-left: 16rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.ep-code {
|
||||
margin-top: 16rpx;
|
||||
font-size: 104rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
letter-spacing: 4rpx;
|
||||
}
|
||||
|
||||
.ep-tag {
|
||||
margin-top: 12rpx;
|
||||
font-size: 24rpx;
|
||||
letter-spacing: 2rpx;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* ---------- 悬浮卡片 ---------- */
|
||||
.ep-card {
|
||||
margin: -56rpx 32rpx 36rpx;
|
||||
padding: 36rpx 32rpx 40rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 16rpx 48rpx rgba(15, 35, 60, 0.08);
|
||||
}
|
||||
|
||||
.ep-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 28rpx;
|
||||
background-image: linear-gradient(135deg, var(--ep-from) 0%, var(--ep-to) 100%);
|
||||
box-shadow: 0 4rpx 16rpx var(--ep-shadow);
|
||||
}
|
||||
|
||||
.ep-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: $u-main-color;
|
||||
}
|
||||
|
||||
.ep-desc {
|
||||
margin-top: 12rpx;
|
||||
font-size: 27rpx;
|
||||
line-height: 1.65;
|
||||
color: $u-content-color;
|
||||
}
|
||||
|
||||
.ep-reasons {
|
||||
margin-top: 28rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #eef0f4;
|
||||
border-radius: 28rpx;
|
||||
background-color: #f7f9fc;
|
||||
}
|
||||
|
||||
.ep-reasons__title {
|
||||
margin-bottom: 12rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: $u-main-color;
|
||||
}
|
||||
|
||||
.ep-reasons__item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.ep-reasons__dot {
|
||||
margin-right: 12rpx;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.6;
|
||||
color: var(--ep-from);
|
||||
}
|
||||
|
||||
.ep-reasons__text {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.6;
|
||||
color: $u-tips-color;
|
||||
}
|
||||
|
||||
.ep-from {
|
||||
margin-top: 24rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
color: $u-light-color;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.ep-from__code {
|
||||
margin-left: 8rpx;
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
background-color: #f2f4f8;
|
||||
color: $u-main-color;
|
||||
}
|
||||
|
||||
.ep-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* 按钮来自各页面的插槽,拿不到本组件的 scoped 样式,故间距写在容器上 */
|
||||
gap: 20rpx;
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.ep-hint {
|
||||
margin-top: 28rpx;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
color: $u-light-color;
|
||||
}
|
||||
|
||||
/* ---------- 底部信息 ---------- */
|
||||
.ep-footer {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0 32rpx 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ep-footer__line {
|
||||
font-size: 22rpx;
|
||||
line-height: 32rpx;
|
||||
color: $u-light-color;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user