优化: 界面交互完善与设置体验

- 审批卡尊重滚动意图,等长切换回底,排队超时按钮修活
- 带图编辑提示不静默丢,删除目标回写,切换文案消歧
- 会话键盘可达+搜索态重命名,筛选计数口径对齐
- 子任务提示正名,看板加载态
- 主题跟随系统,表单脏态拦截,密钥显隐留空提示
This commit is contained in:
lxy
2026-10-03 16:28:38 +08:00
parent 31f7a9570b
commit 3e3c6f4d0f
22 changed files with 294 additions and 12 deletions
+14 -1
View File
@@ -42,7 +42,7 @@
</template>
<script setup lang="ts">
import { reactive, watch, onMounted, useTemplateRef } from 'vue'
import { reactive, watch, onMounted, onUnmounted, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppSettingsStore } from '@/stores/appSettings'
import SettingRow from './SettingRow.vue'
@@ -77,6 +77,14 @@ function applyTheme(theme: string) {
}
}
// 走查 P2-4:原实现只在挂载/改档时读一次 matchMedia.matches,OS 深浅色切换后应用停在旧色,
// 需重启或重选档位才跟随。挂 change 监听实时重算;非 system 档是用户手动定色,不应被 OS
// 切色打断,故回调内先判档。组件卸载必须移除监听(本 Section 随分类切换反复挂卸,不清理会叠监听器)。
const systemDarkQuery = window.matchMedia('(prefers-color-scheme: dark)')
function onSystemThemeChange() {
if (settings.theme === 'system') applyTheme('system')
}
// 即时生效反馈:SettingRow refs,key 映射对应 row
const rowTheme = useTemplateRef<InstanceType<typeof SettingRow>>('rowTheme')
const rowLanguage = useTemplateRef<InstanceType<typeof SettingRow>>('rowLanguage')
@@ -113,6 +121,11 @@ watch(() => settings.language, (val) => {
onMounted(() => {
applyTheme(settings.theme)
systemDarkQuery.addEventListener('change', onSystemThemeChange)
})
onUnmounted(() => {
systemDarkQuery.removeEventListener('change', onSystemThemeChange)
})
</script>
+13 -1
View File
@@ -92,7 +92,15 @@
</div>
<div class="form-field">
<label class="form-label">{{ $t('settings.labelApiKey') }}</label>
<input v-model="providerForm.apiKey" class="setting-input" type="password" :placeholder="$t('settings.phApiKey')" />
<!-- 走查 P3-9:type 恒 password 无法核对已粘贴密钥,加显隐切换 -->
<input v-model="providerForm.apiKey" class="setting-input" :type="showApiKey ? 'text' : 'password'" :placeholder="$t('settings.phApiKey')" />
<button type="button" class="btn-link" :title="$t(showApiKey ? 'settings.apiKeyHide' : 'settings.apiKeyShow')"
@click="showApiKey = !showApiKey">
{{ $t(showApiKey ? 'settings.apiKeyHide' : 'settings.apiKeyShow') }}
</button>
<!-- 走查 P3-9:编辑态留空=沿用已存密钥(后端 FR-S1),此前表单零说明,用户误以为必须重输。
仅编辑态显(新建态密钥必填,不存在"留空"语义)。 -->
<div v-if="providerForm.editId" class="form-field-hint">{{ $t('settings.apiKeyKeepHint') }}</div>
</div>
<div class="form-field">
<label class="form-label">{{ $t('settings.labelDefaultModel') }}</label>
@@ -217,6 +225,9 @@ const props = defineProps<{
const aiProviders = ref<AiProviderConfig[]>([])
// 密钥显隐切换(走查 P3-9):默认隐藏;重开表单时复位,防上一家 provider 的显钥状态延续
const showApiKey = ref(false)
function errMsg(e: unknown): string { return e instanceof Error ? e.message : String(e) }
const providerForm = reactive({
@@ -422,6 +433,7 @@ function openProviderForm(p?: AiProviderConfig) {
}
providerForm.fetching = false
providerForm.saveError = null // 重开表单清旧错误横幅
showApiKey.value = false // 密钥默认隐藏,不延续上次表单的显钥状态(防窥)
providerForm.visible = true
// L19/M32: 记初始快照(在 visible=true、字段回填完成后),isFormDirty 据此比对。
providerForm.savedSnapshot = formBusinessSnapshot()