重构: 前端DRY收口+后端测试类型对齐
- 新增 useToast composable: 消除 AiChat/Settings/Projects 4处 toast 重复 统一默认3000ms(Projects原4000ms为操作类提示保留参数覆盖) - 新增 utils/json.ts parseJsonArray: 消除 parseStack/parseTags/ModuleNode 3处JSON字符串数组解析重复 - 新增 utils/html.ts escapeHtml: 消除 useMarkdown/FilePreview 2处重复 - ProjectDetail score-bar 内联三元改用 scoreTier(消除最后一处阈值硬编码) - ConversationSidebar 删除 formatTime 透传包装(直接用 formatRelative) - 清理死代码: parseTs/stringifyError/ErrorSink/_Unused 改私有或删除 wrapNakedDiff 改私有(无外部 import) - ModuleNode shortPath 改名 truncatedPath(与 useToolCard.shortPath 语义不同)
This commit is contained in:
+4
-17
@@ -164,7 +164,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { useProjectStore } from '@/stores/project'
|
||||
@@ -174,6 +174,7 @@ import ConfirmDialog from '@/components/ConfirmDialog.vue'
|
||||
import ProjectCard from '@/components/project/ProjectCard.vue'
|
||||
import Paginator from '@/components/Paginator.vue'
|
||||
import { useConfirm } from '@/composables/useConfirm'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import type { ProjectRecord } from '@/api/types'
|
||||
import type { ScannedProjectItem } from '@/api/project'
|
||||
|
||||
@@ -303,14 +304,7 @@ onMounted(() => {
|
||||
store.loadProjects()
|
||||
})
|
||||
|
||||
// 卸载清 toast timer:防组件已离开视图后 4s 内 timer 触发向已销毁组件写状态。
|
||||
// 对齐 Settings.vue 的 _toastTimer 清理模式(Knowledge.vue searchTimer 同模式)。
|
||||
onUnmounted(() => {
|
||||
if (_toastTimer) {
|
||||
clearTimeout(_toastTimer)
|
||||
_toastTimer = null
|
||||
}
|
||||
})
|
||||
// toast timer 清理由 useToast composable 的 onUnmounted 自动管理
|
||||
|
||||
// ── 导入历史项目(F-260614-06 scan 第二步) ──
|
||||
const showImportModal = ref(false)
|
||||
@@ -320,14 +314,7 @@ const importScanning = ref(false)
|
||||
const importError = ref('')
|
||||
const importRunning = ref(false)
|
||||
const selectedImportPaths = ref<Set<string>>(new Set())
|
||||
const toast = ref({ visible: false, msg: '', type: 'info' as 'info' | 'error' })
|
||||
let _toastTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
function showToast(msg: string, type: 'info' | 'error' = 'info') {
|
||||
toast.value = { visible: true, msg, type }
|
||||
if (_toastTimer) clearTimeout(_toastTimer)
|
||||
_toastTimer = setTimeout(() => { toast.value.visible = false }, 4000)
|
||||
}
|
||||
const { toast, showToast } = useToast(4000) // Projects 导入操作 toast 用 4000ms(操作类提示)
|
||||
|
||||
const allImportSelected = computed(() =>
|
||||
scannedItems.value.length > 0
|
||||
|
||||
Reference in New Issue
Block a user