mirror of
https://github.com/pure-admin/pure-admin-thin.git
synced 2025-11-26 12:33:38 +08:00
feat: 新增角色管理、岗位管理
This commit is contained in:
173
src/components/VDialog/VDialog.vue
Normal file
173
src/components/VDialog/VDialog.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:fullscreen="fullScreen"
|
||||
class="v-dialog"
|
||||
:class="dialogClazz"
|
||||
:draggable="props.draggable"
|
||||
:show-close="false"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<template #header>
|
||||
<slot name="header">
|
||||
<div
|
||||
style="
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 24px;
|
||||
font-weight: bold;
|
||||
color: rgb(118 131 164);
|
||||
"
|
||||
>
|
||||
<div v-text="props.title" />
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<el-button
|
||||
v-if="props.showFullScreen"
|
||||
:icon="fullScreen ? FullScreenMinimize : FullScreenMaximize"
|
||||
link
|
||||
@click="requestFullScreen"
|
||||
class="header-btn"
|
||||
/>
|
||||
<el-button
|
||||
:icon="Close"
|
||||
link
|
||||
@click="handleCloseClick"
|
||||
class="header-btn"
|
||||
style="margin-left: 0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
<template v-if="useBodyScrolling">
|
||||
<el-scrollbar :max-height="bodyHeight" always>
|
||||
<slot name="default" />
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot name="default" />
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<slot name="footer" v-if="!props.hiddenFooter">
|
||||
<div style="display: flex; justify-content: center">
|
||||
<el-button
|
||||
:loading="props.loading"
|
||||
type="primary"
|
||||
@click="handleConfirm"
|
||||
>{{ props.confirmText }}</el-button
|
||||
>
|
||||
<el-button :loading="props.loading" @click="handleCancel">{{
|
||||
cancelText
|
||||
}}</el-button>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { ElDialog, ElButton, ElScrollbar } from "element-plus";
|
||||
import { DialogEmits, DialogProps } from "./dialog";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import FullScreenMaximize from "@/assets/svg/FullScreenMaximize.svg?component";
|
||||
import FullScreenMinimize from "@/assets/svg/FullScreenMinimize.svg?component";
|
||||
|
||||
const props = withDefaults(defineProps<DialogProps>(), {
|
||||
fullScreen: undefined,
|
||||
confirmText: "确定",
|
||||
cancelText: "取消",
|
||||
disableFooter: false,
|
||||
useBodyScrolling: false,
|
||||
fixedBodyHeight: true,
|
||||
draggable: true,
|
||||
loading: false
|
||||
});
|
||||
const emits = defineEmits<DialogEmits>();
|
||||
|
||||
const visible = computed<boolean>({
|
||||
get: () => {
|
||||
return props.modelValue;
|
||||
},
|
||||
set: v => emits("update:modelValue", v)
|
||||
});
|
||||
|
||||
const fullScreenState = ref(!!props.initFullScreen);
|
||||
const fullScreen = computed<boolean>({
|
||||
get: () => {
|
||||
console.log("fullScreen getter", props.fullScreen, fullScreenState.value);
|
||||
// 非受控模式,状态完全由组件内部控制
|
||||
if (props.fullScreen === undefined) {
|
||||
return fullScreenState.value;
|
||||
} else {
|
||||
return props.fullScreen;
|
||||
}
|
||||
},
|
||||
set: v => {
|
||||
fullScreenState.value = v;
|
||||
console.log("fullScreen setter", v, props.fullScreen);
|
||||
// 受控模式,将状态更新到父组件
|
||||
if (props.fullScreen !== undefined) {
|
||||
emits("update:fullScreen", v);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// const fullScreen = ref<boolean>(false)
|
||||
function requestFullScreen() {
|
||||
fullScreen.value = !fullScreen.value;
|
||||
}
|
||||
|
||||
const bodyHeight = computed(() => {
|
||||
const footerHeight = props.hiddenFooter ? "0" : "52px";
|
||||
if (props.fullScreen) {
|
||||
// footerHeight=52,headerHeight=44,padding=12
|
||||
return `calc(100dvh - ${footerHeight} - 44px)`;
|
||||
} else {
|
||||
return `calc(70dvh - ${footerHeight} - 44px)`;
|
||||
}
|
||||
});
|
||||
|
||||
const dialogClazz = computed(() => {
|
||||
const classList: string[] = ["v-dialog"];
|
||||
if (!props.fixedBodyHeight) {
|
||||
classList.push("flex-body");
|
||||
}
|
||||
if (props.hiddenFooter) {
|
||||
classList.push("hidden-footer");
|
||||
}
|
||||
return classList;
|
||||
});
|
||||
|
||||
function handleConfirm() {
|
||||
emits("confirm");
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
emits("cancel");
|
||||
}
|
||||
|
||||
function handleCloseClick() {
|
||||
visible.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.header-btn :deep(.el-icon),
|
||||
.header-btn :deep(.el-icon svg) {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
</style>
|
||||
62
src/components/VDialog/dialog.css
Normal file
62
src/components/VDialog/dialog.css
Normal file
@@ -0,0 +1,62 @@
|
||||
html.dark .v-dialog {
|
||||
--header-bg-color: #171d1e;
|
||||
--footer-bg-color: #171d1e;
|
||||
}
|
||||
|
||||
.v-dialog {
|
||||
--header-bg-color: #f5f7fa;
|
||||
--footer-bg-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog.hidden-footer .el-dialog__footer {
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 10px;
|
||||
/*border-top: 1px solid var(--el-border-color);*/
|
||||
/*border-bottom: 1px solid var(--el-border-color);*/
|
||||
box-sizing: border-box;
|
||||
background-color: var(--header-bg-color);
|
||||
position: relative; /* 防止被表单覆盖底部 */
|
||||
z-index: calc(var(--el-index-normal) + 1);
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog {
|
||||
box-sizing: border-box;
|
||||
margin: 15dvh auto;
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog.is-fullscreen {
|
||||
box-sizing: border-box;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog .el-dialog__header {
|
||||
padding: 10px 16px;
|
||||
/*border-bottom: 1px solid var(--el-border-color);*/
|
||||
margin-right: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--header-bg-color);
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog--center .el-dialog__body,
|
||||
.el-dialog__body {
|
||||
padding: 16px 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog.is-fullscreen .el-dialog__body {
|
||||
height: calc(100dvh - 44px - 52px);
|
||||
max-height: calc(100dvh - 44px - 52px);
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog .el-dialog__body {
|
||||
height: calc(70dvh - 44px - 52px);
|
||||
}
|
||||
|
||||
.v-dialog.el-dialog.flex-body:not(.is-fullscreen) .el-dialog__body {
|
||||
height: initial;
|
||||
max-height: calc(70dvh - 44px - 52px);
|
||||
}
|
||||
47
src/components/VDialog/dialog.ts
Normal file
47
src/components/VDialog/dialog.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
export interface DialogProps {
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* 显隐
|
||||
*/
|
||||
modelValue: boolean;
|
||||
|
||||
/**
|
||||
* 初始化全屏状态
|
||||
*/
|
||||
initFullScreen?: boolean | undefined;
|
||||
|
||||
/**
|
||||
* 展示全屏按钮
|
||||
*/
|
||||
showFullScreen?: boolean;
|
||||
|
||||
/**
|
||||
* 全屏
|
||||
*/
|
||||
fullScreen?: boolean | undefined;
|
||||
confirmText?: string;
|
||||
cancelText?: string;
|
||||
loading?: boolean;
|
||||
/**
|
||||
* 使用el-scrollbar包裹对话框body
|
||||
*/
|
||||
useBodyScrolling?: boolean;
|
||||
/**
|
||||
* 固定对话框body高度
|
||||
*/
|
||||
fixedBodyHeight?: boolean;
|
||||
|
||||
draggable?: boolean;
|
||||
|
||||
hiddenFooter?: boolean;
|
||||
}
|
||||
|
||||
export type DialogEmits = {
|
||||
"update:modelValue": [val: boolean];
|
||||
"update:fullScreen": [val: boolean];
|
||||
confirm: [];
|
||||
cancel: [];
|
||||
};
|
||||
Reference in New Issue
Block a user