feat(弹窗组件): 新增纯信息弹窗showMessage

This commit is contained in:
hzj 2026-03-26 15:11:55 +08:00
parent 7b9472258b
commit 9cf9464d9c
2 changed files with 78 additions and 45 deletions

View File

@ -1,19 +1,19 @@
<template>
<div v-if="visible" class="modal-overlay" @click="handleOverlayClick">
<div class="modal" :class="[animationClass, modalTypeClass]">
<!-- 图标 -->
<div class="modal-icon">
<!-- 图标 - simple 类型不显示 -->
<div class="modal-icon" v-if="!isSimple">
<div class="icon-circle" :class="iconCircleClass">
<span class="icon-symbol" :class="iconSymbolClass">{{ iconSymbol }}</span>
</div>
</div>
<!-- 标题 -->
<div class="modal-title" v-if="title">{{ title }}</div>
<!-- 标题 - simple 类型不显示 -->
<div class="modal-title" v-if="title && !isSimple">{{ title }}</div>
<!-- 消息内容 -->
<div class="modal-message">{{ message }}</div>
<!-- 按钮 -->
<div class="modal-actions">
<button class="modal-btn" :class="buttonClass" @click="confirm">{{ confirmText }}</button>
@ -28,29 +28,29 @@ import { ref, onMounted, computed } from 'vue'
const props = defineProps({
title: {
type: String,
default: 'Notice'
default: 'Notice',
},
message: {
type: String,
required: true
required: true,
},
type: {
type: String,
default: 'error', // 'error' | 'warning' | 'success' | 'info'
validator: (value) => ['error', 'warning', 'success', 'info'].includes(value)
validator: (value) => ['error', 'warning', 'success', 'info', 'simple'].includes(value), // simple
},
confirmText: {
type: String,
default: 'OK'
default: 'OK',
},
clickToClose: {
type: Boolean,
default: true
default: true,
},
duration: {
type: Number,
default: null //
}
default: null, //
},
})
const emit = defineEmits(['confirm', 'close'])
@ -58,13 +58,16 @@ const emit = defineEmits(['confirm', 'close'])
const visible = ref(false)
const animationClass = ref('')
//
const isSimple = computed(() => props.type === 'simple')
//
const iconSymbol = computed(() => {
const symbols = {
error: '✕',
warning: '⚠',
success: '✓',
info: 'i'
info: 'i',
}
return symbols[props.type] || symbols.error
})
@ -80,7 +83,7 @@ const buttonClass = computed(() => `modal-btn-${props.type}`)
const show = () => {
visible.value = true
animationClass.value = 'modal-enter'
//
if (props.duration && props.duration > 0) {
setTimeout(() => {
@ -116,7 +119,7 @@ onMounted(() => {
//
defineExpose({
show,
close
close,
})
</script>
@ -139,7 +142,9 @@ defineExpose({
.modal {
background: white;
border-radius: 16px;
box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
box-shadow:
0 20px 25px rgba(0, 0, 0, 0.1),
0 10px 10px rgba(0, 0, 0, 0.04);
width: 100%;
max-width: 320px;
padding: 24px 20px 20px;
@ -175,7 +180,7 @@ defineExpose({
.modal-title {
font-size: 18px;
font-weight: 600;
color: #1F2937;
color: #1f2937;
margin-bottom: 12px;
line-height: 1.4;
}
@ -183,7 +188,7 @@ defineExpose({
/* 消息内容 */
.modal-message {
font-size: 14px;
color: #6B7280;
color: #6b7280;
line-height: 1.5;
margin-bottom: 20px;
word-wrap: break-word;
@ -213,52 +218,52 @@ defineExpose({
/* Error 类型样式 */
.modal-error .icon-circle-error {
background-color: #FEE2E2;
border-color: #FECACA;
background-color: #fee2e2;
border-color: #fecaca;
}
.modal-error .icon-symbol-error {
color: #DC2626;
color: #dc2626;
}
.modal-error .modal-btn-error {
background-color: #DC2626;
background-color: #dc2626;
}
.modal-error .modal-btn-error:hover {
background-color: #B91C1C;
background-color: #b91c1c;
}
.modal-error .modal-btn-error:active {
background-color: #991B1B;
background-color: #991b1b;
}
/* Warning 类型样式 */
.modal-warning .icon-circle-warning {
background-color: #FEF3C7;
border-color: #FDE68A;
background-color: #fef3c7;
border-color: #fde68a;
}
.modal-warning .icon-symbol-warning {
color: #D97706;
color: #d97706;
}
.modal-warning .modal-btn-warning {
background-color: #D97706;
background-color: #d97706;
}
.modal-warning .modal-btn-warning:hover {
background-color: #B45309;
background-color: #b45309;
}
.modal-warning .modal-btn-warning:active {
background-color: #92400E;
background-color: #92400e;
}
/* Success 类型样式 */
.modal-success .icon-circle-success {
background-color: #D1FAE5;
border-color: #A7F3D0;
background-color: #d1fae5;
border-color: #a7f3d0;
}
.modal-success .icon-symbol-success {
@ -274,29 +279,48 @@ defineExpose({
}
.modal-success .modal-btn-success:active {
background-color: #065F46;
background-color: #065f46;
}
/* Info 类型样式 */
.modal-info .icon-circle-info {
background-color: #DBEAFE;
border-color: #BFDBFE;
background-color: #dbeafe;
border-color: #bfdbfe;
}
.modal-info .icon-symbol-info {
color: #2563EB;
color: #2563eb;
}
.modal-info .modal-btn-info {
background-color: #2563EB;
background-color: #2563eb;
}
.modal-info .modal-btn-info:hover {
background-color: #1D4ED8;
background-color: #1d4ed8;
}
.modal-info .modal-btn-info:active {
background-color: #1E40AF;
background-color: #1e40af;
}
/* 新增 simple 类型样式 */
.modal-simple .modal-message {
font-size: 15px;
color: #374151;
margin-bottom: 24px;
}
.modal-simple .modal-btn {
background-color: #2563eb;
}
.modal-simple .modal-btn:hover {
background-color: #1d4ed8;
}
.modal-simple .modal-btn:active {
background-color: #1e40af;
}
/* 动画效果 */
@ -350,20 +374,20 @@ defineExpose({
max-width: 280px;
padding: 20px 16px 16px;
}
.icon-circle {
width: 48px;
height: 48px;
}
.icon-symbol {
font-size: 20px;
}
.modal-title {
font-size: 16px;
}
.modal-message {
font-size: 13px;
}

View File

@ -109,6 +109,15 @@ export const showToast = (message, options = {}) => {
return errorModal.show(message, defaultOptions)
}
export const showMessage = (message, options = {}) => {
const defaultOptions = {
confirmText: i18n.global.t('ok') || 'OK',
type: 'simple',
...options,
}
return errorModal.show(message, defaultOptions)
}
// 错误处理的专用方法
export const handleError = (error) => {
let message = i18n.global.t('unknown_error') || 'An unknown error occurred'