优化: AI Chat 渲染与无障碍 + 文件查看 + 同步 IO 收口
- 渲染: 结果/过程分离(气泡只放最终结果,过程轮叙述+工具卡收进轨迹卡默认收起可展开——治『流式后正文消失』且不再 N 气泡打扰) - 渲染 P0: v-memo 定向 dep(只有真正渲染流式块的 item 失效,其余取占位) + renderItems 桶 memo(签名覆盖全消费输入,item 引用稳定) + 指纹 watch 降为 O(1) toolEpoch - TopBar 三处 O(n) messages computed 合并单次遍历;md 缓存改有界 LRU(除满即全清抖动);useTurnTrace 补 never 穷尽 + default;MessageItem 模板去重 - 无障碍(四批累计): 可点容器键盘化(含 role/tabindex/keydown/aria-expanded) + icon-only aria-label 约 60 处 + 装饰图标 aria-hidden + 52 个滚动容器 overscroll-behavior:contain + 设置开关聚焦可见环 + outline 零补偿站点补 :focus-visible - UX 走查项: 灵感 IDEA-10/11、知识 KNOW-6/7/9、项目详情 O8、审计 SA-4、设置 SA-6/26/27/28(脏表单/冗余 save/clamp/删除二次确认) - 文件查看专项: 切工程状态残留 F5/F6、FileTree 去重与展开反馈 F7/F15/F17、切文件头部残留 F18、R 状态着色 F19;FilePreview diff 文件头(---/+++)误当增删渲染修复 + 大纲行高亮死样式修复 + 图片失败文案 i18n 化 - 同步 IO 收口(异步上下文内阻塞): unattended 看板读写改 tokio::fs、fetch_url 探活改 spawn_blocking、http/generate_image 清理改 tokio::fs - 子代理 P3 批量: 任务书钉扎上限/截断文案区分父子语境/环境画像日期/temperature 可覆盖/model 回退上报/lang 透传 - crate 清理: df-execute·df-types 注释与格式、df-ideas 过时注释、df-nodes subflow 夸大描述、df-project 死变量
This commit is contained in:
+23
-6
@@ -17,7 +17,7 @@
|
||||
<!-- 错误条:消费 store.error(对齐 Knowledge/Projects error-banner,不整表替换列表) -->
|
||||
<div v-if="store.error" class="error-banner" style="margin-bottom: var(--df-gap-page)">
|
||||
<span class="error-text">{{ store.error }}</span>
|
||||
<button class="error-dismiss" @click="store.clearError()">✕</button>
|
||||
<button class="error-dismiss" @click="store.clearError()" :aria-label="$t('common.close')">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- 筛选栏(紧凑下拉) -->
|
||||
@@ -91,7 +91,15 @@
|
||||
class="task-group"
|
||||
:class="{ collapsed: collapsedGroups.has(group.projectName) }"
|
||||
>
|
||||
<div class="group-header" @click="toggleGroup(group.projectName)">
|
||||
<div
|
||||
class="group-header"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
:aria-expanded="!collapsedGroups.has(group.projectName)"
|
||||
@click="toggleGroup(group.projectName)"
|
||||
@keydown.enter.prevent="toggleGroup(group.projectName)"
|
||||
@keydown.space.prevent="toggleGroup(group.projectName)"
|
||||
>
|
||||
<span class="group-chevron">{{ collapsedGroups.has(group.projectName) ? '▸' : '▾' }}</span>
|
||||
<span class="group-icon">{{ group.icon }}</span>
|
||||
<h2 class="group-name">{{ group.projectName }}</h2>
|
||||
@@ -140,7 +148,7 @@
|
||||
</div>
|
||||
<div class="task-actions">
|
||||
<span class="status-tag" :class="taskStatusClass(row.task.status)">{{ $t(statusLabel(row.task.status)) }}</span>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === row.task.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
@@ -197,7 +205,7 @@
|
||||
</div>
|
||||
<div class="task-actions">
|
||||
<span class="status-tag" :class="taskStatusClass(child.status)">{{ $t(statusLabel(child.status)) }}</span>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(child.id)">⚙️</button>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(child.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === child.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
@@ -245,7 +253,7 @@
|
||||
</div>
|
||||
<div class="task-actions">
|
||||
<span class="status-tag" :class="taskStatusClass(row.task.status)">{{ $t(statusLabel(row.task.status)) }}</span>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === row.task.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
@@ -298,7 +306,14 @@
|
||||
:title="parentIdSet.has(task.id) ? $t('tasks.kanban.parentNoDrag') : undefined"
|
||||
>
|
||||
<div class="task-card-top">
|
||||
<span class="task-card-title" @click.stop="openDrawer(task.id)">{{ task.title }}</span>
|
||||
<span
|
||||
class="task-card-title"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click.stop="openDrawer(task.id)"
|
||||
@keydown.enter.prevent="openDrawer(task.id)"
|
||||
@keydown.space.prevent="openDrawer(task.id)"
|
||||
>{{ task.title }}</span>
|
||||
</div>
|
||||
<div class="task-card-meta">
|
||||
<span v-if="task.parent_id" class="parent-tag" :title="parentTitle(task.parent_id)">⤷ {{ parentTitle(task.parent_id) }}</span>
|
||||
@@ -1241,6 +1256,8 @@ onUnmounted(() => {
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.filter-select:hover { border-color: var(--df-accent); }
|
||||
/* 聚焦可见环:仅 hover 有变化、聚焦态无边框变化,且 scoped 选择器特异性高于全局 :focus-visible 兜底,须就地补环 */
|
||||
.filter-select:focus-visible { outline: 2px solid var(--df-accent); outline-offset: 1px; }
|
||||
.filter-chip-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user