重构: confirmDialog抽composable+tool_result反向查找+search列限定

- FR-D5 抽 useConfirm 收敛 4 视图(Projects/ProjectDetail/Ideas/Settings)确认弹层重复
- FR-D4 replace_tool_result_content 正向 O(n) 改反向 rposition(审批替换命中最近,调用低频)
- FR-D2 search_vector SELECT * 改显式 14 列(消除隐式依赖,字段级精简待单独立项)
This commit is contained in:
2026-06-14 22:50:59 +08:00
parent 36d68ddb26
commit 4a95f6a1e2
7 changed files with 84 additions and 62 deletions

View File

@@ -0,0 +1,50 @@
//! 统一确认弹层状态机 — 抽自 Projects/ProjectDetail/Ideas/Settings 四处重复
//!
//! 背景:原生 window.confirm 在 Tauri webview 带 localhost:port 来源信息无法去除,
//! 改为自建弹层。四视图各自重复一份 {visible,msg,resolve} + Promise 机制,此处收敛。
//!
//! 分工:本 composable 只管「状态 + Promise」,不渲染 UI ——
//! - Projects/ProjectDetail/Ideas 复用 ../components/ConfirmDialog.vue
//! - Settings 用内联模板(沿用其既有 toast/confirm 同框布局)
//! 各视图绑定 confirmState 的 visible/msg 并把按钮点击回 answerConfirm 即可。
//!
//! i18n:composable 在 setup 内调用,文案由调用方用各自 useI18n().t 翻译后传入 msg,
//! 这里无需 i18n 依赖。dangerLabel 由 ConfirmDialog 组件侧兜底为 common.delete。
import { ref } from 'vue'
export interface ConfirmState {
visible: boolean
msg: string
resolve: null | ((v: boolean) => void)
}
/** 弹出确认对话框,返回 Promise;resolve(true) 表示用户确认,resolve(false) 表示取消 */
export type ConfirmFn = (msg: string) => Promise<boolean>
/** 关闭弹层并回传结果 */
export type AnswerFn = (ok: boolean) => void
export function useConfirm() {
const confirmState = ref<ConfirmState>({
visible: false,
msg: '',
resolve: null,
})
function confirmDialog(msg: string): Promise<boolean> {
return new Promise(resolve => {
confirmState.value.msg = msg
confirmState.value.visible = true
confirmState.value.resolve = resolve
})
}
function answerConfirm(ok: boolean) {
confirmState.value.visible = false
confirmState.value.resolve?.(ok)
confirmState.value.resolve = null
}
return { confirmState, confirmDialog, answerConfirm }
}

View File

@@ -207,26 +207,15 @@ import { Message } from '@arco-design/web-vue'
import { useProjectStore } from '../stores/project'
import { formatDate } from '../utils/time'
import ConfirmDialog from '../components/ConfirmDialog.vue'
import { useConfirm } from '../composables/useConfirm'
import type { IdeaRecord } from '../api/types'
const { t } = useI18n()
const router = useRouter()
const store = useProjectStore()
// ── 确认弹层(替代原生 window.confirm后者在 Tauri webview 带 localhost 来源信息无法去除) ──
const confirmState = ref({ visible: false, msg: '', resolve: null as null | ((v: boolean) => void) })
function confirmDialog(msg: string): Promise<boolean> {
return new Promise(resolve => {
confirmState.value.msg = msg
confirmState.value.visible = true
confirmState.value.resolve = resolve
})
}
function answerConfirm(ok: boolean) {
confirmState.value.visible = false
confirmState.value.resolve?.(ok)
confirmState.value.resolve = null
}
// 确认弹层状态机抽至 composables/useConfirm(原 4 视图重复:Projects/ProjectDetail/Ideas/Settings)
const { confirmState, confirmDialog, answerConfirm } = useConfirm()
type FilterKey = 'all' | 'hot' | 'pending' | 'promoted'

View File

