feat: 新增角色管理、岗位管理

This commit is contained in:
Lyp
2023-07-23 20:58:30 +08:00
parent 6719fd8290
commit b068518ba6
20 changed files with 950 additions and 292 deletions

View 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>

View 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);
}

View 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: [];
};