Files
MrleeAdmin/frontend/admin/src/components/dialog/dialog.vue
T

241 lines
6.3 KiB
Vue
Raw Normal View History

2026-08-31 11:33:59 +08:00
<template>
<component
:is="dialogComponent"
:class="customClass"
:destroy-on-close="dialogPropsRef.destroyOnClose ?? true"
:close-on-click-modal="dialogPropsRef.closeOnClickModal ?? false"
:close-on-press-escape="dialogPropsRef.closeOnPressEscape ?? true"
v-model="dialogVisible"
:width="dialogPropsRef.width ?? '60%'"
:title="dialogPropsRef.title ?? '操作'"
:fullscreen="fullscreen"
:show-close="dialogPropsRef.showClose ?? true"
:direction="dialogPropsRef.direction ?? 'rtl'"
:size="dialogPropsRef.width ?? '40%'"
:modal="dialogPropsRef.modal ?? true"
:append-to-body="true"
:draggable="dialogPropsRef.draggable ?? true"
>
<template #header="{ close, titleId, titleClass }">
<div class="el-dialog__header-inner">
<span :id="titleId" :class="titleClass">{{ dialogPropsRef.title ?? '操作' }}</span>
<div class="dialog-header-actions">
<ElButton
v-if="dialogPropsRef.dialogType === 'dialog'"
class="dialog-header-btn"
@click="toggleFullscreen"
link
>
<template #icon>
<Icon :icon="fullscreen ? 'ri:fullscreen-exit-line' : 'ri:fullscreen-line'" />
</template>
</ElButton>
<ElButton class="dialog-header-btn" @click="close" link>
<Icon icon="ri:close-large-line" />
</ElButton>
</div>
</div>
</template>
<div class="m-dialog-body" v-loading="dialogPropsRef.loading ?? false">
<slot></slot>
</div>
<template #footer v-if="dialogPropsRef.footer">
<slot name="footer">
<slot name="prepend-footer"></slot>
<div class="footer-right">
<ElButton v-if="dialogPropsRef.showCancelButton" @click="handleCancel">取消</ElButton>
<slot name="center-footer"></slot>
<ElButton
v-if="dialogPropsRef.showConfirmButton"
type="primary"
@click="handleSubmit"
v-loading="dialogPropsRef.confirmLoading ?? false"
>确定</ElButton
>
</div>
<slot name="append-footer"></slot>
</slot>
</template>
</component>
</template>
<script setup lang="ts">
import { Icon } from '@/components/icon'
import { DialogEmits, MyDialogInstance, MyDialogProps } from './types'
import { ElDialog, ElDrawer } from 'element-plus'
const props = withDefaults(defineProps<MyDialogProps>(), {
loading: false,
confirmLoading: false,
showConfirmButton: true,
showCancelButton: true,
footer: true,
dialogType: 'dialog',
draggable: false
})
const emit = defineEmits<DialogEmits>()
const dialogVisible = ref(false)
const fullscreen = ref(false)
// 根据 dialogType 决定使用哪个组件
const dialogComponent = computed(() => {
return dialogPropsRef.value.dialogType === 'drawer' ? ElDrawer : ElDialog
})
// 根据 dialogType 设置不同的 customClass
const customClass = computed(() => {
const baseClass = dialogPropsRef.value.customClass ?? 'm-dialog'
return dialogPropsRef.value.dialogType === 'drawer'
? `${baseClass} m-drawer`
: `${baseClass} m-dialog-box`
})
const dialogPropsRef = ref<MyDialogProps>(props)
const toggleFullscreen = () => {
fullscreen.value = !fullscreen.value
}
const handleCancel = () => {
dialogVisible.value = false
if (props.onCancel) {
props.onCancel()
} else {
emit('cancel')
}
}
const handleSubmit = () => {
if (props.onConfirm) {
props.onConfirm()
} else {
emit('confirm')
}
}
const methods: MyDialogInstance = {
open() {
dialogVisible.value = true
},
close() {
dialogVisible.value = false
},
// 设置组件状态(props)
setState(state: MyDialogProps) {
return new Promise((resolve) => {
dialogPropsRef.value = {
...dialogPropsRef.value,
...state
}
nextTick(() => {
resolve()
})
})
},
getState(): Promise<MyDialogProps> {
return new Promise((resolve) => {
resolve(dialogPropsRef.value)
})
}
}
onMounted(() => {
emit('register', methods)
})
defineExpose(methods)
</script>
<style lang="scss" scoped>
.el-dialog__header-inner {
display: flex;
justify-content: space-between;
align-items: center;
}
.dialog-header-actions {
display: flex;
align-items: center;
}
.dialog-header-btn {
margin-left: 10px;
padding: 0;
width: 24px;
height: 24px;
:deep(.el-icon) {
font-size: 16px;
}
}
:deep(.el-dialog__header) {
display: block !important;
}
:deep(.el-drawer__header) {
margin-bottom: 0;
}
</style>
<style lang="scss">
// 全局样式,用于区分 dialog 和 drawer 的外观
.m-dialog-box {
padding: 0;
.el-dialog__header {
// background-color: var(--el-color-primary-light-6);
// border-bottom: 1px solid var(--el-border-color);
padding: 15px 20px !important;
}
.m-dialog-body {
background-color: var(--el-bg-color);
padding: 0;
}
.el-dialog__footer {
// background-color: var(--el-color-primary-light-6);
border-top: 1px solid var(--el-border-color);
padding: 15px 20px !important;
display: flex;
justify-content: flex-end;
align-items: center;
}
.el-dialog__body {
padding: 0 !important;
}
}
.m-drawer {
.el-drawer__header {
// background-color: var(--el-color-primary-light-6);
// border-bottom: 1px solid var(--el-border-color);
padding: 15px 20px !important;
margin-bottom: 0 !important;
}
.m-dialog-body {
background-color: var(--el-bg-color);
padding: 0;
}
.el-drawer__footer {
// background-color: var(--el-color-primary-light-6);
border-top: 1px solid var(--el-border-color);
padding: 15px 20px !important;
display: flex;
justify-content: flex-end;
align-items: center;
}
.el-drawer__body {
padding: 0 !important;
}
}
// 底部按钮两端对齐的样式(用于select-dept和select-position组件)
.m-dialog-footer-between {
.el-dialog__footer {
justify-content: space-between;
}
.el-drawer__footer {
justify-content: space-between;
}
}
</style>