修复: UX扩展审查P0批(后端git/路径确定性bug + 前端UI + 编译阻断)
后端(src-tauri): - project.rs: 4处空if目录校验补return Err(import/relocate/scan_directory/scan_project_with_ai),目录不存在不再静默放行 - ai/tools/git.rs: exec_git改返(String,bool)治git_commit·git_branch create/switch假成功 + git_merge补失败分支 + 加CREATE_NO_WINDOW - module.rs: run_git_cmd加CREATE_NO_WINDOW,治Windows cmd黑窗闪烁(原问题9) 前端: - DependencyGraph.vue: 环检测高亮注入renderGraph,原被fromJSON重建抹除致功能失效 - FileExplorer.vue: 工程下拉closeDropdown加closest判定,原打不开 附(预存编译阻断顺带修): - df-nodes ai_node_helpers.rs: extract_first_json_object临时值借用悬垂E0716 - MessageList.vue: 删isLastUser死代码(vue-tsc TS6133) 审查产出: docs/05-代码审查/UIUX扩展审查-2026-08-02.md(80条发现,8高grep核验全属实)+ docs/todo.md批次段
This commit is contained in:
@@ -95,16 +95,6 @@ function shouldRenderMsg(msg: AiMessage): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/** UX-09:msg 是否为 messages 中最后一条 user 消息(可编辑判定)。 */
|
||||
function isLastUser(msg: AiMessage): boolean {
|
||||
if (msg.role !== 'user') return false
|
||||
const msgs = store.state.messages
|
||||
for (let i = msgs.length - 1; i >= 0; i--) {
|
||||
if (msgs[i].role === 'user') return msgs[i].id === msg.id
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** token 数格式化:<1000 原值,≥1000 用 k(如 1234→1.2k) */
|
||||
function formatTokens(n: number): string {
|
||||
return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n)
|
||||
|
||||
@@ -63,6 +63,7 @@ import { useRouter } from 'vue-router'
|
||||
import { Graph, Selection, Snapline, History, Scroller, MiniMap } from '@antv/x6'
|
||||
import dagre from 'dagre'
|
||||
import '@antv/x6-vue-shape'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { moduleApi, type ProjectModuleRecord, type ModuleDependencyRecord } from '@/api/module'
|
||||
import ModuleNode from './ModuleNode.vue'
|
||||
|
||||
@@ -141,6 +142,7 @@ function renderGraph() {
|
||||
// 映射回 X6 节点格式
|
||||
const nodes = modules.value.map(m => {
|
||||
const pos = g.node(m.id)
|
||||
const isCycle = cycleNodes.value.has(m.id)
|
||||
return {
|
||||
id: m.id,
|
||||
shape: 'vue-shape',
|
||||
@@ -155,6 +157,11 @@ function renderGraph() {
|
||||
stack: m.stack,
|
||||
gitUrl: m.git_url,
|
||||
},
|
||||
// 环节点高亮(红框);renderGraph 是画布唯一渲染入口,高亮必须在这里注入,
|
||||
// 否则会被 graph.fromJSON 整体替换抹除。
|
||||
attrs: isCycle ? {
|
||||
body: { stroke: '#e05050', strokeWidth: 3 },
|
||||
} : undefined,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -218,20 +225,17 @@ const cycleNodes = ref<Set<string>>(new Set())
|
||||
async function checkCycles() {
|
||||
try {
|
||||
const cycles = await moduleApi.detectModuleCycles(props.projectId)
|
||||
// 收集环节点 id,交给 renderGraph 统一渲染高亮(避免 cell.attr 被 fromJSON 抹除)。
|
||||
cycleNodes.value = new Set(cycles)
|
||||
if (cycles.length > 0) {
|
||||
// 高亮环节点(加红色边框)
|
||||
for (const id of cycles) {
|
||||
const cell = graph?.getCellById(id)
|
||||
if (cell) {
|
||||
cell.attr('body/stroke', '#e05050')
|
||||
cell.attr('body/strokeWidth', 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
renderGraph()
|
||||
if (cycles.length > 0) {
|
||||
Message.warning(`检测到 ${cycles.length} 个环节点(已红框高亮)`)
|
||||
} else {
|
||||
Message.success('未检测到环形依赖')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[DependencyGraph] 环检测失败:', e)
|
||||
Message.error('环检测失败')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -360,8 +360,11 @@ function onChangeFileSelect(path: string) {
|
||||
|
||||
watch(() => props.projectId, loadModules, { immediate: true })
|
||||
|
||||
// 点击外部关闭工程下拉
|
||||
function closeDropdown() { moduleDropdownOpen.value = false }
|
||||
// 点击外部关闭工程下拉(点在 .module-dropdown 内不关,否则按钮 toggle 会被冒泡回调立即关闭)
|
||||
function closeDropdown(e: Event) {
|
||||
if ((e.target as HTMLElement)?.closest('.module-dropdown')) return
|
||||
moduleDropdownOpen.value = false
|
||||
}
|
||||
onMounted(() => document.addEventListener('click', closeDropdown))
|
||||
onUnmounted(() => document.removeEventListener('click', closeDropdown))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user