task-248(admin.html观感对齐): 模态/抽屉容器统一(ModalShell/DrawerShell 收口尺寸与关闭语义)
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { dialogTitleOf, drawerLayoutSpec } from './modal-model'
|
||||
|
||||
/**
|
||||
* DrawerShell 右侧抽屉容器(module 13 task 248):封装 el-drawer,统一 admin 尺寸
|
||||
* 与关闭语义(遮罩/Esc),标题透传默认头部、footer 槽承接底部按钮,构成头/体/脚三段。
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{ modelValue: boolean; title?: string; subtitle?: string; width?: string | number }>(),
|
||||
{ title: '', subtitle: '', width: drawerLayoutSpec().width },
|
||||
)
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', value: boolean): void }>()
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v: boolean) => emit('update:modelValue', v),
|
||||
})
|
||||
const spec = computed(() => drawerLayoutSpec())
|
||||
const head = computed(() => dialogTitleOf({ title: props.title, subtitle: props.subtitle }))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
:size="width"
|
||||
:title="head.title"
|
||||
:close-on-click-modal="spec.maskClosable"
|
||||
:close-on-press-escape="spec.escClosable"
|
||||
class="admin-drawer-shell"
|
||||
>
|
||||
<p v-if="head.subtitle" class="admin-drawer-subtitle">{{ head.subtitle }}</p>
|
||||
<slot />
|
||||
<template #footer>
|
||||
<slot name="footer" />
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.admin-drawer-subtitle { margin: 0 0 12px; color: var(--admin-muted); font-size: 13px; }
|
||||
</style>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { dialogTitleOf, modalLayoutSpec } from './modal-model'
|
||||
|
||||
/**
|
||||
* ModalShell 居中模态容器(module 13 task 248):封装 el-dialog,统一 admin 尺寸/圆角
|
||||
* 与关闭语义,标题透传给 Element 默认头部;body 用默认槽、操作区走 footer 槽。
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{ modelValue: boolean; title?: string; subtitle?: string; width?: string | number }>(),
|
||||
{ title: '', subtitle: '', width: modalLayoutSpec().width },
|
||||
)
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', value: boolean): void }>()
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v: boolean) => emit('update:modelValue', v),
|
||||
})
|
||||
const spec = computed(() => modalLayoutSpec())
|
||||
const head = computed(() => dialogTitleOf({ title: props.title, subtitle: props.subtitle }))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:width="width"
|
||||
:title="head.title"
|
||||
:close-on-click-modal="spec.maskClosable"
|
||||
:close-on-press-escape="spec.escClosable"
|
||||
class="admin-modal-shell"
|
||||
>
|
||||
<p v-if="head.subtitle" class="admin-modal-subtitle">{{ head.subtitle }}</p>
|
||||
<slot />
|
||||
<template #footer>
|
||||
<slot name="footer" />
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.admin-modal-subtitle { margin: 0 0 12px; color: var(--admin-muted); font-size: 13px; }
|
||||
</style>
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 模态/抽屉布局模型(module 13 task 248):统一两种承载容器的尺寸与关闭语义,
|
||||
* 对齐 admin.html —— 居中 modal width min(920px,100vw-48)、radius14;右侧 drawer
|
||||
* width min(460px,100%);遮罩点击与 Esc 均关闭。页面接入统一尺寸与头/脚槽。
|
||||
*/
|
||||
export const ADMIN_MODAL_WIDTH = 'min(920px, 100vw - 48px)'
|
||||
export const ADMIN_DRAWER_WIDTH = 'min(460px, 100%)'
|
||||
export const ADMIN_MODAL_RADIUS = 14
|
||||
|
||||
export interface AdminContainerSpec {
|
||||
width: string
|
||||
radius?: number
|
||||
maskClosable: boolean
|
||||
escClosable: boolean
|
||||
}
|
||||
|
||||
export function modalLayoutSpec(): AdminContainerSpec {
|
||||
return { width: ADMIN_MODAL_WIDTH, radius: ADMIN_MODAL_RADIUS, maskClosable: true, escClosable: true }
|
||||
}
|
||||
|
||||
export function drawerLayoutSpec(): AdminContainerSpec {
|
||||
return { width: ADMIN_DRAWER_WIDTH, maskClosable: true, escClosable: true }
|
||||
}
|
||||
|
||||
/** 页面头标题归一:空/空白标题兜底「操作」,副标题去空白后无则省略。 */
|
||||
export function dialogTitleOf(opts: { title?: string; subtitle?: string }): { title: string; subtitle?: string } {
|
||||
const title = opts.title?.trim()
|
||||
const subtitle = opts.subtitle?.trim()
|
||||
return { title: title || '操作', ...(subtitle ? { subtitle } : {}) }
|
||||
}
|
||||
Reference in New Issue
Block a user