feat(sdk): 升级HaveADrink SDK并集成邀请系统
- 将HaveADrink依赖从1.0.8升级至1.0.12版本 - 集成邀请码功能,新增common/invite.js处理邀请链路 - 实现发送好友请求返回邀请码的新流程 - 添加删除动态功能,新增DeleteFeed接口 - 集成UniAppWebSocket适配器,重构WebSocket连接管理 - 优化好友请求支持关键词搜索功能 - 在FeedCard组件中添加删除按钮和分享按钮 - 更新SDK类型定义文件以匹配新接口规范
This commit is contained in:
+224
-9
@@ -41,8 +41,11 @@
|
||||
v-for="feed in feeds"
|
||||
:key="feed.id"
|
||||
:feed="feed"
|
||||
:can-delete="isMyFeed(feed)"
|
||||
@like="handleLike"
|
||||
@comment="goDetail"
|
||||
@share="handleShare"
|
||||
@delete="confirmDeleteFeed"
|
||||
@item-click="goDetail"
|
||||
/>
|
||||
<view v-if="loading" class="circle-loading">
|
||||
@@ -71,12 +74,23 @@
|
||||
<text class="request-text">{{ friendRequests.length }} 条新的好友请求</text>
|
||||
<text class="request-arrow">›</text>
|
||||
</view>
|
||||
<!-- 酒友管理入口(有好友时也可进入:处理请求/删除酒友) -->
|
||||
<view v-if="friends.length && !friendRequests.length" class="friends-entry" @click="goFriends">
|
||||
<text class="friends-entry-icon">👥</text>
|
||||
<text class="friends-entry-text">管理酒友 · 处理好友请求</text>
|
||||
<text class="friends-entry-arrow">›</text>
|
||||
</view>
|
||||
<FriendItem
|
||||
v-for="f in friends"
|
||||
:key="f.id"
|
||||
:friend="f"
|
||||
@item-click="goChat(f)"
|
||||
/>
|
||||
<!-- 有好友时也保留邀请入口,直接触发带邀请码的转发 -->
|
||||
<button v-if="friends.length" class="invite-btn" open-type="share" @click="prepareInviteShare">
|
||||
<text class="invite-btn-icon">👥</text>
|
||||
<text class="invite-btn-text">邀请更多酒友</text>
|
||||
</button>
|
||||
<EmptyState
|
||||
v-if="!friends.length"
|
||||
icon="👥"
|
||||
@@ -120,8 +134,9 @@ import FeedCard from '../../components/FeedCard.vue'
|
||||
import FriendItem from '../../components/FriendItem.vue'
|
||||
import EventCard from '../../components/EventCard.vue'
|
||||
import EmptyState from '../../components/EmptyState.vue'
|
||||
import { GetCircleFeeds, LikeFeed, UnlikeFeed, GetFriends, GetFriendRequests, GetEvents, GetUnreadCount } from '../../common/api'
|
||||
import { GetCircleFeeds, LikeFeed, UnlikeFeed, DeleteFeed, GetFriends, GetFriendRequests, GetEvents, GetUnreadCount } from '../../common/api'
|
||||
import wsManager from '../../common/websocket'
|
||||
import { getMyInviteCode } from '../../common/invite'
|
||||
import themeMixin from '../../common/theme-mixin'
|
||||
|
||||
export default {
|
||||
@@ -147,7 +162,15 @@ export default {
|
||||
// 酒局
|
||||
events: [],
|
||||
// 私信未读
|
||||
unreadTotal: 0
|
||||
unreadTotal: 0,
|
||||
// 当前分享的动态
|
||||
shareFeed: null,
|
||||
// 分享模式:feed(分享动态) / invite(邀请好友) / default
|
||||
shareMode: 'default',
|
||||
// 我的邀请码(分享时携带,一次性)
|
||||
inviteCode: '',
|
||||
// 当前登录用户ID(用于判断动态是否为自己发布)
|
||||
myUserId: ''
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
@@ -155,16 +178,56 @@ export default {
|
||||
this.loadFriends()
|
||||
this.loadEvents()
|
||||
this.loadUnread()
|
||||
this._wsHandler = () => { this.unreadTotal++ }
|
||||
wsManager.on('message', this._wsHandler)
|
||||
this.bindWsEvents()
|
||||
// 读取当前用户ID(删除自己的动态时用)
|
||||
try {
|
||||
const user = JSON.parse(uni.getStorageSync('user_info') || '{}')
|
||||
this.myUserId = user.id !== undefined && user.id !== null ? String(user.id) : ''
|
||||
} catch (e) { this.myUserId = '' }
|
||||
// 预生成邀请码(仅首次/用完后生成,避免每次进页都创建无效邀请)
|
||||
this.ensureInviteCode()
|
||||
// 页面显示时确保 WS 已连接(登录后/断线后兼容)
|
||||
wsManager.connect()
|
||||
},
|
||||
onHide() {
|
||||
if (this._wsHandler) {
|
||||
wsManager.off('message', this._wsHandler)
|
||||
this._wsHandler = null
|
||||
}
|
||||
this.unbindWsEvents()
|
||||
},
|
||||
onUnload() {
|
||||
this.unbindWsEvents()
|
||||
},
|
||||
methods: {
|
||||
// === WebSocket 事件 ===
|
||||
bindWsEvents() {
|
||||
if (this._wsBound) return
|
||||
this._wsBound = true
|
||||
this._wsMsgHandler = this.onWsMessage
|
||||
this._wsConnectHandler = this.onWsConnect
|
||||
wsManager.on('message', this._wsMsgHandler)
|
||||
wsManager.on('connect', this._wsConnectHandler)
|
||||
},
|
||||
unbindWsEvents() {
|
||||
if (!this._wsBound) return
|
||||
this._wsBound = false
|
||||
if (this._wsMsgHandler) {
|
||||
wsManager.off('message', this._wsMsgHandler)
|
||||
this._wsMsgHandler = null
|
||||
}
|
||||
if (this._wsConnectHandler) {
|
||||
wsManager.off('connect', this._wsConnectHandler)
|
||||
this._wsConnectHandler = null
|
||||
}
|
||||
},
|
||||
/** 收到新私信:未读角标实时 +1(自己发的/自己读的不计数) */
|
||||
onWsMessage(data) {
|
||||
if (!data) return
|
||||
const senderId = data.senderId
|
||||
if (senderId && wsManager.userId && String(senderId) === String(wsManager.userId)) return
|
||||
this.unreadTotal++
|
||||
},
|
||||
/** (重)连成功后拉取真实未读数,修正断线期间的漏计/多计 */
|
||||
onWsConnect() {
|
||||
this.loadUnread()
|
||||
},
|
||||
switchTab(i) {
|
||||
this.currentTab = i
|
||||
},
|
||||
@@ -218,9 +281,49 @@ export default {
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
},
|
||||
/** 判断是否为自己发布的动态(仅自己可删) */
|
||||
isMyFeed(feed) {
|
||||
if (!this.myUserId) return false
|
||||
return feed && feed.userId !== undefined && feed.userId !== null && String(feed.userId) === this.myUserId
|
||||
},
|
||||
/** 删除自己的动态(二次确认) */
|
||||
confirmDeleteFeed(feed) {
|
||||
uni.showModal({
|
||||
title: '删除动态',
|
||||
content: '确定要删除这条动态吗?删除后不可恢复',
|
||||
confirmText: '删除',
|
||||
confirmColor: '#FF6B6B',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
try {
|
||||
await DeleteFeed({ feedId: feed.id })
|
||||
this.feeds = this.feeds.filter(f => String(f.id) !== String(feed.id))
|
||||
uni.showToast({ title: '已删除', icon: 'none' })
|
||||
} catch (e) {
|
||||
// httpRequest 已全局弹错误提示(如非本人动态后端会拒绝)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
goDetail(feed) {
|
||||
uni.navigateTo({ url: `/pages/circle-detail/circle-detail?id=${feed.id}` })
|
||||
},
|
||||
/** 记录当前要分享的动态,供 onShareAppMessage 读取 */
|
||||
handleShare(feed) {
|
||||
this.shareMode = 'feed'
|
||||
this.shareFeed = feed
|
||||
},
|
||||
/** 点击邀请按钮:标记本次分享为邀请模式 */
|
||||
prepareInviteShare() {
|
||||
this.shareMode = 'invite'
|
||||
},
|
||||
/** 确保邀请码已生成(仅缺失时拉取,避免频繁创建一次性邀请) */
|
||||
ensureInviteCode() {
|
||||
if (this.inviteCode) return
|
||||
getMyInviteCode().then(code => {
|
||||
if (code) this.inviteCode = code
|
||||
})
|
||||
},
|
||||
goPublish() {
|
||||
uni.navigateTo({ url: '/pages/circle-publish/circle-publish' })
|
||||
},
|
||||
@@ -255,7 +358,9 @@ export default {
|
||||
async loadUnread() {
|
||||
try {
|
||||
const res = await GetUnreadCount()
|
||||
this.unreadTotal = res.data.total
|
||||
if (res.data && typeof res.data.total === 'number') {
|
||||
this.unreadTotal = res.data.total
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
},
|
||||
// === 酒局 ===
|
||||
@@ -281,6 +386,49 @@ export default {
|
||||
this.goPublish()
|
||||
}
|
||||
}
|
||||
},
|
||||
onShareAppMessage() {
|
||||
// 邀请好友分享:链接携带一次性邀请码,好友点开后自动接受邀请
|
||||
if (this.shareMode === 'invite') {
|
||||
let user = {}
|
||||
try {
|
||||
user = JSON.parse(uni.getStorageSync('user_info') || '{}')
|
||||
} catch (e) { /* ignore */ }
|
||||
const parts = []
|
||||
if (this.inviteCode) parts.push(`inviteCode=${encodeURIComponent(this.inviteCode)}`)
|
||||
if (user.nickname) parts.push(`inviterNick=${encodeURIComponent(user.nickname)}`)
|
||||
const query = parts.length ? `?${parts.join('&')}` : ''
|
||||
const nick = user.nickname ? `「${user.nickname}」` : ''
|
||||
// 本次分享已用掉当前邀请码,异步生成新码供下次使用
|
||||
this.inviteCode = ''
|
||||
this.ensureInviteCode()
|
||||
this.shareMode = 'default'
|
||||
return {
|
||||
title: `${nick}邀请你成为酒友,一起记录饮酒生活 🍻`,
|
||||
path: `/pages/index/index${query}`
|
||||
}
|
||||
}
|
||||
const feed = this.shareFeed
|
||||
if (this.shareMode === 'feed' && feed && feed.id) {
|
||||
this.shareMode = 'default'
|
||||
const text = (feed.text || '').replace(/\s+/g, ' ').trim()
|
||||
const title = text
|
||||
? `${feed.nickname || '酒友'}:${text.length > 24 ? text.slice(0, 24) + '…' : text}`
|
||||
: `${feed.nickname || '酒友'}的动态 - 碰盏日记`
|
||||
return {
|
||||
title,
|
||||
path: `/pages/circle-detail/circle-detail?id=${feed.id}&nick=${encodeURIComponent(feed.nickname || '')}&text=${encodeURIComponent(text.slice(0, 60))}&time=${encodeURIComponent(feed.time || '')}`
|
||||
}
|
||||
}
|
||||
return {
|
||||
title: '酒友圈 - 碰盏日记',
|
||||
path: '/pages/index/index'
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '酒友圈 - 碰盏日记'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -443,6 +591,73 @@ export default {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 酒友管理入口 */
|
||||
.friends-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $sp-sm;
|
||||
padding: $sp-md $sp-lg;
|
||||
background: $bg-card;
|
||||
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
|
||||
border-radius: $radius-lg;
|
||||
margin-bottom: $sp-md;
|
||||
|
||||
&:active {
|
||||
background: $bg-card-alt;
|
||||
}
|
||||
}
|
||||
|
||||
.friends-entry-icon {
|
||||
font-size: $fs-base;
|
||||
}
|
||||
|
||||
.friends-entry-text {
|
||||
flex: 1;
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
font-weight: $fw-medium;
|
||||
}
|
||||
|
||||
.friends-entry-arrow {
|
||||
font-size: $fs-xl;
|
||||
color: $text-tertiary;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 邀请更多酒友按钮(重置 button 默认样式) */
|
||||
.invite-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $sp-sm;
|
||||
width: 100%;
|
||||
margin: $sp-md 0 0;
|
||||
padding: $sp-lg 0;
|
||||
background: rgba(232,168,56,0.08);
|
||||
border: 1rpx dashed rgba(232,168,56,0.35);
|
||||
border-radius: $radius-lg;
|
||||
line-height: 1;
|
||||
font-size: inherit;
|
||||
|
||||
&:active {
|
||||
background: rgba(232,168,56,0.14);
|
||||
}
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.invite-btn-icon {
|
||||
font-size: $fs-base;
|
||||
}
|
||||
|
||||
.invite-btn-text {
|
||||
font-size: $fs-sm;
|
||||
color: $amber;
|
||||
font-weight: $fw-bold;
|
||||
}
|
||||
|
||||
/* FAB */
|
||||
.fab {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user