feat(event): 添加酒局报名审核功能并优化前端组件

- 新增 ApproveEvent API 接口用于审核报名用户
- 在 EventCard 组件中显示待审核状态(⏳ 待审核)
- 实现酒局发起人审核报名用户的完整流程
- 添加用户协议和隐私政策页面
- 优化 FeedCard 组件中的图片展示逻辑
- 修复连续打卡天数计算问题
- 更新 HaveADrink SDK 至 1.0.15 版本
This commit is contained in:
cg
2026-08-16 14:50:50 +08:00
parent 527b0e8a8d
commit 81e7a3afa5
20 changed files with 1470 additions and 249 deletions
+38 -101
View File
@@ -4,15 +4,20 @@
<view class="circle-header" :style="{ paddingTop: headerPaddingTop }">
<view class="circle-title-row" :style="{ paddingRight: headerPaddingRight }">
<text class="circle-title">酒友圈</text>
<view class="msg-entry" @click="goChatList">
<!-- 发布入口:标题栏右侧胶囊按钮,替代悬浮 FAB 彻底避免遮挡 -->
<view class="publish-btn" @click="goPublish">
<text class="publish-btn-icon">✏️</text>
<text class="publish-btn-text">发布</text>
</view>
<!-- <view class="msg-entry" @click="goChatList">
<text class="msg-entry-icon">💬</text>
<view v-if="unreadTotal > 0" class="msg-badge">
<text class="msg-badge-text">{{ unreadTotal > 99 ? '99+' : unreadTotal }}</text>
</view>
</view>
</view> -->
<!-- </view> -->
</view>
<!-- Tab 切换 -->
<view class="circle-tabs">
<!-- Tab 切换(暂只保留动态) -->
<!-- <view class="circle-tabs">
<view
v-for="(tab, i) in tabs"
:key="i"
@@ -23,12 +28,13 @@
<text class="circle-tab-text">{{ tab }}</text>
<view v-if="currentTab === i" class="circle-tab-line"></view>
</view>
</view>
</view> -->
</view>
<!-- 动态 Tab -->
<!-- v-if="currentTab === 0" -->
<scroll-view
v-if="currentTab === 0"
class="circle-scroll"
scroll-y
:refresher-enabled="true"
@@ -64,71 +70,6 @@
/>
</view>
</scroll-view>
<!-- 酒友 Tab -->
<scroll-view v-if="currentTab === 1" class="circle-scroll" scroll-y>
<view class="circle-content">
<!-- 好友请求提醒 -->
<view v-if="friendRequests.length" class="request-banner" @click="goFriends">
<text class="request-icon">🔔</text>
<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="👥"
title="还没有酒友"
desc="邀请好友一起记录饮酒生活"
actionText="邀请好友"
@action="goFriends"
/>
</view>
</scroll-view>
<!-- 酒局 Tab -->
<scroll-view v-if="currentTab === 2" class="circle-scroll" scroll-y>
<view class="circle-content">
<EventCard
v-for="evt in events"
:key="evt.id"
:event="evt"
:can-manage="evt.isOrganizer === true"
@edit="goEditEvent"
@delete="confirmDeleteEvent"
@item-click="goEventDetail"
/>
<EmptyState
v-if="!events.length"
icon="🎉"
title="暂无酒局"
desc="发起一场酒局,约上酒友一起喝"
actionText="发起酒局"
@action="goCreateEvent"
/>
</view>
</scroll-view>
<!-- FAB 发布按钮 -->
<view class="fab" @click="handleFab">
<text class="fab-icon">{{ currentTab === 2 ? '🎉' : '✏️' }}</text>
</view>
</view>
</template>
@@ -149,7 +90,7 @@ export default {
const menuBtn = uni.getMenuButtonBoundingClientRect()
const sysInfo = uni.getSystemInfoSync()
return {
tabs: ['动态', '酒友', '酒局'],
tabs: ['动态'],
currentTab: 0,
headerPaddingTop: (menuBtn.top + 8) + 'px',
headerPaddingRight: (sysInfo.windowWidth - menuBtn.left + 8) + 'px',
@@ -178,17 +119,14 @@ export default {
},
onShow() {
this.loadFeeds(true)
this.loadFriends()
this.loadEvents()
this.loadUnread()
this.bindWsEvents()
// 消息入口已隐藏,未读角标暂不展示,空转请求先停掉(恢复入口时打开)
// this.loadUnread()
// 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()
},
@@ -406,11 +344,7 @@ export default {
},
// === FAB ===
handleFab() {
if (this.currentTab === 2) {
this.goCreateEvent()
} else {
this.goPublish()
}
this.goPublish()
}
},
onShareAppMessage() {
@@ -470,7 +404,6 @@ export default {
.circle-header {
padding-left: $sp-lg;
padding-right: $sp-lg;
padding-bottom: $sp-md;
background: $bg-base;
position: relative;
z-index: 10;
@@ -569,7 +502,7 @@ export default {
.circle-content {
padding: $sp-md $sp-lg;
padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
padding-bottom: calc(env(safe-area-inset-bottom) + 48rpx);
}
.circle-loading,
@@ -684,27 +617,31 @@ export default {
font-weight: $fw-bold;
}
/* FAB */
.fab {
position: fixed;
right: $sp-xl;
bottom: calc(env(safe-area-inset-bottom) + 180rpx);
width: 108rpx;
height: 108rpx;
border-radius: 50%;
background: linear-gradient(135deg, $amber, $amber-deep);
/* 发布入口:标题栏右侧胶囊按钮(替代悬浮 FAB,不遮挡任何内容) */
.publish-btn {
display: flex;
align-items: center;
justify-content: center;
box-shadow: $shadow-amber;
z-index: 50;
gap: 6rpx;
height: 60rpx;
padding: 0 24rpx;
border-radius: $radius-full;
background: rgba(232,168,56,0.12);
border: 1rpx solid rgba(232,168,56,0.30);
transition: transform $duration-fast $ease-out;
&:active {
transform: scale(0.9);
background: rgba(232,168,56,0.20);
transform: scale(0.94);
}
}
.fab-icon {
font-size: 44rpx;
.publish-btn-icon {
font-size: 26rpx;
}
.publish-btn-text {
font-size: $fs-sm;
color: $amber;
font-weight: $fw-bold;
}
</style>