@@ -213,6 +213,7 @@ import { formatDate } from '../utils/time'
import { parseStack } from '../utils/project'
import { projectStatusLabel, projectStageInfo, taskStatusLabel, taskStatusClass } from '../constants/project'
import ConfirmDialog from '../components/ConfirmDialog.vue'
import { useConfirm } from '../composables/useConfirm'
const route = useRoute()
const router = useRouter()
@@ -222,20 +223,8 @@ const logListRef = ref<HTMLElement | null>(null)
const showApprovalDialog = ref(false)
let unlisten: (() => void) | null = null
// ── 确认弹层(替代原生 window.confirm后者在 Tauri webview 带 localhost 来源信息无法去除) ──
const confirmState = ref({ visible: false, msg: '', resolve: null as null | ((v: boolean) => void) })
function confirmDialog(msg: string): Promise<boolean> {
return new Promise(resolve => {
confirmState.value.msg = msg
confirmState.value.visible = true
confirmState.value.resolve = resolve
})
}
function answerConfirm(ok: boolean) {
confirmState.value.visible = false
confirmState.value.resolve?.(ok)
confirmState.value.resolve = null
}
// 确认弹层状态机抽至 composables/useConfirm(原 4 视图重复:Projects/ProjectDetail/Ideas/Settings)
const { confirmState, confirmDialog, answerConfirm } = useConfirm()
// ── 阶段定义(labelKey 对应 i18n projectDetail.stage*) ──
const stages = [

View File

@@ -124,6 +124,7 @@ import { formatDate } from '../utils/time'
import { parseStack } from '../utils/project'
import { projectStatusLabel as statusLabel, projectBadgeClass as stageClass } from '../constants/project'
import ConfirmDialog from '../components/ConfirmDialog.vue'
import { useConfirm } from '../composables/useConfirm'
import type { ProjectRecord } from '../api/types'
const router = useRouter()
@@ -133,20 +134,8 @@ const { t } = useI18n()
// 状态映射统一走 ../constants/project(与 ProjectDetail/Tasks/Dashboard 一致)
// formatDate 由 ../utils/time 提供(统一毫秒字符串解析,根治 Invalid Date
// ── 确认弹层(替代原生 window.confirm后者在 Tauri webview 带 localhost 来源信息无法去除) ──
const confirmState = ref({ visible: false, msg: '', resolve: null as null | ((v: boolean) => void) })
function confirmDialog(msg: string): Promise<boolean> {
return new Promise(resolve => {
confirmState.value.msg = msg
confirmState.value.visible = true
confirmState.value.resolve = resolve
})
}
function answerConfirm(ok: boolean) {
confirmState.value.visible = false
confirmState.value.resolve?.(ok)
confirmState.value.resolve = null
}
// 确认弹层状态机抽至 composables/useConfirm(原 4 视图重复:Projects/ProjectDetail/Ideas/Settings)
const { confirmState, confirmDialog, answerConfirm } = useConfirm()
// ── 新建项目 ──
const showCreateModal = ref(false)

View File

@@ -373,6 +373,7 @@ import { reactive, ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { aiApi, knowledgeApi } from '../api'
import { useAppSettingsStore } from '../stores/appSettings'
import { useConfirm } from '../composables/useConfirm'
import type { AiProviderConfig } from '../api/types'
import i18n from '../i18n'
@@ -399,24 +400,9 @@ function showToast(msg: string, type: 'error' | 'warning' | 'info' = 'info') {
_toastTimer = setTimeout(() => { toast.visible = false }, 3000)
}
// 自建确认弹层(替代 window.confirm —— 后者带 webview 来源域名/端口,无法去除)
const confirmState = reactive({
visible: false,
msg: '',
resolve: null as null | ((v: boolean) => void),
})
function confirmDialog(msg: string): Promise<boolean> {
return new Promise(resolve => {
confirmState.msg = msg
confirmState.visible = true
confirmState.resolve = resolve
})
}
function answerConfirm(ok: boolean) {
confirmState.visible = false
confirmState.resolve?.(ok)
confirmState.resolve = null
}
// 确认弹层状态机抽至 composables/useConfirm(原 4 视图重复:Projects/ProjectDetail/Ideas/Settings)
// 模板 confirmState.visible/msg 在 <script setup> 中自动解包 ref,沿用既有内联确认弹层
const { confirmState, confirmDialog, answerConfirm } = useConfirm()
const providerForm = reactive({
visible: false,