148 lines
2.9 KiB
Vue
148 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
interface Props {
|
|
title?: string
|
|
message?: string
|
|
confirmText?: string
|
|
cancelText?: string
|
|
danger?: boolean
|
|
}
|
|
|
|
withDefaults(defineProps<Props>(), {
|
|
title: '提示',
|
|
message: '',
|
|
confirmText: '确认',
|
|
cancelText: '取消',
|
|
danger: false,
|
|
})
|
|
|
|
const visible = defineModel<boolean>('visible', { default: false })
|
|
|
|
const emit = defineEmits<{ confirm: []; cancel: [] }>()
|
|
|
|
function onConfirm(): void {
|
|
emit('confirm')
|
|
visible.value = false
|
|
}
|
|
|
|
function onCancel(): void {
|
|
emit('cancel')
|
|
visible.value = false
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Teleport to="body">
|
|
<div v-if="visible" class="confirm-dialog" @click.self="onCancel">
|
|
<div class="confirm-dialog__panel">
|
|
<h3 class="confirm-dialog__title">
|
|
{{ title }}
|
|
</h3>
|
|
<div class="confirm-dialog__body">
|
|
<slot>{{ message }}</slot>
|
|
</div>
|
|
<div class="confirm-dialog__footer">
|
|
<button class="confirm-dialog__btn" @click="onCancel">
|
|
{{ cancelText }}
|
|
</button>
|
|
<button
|
|
class="confirm-dialog__btn confirm-dialog__btn--confirm"
|
|
:class="{ 'is-danger': danger }"
|
|
@click="onConfirm"
|
|
>
|
|
{{ confirmText }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Teleport>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.confirm-dialog {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 1000;
|
|
.flex(row, center);
|
|
background: transparent;
|
|
|
|
&__panel {
|
|
width: 660px;
|
|
max-width: calc(100vw - 32px);
|
|
padding: @spacing-base;
|
|
border-radius: @radius-lg;
|
|
background: @white;
|
|
box-shadow: @shadow-lg;
|
|
}
|
|
|
|
&__title {
|
|
position: relative;
|
|
margin-bottom: @spacing-base;
|
|
padding-left: 12px;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
color: @heading-color;
|
|
line-height: 20px;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 3px;
|
|
width: 3px;
|
|
height: 14px;
|
|
border-radius: 2px;
|
|
background: @primary-strong;
|
|
}
|
|
}
|
|
|
|
&__body {
|
|
margin-bottom: @spacing-lg;
|
|
font-size: 11px;
|
|
color: @text-color;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
&__footer {
|
|
.flex(row, flex-start);
|
|
gap: @spacing-sm;
|
|
}
|
|
|
|
&__btn {
|
|
flex: 1;
|
|
height: 36px;
|
|
padding: 0 @spacing-base;
|
|
border: none;
|
|
border-radius: @profile-radius;
|
|
background: @profile-quiet-btn;
|
|
color: @text-color;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
transition: all 0.2s;
|
|
|
|
&:hover {
|
|
border: none;
|
|
background: darken(@profile-quiet-btn, 4%);
|
|
color: @text-color;
|
|
}
|
|
|
|
&--confirm {
|
|
background: @primary-strong;
|
|
color: @white;
|
|
|
|
&:hover {
|
|
background: darken(@primary-strong, 6%);
|
|
color: @white;
|
|
}
|
|
|
|
&.is-danger {
|
|
background: @danger-color;
|
|
|
|
&:hover {
|
|
background: darken(@danger-color, 6%);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|