优化: 界面交互完善与设置体验
- 审批卡尊重滚动意图,等长切换回底,排队超时按钮修活 - 带图编辑提示不静默丢,删除目标回写,切换文案消歧 - 会话键盘可达+搜索态重命名,筛选计数口径对齐 - 子任务提示正名,看板加载态 - 主题跟随系统,表单脏态拦截,密钥显隐留空提示
This commit is contained in:
+23
-1
@@ -82,6 +82,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, shallowRef, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { onBeforeRouteLeave } from 'vue-router'
|
||||
import { useConfirm } from '@/composables/useConfirm'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue'
|
||||
@@ -122,9 +123,30 @@ const connectionPanelRef = shallowRef<InstanceType<typeof ConnectionPanel> | nul
|
||||
// 用 computed 包 useSetting,双向绑 SettingsNav v-model
|
||||
// ============================================================
|
||||
const appSettings = useAppSettingsStore()
|
||||
|
||||
// 走查 P2-7:ProviderPanel 已暴露 isFormDirty 但壳未接入,点左栏任一分类/离开路由
|
||||
// 都会 v-else-if 卸载面板,未保存改动无确认直接销毁。两条出口(切分类/路由离开)
|
||||
// 统一走本守卫:脏则二次确认,拒绝即原地不动(SettingsNav 是受控组件,不落值高亮自动回弹)。
|
||||
// 复用 ProviderPanel 自身的 confirmDiscardUnsaved 文案,语义与表单「取消」一致。
|
||||
async function confirmLeaveIfProviderDirty(): Promise<boolean> {
|
||||
if (!providerPanelRef.value?.isFormDirty) return true
|
||||
return await confirmDialog(ti18n('settings.confirmDiscardUnsaved'))
|
||||
}
|
||||
|
||||
const activeCategory = computed<SettingsCategory>({
|
||||
get: () => appSettings.get<SettingsCategory>('df-settings-active-category', 'appearance'),
|
||||
set: (v) => { void appSettings.set('df-settings-active-category', v) },
|
||||
set: (v) => {
|
||||
// 点当前分类是无效切换,不弹确认(脏表单下误点自身不应被质询)
|
||||
if (v === activeCategory.value) return
|
||||
void confirmLeaveIfProviderDirty().then((ok) => {
|
||||
if (ok) void appSettings.set('df-settings-active-category', v)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
// 路由离开(回主页等)同样拦截:Settings 是路由组件,返回 false 阻断本次导航
|
||||
onBeforeRouteLeave(async () => {
|
||||
return await confirmLeaveIfProviderDirty()
|
||||
})
|
||||
|
||||
// AI Prompt 缓存总开关(KV df-ai-anthropic-cache,默认关,与后端 prompt.rs cache_enabled 同键;
|
||||
|
||||
+27
-2
@@ -52,7 +52,10 @@
|
||||
<option value="status">{{ $t('tasks.sort.status') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="filter-count">{{ $t('common.pagination.total', { n: store.tasks.length }) }}</span>
|
||||
<!-- UX走查 P2-2: 计数对齐可见行口径——列表模式按状态筛选后的可见行数(batchScopeIds,
|
||||
含折叠父的子任务),看板模式各状态列恒全显仍取全量;原固定 store.tasks.length,
|
||||
勾选状态芯片后计数不变与可见行数矛盾 -->
|
||||
<span class="filter-count">{{ $t('common.pagination.total', { n: viewMode === 'list' ? batchScopeIds.length : store.tasks.length }) }}</span>
|
||||
<!-- 列表/看板切换(持久化) -->
|
||||
<div class="filter-group view-toggle">
|
||||
<button class="seg-btn" :class="{ 'is-active': viewMode === 'list' }" @click="viewMode = 'list'">{{ $t('tasks.kanban.toggleList') }}</button>
|
||||
@@ -271,8 +274,11 @@
|
||||
<div
|
||||
class="kanban-board"
|
||||
ref="kanbanBoardRef"
|
||||
:class="{ 'is-busy': kanban.kanbanBusy, 'is-hidden': viewMode !== 'kanban' }"
|
||||
:class="{ 'is-busy': kanban.kanbanBusy, 'is-loading': viewMode === 'kanban' && loading, 'is-hidden': viewMode !== 'kanban' }"
|
||||
>
|
||||
<!-- 看板加载指示(UX走查 P2-4):看板常驻渲染,切项目/搜索期间旧筛选卡片仍在展示,
|
||||
轻提示 + 卡片降透明度避免误读为最新数据;局部于看板容器,非全局遮罩,文案对齐列表模式 -->
|
||||
<div v-if="viewMode === 'kanban' && loading" class="kanban-loading">{{ $t('common.loading') }}</div>
|
||||
<div v-for="col in kanbanColumns" :key="col.status" class="kanban-col" :data-status="col.status">
|
||||
<div class="kanban-col-header">
|
||||
<span class="kanban-col-name">{{ $t(statusLabel(col.status)) }}</span>
|
||||
@@ -1000,7 +1006,26 @@ onUnmounted(() => {
|
||||
align-items: flex-start;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 8px;
|
||||
position: relative; /* 承载局部加载浮标(UX走查 P2-4) */
|
||||
}
|
||||
/* 加载浮标:局部于看板容器的轻提示,压在列上方居中,不阻断列布局;pointer-events none 不挡拖拽热区 */
|
||||
.kanban-loading {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 5;
|
||||
padding: 3px 14px;
|
||||
border-radius: 999px;
|
||||
background: var(--df-bg);
|
||||
border: 0.5px solid var(--df-border);
|
||||
color: var(--df-text-dim);
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
/* 加载期间旧筛选卡片降透明度+禁交互,避免被误读为当前筛选的最新结果 */
|
||||
.kanban-board.is-loading .task-card { opacity: 0.45; pointer-events: none; }
|
||||
.kanban-board.is-busy .task-card { pointer-events: none; }
|
||||
.kanban-board.is-hidden { display: none; }
|
||||
.kanban-col {
|
||||
|
||||
Reference in New Issue
Block a user