fix: 第二轮残留(前端)
- 移除 config.tenantCode 死配置,注册页加租户输入 - 全局 errorHandler + unhandledrejection 兜底错误提示 - selectTenant 二次登录加 loading - 路由守卫支持 meta.freeAccess 白名单 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e1bc973034
commit
eff4f8b314
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -18,6 +18,7 @@ declare module 'vue' {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
@ -77,6 +78,7 @@ declare global {
|
||||
const ElButton: typeof import('element-plus/es')['ElButton']
|
||||
const ElCard: typeof import('element-plus/es')['ElCard']
|
||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
const ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
|
||||
@ -18,8 +18,6 @@ export interface LoginConfig {
|
||||
layout: LoginLayout
|
||||
/** 背景(图 URL 或 CSS 渐变/颜色)。 */
|
||||
background?: string
|
||||
/** 登录提交的租户编码(页面不展示租户输入框,统一用此默认租户)。 */
|
||||
tenantCode: string
|
||||
/** 登录字段(JSON Schema,字段名须与后端 DTO 一致)。 */
|
||||
fields: JsonSchema
|
||||
/** 是否显示「记住我」。 */
|
||||
@ -40,7 +38,6 @@ export const defaultLoginConfig: LoginConfig = {
|
||||
subtitle: '通用系统管理脚手架',
|
||||
copyright: '云南投云科技有限公司',
|
||||
layout: 'split',
|
||||
tenantCode: 'touyun',
|
||||
fields: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
10
src/main.ts
10
src/main.ts
@ -1,4 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
|
||||
import App from './App.vue'
|
||||
@ -36,4 +37,13 @@ setAuthExpiredHandler(() => {
|
||||
installI18n(app)
|
||||
installAssets()
|
||||
|
||||
// 全局兜底:未捕获的组件错误 / Promise 拒绝,统一弹出错误提示(避免静默失败)
|
||||
app.config.errorHandler = (err) => {
|
||||
ElMessage.error(err instanceof Error ? err.message : String(err))
|
||||
}
|
||||
window.addEventListener('unhandledrejection', (e) => {
|
||||
const reason = e.reason
|
||||
ElMessage.error(reason instanceof Error ? reason.message : String(reason))
|
||||
})
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@ -208,11 +208,14 @@ const { loading, run: doLogin } = useRequest(
|
||||
|
||||
async function selectTenant(tenantCode: string): Promise<void> {
|
||||
tenantDialogVisible.value = false
|
||||
loading.value = true
|
||||
try {
|
||||
await auth.login(model.username, model.password, tenantCode)
|
||||
router.push(config.homePath)
|
||||
} catch (e) {
|
||||
error.value = (e as Error).message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,11 @@ meta:
|
||||
</div>
|
||||
|
||||
<el-form ref="formRef" class="auth__form" :model="model" :rules="rules" size="large" @keyup.enter="onSubmit">
|
||||
<el-form-item prop="tenantCode">
|
||||
<el-input v-model="model.tenantCode" placeholder="租户编码">
|
||||
<template #prefix><icon type="iconify" icon="mdi:domain" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="model.username" placeholder="用户名">
|
||||
<template #prefix><icon type="iconify" icon="mdi:account" /></template>
|
||||
@ -71,9 +76,10 @@ applyTheme(app.themeColor, app.isDark)
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const loading = ref(false)
|
||||
const model = reactive({ username: '', password: '', confirmPassword: '', email: '', phone: '' })
|
||||
const model = reactive({ tenantCode: '', username: '', password: '', confirmPassword: '', email: '', phone: '' })
|
||||
|
||||
const rules: FormRules = {
|
||||
tenantCode: [{ required: true, message: '请输入租户编码', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
@ -105,7 +111,7 @@ async function onSubmit(): Promise<void> {
|
||||
loading.value = true
|
||||
try {
|
||||
await register({
|
||||
tenantCode: config.tenantCode,
|
||||
tenantCode: model.tenantCode,
|
||||
username: model.username,
|
||||
password: model.password,
|
||||
email: model.email,
|
||||
|
||||
@ -66,8 +66,8 @@ router.beforeEach(async (to, from, next) => {
|
||||
next('/login')
|
||||
return
|
||||
}
|
||||
// 路由级权限:自由路径放行,其余须在可访问菜单中
|
||||
if (FREE_PATHS.has(to.path)) {
|
||||
// 路由级权限:自由路径或 meta.freeAccess 放行,其余须在可访问菜单中
|
||||
if (FREE_PATHS.has(to.path) || to.meta.freeAccess === true) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user