82 lines
2.0 KiB
Vue
82 lines
2.0 KiB
Vue
<script setup>
|
|
import { computed, onBeforeUnmount, onMounted } from 'vue'
|
|
import { CheckCircle2, XCircle, AlertTriangle, Info, X } from '@lucide/vue'
|
|
|
|
/* ---------- props / emits ---------- */
|
|
const props = defineProps({
|
|
/** 唯一标识,由管理器分配 */
|
|
id: { type: String, default: '' },
|
|
/** 类型:info / success / warning / error */
|
|
type: {
|
|
type: String,
|
|
default: 'info',
|
|
validator: (v) => ['info', 'success', 'warning', 'error'].includes(v),
|
|
},
|
|
/** 标题 */
|
|
title: { type: String, default: '' },
|
|
/** 描述内容 */
|
|
description: { type: String, default: '' },
|
|
/** 自动关闭时长(ms),<=0 时不自动关闭 */
|
|
duration: { type: Number, default: 4500 },
|
|
/** 是否显示关闭按钮 */
|
|
closable: { type: Boolean, default: true },
|
|
})
|
|
|
|
const emit = defineEmits(['close'])
|
|
|
|
/* ---------- 图标映射 ---------- */
|
|
const iconMap = {
|
|
info: Info,
|
|
success: CheckCircle2,
|
|
warning: AlertTriangle,
|
|
error: XCircle,
|
|
}
|
|
const iconComp = computed(() => iconMap[props.type] || Info)
|
|
|
|
/* ---------- 自动关闭计时 ---------- */
|
|
let timer = null
|
|
|
|
function clearTimer() {
|
|
if (timer) {
|
|
clearTimeout(timer)
|
|
timer = null
|
|
}
|
|
}
|
|
|
|
function startTimer() {
|
|
if (props.duration > 0) {
|
|
timer = setTimeout(() => emit('close'), props.duration)
|
|
}
|
|
}
|
|
|
|
function onClose() {
|
|
emit('close')
|
|
}
|
|
|
|
onMounted(startTimer)
|
|
onBeforeUnmount(clearTimer)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="fms-notification" :class="`fms-notification-${type}`" role="alert">
|
|
<component :is="iconComp" class="fms-notification-icon" />
|
|
<div class="fms-notification-body">
|
|
<p v-if="title" class="fms-notification-title">{{ title }}</p>
|
|
<p v-if="description" class="fms-notification-desc">{{ description }}</p>
|
|
</div>
|
|
<button
|
|
v-if="closable"
|
|
type="button"
|
|
class="fms-notification-close"
|
|
aria-label="关闭"
|
|
@click="onClose"
|
|
>
|
|
<X :size="14" />
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
@use './index.scss';
|
|
</style>
|