Compare commits

...

23 Commits

Author SHA1 Message Date
6bb7f37276 优化加载信息,优化气泡字体大小 2026-08-06 16:55:37 +08:00
23a03d0ed3 Revert "添加日志窗口,辅助测试。"
This reverts commit d1a56f5b23.
2026-08-06 16:21:41 +08:00
d1a56f5b23 添加日志窗口,辅助测试。 2026-08-06 09:37:37 +08:00
add3802d62 界面隐显后继续流式输出;优化中断逻辑 2026-08-06 08:52:06 +08:00
b4e69802c0 优化好友和群聊新建会话逻辑。 2026-08-05 17:56:12 +08:00
941070a2ee 优化新建会话逻辑 2026-08-05 17:31:48 +08:00
2fff814c79 创建智能体 2026-08-05 17:22:00 +08:00
fb421cd021 好友,群聊分页加载 2026-08-05 14:51:15 +08:00
e0d7f93c80 ai对话分页 2026-08-05 11:42:57 +08:00
fbda01a624 两端同步流式输出,刷新状态,强制退出。 2026-08-04 17:49:42 +08:00
b7c3fc9ff6 输出后闪白修复 2026-08-04 15:31:01 +08:00
2f1702c858 接了智能体列表,其他接口暂不可接 2026-08-04 14:44:48 +08:00
hy
c4fb90b755 Revert "封窗"
This reverts commit 9965f2772d.
2026-08-03 17:29:25 +08:00
hy
a3bab0784d Merge branch 'main' of https://gitea.yuxindazhineng.com/YiLin/phone-app------test1- 2026-08-03 17:09:31 +08:00
hy
9965f2772d 封窗 2026-08-03 17:09:22 +08:00
849e473c7d 按钮组件,链接显示修复 2026-08-03 16:08:52 +08:00
e057e33601 新增工作区下载列表 2026-08-03 09:05:21 +08:00
314a714248 登录页面和文件打开方式 2026-07-31 16:38:01 +08:00
09f4d3ba52 wyxd与聊天页面的切换, 2026-07-31 10:24:55 +08:00
c5958812cf WYXD左右滑动翻页 2026-07-28 17:48:57 +08:00
85ecfc4c5b 新增文件点击,优化流式输出 2026-07-28 16:52:15 +08:00
c90600c66e //修改优先把消息加入列表 2026-07-27 18:01:32 +08:00
9bafcaed5d 修改wyxd居中和去内边距 2026-07-27 16:42:42 +08:00
29 changed files with 4524 additions and 616 deletions

View File

@@ -24,7 +24,7 @@
</view>
<view class="new-chat-btn" @click="goContactPages">
<text>+ 聊天列表</text>
<text>+ 更多聊天列表</text>
</view>
</view>
<view class="chat-history">
@@ -269,7 +269,12 @@
// 新建会话
const openNewChatModal = () => {
console.log("点击了新建会话");
// 好友会话(1)或群聊(2)时,跳转到通讯录页面发起新聊天
if (chatType.value === 1 || chatType.value === 2) {
goContactPages()
return
}
// AI 聊天(0)时,弹出新建会话弹窗
emit('update:showNewChatModal', true)
}

View File

