164 lines
3.9 KiB
TypeScript
164 lines
3.9 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
export interface NotificationItem {
|
|
id: string
|
|
title: string
|
|
message?: string
|
|
type?: 'success' | 'warning' | 'info' | 'error'
|
|
duration?: number
|
|
showProgress?: boolean
|
|
progress?: number
|
|
zIndex?: number
|
|
onClose?: () => void
|
|
// 详细进度信息
|
|
detailTitle?: string
|
|
detailMessage?: string
|
|
}
|
|
|
|
const notifications = ref<NotificationItem[]>([])
|
|
let notificationIdCounter = 0
|
|
let zIndexCounter = 1000
|
|
|
|
export function useNotification() {
|
|
const addNotification = (notification: Omit<NotificationItem, 'id' | 'zIndex'>) => {
|
|
const id = `notification-${notificationIdCounter++}`
|
|
const newNotification: NotificationItem = {
|
|
...notification,
|
|
id,
|
|
zIndex: ++zIndexCounter,
|
|
}
|
|
|
|
notifications.value.push(newNotification)
|
|
|
|
// 自动关闭
|
|
if (notification.duration && notification.duration > 0) {
|
|
setTimeout(() => {
|
|
removeNotification(id)
|
|
}, notification.duration)
|
|
}
|
|
|
|
return id
|
|
}
|
|
|
|
const removeNotification = (id: string) => {
|
|
const index = notifications.value.findIndex((n) => n.id === id)
|
|
if (index !== -1) {
|
|
const notification = notifications.value[index]
|
|
notifications.value.splice(index, 1)
|
|
notification.onClose?.()
|
|
}
|
|
}
|
|
|
|
const success = (title: string, message?: string, options?: Partial<NotificationItem>) => {
|
|
return addNotification({
|
|
title,
|
|
message,
|
|
type: 'success',
|
|
duration: 3000,
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const warning = (title: string, message?: string, options?: Partial<NotificationItem>) => {
|
|
return addNotification({
|
|
title,
|
|
message,
|
|
type: 'warning',
|
|
duration: 3000,
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const info = (title: string, message?: string, options?: Partial<NotificationItem>) => {
|
|
return addNotification({
|
|
title,
|
|
message,
|
|
type: 'info',
|
|
duration: 3000,
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const error = (title: string, message?: string, options?: Partial<NotificationItem>) => {
|
|
return addNotification({
|
|
title,
|
|
message,
|
|
type: 'error',
|
|
duration: 5000,
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const progress = (
|
|
title: string,
|
|
current: number,
|
|
total: number,
|
|
options?: Partial<NotificationItem>,
|
|
) => {
|
|
const progressPercent = Math.round((current / total) * 100)
|
|
return addNotification({
|
|
title,
|
|
message: `${current}/${total}`,
|
|
type: 'info',
|
|
showProgress: true,
|
|
progress: progressPercent,
|
|
duration: 0, // 不自动关闭
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const updateProgress = (id: string, current: number, total: number) => {
|
|
const notification = notifications.value.find((n) => n.id === id)
|
|
if (notification) {
|
|
notification.progress = Math.round((current / total) * 100)
|
|
notification.message = `${current}/${total}`
|
|
}
|
|
}
|
|
|
|
const updateProgressDetail = (
|
|
id: string,
|
|
detailTitle: string,
|
|
detailMessage: string,
|
|
current?: number,
|
|
total?: number
|
|
) => {
|
|
const notification = notifications.value.find((n) => n.id === id)
|
|
if (notification) {
|
|
notification.detailTitle = detailTitle
|
|
notification.detailMessage = detailMessage
|
|
if (current !== undefined && total !== undefined) {
|
|
notification.progress = Math.round((current / total) * 100)
|
|
notification.message = `${current}/${total}`
|
|
}
|
|
}
|
|
}
|
|
|
|
// 更新通知的主标题
|
|
const updateNotificationTitle = (id: string, title: string) => {
|
|
const notification = notifications.value.find((n) => n.id === id)
|
|
if (notification) {
|
|
notification.title = title
|
|
}
|
|
}
|
|
|
|
const clear = () => {
|
|
notifications.value.forEach((n) => n.onClose?.())
|
|
notifications.value = []
|
|
}
|
|
|
|
return {
|
|
notifications,
|
|
addNotification,
|
|
removeNotification,
|
|
success,
|
|
warning,
|
|
info,
|
|
error,
|
|
progress,
|
|
updateProgress,
|
|
updateProgressDetail,
|
|
updateNotificationTitle,
|
|
clear,
|
|
}
|
|
}
|