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']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
|
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
@ -77,6 +78,7 @@ declare global {
|
|||||||
const ElButton: typeof import('element-plus/es')['ElButton']
|
const ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
const ElCard: typeof import('element-plus/es')['ElCard']
|
const ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
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 ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||||
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||||
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
|
|||||||
@ -18,8 +18,6 @@ export interface LoginConfig {
|
|||||||
layout: LoginLayout
|
layout: LoginLayout
|
||||||
/** 背景(图 URL 或 CSS 渐变/颜色)。 */
|
/** 背景(图 URL 或 CSS 渐变/颜色)。 */
|
||||||
background?: string
|
background?: string
|
||||||
/** 登录提交的租户编码(页面不展示租户输入框,统一用此默认租户)。 */
|
|
||||||
tenantCode: string
|
|
||||||
/** 登录字段(JSON Schema,字段名须与后端 DTO 一致)。 */
|
/** 登录字段(JSON Schema,字段名须与后端 DTO 一致)。 */
|
||||||
fields: JsonSchema
|
fields: JsonSchema
|
||||||
/** 是否显示「记住我」。 */
|
/** 是否显示「记住我」。 */
|
||||||
@ -40,7 +38,6 @@ export const defaultLoginConfig: LoginConfig = {
|
|||||||
subtitle: '通用系统管理脚手架',
|
subtitle: '通用系统管理脚手架',
|
||||||
copyright: '云南投云科技有限公司',
|
copyright: '云南投云科技有限公司',
|
||||||
layout: 'split',
|
layout: 'split',
|
||||||
tenantCode: 'touyun',
|
|
||||||
fields: {
|
fields: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|||||||
10
src/main.ts
10
src/main.ts
@ -1,4 +1,5 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
@ -36,4 +37,13 @@ setAuthExpiredHandler(() => {
|
|||||||
installI18n(app)
|
installI18n(app)
|
||||||
installAssets()
|
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')
|
app.mount('#app')
|
||||||
|
|||||||
@ -208,11 +208,14 @@ const { loading, run: doLogin } = useRequest(
|
|||||||
|
|
||||||
async function selectTenant(tenantCode: string): Promise<void> {
|
async function selectTenant(tenantCode: string): Promise<void> {
|
||||||
tenantDialogVisible.value = false
|
tenantDialogVisible.value = false
|
||||||
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
await auth.login(model.username, model.password, tenantCode)
|
await auth.login(model.username, model.password, tenantCode)
|
||||||
router.push(config.homePath)
|
router.push(config.homePath)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = (e as Error).message
|
error.value = (e as Error).message
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,11 @@ meta:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="formRef" class="auth__form" :model="model" :rules="rules" size="large" @keyup.enter="onSubmit">
|
<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-form-item prop="username">
|
||||||
<el-input v-model="model.username" placeholder="用户名">
|
<el-input v-model="model.username" placeholder="用户名">
|
||||||
<template #prefix><icon type="iconify" icon="mdi:account" /></template>
|
<template #prefix><icon type="iconify" icon="mdi:account" /></template>
|
||||||
@ -71,9 +76,10 @@ applyTheme(app.themeColor, app.isDark)
|
|||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const model = reactive({ username: '', password: '', confirmPassword: '', email: '', phone: '' })
|
const model = reactive({ tenantCode: '', username: '', password: '', confirmPassword: '', email: '', phone: '' })
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
|
tenantCode: [{ required: true, message: '请输入租户编码', trigger: 'blur' }],
|
||||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
@ -105,7 +111,7 @@ async function onSubmit(): Promise<void> {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
await register({
|
await register({
|
||||||
tenantCode: config.tenantCode,
|
tenantCode: model.tenantCode,
|
||||||
username: model.username,
|
username: model.username,
|
||||||
password: model.password,
|
password: model.password,
|
||||||
email: model.email,
|
email: model.email,
|
||||||
|
|||||||
@ -66,8 +66,8 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
next('/login')
|
next('/login')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 路由级权限:自由路径放行,其余须在可访问菜单中
|
// 路由级权限:自由路径或 meta.freeAccess 放行,其余须在可访问菜单中
|
||||||
if (FREE_PATHS.has(to.path)) {
|
if (FREE_PATHS.has(to.path) || to.meta.freeAccess === true) {
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user