@@ -1,5 +1,5 @@
{
"name" : "test1",
"name" : "宇恒一号",
"appid" : "__UNI__923FD9E",
"description" : "",
"versionName" : "1.1.1",

View File

@@ -105,11 +105,13 @@
font-size: 36rpx;
font-weight: 700;
color: #1a1a2e;
align-items: center;
}
.ncd-header uni-icons {
display: flex;
flex-shrink: 0;
align-items: center;
}
.ncd-options {
@@ -210,6 +212,194 @@
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
}
/* ========== 智能体选择弹窗 ========== */
.agent-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: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.agent-modal {
width: 85%;
max-height: 70%;
background-color: #ffffff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12);
}
.agent-modal-header {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx 30rpx 20rpx;
position: relative;
border-bottom: 2rpx solid #f0f0f0;
}
.agent-modal-title {
font-size: 34rpx;
font-weight: 700;
color: #1a1a2e;
}
.agent-modal-close {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
padding: 10rpx;
}
.agent-list {
box-sizing: border-box;
flex: 1;
padding: 20rpx 24rpx;
max-height: 600rpx;
}
.agent-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx 0;
}
.agent-loading-text {
margin-top: 16rpx;
font-size: 26rpx;
color: #999;
}
.agent-empty {
display: flex;
align-items: center;
justify-content: center;
padding: 80rpx 0;
}
.agent-empty-text {
font-size: 28rpx;
color: #999;
}
.agent-card {
box-sizing: border-box;
width: 100%;
background: linear-gradient(135deg, #f8f5ff, #efe8ff);
border: 2rpx solid #c4b5fd;
border-radius: 20rpx;
padding: 28rpx 24rpx;
margin-bottom: 20rpx;
transition: all 0.2s ease;
overflow: hidden;
}
.agent-card:active {
transform: scale(0.98);
border-color: #a78bfa;
background: linear-gradient(135deg, #f3efff, #e8dcff);
}
.agent-card-header {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.agent-avatar {
width: 70rpx;
height: 70rpx;
border-radius: 20rpx;
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.agent-card-info {
margin-left: 16rpx;
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
}
.agent-card-title {
font-size: 30rpx;
font-weight: 600;
color: #1a1a2e;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.agent-card-category {
font-size: 22rpx;
color: #8b5cf6;
margin-top: 4rpx;
}
.agent-card-desc {
font-size: 26rpx;
color: #555;
line-height: 1.5;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-card-welcome {
font-size: 24rpx;
color: #7c3aed;
margin-top: 12rpx;
padding-top: 12rpx;
border-top: 2rpx dashed #ddd6fe;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-modal-footer {
padding: 20rpx 30rpx 30rpx;
border-top: 2rpx solid #f0f0f0;
display: flex;
justify-content: flex-end;
}
.agent-modal-btn {
padding: 18rpx 48rpx;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
}
.agent-modal-btn-cancel {
background: #f0f0f0;
color: #666;
}
.agent-modal-btn-cancel:active {
background: #e0e0e0;
}
/* ==========新建聊天列表相关====== */
.close-option-card {
width: 100%;
@@ -317,6 +507,10 @@
font-size: 48rpx;
}
.chat-btn-group .head-btn:nth-child(4) {
/* 刷新按钮 */
}
.log-out {
/* background: #ffd4d4; */
}
@@ -325,6 +519,62 @@
color: #ff4d4f;
}
/* ==========WYXD 文件入口横幅========== */
.wyxd-banner {
display: flex;
align-items: center;
padding: 14rpx 24rpx;
margin: 6rpx 20rpx;
background: linear-gradient(135deg, #e8f4fd, #f0e6ff);
border: 1.5rpx solid rgba(120, 120, 220, 0.25);
border-radius: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(100, 100, 200, 0.08);
}
.wyxd-banner:active {
background: linear-gradient(135deg, #d8eafb, #e6d8ff);
transform: scale(0.98);
}
.wyxd-banner-icon {
font-size: 32rpx;
color: #6c6ce0;
margin-right: 12rpx;
}
.wyxd-banner-text {
flex: 1;
font-size: 26rpx;
font-weight: 600;
color: #4a4ab8;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wyxd-banner-arrow {
font-size: 24rpx;
color: #9999cc;
}
.wyxd-banner-close {
width: 36rpx;
height: 36rpx;
line-height: 36rpx;
text-align: center;
font-size: 28rpx;
color: #9999cc;
border-radius: 50%;
background: rgba(100, 100, 200, 0.08);
margin-left: 8rpx;
flex-shrink: 0;
}
.wyxd-banner-close:active {
background: rgba(100, 100, 200, 0.18);
color: #6c6ce0;
}
/* ==========聊天主体部分========== */
.main-chat {
display: flex;

File diff suppressed because it is too large Load Diff

View File

@@ -475,6 +475,7 @@
uploadCloudDbFile,
deleteCloudDb
} from '@/utils/cloud-api.js';
import { openFile as openFileNative } from '@/utils/fileOpener.js'
const userToken = ref('');
const userId = ref('');
@@ -826,19 +827,10 @@
}
};
// 使用系统默认应用打开
// 打开文件(弹出应用选择菜单)
const openFile = (filePath) => {
uni.openDocument({
filePath: filePath,
success: () => uni.showToast({
title: '打开成功',
icon: 'success'
}),
fail: (err) => {
console.error('打开文件失败:', err);
// 如果默认应用打开失败,尝试弹出选择菜单
openFileWithMenu(filePath);
}
openFileNative(filePath, () => {
openFileWithMenu(filePath);
});
};

View File

@@ -32,9 +32,14 @@
<!-- 幻灯片 -->
<view v-else class="wyxd-slide-area">
<scroll-view class="wyxd-slide-scroll" scroll-y :show-scrollbar="false">
<view class="wyxd-slide-card" v-html="currentSlide.html"></view>
</scroll-view>
<swiper class="wyxd-swiper" :current="currentIndex"
@change="onSwiperChange" :duration="250" easing-function="easeOutCubic">
<swiper-item v-for="(slide, idx) in slides" :key="idx">
<scroll-view class="wyxd-slide-scroll" scroll-y :show-scrollbar="false">
<view class="wyxd-slide-card" v-html="slide.html"></view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</view>
@@ -89,10 +94,12 @@ const statusText = computed(() => {
const displayName = computed(() => fileName.value || '未命名文档')
const currentSlide = computed(() => slides.value[currentIndex.value] || { html: '' })
const pad = (n) => String(n).padStart(2, '0')
const onSwiperChange = (e) => {
currentIndex.value = e.detail.current
}
const goBack = () => {
uni.navigateBack()
}
@@ -181,7 +188,8 @@ onLoad((options) => {
userToken: userToken.value
})
if (isWyxdCached(workspaceId.value, filePath.value)) {
// forceDownload 强制重新下载不走缓存
if (options.forceDownload !== '1' && isWyxdCached(workspaceId.value, filePath.value)) {
loadFromCache()
} else {
startDownload()
@@ -244,7 +252,12 @@ onLoad((options) => {
.wyxd-slide-area {
flex: 1;
min-height: 0;
padding: 20rpx;
/* padding: 20rpx; */
}
.wyxd-swiper {
width: 100%;
height: 100%;
}
.wyxd-slide-scroll {
@@ -254,10 +267,18 @@ onLoad((options) => {
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.wyxd-slide-card {
/* .wyxd-slide-card {
padding: 32rpx;
min-height: 100%;
box-sizing: border-box;
} */
.wyxd-slide-card {
min-height: 100%;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column; /* 子元素垂直排列 */
}
/* ===== 底部翻页 ===== */

View File

@@ -380,3 +380,164 @@
.workspace-footer .iconfont {
font-size: 40rpx !important;
}
/* ===== 标签切换 ===== */
.workspace-tabs {
display: flex;
width: 100%;
padding: 0 24rpx;
box-sizing: border-box;
gap: 20rpx;
}
.tab-item {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 18rpx 0;
font-size: 28rpx;
font-weight: 500;
color: #999;
border-bottom: 4rpx solid transparent;
transition: all 0.2s ease;
position: relative;
}
.tab-item.active {
color: #6c63ff;
border-bottom-color: #6c63ff;
}
.tab-badge {
margin-left: 8rpx;
background: #ff5e57;
color: #fff;
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 20rpx;
line-height: 1.4;
}
/* ===== 下载列表 ===== */
.download-content {
flex: 1;
overflow: auto;
}
.download-empty {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 200rpx;
color: #bbb;
font-size: 28rpx;
}
.download-empty .iconfont {
font-size: 140rpx;
color: #ddd;
margin-bottom: 20rpx;
}
.download-list {
padding: 20rpx 24rpx;
}
.download-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12rpx 8rpx 20rpx;
font-size: 24rpx;
color: #999;
}
.clear-btn {
color: #ff5e57;
font-size: 24rpx;
font-weight: 500;
padding: 4rpx 12rpx;
}
.download-item {
display: flex;
align-items: center;
padding: 24rpx 20rpx;
background: rgba(255, 255, 255, 0.85);
border-radius: 20rpx;
margin-bottom: 16rpx;
transition: all 0.15s ease;
}
.download-item:active {
transform: scale(0.98);
background: rgba(255, 255, 255, 0.95);
}
.di-icon {
width: 80rpx;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
background: rgba(108, 99, 255, 0.08);
border-radius: 18rpx;
margin-right: 20rpx;
flex-shrink: 0;
}
.di-icon .iconfont {
font-size: 40rpx;
color: #6c63ff;
}
.di-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 6rpx;
min-width: 0;
}
.di-name {
font-size: 28rpx;
font-weight: 500;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-meta {
font-size: 22rpx;
color: #999;
}
.di-path {
font-size: 20rpx;
color: #bbb;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-delete {
width: 56rpx;
height: 56rpx;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.di-delete .iconfont {
font-size: 36rpx;
color: #ccc;
transition: color 0.15s ease;
}
.di-delete:active .iconfont {
color: #ff5e57;
}

View File

@@ -66,8 +66,20 @@
<view v-if="isSearchFocus" class="cancel-search" @click="handleSearchFocus">取消</view>
</view>
<!-- 标签切换 -->
<view class="workspace-tabs">
<view class="tab-item" :class="{ active: activeTab === 'workspace' }" @click="switchTab('workspace')">
工作区
</view>
<view class="tab-item" :class="{ active: activeTab === 'downloads' }" @click="switchTab('downloads')">
下载列表
<text v-if="downloadList.length > 0" class="tab-badge">{{ downloadList.length }}</text>
</view>
</view>
</view>
<view class="workspace-content">
<!-- ===== 工作区文件 ===== -->
<view class="workspace-content" v-if="activeTab === 'workspace'">
<view class="folder-null" v-if="currentFolderList.length===0">
<view class="iconfont icon-wenjianjia"></view>
文件夹为空
@@ -89,6 +101,34 @@
</view>
</view>
</view>
<!-- ===== 下载列表 ===== -->
<view class="download-content" v-if="activeTab === 'downloads'">
<view v-if="downloadList.length === 0" class="download-empty">
<text class="iconfont icon-xiazai"></text>
<text>暂无下载文件</text>
</view>
<view v-else class="download-list">
<view class="download-header">
<text>已下载 {{ downloadList.length }} 个文件</text>
<text class="clear-btn" @click="handleClearDownloads">清空</text>
</view>
<view class="download-item" v-for="item in downloadList" :key="item.id" @click="openDownloadFile(item)">
<view class="di-icon">
<text class="iconfont" :class="getFileIcon(item.name)"></text>
</view>
<view class="di-info">
<text class="di-name">{{ item.name }}</text>
<text class="di-meta">{{ formatDownloadTime(item.time) }} · {{ formatDownloadSize(item.size) }}</text>
<text class="di-path">{{ item.displayPath || item.path }}</text>
</view>
<view class="di-delete" @click.stop="handleDeleteDownload(item.id)">
<text class="iconfont icon-del"></text>
</view>
</view>
</view>
</view>
<view v-if="isSelectFolder" class="workspace-footer" :class="{'folder-actions':selectFileList.length>0}">
<view class="iconfont icon-shangchuan" @click="handleUploadFile"></view>
<!-- <view class="iconfont icon-fuzhi"></view> -->
@@ -121,11 +161,22 @@
workspaceUploadFileByURL,
updateWorkspaceFileName
} from '@/utils/cloud-api.js'
import { openFile as openFileNative } from '@/utils/fileOpener.js'
import {
getDownloadList,
saveDownload,
deleteDownload,
clearAllDownloads,
formatFileSize,
formatTime
} from '@/utils/downloadManager.js'
const UserToken = ref('')
const workspaceId = ref('')
const navbarBeforeTitle = ref('');
const navbarTitle = ref('工作区');
const activeTab = ref('workspace')
const downloadList = ref([])
// 选择文件模式
const isSelectFolder = ref(false);
@@ -284,20 +335,35 @@
const handleLongPress = (folder) => {
if (isSelectFolder.value) return;
const isWyxd = folder.name && folder.name.toLowerCase().endsWith('.wyxd');
const itemList = isWyxd ? ['下载', '删除', 'WYXD查看器'] : ['下载', '删除'];
const itemList = isWyxd ? ['下载', '删除', 'WYXD查看器', 'AI修改'] : ['下载', '删除'];
uni.showActionSheet({
title: folder.name,
itemList: itemList,
success: (res) => {
switch (res.tapIndex) {
case 0:
handleDownload(folder);
break;
case 1:
handleDelete(folder);
break;
case 2:
if (isWyxd) openWyxdViewer(folder);
break;
if (isWyxd) {
switch (res.tapIndex) {
case 0:
handleDownload(folder);
break;
case 1:
handleDelete(folder);
break;
case 2:
openWyxdViewer(folder);
break;
case 3: // 'AI修改',
handleAiModify(folder);
break;
}
} else {
switch (res.tapIndex) {
case 0:
handleDownload(folder);
break;
case 1:
handleDelete(folder);
break;
}
}
}
})
@@ -379,6 +445,7 @@
const downloadUrl = fileInfo.url;
const fileName = folder.name;
const fileSize = fileInfo.size || 0;
uni.showLoading({
title: '下载中...'
@@ -391,8 +458,14 @@
uni.hideLoading();
if (downloadRes.statusCode === 200) {
const tempPath = downloadRes.tempFilePath;
// 下载成功,直接打开文件
console.log("// 下载成功,文件下载路径为:",tempPath);
// 持久化保存到本地
saveDownload(tempPath, fileName, fileSize).then((record) => {
downloadList.value.unshift(record);
uni.showToast({ title: '下载成功', icon: 'success' });
}).catch(() => {
// 保存失败不影响打开
});
// 下载成功后打开文件
openFile(tempPath);
} else {
uni.showToast({
@@ -420,42 +493,108 @@
}
};
// 使用系统默认应用打开
// 打开文件(弹出应用选择菜单)
const openFile = (filePath) => {
uni.openDocument({
filePath: filePath,
success: () => uni.showToast({
title: '打开成功',
icon: 'success'
}),
fail: (err) => {
console.error('打开文件失败:', err);
uni.showToast({
title: '无法打开此文件',
icon: 'error'
});
}
openFileNative(filePath, () => {
uni.showToast({ title: '无法打开此文件', icon: 'error' });
});
};
// 选择其他应用打开
const openFileWithMenu = (filePath) => {
uni.openDocument({
filePath: filePath,
showMenu: true,
success: () => uni.showToast({
title: '打开成功',
icon: 'success'
}),
fail: (err) => {
console.error('打开文件失败:', err);
uni.showToast({
title: '无法打开此文件',
icon: 'error'
});
// ===== 下载列表相关 =====
const switchTab = (tab) => {
activeTab.value = tab
if (tab === 'downloads') {
loadDownloads()
}
}
const loadDownloads = () => {
downloadList.value = getDownloadList()
}
const openDownloadFile = (item) => {
// #ifdef APP-PLUS
// 检查公共目录下文件是否存在
plus.io.resolveLocalFileSystemURL(
item.path,
() => {
// 文件存在,直接打开
openFile(item.path)
},
() => {
// 文件已被手动删除
uni.showToast({ title: '文件已失效,将移除记录', icon: 'none' })
handleDeleteDownload(item.id)
}
});
};
)
// #endif
// #ifndef APP-PLUS
uni.getSavedFileList({
success: (res) => {
const found = res.fileList.find(f => f.filePath === item.path)
if (found) {
openFile(item.path)
} else {
uni.showToast({ title: '文件已失效,将移除记录', icon: 'none' })
handleDeleteDownload(item.id)
}
},
fail: () => openFile(item.path)
})
// #endif
}
const handleDeleteDownload = (id) => {
uni.showModal({
title: '删除文件',
content: '确定要删除此下载文件吗?',
success: (res) => {
if (res.confirm) {
deleteDownload(id).then(() => {
downloadList.value = getDownloadList()
uni.showToast({ title: '已删除', icon: 'success' })
}).catch(() => {
uni.showToast({ title: '删除失败', icon: 'error' })
})
}
}
})
}
const handleClearDownloads = () => {
if (downloadList.value.length === 0) return
uni.showModal({
title: '清空下载',
content: '确定要清空所有下载文件吗?此操作不可撤销。',
success: (res) => {
if (res.confirm) {
clearAllDownloads().then(() => {
downloadList.value = []
uni.showToast({ title: '已清空', icon: 'success' })
})
}
}
})
}
const formatDownloadSize = formatFileSize
const formatDownloadTime = formatTime
// const getFileIcon = (fileName) => {
// const ext = fileName.split('.').pop().toLowerCase()
// const iconMap = {
// pdf: 'icon-PDF',
// doc: 'icon-word', docx: 'icon-word',
// xls: 'icon-excel', xlsx: 'icon-excel',
// ppt: 'icon-PPD', pptx: 'icon-PPD',
// zip: 'icon-yasuobao', rar: 'icon-yasuobao', '7z': 'icon-yasuobao',
// jpg: 'icon-tupian', jpeg: 'icon-tupian', png: 'icon-tupian', gif: 'icon-tupian',
// mp3: 'icon-yinle', wav: 'icon-yinle', flac: 'icon-yinle',
// mp4: 'icon-shipin', avi: 'icon-shipin', mov: 'icon-shipin',
// txt: 'icon-txt', md: 'icon-txt',
// }
// return iconMap[ext] || 'icon-weizhiwenjian'
// }
// WYXD 查看器入口
const openWyxdViewer = (folder) => {
@@ -472,6 +611,17 @@
});
};
// AI修改入口跳转对话页并传入 WYXD 信息
const handleAiModify = (folder) => {
const filePath = folder.path.startsWith('./') ? folder.path.slice(2) : folder.path;
uni.navigateTo({
url: '/pages/Chat/Chat?wyxdWorkspaceId=' + encodeURIComponent(workspaceId.value)
+ '&wyxdFilePath=' + encodeURIComponent(filePath)
+ '&wyxdFileName=' + encodeURIComponent(folder.name)
+ '&wyxdUserToken=' + encodeURIComponent(UserToken.value)
});
};
// 删除
const handleDelete = (folder) => {
uni.showModal({
@@ -605,7 +755,10 @@
// 处理文件夹点击(非选择模式下进入文件夹,仅目录可点击进入)
const handleFolderClick = (folder) => {
if (folder.type !== 'directory') return;
if (folder.type !== 'directory') {
handleLongPress(folder)
return
}
folderStack.value.push({
path: folder.path,
name: folder.name
@@ -666,6 +819,7 @@
onMounted(() => {
initCurrentFolderList();
loadDownloads();
})
</script>

View File

@@ -66,7 +66,11 @@
</view>
<view class="main-chat">
<scroll-view class="chat-messages" direction="vertical" scroll-y :scroll-into-view="scrollToView"
:upper-threshold="0" :scroll-with-animation="true" @scroll="onScroll">
:upper-threshold="50" :scroll-with-animation="true" @scroll="onScroll" @scrolltoupper="onScrollToUpper">
<!-- 加载更多提示 -->
<view v-if="(ChatType === 0 && isAILoadingMore) || (ChatType === 1 && isFriendLoadingMore) || (ChatType === 2 && isGroupLoadingMore)" class="load-more-tip">
<text>加载更多消息...</text>
</view>
<!-- 与AI的对话内容展示 -->
<template v-for="(message, index) in currentMessages" :key="index">
<view v-if="ChatType === 0 && message.role !== 'tool'" class="chat-message" :id="'msg-' + index"
@@ -325,6 +329,7 @@
chooseFile
} from '@/uni_modules/lime-choose-file'
import socketManager from '../../utils/socket';
import { openFile as openFileNative } from '@/utils/fileOpener.js'
const friendSocketStore = useFriendSocketStore()
// 连接实时通讯eriendsocket
@@ -490,15 +495,7 @@
}
// 打开文件
const openFile = (url) => {
uni.downloadFile({
url: url,
success: (res) => {
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true
})
}
})
downloadAndOpen(url);
}
// 文件大小格式化
const formatFileSize = (size) => {
@@ -1131,14 +1128,16 @@
if (reason === 'pc offline') {
isThinking.value = false
socketStore.authFailReason = ''
nextTick(() => {
uni.showModal({
title: '提示',
content: 'PC端不在线不可聊天',
showCancel: false,
confirmText: '知道了'
})
uni.showToast({
title: 'PC端不在线',
icon: 'none',
duration: 1500
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/Login/Login'
})
}, 1500)
}
})
@@ -1322,6 +1321,22 @@
// 加载状态和分页相关变量
const isLoadingMore = ref(false) // 是否正在加载更多
const currentPage = ref(1) // 当前页码(如果后端支持分页)
const pageSize = 200;
// AI 消息分页
const isAILoadingMore = ref(false)
const aiPageNumber = ref(0) // AI 会话当前服务端页码0-based
const hasMoreAIMessages = ref(true)
// 好友消息分页
const isFriendLoadingMore = ref(false)
const friendPageNumber = ref(1) // 好友消息当前页码1-based
const hasMoreFriendMessages = ref(true)
// 群聊消息分页
const isGroupLoadingMore = ref(false)
const groupPageNumber = ref(1) // 群聊消息当前页码1-based
const hasMoreGroupMessages = ref(true)
// 计算属性:自动根据 allmessages 和 currentPage 计算显示消息
const currentMessages = computed(() => {
// return allmessages.value.slice(-pageInfoNumber);
@@ -1332,9 +1347,11 @@
// 获取对话消息
const takeConversationMessages = async () => {
try {
allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || [];
aiPageNumber.value = 0
hasMoreAIMessages.value = true
const rawMessages = await getConversationMessages(userToken.value, currentSessionId.value, pageSize, 0) || [];
allmessages.value = rawMessages
// console.log("获取到的所有消息:", JSON.stringify(allmessages.value) );
// currentMessages.value = allmessages.value.slice(-pageInfoNumber);
// 数据获取后执行滚动
scrollToBottom();
} catch (error) {
@@ -1346,7 +1363,10 @@
}
const takeFriendMessages = async () => {
try {
allmessages.value = await getFriendMessages(currentSessionId.value) || [];
friendPageNumber.value = 1
hasMoreFriendMessages.value = true
const rawMessages = await getFriendMessages(currentSessionId.value, 1) || [];
allmessages.value = rawMessages
// console.log("好友消息:", JSON.stringify(allmessages.value));
// 数据获取后执行滚动
scrollToBottom();
@@ -1359,7 +1379,10 @@
}
const takeGroupMessages = async () => {
try {
allmessages.value = await getGroupMessages(currentSessionId.value) || [];
groupPageNumber.value = 1
hasMoreGroupMessages.value = true
const rawMessages = await getGroupMessages(currentSessionId.value, 1) || [];
allmessages.value = rawMessages
console.log("群聊消息:", allmessages.value);
// 获取群成员列表并获取头像
const memberList = await getGroupMemberList(currentSessionId.value)
@@ -1399,6 +1422,90 @@
// 监听滚动
const onScroll = (e) => {}
// 滚动到顶部时加载更多消息(根据 ChatType 分发)
const onScrollToUpper = async () => {
if (ChatType.value === 0) {
await loadMoreAIMessages()
} else if (ChatType.value === 1) {
await loadMoreFriendMessages()
} else if (ChatType.value === 2) {
await loadMoreGroupMessages()
}
}
// 加载更多 AI 历史消息(上一页),并定位到原第一条消息
const loadMoreAIMessages = async () => {
if (isAILoadingMore.value || !hasMoreAIMessages.value || !currentSessionId.value) return
isAILoadingMore.value = true
try {
const nextPage = aiPageNumber.value + 1
const olderMessages = await getConversationMessages(userToken.value, currentSessionId.value, pageSize, nextPage)
if (olderMessages && olderMessages.length > 0) {
aiPageNumber.value = nextPage
allmessages.value = [...olderMessages, ...allmessages.value]
await nextTick()
scrollToView.value = 'msg-' + olderMessages.length
} else {
hasMoreAIMessages.value = false
}
} catch (e) {
console.error('加载更多AI消息失败:', e)
uni.showToast({ title: '加载更多失败', icon: 'none' })
} finally {
isAILoadingMore.value = false
}
}
// 加载更多好友历史消息(上一页),并定位到原第一条消息
const loadMoreFriendMessages = async () => {
if (isFriendLoadingMore.value || !hasMoreFriendMessages.value || !currentSessionId.value) return
isFriendLoadingMore.value = true
try {
const nextPage = friendPageNumber.value + 1
const olderMessages = await getFriendMessages(currentSessionId.value, nextPage)
if (olderMessages && olderMessages.length > 0) {
friendPageNumber.value = nextPage
allmessages.value = [...olderMessages, ...allmessages.value]
await nextTick()
scrollToView.value = 'msg-' + olderMessages.length
} else {
hasMoreFriendMessages.value = false
}
} catch (e) {
console.error('加载更多好友消息失败:', e)
uni.showToast({ title: '加载更多失败', icon: 'none' })
} finally {
isFriendLoadingMore.value = false
}
}
// 加载更多群聊历史消息(上一页),并定位到原第一条消息
const loadMoreGroupMessages = async () => {
if (isGroupLoadingMore.value || !hasMoreGroupMessages.value || !currentSessionId.value) return
isGroupLoadingMore.value = true
try {
const nextPage = groupPageNumber.value + 1
const olderMessages = await getGroupMessages(currentSessionId.value, nextPage)
if (olderMessages && olderMessages.length > 0) {
groupPageNumber.value = nextPage
allmessages.value = [...olderMessages, ...allmessages.value]
await nextTick()
scrollToView.value = 'msg-' + olderMessages.length
} else {
hasMoreGroupMessages.value = false
}
} catch (e) {
console.error('加载更多群聊消息失败:', e)
uni.showToast({ title: '加载更多失败', icon: 'none' })
} finally {
isGroupLoadingMore.value = false
}
}
// 滑动到底部
const scrollToBottom = async () => {
await nextTick();

View File

@@ -30,6 +30,7 @@ export const useSocketStore = defineStore('socket', () => {
const maxLogCount = ref(20)
const authFailReason = ref('')
const pcOffline = ref(false)
// ==================== 计算属性 ====================
const isConnected = computed(() => connectionStatus.value === 'connected')
@@ -66,6 +67,7 @@ export const useSocketStore = defineStore('socket', () => {
...config.value,
...options
}
pcOffline.value = false // 每次连接时重置 PC 离线标记
addLog('info',
`准备连接WebSocket。Token:${config.value.token || '未设置'}。ConversationId: ${config.value.conversationId || '未设置'}`
)
@@ -182,6 +184,7 @@ export const useSocketStore = defineStore('socket', () => {
break
case 'pc_offline':
pcOffline.value = true
addLog('warn', 'PC 端已离线')
break
@@ -287,6 +290,7 @@ export const useSocketStore = defineStore('socket', () => {
logs,
config,
authFailReason,
pcOffline,
// 计算属性
isConnected,

View File

@@ -1,8 +1,8 @@
;(function(){
let u=void 0,isReady=false,onReadyCallbacks=[],isServiceReady=false,onServiceReadyCallbacks=[];
const __uniConfig = {"pages":[],"globalStyle":{"backgroundColor":"#F8F8F8","navigationBar":{"backgroundColor":"#F8F8F8","titleText":"uni-app","type":"default","titleColor":"#000000"},"isNVue":false},"nvue":{"compiler":"uni-app","styleCompiler":"uni-app","flex-direction":"column"},"renderer":"auto","appname":"test1","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":true},"compilerVersion":"5.07","entryPagePath":"pages/Login/Login","entryPageQuery":"","realEntryPagePath":"","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000},"locales":{},"darkmode":false,"themeConfig":{}};
const __uniRoutes = [{"path":"pages/Login/Login","meta":{"isQuit":true,"isEntry":true,"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"登录页面","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/Chat/Chat","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"聊天页面(主页面)","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/WorkSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"工作区文件管理","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/UserProfileModal/UserProfileModal","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/ContactPages/ContactPages","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/TemplateSpace/TemplateSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDatabase/CloudDatabase","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"云端数据","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDbDetail/CloudDbDetail","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"数据库详情","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/text/text","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}},{"path":"pages/text/IntuitiveAipptViewer","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}}].map(uniRoute=>(uniRoute.meta.route=uniRoute.path,__uniConfig.pages.push(uniRoute.path),uniRoute.path='/'+uniRoute.path,uniRoute));
const __uniConfig = {"pages":[],"globalStyle":{"backgroundColor":"#F8F8F8","navigationBar":{"backgroundColor":"#F8F8F8","titleText":"uni-app","type":"default","titleColor":"#000000"},"isNVue":false},"nvue":{"compiler":"uni-app","styleCompiler":"uni-app","flex-direction":"column"},"renderer":"auto","appname":"宇恒一号","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":true},"compilerVersion":"5.07","entryPagePath":"pages/Login/Login","entryPageQuery":"","realEntryPagePath":"","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000},"locales":{},"darkmode":false,"themeConfig":{}};
const __uniRoutes = [{"path":"pages/Login/Login","meta":{"isQuit":true,"isEntry":true,"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"登录页面","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/Chat/Chat","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"聊天页面(主页面)","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/WorkSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"工作区文件管理","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/UserProfileModal/UserProfileModal","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/ContactPages/ContactPages","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/TemplateSpace/TemplateSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDatabase/CloudDatabase","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"云端数据","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDbDetail/CloudDbDetail","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"数据库详情","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/text/text","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}},{"path":"pages/text/IntuitiveAipptViewer","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}},{"path":"pages/WYXD/WYXD","meta":{"titleNView":false,"bounce":"none","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}}].map(uniRoute=>(uniRoute.meta.route=uniRoute.path,__uniConfig.pages.push(uniRoute.path),uniRoute.path='/'+uniRoute.path,uniRoute));
__uniConfig.styles=[];//styles
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
__uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
"iPad"
],
"id": "__UNI__923FD9E",
"name": "test1",
"name": "宇恒一号",
"version": {
"name": "1.1.1",
"code": 2

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
;(function(){
let u=void 0,isReady=false,onReadyCallbacks=[],isServiceReady=false,onServiceReadyCallbacks=[];
const __uniConfig = {"pages":[],"globalStyle":{"backgroundColor":"#F8F8F8","navigationBar":{"backgroundColor":"#F8F8F8","titleText":"uni-app","type":"default","titleColor":"#000000"},"isNVue":false},"nvue":{"compiler":"uni-app","styleCompiler":"uni-app","flex-direction":"column"},"renderer":"auto","appname":"test1","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":true},"compilerVersion":"5.07","entryPagePath":"pages/Login/Login","entryPageQuery":"","realEntryPagePath":"","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000},"locales":{},"darkmode":false,"themeConfig":{}};
const __uniConfig = {"pages":[],"globalStyle":{"backgroundColor":"#F8F8F8","navigationBar":{"backgroundColor":"#F8F8F8","titleText":"uni-app","type":"default","titleColor":"#000000"},"isNVue":false},"nvue":{"compiler":"uni-app","styleCompiler":"uni-app","flex-direction":"column"},"renderer":"auto","appname":"宇恒一号","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":true},"compilerVersion":"5.07","entryPagePath":"pages/Login/Login","entryPageQuery":"","realEntryPagePath":"","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000},"locales":{},"darkmode":false,"themeConfig":{}};
const __uniRoutes = [{"path":"pages/Login/Login","meta":{"isQuit":true,"isEntry":true,"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"登录页面","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/Chat/Chat","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"聊天页面(主页面)","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/WorkSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"工作区文件管理","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/UserProfileModal/UserProfileModal","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/ContactPages/ContactPages","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/WorkSpace/TemplateSpace/TemplateSpace","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDatabase/CloudDatabase","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"云端数据","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/CloudDbDetail/CloudDbDetail","meta":{"titleNView":false,"bounce":"none","softinputMode":"adjustResize","navigationBar":{"titleText":"数据库详情","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/text/text","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}},{"path":"pages/text/IntuitiveAipptViewer","meta":{"navigationBar":{"titleText":"","type":"default"},"isNVue":false}},{"path":"pages/WYXD/WYXD","meta":{"titleNView":false,"bounce":"none","navigationBar":{"titleText":"","style":"custom","type":"default"},"isNVue":false}}].map(uniRoute=>(uniRoute.meta.route=uniRoute.path,__uniConfig.pages.push(uniRoute.path),uniRoute.path='/'+uniRoute.path,uniRoute));
__uniConfig.styles=[];//styles
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"iPad"
],
"id": "__UNI__923FD9E",
"name": "test1",
"name": "宇恒一号",
"version": {
"name": "1.1.1",
"code": 2

View File

@@ -1006,10 +1006,12 @@ to { opacity: 1; transform: translateY(0) scale(1);
font-size: 1.125rem;
font-weight: 700;
color: #1a1a2e;
align-items: center;
}
.ncd-header uni-icons[data-v-5eb7b895] {
display: flex;
flex-shrink: 0;
align-items: center;
}
.ncd-options[data-v-5eb7b895] {
display: flex;
@@ -1094,6 +1096,171 @@ to { opacity: 1; transform: translateY(0) scale(1);
.ncd-intelligence .ncd-opt-icon[data-v-5eb7b895] {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
}
/* ========== 智能体选择弹窗 ========== */
.agent-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: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.agent-modal[data-v-5eb7b895] {
width: 85%;
max-height: 70%;
background-color: #ffffff;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.agent-modal-header[data-v-5eb7b895] {
display: flex;
justify-content: center;
align-items: center;
padding: 0.9375rem 0.9375rem 0.625rem;
position: relative;
border-bottom: 0.0625rem solid #f0f0f0;
}
.agent-modal-title[data-v-5eb7b895] {
font-size: 1.0625rem;
font-weight: 700;
color: #1a1a2e;
}
.agent-modal-close[data-v-5eb7b895] {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
padding: 0.3125rem;
}
.agent-list[data-v-5eb7b895] {
box-sizing: border-box;
flex: 1;
padding: 0.625rem 0.75rem;
max-height: 18.75rem;
}
.agent-loading[data-v-5eb7b895] {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.875rem 0;
}
.agent-loading-text[data-v-5eb7b895] {
margin-top: 0.5rem;
font-size: 0.8125rem;
color: #999;
}
.agent-empty[data-v-5eb7b895] {
display: flex;
align-items: center;
justify-content: center;
padding: 2.5rem 0;
}
.agent-empty-text[data-v-5eb7b895] {
font-size: 0.875rem;
color: #999;
}
.agent-card[data-v-5eb7b895] {
box-sizing: border-box;
width: 100%;
background: linear-gradient(135deg, #f8f5ff, #efe8ff);
border: 0.0625rem solid #c4b5fd;
border-radius: 0.625rem;
padding: 0.875rem 0.75rem;
margin-bottom: 0.625rem;
transition: all 0.2s ease;
overflow: hidden;
}
.agent-card[data-v-5eb7b895]:active {
transform: scale(0.98);
border-color: #a78bfa;
background: linear-gradient(135deg, #f3efff, #e8dcff);
}
.agent-card-header[data-v-5eb7b895] {
display: flex;
align-items: center;
margin-bottom: 0.5rem;
}
.agent-avatar[data-v-5eb7b895] {
width: 2.1875rem;
height: 2.1875rem;
border-radius: 0.625rem;
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.agent-card-info[data-v-5eb7b895] {
margin-left: 0.5rem;
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
}
.agent-card-title[data-v-5eb7b895] {
font-size: 0.9375rem;
font-weight: 600;
color: #1a1a2e;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.agent-card-category[data-v-5eb7b895] {
font-size: 0.6875rem;
color: #8b5cf6;
margin-top: 0.125rem;
}
.agent-card-desc[data-v-5eb7b895] {
font-size: 0.8125rem;
color: #555;
line-height: 1.5;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-card-welcome[data-v-5eb7b895] {
font-size: 0.75rem;
color: #7c3aed;
margin-top: 0.375rem;
padding-top: 0.375rem;
border-top: 0.0625rem dashed #ddd6fe;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-modal-footer[data-v-5eb7b895] {
padding: 0.625rem 0.9375rem 0.9375rem;
border-top: 0.0625rem solid #f0f0f0;
display: flex;
justify-content: flex-end;
}
.agent-modal-btn[data-v-5eb7b895] {
padding: 0.5625rem 1.5rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
}
.agent-modal-btn-cancel[data-v-5eb7b895] {
background: #f0f0f0;
color: #666;
}
.agent-modal-btn-cancel[data-v-5eb7b895]:active {
background: #e0e0e0;
}
/* ==========新建聊天列表相关====== */
.close-option-card[data-v-5eb7b895] {
width: 100%;
@@ -1186,12 +1353,64 @@ to { opacity: 1; transform: translateY(0) scale(1);
.head-btn .iconfont[data-v-5eb7b895] {
font-size: 1.5rem;
}
.chat-btn-group .head-btn[data-v-5eb7b895]:nth-child(4) {
/* 刷新按钮 */
}
.log-out[data-v-5eb7b895] {
/* background: #ffd4d4; */
}
.log-out .iconfont[data-v-5eb7b895] {
color: #ff4d4f;
}
/* ==========WYXD 文件入口横幅========== */
.wyxd-banner[data-v-5eb7b895] {
display: flex;
align-items: center;
padding: 0.4375rem 0.75rem;
margin: 0.1875rem 0.625rem;
background: linear-gradient(135deg, #e8f4fd, #f0e6ff);
border: 0.04688rem solid rgba(120, 120, 220, 0.25);
border-radius: 0.5rem;
box-shadow: 0 0.0625rem 0.25rem rgba(100, 100, 200, 0.08);
}
.wyxd-banner[data-v-5eb7b895]:active {
background: linear-gradient(135deg, #d8eafb, #e6d8ff);
transform: scale(0.98);
}
.wyxd-banner-icon[data-v-5eb7b895] {
font-size: 1rem;
color: #6c6ce0;
margin-right: 0.375rem;
}
.wyxd-banner-text[data-v-5eb7b895] {
flex: 1;
font-size: 0.8125rem;
font-weight: 600;
color: #4a4ab8;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wyxd-banner-arrow[data-v-5eb7b895] {
font-size: 0.75rem;
color: #9999cc;
}
.wyxd-banner-close[data-v-5eb7b895] {
width: 1.125rem;
height: 1.125rem;
line-height: 1.125rem;
text-align: center;
font-size: 0.875rem;
color: #9999cc;
border-radius: 50%;
background: rgba(100, 100, 200, 0.08);
margin-left: 0.25rem;
flex-shrink: 0;
}
.wyxd-banner-close[data-v-5eb7b895]:active {
background: rgba(100, 100, 200, 0.18);
color: #6c6ce0;
}
/* ==========聊天主体部分========== */
.main-chat[data-v-5eb7b895] {
display: flex;
@@ -1658,44 +1877,57 @@ to { opacity: 1; transform: translateY(0);
/* 气泡内容字体:确保 v-html 渲染的 markdown 内容使用系统字体栈 */
.chat-content {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "HarmonyOS Sans", "MiSans", "Source Han Sans CN", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif !important;
font-size: 16px !important;
font-weight: 600 !important;
line-height: 1.6;
margin: 0.25rem 0;
font-size: 0.9375rem !important;
line-height: 1.5rem !important;
margin: 0.25rem 0 !important;
/* 普通正文 */
/* 粗体和斜体样式 */
/* 气泡内的内联链接(替代 <a> 标签,点击由 JS 拦截处理) */
/* 可下载文件链接 → 按钮卡片样式 */
}
.chat-content h1 {
font-size: 1.3125rem;
line-height: 1.4;
margin: 0.5rem 0 0.3125rem;
font-size: 1.0625rem !important;
font-weight: 600 !important;
line-height: 1.75rem !important;
margin: 0.6875rem 0 0.4375rem !important;
}
.chat-content h2 {
font-size: 1.1875rem;
line-height: 1.4;
margin: 0.4375rem 0 0.25rem;
font-size: 1rem !important;
font-weight: 600 !important;
line-height: 1.625rem !important;
margin: 0.5625rem 0 0.3125rem !important;
}
.chat-content h3 {
font-size: 1.125rem;
line-height: 1.4;
margin: 0.375rem 0 0.25rem;
font-size: 0.9375rem !important;
font-weight: 600 !important;
line-height: 1.5rem !important;
margin: 0.4375rem 0 0.1875rem !important;
}
.chat-content h4 {
font-size: 0.875rem !important;
font-weight: 600 !important;
line-height: 1.5rem !important;
margin: 0.4375rem 0 0.1875rem !important;
}
.chat-content h5 {
font-size: 0.8125rem !important;
font-weight: 600 !important;
line-height: 1.375rem !important;
margin: 0.3125rem 0 0.125rem !important;
}
.chat-content h4,
.chat-content h5,
.chat-content h6 {
font-size: 1.0625rem;
line-height: 1.5;
margin: 0.3125rem 0 0.1875rem;
font-size: 0.75rem !important;
font-weight: 600 !important;
line-height: 1.25rem !important;
margin: 0.3125rem 0 0.125rem !important;
}
.chat-content p,
.chat-content uni-text,
.chat-content span {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "HarmonyOS Sans", "MiSans", "Source Han Sans CN", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif !important;
font-size: 1.1875rem !important;
font-weight: 400 !important;
line-height: 1.6;
margin: 0.25rem 0;
font-size: 0.9375rem !important;
line-height: 1.5rem !important;
margin: 0.25rem 0 !important;
}
.chat-content strong,
.chat-content b {
@@ -1710,6 +1942,38 @@ to { opacity: 1; transform: translateY(0);
text-decoration: underline;
word-break: break-all;
}
.chat-content .chat-download-btn {
display: inline-flex !important;
align-items: center;
gap: 0.25rem;
padding: 0.25rem 0.4375rem;
margin: 0.125rem 0;
background: #f5f7fb;
border: 0.0625rem solid #e4e8f0;
border-radius: 0.25rem;
text-decoration: none !important;
color: #333 !important;
word-break: break-all;
transition: all 0.15s ease;
}
.chat-content .chat-download-btn:active {
background: #eef1f7;
border-color: #c8cde0;
transform: scale(0.98);
}
.chat-content .chat-download-btn .chat-dl-icon {
font-size: 0.8125rem !important;
line-height: 1;
flex-shrink: 0;
}
.chat-content .chat-download-btn .chat-dl-name {
font-size: 16px !important;
font-weight: 500;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 流式气泡中的加载动画 */
.bubble-loading-dots {

View File

@@ -333,6 +333,146 @@
.workspace-footer .iconfont[data-v-507487c4] {
font-size: 1.25rem !important;
}
/* ===== 标签切换 ===== */
.workspace-tabs[data-v-507487c4] {
display: flex;
width: 100%;
padding: 0 0.75rem;
box-sizing: border-box;
gap: 0.625rem;
}
.tab-item[data-v-507487c4] {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 0.5625rem 0;
font-size: 0.875rem;
font-weight: 500;
color: #999;
border-bottom: 0.125rem solid transparent;
transition: all 0.2s ease;
position: relative;
}
.tab-item.active[data-v-507487c4] {
color: #6c63ff;
border-bottom-color: #6c63ff;
}
.tab-badge[data-v-507487c4] {
margin-left: 0.25rem;
background: #ff5e57;
color: #fff;
font-size: 0.625rem;
padding: 0.0625rem 0.3125rem;
border-radius: 0.625rem;
line-height: 1.4;
}
/* ===== 下载列表 ===== */
.download-content[data-v-507487c4] {
flex: 1;
overflow: auto;
}
.download-empty[data-v-507487c4] {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 6.25rem;
color: #bbb;
font-size: 0.875rem;
}
.download-empty .iconfont[data-v-507487c4] {
font-size: 4.375rem;
color: #ddd;
margin-bottom: 0.625rem;
}
.download-list[data-v-507487c4] {
padding: 0.625rem 0.75rem;
}
.download-header[data-v-507487c4] {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.375rem 0.25rem 0.625rem;
font-size: 0.75rem;
color: #999;
}
.clear-btn[data-v-507487c4] {
color: #ff5e57;
font-size: 0.75rem;
font-weight: 500;
padding: 0.125rem 0.375rem;
}
.download-item[data-v-507487c4] {
display: flex;
align-items: center;
padding: 0.75rem 0.625rem;
background: rgba(255, 255, 255, 0.85);
border-radius: 0.625rem;
margin-bottom: 0.5rem;
transition: all 0.15s ease;
}
.download-item[data-v-507487c4]:active {
transform: scale(0.98);
background: rgba(255, 255, 255, 0.95);
}
.di-icon[data-v-507487c4] {
width: 2.5rem;
height: 2.5rem;
display: flex;
justify-content: center;
align-items: center;
background: rgba(108, 99, 255, 0.08);
border-radius: 0.5625rem;
margin-right: 0.625rem;
flex-shrink: 0;
}
.di-icon .iconfont[data-v-507487c4] {
font-size: 1.25rem;
color: #6c63ff;
}
.di-info[data-v-507487c4] {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.1875rem;
min-width: 0;
}
.di-name[data-v-507487c4] {
font-size: 0.875rem;
font-weight: 500;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-meta[data-v-507487c4] {
font-size: 0.6875rem;
color: #999;
}
.di-path[data-v-507487c4] {
font-size: 0.625rem;
color: #bbb;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-delete[data-v-507487c4] {
width: 1.75rem;
height: 1.75rem;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.di-delete .iconfont[data-v-507487c4] {
font-size: 1.125rem;
color: #ccc;
transition: color 0.15s ease;
}
.di-delete:active .iconfont[data-v-507487c4] {
color: #ff5e57;
}
.wyxd-container[data-v-507487c4] {
display: flex;
flex-direction: column;
@@ -378,7 +518,11 @@
.wyxd-slide-area[data-v-507487c4] {
flex: 1;
min-height: 0;
padding: 0.625rem;
/* padding: 20rpx; */
}
.wyxd-swiper[data-v-507487c4] {
width: 100%;
height: 100%;
}
.wyxd-slide-scroll[data-v-507487c4] {
height: 100%;
@@ -386,10 +530,18 @@
border-radius: 0.375rem;
box-shadow: 0 0.0625rem 0.375rem rgba(0, 0, 0, 0.04);
}
.wyxd-slide-card[data-v-507487c4] {
padding: 1rem;
/* .wyxd-slide-card {
padding: 32rpx;
min-height: 100%;
box-sizing: border-box;
} */
.wyxd-slide-card[data-v-507487c4] {
min-height: 100%;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column; /* 子元素垂直排列 */
}
/* ===== 底部翻页 ===== */
.wyxd-pager[data-v-507487c4] {

View File

@@ -333,6 +333,146 @@
.workspace-footer .iconfont[data-v-769edd25] {
font-size: 1.25rem !important;
}
/* ===== 标签切换 ===== */
.workspace-tabs[data-v-769edd25] {
display: flex;
width: 100%;
padding: 0 0.75rem;
box-sizing: border-box;
gap: 0.625rem;
}
.tab-item[data-v-769edd25] {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 0.5625rem 0;
font-size: 0.875rem;
font-weight: 500;
color: #999;
border-bottom: 0.125rem solid transparent;
transition: all 0.2s ease;
position: relative;
}
.tab-item.active[data-v-769edd25] {
color: #6c63ff;
border-bottom-color: #6c63ff;
}
.tab-badge[data-v-769edd25] {
margin-left: 0.25rem;
background: #ff5e57;
color: #fff;
font-size: 0.625rem;
padding: 0.0625rem 0.3125rem;
border-radius: 0.625rem;
line-height: 1.4;
}
/* ===== 下载列表 ===== */
.download-content[data-v-769edd25] {
flex: 1;
overflow: auto;
}
.download-empty[data-v-769edd25] {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 6.25rem;
color: #bbb;
font-size: 0.875rem;
}
.download-empty .iconfont[data-v-769edd25] {
font-size: 4.375rem;
color: #ddd;
margin-bottom: 0.625rem;
}
.download-list[data-v-769edd25] {
padding: 0.625rem 0.75rem;
}
.download-header[data-v-769edd25] {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.375rem 0.25rem 0.625rem;
font-size: 0.75rem;
color: #999;
}
.clear-btn[data-v-769edd25] {
color: #ff5e57;
font-size: 0.75rem;
font-weight: 500;
padding: 0.125rem 0.375rem;
}
.download-item[data-v-769edd25] {
display: flex;
align-items: center;
padding: 0.75rem 0.625rem;
background: rgba(255, 255, 255, 0.85);
border-radius: 0.625rem;
margin-bottom: 0.5rem;
transition: all 0.15s ease;
}
.download-item[data-v-769edd25]:active {
transform: scale(0.98);
background: rgba(255, 255, 255, 0.95);
}
.di-icon[data-v-769edd25] {
width: 2.5rem;
height: 2.5rem;
display: flex;
justify-content: center;
align-items: center;
background: rgba(108, 99, 255, 0.08);
border-radius: 0.5625rem;
margin-right: 0.625rem;
flex-shrink: 0;
}
.di-icon .iconfont[data-v-769edd25] {
font-size: 1.25rem;
color: #6c63ff;
}
.di-info[data-v-769edd25] {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.1875rem;
min-width: 0;
}
.di-name[data-v-769edd25] {
font-size: 0.875rem;
font-weight: 500;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-meta[data-v-769edd25] {
font-size: 0.6875rem;
color: #999;
}
.di-path[data-v-769edd25] {
font-size: 0.625rem;
color: #bbb;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-delete[data-v-769edd25] {
width: 1.75rem;
height: 1.75rem;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.di-delete .iconfont[data-v-769edd25] {
font-size: 1.125rem;
color: #ccc;
transition: color 0.15s ease;
}
.di-delete:active .iconfont[data-v-769edd25] {
color: #ff5e57;
}
/* 编辑模板弹窗 */
.edit-template-wrapper[data-v-769edd25] {
}

View File

@@ -865,3 +865,143 @@
.workspace-footer .iconfont[data-v-c1a60359] {
font-size: 1.25rem !important;
}
/* ===== 标签切换 ===== */
.workspace-tabs[data-v-c1a60359] {
display: flex;
width: 100%;
padding: 0 0.75rem;
box-sizing: border-box;
gap: 0.625rem;
}
.tab-item[data-v-c1a60359] {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 0.5625rem 0;
font-size: 0.875rem;
font-weight: 500;
color: #999;
border-bottom: 0.125rem solid transparent;
transition: all 0.2s ease;
position: relative;
}
.tab-item.active[data-v-c1a60359] {
color: #6c63ff;
border-bottom-color: #6c63ff;
}
.tab-badge[data-v-c1a60359] {
margin-left: 0.25rem;
background: #ff5e57;
color: #fff;
font-size: 0.625rem;
padding: 0.0625rem 0.3125rem;
border-radius: 0.625rem;
line-height: 1.4;
}
/* ===== 下载列表 ===== */
.download-content[data-v-c1a60359] {
flex: 1;
overflow: auto;
}
.download-empty[data-v-c1a60359] {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 6.25rem;
color: #bbb;
font-size: 0.875rem;
}
.download-empty .iconfont[data-v-c1a60359] {
font-size: 4.375rem;
color: #ddd;
margin-bottom: 0.625rem;
}
.download-list[data-v-c1a60359] {
padding: 0.625rem 0.75rem;
}
.download-header[data-v-c1a60359] {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.375rem 0.25rem 0.625rem;
font-size: 0.75rem;
color: #999;
}
.clear-btn[data-v-c1a60359] {
color: #ff5e57;
font-size: 0.75rem;
font-weight: 500;
padding: 0.125rem 0.375rem;
}
.download-item[data-v-c1a60359] {
display: flex;
align-items: center;
padding: 0.75rem 0.625rem;
background: rgba(255, 255, 255, 0.85);
border-radius: 0.625rem;
margin-bottom: 0.5rem;
transition: all 0.15s ease;
}
.download-item[data-v-c1a60359]:active {
transform: scale(0.98);
background: rgba(255, 255, 255, 0.95);
}
.di-icon[data-v-c1a60359] {
width: 2.5rem;
height: 2.5rem;
display: flex;
justify-content: center;
align-items: center;
background: rgba(108, 99, 255, 0.08);
border-radius: 0.5625rem;
margin-right: 0.625rem;
flex-shrink: 0;
}
.di-icon .iconfont[data-v-c1a60359] {
font-size: 1.25rem;
color: #6c63ff;
}
.di-info[data-v-c1a60359] {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.1875rem;
min-width: 0;
}
.di-name[data-v-c1a60359] {
font-size: 0.875rem;
font-weight: 500;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-meta[data-v-c1a60359] {
font-size: 0.6875rem;
color: #999;
}
.di-path[data-v-c1a60359] {
font-size: 0.625rem;
color: #bbb;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.di-delete[data-v-c1a60359] {
width: 1.75rem;
height: 1.75rem;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
}
.di-delete .iconfont[data-v-c1a60359] {
font-size: 1.125rem;
color: #ccc;
transition: color 0.15s ease;
}
.di-delete:active .iconfont[data-v-c1a60359] {
color: #ff5e57;
}

View File

@@ -1006,10 +1006,12 @@ to { opacity: 1; transform: translateY(0) scale(1);
font-size: 1.125rem;
font-weight: 700;
color: #1a1a2e;
align-items: center;
}
.ncd-header uni-icons[data-v-fdf84df1] {
display: flex;
flex-shrink: 0;
align-items: center;
}
.ncd-options[data-v-fdf84df1] {
display: flex;
@@ -1094,6 +1096,171 @@ to { opacity: 1; transform: translateY(0) scale(1);
.ncd-intelligence .ncd-opt-icon[data-v-fdf84df1] {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
}
/* ========== 智能体选择弹窗 ========== */
.agent-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: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.agent-modal[data-v-fdf84df1] {
width: 85%;
max-height: 70%;
background-color: #ffffff;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.agent-modal-header[data-v-fdf84df1] {
display: flex;
justify-content: center;
align-items: center;
padding: 0.9375rem 0.9375rem 0.625rem;
position: relative;
border-bottom: 0.0625rem solid #f0f0f0;
}
.agent-modal-title[data-v-fdf84df1] {
font-size: 1.0625rem;
font-weight: 700;
color: #1a1a2e;
}
.agent-modal-close[data-v-fdf84df1] {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-50%);
padding: 0.3125rem;
}
.agent-list[data-v-fdf84df1] {
box-sizing: border-box;
flex: 1;
padding: 0.625rem 0.75rem;
max-height: 18.75rem;
}
.agent-loading[data-v-fdf84df1] {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.875rem 0;
}
.agent-loading-text[data-v-fdf84df1] {
margin-top: 0.5rem;
font-size: 0.8125rem;
color: #999;
}
.agent-empty[data-v-fdf84df1] {
display: flex;
align-items: center;
justify-content: center;
padding: 2.5rem 0;
}
.agent-empty-text[data-v-fdf84df1] {
font-size: 0.875rem;
color: #999;
}
.agent-card[data-v-fdf84df1] {
box-sizing: border-box;
width: 100%;
background: linear-gradient(135deg, #f8f5ff, #efe8ff);
border: 0.0625rem solid #c4b5fd;
border-radius: 0.625rem;
padding: 0.875rem 0.75rem;
margin-bottom: 0.625rem;
transition: all 0.2s ease;
overflow: hidden;
}
.agent-card[data-v-fdf84df1]:active {
transform: scale(0.98);
border-color: #a78bfa;
background: linear-gradient(135deg, #f3efff, #e8dcff);
}
.agent-card-header[data-v-fdf84df1] {
display: flex;
align-items: center;
margin-bottom: 0.5rem;
}
.agent-avatar[data-v-fdf84df1] {
width: 2.1875rem;
height: 2.1875rem;
border-radius: 0.625rem;
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.agent-card-info[data-v-fdf84df1] {
margin-left: 0.5rem;
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
}
.agent-card-title[data-v-fdf84df1] {
font-size: 0.9375rem;
font-weight: 600;
color: #1a1a2e;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.agent-card-category[data-v-fdf84df1] {
font-size: 0.6875rem;
color: #8b5cf6;
margin-top: 0.125rem;
}
.agent-card-desc[data-v-fdf84df1] {
font-size: 0.8125rem;
color: #555;
line-height: 1.5;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-card-welcome[data-v-fdf84df1] {
font-size: 0.75rem;
color: #7c3aed;
margin-top: 0.375rem;
padding-top: 0.375rem;
border-top: 0.0625rem dashed #ddd6fe;
word-break: break-all;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.agent-modal-footer[data-v-fdf84df1] {
padding: 0.625rem 0.9375rem 0.9375rem;
border-top: 0.0625rem solid #f0f0f0;
display: flex;
justify-content: flex-end;
}
.agent-modal-btn[data-v-fdf84df1] {
padding: 0.5625rem 1.5rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
}
.agent-modal-btn-cancel[data-v-fdf84df1] {
background: #f0f0f0;
color: #666;
}
.agent-modal-btn-cancel[data-v-fdf84df1]:active {
background: #e0e0e0;
}
/* ==========新建聊天列表相关====== */
.close-option-card[data-v-fdf84df1] {
width: 100%;
@@ -1186,12 +1353,64 @@ to { opacity: 1; transform: translateY(0) scale(1);
.head-btn .iconfont[data-v-fdf84df1] {
font-size: 1.5rem;
}
.chat-btn-group .head-btn[data-v-fdf84df1]:nth-child(4) {
/* 刷新按钮 */
}
.log-out[data-v-fdf84df1] {
/* background: #ffd4d4; */
}
.log-out .iconfont[data-v-fdf84df1] {
color: #ff4d4f;
}
/* ==========WYXD 文件入口横幅========== */
.wyxd-banner[data-v-fdf84df1] {
display: flex;
align-items: center;
padding: 0.4375rem 0.75rem;
margin: 0.1875rem 0.625rem;
background: linear-gradient(135deg, #e8f4fd, #f0e6ff);
border: 0.04688rem solid rgba(120, 120, 220, 0.25);
border-radius: 0.5rem;
box-shadow: 0 0.0625rem 0.25rem rgba(100, 100, 200, 0.08);
}
.wyxd-banner[data-v-fdf84df1]:active {
background: linear-gradient(135deg, #d8eafb, #e6d8ff);
transform: scale(0.98);
}
.wyxd-banner-icon[data-v-fdf84df1] {
font-size: 1rem;
color: #6c6ce0;
margin-right: 0.375rem;
}
.wyxd-banner-text[data-v-fdf84df1] {
flex: 1;
font-size: 0.8125rem;
font-weight: 600;
color: #4a4ab8;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wyxd-banner-arrow[data-v-fdf84df1] {
font-size: 0.75rem;
color: #9999cc;
}
.wyxd-banner-close[data-v-fdf84df1] {
width: 1.125rem;
height: 1.125rem;
line-height: 1.125rem;
text-align: center;
font-size: 0.875rem;
color: #9999cc;
border-radius: 50%;
background: rgba(100, 100, 200, 0.08);
margin-left: 0.25rem;
flex-shrink: 0;
}
.wyxd-banner-close[data-v-fdf84df1]:active {
background: rgba(100, 100, 200, 0.18);
color: #6c6ce0;
}
/* ==========聊天主体部分========== */
.main-chat[data-v-fdf84df1] {
display: flex;

View File

@@ -29,7 +29,11 @@ export const login = async (username, password) => {
}
} else {
if (String(res.statusCode).startsWith('5')) {
reject({ serverError: true, code: res.statusCode, message: '服务器升级中,请稍后再试' })
reject({
serverError: true,
code: res.statusCode,
message: '服务器升级中,请稍后再试'
})
} else {
reject(`请求失败:${res.statusCode}`)
}
@@ -73,15 +77,16 @@ export const getUserConversations = async (token) => {
}
// 获取与AI的对话内容
export const getConversationMessages = async (token, conversatio_id) => {
export const getConversationMessages = async (token, conversation_id, size, page_number) => {
return new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}/get_conversation_messages`,
method: 'POST',
data: {
"access_token": token,
"login_type": "phone",
"conversation_id": conversatio_id
"conversation_id": conversation_id,
"size": 20,
"current": page_number
},
header: {
'Content-Type': 'application/json'
@@ -90,14 +95,15 @@ export const getConversationMessages = async (token, conversatio_id) => {
if (res.statusCode === 200) {
const messagesInfo = res.data
if (messagesInfo) {
// console.log("返回数据为",messagesInfo);
console.log("工作区id为", messagesInfo.workspace_id || '(无)');
if (messagesInfo.workspace_id) {
uni.setStorageSync('workspace_id', messagesInfo.workspace_id)
}
const filtered = (messagesInfo.messages || []).filter(
m => m.role !== 'tool'
)
resolve(filtered)
m => m.role !== 'tool'
)
resolve(filtered)
} else {
const msg = res.data.error || '获取消息出错啦'
reject(msg)
@@ -556,9 +562,9 @@ export const workspaceUploadFileByURL = (token, workspacesId, urls, dirPath) =>
const failedItems = (respond.results || [])
.filter(r => !r.success)
.map(r => r.error || '未知错误');
const msg = failedItems.length > 0
? `上传失败 ${respond.failed_count}/${respond.total_files}${failedItems[0]}`
: (respond.summary || respond?.error || '上传文件到工作区出错啦');
const msg = failedItems.length > 0 ?
`上传失败 ${respond.failed_count}/${respond.total_files}${failedItems[0]}` :
(respond.summary || respond?.error || '上传文件到工作区出错啦');
reject(msg);
}
} else {
@@ -585,14 +591,19 @@ export const uploadFileToShortStorage = (workspacesId, files, filePath) => {
// 构建 files 数组供 uni.uploadFile 使用
const uploadFiles = fileList.map((file) => {
const fileUri = typeof file === 'string' ? file : (file.tempFilePath || file.path || file);
const fileUri = typeof file === 'string' ? file : (file.tempFilePath || file.path ||
file);
return {
name: 'files',
uri: fileUri
};
});
console.log('uploadFileToShortStorage 参数:', { workspacesId, fileCount: uploadFiles.length, filePath });
console.log('uploadFileToShortStorage 参数:', {
workspacesId,
fileCount: uploadFiles.length,
filePath
});
uni.uploadFile({
url: `${BASE_URL}/cloud_api/file/temp/upload`,
@@ -614,9 +625,13 @@ export const uploadFileToShortStorage = (workspacesId, files, filePath) => {
resolve(respond);
} else if (respond.success) {
// 兼容 { success: true, url: "..." } 格式
resolve([{ url: respond.url || respond.message, success: true }]);
resolve([{
url: respond.url || respond.message,
success: true
}]);
} else {
const msg = respond?.error || respond?.message || '上传文件到短存云端获取URL出错啦';
const msg = respond?.error || respond?.message ||
'上传文件到短存云端获取URL出错啦';
reject(msg);
}
} catch (e) {
@@ -1718,3 +1733,80 @@ export const conversationMessageDownload = (token, workspacesId, localUrl) => {
});
});
};
// 智能体
// 获取智能体列表
export const getAgentList = (token) => {
return new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}/cloud_api/agent/list`,
method: "POST",
header: {
'Content-Type': 'application/json'
},
data: {
"access_token": token
},
success: (res) => {
if (res.statusCode === 200) {
const respond = res.data;
if (respond.success) {
resolve(respond.data)
} else {
const msg = '获取智能体列表出错啦';
reject(msg);
}
} else {
reject(`获取智能体列表失败:${res.statusCode}`)
}
},
fail: (err) => {
const msg = err.errMsg || '网络错误';
reject(msg);
}
})
})
}
// 创建智能体会话
export const addConversationAgent = (token, agent_id) => {
return new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}/cloud_api/phone/conversation/agent/add`,
method: "POST",
header: {
"Content-Type": "application/json"
},
data: {
"access_token": token,
"agent_id": agent_id
},
success: (res) => {
if (res.statusCode === 200) {
const respond = res.data
// 返回格式: { success: true, title: "...", conversation_id: "...", workspace_id: "..." }
if (respond?.success && respond?.conversation_id) {
// // 保存 workspace_id 到本地存储
// if (respond.workspace_id) {
// uni.setStorageSync('workspace_id', respond.workspace_id)
// }
resolve({
conversation_id: respond.conversation_id,
workspace_id: respond.workspace_id,
title: respond.title || ''
})
} else {
const msg = respond?.error || '创建智能体会话出错啦'
reject(msg)
}
} else {
reject(`创建智能体会话失败:${res.statusCode}`)
}
},
fail: (err) => {
const msg = err.errMsg || '网络错误'
reject(msg)
}
})
})
}

284
utils/downloadManager.js Normal file
View File

@@ -0,0 +1,284 @@
/**
* 下载管理工具
* 文件保存到公共下载目录,用户可通过文件管理器访问
*/
const STORAGE_KEY = 'localDownloads'
const SUB_DIR = 'AppDownloads' // 公共下载目录下的子文件夹
/**
* 获取公共下载目录路径
* @returns {Promise<string>} 下载目录绝对路径
*/
function getPublicDownloadDir() {
return new Promise((resolve, reject) => {
// #ifdef APP-PLUS
plus.io.requestFileSystem(
plus.io.PUBLIC_DOWNLOADS,
(fs) => {
// PUBLIC_DOWNLOADS 对应 /storage/emulated/0/Download/
fs.root.getDirectory(
SUB_DIR,
{ create: true },
(dirEntry) => {
resolve(dirEntry.fullPath)
},
(err) => {
console.error('getDirectory failed:', err)
reject(err)
}
)
},
(err) => {
console.error('requestFileSystem failed:', err)
reject(err)
}
)
// #endif
// #ifndef APP-PLUS
reject(new Error('仅APP端支持'))
// #endif
})
}
/**
* 从完整路径中提取可读的显示路径
* 如 /storage/emulated/0/Download/AppDownloads/xxx.pdf → 下载/AppDownloads/xxx.pdf
*/
function getDisplayPath(fullPath) {
const idx = fullPath.indexOf('/Download/')
if (idx !== -1) {
return '下载/' + fullPath.slice(idx + 10)
}
return fullPath
}
/**
* 获取所有下载记录
* @returns {Array} 下载记录列表
*/
export function getDownloadList() {
try {
return uni.getStorageSync(STORAGE_KEY) || []
} catch (e) {
return []
}
}
/**
* 保存下载记录(复制到公共下载目录)
* @param {string} tempFilePath 临时文件路径uni.downloadFile 返回的)
* @param {string} fileName 文件名
* @param {number} fileSize 文件大小(字节,可选)
*/
export function saveDownload(tempFilePath, fileName, fileSize) {
return new Promise((resolve, reject) => {
// #ifdef APP-PLUS
getPublicDownloadDir().then((dirPath) => {
const destPathForUrl = plus.io.convertLocalFileSystemURL(dirPath + '/' + fileName)
plus.io.resolveLocalFileSystemURL(
tempFilePath,
(fileEntry) => {
plus.io.resolveLocalFileSystemURL(
dirPath,
(dirEntry) => {
fileEntry.copyTo(
dirEntry,
fileName,
() => {
const record = {
id: Date.now().toString(),
name: fileName,
path: destPathForUrl,
displayPath: getDisplayPath(destPathForUrl),
size: fileSize || 0,
time: Date.now()
}
const list = getDownloadList()
const exists = list.some(item => item.name === fileName)
if (exists) {
const idx = list.findIndex(item => item.name === fileName)
if (idx !== -1) list.splice(idx, 1)
}
list.unshift(record)
try {
uni.setStorageSync(STORAGE_KEY, list)
} catch (e) {
list.pop()
uni.setStorageSync(STORAGE_KEY, list)
}
resolve(record)
},
(err) => {
console.error('copyTo failed:', err)
reject(err)
}
)
},
reject
)
},
reject
)
}).catch(reject)
// #endif
// #ifndef APP-PLUS
// 非 APP 端降级使用 uni.saveFile
uni.saveFile({
tempFilePath: tempFilePath,
success: (saveRes) => {
const record = {
id: Date.now().toString(),
name: fileName,
path: saveRes.savedFilePath,
size: fileSize || 0,
time: Date.now()
}
const list = getDownloadList()
list.unshift(record)
uni.setStorageSync(STORAGE_KEY, list)
resolve(record)
},
fail: reject
})
// #endif
})
}
/**
* 删除单条下载记录及其文件
* @param {string} id 记录 ID
*/
export function deleteDownload(id) {
return new Promise((resolve, reject) => {
const list = getDownloadList()
const record = list.find(item => item.id === id)
if (!record) {
reject(new Error('记录不存在'))
return
}
// #ifdef APP-PLUS
// 删除公共目录下的文件
plus.io.resolveLocalFileSystemURL(
record.path,
(fileEntry) => {
fileEntry.remove(
() => {
const newList = list.filter(item => item.id !== id)
uni.setStorageSync(STORAGE_KEY, newList)
resolve()
},
() => {
// 文件不存在也清除记录
const newList = list.filter(item => item.id !== id)
uni.setStorageSync(STORAGE_KEY, newList)
resolve()
}
)
},
() => {
// 无法解析路径,直接清除记录
const newList = list.filter(item => item.id !== id)
uni.setStorageSync(STORAGE_KEY, newList)
resolve()
}
)
// #endif
// #ifndef APP-PLUS
uni.removeSavedFile({
filePath: record.path,
success: () => {
const newList = list.filter(item => item.id !== id)
uni.setStorageSync(STORAGE_KEY, newList)
resolve()
},
fail: () => {
const newList = list.filter(item => item.id !== id)
uni.setStorageSync(STORAGE_KEY, newList)
resolve()
}
})
// #endif
})
}
/**
* 清空所有下载记录和文件
*/
export function clearAllDownloads() {
return new Promise((resolve) => {
const list = getDownloadList()
if (list.length === 0) {
resolve()
return
}
// #ifdef APP-PLUS
let count = 0
const done = () => {
count++
if (count >= list.length) {
uni.setStorageSync(STORAGE_KEY, [])
resolve()
}
}
list.forEach(record => {
plus.io.resolveLocalFileSystemURL(
record.path,
(fileEntry) => {
fileEntry.remove(done, done)
},
done
)
})
setTimeout(() => {
uni.setStorageSync(STORAGE_KEY, [])
resolve()
}, 5000)
// #endif
// #ifndef APP-PLUS
let count = 0
list.forEach(record => {
uni.removeSavedFile({
filePath: record.path,
success: () => { count++; if (count >= list.length) { uni.setStorageSync(STORAGE_KEY, []); resolve() } },
fail: () => { count++; if (count >= list.length) { uni.setStorageSync(STORAGE_KEY, []); resolve() } }
})
})
if (list.length === 0) resolve()
setTimeout(() => { uni.setStorageSync(STORAGE_KEY, []); resolve() }, 3000)
// #endif
})
}
/**
* 格式化文件大小为可读字符串
* @param {number} bytes 字节数
* @returns {string}
*/
export function formatFileSize(bytes) {
if (!bytes || bytes <= 0) return '未知大小'
const units = ['B', 'KB', 'MB', 'GB']
let i = 0
let size = bytes
while (size >= 1024 && i < units.length - 1) {
size /= 1024
i++
}
return size.toFixed(i === 0 ? 0 : 1) + ' ' + units[i]
}
/**
* 格式化时间戳为可读日期
* @param {number} timestamp
* @returns {string}
*/
export function formatTime(timestamp) {
const d = new Date(timestamp)
const pad = n => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

124
utils/fileOpener.js Normal file
View File

@@ -0,0 +1,124 @@
/**
* 文件打开工具 - 强制弹出应用选择器
*
* uni.openDocument 的 showMenu 和 plus.runtime.openFile 在真机上
* 都可能直接跳转默认应用。用 Android 原生 Intent.createChooser
* 强制弹出"选择应用"对话框。
*
* Android 7.0+ 会阻止 file:// URI 暴露给其他应用,需要禁用此限制。
*/
/**
* 根据文件扩展名获取 MIME 类型
*/
function getMimeType(filePath) {
const ext = filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase()
const mimeMap = {
'pdf': 'application/pdf',
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls': 'application/vnd.ms-excel',
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt': 'application/vnd.ms-powerpoint',
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'txt': 'text/plain',
'html': 'text/html',
'htm': 'text/html',
'xml': 'text/xml',
'json': 'application/json',
'csv': 'text/csv',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'bmp': 'image/bmp',
'webp': 'image/webp',
'mp4': 'video/mp4',
'mp3': 'audio/mpeg',
'wav': 'audio/wav',
'zip': 'application/zip',
'rar': 'application/x-rar-compressed',
'7z': 'application/x-7z-compressed',
'apk': 'application/vnd.android.package-archive'
}
return mimeMap[ext] || '*/*'
}
/**
* 打开文件,弹出应用选择器
* @param {string} filePath 本地文件路径
* @param {Function} onFail 打开失败时的回调
*/
export function openFile(filePath, onFail) {
// #ifdef APP-PLUS
try {
const main = plus.android.runtimeMainActivity()
const Intent = plus.android.importClass('android.content.Intent')
const Uri = plus.android.importClass('android.net.Uri')
const File = plus.android.importClass('java.io.File')
// Android 7.0+ 默认禁止 file:// URI禁用此限制
if (plus.os.sdkInt >= 24) {
const StrictMode = plus.android.importClass('android.os.StrictMode')
StrictMode.disableDeathOnFileUriExposure()
}
const file = new File(filePath)
if (!file.exists()) {
throw new Error('文件不存在: ' + filePath)
}
const uri = Uri.fromFile(file)
const mimeType = getMimeType(filePath)
const intent = new Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, mimeType)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// 核心createChooser 每次必弹选择器,无视已设置的默认应用
const chooser = Intent.createChooser(intent, '选择应用打开')
main.startActivity(chooser)
console.log('openFile success - chooser shown')
} catch (e) {
console.error('openFile native failed, fallback:', e)
uni.openDocument({
filePath: filePath,
showMenu: true,
fail: typeof onFail === 'function' ? onFail : () => {}
})
}
// #endif
// #ifndef APP-PLUS
uni.openDocument({
filePath: filePath,
showMenu: true,
fail: typeof onFail === 'function' ? onFail : () => {}
})
// #endif
}
/**
* 下载文件并打开(弹出应用选择器)
* @param {string} url 远程文件 URL
* @param {Function} onFail 失败回调
*/
export function downloadAndOpen(url, onFail) {
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
openFile(res.tempFilePath, onFail)
} else {
console.error('下载失败, statusCode:', res.statusCode)
if (typeof onFail === 'function') onFail()
}
},
fail: (err) => {
console.error('downloadFile fail:', err)
if (typeof onFail === 'function') onFail()
}
})
}

View File

@@ -84,7 +84,7 @@ export const getGroup = async (sendId) => {
}
// 获取与好友的对话内容
export const getFriendMessages = async (sessionId, current = 1) => {
export const getFriendMessages = async (sessionId, size, current = 1) => {
console.log('请求的好友消息id', sessionId);
return new Promise((resolve, reject) => {
uni.request({
@@ -92,7 +92,7 @@ export const getFriendMessages = async (sessionId, current = 1) => {
method: 'POST',
data: {
"sessionId": sessionId,
"size": 100,
"size": size,
"current": current,
"beginTime": "",
"endTime": ""
@@ -130,7 +130,7 @@ export const getFriendMessages = async (sessionId, current = 1) => {
// 获取群聊的对话内容
export const getGroupMessages = async (groupId, current = 1) => {
export const getGroupMessages = async (groupId, size, current = 1) => {
console.log('请求的群聊消息id', groupId);
return new Promise((resolve, reject) => {
uni.request({
@@ -138,7 +138,7 @@ export const getGroupMessages = async (groupId, current = 1) => {
method: 'POST',
data: {
"current": current,
"size": 100,
"size": size,
"groupId": groupId,
"beginTime": "",
"endTime": ""