优化会话列表名称,添加复制和转发,转发待完善

This commit is contained in:
2026-08-07 17:58:36 +08:00
parent 53ca1cd851
commit 96d58abc2f
21 changed files with 1845 additions and 109 deletions

View File

@@ -72,10 +72,7 @@
<view class="history-chat-avatar">
<uni-icons type="chat-filled" size="26" color="#007aff"></uni-icons>
</view>
<view v-if="chat.agent_id">
{{truncateText(chat.agent_data?.title) || "加载中"}}
</view>
<view v-else>{{truncateText(chat.title)}}</view>
<view>{{truncateText(getConvName(chat))}}</view>
</view>
<!-- 好友对话列表 -->
<view v-if="chatType === 1" v-for="chat in UserConversations" :key="chat.sessionId"
@@ -325,6 +322,18 @@
return text.length > maxLength ? text.substring(0, maxLength) + '...' : text
}
// 获取会话名称agent_title > 清理后的title > 格式化时间
const getConvName = (conv) => {
if (conv.agent_data?.title) return conv.agent_data.title
if (conv.title && !conv.title.startsWith('[文件信息')) return conv.title
if (conv.created_at) {
const t = conv.created_at
const pad = (n) => String(n).padStart(2, '0')
return `${t.year}${t.month}${t.day}${pad(t.hour)}:${pad(t.minute)}:${pad(t.second)}`
}
return '未命名会话'
}
onMounted(async () => {
UserToken.value = getToken()
const UserInfo = await getUserInfo(UserToken.value)

View File

@@ -400,6 +400,191 @@
background: #e0e0e0;
}
/* ========== 转发消息弹窗 ========== */
.forward-modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.forward-modal {
width: 85%;
max-height: 72%;
background-color: #fff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12);
}
.forward-modal-header {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 28rpx 30rpx 20rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.forward-modal-title {
font-size: 34rpx;
font-weight: 700;
color: #1a1a2e;
}
.forward-modal-close {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
}
.forward-preview-box {
margin: 20rpx 30rpx 8rpx;
padding: 20rpx 24rpx;
background: #f7f8fc;
border-radius: 14rpx;
border-left: 6rpx solid #007aff;
}
.forward-preview-label {
font-size: 24rpx;
color: #999;
display: block;
margin-bottom: 8rpx;
}
.forward-preview-text {
font-size: 28rpx;
color: #333;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
.forward-select-label {
font-size: 26rpx;
color: #666;
padding: 12rpx 30rpx 8rpx;
display: block;
}
.forward-conv-list {
flex: 1;
max-height: 400rpx;
padding: 0 20rpx;
}
.forward-empty {
display: flex;
justify-content: center;
align-items: center;
height: 160rpx;
color: #999;
font-size: 26rpx;
}
.forward-conv-item {
display: flex;
align-items: center;
padding: 22rpx 16rpx;
border-radius: 16rpx;
margin-bottom: 8rpx;
background: #fafafa;
transition: background 0.2s;
}
.forward-conv-item:active {
background: #eef4ff;
}
.forward-conv-selected {
background: #e8f0fe;
border: 2rpx solid #007aff;
}
.forward-conv-avatar {
width: 60rpx;
height: 60rpx;
border-radius: 14rpx;
background: #e8f0fe;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
.forward-conv-info {
flex: 1;
min-width: 0;
}
.forward-conv-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.forward-conv-check {
flex-shrink: 0;
margin-left: 12rpx;
}
.forward-modal-footer {
padding: 20rpx 30rpx 30rpx;
border-top: 2rpx solid #f0f0f0;
display: flex;
justify-content: flex-end;
gap: 20rpx;
}
.forward-modal-btn {
padding: 18rpx 48rpx;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
}
.forward-btn-cancel {
background: #f0f0f0;
color: #666;
}
.forward-btn-cancel:active {
background: #e0e0e0;
}
.forward-btn-confirm {
background: #007aff;
color: #fff;
}
.forward-btn-confirm:active {
background: #005fcc;
}
.forward-btn-disabled {
background: #b0d0f0;
color: #fff;
pointer-events: none;
}
/* ==========新建聊天列表相关====== */
.close-option-card {
width: 100%;
@@ -619,7 +804,7 @@
.chat-message {
display: flex;
align-items: flex-start;
flex-direction: column;
margin: 14rpx 0;
box-sizing: border-box;
animation: msgFadeIn 0.3s ease;
@@ -631,6 +816,17 @@
}
.message-user {
align-items: flex-end;
}
/* avatar + 气泡行(上方) */
.message-row {
display: flex;
align-items: flex-start;
width: 100%;
}
.message-user .message-row {
flex-direction: row-reverse;
}
@@ -675,6 +871,9 @@
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
background: #ffffff;
border: 1rpx solid #eeeef5;
/* 启用文本选择复制 */
user-select: text;
-webkit-user-select: text;
}
.chat-content-user {
@@ -694,6 +893,81 @@
border-bottom-left-radius: 8rpx;
}
/* 消息操作栏 */
.message-actions {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16rpx;
padding-top: 12rpx;
border-top: 1rpx solid rgba(0, 0, 0, 0.06);
gap: 24rpx;
}
.message-actions-user {
justify-content: flex-start;
border-top-color: rgba(255, 255, 255, 0.3);
}
.message-action-item {
display: flex;
align-items: center;
gap: 6rpx;
padding: 8rpx 16rpx;
border-radius: 12rpx;
transition: all 0.2s ease;
}
.message-action-item:active {
background: rgba(0, 0, 0, 0.05);
transform: scale(0.95);
}
.message-actions-user .message-action-item:active {
background: rgba(255, 255, 255, 0.2);
}
.action-text {
font-size: 22rpx;
color: #999;
}
.message-actions-user .action-text {
color: rgba(255, 255, 255, 0.8);
}
/* 消息转发弹窗 */
.msg-actions {
display: flex;
align-items: center;
gap: 16rpx;
margin-top: 10rpx;
}
.msg-actions-user {
justify-content: flex-end;
}
.msg-action-btn {
display: flex;
align-items: center;
gap: 6rpx;
padding: 4rpx 0;
}
.msg-action-icon {
font-size: 26rpx;
}
.msg-action-label {
font-size: 22rpx;
color: #888;
}
.msg-action-forward {
margin-left: 8rpx;
}
/* 图片消息 */
.message-image {
max-width: 300rpx;

View File

@@ -78,6 +78,54 @@
</view>
</view>
<!-- 转发消息弹窗 -->
<view class="forward-modal-mask" v-if="showForwardPopup" @click="cancelForward">
<view class="forward-modal" @click.stop>
<view class="forward-modal-header">
<text class="forward-modal-title">转发消息</text>
<view class="forward-modal-close" @click="cancelForward">
<uni-icons type="closeempty" size="20" color="#999"></uni-icons>
</view>
</view>
<!-- 被转发消息的预览 -->
<!-- <view class="forward-preview-box">
<text class="forward-preview-label">消息内容</text>
<text class="forward-preview-text">{{ forwardPreview }}</text>
</view> -->
<text class="forward-select-label">选择目标会话</text>
<scroll-view class="forward-conv-list" scroll-y="true">
<view v-if="forwardConversations.length === 0" class="forward-empty">
<text>暂无其他会话</text>
</view>
<view v-else
v-for="conv in forwardConversations"
:key="conv._id"
class="forward-conv-item"
:class="{ 'forward-conv-selected': forwardSelectedId === conv._id }"
@click="forwardSelectedId = conv._id"
>
<view class="forward-conv-avatar">
<uni-icons type="chat-filled" size="24" color="#007aff"></uni-icons>
</view>
<view class="forward-conv-info">
<text class="forward-conv-name">{{ getConvName(conv) }}</text>
</view>
<view v-if="forwardSelectedId === conv._id" class="forward-conv-check">
<uni-icons type="checkmarkempty" size="20" color="#007aff"></uni-icons>
</view>
</view>
</scroll-view>
<view class="forward-modal-footer">
<view class="forward-modal-btn forward-btn-cancel" @click="cancelForward">
<text>取消</text>
</view>
<view class="forward-modal-btn forward-btn-confirm" :class="{ 'forward-btn-disabled': !forwardSelectedId }" @click="confirmForward">
<text>确认转发</text>
</view>
</view>
</view>
</view>
<view class="chat-page page-container">
<!-- 弹窗出来时的笼罩层 -->
<view v-if="isChatSidebar" class="mask" @click="handleChatSidebar"></view>
@@ -159,6 +207,7 @@
<view class="chat-content"
:class="{'chat-content-user':message.role==='user', 'chat-content-assistant':message.role==='assistant' || message.role==='tool'}"
@click="handleChatContentClick($event, message)"
@longpress="handleLongPress(message)"
v-if="(message.content && String(message.content).trim() !== '') || message._streaming || (message.yxd_files && message.yxd_files.length > 0) || (message.role === 'tool' && message.yxd_tool_name === 'sendFrom')">
<!-- 流式加载中显示跳动的点 -->
<view
@@ -231,6 +280,17 @@
</view>
</view>
</template>
<!-- 操作栏复制转发仅非流式非用户上传文件 sendFrom 工具消息时显示 -->
<view v-if="!message._streaming && message.role !== 'tool'" class="message-actions" :class="{'message-actions-user': message.role === 'user'}">
<view class="message-action-item" @click.stop="copyMessage(message)">
<view class="iconfont icon-fuzhi1" color="#333"></view>
<text class="action-text">复制</text>
</view>
<view class="message-action-item" @click.stop="forwardMessage(message)">
<view class="iconfont icon-zhuanfa_3" color="#333"></view>
<text class="action-text">转发</text>
</view>
</view>
</view>
</view>
</template>
@@ -249,7 +309,8 @@
<view v-else class="iconfont icon-yonghuziliao"></view>
</view>
<view class="chat-content" :class="{'chat-content-user':message.sender === UserId}"
@click="handleChatContentClick($event, message)">
@click="handleChatContentClick($event, message)"
@longpress="handleLongPress(message)">
<view v-if="message.content && String(message.content).trim() !== ''"
v-html="pareseMarkdown(message.content)"></view>
<!-- 2. 图片 + 文件 渲染核心新增 -->
@@ -271,6 +332,17 @@
</view>
</view>
</view>
<!-- 好友消息操作栏 -->
<view v-if="message.content && String(message.content).trim() !== ''" class="message-actions" :class="{'message-actions-user': message.sender === UserId}">
<view class="message-action-item" @click.stop="copyMessage(message)">
<uni-icons type="copy" size="14" color="#333"></uni-icons>
<text class="action-text">复制</text>
</view>
<view class="message-action-item" @click.stop="forwardMessage(message)">
<uni-icons type="redo" size="14" color="#999"></uni-icons>
<text class="action-text">转发</text>
</view>
</view>
</view>
</view>
<!-- 与群聊的对话内容展示 -->
@@ -288,7 +360,8 @@
<view v-else class="iconfont icon-yonghuziliao"></view>
</view>
<view class="chat-content" :class="{'chat-content-user':message.sender === UserId}"
@click="handleChatContentClick($event, message)">
@click="handleChatContentClick($event, message)"
@longpress="handleLongPress(message)">
<view v-if="message.message && String(message.message).trim() !== ''"
v-html="pareseMarkdown(message.message)"></view>
<!-- 2. 图片 + 文件 渲染核心新增 -->
@@ -310,6 +383,17 @@
</view>
</view>
</view>
<!-- 群聊消息操作栏 -->
<view v-if="message.message && String(message.message).trim() !== ''" class="message-actions" :class="{'message-actions-user': message.sender === UserId}">
<view class="message-action-item" @click.stop="copyMessage({content: message.message})">
<uni-icons type="copy" size="14" color="#333"></uni-icons>
<text class="action-text">复制</text>
</view>
<view class="message-action-item" @click.stop="forwardMessage({content: message.message})">
<uni-icons type="redo" size="14" color="#999"></uni-icons>
<text class="action-text">转发</text>
</view>
</view>
</view>
</view>
<!-- 底部锚点两个交替切换确保流式时每次都能触发滚动到底部 -->
@@ -388,8 +472,8 @@
<script setup>
import {
computed,
getCurrentInstance,
computed,
nextTick,
onMounted,
reactive,
@@ -863,6 +947,131 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
agentList.value = []
}
// 复制消息内容
const copyMessage = (message) => {
// 提取纯文本内容用于复制
const textContent = parseFileInfo(message.content).textContent || message.content || ''
uni.setClipboardData({
data: textContent,
success: () => {
uni.showToast({ title: '已复制到剪贴板', icon: 'success' })
},
fail: () => {
uni.showToast({ title: '复制失败', icon: 'none' })
}
})
}
// 长按气泡处理 - 直接复制内容
const handleLongPress = (message) => {
// 流式消息不处理
// if (message._streaming) return
// // 适配不同消息格式
// let textContent = ''
// if (message.content && parseFileInfo(message.content).textContent) {
// // AI 对话格式(含文件信息)
// textContent = parseFileInfo(message.content).textContent
// } else if (message.content) {
// // 好友对话格式
// textContent = message.content
// } else if (message.message) {
// // 群聊对话格式
// textContent = message.message
// }
// if (!textContent || String(textContent).trim() === '') return
// uni.setClipboardData({
// data: textContent,
// success: () => {
// uni.showToast({ title: '已复制到剪贴板', icon: 'success' })
// },
// fail: () => {
// uni.showToast({ title: '复制失败', icon: 'none' })
// }
// })
}
// ===== 转发消息 =====
const showForwardPopup = ref(false)
const forwardTargetMessage = ref(null)
const forwardSelectedId = ref('')
// 可转发的会话列表(排除当前会话)
const forwardConversations = computed(() => {
return UserConversations.value.filter(c => c._id !== currentSessionId.value)
})
// 转发内容预览
const forwardPreview = computed(() => {
if (!forwardTargetMessage.value) return ''
const obj = parseFileInfo(forwardTargetMessage.value.content || '')
return obj.textContent || ''
})
// 打开转发弹窗
const forwardMessage = (message) => {
if (ChatType.value !== 0) {
uni.showToast({ title: '仅支持在 AI 会话中转发', icon: 'none', duration: 1500 })
return
}
forwardTargetMessage.value = message
forwardSelectedId.value = ''
// 确保会话列表已加载
if (forwardConversations.value.length === 0 && UserConversations.value.length <= 1) {
uni.showToast({ title: '暂无其他会话可转发', icon: 'none', duration: 1500 })
return
}
showForwardPopup.value = true
}
// 取消转发
const cancelForward = () => {
showForwardPopup.value = false
forwardTargetMessage.value = null
forwardSelectedId.value = ''
}
// 格式化会话显示名称
const getConvName = (conv) => {
// 优先智能体名称
if (conv.agent_data?.title) return conv.agent_data.title
// 其次 title排除文件信息格式
if (conv.title && !conv.title.startsWith('[文件信息')) return conv.title
// 最后用创建时间
if (conv.created_at) {
const t = conv.created_at
const pad = (n) => String(n).padStart(2, '0')
return `${t.year}${t.month}${t.day}${pad(t.hour)}:${pad(t.minute)}:${pad(t.second)}`
}
return '未命名会话'
}
// 确认转发
const confirmForward = async () => {
if (!forwardSelectedId.value || !forwardTargetMessage.value) {
uni.showToast({ title: '请选择目标会话', icon: 'none' })
return
}
try {
uni.showLoading({ title: '转发中...' })
const message = forwardTargetMessage.value
const textContent = parseFileInfo(message.content || '').textContent || message.content || ''
const forwardContent = `[转发消息] ${textContent}`
await addMessageDict(userToken.value, message.role || 'user', forwardSelectedId.value, forwardContent)
uni.hideLoading()
uni.showToast({ title: '转发成功', icon: 'success', duration: 1500 })
// 刷新会话列表以更新 preview
await takeUserConversations()
cancelForward()
} catch (error) {
uni.hideLoading()
console.error('转发失败:', error)
uni.showToast({ title: `转发失败: ${error}`, icon: 'none', duration: 2000 })
}
}
const handleAgentSelect = async (agent) => {
closeAgentModal()
uni.showLoading({ title: '正在创建智能体...', mask: true })
@@ -2517,4 +2726,193 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
color: #fff;
font-weight: 500;
}
/* ========== 转发消息弹窗 ========== */
.forward-modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.forward-modal {
width: 85%;
max-height: 72%;
background-color: #fff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12);
}
.forward-modal-header {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 28rpx 30rpx 20rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.forward-modal-title {
font-size: 34rpx;
font-weight: 700;
color: #1a1a2e;
}
.forward-modal-close {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
}
.forward-preview-box {
margin: 20rpx 30rpx 8rpx;
padding: 20rpx 24rpx;
background: #f7f8fc;
border-radius: 14rpx;
border-left: 6rpx solid #007aff;
flex-shrink: 0;
}
.forward-preview-label {
font-size: 24rpx;
color: #999;
display: block;
margin-bottom: 8rpx;
}
.forward-preview-text {
font-size: 28rpx;
color: #333;
word-break: break-all;
max-height: 160rpx;
overflow-y: auto;
line-height: 1.5;
}
.forward-select-label {
font-size: 26rpx;
color: #666;
padding: 12rpx 30rpx 8rpx;
display: block;
flex-shrink: 0;
}
.forward-conv-list {
flex: 1;
height: 0;
min-height: 500rpx;
padding: 0 20rpx;
box-sizing: border-box;
}
.forward-empty {
display: flex;
justify-content: center;
align-items: center;
height: 160rpx;
color: #999;
font-size: 26rpx;
}
.forward-conv-item {
display: flex;
align-items: center;
padding: 22rpx 16rpx;
border-radius: 16rpx;
margin-bottom: 8rpx;
background: #fafafa;
transition: background 0.2s;
}
.forward-conv-item:active {
background: #eef4ff;
}
.forward-conv-selected {
background: #e8f0fe;
border: 2rpx solid #007aff;
}
.forward-conv-avatar {
width: 60rpx;
height: 60rpx;
border-radius: 14rpx;
background: #e8f0fe;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
.forward-conv-info {
flex: 1;
min-width: 0;
}
.forward-conv-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.forward-conv-check {
flex-shrink: 0;
margin-left: 12rpx;
}
.forward-modal-footer {
padding: 20rpx 30rpx 30rpx;
border-top: 2rpx solid #f0f0f0;
display: flex;
justify-content: flex-end;
gap: 20rpx;
flex-shrink: 0;
}
.forward-modal-btn {
padding: 18rpx 48rpx;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
}
.forward-btn-cancel {
background: #f0f0f0;
color: #666;
}
.forward-btn-cancel:active {
background: #e0e0e0;
}
.forward-btn-confirm {
background: #007aff;
color: #fff;
}
.forward-btn-confirm:active {
background: #005fcc;
}
.forward-btn-disabled {
background: #b0d0f0;
color: #fff;
pointer-events: none;
}
</style>

View File

@@ -54,6 +54,18 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe6ea;</span>
<div class="name">转发</div>
<div class="code-name">&amp;#xe6ea;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe6fc;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe6fc;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe695;</span>
<div class="name">代码</div>
@@ -480,9 +492,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1783330740989') format('woff2'),
url('iconfont.woff?t=1783330740989') format('woff'),
url('iconfont.ttf?t=1783330740989') format('truetype');
src: url('iconfont.woff2?t=1786091687579') format('woff2'),
url('iconfont.woff?t=1786091687579') format('woff'),
url('iconfont.ttf?t=1786091687579') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -508,6 +520,24 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-zhuanfa_3"></span>
<div class="name">
转发
</div>
<div class="code-name">.icon-zhuanfa_3
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi1"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-daima"></span>
<div class="name">
@@ -1147,6 +1177,22 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zhuanfa_3"></use>
</svg>
<div class="name">转发</div>
<div class="code-name">#icon-zhuanfa_3</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi1"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-daima"></use>

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4890805 */
src: url('iconfont.woff2?t=1783330740989') format('woff2'),
url('iconfont.woff?t=1783330740989') format('woff'),
url('iconfont.ttf?t=1783330740989') format('truetype');
src: url('iconfont.woff2?t=1786091687579') format('woff2'),
url('iconfont.woff?t=1786091687579') format('woff'),
url('iconfont.ttf?t=1786091687579') format('truetype');
}
.iconfont {
@@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zhuanfa_3:before {
content: "\e6ea";
}
.icon-fuzhi1:before {
content: "\e6fc";
}
.icon-daima:before {
content: "\e695";
}

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "16322565",
"name": "转发",
"font_class": "zhuanfa_3",
"unicode": "e6ea",
"unicode_decimal": 59114
},
{
"icon_id": "16322894",
"name": "复制",
"font_class": "fuzhi1",
"unicode": "e6fc",
"unicode_decimal": 59132
},
{
"icon_id": "1767709",
"name": "代码",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2649,7 +2649,7 @@ if (uni.restoreGlobal) {
isSelectMode.value = false;
emit("refresh-conversations");
} catch (error) {
formatAppLog("error", "at components/ChatSidebar.vue:210", "删除会话失败:", error);
formatAppLog("error", "at components/ChatSidebar.vue:207", "删除会话失败:", error);
uni.showToast({
title: "删除失败,请重试",
icon: "none"
@@ -2678,7 +2678,7 @@ if (uni.restoreGlobal) {
uni.showToast({ title: "已删除全部对话", icon: "success" });
emit("refresh-conversations");
} catch (error) {
formatAppLog("error", "at components/ChatSidebar.vue:242", "清空全部对话失败:", error);
formatAppLog("error", "at components/ChatSidebar.vue:239", "清空全部对话失败:", error);
uni.showToast({ title: "删除失败,请重试", icon: "none" });
}
}
@@ -2690,7 +2690,7 @@ if (uni.restoreGlobal) {
});
const currentChatId = vue.toRef(props, "currentSessionId");
const selectChat = (chatId, receiverId = "") => {
formatAppLog("log", "at components/ChatSidebar.vue:260", "选择的id是", chatId);
formatAppLog("log", "at components/ChatSidebar.vue:257", "选择的id是", chatId);
if (receiverId) {
uni.setStorageSync("receiverId", receiverId);
}
@@ -2741,14 +2741,27 @@ if (uni.restoreGlobal) {
return "";
return text.length > maxLength ? text.substring(0, maxLength) + "..." : text;
};
const getConvName = (conv) => {
var _a;
if ((_a = conv.agent_data) == null ? void 0 : _a.title)
return conv.agent_data.title;
if (conv.title && !conv.title.startsWith("[文件信息"))
return conv.title;
if (conv.created_at) {
const t2 = conv.created_at;
const pad = (n2) => String(n2).padStart(2, "0");
return `${t2.year}${t2.month}${t2.day}${pad(t2.hour)}:${pad(t2.minute)}:${pad(t2.second)}`;
}
return "未命名会话";
};
vue.onMounted(async () => {
UserToken.value = getToken();
const UserInfo = await getUserInfo(UserToken.value);
UserAvatar.value = UserInfo.avatar || "";
UserName.value = UserInfo.username || "";
formatAppLog("log", "at components/ChatSidebar.vue:333", "菜单收到的会话列表:", UserConversations.value);
formatAppLog("log", "at components/ChatSidebar.vue:342", "菜单收到的会话列表:", UserConversations.value);
});
const __returned__ = { props, emit, UserConversations, showNewChatModal, chatType, openUserCardVisible, isSelectMode, selectedHistoryIds, deleteConversations, clearAllConversations, isAllHistorySelected, currentChatId, selectChat, openNewChatModal, goContactPages, chatHistoryQuery, isHistorySearchFocused, toggleSelectMode, toggleHistorySelect, toggleSelectAllHistory, UserToken, UserAvatar, UserName, truncateText, computed: vue.computed, onMounted: vue.onMounted, onUnmounted: vue.onUnmounted, ref: vue.ref, toRef: vue.toRef, get deleteConversation() {
const __returned__ = { props, emit, UserConversations, showNewChatModal, chatType, openUserCardVisible, isSelectMode, selectedHistoryIds, deleteConversations, clearAllConversations, isAllHistorySelected, currentChatId, selectChat, openNewChatModal, goContactPages, chatHistoryQuery, isHistorySearchFocused, toggleSelectMode, toggleHistorySelect, toggleSelectAllHistory, UserToken, UserAvatar, UserName, truncateText, getConvName, computed: vue.computed, onMounted: vue.onMounted, onUnmounted: vue.onUnmounted, ref: vue.ref, toRef: vue.toRef, get deleteConversation() {
return deleteConversation;
}, get getToken() {
return getToken;
@@ -2902,7 +2915,6 @@ if (uni.restoreGlobal) {
vue.Fragment,
{ key: 0 },
vue.renderList($setup.UserConversations, (chat) => {
var _a;
return vue.openBlock(), vue.createElementBlock("view", {
key: chat._id,
"data-chat-id": chat._id,
@@ -2927,19 +2939,13 @@ if (uni.restoreGlobal) {
color: "#007aff"
})
]),
chat.agent_id ? (vue.openBlock(), vue.createElementBlock(
vue.createElementVNode(
"view",
{ key: 1 },
vue.toDisplayString($setup.truncateText((_a = chat.agent_data) == null ? void 0 : _a.title) || "加载中"),
null,
vue.toDisplayString($setup.truncateText($setup.getConvName(chat))),
1
/* TEXT */
)) : (vue.openBlock(), vue.createElementBlock(
"view",
{ key: 2 },
vue.toDisplayString($setup.truncateText(chat.title)),
1
/* TEXT */
))
)
], 10, ["data-chat-id", "onClick"]);
}),
128
@@ -5811,7 +5817,7 @@ This will fail in production.`);
if (friendSocketStore.isConnected)
return;
if (!userToken.value || !UserId.value) {
formatAppLog("warn", "at pages/Chat/Chat.vue:453", "Token或UserId未准备好");
formatAppLog("warn", "at pages/Chat/Chat.vue:537", "Token或UserId未准备好");
return;
}
friendSocketStore.connect({
@@ -6008,7 +6014,7 @@ This will fail in production.`);
});
return html;
} catch (e2) {
formatAppLog("error", "at pages/Chat/Chat.vue:661", "解析失败", e2);
formatAppLog("error", "at pages/Chat/Chat.vue:745", "解析失败", e2);
return content;
}
};
@@ -6059,7 +6065,7 @@ This will fail in production.`);
files
};
} catch (e2) {
formatAppLog("error", "at pages/Chat/Chat.vue:730", "解析文件信息失败:", e2);
formatAppLog("error", "at pages/Chat/Chat.vue:814", "解析文件信息失败:", e2);
return {
textContent: content,
files: []
@@ -6103,7 +6109,7 @@ This will fail in production.`);
return;
}
values._submitted = true;
formatAppLog("log", "at pages/Chat/Chat.vue:777", "表单提交:", formData.formId, { ...values, _submitted: void 0 });
formatAppLog("log", "at pages/Chat/Chat.vue:861", "表单提交:", formData.formId, { ...values, _submitted: void 0 });
uni.showToast({ title: "提交成功", icon: "success" });
};
const selectNormalChat = async () => {
@@ -6139,7 +6145,7 @@ This will fail in production.`);
currentSessionId.value = conversationId;
uni.setStorageSync("currentSessionId", conversationId);
} catch (error) {
formatAppLog("error", "at pages/Chat/Chat.vue:822", "新建普通会话失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:906", "新建普通会话失败:", error);
uni.showToast({
title: "创建会话失败,请重试",
icon: "none"
@@ -6166,7 +6172,7 @@ This will fail in production.`);
uni.showToast({ title: "获取智能体列表失败", icon: "none" });
}
} catch (error) {
formatAppLog("error", "at pages/Chat/Chat.vue:854", "获取智能体列表失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:938", "获取智能体列表失败:", error);
uni.showToast({ title: "获取智能体列表失败,请重试", icon: "none" });
} finally {
agentLoading.value = false;
@@ -6176,6 +6182,84 @@ This will fail in production.`);
showAgentModal.value = false;
agentList.value = [];
};
const copyMessage = (message) => {
const textContent = parseFileInfo(message.content).textContent || message.content || "";
uni.setClipboardData({
data: textContent,
success: () => {
uni.showToast({ title: "已复制到剪贴板", icon: "success" });
},
fail: () => {
uni.showToast({ title: "复制失败", icon: "none" });
}
});
};
const handleLongPress = (message) => {
};
const showForwardPopup = vue.ref(false);
const forwardTargetMessage = vue.ref(null);
const forwardSelectedId = vue.ref("");
const forwardConversations = vue.computed(() => {
return UserConversations.value.filter((c) => c._id !== currentSessionId.value);
});
const forwardPreview = vue.computed(() => {
if (!forwardTargetMessage.value)
return "";
const obj = parseFileInfo(forwardTargetMessage.value.content || "");
return obj.textContent || "";
});
const forwardMessage = (message) => {
if (ChatType.value !== 0) {
uni.showToast({ title: "仅支持在 AI 会话中转发", icon: "none", duration: 1500 });
return;
}
forwardTargetMessage.value = message;
forwardSelectedId.value = "";
if (forwardConversations.value.length === 0 && UserConversations.value.length <= 1) {
uni.showToast({ title: "暂无其他会话可转发", icon: "none", duration: 1500 });
return;
}
showForwardPopup.value = true;
};
const cancelForward = () => {
showForwardPopup.value = false;
forwardTargetMessage.value = null;
forwardSelectedId.value = "";
};
const getConvName = (conv) => {
var _a;
if ((_a = conv.agent_data) == null ? void 0 : _a.title)
return conv.agent_data.title;
if (conv.title && !conv.title.startsWith("[文件信息"))
return conv.title;
if (conv.created_at) {
const t2 = conv.created_at;
const pad = (n2) => String(n2).padStart(2, "0");
return `${t2.year}${t2.month}${t2.day}${pad(t2.hour)}:${pad(t2.minute)}:${pad(t2.second)}`;
}
return "未命名会话";
};
const confirmForward = async () => {
if (!forwardSelectedId.value || !forwardTargetMessage.value) {
uni.showToast({ title: "请选择目标会话", icon: "none" });
return;
}
try {
uni.showLoading({ title: "转发中..." });
const message = forwardTargetMessage.value;
const textContent = parseFileInfo(message.content || "").textContent || message.content || "";
const forwardContent = `[转发消息] ${textContent}`;
await addMessageDict(userToken.value, message.role || "user", forwardSelectedId.value, forwardContent);
uni.hideLoading();
uni.showToast({ title: "转发成功", icon: "success", duration: 1500 });
await takeUserConversations();
cancelForward();
} catch (error) {
uni.hideLoading();
formatAppLog("error", "at pages/Chat/Chat.vue:1070", "转发失败:", error);
uni.showToast({ title: `转发失败: ${error}`, icon: "none", duration: 2e3 });
}
};
const handleAgentSelect = async (agent) => {
closeAgentModal();
uni.showLoading({ title: "正在创建智能体...", mask: true });
@@ -6193,7 +6277,7 @@ This will fail in production.`);
uni.showToast({ title: `已创建「${result.title || agent.title}」会话`, icon: "success" });
} catch (error) {
uni.hideLoading();
formatAppLog("error", "at pages/Chat/Chat.vue:885", "创建智能体会话失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:1094", "创建智能体会话失败:", error);
uni.showToast({ title: typeof error === "string" ? error : "创建失败,请重试", icon: "none" });
}
};
@@ -6282,7 +6366,7 @@ This will fail in production.`);
};
const previewFileArray = vue.ref([]);
const uploadPhoto = () => {
formatAppLog("log", "at pages/Chat/Chat.vue:1002", "点击了拍照上传");
formatAppLog("log", "at pages/Chat/Chat.vue:1211", "点击了拍照上传");
uni.chooseImage({
count: 1,
sourceType: ["camera", "album"],
@@ -6305,7 +6389,7 @@ This will fail in production.`);
});
},
fail: (err) => {
formatAppLog("error", "at pages/Chat/Chat.vue:1020", "选择图片失败", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1229", "选择图片失败", err);
}
});
};
@@ -6314,12 +6398,12 @@ This will fail in production.`);
};
const fileList = vue.ref([]);
const uploadFile = () => {
formatAppLog("log", "at pages/Chat/Chat.vue:1031", "点击了上传文件");
formatAppLog("log", "at pages/Chat/Chat.vue:1240", "点击了上传文件");
chooseFile({
count: 5,
type: "all",
success: (res) => {
formatAppLog("log", "at pages/Chat/Chat.vue:1036", "成功了");
formatAppLog("log", "at pages/Chat/Chat.vue:1245", "成功了");
fileList.value = res.tempFiles;
previewFileArray.value.push(...res.tempFiles);
uni.showToast({
@@ -6328,7 +6412,7 @@ This will fail in production.`);
});
},
fail: (err) => {
formatAppLog("error", "at pages/Chat/Chat.vue:1047", "选择失败:", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1256", "选择失败:", err);
uni.showToast({
title: "选择失败",
icon: "error"
@@ -6567,7 +6651,7 @@ This will fail in production.`);
previewFileArray.value = [];
} catch (err) {
uni.hideLoading();
formatAppLog("error", "at pages/Chat/Chat.vue:1322", "文件上传失败:", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1531", "文件上传失败:", err);
uni.showToast({
title: "文件上传失败,请重试",
icon: "error"
@@ -6701,15 +6785,15 @@ This will fail in production.`);
}
};
const stopConversation = async () => {
formatAppLog("log", "at pages/Chat/Chat.vue:1492", "中断对话 - 当前会话ID:", currentSessionId.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1701", "中断对话 - 当前会话ID:", currentSessionId.value);
try {
await socketStore.send({
type: "stop",
conversation_id: currentSessionId.value
});
formatAppLog("log", "at pages/Chat/Chat.vue:1498", "中断指令已发送成功");
formatAppLog("log", "at pages/Chat/Chat.vue:1707", "中断指令已发送成功");
} catch (err) {
formatAppLog("error", "at pages/Chat/Chat.vue:1500", "中断指令发送失败:", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1709", "中断指令发送失败:", err);
}
if (streamingMessageId.value) {
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
@@ -6728,9 +6812,9 @@ This will fail in production.`);
});
};
vue.watch(() => socketStore.isThinking, async (newVal, oldVal) => {
formatAppLog("log", "at pages/Chat/Chat.vue:1525", "isThinking 变化:", oldVal, "→", newVal, "messageString:", socketStore.messageString);
formatAppLog("log", "at pages/Chat/Chat.vue:1734", "isThinking 变化:", oldVal, "→", newVal, "messageString:", socketStore.messageString);
if (!oldVal && newVal) {
formatAppLog("log", "at pages/Chat/Chat.vue:1528", "AI开始回复跨设备同步锁定输入框");
formatAppLog("log", "at pages/Chat/Chat.vue:1737", "AI开始回复跨设备同步锁定输入框");
isThinking.value = true;
if (!isSelfSent.value) {
await takeConversationMessages();
@@ -6747,7 +6831,7 @@ This will fail in production.`);
return;
}
if (oldVal && !newVal) {
formatAppLog("log", "at pages/Chat/Chat.vue:1547", "AI回复结束正常/中断),解锁并刷新消息列表");
formatAppLog("log", "at pages/Chat/Chat.vue:1756", "AI回复结束正常/中断),解锁并刷新消息列表");
await takeConversationMessages();
if (streamingMessageId.value) {
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
@@ -6818,15 +6902,15 @@ This will fail in production.`);
UserData.value = await getUserInfo(userToken.value);
UserId.value = UserData.value._id;
UserAvatar.value = UserData.value.avatar || "";
formatAppLog("log", "at pages/Chat/Chat.vue:1634", "用户信息已加载:", UserId.value, UserAvatar.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1843", "用户信息已加载:", UserId.value, UserAvatar.value);
} catch (error) {
formatAppLog("error", "at pages/Chat/Chat.vue:1636", "获取用户信息失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:1845", "获取用户信息失败:", error);
}
};
const takeUserConversations = async () => {
try {
userToken.value = getToken();
formatAppLog("log", "at pages/Chat/Chat.vue:1644", "token:", userToken.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1853", "token:", userToken.value);
UserConversations.value = await getUserConversations(userToken.value) || [];
const savedSessionId = getCurrentSessionId();
if (savedSessionId && UserConversations.value.some((c) => c._id === savedSessionId)) {
@@ -6836,7 +6920,7 @@ This will fail in production.`);
} else {
currentSessionId.value = "";
}
formatAppLog("log", "at pages/Chat/Chat.vue:1656", "保存会话id", currentSessionId.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1865", "保存会话id", currentSessionId.value);
uni.setStorageSync("currentSessionId", currentSessionId.value);
} catch (error) {
uni.showToast({
@@ -6848,17 +6932,17 @@ This will fail in production.`);
const FriendInfoList = vue.ref([]);
const takeFriendList = async () => {
try {
formatAppLog("log", "at pages/Chat/Chat.vue:1671", "开始获取好友列表");
formatAppLog("log", "at pages/Chat/Chat.vue:1880", "开始获取好友列表");
const friendList = await getChatFriend(UserId.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1674", "friendList:", friendList);
formatAppLog("log", "at pages/Chat/Chat.vue:1883", "friendList:", friendList);
if (friendList && friendList.length) {
FriendInfoList.value = await takeUserAvatar(friendList);
} else {
FriendInfoList.value = [];
formatAppLog("log", "at pages/Chat/Chat.vue:1679", "好友列表为空");
formatAppLog("log", "at pages/Chat/Chat.vue:1888", "好友列表为空");
}
} catch (error) {
formatAppLog("error", "at pages/Chat/Chat.vue:1682", "获取好友列表失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:1891", "获取好友列表失败:", error);
FriendInfoList.value = [];
} finally {
UserConversations.value = FriendInfoList.value;
@@ -6885,17 +6969,17 @@ This will fail in production.`);
};
});
} catch (err) {
formatAppLog("error", "at pages/Chat/Chat.vue:1712", "获取好友头像失败", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1921", "获取好友头像失败", err);
return friendList;
}
};
const GroupList = vue.ref([]);
const takeGroupList = async () => {
try {
formatAppLog("log", "at pages/Chat/Chat.vue:1722", "开始获取群聊列表");
formatAppLog("log", "at pages/Chat/Chat.vue:1931", "开始获取群聊列表");
GroupList.value = await getGroup(UserId.value);
} catch (error) {
formatAppLog("error", "at pages/Chat/Chat.vue:1727", "获取群聊列表失败:", error);
formatAppLog("error", "at pages/Chat/Chat.vue:1936", "获取群聊列表失败:", error);
GroupList.value = [];
} finally {
UserConversations.value = GroupList.value;
@@ -6907,22 +6991,22 @@ This will fail in production.`);
return [];
try {
const memberIds = memberList.map((item) => item.groupContactId);
formatAppLog("log", "at pages/Chat/Chat.vue:1741", "请求头像的ID列表:", memberIds);
formatAppLog("log", "at pages/Chat/Chat.vue:1950", "请求头像的ID列表:", memberIds);
const memberAvatarList = await getUserAvatar(userToken.value, memberIds);
formatAppLog("log", "at pages/Chat/Chat.vue:1743", "头像接口返回数据:", memberAvatarList);
formatAppLog("log", "at pages/Chat/Chat.vue:1952", "头像接口返回数据:", memberAvatarList);
const userMap = new Map(memberAvatarList.map((user) => [user.user_id, user]) || []);
formatAppLog("log", "at pages/Chat/Chat.vue:1746", "userMap的keys:", Array.from(userMap.keys()));
formatAppLog("log", "at pages/Chat/Chat.vue:1955", "userMap的keys:", Array.from(userMap.keys()));
return memberList.map((member) => {
const memberId = member.groupContactId;
const userInfo = userMap.get(memberId);
formatAppLog("log", "at pages/Chat/Chat.vue:1751", `查找 ${memberId} 的头像:`, userInfo);
formatAppLog("log", "at pages/Chat/Chat.vue:1960", `查找 ${memberId} 的头像:`, userInfo);
return {
...member,
avatar: (userInfo == null ? void 0 : userInfo.avatar) || null
};
});
} catch (err) {
formatAppLog("error", "at pages/Chat/Chat.vue:1758", "获取群成员头像失败", err);
formatAppLog("error", "at pages/Chat/Chat.vue:1967", "获取群成员头像失败", err);
return memberList;
}
};
@@ -6989,12 +7073,12 @@ This will fail in production.`);
hasMoreGroupMessages.value = true;
const rawMessages = await getGroupMessages(currentSessionId.value, pageSize$1, 0) || [];
allmessages.value = rawMessages;
formatAppLog("log", "at pages/Chat/Chat.vue:1850", "群聊消息:", allmessages.value);
formatAppLog("log", "at pages/Chat/Chat.vue:2059", "群聊消息:", allmessages.value);
const memberList = await getGroupMemberList(currentSessionId.value);
formatAppLog("log", "at pages/Chat/Chat.vue:1853", "获取到的群成员列表:", memberList);
formatAppLog("log", "at pages/Chat/Chat.vue:2062", "获取到的群成员列表:", memberList);
if (memberList && memberList.length) {
groupMemberList.value = await takeGroupMemberAvatar(memberList);
formatAppLog("log", "at pages/Chat/Chat.vue:1856", "群成员列表(带头像):", groupMemberList.value);
formatAppLog("log", "at pages/Chat/Chat.vue:2065", "群成员列表(带头像):", groupMemberList.value);
} else {
groupMemberList.value = [];
}
@@ -7036,7 +7120,7 @@ This will fail in production.`);
hasMoreAIMessages.value = false;
}
} catch (e2) {
formatAppLog("error", "at pages/Chat/Chat.vue:1921", "加载更多消息失败:", e2);
formatAppLog("error", "at pages/Chat/Chat.vue:2130", "加载更多消息失败:", e2);
uni.showToast({ title: "加载更多失败", icon: "none" });
} finally {
isAILoadingMore.value = false;
@@ -7061,7 +7145,7 @@ This will fail in production.`);
hasMoreFriendMessages.value = false;
}
} catch (e2) {
formatAppLog("error", "at pages/Chat/Chat.vue:1949", "加载更多好友消息失败:", e2);
formatAppLog("error", "at pages/Chat/Chat.vue:2158", "加载更多好友消息失败:", e2);
uni.showToast({ title: "加载更多失败", icon: "none" });
} finally {
isFriendLoadingMore.value = false;
@@ -7086,7 +7170,7 @@ This will fail in production.`);
hasMoreGroupMessages.value = false;
}
} catch (e2) {
formatAppLog("error", "at pages/Chat/Chat.vue:1977", "加载更多群聊消息失败:", e2);
formatAppLog("error", "at pages/Chat/Chat.vue:2186", "加载更多群聊消息失败:", e2);
uni.showToast({ title: "加载更多失败", icon: "none" });
} finally {
isGroupLoadingMore.value = false;
@@ -7102,9 +7186,9 @@ This will fail in production.`);
}
};
vue.watch(() => friendSocketStore.MessageReceived, (newId) => {
formatAppLog("log", "at pages/Chat/Chat.vue:1998", "收到了好友消息");
formatAppLog("log", "at pages/Chat/Chat.vue:2207", "收到了好友消息");
if (newId) {
formatAppLog("log", "at pages/Chat/Chat.vue:2000", "ChatType:", ChatType.value);
formatAppLog("log", "at pages/Chat/Chat.vue:2209", "ChatType:", ChatType.value);
switch (ChatType.value) {
case 0:
takeConversationMessages();
@@ -7119,7 +7203,7 @@ This will fail in production.`);
friendSocketStore.MessageReceived = false;
break;
default:
formatAppLog("log", "at pages/Chat/Chat.vue:2016", "default 分支");
formatAppLog("log", "at pages/Chat/Chat.vue:2225", "default 分支");
friendSocketStore.MessageReceived = false;
break;
}
@@ -7209,11 +7293,11 @@ This will fail in production.`);
onUnload(() => {
socketStore.disconnect();
});
const __returned__ = { friendSocketStore, handleFriendConnect, socketStore, ChatType, wyxdWorkspaceId, wyxdFilePath, wyxdFileName, wyxdUserToken, hasWyxdFile, convertMarkdownTable, renderTable, escapeLoneUnderscores, isDownloadLink, renderDownloadBtn, supportedExtensions, extPattern, pareseMarkdown, sanitizeContent, previewImage, openFile: openFile$1, formatFileSize: formatFileSize2, parseFileInfo, getToolFormData, ensureToolForm, submitToolForm, selectNormalChat, showNewChatModal, closeNewChatModal, showAgentModal, agentList, agentLoading, selectAgentChat, closeAgentModal, handleAgentSelect, isChatSidebar, handleChatSidebar, goWorkSpace, goWyxdViewer, goCloudDatabase, logOut, handleRefresh, previewFileArray, uploadPhoto, deleteImage, fileList, uploadFile, handleConnect, isThinking, isSelfSent, isUploading, isLoadingMessages, uploadedFiles, streamingMessageId, showMessageModal, detailLinks, handleChatContentClick, extractLinks, extractFileNameFromUrl, getFileTypeInfo, showMessageDetail, closeMessageDetail, downloadToast, get downloadToastTimer() {
const __returned__ = { friendSocketStore, handleFriendConnect, socketStore, ChatType, wyxdWorkspaceId, wyxdFilePath, wyxdFileName, wyxdUserToken, hasWyxdFile, convertMarkdownTable, renderTable, escapeLoneUnderscores, isDownloadLink, renderDownloadBtn, supportedExtensions, extPattern, pareseMarkdown, sanitizeContent, previewImage, openFile: openFile$1, formatFileSize: formatFileSize2, parseFileInfo, getToolFormData, ensureToolForm, submitToolForm, selectNormalChat, showNewChatModal, closeNewChatModal, showAgentModal, agentList, agentLoading, selectAgentChat, closeAgentModal, copyMessage, handleLongPress, showForwardPopup, forwardTargetMessage, forwardSelectedId, forwardConversations, forwardPreview, forwardMessage, cancelForward, getConvName, confirmForward, handleAgentSelect, isChatSidebar, handleChatSidebar, goWorkSpace, goWyxdViewer, goCloudDatabase, logOut, handleRefresh, previewFileArray, uploadPhoto, deleteImage, fileList, uploadFile, handleConnect, isThinking, isSelfSent, isUploading, isLoadingMessages, uploadedFiles, streamingMessageId, showMessageModal, detailLinks, handleChatContentClick, extractLinks, extractFileNameFromUrl, getFileTypeInfo, showMessageDetail, closeMessageDetail, downloadToast, get downloadToastTimer() {
return downloadToastTimer;
}, set downloadToastTimer(v) {
downloadToastTimer = v;
}, showDownloadToast, hideDownloadToast, openLink, downloadAndHandle, sendMessage, sendFriendMessage, sendGroupMessage, sendAIMessage, stopConversation, textMessage, UserConversations, currentSessionId, userToken, UserId, UserAvatar, UserData, takeUserInfo, takeUserConversations, FriendInfoList, takeFriendList, takeTalkUserAvatar, takeUserAvatar, GroupList, takeGroupList, groupMemberList, takeGroupMemberAvatar, getGroupMemberAvatarById, allmessages, scrollToView, bottomToggle, scrollAnimationEnabled, toolFormValues, isLoadingMore, isAILoadingMore, aiPageNumber, hasMoreAIMessages, currentPage, pageSize: pageSize$1, isFriendLoadingMore, friendPageNumber, hasMoreFriendMessages, isGroupLoadingMore, groupPageNumber, hasMoreGroupMessages, groupSize, currentMessages, takeConversationMessages, takeFriendMessages, takeGroupMessages, onScrollToUpper, loadMoreAIMessages, loadMoreFriendMessages, loadMoreGroupMessages, onScroll, scrollToBottom, computed: vue.computed, getCurrentInstance: vue.getCurrentInstance, nextTick: vue.nextTick, onMounted: vue.onMounted, reactive: vue.reactive, ref: vue.ref, watch: vue.watch, get onLoad() {
}, showDownloadToast, hideDownloadToast, openLink, downloadAndHandle, sendMessage, sendFriendMessage, sendGroupMessage, sendAIMessage, stopConversation, textMessage, UserConversations, currentSessionId, userToken, UserId, UserAvatar, UserData, takeUserInfo, takeUserConversations, FriendInfoList, takeFriendList, takeTalkUserAvatar, takeUserAvatar, GroupList, takeGroupList, groupMemberList, takeGroupMemberAvatar, getGroupMemberAvatarById, allmessages, scrollToView, bottomToggle, scrollAnimationEnabled, toolFormValues, isLoadingMore, isAILoadingMore, aiPageNumber, hasMoreAIMessages, currentPage, pageSize: pageSize$1, isFriendLoadingMore, friendPageNumber, hasMoreFriendMessages, isGroupLoadingMore, groupPageNumber, hasMoreGroupMessages, groupSize, currentMessages, takeConversationMessages, takeFriendMessages, takeGroupMessages, onScrollToUpper, loadMoreAIMessages, loadMoreFriendMessages, loadMoreGroupMessages, onScroll, scrollToBottom, getCurrentInstance: vue.getCurrentInstance, computed: vue.computed, nextTick: vue.nextTick, onMounted: vue.onMounted, reactive: vue.reactive, ref: vue.ref, watch: vue.watch, get onLoad() {
return onLoad;
}, get onShow() {
return onShow;
@@ -7446,6 +7530,102 @@ This will fail in production.`);
])
])
])) : vue.createCommentVNode("v-if", true),
$setup.showForwardPopup ? (vue.openBlock(), vue.createElementBlock("view", {
key: 2,
class: "forward-modal-mask",
onClick: $setup.cancelForward
}, [
vue.createElementVNode("view", {
class: "forward-modal",
onClick: _cache[2] || (_cache[2] = vue.withModifiers(() => {
}, ["stop"]))
}, [
vue.createElementVNode("view", { class: "forward-modal-header" }, [
vue.createElementVNode("text", { class: "forward-modal-title" }, "转发消息"),
vue.createElementVNode("view", {
class: "forward-modal-close",
onClick: $setup.cancelForward
}, [
vue.createVNode(_component_uni_icons, {
type: "closeempty",
size: "20",
color: "#999"
})
])
]),
vue.createElementVNode("text", { class: "forward-select-label" }, "选择目标会话"),
vue.createElementVNode("scroll-view", {
class: "forward-conv-list",
"scroll-y": "true"
}, [
$setup.forwardConversations.length === 0 ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
class: "forward-empty"
}, [
vue.createElementVNode("text", null, "暂无其他会话")
])) : (vue.openBlock(true), vue.createElementBlock(
vue.Fragment,
{ key: 1 },
vue.renderList($setup.forwardConversations, (conv) => {
return vue.openBlock(), vue.createElementBlock("view", {
key: conv._id,
class: vue.normalizeClass(["forward-conv-item", { "forward-conv-selected": $setup.forwardSelectedId === conv._id }]),
onClick: ($event) => $setup.forwardSelectedId = conv._id
}, [
vue.createElementVNode("view", { class: "forward-conv-avatar" }, [
vue.createVNode(_component_uni_icons, {
type: "chat-filled",
size: "24",
color: "#007aff"
})
]),
vue.createElementVNode("view", { class: "forward-conv-info" }, [
vue.createElementVNode(
"text",
{ class: "forward-conv-name" },
vue.toDisplayString($setup.getConvName(conv)),
1
/* TEXT */
)
]),
$setup.forwardSelectedId === conv._id ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
class: "forward-conv-check"
}, [
vue.createVNode(_component_uni_icons, {
type: "checkmarkempty",
size: "20",
color: "#007aff"
})
])) : vue.createCommentVNode("v-if", true)
], 10, ["onClick"]);
}),
128
/* KEYED_FRAGMENT */
))
]),
vue.createElementVNode("view", { class: "forward-modal-footer" }, [
vue.createElementVNode("view", {
class: "forward-modal-btn forward-btn-cancel",
onClick: $setup.cancelForward
}, [
vue.createElementVNode("text", null, "取消")
]),
vue.createElementVNode(
"view",
{
class: vue.normalizeClass(["forward-modal-btn forward-btn-confirm", { "forward-btn-disabled": !$setup.forwardSelectedId }]),
onClick: $setup.confirmForward
},
[
vue.createElementVNode("text", null, "确认转发")
],
2
/* CLASS */
)
])
])
])) : vue.createCommentVNode("v-if", true),
vue.createElementVNode("view", { class: "chat-page page-container" }, [
$setup.isChatSidebar ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
@@ -7461,13 +7641,13 @@ This will fail in production.`);
vue.createVNode($setup["ChatSidebar"], {
chatList: $setup.UserConversations,
showNewChatModal: $setup.showNewChatModal,
"onUpdate:showNewChatModal": _cache[2] || (_cache[2] = ($event) => $setup.showNewChatModal = $event),
"onUpdate:showNewChatModal": _cache[3] || (_cache[3] = ($event) => $setup.showNewChatModal = $event),
currentSessionId: $setup.currentSessionId,
"onUpdate:currentSessionId": _cache[3] || (_cache[3] = ($event) => $setup.currentSessionId = $event),
"onUpdate:currentSessionId": _cache[4] || (_cache[4] = ($event) => $setup.currentSessionId = $event),
chatType: $setup.ChatType,
"onUpdate:chatType": _cache[4] || (_cache[4] = ($event) => $setup.ChatType = $event),
"onUpdate:chatType": _cache[5] || (_cache[5] = ($event) => $setup.ChatType = $event),
onRefreshConversations: $setup.takeUserConversations,
onSelectChat: _cache[5] || (_cache[5] = ($event) => $setup.isChatSidebar = false)
onSelectChat: _cache[6] || (_cache[6] = ($event) => $setup.isChatSidebar = false)
}, null, 8, ["chatList", "showNewChatModal", "currentSessionId", "chatType"])
],
2
@@ -7533,7 +7713,7 @@ This will fail in production.`);
}, ""),
vue.createElementVNode("view", {
class: "wyxd-banner-close",
onClick: _cache[6] || (_cache[6] = vue.withModifiers(($event) => $setup.hasWyxdFile = false, ["stop"]))
onClick: _cache[7] || (_cache[7] = vue.withModifiers(($event) => $setup.hasWyxdFile = false, ["stop"]))
}, "×")
])) : vue.createCommentVNode("v-if", true),
vue.createElementVNode("view", { class: "main-chat" }, [
@@ -7603,7 +7783,8 @@ This will fail in production.`);
message.content && String(message.content).trim() !== "" || message._streaming || message.yxd_files && message.yxd_files.length > 0 || message.role === "tool" && message.yxd_tool_name === "sendFrom" ? (vue.openBlock(), vue.createElementBlock("view", {
key: 1,
class: vue.normalizeClass(["chat-content", { "chat-content-user": message.role === "user", "chat-content-assistant": message.role === "assistant" || message.role === "tool" }]),
onClick: ($event) => $setup.handleChatContentClick($event, message)
onClick: ($event) => $setup.handleChatContentClick($event, message),
onLongpress: ($event) => $setup.handleLongPress(message)
}, [
message._streaming && (!message.content || String(message.content).trim() === "") ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
@@ -7802,8 +7983,39 @@ This will fail in production.`);
],
64
/* STABLE_FRAGMENT */
)) : vue.createCommentVNode("v-if", true),
!message._streaming && message.role !== "tool" ? (vue.openBlock(), vue.createElementBlock(
"view",
{
key: 5,
class: vue.normalizeClass(["message-actions", { "message-actions-user": message.role === "user" }])
},
[
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.copyMessage(message), ["stop"])
}, [
vue.createElementVNode("view", {
class: "iconfont icon-fuzhi1",
color: "#333"
}),
vue.createElementVNode("text", { class: "action-text" }, "复制")
], 8, ["onClick"]),
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.forwardMessage(message), ["stop"])
}, [
vue.createElementVNode("view", {
class: "iconfont icon-zhuanfa_3",
color: "#333"
}),
vue.createElementVNode("text", { class: "action-text" }, "转发")
], 8, ["onClick"])
],
2
/* CLASS */
)) : vue.createCommentVNode("v-if", true)
], 10, ["onClick"])) : vue.createCommentVNode("v-if", true)
], 42, ["onClick", "onLongpress"])) : vue.createCommentVNode("v-if", true)
], 10, ["id"])) : vue.createCommentVNode("v-if", true)
],
64
@@ -7849,7 +8061,8 @@ This will fail in production.`);
),
vue.createElementVNode("view", {
class: vue.normalizeClass(["chat-content", { "chat-content-user": message.sender === $setup.UserId }]),
onClick: ($event) => $setup.handleChatContentClick($event, message)
onClick: ($event) => $setup.handleChatContentClick($event, message),
onLongpress: ($event) => $setup.handleLongPress(message)
}, [
message.content && String(message.content).trim() !== "" ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
@@ -7899,8 +8112,41 @@ This will fail in production.`);
128
/* KEYED_FRAGMENT */
))
])) : vue.createCommentVNode("v-if", true)
], 10, ["onClick"])
])) : vue.createCommentVNode("v-if", true),
message.content && String(message.content).trim() !== "" ? (vue.openBlock(), vue.createElementBlock(
"view",
{
key: 2,
class: vue.normalizeClass(["message-actions", { "message-actions-user": message.sender === $setup.UserId }])
},
[
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.copyMessage(message), ["stop"])
}, [
vue.createVNode(_component_uni_icons, {
type: "copy",
size: "14",
color: "#333"
}),
vue.createElementVNode("text", { class: "action-text" }, "复制")
], 8, ["onClick"]),
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.forwardMessage(message), ["stop"])
}, [
vue.createVNode(_component_uni_icons, {
type: "redo",
size: "14",
color: "#999"
}),
vue.createElementVNode("text", { class: "action-text" }, "转发")
], 8, ["onClick"])
],
2
/* CLASS */
)) : vue.createCommentVNode("v-if", true)
], 42, ["onClick", "onLongpress"])
], 10, ["id"]);
}),
128
@@ -7942,7 +8188,8 @@ This will fail in production.`);
),
vue.createElementVNode("view", {
class: vue.normalizeClass(["chat-content", { "chat-content-user": message.sender === $setup.UserId }]),
onClick: ($event) => $setup.handleChatContentClick($event, message)
onClick: ($event) => $setup.handleChatContentClick($event, message),
onLongpress: ($event) => $setup.handleLongPress(message)
}, [
message.message && String(message.message).trim() !== "" ? (vue.openBlock(), vue.createElementBlock("view", {
key: 0,
@@ -7992,8 +8239,41 @@ This will fail in production.`);
128
/* KEYED_FRAGMENT */
))
])) : vue.createCommentVNode("v-if", true)
], 10, ["onClick"])
])) : vue.createCommentVNode("v-if", true),
message.message && String(message.message).trim() !== "" ? (vue.openBlock(), vue.createElementBlock(
"view",
{
key: 2,
class: vue.normalizeClass(["message-actions", { "message-actions-user": message.sender === $setup.UserId }])
},
[
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.copyMessage({ content: message.message }), ["stop"])
}, [
vue.createVNode(_component_uni_icons, {
type: "copy",
size: "14",
color: "#333"
}),
vue.createElementVNode("text", { class: "action-text" }, "复制")
], 8, ["onClick"]),
vue.createElementVNode("view", {
class: "message-action-item",
onClick: vue.withModifiers(($event) => $setup.forwardMessage({ content: message.message }), ["stop"])
}, [
vue.createVNode(_component_uni_icons, {
type: "redo",
size: "14",
color: "#999"
}),
vue.createElementVNode("text", { class: "action-text" }, "转发")
], 8, ["onClick"])
],
2
/* CLASS */
)) : vue.createCommentVNode("v-if", true)
], 42, ["onClick", "onLongpress"])
], 10, ["id"]);
}),
128
@@ -8019,7 +8299,7 @@ This will fail in production.`);
"view",
{
class: vue.normalizeClass(["chat-interactive-btn", { disabled: $setup.isThinking }]),
onClick: _cache[7] || (_cache[7] = ($event) => !$setup.isThinking && $setup.uploadPhoto())
onClick: _cache[8] || (_cache[8] = ($event) => !$setup.isThinking && $setup.uploadPhoto())
},
"拍照上传",
2
@@ -8029,7 +8309,7 @@ This will fail in production.`);
"view",
{
class: vue.normalizeClass(["chat-interactive-btn", { disabled: $setup.isThinking }]),
onClick: _cache[8] || (_cache[8] = ($event) => !$setup.isThinking && $setup.uploadFile())
onClick: _cache[9] || (_cache[9] = ($event) => !$setup.isThinking && $setup.uploadFile())
},
"上传文件",
2
@@ -8077,7 +8357,7 @@ This will fail in production.`);
class: "message-input",
placeholder: $setup.isThinking ? $setup.isSelfSent ? "AI 正在回复中..." : "电脑正在运行,请稍后" : "输入消息...",
disabled: $setup.isThinking,
"onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => $setup.textMessage = $event),
"onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => $setup.textMessage = $event),
"auto-height": ""
}, null, 8, ["placeholder", "disabled"]), [
[vue.vModelText, $setup.textMessage]
@@ -8091,7 +8371,7 @@ This will fail in production.`);
])) : (vue.openBlock(), vue.createElementBlock("view", {
key: 1,
class: "input-btn-group send-message-btn",
onClick: _cache[10] || (_cache[10] = ($event) => $setup.sendMessage())
onClick: _cache[11] || (_cache[11] = ($event) => $setup.sendMessage())
}, [
vue.createElementVNode("view", { class: "iconfont icon-fasong" })
]))
@@ -8107,13 +8387,13 @@ This will fail in production.`);
])
]),
$setup.showMessageModal ? (vue.openBlock(), vue.createElementBlock("view", {
key: 2,
key: 3,
class: "ncd-overlay",
onClick: $setup.closeMessageDetail
}, [
vue.createElementVNode("view", {
class: "ncd-card message-detail-card",
onClick: _cache[11] || (_cache[11] = vue.withModifiers(() => {
onClick: _cache[12] || (_cache[12] = vue.withModifiers(() => {
}, ["stop"]))
}, [
vue.createElementVNode("view", { class: "ncd-header" }, [
@@ -8173,7 +8453,7 @@ This will fail in production.`);
$setup.downloadToast.show ? (vue.openBlock(), vue.createElementBlock(
"view",
{
key: 3,
key: 4,
class: vue.normalizeClass(["download-toast-overlay", $setup.downloadToast.show ? "" : ""])
},
[

View File

@@ -28,9 +28,9 @@
/*每个页面公共css */
@font-face {
font-family: "iconfont"; /* Project id 4890805 */
src: url('static/iconfont/iconfont.woff2?t=1783330740989') format('woff2'),
url('static/iconfont/iconfont.woff?t=1783330740989') format('woff'),
url('static/iconfont/iconfont.ttf?t=1783330740989') format('truetype');
src: url('static/iconfont/iconfont.woff2?t=1786091687579') format('woff2'),
url('static/iconfont/iconfont.woff?t=1786091687579') format('woff'),
url('static/iconfont/iconfont.ttf?t=1786091687579') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
@@ -39,6 +39,12 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-zhuanfa_3:before {
content: "\e6ea";
}
.icon-fuzhi1:before {
content: "\e6fc";
}
.icon-daima:before {
content: "\e695";
}

View File

@@ -1261,6 +1261,166 @@ to { opacity: 1; transform: translateY(0) scale(1);
.agent-modal-btn-cancel[data-v-5eb7b895]:active {
background: #e0e0e0;
}
/* ========== 转发消息弹窗 ========== */
.forward-modal-mask[data-v-5eb7b895] {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.forward-modal[data-v-5eb7b895] {
width: 85%;
max-height: 72%;
background-color: #fff;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.forward-modal-header[data-v-5eb7b895] {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 0.875rem 0.9375rem 0.625rem;
border-bottom: 0.0625rem solid #f0f0f0;
}
.forward-modal-title[data-v-5eb7b895] {
font-size: 1.0625rem;
font-weight: 700;
color: #1a1a2e;
}
.forward-modal-close[data-v-5eb7b895] {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
}
.forward-preview-box[data-v-5eb7b895] {
margin: 0.625rem 0.9375rem 0.25rem;
padding: 0.625rem 0.75rem;
background: #f7f8fc;
border-radius: 0.4375rem;
border-left: 0.1875rem solid #007aff;
}
.forward-preview-label[data-v-5eb7b895] {
font-size: 0.75rem;
color: #999;
display: block;
margin-bottom: 0.25rem;
}
.forward-preview-text[data-v-5eb7b895] {
font-size: 0.875rem;
color: #333;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
.forward-select-label[data-v-5eb7b895] {
font-size: 0.8125rem;
color: #666;
padding: 0.375rem 0.9375rem 0.25rem;
display: block;
}
.forward-conv-list[data-v-5eb7b895] {
flex: 1;
max-height: 12.5rem;
padding: 0 0.625rem;
}
.forward-empty[data-v-5eb7b895] {
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
color: #999;
font-size: 0.8125rem;
}
.forward-conv-item[data-v-5eb7b895] {
display: flex;
align-items: center;
padding: 0.6875rem 0.5rem;
border-radius: 0.5rem;
margin-bottom: 0.25rem;
background: #fafafa;
transition: background 0.2s;
}
.forward-conv-item[data-v-5eb7b895]:active {
background: #eef4ff;
}
.forward-conv-selected[data-v-5eb7b895] {
background: #e8f0fe;
border: 0.0625rem solid #007aff;
}
.forward-conv-avatar[data-v-5eb7b895] {
width: 1.875rem;
height: 1.875rem;
border-radius: 0.4375rem;
background: #e8f0fe;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.625rem;
flex-shrink: 0;
}
.forward-conv-info[data-v-5eb7b895] {
flex: 1;
min-width: 0;
}
.forward-conv-name[data-v-5eb7b895] {
font-size: 0.875rem;
color: #333;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.forward-conv-check[data-v-5eb7b895] {
flex-shrink: 0;
margin-left: 0.375rem;
}
.forward-modal-footer[data-v-5eb7b895] {
padding: 0.625rem 0.9375rem 0.9375rem;
border-top: 0.0625rem solid #f0f0f0;
display: flex;
justify-content: flex-end;
gap: 0.625rem;
}
.forward-modal-btn[data-v-5eb7b895] {
padding: 0.5625rem 1.5rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
}
.forward-btn-cancel[data-v-5eb7b895] {
background: #f0f0f0;
color: #666;
}
.forward-btn-cancel[data-v-5eb7b895]:active {
background: #e0e0e0;
}
.forward-btn-confirm[data-v-5eb7b895] {
background: #007aff;
color: #fff;
}
.forward-btn-confirm[data-v-5eb7b895]:active {
background: #005fcc;
}
.forward-btn-disabled[data-v-5eb7b895] {
background: #b0d0f0;
color: #fff;
pointer-events: none;
}
/* ==========新建聊天列表相关====== */
.close-option-card[data-v-5eb7b895] {
width: 100%;
@@ -1449,7 +1609,7 @@ to { opacity: 1; transform: translateY(0) scale(1);
}
.chat-message[data-v-5eb7b895] {
display: flex;
align-items: flex-start;
flex-direction: column;
margin: 0.4375rem 0;
box-sizing: border-box;
animation: msgFadeIn-5eb7b895 0.3s ease;
@@ -1461,6 +1621,15 @@ to { opacity: 1; transform: translateY(0);
}
}
.message-user[data-v-5eb7b895] {
align-items: flex-end;
}
/* avatar + 气泡行(上方) */
.message-row[data-v-5eb7b895] {
display: flex;
align-items: flex-start;
width: 100%;
}
.message-user .message-row[data-v-5eb7b895] {
flex-direction: row-reverse;
}
.chat-avatar[data-v-5eb7b895] {
@@ -1501,6 +1670,9 @@ to { opacity: 1; transform: translateY(0);
box-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.04);
background: #ffffff;
border: 0.03125rem solid #eeeef5;
/* 启用文本选择复制 */
user-select: text;
-webkit-user-select: text;
}
.chat-content-user[data-v-5eb7b895] {
background: linear-gradient(135deg, #c4b5fd, #b8a5f0);
@@ -1516,6 +1688,68 @@ to { opacity: 1; transform: translateY(0);
.chat-content[data-v-5eb7b895]:not(.chat-content-user) {
border-bottom-left-radius: 0.25rem;
}
/* 消息操作栏 */
.message-actions[data-v-5eb7b895] {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 0.5rem;
padding-top: 0.375rem;
border-top: 0.03125rem solid rgba(0, 0, 0, 0.06);
gap: 0.75rem;
}
.message-actions-user[data-v-5eb7b895] {
justify-content: flex-start;
border-top-color: rgba(255, 255, 255, 0.3);
}
.message-action-item[data-v-5eb7b895] {
display: flex;
align-items: center;
gap: 0.1875rem;
padding: 0.25rem 0.5rem;
border-radius: 0.375rem;
transition: all 0.2s ease;
}
.message-action-item[data-v-5eb7b895]:active {
background: rgba(0, 0, 0, 0.05);
transform: scale(0.95);
}
.message-actions-user .message-action-item[data-v-5eb7b895]:active {
background: rgba(255, 255, 255, 0.2);
}
.action-text[data-v-5eb7b895] {
font-size: 0.6875rem;
color: #999;
}
.message-actions-user .action-text[data-v-5eb7b895] {
color: rgba(255, 255, 255, 0.8);
}
/* 消息转发弹窗 */
.msg-actions[data-v-5eb7b895] {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.3125rem;
}
.msg-actions-user[data-v-5eb7b895] {
justify-content: flex-end;
}
.msg-action-btn[data-v-5eb7b895] {
display: flex;
align-items: center;
gap: 0.1875rem;
padding: 0.125rem 0;
}
.msg-action-icon[data-v-5eb7b895] {
font-size: 0.8125rem;
}
.msg-action-label[data-v-5eb7b895] {
font-size: 0.6875rem;
color: #888;
}
.msg-action-forward[data-v-5eb7b895] {
margin-left: 0.25rem;
}
/* 图片消息 */
.message-image[data-v-5eb7b895] {
max-width: 9.375rem;
@@ -2224,3 +2458,168 @@ to {
color: #fff;
font-weight: 500;
}
/* ========== 转发消息弹窗 ========== */
.forward-modal-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.forward-modal {
width: 85%;
max-height: 72%;
background-color: #fff;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.forward-modal-header {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 0.875rem 0.9375rem 0.625rem;
border-bottom: 0.0625rem solid #f0f0f0;
}
.forward-modal-title {
font-size: 1.0625rem;
font-weight: 700;
color: #1a1a2e;
}
.forward-modal-close {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
}
.forward-preview-box {
margin: 0.625rem 0.9375rem 0.25rem;
padding: 0.625rem 0.75rem;
background: #f7f8fc;
border-radius: 0.4375rem;
border-left: 0.1875rem solid #007aff;
flex-shrink: 0;
}
.forward-preview-label {
font-size: 0.75rem;
color: #999;
display: block;
margin-bottom: 0.25rem;
}
.forward-preview-text {
font-size: 0.875rem;
color: #333;
word-break: break-all;
max-height: 5rem;
overflow-y: auto;
line-height: 1.5;
}
.forward-select-label {
font-size: 0.8125rem;
color: #666;
padding: 0.375rem 0.9375rem 0.25rem;
display: block;
flex-shrink: 0;
}
.forward-conv-list {
flex: 1;
height: 0;
min-height: 15.625rem;
padding: 0 0.625rem;
box-sizing: border-box;
}
.forward-empty {
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
color: #999;
font-size: 0.8125rem;
}
.forward-conv-item {
display: flex;
align-items: center;
padding: 0.6875rem 0.5rem;
border-radius: 0.5rem;
margin-bottom: 0.25rem;
background: #fafafa;
transition: background 0.2s;
}
.forward-conv-item:active {
background: #eef4ff;
}
.forward-conv-selected {
background: #e8f0fe;
border: 0.0625rem solid #007aff;
}
.forward-conv-avatar {
width: 1.875rem;
height: 1.875rem;
border-radius: 0.4375rem;
background: #e8f0fe;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.625rem;
flex-shrink: 0;
}
.forward-conv-info {
flex: 1;
min-width: 0;
}
.forward-conv-name {
font-size: 0.875rem;
color: #333;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.forward-conv-check {
flex-shrink: 0;
margin-left: 0.375rem;
}
.forward-modal-footer {
padding: 0.625rem 0.9375rem 0.9375rem;
border-top: 0.0625rem solid #f0f0f0;
display: flex;
justify-content: flex-end;
gap: 0.625rem;
flex-shrink: 0;
}
.forward-modal-btn {
padding: 0.5625rem 1.5rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
}
.forward-btn-cancel {
background: #f0f0f0;
color: #666;
}
.forward-btn-cancel:active {
background: #e0e0e0;
}
.forward-btn-confirm {
background: #007aff;
color: #fff;
}
.forward-btn-confirm:active {
background: #005fcc;
}
.forward-btn-disabled {
background: #b0d0f0;
color: #fff;
pointer-events: none;
}

View File

@@ -1261,6 +1261,166 @@ to { opacity: 1; transform: translateY(0) scale(1);
.agent-modal-btn-cancel[data-v-fdf84df1]:active {
background: #e0e0e0;
}
/* ========== 转发消息弹窗 ========== */
.forward-modal-mask[data-v-fdf84df1] {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.forward-modal[data-v-fdf84df1] {
width: 85%;
max-height: 72%;
background-color: #fff;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.forward-modal-header[data-v-fdf84df1] {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 0.875rem 0.9375rem 0.625rem;
border-bottom: 0.0625rem solid #f0f0f0;
}
.forward-modal-title[data-v-fdf84df1] {
font-size: 1.0625rem;
font-weight: 700;
color: #1a1a2e;
}
.forward-modal-close[data-v-fdf84df1] {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
}
.forward-preview-box[data-v-fdf84df1] {
margin: 0.625rem 0.9375rem 0.25rem;
padding: 0.625rem 0.75rem;
background: #f7f8fc;
border-radius: 0.4375rem;
border-left: 0.1875rem solid #007aff;
}
.forward-preview-label[data-v-fdf84df1] {
font-size: 0.75rem;
color: #999;
display: block;
margin-bottom: 0.25rem;
}
.forward-preview-text[data-v-fdf84df1] {
font-size: 0.875rem;
color: #333;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
.forward-select-label[data-v-fdf84df1] {
font-size: 0.8125rem;
color: #666;
padding: 0.375rem 0.9375rem 0.25rem;
display: block;
}
.forward-conv-list[data-v-fdf84df1] {
flex: 1;
max-height: 12.5rem;
padding: 0 0.625rem;
}
.forward-empty[data-v-fdf84df1] {
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
color: #999;
font-size: 0.8125rem;
}
.forward-conv-item[data-v-fdf84df1] {
display: flex;
align-items: center;
padding: 0.6875rem 0.5rem;
border-radius: 0.5rem;
margin-bottom: 0.25rem;
background: #fafafa;
transition: background 0.2s;
}
.forward-conv-item[data-v-fdf84df1]:active {
background: #eef4ff;
}
.forward-conv-selected[data-v-fdf84df1] {
background: #e8f0fe;
border: 0.0625rem solid #007aff;
}
.forward-conv-avatar[data-v-fdf84df1] {
width: 1.875rem;
height: 1.875rem;
border-radius: 0.4375rem;
background: #e8f0fe;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.625rem;
flex-shrink: 0;
}
.forward-conv-info[data-v-fdf84df1] {
flex: 1;
min-width: 0;
}
.forward-conv-name[data-v-fdf84df1] {
font-size: 0.875rem;
color: #333;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.forward-conv-check[data-v-fdf84df1] {
flex-shrink: 0;
margin-left: 0.375rem;
}
.forward-modal-footer[data-v-fdf84df1] {
padding: 0.625rem 0.9375rem 0.9375rem;
border-top: 0.0625rem solid #f0f0f0;
display: flex;
justify-content: flex-end;
gap: 0.625rem;
}
.forward-modal-btn[data-v-fdf84df1] {
padding: 0.5625rem 1.5rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
}
.forward-btn-cancel[data-v-fdf84df1] {
background: #f0f0f0;
color: #666;
}
.forward-btn-cancel[data-v-fdf84df1]:active {
background: #e0e0e0;
}
.forward-btn-confirm[data-v-fdf84df1] {
background: #007aff;
color: #fff;
}
.forward-btn-confirm[data-v-fdf84df1]:active {
background: #005fcc;
}
.forward-btn-disabled[data-v-fdf84df1] {
background: #b0d0f0;
color: #fff;
pointer-events: none;
}
/* ==========新建聊天列表相关====== */
.close-option-card[data-v-fdf84df1] {
width: 100%;
@@ -1449,7 +1609,7 @@ to { opacity: 1; transform: translateY(0) scale(1);
}
.chat-message[data-v-fdf84df1] {
display: flex;
align-items: flex-start;
flex-direction: column;
margin: 0.4375rem 0;
box-sizing: border-box;
animation: msgFadeIn-fdf84df1 0.3s ease;
@@ -1461,6 +1621,15 @@ to { opacity: 1; transform: translateY(0);
}
}
.message-user[data-v-fdf84df1] {
align-items: flex-end;
}
/* avatar + 气泡行(上方) */
.message-row[data-v-fdf84df1] {
display: flex;
align-items: flex-start;
width: 100%;
}
.message-user .message-row[data-v-fdf84df1] {
flex-direction: row-reverse;
}
.chat-avatar[data-v-fdf84df1] {
@@ -1501,6 +1670,9 @@ to { opacity: 1; transform: translateY(0);
box-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.04);
background: #ffffff;
border: 0.03125rem solid #eeeef5;
/* 启用文本选择复制 */
user-select: text;
-webkit-user-select: text;
}
.chat-content-user[data-v-fdf84df1] {
background: linear-gradient(135deg, #c4b5fd, #b8a5f0);
@@ -1516,6 +1688,68 @@ to { opacity: 1; transform: translateY(0);
.chat-content[data-v-fdf84df1]:not(.chat-content-user) {
border-bottom-left-radius: 0.25rem;
}
/* 消息操作栏 */
.message-actions[data-v-fdf84df1] {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 0.5rem;
padding-top: 0.375rem;
border-top: 0.03125rem solid rgba(0, 0, 0, 0.06);
gap: 0.75rem;
}
.message-actions-user[data-v-fdf84df1] {
justify-content: flex-start;
border-top-color: rgba(255, 255, 255, 0.3);
}
.message-action-item[data-v-fdf84df1] {
display: flex;
align-items: center;
gap: 0.1875rem;
padding: 0.25rem 0.5rem;
border-radius: 0.375rem;
transition: all 0.2s ease;
}
.message-action-item[data-v-fdf84df1]:active {
background: rgba(0, 0, 0, 0.05);
transform: scale(0.95);
}
.message-actions-user .message-action-item[data-v-fdf84df1]:active {
background: rgba(255, 255, 255, 0.2);
}
.action-text[data-v-fdf84df1] {
font-size: 0.6875rem;
color: #999;
}
.message-actions-user .action-text[data-v-fdf84df1] {
color: rgba(255, 255, 255, 0.8);
}
/* 消息转发弹窗 */
.msg-actions[data-v-fdf84df1] {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.3125rem;
}
.msg-actions-user[data-v-fdf84df1] {
justify-content: flex-end;
}
.msg-action-btn[data-v-fdf84df1] {
display: flex;
align-items: center;
gap: 0.1875rem;
padding: 0.125rem 0;
}
.msg-action-icon[data-v-fdf84df1] {
font-size: 0.8125rem;
}
.msg-action-label[data-v-fdf84df1] {
font-size: 0.6875rem;
color: #888;
}
.msg-action-forward[data-v-fdf84df1] {
margin-left: 0.25rem;
}
/* 图片消息 */
.message-image[data-v-fdf84df1] {
max-width: 9.375rem;

View File

@@ -54,6 +54,18 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe6ea;</span>
<div class="name">转发</div>
<div class="code-name">&amp;#xe6ea;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe6fc;</span>
<div class="name">复制</div>
<div class="code-name">&amp;#xe6fc;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe695;</span>
<div class="name">代码</div>
@@ -480,9 +492,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1783330740989') format('woff2'),
url('iconfont.woff?t=1783330740989') format('woff'),
url('iconfont.ttf?t=1783330740989') format('truetype');
src: url('iconfont.woff2?t=1786091687579') format('woff2'),
url('iconfont.woff?t=1786091687579') format('woff'),
url('iconfont.ttf?t=1786091687579') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -508,6 +520,24 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-zhuanfa_3"></span>
<div class="name">
转发
</div>
<div class="code-name">.icon-zhuanfa_3
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-fuzhi1"></span>
<div class="name">
复制
</div>
<div class="code-name">.icon-fuzhi1
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-daima"></span>
<div class="name">
@@ -1147,6 +1177,22 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-zhuanfa_3"></use>
</svg>
<div class="name">转发</div>
<div class="code-name">#icon-zhuanfa_3</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fuzhi1"></use>
</svg>
<div class="name">复制</div>
<div class="code-name">#icon-fuzhi1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-daima"></use>

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4890805 */
src: url('iconfont.woff2?t=1783330740989') format('woff2'),
url('iconfont.woff?t=1783330740989') format('woff'),
url('iconfont.ttf?t=1783330740989') format('truetype');
src: url('iconfont.woff2?t=1786091687579') format('woff2'),
url('iconfont.woff?t=1786091687579') format('woff'),
url('iconfont.ttf?t=1786091687579') format('truetype');
}
.iconfont {
@@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-zhuanfa_3:before {
content: "\e6ea";
}
.icon-fuzhi1:before {
content: "\e6fc";
}
.icon-daima:before {
content: "\e695";
}

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "16322565",
"name": "转发",
"font_class": "zhuanfa_3",
"unicode": "e6ea",
"unicode_decimal": 59114
},
{
"icon_id": "16322894",
"name": "复制",
"font_class": "fuzhi1",
"unicode": "e6fc",
"unicode_decimal": 59132
},
{
"icon_id": "1767709",
"name": "代码",