Skip to content

Commit b947eb7

Browse files
committed
refactor(ui): 优化消息区域布局和 TodoPanel 显示逻辑
将 TodoPanel 从消息流中独立出来,固定在动态区域底部显示 只在存在活动 TODO(pending/in_progress)时显示 TodoPanel
1 parent afb5272 commit b947eb7

1 file changed

Lines changed: 16 additions & 9 deletions

File tree

src/ui/components/MessageArea.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ interface MessageAreaProps {
2424
*
2525
* 布局优化:
2626
* - Header 作为 Static 的第一个子项,确保永远在历史消息顶部
27+
* - TodoPanel 独立显示在动态区域底部,不随消息滚动被冻结
28+
* - 只在有活动 TODO(pending/in_progress)时显示 TodoPanel
2729
*/
2830
export const MessageArea: React.FC<MessageAreaProps> = React.memo(
2931
({ sessionState, terminalWidth, todos = [], showTodoPanel = false }) => {
@@ -47,10 +49,12 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
4749
};
4850
}, [sessionState.messages, sessionState.isThinking]);
4951

50-
// 找到最后一条用户消息的索引(用于 TodoPanel 定位)
51-
const lastUserMessageIndex = useMemo(() => {
52-
return sessionState.messages.findLastIndex((msg) => msg.role === 'user');
53-
}, [sessionState.messages]);
52+
// 检测是否有活动的 TODO(进行中或待处理)
53+
const hasActiveTodos = useMemo(() => {
54+
return todos.some(
55+
(todo) => todo.status === 'pending' || todo.status === 'in_progress'
56+
);
57+
}, [todos]);
5458

5559
// 渲染单个消息(用于 Static 和 dynamic 区域)
5660
const renderMessage = (msg: SessionMessage, index: number, isPending = false) => (
@@ -62,10 +66,6 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
6266
metadata={msg.metadata as Record<string, unknown>}
6367
isPending={isPending}
6468
/>
65-
{/* 在最后一条用户消息后显示 TodoPanel */}
66-
{index === lastUserMessageIndex && showTodoPanel && todos.length > 0 && (
67-
<TodoPanel todos={todos} visible={true} compact={false} />
68-
)}
6969
</Box>
7070
);
7171

@@ -82,7 +82,7 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
8282
});
8383

8484
return items;
85-
}, [completedMessages, lastUserMessageIndex, showTodoPanel, todos]);
85+
}, [completedMessages]);
8686

8787
return (
8888
<Box flexDirection="column" flexGrow={1} paddingX={2}>
@@ -93,6 +93,13 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
9393
{/* 动态区域:只有流式传输的消息会重新渲染 */}
9494
{streamingMessage &&
9595
renderMessage(streamingMessage, completedMessages.length, true)}
96+
97+
{/* TodoPanel 独立显示(仅在有活动 TODO 时) */}
98+
{showTodoPanel && hasActiveTodos && (
99+
<Box marginTop={1}>
100+
<TodoPanel todos={todos} visible={true} compact={false} />
101+
</Box>
102+
)}
96103
</Box>
97104
</Box>
98105
);

0 commit comments

Comments
 (0)