From cc8d5817aaa20bf2bfbfe37d56a20732e1fe1902 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Sat, 11 Jul 2026 19:58:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=9E=81=E7=AE=80=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E5=B1=95=E5=BC=80=E9=AB=98=E5=BA=A6=E9=99=90=E5=88=B6?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E4=B8=8E=E4=B8=AA=E4=BA=BA=E7=A9=BA=E9=97=B4?= =?UTF-8?q?=E6=8C=81=E4=B9=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/personalization_manager.py | 7 +++ static/src/components/chat/MinimalBlocks.vue | 55 ++++++++++++++++++- .../personalization/PersonalizationDrawer.vue | 53 ++++++++++++++++++ static/src/stores/personalization.ts | 27 +++++++++ 4 files changed, 140 insertions(+), 2 deletions(-) diff --git a/modules/personalization_manager.py b/modules/personalization_manager.py index b63125e..d5baca6 100644 --- a/modules/personalization_manager.py +++ b/modules/personalization_manager.py @@ -98,6 +98,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = { "block_display_mode": "stacked", # 堆叠块显示模式:traditional-传统列表 / stacked-堆叠动画 / minimal-极简模式 "show_status_avatar": True, # 是否显示助手状态形象 "stacked_hide_borders": False, # 堆叠块隐藏边线 + "minimal_expand_height_limited": True, # 极简模式展开摘要行时限制最大高度 "show_git_status_bar": True, # 是否显示输入栏上方 Git 状态栏 "versioning_enabled_by_default": True, # 新对话是否默认开启版本控制 "versioning_backup_mode": "shallow", # 文件备份方式:shallow-浅备份(只备份AI编辑的文件)/ full-完全备份(整个工作区) @@ -467,6 +468,12 @@ def sanitize_personalization_payload( else: base["stacked_hide_borders"] = bool(base.get("stacked_hide_borders", False)) + # 极简模式展开高度限制 + if "minimal_expand_height_limited" in data: + base["minimal_expand_height_limited"] = bool(data.get("minimal_expand_height_limited")) + else: + base["minimal_expand_height_limited"] = bool(base.get("minimal_expand_height_limited", True)) + # 助手状态形象显示开关 if "show_status_avatar" in data: base["show_status_avatar"] = bool(data.get("show_status_avatar")) diff --git a/static/src/components/chat/MinimalBlocks.vue b/static/src/components/chat/MinimalBlocks.vue index 945898d..df3b2f7 100644 --- a/static/src/components/chat/MinimalBlocks.vue +++ b/static/src/components/chat/MinimalBlocks.vue @@ -74,7 +74,11 @@
-
+
personalizationStore.form.minimal_expand_height_limited); import { getRandomLoader } from './loaders/index'; import MarkdownRenderer from './MarkdownRenderer.vue'; @@ -206,9 +213,9 @@ const emit = defineEmits<{ (event: 'group-toggle', payload: { groupId: string; expanded: boolean }): void; }>(); -const personalizationStore = usePersonalizationStore(); const expandedGroups = ref(new Set()); const thinkingRefs = new Map(); +const stepsWrapperRefs = new Map(); const summaryLoaders = new Map(); const TOOL_REEL_ITEM_HEIGHT = 26; const TOOL_REEL_INTERVAL_MS = 1450; @@ -804,6 +811,21 @@ const getSummarySteps = (actions: Action[]) => { })); }; +const registerStepsWrapper = (groupId: string, el: Element | null) => { + if (el instanceof HTMLElement) { + stepsWrapperRefs.set(groupId, el); + } else { + stepsWrapperRefs.delete(groupId); + } +}; + +const scrollStepsWrapperToBottom = (groupId: string) => { + const wrapper = stepsWrapperRefs.get(groupId); + if (wrapper) { + wrapper.scrollTop = wrapper.scrollHeight; + } +}; + const toggleExpand = (groupId: string) => { if (expandedGroups.value.has(groupId)) { expandedGroups.value.delete(groupId); @@ -831,6 +853,10 @@ const toggleExpand = (groupId: string) => { nextTick(() => { const group = blockGroups.value.find((g) => g.id === groupId); if (group && group.actions) { + // 运行中展开时,将展开区滚动到底部 + if (isSummaryRunning(group.actions, groupId)) { + scrollStepsWrapperToBottom(groupId); + } group.actions.forEach((action) => { if (action.type === 'thinking') { const blockId = action.id || action.blockId; @@ -954,6 +980,19 @@ watch( () => props.actions, () => { syncToolReels(); + // 对展开的 running 摘要组,自动将展开区滚动到底部 + nextTick(() => { + blockGroups.value.forEach((group) => { + if ( + group.type === 'summary' && + group.actions && + expandedGroups.value.has(group.id) && + isSummaryRunning(group.actions, group.id) + ) { + scrollStepsWrapperToBottom(group.id); + } + }); + }); }, { deep: true, immediate: true } ); @@ -967,6 +1006,7 @@ watch( onBeforeUnmount(() => { Object.keys(toolReelStates).forEach(clearToolReelTimers); + stepsWrapperRefs.clear(); }); @@ -1143,6 +1183,17 @@ onBeforeUnmount(() => { min-height: 0; } +.steps-wrapper.height-limited { + max-height: min(450px, 70vh); + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; +} + +.steps-wrapper.height-limited::-webkit-scrollbar { + display: none; +} + .steps-container.show { grid-template-rows: 1fr; } diff --git a/static/src/components/personalization/PersonalizationDrawer.vue b/static/src/components/personalization/PersonalizationDrawer.vue index c6ec2e5..15ef427 100644 --- a/static/src/components/personalization/PersonalizationDrawer.vue +++ b/static/src/components/personalization/PersonalizationDrawer.vue @@ -305,6 +305,28 @@ > +
智能体交流风格 @@ -802,6 +824,28 @@ > +
简略消息显示 { const currentBlockDisplayMode = computed(() => experiments.value.blockDisplayMode); const stackedHideBorders = computed(() => form.value.stacked_hide_borders); +const minimalExpandHeightLimited = computed(() => form.value.minimal_expand_height_limited); const blockDisplayLabel = computed(() => { return ( @@ -2700,6 +2745,14 @@ const handleStackedHideBordersChange = (event: Event) => { }); }; +const handleMinimalExpandHeightLimitedChange = (event: Event) => { + const target = event.target as HTMLInputElement; + personalization.updateField({ + key: 'minimal_expand_height_limited', + value: target.checked + }); +}; + const compactMessageDisplayOptions = [ { id: 'full', diff --git a/static/src/stores/personalization.ts b/static/src/stores/personalization.ts index 192b276..effe976 100644 --- a/static/src/stores/personalization.ts +++ b/static/src/stores/personalization.ts @@ -31,6 +31,7 @@ interface PersonalForm { show_git_status_bar: boolean; auto_open_terminal_panel: boolean; stacked_hide_borders: boolean; + minimal_expand_height_limited: boolean; enhanced_tool_display_categories: string[]; enabled_skills: string[]; self_identify: string; @@ -104,6 +105,7 @@ const RUN_MODE_OPTIONS: RunMode[] = ['fast', 'thinking', 'deep']; const EXPERIMENT_STORAGE_KEY = 'agents_personalization_experiments'; const THEME_STORAGE_KEY = 'agents_ui_theme'; const STACKED_HIDE_BORDERS_STORAGE_KEY = 'agents_stacked_hide_borders'; +const MINIMAL_EXPAND_HEIGHT_LIMITED_STORAGE_KEY = 'agents_minimal_expand_height_limited'; const loadCachedTheme = (): PersonalForm['theme'] => { if (typeof window === 'undefined' || !window.localStorage) { @@ -153,6 +155,25 @@ const persistStackedHideBorders = (value: boolean) => { } }; +const loadCachedMinimalExpandHeightLimited = (): boolean => { + if (typeof window === 'undefined' || !window.localStorage) { + return true; + } + const saved = window.localStorage.getItem(MINIMAL_EXPAND_HEIGHT_LIMITED_STORAGE_KEY); + return saved === null ? true : saved === 'true'; +}; + +const persistMinimalExpandHeightLimited = (value: boolean) => { + if (typeof window === 'undefined' || !window.localStorage) { + return; + } + try { + window.localStorage.setItem(MINIMAL_EXPAND_HEIGHT_LIMITED_STORAGE_KEY, value ? 'true' : 'false'); + } catch (error) { + console.warn('写入极简展开高度限制设置失败:', error); + } +}; + const defaultForm = (): PersonalForm => ({ enabled: false, communication_style: 'default', @@ -174,6 +195,7 @@ const defaultForm = (): PersonalForm => ({ show_git_status_bar: true, auto_open_terminal_panel: true, stacked_hide_borders: loadCachedStackedHideBorders(), + minimal_expand_height_limited: loadCachedMinimalExpandHeightLimited(), enhanced_tool_display_categories: [], enabled_skills: [], self_identify: '', @@ -372,6 +394,7 @@ export const usePersonalizationStore = defineStore('personalization', { show_git_status_bar: data.show_git_status_bar !== false, auto_open_terminal_panel: data.auto_open_terminal_panel !== false, stacked_hide_borders: !!data.stacked_hide_borders, + minimal_expand_height_limited: data.minimal_expand_height_limited !== false, enhanced_tool_display_categories: Array.isArray(data.enhanced_tool_display_categories) ? data.enhanced_tool_display_categories.filter( (item: unknown) => typeof item === 'string' @@ -469,6 +492,7 @@ export const usePersonalizationStore = defineStore('personalization', { } persistDefaultHideWorkspace(this.form.default_hide_workspace); persistStackedHideBorders(this.form.stacked_hide_borders); + persistMinimalExpandHeightLimited(this.form.minimal_expand_height_limited); if (this.form.default_hide_workspace) { useUiStore().setWorkspaceCollapsed(true); } @@ -673,6 +697,9 @@ export const usePersonalizationStore = defineStore('personalization', { if (payload.key === 'stacked_hide_borders') { persistStackedHideBorders(!!payload.value); } + if (payload.key === 'minimal_expand_height_limited') { + persistMinimalExpandHeightLimited(!!payload.value); + } this.clearFeedback(); this.scheduleAutoSave(); },