优化: 无障碍批次(可点容器键盘化 + icon-only aria-label)
- P2-2 命名 4 处可点容器键盘可达: ToolCard 卡头 / MessageList 轨迹卡头 / AuditLog audit-row(tr) / conv-list-item —— tabindex+keydown 复用原 handler, div 类加 role=button+aria-expanded; tr 因 role=button 会抹掉行语义故不加 role - P3-2 3 处 icon-only 按钮补 aria-label(EnrichmentPanel 关闭 / ProjectDetail 编辑·删除),复用同 :title 的 i18n key,零新增键 - 硬约束执行: 4 个并行子代理按文件分区,零跨文件改动;主代理独立核查 diff 后修正一处语义缺陷(tr role) - 看板同步: P2-2 销账 / P3-2 部分完成(~12 处待续) / 残留诊断代码 authz_debug 已清销账 / G6 标题泄漏(title.rs sanitize_title_source 双路径)销账 - 验收: bunx vue-tsc --noEmit EXIT 0 + node scripts/check-i18n.cjs 0 失败
This commit is contained in:
+4
-4
@@ -24,8 +24,8 @@
|
|||||||
> 背景:src 43 个 .vue 文件 UI 规范缺口全量合规走查(Vercel Web Interface Guidelines 适用子集)+ 审批/aichat/项目知识审计三域子代理分组审。质量中上无阻断,缺口集中 4 类系统性模式,其中 2 类可全局样式一刀切收敛。
|
> 背景:src 43 个 .vue 文件 UI 规范缺口全量合规走查(Vercel Web Interface Guidelines 适用子集)+ 审批/aichat/项目知识审计三域子代理分组审。质量中上无阻断,缺口集中 4 类系统性模式,其中 2 类可全局样式一刀切收敛。
|
||||||
> 详情:[05-代码审查/UX走查-Web规范合规-2026-10-05.md](./05-代码审查/UX走查-Web规范合规-2026-10-05.md)
|
> 详情:[05-代码审查/UX走查-Web规范合规-2026-10-05.md](./05-代码审查/UX走查-Web规范合规-2026-10-05.md)
|
||||||
|
|
||||||
- [ ] P2-2 高频可点 div 键盘化:ToolCard:11 卡头/MessageList:1423 轨迹头/AuditLog:67,119 审计行(@click div 全仓 56 处,去 mask 合规项约 20 真缺口,高频改 button 其余 tabindex+keydown)
|
- [x] P2-2 高频可点 div 键盘化:ToolCard:11 卡头/MessageList:1423 轨迹头/AuditLog:67,119 审计行(@click div 全仓 56 处,去 mask 合规项约 20 真缺口,高频改 button 其余 tabindex+keydown) ✅ **2026-10-10 完成(named 高频点)**:四面包裹处均补 `role="button" tabindex="0"` + `@keydown.enter/.space.prevent` 复用原 handler(带展开态的补 `:aria-expanded`;AuditLog 的 `<tr>` 仅补 tabindex+keydown——加 role=button 会抹掉表格行语义,故不加)。验收:`bunx vue-tsc --noEmit` EXIT 0。**剩余**:全仓另 ~16 处 @click div 未清(见 P3-2)。
|
||||||
- [ ] P3-2 icon-only 按钮缺 aria-label ~15 处(title 非等价读屏补偿;EnrichmentPanel 关闭钮/ProjectDetail:185,189 编辑删除钮等)+剩余 div 键盘化
|
- [~] P3-2 icon-only 按钮缺 aria-label ~15 处(title 非等价读屏补偿;EnrichmentPanel 关闭钮/ProjectDetail:185,189 编辑删除钮等)+剩余 div 键盘化 ✅ **2026-10-10 完成 3/15**(EnrichmentPanel 关闭钮 + ProjectDetail 模块编辑/删除钮,均复用已有 `:title` 同表达式为 `:aria-label`,未新增 i18n 键);**剩余 ~12 处** 未清,按「存量 vs 仅本批」拍板点待用户定范围。
|
||||||
- 拍板点:修复范围「存量 vs 仅本批」——transition:all/outline:none 大半为存量;本批新代码 a11y 意识已好(svg aria-hidden 批补/MessageList role=log+aria-live/hover-only focus-within 补偿),仅清本批则工作量降 60%+
|
- 拍板点:修复范围「存量 vs 仅本批」——transition:all/outline:none 大半为存量;本批新代码 a11y 意识已好(svg aria-hidden 批补/MessageList role=log+aria-live/hover-only focus-within 补偿),仅清本批则工作量降 60%+
|
||||||
|
|
||||||
### 💡 2026-09-29 aichat 可用性与交互成本研究(三动线走查+异常循环截图实证,39 项新发现)
|
### 💡 2026-09-29 aichat 可用性与交互成本研究(三动线走查+异常循环截图实证,39 项新发现)
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
**销账核对(已登记 8 复核)**:SMELL-P1-6(line221·#5 覆盖 executed/completed 双轨)/ MED-1(tool_registry:546 bind_directory)/ REFACTOR-260619-08(tool_registry:881 拆)/ REFACTOR-260619-09(context.rs:1 God 1552行)/ ARC-260619-05(agentic:318 超长)/ UX-260617-28(双监听器 INFO)。**均仍在未完成,审查复核确认,保留**。
|
**销账核对(已登记 8 复核)**:SMELL-P1-6(line221·#5 覆盖 executed/completed 双轨)/ MED-1(tool_registry:546 bind_directory)/ REFACTOR-260619-08(tool_registry:881 拆)/ REFACTOR-260619-09(context.rs:1 God 1552行)/ ARC-260619-05(agentic:318 超长)/ UX-260617-28(双监听器 INFO)。**均仍在未完成,审查复核确认,保留**。
|
||||||
|
|
||||||
**残留诊断代码(待清)**:chat.rs `authz_debug`/`authz-debug.log`(L2 调试遗留,P2 报 chat.rs:548 硬编码绝对路径),L2 完成后可清。
|
**残留诊断代码(待清)**:chat.rs `authz_debug`/`authz-debug.log`(L2 调试遗留,P2 报 chat.rs:548 硬编码绝对路径),L2 完成后可清。✅ **2026-10-10 核验销账**:`grep -rn "authz_debug|authz-debug.log" src-tauri/src/` 零命中,残留已清。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -670,7 +670,7 @@
|
|||||||
- [ ] **G4 销账带证据**:勾选 [x] 须附验收命令输出行,无证据视同未完成
|
- [ ] **G4 销账带证据**:勾选 [x] 须附验收命令输出行,无证据视同未完成
|
||||||
|
|
||||||
### 桌面能力同步(随本批)
|
### 桌面能力同步(随本批)
|
||||||
- [ ] G6 缺陷9 标题泄漏桌面同症随批修
|
- [x] G6 缺陷9 标题泄漏桌面同症随批修 ✅ **2026-10-10 核验销账**:`title.rs:241 sanitize_title_source`(剥 HTML/Markdown 标签,含 `<details>/<summary>`/代码围栏)已接入 `extract_title` 的 LLM 路径(:280)与兜底路径(:298),桌面与飞书同源,缺陷9 桌面同症已随 70d6e98 一并修。
|
||||||
|
|
||||||
|
|
||||||
## 无人值守可靠性专项(2026-10-06 swarm 立项,设计档:docs/02-架构设计/无人值守可靠性专项设计-20261006.md+temp/V49断点续跑设计-20261006.md)
|
## 无人值守可靠性专项(2026-10-06 swarm 立项,设计档:docs/02-架构设计/无人值守可靠性专项设计-20261006.md+temp/V49断点续跑设计-20261006.md)
|
||||||
|
|||||||
@@ -8,7 +8,15 @@
|
|||||||
:data-risk="riskLevel"
|
:data-risk="riskLevel"
|
||||||
>
|
>
|
||||||
<!-- 卡片头部:图标 + 名称 + 状态 -->
|
<!-- 卡片头部:图标 + 名称 + 状态 -->
|
||||||
<div class="ai-tool-header" @click="emit('toggle', tc.id)">
|
<div
|
||||||
|
class="ai-tool-header"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
:aria-expanded="isExpanded || shouldKeepOpen(tc)"
|
||||||
|
@click="emit('toggle', tc.id)"
|
||||||
|
@keydown.enter.prevent="emit('toggle', tc.id)"
|
||||||
|
@keydown.space.prevent="emit('toggle', tc.id)"
|
||||||
|
>
|
||||||
<span class="ai-tool-icon-wrap" :class="'ai-tool-icon-wrap--' + toolCategory(tc.name)">
|
<span class="ai-tool-icon-wrap" :class="'ai-tool-icon-wrap--' + toolCategory(tc.name)">
|
||||||
<span v-html="toolIcon(tc.name)"></span>
|
<span v-html="toolIcon(tc.name)"></span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function toggleExpanded(current: boolean) {
|
|||||||
</svg>
|
</svg>
|
||||||
<span class="ai-enrichment-badge">{{ enrichmentBadgeText }}</span>
|
<span class="ai-enrichment-badge">{{ enrichmentBadgeText }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="ai-enrichment-dismiss" @click="emit('dismiss')" :title="$t('aiChat.enrichmentDismiss')">×</button>
|
<button class="ai-enrichment-dismiss" @click="emit('dismiss')" :title="$t('aiChat.enrichmentDismiss')" :aria-label="$t('aiChat.enrichmentDismiss')">×</button>
|
||||||
<div v-if="enrichmentExpanded" class="ai-enrichment-panel">
|
<div v-if="enrichmentExpanded" class="ai-enrichment-panel">
|
||||||
<div class="ai-enrichment-label">{{ $t('aiChat.enrichmentLabel') }}</div>
|
<div class="ai-enrichment-label">{{ $t('aiChat.enrichmentLabel') }}</div>
|
||||||
<pre class="ai-enrichment-body"><code>{{ enrichmentDetailText }}</code></pre>
|
<pre class="ai-enrichment-body"><code>{{ enrichmentDetailText }}</code></pre>
|
||||||
|
|||||||
@@ -1507,7 +1507,15 @@ defineExpose({
|
|||||||
每轮思考 pill + 工具卡;头部聚合行含调用/耗时/全程 token 汇总) -->
|
每轮思考 pill + 工具卡;头部聚合行含调用/耗时/全程 token 汇总) -->
|
||||||
<div v-if="item.kind === 'trace'" class="ai-msg-slot ai-msg-slot--proc">
|
<div v-if="item.kind === 'trace'" class="ai-msg-slot ai-msg-slot--proc">
|
||||||
<div class="ai-trace-card" :class="{ 'ai-trace-card--open': item.expanded }" :data-trace-key="item.key">
|
<div class="ai-trace-card" :class="{ 'ai-trace-card--open': item.expanded }" :data-trace-key="item.key">
|
||||||
<div class="ai-trace-head" @click="toggleTrace(item.key)">
|
<div
|
||||||
|
class="ai-trace-head"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
:aria-expanded="item.expanded"
|
||||||
|
@click="toggleTrace(item.key)"
|
||||||
|
@keydown.enter.prevent="toggleTrace(item.key)"
|
||||||
|
@keydown.space.prevent="toggleTrace(item.key)"
|
||||||
|
>
|
||||||
<span class="ai-trace-chevron" :class="{ 'is-open': item.expanded }">▸</span>
|
<span class="ai-trace-chevron" :class="{ 'is-open': item.expanded }">▸</span>
|
||||||
<span class="ai-trace-title">{{ $t('ai.trace.roundN', { n: item.round }) }}</span>
|
<span class="ai-trace-title">{{ $t('ai.trace.roundN', { n: item.round }) }}</span>
|
||||||
<span class="ai-trace-agg" :title="traceHoverTitle(item.startTs, item.endTs)">{{ traceAggText(item.stats, item.startTs, item.endTs) }}</span>
|
<span class="ai-trace-agg" :title="traceHoverTitle(item.startTs, item.endTs)">{{ traceAggText(item.stats, item.startTs, item.endTs) }}</span>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<template v-for="r in filteredRecords" :key="r.id">
|
<template v-for="r in filteredRecords" :key="r.id">
|
||||||
<tr class="audit-row" :class="{ expanded: expandedId === r.id }" @click="toggleExpand(r.id)">
|
<tr class="audit-row" :class="{ expanded: expandedId === r.id }" tabindex="0" @click="toggleExpand(r.id)" @keydown.enter.prevent="toggleExpand(r.id)" @keydown.space.prevent="toggleExpand(r.id)">
|
||||||
<td class="col-time">
|
<td class="col-time">
|
||||||
<div class="time-rel">{{ formatRelative(r.requested_at) }}</div>
|
<div class="time-rel">{{ formatRelative(r.requested_at) }}</div>
|
||||||
<div class="time-abs">{{ formatDate(r.requested_at) }}</div>
|
<div class="time-abs">{{ formatDate(r.requested_at) }}</div>
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
<!-- 左侧:对话标题列表 -->
|
<!-- 左侧:对话标题列表 -->
|
||||||
<div class="conv-list-panel">
|
<div class="conv-list-panel">
|
||||||
<div class="conv-list" v-if="conversations.length > 0">
|
<div class="conv-list" v-if="conversations.length > 0">
|
||||||
<div v-for="conv in conversations" :key="conv.id" class="conv-list-item" :class="{ active: expandedConv === conv.id }" @click="toggleConv(conv.id)">
|
<div v-for="conv in conversations" :key="conv.id" class="conv-list-item" :class="{ active: expandedConv === conv.id }" role="button" tabindex="0" :aria-expanded="expandedConv === conv.id" @click="toggleConv(conv.id)" @keydown.enter.prevent="toggleConv(conv.id)" @keydown.space.prevent="toggleConv(conv.id)">
|
||||||
<span class="conv-list-item-title">{{ conv.title || '—' }}</span>
|
<span class="conv-list-item-title">{{ conv.title || '—' }}</span>
|
||||||
<span class="conv-list-item-date">{{ formatDate(conv.updated_at) }}</span>
|
<span class="conv-list-item-date">{{ formatDate(conv.updated_at) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -170,10 +170,10 @@
|
|||||||
<span v-else class="module-status-badge module-status-active">{{ $t('projectDetail.moduleStatusActive') }}</span>
|
<span v-else class="module-status-badge module-status-active">{{ $t('projectDetail.moduleStatusActive') }}</span>
|
||||||
<span class="module-path-overview" :title="m.path">{{ m.path }}</span>
|
<span class="module-path-overview" :title="m.path">{{ m.path }}</span>
|
||||||
<span class="module-row-actions">
|
<span class="module-row-actions">
|
||||||
<button class="ai-btn-icon" :title="$t('fileExplorer.editModule')" @click="openEditModule(m)">
|
<button class="ai-btn-icon" :title="$t('fileExplorer.editModule')" :aria-label="$t('fileExplorer.editModule')" @click="openEditModule(m)">
|
||||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="ai-btn-icon module-row-action-danger" :title="$t('fileExplorer.deleteCurrentModule')" @click="confirmRemoveModule(m)">
|
<button class="ai-btn-icon module-row-action-danger" :title="$t('fileExplorer.deleteCurrentModule')" :aria-label="$t('fileExplorer.deleteCurrentModule')" @click="confirmRemoveModule(m)">
|
||||||
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
<svg aria-hidden="true" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user