Skip to content

Commit 0e2abcc

Browse files
committed
feat: 优化助手消息组件和计算器结果展示
- 在 AgentMessageComponent.vue 中更新消息解析逻辑,使用 parsedMessage 处理内容和推理信息。 - 改进样式,增强用户体验,包括工具调用结果的展示和交互效果。 - 移除 CalculatorResult.vue 中不必要的元素,简化结果展示。
1 parent d1f4d85 commit 0e2abcc

File tree

2 files changed

+103
-35
lines changed

2 files changed

+103
-35
lines changed

web/src/components/AgentMessageComponent.vue

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,28 @@
55

66
<!-- 助手消息 -->
77
<div v-else-if="message.type === 'ai'" class="assistant-message">
8-
<div v-if="message.reasoning_content" class="reasoning-box">
8+
<div v-if="parsedMessage.reasoning_content" class="reasoning-box">
99
<a-collapse v-model:activeKey="reasoningActiveKey" :bordered="false">
1010
<template #expandIcon="{ isActive }">
1111
<caret-right-outlined :rotate="isActive ? 90 : 0" />
1212
</template>
1313
<a-collapse-panel key="show" :header="message.status=='reasoning' ? '正在思考...' : '推理过程'" class="reasoning-header">
14-
<p class="reasoning-content">{{ message.reasoning_content.trim() }}</p>
14+
<p class="reasoning-content">{{ parsedMessage.reasoning_content.trim() }}</p>
1515
</a-collapse-panel>
1616
</a-collapse>
1717
</div>
1818

1919
<!-- 消息内容 -->
2020
<!-- <div v-else-if="message.content" v-html="renderMarkdown(message)" class="message-md"></div> -->
21-
<MdPreview v-else-if="message.content" ref="editorRef"
21+
<MdPreview v-if="parsedMessage.content" ref="editorRef"
2222
editorId="preview-only"
2323
previewTheme="github"
2424
:showCodeRowNumber="false"
25-
:modelValue="message.content"
25+
:modelValue="parsedMessage.content"
2626
:key="message.id"
2727
class="message-md"/>
2828

29-
<div v-else-if="message.reasoning_content" class="empty-block"></div>
29+
<div v-else-if="parsedMessage.reasoning_content" class="empty-block"></div>
3030

3131
<div v-if="message.tool_calls && Object.keys(message.tool_calls).length > 0" class="tool-calls-container">
3232
<div v-for="(toolCall, index) in message.tool_calls || {}" :key="index" class="tool-call-container">
@@ -38,13 +38,13 @@
3838
<span class="tool-name">{{ toolCall.name || toolCall.function.name }}</span>
3939
</span>
4040
<span v-else>
41-
<ThunderboltOutlined /> 工具 <span class="tool-name">{{ toolCall.name || toolCall.function.name }}</span> 执行完成
41+
<ThunderboltOutlined /> &nbsp; 工具 <span class="tool-name">{{ toolCall.name || toolCall.function.name }}</span> 执行完成
4242
</span>
4343
</div>
4444
<div class="tool-content" v-show="expandedToolCalls.has(toolCall.id)">
4545
<div class="tool-params" v-if="toolCall.args || toolCall.function.arguments">
4646
<div class="tool-params-content">
47-
<pre> 参数: {{ toolCall.args || toolCall.function.arguments }}</pre>
47+
<strong>参数:</strong> {{ toolCall.args || toolCall.function.arguments }}
4848
</div>
4949
</div>
5050
<div class="tool-result" v-if="toolCall.tool_call_result && toolCall.tool_call_result.content">
@@ -137,6 +137,26 @@ const isEmptyAndLoading = computed(() => {
137137
return isEmpty && isLoading;
138138
});
139139
140+
const parsedMessage = computed(() => {
141+
const message = props.message;
142+
if (message.content) {
143+
// 匹配完整的 <think>...</think> 标签
144+
const thinkContent = message.content.match(/<think>(.*?)<\/think>/s);
145+
if (thinkContent) {
146+
message.reasoning_content = thinkContent[1];
147+
message.content = message.content.replace(/<think>(.*?)<\/think>/s, '');
148+
} else {
149+
// 匹配未闭合的 <think> 标签,处理加载中的情况
150+
const incompleteThinkContent = message.content.match(/<think>(.*?)$/s);
151+
if (incompleteThinkContent) {
152+
message.reasoning_content = incompleteThinkContent[1];
153+
message.content = message.content.replace(/<think>(.*?)$/s, '');
154+
}
155+
}
156+
}
157+
return message;
158+
});
159+
140160
const toggleToolCall = (toolCallId) => {
141161
if (expandedToolCalls.value.has(toolCallId)) {
142162
expandedToolCalls.value.delete(toolCallId);
@@ -207,14 +227,61 @@ const toggleToolCall = (toolCallId) => {
207227
.reasoning-box {
208228
margin-top: 10px;
209229
margin-bottom: 15px;
210-
border-radius: 8px;
211-
border: 1px solid var(--main-light-3);
230+
border-radius: 12px;
231+
border: 1px solid var(--gray-200);
232+
background-color: var(--gray-50);
233+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
234+
overflow: hidden;
235+
transition: all 0.2s ease;
236+
237+
&:hover {
238+
border-color: var(--main-300);
239+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
240+
}
241+
242+
:deep(.ant-collapse) {
243+
background-color: transparent;
244+
border: none;
245+
246+
.ant-collapse-item {
247+
border: none;
248+
249+
.ant-collapse-header {
250+
padding: 12px 16px;
251+
background-color: var(--gray-100);
252+
font-size: 14px;
253+
font-weight: 500;
254+
color: var(--gray-800);
255+
border-bottom: 1px solid var(--gray-200);
256+
transition: all 0.2s ease;
257+
258+
&:hover {
259+
background-color: var(--gray-150);
260+
}
261+
262+
.ant-collapse-expand-icon {
263+
color: var(--main-600);
264+
}
265+
}
266+
267+
.ant-collapse-content {
268+
border: none;
269+
background-color: transparent;
270+
271+
.ant-collapse-content-box {
272+
padding: 16px;
273+
background-color: var(--gray-50);
274+
}
275+
}
276+
}
277+
}
212278
213279
.reasoning-content {
214280
font-size: 13px;
215281
color: var(--gray-800);
216282
white-space: pre-wrap;
217283
margin: 0;
284+
line-height: 1.6;
218285
}
219286
}
220287
@@ -251,11 +318,18 @@ const toggleToolCall = (toolCallId) => {
251318
:deep(.tool-call-display) {
252319
background-color: var(--gray-50);
253320
border: 1px solid var(--gray-200);
254-
border-radius: 8px;
321+
border-radius: 12px;
255322
overflow: hidden;
323+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
324+
transition: all 0.2s ease;
325+
326+
&:hover {
327+
border-color: var(--main-300);
328+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
329+
}
256330
257331
.tool-header {
258-
padding: 10px 12px;
332+
padding: 12px 16px;
259333
background-color: var(--gray-100);
260334
font-size: 14px;
261335
font-weight: 500;
@@ -267,9 +341,20 @@ const toggleToolCall = (toolCallId) => {
267341
cursor: pointer;
268342
user-select: none;
269343
position: relative;
344+
transition: all 0.2s ease;
345+
346+
&:hover {
347+
background-color: var(--gray-150);
348+
}
270349
271350
.anticon {
272351
color: var(--main-600);
352+
font-size: 16px;
353+
}
354+
355+
.tool-name {
356+
font-weight: 600;
357+
color: var(--main-700);
273358
}
274359
275360
.step-badge {
@@ -285,27 +370,30 @@ const toggleToolCall = (toolCallId) => {
285370
286371
.tool-content {
287372
transition: all 0.3s ease;
373+
288374
.tool-params {
289-
padding: 10px 12px;
375+
padding: 16px;
290376
background-color: var(--gray-50);
291377
292378
.tool-params-header {
293379
background-color: var(--gray-100);
294380
font-size: 13px;
295381
color: var(--gray-800);
382+
margin-bottom: 8px;
383+
font-weight: 500;
296384
}
297385
298386
.tool-params-content {
299387
margin: 0;
300388
font-size: 13px;
301389
background-color: var(--gray-100);
302-
border-radius: 4px;
303-
padding: 8px;
304390
overflow-x: auto;
305391
color: var(--gray-800);
392+
line-height: 1.5;
306393
307394
pre {
308395
margin: 0;
396+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
309397
}
310398
}
311399
}
@@ -315,7 +403,7 @@ const toggleToolCall = (toolCallId) => {
315403
background-color: transparent;
316404
317405
.tool-result-header {
318-
padding: 10px 12px;
406+
padding: 12px 16px;
319407
background-color: var(--gray-100);
320408
font-size: 12px;
321409
color: var(--gray-700);

web/src/components/ToolCallingResult/CalculatorResult.vue

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,8 @@
66

77
<div class="calc-display">
88
<div class="result-container">
9-
<div class="result-label">结果:</div>
109
<div class="result-value">{{ formatNumber(data) }}</div>
1110
</div>
12-
13-
<div class="result-actions">
14-
<a-button size="small" @click="copyResult" type="primary" ghost>
15-
<CopyOutlined /> 复制结果
16-
</a-button>
17-
</div>
18-
</div>
19-
20-
<!-- 如果结果很大或很小,显示科学记数法 -->
21-
<div v-if="showScientificNotation" class="scientific-notation">
22-
<span class="notation-label">科学记数法:</span>
23-
<span class="notation-value">{{ data.toExponential(6) }}</span>
24-
</div>
25-
26-
<!-- 显示数字类型信息 -->
27-
<div class="number-info">
28-
<a-tag :color="getNumberTypeColor()">{{ getNumberType() }}</a-tag>
29-
<span v-if="isInteger" class="number-detail">整数</span>
30-
<span v-else class="number-detail">{{ getDecimalPlaces() }} 位小数</span>
3111
</div>
3212
</div>
3313
</template>

0 commit comments

Comments
 (0)