feat: unified dialog manager (showDialog service + ty-dialog host)
- 新增 showDialog({component, props, title,...}) 服务,返回 Promise
- 内容组件 defineExpose({submit}) 校验并返回数据,校验失败对话框不关闭
- <ty-dialog /> 宿主挂 App.vue,统一渲染对话框栈(支持嵌套)
- ty-crud 改用 showDialog 打开表单(移除 ty-form-dialog)
- ty-form 增加 submit();用户管理页重置密码抽成独立组件 + showDialog
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
16b512a3f1
commit
35892486e8
4
components.d.ts
vendored
4
components.d.ts
vendored
@ -46,9 +46,9 @@ declare module 'vue' {
|
|||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
TyBreadcrumb: typeof import('./src/components/ty-breadcrumb.vue')['default']
|
TyBreadcrumb: typeof import('./src/components/ty-breadcrumb.vue')['default']
|
||||||
TyCrud: typeof import('./src/components/ty-crud.vue')['default']
|
TyCrud: typeof import('./src/components/ty-crud.vue')['default']
|
||||||
|
TyDialog: typeof import('./src/components/ty-dialog.vue')['default']
|
||||||
TyFooter: typeof import('./src/components/ty-footer.vue')['default']
|
TyFooter: typeof import('./src/components/ty-footer.vue')['default']
|
||||||
TyForm: typeof import('./src/components/ty-form.vue')['default']
|
TyForm: typeof import('./src/components/ty-form.vue')['default']
|
||||||
TyFormDialog: typeof import('./src/components/ty-form-dialog.vue')['default']
|
|
||||||
TyHeader: typeof import('./src/components/ty-header.vue')['default']
|
TyHeader: typeof import('./src/components/ty-header.vue')['default']
|
||||||
TyMixbar: typeof import('./src/components/ty-mixbar.vue')['default']
|
TyMixbar: typeof import('./src/components/ty-mixbar.vue')['default']
|
||||||
TySearchForm: typeof import('./src/components/ty-search-form.vue')['default']
|
TySearchForm: typeof import('./src/components/ty-search-form.vue')['default']
|
||||||
@ -99,9 +99,9 @@ declare global {
|
|||||||
const RouterView: typeof import('vue-router')['RouterView']
|
const RouterView: typeof import('vue-router')['RouterView']
|
||||||
const TyBreadcrumb: typeof import('./src/components/ty-breadcrumb.vue')['default']
|
const TyBreadcrumb: typeof import('./src/components/ty-breadcrumb.vue')['default']
|
||||||
const TyCrud: typeof import('./src/components/ty-crud.vue')['default']
|
const TyCrud: typeof import('./src/components/ty-crud.vue')['default']
|
||||||
|
const TyDialog: typeof import('./src/components/ty-dialog.vue')['default']
|
||||||
const TyFooter: typeof import('./src/components/ty-footer.vue')['default']
|
const TyFooter: typeof import('./src/components/ty-footer.vue')['default']
|
||||||
const TyForm: typeof import('./src/components/ty-form.vue')['default']
|
const TyForm: typeof import('./src/components/ty-form.vue')['default']
|
||||||
const TyFormDialog: typeof import('./src/components/ty-form-dialog.vue')['default']
|
|
||||||
const TyHeader: typeof import('./src/components/ty-header.vue')['default']
|
const TyHeader: typeof import('./src/components/ty-header.vue')['default']
|
||||||
const TyMixbar: typeof import('./src/components/ty-mixbar.vue')['default']
|
const TyMixbar: typeof import('./src/components/ty-mixbar.vue')['default']
|
||||||
const TySearchForm: typeof import('./src/components/ty-search-form.vue')['default']
|
const TySearchForm: typeof import('./src/components/ty-search-form.vue')['default']
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-config-provider :locale="zhCn">
|
<el-config-provider :locale="zhCn">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
<ty-dialog />
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -63,17 +63,6 @@
|
|||||||
</ty-table>
|
</ty-table>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<ty-form-dialog
|
|
||||||
v-model:visible="dialogVisible"
|
|
||||||
:title="dialogMode === 'edit' ? `编辑${entityName}` : `新增${entityName}`"
|
|
||||||
:schema="formSchema"
|
|
||||||
:model-value="form"
|
|
||||||
:mode="dialogMode"
|
|
||||||
:readonly-keys="dialogMode === 'edit' ? editReadonlyKeys : []"
|
|
||||||
:submitting="submitting"
|
|
||||||
@submit="handleSubmit"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -88,6 +77,8 @@ import type {
|
|||||||
PageResult,
|
PageResult,
|
||||||
TableColumn,
|
TableColumn,
|
||||||
} from '@/types/crud'
|
} from '@/types/crud'
|
||||||
|
import TyForm from '@/components/ty-form.vue'
|
||||||
|
import { showDialog } from '@/utils/dialog'
|
||||||
|
|
||||||
defineOptions({ name: 'TyCrud' })
|
defineOptions({ name: 'TyCrud' })
|
||||||
|
|
||||||
@ -144,12 +135,6 @@ const selectedRows = ref<Record<string, any>[]>([])
|
|||||||
|
|
||||||
const query = reactive<Record<string, any>>(buildModel(props.searchSchema))
|
const query = reactive<Record<string, any>>(buildModel(props.searchSchema))
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
|
||||||
const dialogMode = ref<'create' | 'edit'>('create')
|
|
||||||
const editingId = ref<string | null>(null)
|
|
||||||
const submitting = ref(false)
|
|
||||||
const form = reactive<Record<string, any>>({})
|
|
||||||
|
|
||||||
function buildModel(schema?: JsonSchema): Record<string, any> {
|
function buildModel(schema?: JsonSchema): Record<string, any> {
|
||||||
const model: Record<string, any> = {}
|
const model: Record<string, any> = {}
|
||||||
if (!schema) return model
|
if (!schema) return model
|
||||||
@ -183,39 +168,38 @@ function handleReset(): void {
|
|||||||
fetchList()
|
fetchList()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openCreate(): void {
|
async function openCreate(): Promise<void> {
|
||||||
dialogMode.value = 'create'
|
const model = buildModel(props.formSchema)
|
||||||
editingId.value = null
|
const data = await showDialog({
|
||||||
Object.assign(form, buildModel(props.formSchema))
|
component: TyForm,
|
||||||
dialogVisible.value = true
|
props: { schema: props.formSchema, modelValue: model, mode: 'create' },
|
||||||
|
title: `新增${props.entityName}`,
|
||||||
|
})
|
||||||
|
if (data == null) return
|
||||||
|
await props.create(data)
|
||||||
|
ElMessage.success('新增成功')
|
||||||
|
fetchList()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEdit(row: Record<string, any>): void {
|
async function openEdit(row: Record<string, any>): Promise<void> {
|
||||||
dialogMode.value = 'edit'
|
|
||||||
editingId.value = String(row[props.idKey])
|
|
||||||
const model = buildModel(props.formSchema)
|
const model = buildModel(props.formSchema)
|
||||||
for (const key of Object.keys(props.formSchema.properties)) {
|
for (const key of Object.keys(props.formSchema.properties)) {
|
||||||
model[key] = row[key] ?? model[key]
|
model[key] = row[key] ?? model[key]
|
||||||
}
|
}
|
||||||
Object.assign(form, model)
|
const data = await showDialog({
|
||||||
dialogVisible.value = true
|
component: TyForm,
|
||||||
}
|
props: {
|
||||||
|
schema: props.formSchema,
|
||||||
async function handleSubmit(): Promise<void> {
|
modelValue: model,
|
||||||
submitting.value = true
|
mode: 'edit',
|
||||||
try {
|
readonlyKeys: props.editReadonlyKeys,
|
||||||
if (dialogMode.value === 'edit') {
|
},
|
||||||
await props.update(editingId.value!, { ...form })
|
title: `编辑${props.entityName}`,
|
||||||
|
})
|
||||||
|
if (data == null) return
|
||||||
|
await props.update(String(row[props.idKey]), data)
|
||||||
ElMessage.success('更新成功')
|
ElMessage.success('更新成功')
|
||||||
} else {
|
|
||||||
await props.create({ ...form })
|
|
||||||
ElMessage.success('新增成功')
|
|
||||||
}
|
|
||||||
dialogVisible.value = false
|
|
||||||
fetchList()
|
fetchList()
|
||||||
} finally {
|
|
||||||
submitting.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDelete(row: Record<string, any>): Promise<void> {
|
async function handleDelete(row: Record<string, any>): Promise<void> {
|
||||||
|
|||||||
61
src/components/ty-dialog.vue
Normal file
61
src/components/ty-dialog.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-for="dialog in dialogs"
|
||||||
|
:key="dialog.id"
|
||||||
|
:model-value="true"
|
||||||
|
:title="dialog.options.title"
|
||||||
|
:width="dialog.options.width ?? '480px'"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
@close="handleClose(dialog)"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="dialog.options.component"
|
||||||
|
v-bind="dialog.options.props ?? {}"
|
||||||
|
:ref="setRef(dialog.id)"
|
||||||
|
/>
|
||||||
|
<template v-if="dialog.options.showFooter !== false" #footer>
|
||||||
|
<el-button @click="handleCancel(dialog)">{{ dialog.options.cancelText ?? '取消' }}</el-button>
|
||||||
|
<el-button type="primary" @click="handleConfirm(dialog)">{{ dialog.options.confirmText ?? '确定' }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
import { closeDialog, dialogs, type DialogInstance } from '@/utils/dialog'
|
||||||
|
|
||||||
|
defineOptions({ name: 'TyDialog' })
|
||||||
|
|
||||||
|
const componentRefs = reactive<Record<number, any>>({})
|
||||||
|
|
||||||
|
function setRef(id: number): (el: unknown) => void {
|
||||||
|
return (el) => {
|
||||||
|
if (el) componentRefs[id] = el
|
||||||
|
else delete componentRefs[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleConfirm(dialog: DialogInstance): Promise<void> {
|
||||||
|
const ref = componentRefs[dialog.id]
|
||||||
|
let data: any
|
||||||
|
if (ref?.submit) {
|
||||||
|
try {
|
||||||
|
data = await ref.submit()
|
||||||
|
} catch {
|
||||||
|
// 校验失败,保持对话框打开
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dialog.options.onConfirm) await dialog.options.onConfirm(data)
|
||||||
|
closeDialog(dialog.id, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel(dialog: DialogInstance): void {
|
||||||
|
closeDialog(dialog.id, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClose(dialog: DialogInstance): void {
|
||||||
|
closeDialog(dialog.id, null)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -1,65 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-dialog v-model="visible" :title="title" :width="width" destroy-on-close @closed="onClosed">
|
|
||||||
<ty-form
|
|
||||||
ref="formRef"
|
|
||||||
:schema="schema"
|
|
||||||
:model-value="modelValue"
|
|
||||||
:readonly-keys="readonlyKeys"
|
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="visible = false">取消</el-button>
|
|
||||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import type { JsonSchema } from '@/types/crud'
|
|
||||||
|
|
||||||
defineOptions({ name: 'TyFormDialog' })
|
|
||||||
|
|
||||||
const visible = defineModel<boolean>('visible', { default: false })
|
|
||||||
|
|
||||||
withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
title?: string
|
|
||||||
/** 表单 JSON Schema。 */
|
|
||||||
schema: JsonSchema
|
|
||||||
/** 表单数据(就地绑定)。 */
|
|
||||||
modelValue: Record<string, any>
|
|
||||||
readonlyKeys?: string[]
|
|
||||||
/** 表单模式(create/edit),透传给 schema form 用于 showOn。 */
|
|
||||||
mode?: 'create' | 'edit'
|
|
||||||
submitting?: boolean
|
|
||||||
width?: string
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
readonlyKeys: () => [],
|
|
||||||
mode: undefined,
|
|
||||||
submitting: false,
|
|
||||||
width: '480px',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'submit'): void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const formRef = ref<{ validate: () => Promise<unknown>; resetFields?: () => void }>()
|
|
||||||
|
|
||||||
async function handleSubmit(): Promise<void> {
|
|
||||||
try {
|
|
||||||
await formRef.value?.validate()
|
|
||||||
} catch {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
emit('submit')
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClosed(): void {
|
|
||||||
formRef.value?.resetFields?.()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -147,7 +147,13 @@ function widgetStyle(prop: JsonSchemaProperty): Record<string, string> {
|
|||||||
return { width: prop.width ?? (props.inline ? '200px' : '100%') }
|
return { width: prop.width ?? (props.inline ? '200px' : '100%') }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function submit(): Promise<Record<string, any>> {
|
||||||
|
await formRef.value?.validate()
|
||||||
|
return { ...props.modelValue }
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
submit,
|
||||||
validate: () => formRef.value?.validate(),
|
validate: () => formRef.value?.validate(),
|
||||||
resetFields: () => formRef.value?.resetFields(),
|
resetFields: () => formRef.value?.resetFields(),
|
||||||
clearValidate: () => formRef.value?.clearValidate(),
|
clearValidate: () => formRef.value?.clearValidate(),
|
||||||
|
|||||||
@ -25,32 +25,14 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</ty-crud>
|
</ty-crud>
|
||||||
|
|
||||||
<el-dialog v-model="resetPwd.visible" title="重置密码" width="420px" destroy-on-close>
|
|
||||||
<el-form label-width="80px">
|
|
||||||
<el-form-item label="用户名"
|
|
||||||
><span>{{ resetPwd.username }}</span></el-form-item
|
|
||||||
>
|
|
||||||
<el-form-item label="新密码">
|
|
||||||
<el-input
|
|
||||||
v-model="resetPwd.password"
|
|
||||||
type="password"
|
|
||||||
show-password
|
|
||||||
placeholder="请输入新密码"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="resetPwd.visible = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="submitResetPwd">确定</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import type { CrudAction, JsonSchema, PageQuery, PageResult, TableColumn } from '@/types/crud'
|
import type { CrudAction, JsonSchema, PageQuery, PageResult, TableColumn } from '@/types/crud'
|
||||||
|
import { showDialog } from '@/utils/dialog'
|
||||||
|
import ResetPasswordForm from './reset-password-form.vue'
|
||||||
|
|
||||||
const STATUS_MAP = {
|
const STATUS_MAP = {
|
||||||
enabled: { label: '启用', type: 'success' },
|
enabled: { label: '启用', type: 'success' },
|
||||||
@ -130,7 +112,7 @@ const formSchema: JsonSchema = {
|
|||||||
const actions: CrudAction[] = [
|
const actions: CrudAction[] = [
|
||||||
'edit',
|
'edit',
|
||||||
'delete',
|
'delete',
|
||||||
{ label: '重置密码', type: 'warning', onClick: (row) => openResetPwd(row) },
|
{ label: '重置密码', type: 'warning', onClick: (row) => resetPwd(row) },
|
||||||
]
|
]
|
||||||
|
|
||||||
// ---- 占位数据(后续对接后端时替换为 http 调用)----
|
// ---- 占位数据(后续对接后端时替换为 http 调用)----
|
||||||
@ -305,20 +287,16 @@ const remove = (id: string): Promise<unknown> =>
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const resetPwd = reactive({ visible: false, id: '', username: '', password: '' })
|
async function resetPwd(row: Record<string, any>): Promise<void> {
|
||||||
|
const result = await showDialog({
|
||||||
function openResetPwd(row: Record<string, any>): void {
|
component: ResetPasswordForm,
|
||||||
resetPwd.visible = true
|
props: { username: String(row.username) },
|
||||||
resetPwd.id = String(row.id)
|
title: '重置密码',
|
||||||
resetPwd.username = String(row.username)
|
width: '420px',
|
||||||
resetPwd.password = ''
|
})
|
||||||
}
|
if (result == null) return
|
||||||
|
|
||||||
async function submitResetPwd(): Promise<void> {
|
|
||||||
// mock:无真实密码存储,仅模拟
|
// mock:无真实密码存储,仅模拟
|
||||||
await delay(() => null)
|
|
||||||
ElMessage.success('密码已重置')
|
ElMessage.success('密码已重置')
|
||||||
resetPwd.visible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const crudRef = ref()
|
const crudRef = ref()
|
||||||
|
|||||||
27
src/pages/system/user/reset-password-form.vue
Normal file
27
src/pages/system/user/reset-password-form.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="mb-md text-sm text-text-regular">用户:{{ username }}</div>
|
||||||
|
<el-input v-model="password" type="password" show-password placeholder="请输入新密码" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
defineOptions({ name: 'ResetPasswordForm' })
|
||||||
|
|
||||||
|
defineProps<{ username: string }>()
|
||||||
|
|
||||||
|
const password = ref('')
|
||||||
|
|
||||||
|
function submit(): { password: string } {
|
||||||
|
if (!password.value) {
|
||||||
|
ElMessage.warning('请输入新密码')
|
||||||
|
throw new Error('请输入新密码')
|
||||||
|
}
|
||||||
|
return { password: password.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ submit })
|
||||||
|
</script>
|
||||||
50
src/utils/dialog.ts
Normal file
50
src/utils/dialog.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { markRaw, reactive, type Component } from 'vue'
|
||||||
|
|
||||||
|
export interface DialogOptions {
|
||||||
|
/** 对话框内容组件。 */
|
||||||
|
component: Component
|
||||||
|
title?: string
|
||||||
|
width?: string
|
||||||
|
/** 传给内容组件的 props。 */
|
||||||
|
props?: Record<string, any>
|
||||||
|
confirmText?: string
|
||||||
|
cancelText?: string
|
||||||
|
/** 是否显示默认 取消/确定 底部(false 时内容组件自带底部)。 */
|
||||||
|
showFooter?: boolean
|
||||||
|
/** 确认回调,参数为内容组件 submit() 返回的数据。 */
|
||||||
|
onConfirm?: (data: any) => void | Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DialogInstance {
|
||||||
|
id: number
|
||||||
|
options: DialogOptions
|
||||||
|
resolve: (value: any) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前打开的对话框栈(由 <ty-dialog /> 宿主渲染)。 */
|
||||||
|
export const dialogs = reactive<DialogInstance[]>([])
|
||||||
|
|
||||||
|
let seq = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开一个对话框。返回 Promise:确认时 resolve 内容组件 submit() 返回的数据,
|
||||||
|
* 取消/关闭时 resolve null。
|
||||||
|
*/
|
||||||
|
export function showDialog(options: DialogOptions): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
dialogs.push({
|
||||||
|
id: ++seq,
|
||||||
|
options: { ...options, component: markRaw(options.component) },
|
||||||
|
resolve,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 关闭指定对话框并 resolve。 */
|
||||||
|
export function closeDialog(id: number, result?: any): void {
|
||||||
|
const idx = dialogs.findIndex((d) => d.id === id)
|
||||||
|
if (idx >= 0) {
|
||||||
|
const [dialog] = dialogs.splice(idx, 1)
|
||||||
|
dialog.resolve(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
13
typed-router.d.ts
vendored
13
typed-router.d.ts
vendored
@ -58,6 +58,13 @@ declare module 'vue-router/auto-routes' {
|
|||||||
Record<never, never>,
|
Record<never, never>,
|
||||||
| never
|
| never
|
||||||
>,
|
>,
|
||||||
|
'/system/user/reset-password-form': RouteRecordInfo<
|
||||||
|
'/system/user/reset-password-form',
|
||||||
|
'/system/user/reset-password-form',
|
||||||
|
Record<never, never>,
|
||||||
|
Record<never, never>,
|
||||||
|
| never
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,6 +108,12 @@ declare module 'vue-router/auto-routes' {
|
|||||||
views:
|
views:
|
||||||
| never
|
| never
|
||||||
}
|
}
|
||||||
|
'src/pages/system/user/reset-password-form.vue': {
|
||||||
|
routes:
|
||||||
|
| '/system/user/reset-password-form'
|
||||||
|
views:
|
||||||
|
| never
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user