feat: 消息ui优化

This commit is contained in:
Gsh
2026-01-31 21:28:13 +08:00
parent dbc6b8cf5e
commit f57b5befd7
2 changed files with 33 additions and 35 deletions

View File

@@ -6,7 +6,7 @@ import type { BubbleListInstance } from 'vue-element-plus-x/types/BubbleList';
import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard'; import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard';
import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking'; import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking';
import type { UnifiedMessage } from '@/utils/apiFormatConverter'; import type { UnifiedMessage } from '@/utils/apiFormatConverter';
import { ArrowLeftBold, ArrowRightBold, Clock, Delete, Document, DocumentCopy, Edit, Loading, Refresh } from '@element-plus/icons-vue'; import { ArrowLeftBold, ArrowRightBold, Delete, Document, DocumentCopy, Edit, Loading, Refresh } from '@element-plus/icons-vue';
import { ElIcon, ElMessage } from 'element-plus'; import { ElIcon, ElMessage } from 'element-plus';
import { useHookFetch } from 'hook-fetch/vue'; import { useHookFetch } from 'hook-fetch/vue';
import mammoth from 'mammoth'; import mammoth from 'mammoth';
@@ -532,13 +532,9 @@ function enterDeleteMode(item?: MessageItem) {
selectedMessageIds.value = []; selectedMessageIds.value = [];
deleteTargetMessage.value = item || null; deleteTargetMessage.value = item || null;
// 如果指定了消息,自动选中该消息及其之后的所有消息 // 如果指定了消息,自动选中当前点击的这条消息
if (item && item.id) { if (item && item.id) {
const itemIndex = bubbleItems.value.findIndex(msg => msg.key === item.key); selectedMessageIds.value = [item.id];
if (itemIndex !== -1) {
const messagesToDelete = bubbleItems.value.slice(itemIndex);
selectedMessageIds.value = messagesToDelete.filter(msg => msg.id).map(msg => msg.id!);
}
} }
} }
@@ -1282,7 +1278,6 @@ onUnmounted(() => {
<!-- 时间和token信息 --> <!-- 时间和token信息 -->
<div class="footer-info"> <div class="footer-info">
<span v-if="item.creationTime" class="footer-time"> <span v-if="item.creationTime" class="footer-time">
<ElIcon><Clock /></ElIcon>
{{ item.creationTime }} {{ item.creationTime }}
</span> </span>
<span v-if="item.role !== 'user' && item?.tokenUsage?.total" class="footer-token"> <span v-if="item.role !== 'user' && item?.tokenUsage?.total" class="footer-token">
@@ -1410,6 +1405,7 @@ onUnmounted(() => {
// 删除模式 // 删除模式
&.delete-mode { &.delete-mode {
.el-bubble { .el-bubble {
// 删除模式下:用户消息加回 flex:auto // 删除模式下:用户消息加回 flex:auto
&[class*="end"] .el-bubble-content-wrapper { &[class*="end"] .el-bubble-content-wrapper {
@@ -1483,7 +1479,9 @@ onUnmounted(() => {
border-color: #8ab4f8; border-color: #8ab4f8;
} }
} }
} }
} }
.el-bubble { .el-bubble {
@@ -1517,14 +1515,22 @@ onUnmounted(() => {
// 正常模式下:去掉 flex:auto // 正常模式下:去掉 flex:auto
.el-bubble-content-wrapper { .el-bubble-content-wrapper {
flex: none; flex: none;
max-width: fit-content;
} }
// 编辑模式下:加回 flex:auto // 编辑模式下:加回 flex:auto
&:has(.edit-message-wrapper-full) .el-bubble-content-wrapper { &:has(.edit-message-wrapper-full) .el-bubble-content-wrapper {
flex: auto; flex: auto;
max-width: 100%;
} }
.el-bubble-content { .el-bubble-content {
width: fit-content;
max-width: 100%;
}
// 编辑模式下:加回 flex:auto
&:has(.edit-message-wrapper-full) .el-bubble-content {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
} }
@@ -1623,7 +1629,7 @@ onUnmounted(() => {
.footer-wrapper { .footer-wrapper {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 8px; margin-top: 4px;
padding: 0 2px; padding: 0 2px;
} }
@@ -1637,33 +1643,28 @@ onUnmounted(() => {
.footer-info { .footer-info {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
font-size: 12px; font-size: 12px;
color: #8c8c8c; color: #888;
.footer-time { .footer-time {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; color: #888;
.el-icon {
font-size: 12px;
color: #bfbfbf;
}
} }
.footer-token { .footer-token {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; color: #888;
color: #8c8c8c;
&::before { &::before {
content: ''; content: '';
width: 4px; width: 3px;
height: 4px; height: 3px;
background: #bfbfbf; background: #bbb;
border-radius: 50%; border-radius: 50%;
margin-right: 8px;
} }
} }
} }
@@ -1671,23 +1672,17 @@ onUnmounted(() => {
.footer-actions { .footer-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 2px;
opacity: 0.4;
transition: opacity 0.2s ease;
.footer-wrapper:hover & {
opacity: 1;
}
.el-button { .el-button {
width: 26px; width: 24px;
height: 26px; height: 24px;
padding: 0; padding: 0;
font-size: 13px; font-size: 13px;
color: #8c8c8c; color: #555;
border: none; border: none;
background: transparent; background: transparent;
border-radius: 6px; border-radius: 4px;
transition: all 0.2s ease; transition: all 0.2s ease;
&:hover { &:hover {
@@ -1700,12 +1695,12 @@ onUnmounted(() => {
} }
&[disabled] { &[disabled] {
color: #d9d9d9; color: #bbb;
background: transparent; background: transparent;
} }
.el-icon { .el-icon {
font-size: 14px; font-size: 13px;
} }
} }
} }

View File

@@ -215,6 +215,9 @@
--el-button-border-radius-base: var(--border-radius-md); --el-button-border-radius-base: var(--border-radius-md);
--el-button-hover-bg-color: var(--color-primary-dark); --el-button-hover-bg-color: var(--color-primary-dark);
--el-button-active-bg-color: var(--color-primary-darker); --el-button-active-bg-color: var(--color-primary-darker);
--el-padding-sm: 6px
} }
/* ========== 暗色模式变量 ========== */ /* ========== 暗色模式变量 ========== */