Skip to content

Commit 15a7a32

Browse files
committed
feat(feedback): 增加反馈消息和对话标题的展开收起功能
在反馈模态框中添加消息内容和对话标题的展开/收起功能,优化长文本显示体验 添加相关样式和交互逻辑,支持自适应显示和折叠 移除消息内容长度限制,显示完整内容
1 parent 44ede4d commit 15a7a32

File tree

6 files changed

+165
-46
lines changed

6 files changed

+165
-46
lines changed

server/routers/dashboard_router.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ async def get_all_feedbacks(
718718
"rating": feedback.rating,
719719
"reason": feedback.reason,
720720
"created_at": feedback.created_at.isoformat(),
721-
"message_content": message.content[:100] + ("..." if len(message.content) > 100 else ""),
721+
"message_content": message.content,
722722
"conversation_title": conversation.title,
723723
"agent_id": conversation.agent_id,
724724
}

web/src/components/AgentChatComponent.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,6 @@ watch(conversations, () => {
10671067
display: flex;
10681068
flex-direction: column;
10691069
overflow-x: hidden;
1070-
background: var(--gray-0);
10711070
position: relative;
10721071
box-sizing: border-box;
10731072
overflow-y: scroll;

web/src/components/KnowledgeBaseCard.vue

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,22 @@
1818
<a-button
1919
type="text"
2020
size="small"
21-
:icon="h(CopyOutlined)"
2221
@click="copyDatabaseId"
2322
title="复制知识库ID"
24-
/>
23+
>
24+
<template #icon>
25+
<Copy :size="14" />
26+
</template>
27+
</a-button>
2528
<a-button
2629
@click="showEditModal"
2730
type="text"
2831
size="small"
29-
:icon="h(EditOutlined)"
30-
/>
32+
>
33+
<template #icon>
34+
<Pencil :size="14" />
35+
</template>
36+
</a-button>
3137
</div>
3238
</div>
3339

@@ -55,7 +61,10 @@
5561
<a-modal v-model:open="editModalVisible" title="编辑知识库信息">
5662
<template #footer>
5763
<a-button danger @click="deleteDatabase" style="margin-right: auto; margin-left: 0;">
58-
<DeleteOutlined /> 删除数据库
64+
<template #icon>
65+
<Trash2 :size="16" style="vertical-align: -3px; margin-right: 4px;" />
66+
</template>
67+
删除数据库
5968
</a-button>
6069
<a-button key="back" @click="editModalVisible = false">取消</a-button>
6170
<a-button key="submit" type="primary" @click="handleEditSubmit">确定</a-button>
@@ -97,12 +106,12 @@ import { useRouter } from 'vue-router';
97106
import { useDatabaseStore } from '@/stores/database';
98107
import { getKbTypeLabel, getKbTypeColor } from '@/utils/kb_utils';
99108
import { message } from 'ant-design-vue';
109+
import { LeftOutlined } from '@ant-design/icons-vue';
100110
import {
101-
LeftOutlined,
102-
EditOutlined,
103-
DeleteOutlined,
104-
CopyOutlined,
105-
} from '@ant-design/icons-vue';
111+
Pencil,
112+
Trash2,
113+
Copy,
114+
} from 'lucide-vue-next';
106115
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
107116
import AiTextarea from '@/components/AiTextarea.vue';
108117

web/src/components/dashboard/FeedbackModalComponent.vue

Lines changed: 140 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,54 @@
4848
</a-tag>
4949
</div>
5050

51-
<!-- 卡片内容:消息内容和对话信息 -->
51+
<!-- 卡片内容:对话信息、消息内容和反馈原因 -->
5252
<div class="card-content">
53-
<div class="message-section">
54-
<div class="message-content">{{ feedback.message_content }}</div>
55-
</div>
56-
57-
<div class="conversation-section">
53+
<!-- 对话标题 -->
54+
<div class="conversation-section" v-if="feedback.conversation_title">
5855
<div class="conversation-info">
5956
<div class="info-item">
57+
<span
58+
class="conversation-title"
59+
:class="{ 'collapsed': !expandedStates.get(`${feedback.id}-conversation`) }"
60+
>
61+
标题:{{ feedback.conversation_title }}
62+
</span>
63+
<a-button
64+
v-if="shouldShowConversationExpandButton(feedback.conversation_title)"
65+
type="link"
66+
size="small"
67+
@click="toggleConversationExpand(feedback.id)"
68+
class="expand-button-inline"
69+
>
70+
{{ expandedStates.get(`${feedback.id}-conversation`) ? '收起' : '展开' }}
71+
</a-button>
72+
</div>
73+
<div class="info-item" v-if="!props.agentId">
6074
<span class="label">智能体:</span>
6175
<span class="value">{{ feedback.agent_id }}</span>
6276
</div>
63-
<div class="info-item" v-if="feedback.conversation_title">
64-
<span class="label">对话:</span>
65-
<span class="value">{{ feedback.conversation_title }}</span>
66-
</div>
6777
</div>
6878
</div>
6979

80+
<!-- 消息内容 -->
81+
<div class="message-section">
82+
<div
83+
class="message-content"
84+
:class="{ 'collapsed': !expandedStates.get(`${feedback.id}-message`) }"
85+
>
86+
{{ feedback.message_content }}
87+
</div>
88+
<a-button
89+
v-if="shouldShowExpandButton(feedback.message_content)"
90+
type="link"
91+
size="small"
92+
@click="toggleExpand(feedback.id)"
93+
class="expand-button"
94+
>
95+
{{ expandedStates.get(`${feedback.id}-message`) ? '收起' : '展开全部' }}
96+
</a-button>
97+
</div>
98+
7099
<!-- 反馈原因 -->
71100
<div v-if="feedback.reason" class="reason-section">
72101
<div class="reason-content">{{ feedback.reason }}</div>
@@ -98,6 +127,14 @@ import { LikeOutlined, DislikeOutlined, ClockCircleOutlined } from '@ant-design/
98127
import { dashboardApi } from '@/apis/dashboard_api'
99128
import { formatFullDateTime } from '@/utils/time'
100129
130+
// 常量配置
131+
const CONFIG = {
132+
MESSAGE_MAX_LINES: 8, // 消息最大显示行数
133+
CONVERSATION_MAX_LINES: 2, // 对话标题最大显示行数
134+
CONVERSATION_MAX_CHARS: 60, // 对话标题字符数阈值
135+
AVG_CHARS_PER_LINE: 30 // 每行平均字符数(中英文混合)
136+
}
137+
101138
// Props
102139
const props = defineProps({
103140
agentId: {
@@ -119,6 +156,9 @@ const feedbackOptions = [
119156
{ label: '点踩', value: 'dislike' }
120157
]
121158
159+
// 展开状态映射(使用 Map 避免直接修改对象)
160+
const expandedStates = ref(new Map())
161+
122162
// 显示模态框
123163
const show = () => {
124164
modalVisible.value = true
@@ -128,6 +168,37 @@ const show = () => {
128168
// 暴露方法给父组件
129169
defineExpose({ show })
130170
171+
// 计算文本行数的辅助函数(估算)
172+
const estimateLines = (text) => {
173+
if (!text) return 0
174+
return Math.ceil(text.length / CONFIG.AVG_CHARS_PER_LINE)
175+
}
176+
177+
// 判断是否显示展开按钮
178+
const shouldShowExpandButton = (content) => {
179+
return estimateLines(content) > CONFIG.MESSAGE_MAX_LINES
180+
}
181+
182+
// 判断对话标题是否需要展开按钮
183+
const shouldShowConversationExpandButton = (title) => {
184+
if (!title) return false
185+
return title.length > CONFIG.CONVERSATION_MAX_CHARS
186+
}
187+
188+
// 切换展开/收起状态
189+
const toggleExpand = (feedbackId) => {
190+
const key = `${feedbackId}-message`
191+
const currentState = expandedStates.value.get(key) ?? false
192+
expandedStates.value.set(key, !currentState)
193+
}
194+
195+
// 切换对话标题展开/收起状态
196+
const toggleConversationExpand = (feedbackId) => {
197+
const key = `${feedbackId}-conversation`
198+
const currentState = expandedStates.value.get(key) ?? false
199+
expandedStates.value.set(key, !currentState)
200+
}
201+
131202
// 加载反馈列表
132203
const loadFeedbacks = async () => {
133204
loadingFeedbacks.value = true
@@ -139,9 +210,12 @@ const loadFeedbacks = async () => {
139210
140211
const response = await dashboardApi.getFeedbacks(params)
141212
feedbacks.value = response
213+
// 重置展开状态
214+
expandedStates.value.clear()
142215
} catch (error) {
143216
console.error('加载反馈列表失败:', error)
144-
message.error('加载反馈列表失败')
217+
message.error('加载反馈列表失败,请稍后重试')
218+
feedbacks.value = []
145219
} finally {
146220
loadingFeedbacks.value = false
147221
}
@@ -268,6 +342,25 @@ watch(() => props.agentId, () => {
268342
line-height: 1.4;
269343
color: var(--gray-800);
270344
word-break: break-word;
345+
overflow: hidden;
346+
transition: max-height 0.3s ease;
347+
}
348+
349+
.message-content.collapsed {
350+
display: -webkit-box;
351+
-webkit-box-orient: vertical;
352+
-webkit-line-clamp: 8;
353+
line-clamp: 8;
354+
overflow: hidden;
355+
text-overflow: ellipsis;
356+
}
357+
358+
.expand-button {
359+
padding: 0;
360+
height: auto;
361+
font-size: 12px;
362+
margin-top: 8px;
363+
color: var(--main-color);
271364
}
272365
273366
.conversation-section {
@@ -277,7 +370,7 @@ watch(() => props.agentId, () => {
277370
.conversation-info {
278371
display: flex;
279372
flex-direction: column;
280-
gap: 4px;
373+
gap: 8px;
281374
}
282375
283376
.info-item {
@@ -297,6 +390,41 @@ watch(() => props.agentId, () => {
297390
font-weight: 400;
298391
word-break: break-all;
299392
}
393+
394+
// 对话标题样式(独立显示)
395+
.conversation-title {
396+
display: block;
397+
color: var(--gray-700);
398+
font-size: 13px;
399+
font-weight: 500;
400+
line-height: 1.4;
401+
word-break: break-word;
402+
transition: all 0.3s ease;
403+
404+
&.collapsed {
405+
display: -webkit-box;
406+
-webkit-box-orient: vertical;
407+
-webkit-line-clamp: 2;
408+
line-clamp: 2;
409+
overflow: hidden;
410+
text-overflow: ellipsis;
411+
}
412+
}
413+
414+
// 包含对话标题的 info-item 改为垂直布局
415+
&:has(.conversation-title) {
416+
flex-direction: column;
417+
align-items: flex-start;
418+
gap: 4px;
419+
}
420+
}
421+
422+
.expand-button-inline {
423+
padding: 0;
424+
height: auto;
425+
font-size: 11px;
426+
color: var(--main-color);
427+
align-self: flex-start;
300428
}
301429
302430
.reason-section {
@@ -346,14 +474,8 @@ watch(() => props.agentId, () => {
346474
gap: 12px;
347475
}
348476
349-
.feedback-card {
350-
margin-bottom: 0;
351-
}
352-
353477
.card-header {
354478
padding: 10px 12px;
355-
flex-direction: column;
356-
align-items: flex-start;
357479
gap: 8px;
358480
}
359481
@@ -362,19 +484,6 @@ watch(() => props.agentId, () => {
362484
gap: 10px;
363485
}
364486
365-
.conversation-info {
366-
.info-item {
367-
flex-direction: column;
368-
align-items: flex-start;
369-
gap: 2px;
370-
371-
.label {
372-
min-width: auto;
373-
margin-right: 0;
374-
}
375-
}
376-
}
377-
378487
.card-footer {
379488
padding: 6px 12px;
380489
}

web/src/layouts/AppLayout.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ onMounted(async () => {
9494
getRemoteConfig()
9595
getRemoteDatabase()
9696
fetchGithubStars() // Fetch GitHub stars on mount
97+
// 预加载任务数据,确保任务中心打开时有内容
98+
taskerStore.loadTasks()
9799
})
98100
99101
// 打印当前页面的路由信息,使用 vue3 的 setup composition API

web/src/views/DataBaseInfoView.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<span :style="{ color: !isEvaluationSupported ? 'var(--gray-400)' : '' }">
4848
RAG评估
4949
<a-tooltip v-if="!isEvaluationSupported" title="仅支持 Milvus 类型的知识库">
50-
<InfoCircleOutlined style="margin-left: 4px;" />
50+
<Info :size="14" style="margin-left: 4px; vertical-align: middle;" />
5151
</a-tooltip>
5252
</span>
5353
</template>
@@ -62,7 +62,7 @@
6262
<span :style="{ color: !isEvaluationSupported ? 'var(--gray-400)' : '' }">
6363
评估基准
6464
<a-tooltip v-if="!isEvaluationSupported" title="仅支持 Milvus 类型的知识库">
65-
<InfoCircleOutlined style="margin-left: 4px;" />
65+
<Info :size="14" style="margin-left: 4px; vertical-align: middle;" />
6666
</a-tooltip>
6767
</span>
6868
</template>
@@ -93,7 +93,7 @@ import { onMounted, reactive, ref, watch, onUnmounted, computed } from 'vue';
9393
import { useRoute } from 'vue-router';
9494
import { useDatabaseStore } from '@/stores/database';
9595
import { useTaskerStore } from '@/stores/tasker';
96-
import { InfoCircleOutlined } from '@ant-design/icons-vue';
96+
import { Info } from 'lucide-vue-next';
9797
import KnowledgeBaseCard from '@/components/KnowledgeBaseCard.vue';
9898
import FileTable from '@/components/FileTable.vue';
9999
import FileDetailModal from '@/components/FileDetailModal.vue';

0 commit comments

Comments
 (0)