mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-05-07 13:30:57 +08:00
feat: toast样式优化
This commit is contained in:
+7
-1
@@ -26,6 +26,12 @@ const tooltip = {
|
||||
delayDuration: 100,
|
||||
}
|
||||
|
||||
const toaster = {
|
||||
position: 'top-center' as const,
|
||||
progress: false,
|
||||
duration: 2000,
|
||||
}
|
||||
|
||||
// 应用启动时初始化
|
||||
onMounted(async () => {
|
||||
// 平台检测 - 设置 CSS 类名以驱动平台差异化样式(如标题栏安全区域高度)
|
||||
@@ -46,7 +52,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UApp :tooltip="tooltip">
|
||||
<UApp :tooltip="tooltip" :toaster="toaster">
|
||||
<!-- 自定义标题栏 - 拖拽区域 + 窗口控制按钮 -->
|
||||
<TitleBar />
|
||||
<div class="relative flex h-screen w-full overflow-hidden bg-gray-50 dark:bg-gray-900">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import ConversationList from './chat/ConversationList.vue'
|
||||
import DataSourcePanel from './chat/DataSourcePanel.vue'
|
||||
import ChatMessage from './chat/ChatMessage.vue'
|
||||
@@ -162,20 +162,13 @@ const showWelcomeCard = computed(() => {
|
||||
})
|
||||
|
||||
function showRunningTaskToast() {
|
||||
toast.add({
|
||||
title: t('ai.chat.backgroundTask.runningTitle'),
|
||||
toast.warn(t('ai.chat.backgroundTask.runningTitle'), {
|
||||
description: t('ai.chat.backgroundTask.runningDescription'),
|
||||
color: 'warning',
|
||||
icon: 'i-heroicons-sparkles',
|
||||
})
|
||||
}
|
||||
|
||||
function showLockedActionToast() {
|
||||
toast.add({
|
||||
title: t('ai.chat.backgroundTask.blockedAction'),
|
||||
color: 'warning',
|
||||
icon: 'i-heroicons-lock-closed',
|
||||
})
|
||||
toast.warn(t('ai.chat.backgroundTask.blockedAction'))
|
||||
}
|
||||
|
||||
// 选择助手
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useAssistantStore, type AssistantConfigFull } from '@/stores/assistant'
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -123,7 +123,7 @@ async function loadConfig(id: string) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[AssistantConfigModal] Failed to load config:', error)
|
||||
toast.add({ title: t('ai.assistant.toast.loadFailed'), description: String(error), color: 'error' })
|
||||
toast.fail(t('ai.assistant.toast.loadFailed'), { description: String(error) })
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
@@ -146,34 +146,30 @@ async function handleSave() {
|
||||
if (isCreateMode.value) {
|
||||
const result = await assistantStore.createAssistant(payload)
|
||||
if (result.success) {
|
||||
toast.add({ title: t('ai.assistant.toast.createSuccess'), color: 'success' })
|
||||
toast.success(t('ai.assistant.toast.createSuccess'))
|
||||
emit('created', result.id!)
|
||||
closeModal()
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('ai.assistant.toast.createFailed'),
|
||||
toast.fail(t('ai.assistant.toast.createFailed'), {
|
||||
description: result.error || t('ai.assistant.toast.unknownError'),
|
||||
color: 'error',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (!props.assistantId) return
|
||||
const result = await assistantStore.updateAssistant(props.assistantId, payload)
|
||||
if (result.success) {
|
||||
toast.add({ title: t('ai.assistant.toast.saveSuccess'), color: 'success' })
|
||||
toast.success(t('ai.assistant.toast.saveSuccess'))
|
||||
emit('saved')
|
||||
closeModal()
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('ai.assistant.toast.saveFailed'),
|
||||
toast.fail(t('ai.assistant.toast.saveFailed'), {
|
||||
description: result.error || t('ai.assistant.toast.unknownError'),
|
||||
color: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[AssistantConfigModal] Save failed:', error)
|
||||
toast.add({ title: t('ai.assistant.toast.saveFailed'), description: String(error), color: 'error' })
|
||||
toast.fail(t('ai.assistant.toast.saveFailed'), { description: String(error) })
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
@@ -186,18 +182,16 @@ async function handleReset() {
|
||||
try {
|
||||
const result = await assistantStore.resetAssistant(props.assistantId)
|
||||
if (result.success) {
|
||||
toast.add({ title: t('ai.assistant.toast.resetSuccess'), color: 'success' })
|
||||
toast.success(t('ai.assistant.toast.resetSuccess'))
|
||||
await loadConfig(props.assistantId)
|
||||
emit('saved')
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('ai.assistant.toast.resetFailed'),
|
||||
toast.fail(t('ai.assistant.toast.resetFailed'), {
|
||||
description: result.error || t('ai.assistant.toast.unknownError'),
|
||||
color: 'error',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
toast.add({ title: t('ai.assistant.toast.resetFailed'), description: String(error), color: 'error' })
|
||||
toast.fail(t('ai.assistant.toast.resetFailed'), { description: String(error) })
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ref, watch, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAssistantStore, type CloudAssistantItem } from '@/stores/assistant'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -74,9 +74,9 @@ async function handleImportCloud(item: CloudAssistantItem) {
|
||||
try {
|
||||
const result = await assistantStore.importFromCloud(item)
|
||||
if (result.success) {
|
||||
toast.add({ title: t('ai.assistant.market.importSuccess'), color: 'success' })
|
||||
toast.success(t('ai.assistant.market.importSuccess'))
|
||||
} else {
|
||||
toast.add({ title: t('ai.assistant.market.importFailed'), description: result.error, color: 'error' })
|
||||
toast.fail(t('ai.assistant.market.importFailed'), { description: result.error })
|
||||
}
|
||||
} finally {
|
||||
const next = new Set(importingIds.value)
|
||||
@@ -91,14 +91,14 @@ async function handleReimportCloud(item: CloudAssistantItem) {
|
||||
try {
|
||||
const deleteResult = await assistantStore.deleteAssistant(item.id)
|
||||
if (!deleteResult.success) {
|
||||
toast.add({ title: t('ai.assistant.market.importFailed'), description: deleteResult.error, color: 'error' })
|
||||
toast.fail(t('ai.assistant.market.importFailed'), { description: deleteResult.error })
|
||||
return
|
||||
}
|
||||
const importResult = await assistantStore.importFromCloud(item)
|
||||
if (importResult.success) {
|
||||
toast.add({ title: t('ai.assistant.market.importSuccess'), color: 'success' })
|
||||
toast.success(t('ai.assistant.market.importSuccess'))
|
||||
} else {
|
||||
toast.add({ title: t('ai.assistant.market.importFailed'), description: importResult.error, color: 'error' })
|
||||
toast.fail(t('ai.assistant.market.importFailed'), { description: importResult.error })
|
||||
}
|
||||
} finally {
|
||||
const next = new Set(importingIds.value)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import dayjs from 'dayjs'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import type { ContentBlock, ToolBlockContent } from '@/composables/useAIChat'
|
||||
import CaptureButton from '@/components/common/CaptureButton.vue'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
|
||||
const { t, te, locale } = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -286,20 +286,9 @@ async function handleCopyMarkdown() {
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(copyMarkdownText.value)
|
||||
toast.add({
|
||||
title: t('ai.chat.message.copy.success'),
|
||||
color: 'primary',
|
||||
icon: 'i-heroicons-clipboard-document-check',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.success(t('ai.chat.message.copy.success'))
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: t('ai.chat.message.copy.failed'),
|
||||
description: String(error),
|
||||
color: 'error',
|
||||
icon: 'i-heroicons-x-circle',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail(t('ai.chat.message.copy.failed'), { description: String(error) })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { usePromptStore } from '@/stores/prompt'
|
||||
import { useLLMStore } from '@/stores/llm'
|
||||
@@ -95,12 +95,7 @@ async function switchModelConfig(configId: string) {
|
||||
if (success) {
|
||||
isModelPopoverOpen.value = false
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('ai.chat.statusBar.model.switchFailed'),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.fail(t('ai.chat.statusBar.model.switchFailed'))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +118,7 @@ async function handleExportConversation() {
|
||||
])
|
||||
|
||||
if (!conv || messages.length === 0) {
|
||||
toast.add({
|
||||
title: t('ai.chat.conversation.export.noMessages'),
|
||||
icon: 'i-heroicons-exclamation-triangle',
|
||||
color: 'warning',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.warn(t('ai.chat.conversation.export.noMessages'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -152,9 +142,7 @@ async function handleExportConversation() {
|
||||
toast.add({
|
||||
title: t('common.exportSuccess'),
|
||||
description: filename,
|
||||
icon: 'i-heroicons-check-circle',
|
||||
color: 'primary',
|
||||
duration: 2000,
|
||||
actions: [
|
||||
{
|
||||
label: t('common.openFolder'),
|
||||
@@ -165,23 +153,11 @@ async function handleExportConversation() {
|
||||
],
|
||||
})
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('common.exportFailed'),
|
||||
description: result.error,
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.fail(t('common.exportFailed'), { description: result.error })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导出对话失败:', error)
|
||||
toast.add({
|
||||
title: t('common.exportFailed'),
|
||||
description: String(error),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.fail(t('common.exportFailed'), { description: String(error) })
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
@@ -194,23 +170,13 @@ async function openAiLogFile() {
|
||||
try {
|
||||
const result = await window.aiApi.showAiLogFile()
|
||||
if (!result?.success) {
|
||||
toast.add({
|
||||
title: t('ai.chat.statusBar.log.openFailed'),
|
||||
toast.fail(t('ai.chat.statusBar.log.openFailed'), {
|
||||
description: result?.error || t('ai.chat.statusBar.log.openFailedDesc'),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 2000,
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('打开 AI 日志失败:', error)
|
||||
toast.add({
|
||||
title: t('ai.chat.statusBar.log.openFailed'),
|
||||
description: String(error),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.fail(t('ai.chat.statusBar.log.openFailed'), { description: String(error) })
|
||||
} finally {
|
||||
isOpeningLog.value = false
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSkillStore, type CloudSkillItem } from '@/stores/skill'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -71,9 +71,9 @@ async function handleImportCloud(item: CloudSkillItem) {
|
||||
try {
|
||||
const result = await skillStore.importFromCloud(item)
|
||||
if (result.success) {
|
||||
toast.add({ title: t('ai.skill.market.importSuccess'), color: 'success' })
|
||||
toast.success(t('ai.skill.market.importSuccess'))
|
||||
} else {
|
||||
toast.add({ title: t('ai.skill.market.importFailed'), description: result.error, color: 'error' })
|
||||
toast.fail(t('ai.skill.market.importFailed'), { description: result.error })
|
||||
}
|
||||
} finally {
|
||||
const next = new Set(importingIds.value)
|
||||
@@ -88,14 +88,14 @@ async function handleReimportCloud(item: CloudSkillItem) {
|
||||
try {
|
||||
const deleteResult = await skillStore.deleteSkill(item.id)
|
||||
if (!deleteResult.success) {
|
||||
toast.add({ title: t('ai.skill.market.importFailed'), description: deleteResult.error, color: 'error' })
|
||||
toast.fail(t('ai.skill.market.importFailed'), { description: deleteResult.error })
|
||||
return
|
||||
}
|
||||
const importResult = await skillStore.importFromCloud(item)
|
||||
if (importResult.success) {
|
||||
toast.add({ title: t('ai.skill.market.importSuccess'), color: 'success' })
|
||||
toast.success(t('ai.skill.market.importSuccess'))
|
||||
} else {
|
||||
toast.add({ title: t('ai.skill.market.importFailed'), description: importResult.error, color: 'error' })
|
||||
toast.fail(t('ai.skill.market.importFailed'), { description: importResult.error })
|
||||
}
|
||||
} finally {
|
||||
const next = new Set(importingIds.value)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import { ref, computed, watch, toRaw } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import ConditionPanel from './ConditionPanel.vue'
|
||||
import SessionPanel from './SessionPanel.vue'
|
||||
@@ -274,28 +274,15 @@ async function exportFeedPack() {
|
||||
const exportResult = await window.aiApi.exportFilterResultToFile(exportParams)
|
||||
|
||||
if (exportResult.success && exportResult.filePath) {
|
||||
toast.add({
|
||||
title: t('analysis.filter.exportSuccess'),
|
||||
description: exportResult.filePath,
|
||||
color: 'green',
|
||||
icon: 'i-heroicons-check-circle',
|
||||
})
|
||||
toast.success(t('analysis.filter.exportSuccess'), { description: exportResult.filePath })
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('analysis.filter.exportFailed'),
|
||||
toast.fail(t('analysis.filter.exportFailed'), {
|
||||
description: exportResult.error || t('common.error.unknown'),
|
||||
color: 'red',
|
||||
icon: 'i-heroicons-x-circle',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error)
|
||||
toast.add({
|
||||
title: t('analysis.filter.exportFailed'),
|
||||
description: String(error),
|
||||
color: 'red',
|
||||
icon: 'i-heroicons-x-circle',
|
||||
})
|
||||
toast.fail(t('analysis.filter.exportFailed'), { description: String(error) })
|
||||
} finally {
|
||||
stopExportProgressListener()
|
||||
isExporting.value = false
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import dayjs from 'dayjs'
|
||||
import type { SQLResult } from './types'
|
||||
@@ -240,9 +240,7 @@ async function exportResult() {
|
||||
toast.add({
|
||||
title: t('common.exportSuccess'),
|
||||
description: filename,
|
||||
icon: 'i-heroicons-check-circle',
|
||||
color: 'primary',
|
||||
duration: 3000,
|
||||
actions: [
|
||||
{
|
||||
label: t('common.openFolder'),
|
||||
@@ -253,23 +251,11 @@ async function exportResult() {
|
||||
],
|
||||
})
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('common.exportFailed'),
|
||||
description: result.error,
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail(t('common.exportFailed'), { description: result.error })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('导出失败:', err)
|
||||
toast.add({
|
||||
title: t('common.exportFailed'),
|
||||
description: String(err),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail(t('common.exportFailed'), { description: String(err) })
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useVirtualizer } from '@tanstack/vue-virtual'
|
||||
import BatchSummaryModal from './BatchSummaryModal.vue'
|
||||
|
||||
@@ -247,18 +247,12 @@ async function generateSummary(session: ChatSessionItem, event: Event) {
|
||||
allSessions.value[index] = { ...allSessions.value[index], summary: result.summary }
|
||||
}
|
||||
} else {
|
||||
toast.add({
|
||||
title: t('records.summaryFailed', '摘要生成失败'),
|
||||
toast.fail(t('records.summaryFailed', '摘要生成失败'), {
|
||||
description: result.error || t('records.summaryUnknownError', '未知错误'),
|
||||
color: 'error',
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: t('records.summaryFailed', '摘要生成失败'),
|
||||
description: String(error),
|
||||
color: 'error',
|
||||
})
|
||||
toast.fail(t('records.summaryFailed', '摘要生成失败'), { description: String(error) })
|
||||
} finally {
|
||||
generatingSummaryIds.value.delete(session.id)
|
||||
console.log('[SessionTimeline] 生成完成')
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
export { useAsyncData, useMultipleAsyncData } from './useAsyncData'
|
||||
export { usePageAnchors, type AnchorItem } from './usePageAnchors'
|
||||
export { useAIChat, type ChatMessage, type SourceMessage } from './useAIChat'
|
||||
export { useToast } from './useToast'
|
||||
export { useScreenCapture, type ScreenCaptureOptions } from './useScreenCapture'
|
||||
export { useTimeSelect } from './useTimeSelect'
|
||||
export { useSessionAnalysisPageBase, useSessionHeaderDescription } from './useSessionAnalysisPageBase'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
import { captureAsImageData } from '@/utils/snapCapture'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useLayoutStore } from '@/stores/layout'
|
||||
|
||||
/** 默认移动端最大宽度 */
|
||||
@@ -53,9 +53,7 @@ export function useScreenCapture() {
|
||||
toast.add({
|
||||
title: '截图已保存',
|
||||
description: `已保存到下载目录:${filename}`,
|
||||
icon: 'i-heroicons-check-circle',
|
||||
color: 'primary',
|
||||
duration: 3000,
|
||||
actions: [
|
||||
{
|
||||
label: '打开目录',
|
||||
@@ -70,13 +68,7 @@ export function useScreenCapture() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存图片失败:', error)
|
||||
toast.add({
|
||||
title: '保存失败',
|
||||
description: String(error),
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail('保存失败', { description: String(error) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +80,7 @@ export function useScreenCapture() {
|
||||
|
||||
toast.add({
|
||||
title: '截图已复制到剪贴板',
|
||||
icon: 'i-heroicons-check-circle',
|
||||
color: 'primary',
|
||||
duration: 3000,
|
||||
actions: [
|
||||
{
|
||||
label: '预览截图',
|
||||
@@ -430,13 +420,7 @@ export function useScreenCapture() {
|
||||
showSuccessToast(imageData)
|
||||
} else {
|
||||
// 复制失败时,直接打开预览弹窗
|
||||
toast.add({
|
||||
title: '截图完成',
|
||||
description: '复制到剪贴板失败,请手动保存',
|
||||
icon: 'i-heroicons-exclamation-triangle',
|
||||
color: 'warning',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.warn('截图完成', { description: '复制到剪贴板失败,请手动保存' })
|
||||
layoutStore.openScreenCaptureModal(imageData)
|
||||
}
|
||||
|
||||
@@ -451,13 +435,7 @@ export function useScreenCapture() {
|
||||
errorMessage = '页面包含无法处理的特殊字符,请尝试截屏其他区域'
|
||||
}
|
||||
|
||||
toast.add({
|
||||
title: '截屏失败',
|
||||
description: errorMessage,
|
||||
icon: 'i-heroicons-x-circle',
|
||||
color: 'error',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail('截屏失败', { description: errorMessage })
|
||||
return false
|
||||
} finally {
|
||||
// 移除水印
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { useToast as useNuxtToast } from '@nuxt/ui/composables'
|
||||
|
||||
interface AppToastOptions {
|
||||
description?: string
|
||||
duration?: number
|
||||
}
|
||||
|
||||
interface AppToastPayload extends AppToastOptions {
|
||||
title: string
|
||||
color?: 'primary' | 'success' | 'warning' | 'error' | 'neutral'
|
||||
}
|
||||
|
||||
const DEFAULT_TOAST_DURATION = 2000
|
||||
|
||||
export function useToast() {
|
||||
const toast = useNuxtToast()
|
||||
|
||||
function add(payload: AppToastPayload) {
|
||||
toast.add({
|
||||
...payload,
|
||||
duration: payload.duration ?? DEFAULT_TOAST_DURATION,
|
||||
})
|
||||
}
|
||||
|
||||
function success(title: string, options: AppToastOptions = {}) {
|
||||
add({
|
||||
title,
|
||||
color: 'success',
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
function fail(title: string, options: AppToastOptions = {}) {
|
||||
add({
|
||||
title,
|
||||
color: 'error',
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
function info(title: string, options: AppToastOptions = {}) {
|
||||
add({
|
||||
title,
|
||||
color: 'primary',
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
function warn(title: string, options: AppToastOptions = {}) {
|
||||
add({
|
||||
title,
|
||||
color: 'warning',
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
add,
|
||||
success,
|
||||
fail,
|
||||
info,
|
||||
warn,
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
|
||||
interface LegacyPromptStoreData {
|
||||
customPromptPresets?: Array<{
|
||||
@@ -79,20 +79,9 @@ async function handleCopyJson() {
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(formattedPromptStoreJson.value)
|
||||
toast.add({
|
||||
title: t('settings.aiPrompt.legacyPrompt.copySuccess'),
|
||||
color: 'primary',
|
||||
icon: 'i-heroicons-clipboard-document-check',
|
||||
duration: 2000,
|
||||
})
|
||||
toast.success(t('settings.aiPrompt.legacyPrompt.copySuccess'))
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: t('settings.aiPrompt.legacyPrompt.copyFailed'),
|
||||
description: String(error),
|
||||
color: 'error',
|
||||
icon: 'i-heroicons-x-circle',
|
||||
duration: 3000,
|
||||
})
|
||||
toast.fail(t('settings.aiPrompt.legacyPrompt.copyFailed'), { description: String(error) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useToast } from '@nuxt/ui/runtime/composables/useToast.js'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import type { AnalysisSession } from '@/types/base'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -296,18 +296,10 @@ async function executeMerge() {
|
||||
showMergeModal.value = false
|
||||
|
||||
// 提示成功
|
||||
toast.add({
|
||||
title: t('tools.batchManage.mergeSuccess', { count: selectedSessionIds.length }),
|
||||
icon: 'i-heroicons-check-circle',
|
||||
color: 'success',
|
||||
})
|
||||
toast.success(t('tools.batchManage.mergeSuccess', { count: selectedSessionIds.length }))
|
||||
} catch (error) {
|
||||
console.error('[BatchDelete] 合并失败:', error)
|
||||
toast.add({
|
||||
title: t('tools.batchManage.mergeError', { error: String(error) }),
|
||||
icon: 'i-heroicons-exclamation-circle',
|
||||
color: 'error',
|
||||
})
|
||||
toast.fail(t('tools.batchManage.mergeError', { error: String(error) }))
|
||||
|
||||
// 清理临时文件
|
||||
if (tempFiles.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user