|
|
<template> |
|
|
<div class="confirm-overlay" v-if="visible" @click="handleCancel"> |
|
|
<div class="confirm-dialog" @click.stop> |
|
|
<div class="dialog-header"> |
|
|
<h3 class="dialog-title">{{ title }}</h3> |
|
|
</div> |
|
|
|
|
|
<div class="dialog-content"> |
|
|
<p class="dialog-message">{{ message }}</p> |
|
|
</div> |
|
|
|
|
|
<div class="dialog-actions"> |
|
|
<button |
|
|
class="dialog-btn dialog-btn-cancel" |
|
|
@click="handleCancel" |
|
|
> |
|
|
{{ cancelText }} |
|
|
</button> |
|
|
<button |
|
|
class="dialog-btn dialog-btn-confirm" |
|
|
@click="handleConfirm" |
|
|
:class="{ danger: type === 'danger' }" |
|
|
> |
|
|
{{ confirmText }} |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
|
|
|
<script setup> |
|
|
import { ref } from 'vue' |
|
|
|
|
|
const props = defineProps({ |
|
|
title: { |
|
|
type: String, |
|
|
default: '确认操作' |
|
|
}, |
|
|
message: { |
|
|
type: String, |
|
|
required: true |
|
|
}, |
|
|
confirmText: { |
|
|
type: String, |
|
|
default: '确认' |
|
|
}, |
|
|
cancelText: { |
|
|
type: String, |
|
|
default: '取消' |
|
|
}, |
|
|
type: { |
|
|
type: String, |
|
|
default: 'normal', |
|
|
} |
|
|
}) |
|
|
|
|
|
const emit = defineEmits(['confirm', 'cancel']) |
|
|
|
|
|
const visible = ref(false) |
|
|
|
|
|
const show = () => { |
|
|
visible.value = true |
|
|
} |
|
|
|
|
|
const hide = () => { |
|
|
visible.value = false |
|
|
} |
|
|
|
|
|
const handleConfirm = () => { |
|
|
emit('confirm') |
|
|
hide() |
|
|
} |
|
|
|
|
|
const handleCancel = () => { |
|
|
emit('cancel') |
|
|
hide() |
|
|
} |
|
|
|
|
|
defineExpose({ |
|
|
show, |
|
|
hide |
|
|
}) |
|
|
</script> |
|
|
|
|
|
<style scoped> |
|
|
.confirm-overlay { |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
right: 0; |
|
|
bottom: 0; |
|
|
background: rgba(0, 0, 0, 0.6); |
|
|
backdrop-filter: blur(10px); |
|
|
z-index: 3000; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
animation: fadeIn 0.2s ease-out; |
|
|
} |
|
|
|
|
|
.confirm-dialog { |
|
|
background: var(--bg-card); |
|
|
border-radius: 16px; |
|
|
padding: 0; |
|
|
width: 90%; |
|
|
max-width: 360px; |
|
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); |
|
|
animation: slideUp 0.2s ease-out; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.dialog-header { |
|
|
padding: 24px 24px 16px; |
|
|
border-bottom: 1px solid var(--border-lighter); |
|
|
} |
|
|
|
|
|
.dialog-title { |
|
|
font-size: 18px; |
|
|
font-weight: 600; |
|
|
color: var(--text-primary); |
|
|
margin: 0; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.dialog-content { |
|
|
padding: 16px 24px 24px; |
|
|
} |
|
|
|
|
|
.dialog-message { |
|
|
font-size: 16px; |
|
|
color: var(--text-secondary); |
|
|
line-height: 1.4; |
|
|
margin: 0; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.dialog-actions { |
|
|
display: flex; |
|
|
gap: 12px; |
|
|
padding: 0 24px 24px; |
|
|
} |
|
|
|
|
|
.dialog-btn { |
|
|
flex: 1; |
|
|
padding: 12px 24px; |
|
|
border: none; |
|
|
border-radius: 8px; |
|
|
font-size: 16px; |
|
|
font-weight: 500; |
|
|
cursor: pointer; |
|
|
transition: var(--transition-fast); |
|
|
min-height: 44px; |
|
|
} |
|
|
|
|
|
.dialog-btn-cancel { |
|
|
background: var(--bg-secondary); |
|
|
color: var(--text-secondary); |
|
|
border: 1px solid var(--border-light); |
|
|
} |
|
|
|
|
|
.dialog-btn-cancel:hover { |
|
|
background: var(--bg-tertiary); |
|
|
color: var(--text-primary); |
|
|
} |
|
|
|
|
|
.dialog-btn-confirm { |
|
|
background: var(--primary-color); |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.dialog-btn-confirm:hover { |
|
|
background: var(--primary-color-hover); |
|
|
} |
|
|
|
|
|
.dialog-btn-confirm.danger { |
|
|
background: #ff4444; |
|
|
} |
|
|
|
|
|
.dialog-btn-confirm.danger:hover { |
|
|
background: #ff2222; |
|
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; } |
|
|
to { opacity: 1; } |
|
|
} |
|
|
|
|
|
@keyframes slideUp { |
|
|
from { |
|
|
opacity: 0; |
|
|
transform: translateY(20px); |
|
|
} |
|
|
to { |
|
|
opacity: 1; |
|
|
transform: translateY(0); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 375px) { |
|
|
.confirm-dialog { |
|
|
width: 95%; |
|
|
max-width: none; |
|
|
} |
|
|
|
|
|
.dialog-header { |
|
|
padding: 20px 20px 12px; |
|
|
} |
|
|
|
|
|
.dialog-title { |
|
|
font-size: 16px; |
|
|
} |
|
|
|
|
|
.dialog-content { |
|
|
padding: 12px 20px 20px; |
|
|
} |
|
|
|
|
|
.dialog-message { |
|
|
font-size: 15px; |
|
|
} |
|
|
|
|
|
.dialog-actions { |
|
|
padding: 0 20px 20px; |
|
|
gap: 8px; |
|
|
} |
|
|
|
|
|
.dialog-btn { |
|
|
padding: 10px 16px; |
|
|
font-size: 15px; |
|
|
} |
|
|
} |
|
|
</style> |