From 488bebcc87b89e8c88f93a12ed04d3a290c05334 Mon Sep 17 00:00:00 2001 From: YiLin <482244139@qq.com> Date: Thu, 25 Jun 2026 17:48:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=91=E7=AB=AF=E6=96=87=E4=BB=B6=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages.json | 14 +- pages/Chat/Chat.vue | 76 +- pages/CloudDatabase/CloudDatabase.css | 669 +++++ pages/CloudDatabase/CloudDatabase.vue | 982 +++++++ pages/ContactPages/ContactPages.css | 20 +- pages/ContactPages/ContactPages.vue | 213 +- pages/UserProfileModal/UserProfileModal.vue | 61 +- static/iconfont/demo_index.html | 29 +- static/iconfont/iconfont.css | 10 +- static/iconfont/iconfont.js | 2 +- static/iconfont/iconfont.json | 7 + static/iconfont/iconfont.ttf | Bin 20564 -> 20808 bytes static/iconfont/iconfont.woff | Bin 10704 -> 10892 bytes static/iconfont/iconfont.woff2 | Bin 8820 -> 8976 bytes .../dist/dev/app-plus/app-config-service.js | 2 +- unpackage/dist/dev/app-plus/app-service.js | 2268 +++++++++++++++-- unpackage/dist/dev/app-plus/app.css | 9 +- .../pages/CloudDatabase/CloudDatabase.css | 1116 ++++++++ .../pages/ContactPages/ContactPages.css | 19 +- .../app-plus/static/iconfont/demo_index.html | 29 +- .../dev/app-plus/static/iconfont/iconfont.css | 10 +- .../dev/app-plus/static/iconfont/iconfont.js | 2 +- .../app-plus/static/iconfont/iconfont.json | 7 + .../dev/app-plus/static/iconfont/iconfont.ttf | Bin 20564 -> 20808 bytes .../app-plus/static/iconfont/iconfont.woff | Bin 10704 -> 10892 bytes .../app-plus/static/iconfont/iconfont.woff2 | Bin 8820 -> 8976 bytes utils/cloud-api.js | 201 +- utils/friend-api.js | 107 +- utils/friend-socket.js | 12 +- utils/socket.js | 3 +- 30 files changed, 5442 insertions(+), 426 deletions(-) create mode 100644 pages/CloudDatabase/CloudDatabase.css create mode 100644 pages/CloudDatabase/CloudDatabase.vue create mode 100644 unpackage/dist/dev/app-plus/pages/CloudDatabase/CloudDatabase.css diff --git a/pages.json b/pages.json index 0f693bd..57bec78 100644 --- a/pages.json +++ b/pages.json @@ -87,7 +87,19 @@ { "path" : "pages/text/text2", "style" : {} - } + }, + { + "path": "pages/CloudDatabase/CloudDatabase", + "style": { + "navigationBarTitleText": "云端数据", + "navigationStyle": "custom", + "app-plus": { + "titleNView": false, + "bounce": "none", + "softinputMode": "adjustResize" + } + } + } ], "uniIdRouter" : {}, "condition" : { diff --git a/pages/Chat/Chat.vue b/pages/Chat/Chat.vue index 12c5313..6212087 100644 --- a/pages/Chat/Chat.vue +++ b/pages/Chat/Chat.vue @@ -70,6 +70,9 @@ + + + @@ -80,24 +83,46 @@ - - - + + + - - - - - + + + + + + + + + + + + 📄 + {{ file.name }} + {{ formatFileSize(file.fileSize) }} + + + @@ -417,6 +442,22 @@ return size.toFixed(2) + 'MB' } + // 从消息 content 中提取文件信息 + // 格式: [文件信息:[{...}]] + const parseFileInfo = (content) => { + if (!content || typeof content !== 'string') return { textContent: content || '', files: [] } + const match = content.match(/\[文件信息:(\[.*?\])\]/) + if (!match) return { textContent: content, files: [] } + try { + const files = JSON.parse(match[1]) + const textContent = content.replace(match[0], '').trim() + return { textContent, files } + } catch (e) { + console.error('解析文件信息失败:', e) + return { textContent: content, files: [] } + } + } + @@ -483,6 +524,17 @@ url: '/pages/WorkSpace/WorkSpace' }) } + + // 跳转到云端数据库 + const goCloudDatabase = () => { + // 保存当前会话id,确保从工作区返回时能恢复 + if (currentSessionId.value) { + uni.setStorageSync('currentSessionId', currentSessionId.value) + } + uni.navigateTo({ + url: '/pages/CloudDatabase/CloudDatabase' + }) + } const logOut = () => { uni.reLaunch({ @@ -821,7 +873,7 @@ userToken.value = getToken(); console.log("token:", userToken.value); UserConversations.value = await getUserConversations(userToken.value) || []; - console.log("UserConversations:", UserConversations.value); + // console.log("UserConversations:", JSON.stringify(UserConversations.value) ); // 优先恢复已保存的会话id,避免刷新到列表第一个 const savedSessionId = getCurrentSessionId(); if (savedSessionId && UserConversations.value.some(c => c._id === savedSessionId)) { @@ -964,7 +1016,7 @@ const takeConversationMessages = async () => { try { allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || []; - // console.log("AI消息:", allmessages.value); + // console.log("AI消息:", JSON.stringify(allmessages.value) ); // currentMessages.value = allmessages.value.slice(-pageInfoNumber); // 数据获取后执行滚动 scrollToBottom(); diff --git a/pages/CloudDatabase/CloudDatabase.css b/pages/CloudDatabase/CloudDatabase.css new file mode 100644 index 0000000..d1595f5 --- /dev/null +++ b/pages/CloudDatabase/CloudDatabase.css @@ -0,0 +1,669 @@ + +.cloud-db-container { + display: flex; + flex-direction: column; + width: 100%; + height: 100vh; + background-color: #f5f6fa; +} + +.cloud-db-header { + flex-shrink: 0; + background-color: #ffffff; + padding-bottom: 0; +} + +.custom-navbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20rpx 30rpx; + box-sizing: border-box; + position: relative; +} + +.navbar-left { + display: flex; + align-items: center; + min-width: 160rpx; +} + +.custom-navbar-icon { + font-size: 44rpx; + color: #333; +} + +.navbar-title { + font-size: 36rpx; + font-weight: 600; + color: #1a1a2e; +} + +.navbar-right { + width: auto; + min-width: 80rpx; + display: flex; + align-items: center; + justify-content: flex-end; +} + +.navbar-before-title { + font-size: 26rpx; + color: #3b86ff; + margin-left: 8rpx; +} + +.navbar-right-text { + font-size: 28rpx; + color: #3b86ff; + font-weight: 500; +} + +/* 菜单 */ +.menu-open { + color: #3b86ff; +} + +.menu-card { + position: absolute; + top: 80rpx; + right: 20rpx; + background: #fff; + border-radius: 16rpx; + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); + padding: 12rpx 0; + z-index: 100; + min-width: 200rpx; +} + +.menu-card-item { + padding: 20rpx 32rpx; + font-size: 28rpx; + color: #333; +} + +.menu-card-item:active { + background: #f5f6fa; +} + +.solid-line { + height: 1rpx; + background: #eee; + margin: 4rpx 20rpx; +} + +.file-count { + font-size: 24rpx; + color: #999; + font-weight: 400; +} + +/* 分类切换 Tab */ +.category-tabs { + display: flex; + padding: 10rpx 30rpx 0; + gap: 40rpx; + border-bottom: 2rpx solid #eee; +} + +.category-tab { + font-size: 30rpx; + color: #999; + padding-bottom: 20rpx; + position: relative; + font-weight: 500; + transition: color 0.3s; +} + +.category-tab.active { + color: #3b86ff; + font-weight: 600; +} + +.category-tab.active::after { + content: ''; + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: 48rpx; + height: 6rpx; + background: #3b86ff; + border-radius: 3rpx; +} + +/* 内容区域 */ +.cloud-db-content { + flex: 1; + min-height: 0; + padding: 20rpx 30rpx; + box-sizing: border-box; +} + +/* 区块 */ +.section-block { + background: #ffffff; + border-radius: 20rpx; + padding: 24rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); +} + +.section-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; +} + +.section-title { + display: flex; + align-items: center; + gap: 12rpx; + font-size: 32rpx; + font-weight: 600; + color: #1a1a2e; +} + +.section-title .iconfont { + font-size: 36rpx; + color: #3b86ff; +} + +.section-actions { + display: flex; + align-items: center; + gap: 10rpx; +} + +.action-btn { + display: flex; + align-items: center; + gap: 6rpx; + padding: 10rpx 20rpx; + background: rgba(59, 134, 255, 0.08); + color: #3b86ff; + border-radius: 30rpx; + font-size: 24rpx; + font-weight: 500; +} + +.section-divider { + height: 2rpx; + margin: 4rpx 0 20rpx; +} + +/* 空状态 */ +.empty-tip { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60rpx 0; + color: #bbb; + font-size: 26rpx; + gap: 16rpx; +} + +.empty-tip .iconfont { + font-size: 80rpx; + color: #ddd; +} + +/* 文件网格 */ +.file-grid { + display: flex; + flex-wrap: wrap; + gap: 16rpx; +} + +.file-item { + width: calc(33.33% - 12rpx); + display: flex; + flex-direction: column; + align-items: center; + padding: 20rpx 10rpx; + border-radius: 16rpx; + background: #f8f9fc; + border: 2rpx solid transparent; + transition: all 0.2s; + box-sizing: border-box; +} + +.file-item:active { + border-color: #3b86ff; + background: rgba(59, 134, 255, 0.04); +} + +.file-icon { + width: 80rpx; + height: 80rpx; + display: flex; + align-items: center; + justify-content: center; + border-radius: 16rpx; + margin-bottom: 10rpx; +} + +.file-icon.is-directory { + background: rgba(255, 170, 0, 0.12); +} + +.file-icon.is-directory .iconfont { + font-size: 48rpx; + color: #ffa500; +} + +.file-icon.is-file { + background: rgba(59, 134, 255, 0.1); +} + +.file-icon.is-file .iconfont { + font-size: 44rpx; + color: #3b86ff; +} + +.file-name { + font-size: 24rpx; + color: #333; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; + margin-bottom: 6rpx; +} + +.file-meta { + display: flex; + gap: 8rpx; + align-items: center; +} + +.file-type-tag { + font-size: 20rpx; + color: #999; + background: #f0f0f0; + padding: 2rpx 10rpx; + border-radius: 8rpx; +} + +.file-size { + font-size: 20rpx; + color: #bbb; +} + +/* 数据表列表 */ +.table-list { + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.table-item { + display: flex; + align-items: center; + padding: 20rpx; + border-radius: 14rpx; + background: #f8f9fc; + border: 2rpx solid transparent; + transition: all 0.2s; +} + +.table-item:active { + border-color: #3b86ff; + background: rgba(59, 134, 255, 0.03); +} + +.table-icon { + width: 64rpx; + height: 64rpx; + display: flex; + align-items: center; + justify-content: center; + background: rgba(59, 134, 255, 0.08); + border-radius: 14rpx; + margin-right: 20rpx; + flex-shrink: 0; +} + +.table-info { + flex: 1; + min-width: 0; +} + +.table-name { + font-size: 28rpx; + font-weight: 600; + color: #1a1a2e; + margin-bottom: 4rpx; +} + +.table-desc { + font-size: 22rpx; + color: #999; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.table-meta { + display: flex; + align-items: center; + gap: 6rpx; + flex-shrink: 0; +} + +.table-rows { + font-size: 22rpx; + color: #bbb; +} + +/* 团队管理 */ +.team-manage-block { + cursor: pointer; +} + +.team-count { + font-size: 24rpx; + color: #999; +} + +.team-selector { + padding: 0 0 20rpx; +} + +.team-scroll { + white-space: nowrap; +} + +.team-chip { + display: inline-block; + padding: 12rpx 28rpx; + margin-right: 16rpx; + border-radius: 30rpx; + font-size: 26rpx; + color: #666; + background: #f0f2f5; + transition: all 0.2s; +} + +.team-chip.active { + color: #fff; + background: #3b86ff; + font-weight: 500; +} + +.select-team-tip { + padding: 80rpx 0; +} + +/* ===== 弹窗样式 ===== */ +.popup-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.4); + z-index: 999; + display: flex; + align-items: center; + justify-content: center; +} + +.popup-card { + width: 600rpx; + background: #fff; + border-radius: 30rpx; + padding: 40rpx 30rpx; + box-sizing: border-box; + position: relative; + max-height: 80vh; + display: flex; + flex-direction: column; +} + +.close-popup-card { + position: absolute; + top: 20rpx; + right: 20rpx; + width: 50rpx; + height: 50rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.close-popup-card .iconfont { + font-size: 40rpx; + color: #999; +} + +.popup-title { + font-size: 34rpx; + font-weight: 600; + color: #1a1a2e; + margin-bottom: 30rpx; + text-align: center; +} + +.new-folder-name { + font-size: 26rpx; + color: #666; + margin-bottom: 10rpx; +} + +.create-folder-name { + margin-bottom: 20rpx; +} + +.create-folder-name input { + width: 100%; + height: auto; + padding: 20rpx; + box-sizing: border-box; + border: 1rpx solid #e0e0e0; + border-radius: 16rpx; + font-size: 28rpx; + background: #f9fafb; +} + +.create-folder-name input:focus { + border-color: #3b86ff; + background: #fff; +} + +.nf-path-label { + font-size: 24rpx; + color: #999; + margin-bottom: 8rpx; +} + +.nf-path-display { + font-size: 24rpx; + color: #3b86ff; + background: rgba(59, 134, 255, 0.06); + padding: 12rpx 16rpx; + border-radius: 10rpx; + margin-bottom: 20rpx; +} + +.option-wrapper { + display: flex; + gap: 20rpx; + justify-content: flex-end; + margin-top: 10rpx; +} + +.opt-btn { + padding: 16rpx 40rpx; + border-radius: 30rpx; + font-size: 28rpx; + font-weight: 500; +} + +.opt-cancel { + color: #999; + background: #f0f2f5; +} + +.opt-confirm { + color: #fff; + background: #3b86ff; +} + +/* 团队管理弹窗 */ +.team-manage-body { + flex: 1; + min-height: 0; + max-height: 500rpx; + margin-bottom: 20rpx; +} + +.member-list { + display: flex; + flex-direction: column; + gap: 10rpx; +} + +.member-item { + display: flex; + align-items: center; + padding: 16rpx; + border-radius: 14rpx; + background: #f8f9fc; +} + +.member-avatar { + width: 70rpx; + height: 70rpx; + border-radius: 50%; + overflow: hidden; + margin-right: 16rpx; + flex-shrink: 0; +} + +.member-avatar image { + width: 100%; + height: 100%; +} + +.default-avatar { + width: 100%; + height: 100%; + background: #ccc; + display: flex; + align-items: center; + justify-content: center; +} + +.member-info { + flex: 1; + min-width: 0; +} + +.member-name { + font-size: 28rpx; + font-weight: 500; + color: #333; +} + +.member-label { + font-size: 22rpx; + color: #999; + margin-top: 4rpx; +} + +.member-actions { + flex-shrink: 0; +} + +.member-role { + font-size: 22rpx; + padding: 6rpx 16rpx; + border-radius: 20rpx; +} + +.member-role.owner { + color: #e6a23c; + background: rgba(230, 162, 60, 0.1); +} + +.member-role.admin { + color: #3b86ff; + background: rgba(59, 134, 255, 0.1); +} + +.member-actions-right { + display: flex; + gap: 8rpx; +} + +.member-action-btn { + font-size: 20rpx; + padding: 8rpx 14rpx; + border-radius: 16rpx; +} + +.set-admin { + color: #3b86ff; + border: 1rpx solid #3b86ff; +} + +.remove-member { + color: #f56c6c; + border: 1rpx solid #f56c6c; +} + +.invite-section { + border-top: 1rpx solid #eee; + padding-top: 20rpx; +} + +.invite-input-wrapper { + display: flex; + align-items: center; + gap: 16rpx; +} + +.invite-input { + flex: 1; + height: auto; + padding: 18rpx 20rpx; + box-sizing: border-box; + border: 1rpx solid #e0e0e0; + border-radius: 30rpx; + font-size: 26rpx; + background: #f9fafb; +} + +.invite-btn { + background: #3b86ff; + color: #fff; + font-size: 24rpx; + padding: 14rpx 32rpx; +} + +.folder-null { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60rpx 0; + color: #bbb; + font-size: 26rpx; + gap: 12rpx; +} + +.folder-null .iconfont { + font-size: 64rpx; + color: #ddd; +} + +.text-btn { + padding: 8rpx 20rpx; + border-radius: 30rpx; + font-size: 14px; + font-weight: 500; +} \ No newline at end of file diff --git a/pages/CloudDatabase/CloudDatabase.vue b/pages/CloudDatabase/CloudDatabase.vue new file mode 100644 index 0000000..bdbbb8d --- /dev/null +++ b/pages/CloudDatabase/CloudDatabase.vue @@ -0,0 +1,982 @@ + + + + + diff --git a/pages/ContactPages/ContactPages.css b/pages/ContactPages/ContactPages.css index 4cfafed..39f3c5e 100644 --- a/pages/ContactPages/ContactPages.css +++ b/pages/ContactPages/ContactPages.css @@ -350,15 +350,27 @@ align-items: center; } -.agree-btn, -.refuse-btn { +.agree-btn { font-size: 14px; font-weight: 500; - border: 1px solid #666; - margin-left: 10rpx; + border: 1px solid #3b86ff; + color: #3b86ff; box-sizing: border-box; } +/* 好友申请状态 */ +.friend-status { + font-size: 14px; + font-weight: 500; + padding: 8rpx 20rpx; + border-radius: 30rpx; +} + +.friend-status.agreed { + color: #059669; + background-color: rgba(16, 185, 129, 0.1); +} + /* 通讯录 */ .contact-list { diff --git a/pages/ContactPages/ContactPages.vue b/pages/ContactPages/ContactPages.vue index b121852..1c7e7e5 100644 --- a/pages/ContactPages/ContactPages.vue +++ b/pages/ContactPages/ContactPages.vue @@ -9,7 +9,13 @@ {{isAgreeBeFriend ? '通过好友申请' : '申请添加朋友'}} - {{currentAddFriend.avatar}} + + + + + + {{currentAddFriend.username}} @@ -18,9 +24,9 @@ 好友备注 - + - {{isAgreeBeFriend ? '确认通过' : '发送申请'}} + {{isAgreeBeFriend ? '确认通过' : '发送申请'}} @@ -158,7 +164,7 @@ + v-model="searchFriendName" confirm-type="search" @confirm="searchFriend"/> 请输入用户名或邮箱进行搜索 @@ -167,13 +173,16 @@ - {{friend.avatar}} + + + + {{friend.nickname}} {{friend.email}} - + 添加 @@ -218,7 +227,7 @@ friend.nickname friend.email - + 添加 @@ -258,24 +267,28 @@ 好友申请 - + 暂无好友申请 + - + - {{friend.avatar}} - - - {{friend.nickname}} - {{friend.email}} - - - - 拒绝 - 同意 + + + + + {{request.friendNickName || request.sendId}} + {{request.message || '请求添加你为好友'}} + + + + 同意 + + 已同意 + - @@ -306,7 +319,10 @@ } from '@/utils/user-info.js' import { getChatFriend, - getGroup + getGroup, + sendFriendRequest, + getFriendRequestList, + saveFriend } from '@/utils/friend-api.js' import { getUserInfo, @@ -466,6 +482,7 @@ onMounted(async () => { await takeFriendList() await takeGroupList() + await takeFriendRequestList() handleFriendConnect() }) // 群聊相关 @@ -656,7 +673,7 @@ // 模糊查询:遍历 mockFriendDB,匹配 nickname、username 或 email const keyword = searchFriendName.value.toLowerCase().trim(); searchResultList.value = await searchUsers(userToken.value,keyword) - console.log("searchResultList.value:",searchResultList.value); + console.log("searchResultList.value:",JSON.stringify(searchResultList.value)); // const results = mockFriendDB.value.filter(friend => { // const isMatch = friend.nickname.toLowerCase().includes(keyword) || friend.username.toLowerCase() // .includes(keyword) || friend.email.toLowerCase().includes(keyword); @@ -670,7 +687,7 @@ const currentAddFriend = ref(null) const addNewFriend = (id) => { - const friend = mockFriendDB.value.find(friend => friend.id === id) + const friend = searchResultList.value.find(friend => friend._id === id) if (friend) { // 创建副本避免引用问题 currentAddFriend.value = { @@ -685,6 +702,8 @@ currentAddFriend.value = null isAgreeBeFriend.value = false } + + const inputFriendNickname = ref('') // 视频会议相关 const isVoice = ref(false); @@ -698,77 +717,97 @@ // 好友申请相关 const isAgreeBeFriend = ref(false) - const refuseBeFriend = (friend) => { - + const friendRequestList = ref([]) + // 获取好友申请列表 + const takeFriendRequestList = async () => { + try { + if (!UserId.value) return + const list = await getFriendRequestList(UserId.value) + if (list && list.length) { + friendRequestList.value = await takeRequestAvatar(list) + } else { + friendRequestList.value = [] + } + } catch (error) { + console.error('获取好友申请列表失败:', error) + friendRequestList.value = [] + } } - const agreeBeFriend = (friend) => { + // 获取好友申请人的头像 + const takeRequestAvatar = async (requestList) => { + if (!requestList?.length) return [] + try { + const requestIds = requestList.map(item => item.sendId) + const avatarList = await getUserAvatar(userToken.value, requestIds) + const userMap = new Map(avatarList.map(user => [user.user_id, user]) || []) + return requestList.map(request => { + const userInfo = userMap.get(request.sendId) + return { + ...request, + avatar: userInfo?.avatar || null + } + }) + } catch (err) { + console.error('获取申请人头像失败', err) + return requestList + } + } + + const agreeBeFriend = (request) => { isAgreeBeFriend.value = true currentAddFriend.value = { - ...friend + ...request, + username: request.friendNickName || request.sendId } } - - - // 模拟好友数据库 - const mockFriendDB = ref([{ - id: 1, - nickname: '张三', - username: 'zhangsan', - email: 'zhangsan@example.com', - avatar: '👤' - }, - { - id: 2, - nickname: '李四', - username: 'lisi', - email: 'lisi@example.com', - avatar: '👥' - }, - { - id: 3, - nickname: '王小明', - username: 'wangxm', - email: 'wang@example.com', - avatar: '👪' - }, - { - id: 4, - nickname: '赵磊', - username: 'zhaolei', - email: 'zhao@example.com', - avatar: '🗣️' - }, - { - id: 5, - nickname: '张三2', - username: 'zhangsan', - email: 'zhangsan@example.com', - avatar: '👤' - }, - { - id: 6, - nickname: '李四2', - username: 'lisi', - email: 'lisi@example.com', - avatar: '👥' - }, - { - id: 7, - nickname: '王小明2', - username: 'wangxm', - email: 'wang@example.com', - avatar: '👪' - }, - { - id: 8, - nickname: '赵磊2', - username: 'zhaolei', - email: 'zhao@example.com', - avatar: '🗣️' + // 同意好友申请的确认操作 + const handleFriendOperate = async () => { + if (isAgreeBeFriend.value) { + // 通过好友申请(保存好友即同意) + try { + const friendId = currentAddFriend.value.sendId + const friendNickName = inputFriendNickname.value || currentAddFriend.value.friendNickName || '' + const sessionId = currentAddFriend.value.sessionId || Date.now() + const friendRelationshipId = currentAddFriend.value.id + await saveFriend([ + { + friendNickName: friendNickName, + sender: UserId.value, + receiver: friendId, + sessionId: sessionId, + friendRelationshipId: friendRelationshipId + }, + { + friendNickName: '', + sender: friendId, + receiver: UserId.value, + sessionId: sessionId, + friendRelationshipId: friendRelationshipId + } + ]) + uni.showToast({ title: '已同意好友申请', icon: 'none' }) + const target = friendRequestList.value.find(item => item.sendId === friendId) + if (target) target.status = 1 + closeAddFriendCard() + await takeFriendList() + } catch (error) { + console.error('同意好友申请失败:', error) + uni.showToast({ title: '操作失败', icon: 'none' }) + } + } else { + // 申请好友(添加好友页面的发送申请) + try { + const friendId = currentAddFriend.value._id + const msg = await sendFriendRequest(UserId.value, inputFriendNickname.value, friendId) + uni.showToast({ title: msg, icon: 'none' }) + closeAddFriendCard() + } catch (error) { + console.error('发送好友申请失败:', error) + uni.showToast({ title: '发送申请失败', icon: 'none' }) + } } - - ]) + } // 通讯录相关 diff --git a/pages/UserProfileModal/UserProfileModal.vue b/pages/UserProfileModal/UserProfileModal.vue index 962b225..3b90456 100644 --- a/pages/UserProfileModal/UserProfileModal.vue +++ b/pages/UserProfileModal/UserProfileModal.vue @@ -48,8 +48,8 @@ onMounted, ref } from 'vue'; - import { getUserInfo } from '@/utils/cloud-api.js' - import {getToken} from '@/utils/user-info.js' + import { getUserInfo, updateUserInfo } from '@/utils/cloud-api.js' + import { getToken } from '@/utils/user-info.js' const closeUserCard = () => { console.log("点击了返回") @@ -63,13 +63,39 @@ }) } - const saveUpdate = () => { - uni.navigateBack({ - url: '/pages/Chat/Chat' - }) + const saveUpdate = async() => { + // 表单校验 + if (!editUsername.value.trim()) { + uni.showToast({ title: '用户名不能为空', icon: 'none' }) + return + } + + uni.showLoading({ title: '保存中...', mask: true }) + + try { + await updateUserInfo( + UserToken.value, + UserId.value, + editUsername.value.trim(), + editEmail.value.trim(), + editUserAvatar.value + ) + uni.hideLoading() + uni.showToast({ title: '保存成功', icon: 'success' }) + // 保存成功后延迟返回上一页 + setTimeout(() => { + closeUserCard() + }, 800) + } catch (err) { + uni.hideLoading() + const msg = typeof err === 'string' ? err : '保存失败,请稍后重试' + uni.showToast({ title: msg, icon: 'none' }) + console.error('保存用户信息失败:', err) + } } - + const UserToken = ref('') + const UserId = ref('') const editUserAvatar = ref('') const editUsername = ref('') const editEmail = ref('') @@ -84,7 +110,7 @@ sourceType: ['album', 'camera'], success: (res) => { const tempFilePath = res.tempFilePaths[0] - handlrImageSelected(tempFilePath) + handleImageSelected(tempFilePath) }, fail: (err) => { console.log('选择图片失败', err); @@ -93,17 +119,22 @@ } // 处理选择的图片 - const handlrImageSelected = (filePath) => { + const handleImageSelected = (filePath) => { editUserAvatar.value = filePath } onMounted(async()=>{ - const token = getToken() - const UserInfo = await getUserInfo(token) - - editUserAvatar.value = UserInfo.avatar || '' - editUsername.value = UserInfo.username || '' - editEmail.value = UserInfo.email || '' + UserToken.value = getToken() + try { + const UserInfo = await getUserInfo(UserToken.value) + UserId.value = UserInfo._id || '' + editUserAvatar.value = UserInfo.avatar || '' + editUsername.value = UserInfo.username || '' + editEmail.value = UserInfo.email || '' + } catch (err) { + console.error('获取用户信息失败:', err) + uni.showToast({ title: '加载用户信息失败', icon: 'none' }) + } }) diff --git a/static/iconfont/demo_index.html b/static/iconfont/demo_index.html index b6c8508..3bfb318 100644 --- a/static/iconfont/demo_index.html +++ b/static/iconfont/demo_index.html @@ -54,6 +54,12 @@