Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
41747d53
Commit
41747d53
authored
Feb 09, 2026
by
水玉婷
Browse files
feat:添加复制功能
parent
958ab12c
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/views/components/AiChat.vue
View file @
41747d53
...
@@ -83,14 +83,20 @@
...
@@ -83,14 +83,20 @@
</a-button>
</a-button>
</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<!-- 操作按钮 -->
<!-- <div class="operation-box" v-if="msg.recordId">
<div
class=
"operation-box"
v-if=
"msg.messageType === 'received' && msg.recordId"
>
<p>
<div
class=
"operation-buttons"
>
<span>提示词Token数量:{{ msg.promptTokens }}</span>
<button
class=
"operation-btn copy-btn"
@
click=
"handleCopy(msg)"
title=
"复制"
>
<span>答复Token数量:{{ msg.completionTokens }}</span>
<copy-outlined
/>
<span>总Token数量: {{ msg.totalTokens }}</span>
</button>
</p>
<button
class=
"operation-btn like-btn"
@
click=
"handleLike(msg)"
title=
"赞"
>
</div> -->
<like-outlined
/>
</button>
<button
class=
"operation-btn dislike-btn"
@
click=
"handleDislike(msg)"
title=
"踩"
>
<dislike-outlined
/>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -120,7 +126,7 @@
...
@@ -120,7 +126,7 @@
import
{
ref
,
onMounted
,
onBeforeUnmount
,
nextTick
}
from
'
vue
'
;
import
{
ref
,
onMounted
,
onBeforeUnmount
,
nextTick
}
from
'
vue
'
;
import
dayjs
from
'
dayjs
'
;
import
dayjs
from
'
dayjs
'
;
import
{
markdownTemplate
,
isLastBlockMarkdown
,
getLastMarkdownBlockIndex
,
mergeMarkdownContent
}
from
'
./utils/markdownTemplate
'
;
import
{
markdownTemplate
,
isLastBlockMarkdown
,
getLastMarkdownBlockIndex
,
mergeMarkdownContent
}
from
'
./utils/markdownTemplate
'
;
import
{
SendOutlined
,
UserOutlined
,
ReloadOutlined
,
CopyOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
SendOutlined
,
UserOutlined
,
ReloadOutlined
,
CopyOutlined
,
LikeOutlined
,
DislikeOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
message
as
antdMessage
}
from
'
ant-design-vue
'
;
import
{
message
as
antdMessage
}
from
'
ant-design-vue
'
;
import
defaultAvatar
from
'
@/assets/logo.png
'
;
import
defaultAvatar
from
'
@/assets/logo.png
'
;
import
rightIcon
from
'
@/assets/right.svg
'
import
rightIcon
from
'
@/assets/right.svg
'
...
@@ -506,8 +512,6 @@ const retrySendMessage = async (messageIndex: number) => {
...
@@ -506,8 +512,6 @@ const retrySendMessage = async (messageIndex: number) => {
});
});
};
};
// 处理消息点击 - 将消息内容放到输入框
// 处理消息点击 - 将消息内容放到输入框
const
handleMessageClick
=
(
message
:
Message
,
block
:
any
)
=>
{
const
handleMessageClick
=
(
message
:
Message
,
block
:
any
)
=>
{
// 只处理文字消息,不处理音频、图表等特殊消息
// 只处理文字消息,不处理音频、图表等特殊消息
...
@@ -516,34 +520,9 @@ const handleMessageClick = (message: Message, block: any) => {
...
@@ -516,34 +520,9 @@ const handleMessageClick = (message: Message, block: any) => {
}
}
try
{
try
{
// 提取消息中的文本内容
// 直接使用原始内容
let
textToInput
=
''
;
if
(
message
.
originalContent
)
{
messageText
.
value
=
message
.
originalContent
;
if
(
message
.
contentBlocks
&&
message
.
contentBlocks
.
length
>
0
)
{
message
.
contentBlocks
.
forEach
(
block
=>
{
// 跳过非文字内容块
if
(
block
.
audioData
||
block
.
chartData
)
{
return
;
}
if
(
block
.
content
)
{
// 移除HTML标签,只保留纯文本
const
textContent
=
block
.
content
.
replace
(
/<
[^
>
]
*>/g
,
''
).
trim
();
if
(
textContent
)
{
textToInput
+=
textContent
+
'
\n
'
;
}
}
});
}
// 如果没有内容,使用原始内容
if
(
!
textToInput
.
trim
()
&&
message
.
originalContent
)
{
textToInput
=
message
.
originalContent
;
}
if
(
textToInput
.
trim
())
{
// 将内容设置到输入框
messageText
.
value
=
textToInput
.
trim
();
// 自动调整输入框高度
// 自动调整输入框高度
adjustTextareaHeight
();
adjustTextareaHeight
();
// 聚焦到输入框
// 聚焦到输入框
...
@@ -628,6 +607,67 @@ const toggleThinkBox = (messageIndex: number, blockIndex: number) => {
...
@@ -628,6 +607,67 @@ const toggleThinkBox = (messageIndex: number, blockIndex: number) => {
!
messages
.
value
[
messageIndex
].
contentBlocks
[
blockIndex
].
thinkBoxExpanded
;
!
messages
.
value
[
messageIndex
].
contentBlocks
[
blockIndex
].
thinkBoxExpanded
;
}
}
};
};
// 复制消息内容
const
handleCopy
=
async
(
msg
:
Message
)
=>
{
try
{
let
textToCopy
=
''
;
// 遍历所有内容块
msg
.
contentBlocks
.
forEach
(
block
=>
{
if
(
block
.
chartData
)
{
// 如果是表格内容,复制description
textToCopy
+=
block
.
chartData
.
description
||
''
;
}
else
if
(
block
.
content
)
{
// 检查是否是iframe内容
if
(
block
.
content
.
includes
(
'
message-iframe
'
))
{
// 提取iframe的src属性
const
srcMatch
=
block
.
content
.
match
(
/src="
([^
"
]
+
)
"/
);
if
(
srcMatch
&&
srcMatch
[
1
])
{
textToCopy
+=
srcMatch
[
1
]
+
'
\n
'
;
}
}
else
{
// 其他内容复制content
// 移除HTML标签,保留纯文本
const
textContent
=
block
.
content
.
replace
(
/<
[^
>
]
*>/g
,
''
).
trim
();
if
(
textContent
)
{
textToCopy
+=
textContent
+
'
\n
'
;
}
}
}
});
// 如果没有内容,使用原始内容
if
(
!
textToCopy
.
trim
()
&&
msg
.
originalContent
)
{
textToCopy
=
msg
.
originalContent
;
}
if
(
textToCopy
.
trim
())
{
// 使用Clipboard API复制到剪贴板
await
navigator
.
clipboard
.
writeText
(
textToCopy
.
trim
());
antdMessage
.
success
(
'
内容已复制到剪贴板
'
);
}
else
{
antdMessage
.
warning
(
'
没有可复制的内容
'
);
}
}
catch
(
error
)
{
console
.
error
(
'
复制失败:
'
,
error
);
antdMessage
.
error
(
'
复制失败,请手动复制
'
);
}
};
// 点赞消息
const
handleLike
=
(
msg
:
Message
)
=>
{
console
.
log
(
'
点赞消息:
'
,
msg
.
recordId
);
antdMessage
.
success
(
'
已点赞
'
);
// 这里可以添加实际的点赞API调用
};
// 踩消息
const
handleDislike
=
(
msg
:
Message
)
=>
{
console
.
log
(
'
踩消息:
'
,
msg
.
recordId
);
antdMessage
.
success
(
'
已踩
'
);
// 这里可以添加实际的踩API调用
};
// 处理按键事件
// 处理按键事件
const
handleKeyPress
=
(
e
:
KeyboardEvent
)
=>
{
const
handleKeyPress
=
(
e
:
KeyboardEvent
)
=>
{
if
(
e
.
key
===
'
Enter
'
&&
!
e
.
shiftKey
)
{
if
(
e
.
key
===
'
Enter
'
&&
!
e
.
shiftKey
)
{
...
...
src/views/components/style.less
View file @
41747d53
...
@@ -301,6 +301,57 @@ li {
...
@@ -301,6 +301,57 @@ li {
margin: 20px 0px 8px;
margin: 20px 0px 8px;
}
}
// 操作按钮样式
.operation-box {
margin-top: 12px;
display: flex;
.operation-buttons {
display: flex;
gap: 6px;
align-items: center;
.operation-btn {
border: none;
background: @gray-2;
color: @gray-7;
padding: 6px;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: all 0.3s ease;
&:hover {
background: @gray-3;
color: @gray-7;
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
}
&.copy-btn:hover {
background: @blue-light-1;
color: @primary-color;
}
&.like-btn:hover {
background: #f6ffed;
color: @success-color;
}
&.dislike-btn:hover {
background: #fff2f0;
color: @error-color;
}
}
}
}
// 失败消息样式
// 失败消息样式
.message-failed-wrapper {
.message-failed-wrapper {
margin-top: 12px;
margin-top: 12px;
...
@@ -620,19 +671,6 @@ li {
...
@@ -620,19 +671,6 @@ li {
}
}
}
}
.operation-box {
margin-top: 6px;
p {
color: @gray-5;
span {
margin-right: 15px;
}
}
}
// =============================================
// =============================================
// iframe消息样式
// iframe消息样式
...
@@ -1244,19 +1282,6 @@ li {
...
@@ -1244,19 +1282,6 @@ li {
}
}
}
}
.operation-box {
margin-top: 6px;
p {
color: @gray-5;
font-size: 16px;
span {
margin-right: 15px;
}
}
}
@keyframes waveAnimation {
@keyframes waveAnimation {
0%,
0%,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment