feat(event): 添加酒局报名审核功能并优化前端组件
- 新增 ApproveEvent API 接口用于审核报名用户
- 在 EventCard 组件中显示待审核状态(⏳ 待审核)
- 实现酒局发起人审核报名用户的完整流程
- 添加用户协议和隐私政策页面
- 优化 FeedCard 组件中的图片展示逻辑
- 修复连续打卡天数计算问题
- 更新 HaveADrink SDK 至 1.0.15 版本
This commit is contained in:
+190
-22
@@ -32,10 +32,12 @@
|
||||
<text class="stat-label">标准杯</text>
|
||||
</view>
|
||||
<view class="stat-card card">
|
||||
<text class="stat-value text-num" :class="stats.streakType === 'drank' ? 'text-amber' : 'text-mint'">
|
||||
{{ stats.streak }}
|
||||
</text>
|
||||
<text class="stat-label">{{ stats.streakType === 'drank' ? '连喝天数' : '戒酒天数' }}</text>
|
||||
<text class="stat-value text-num text-amber">{{ stats.drankStreak }}</text>
|
||||
<text class="stat-label">连喝天数</text>
|
||||
</view>
|
||||
<view class="stat-card card">
|
||||
<text class="stat-value text-num text-mint">{{ stats.abstainStreak }}</text>
|
||||
<text class="stat-label">戒酒天数</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -83,9 +85,10 @@
|
||||
<!-- 日期记录弹窗 -->
|
||||
<view v-if="showDayDetail" class="day-overlay" @click="showDayDetail = false">
|
||||
<view class="day-detail card-elevated" @click.stop>
|
||||
<view class="day-detail-handle"></view>
|
||||
<view class="day-detail-header flex-between">
|
||||
<text class="text-h3">{{ selectedDate }}</text>
|
||||
<text class="btn-text" @click="showDayDetail = false">关闭</text>
|
||||
<text class="day-detail-date text-h3">{{ selectedDate }}</text>
|
||||
<text class="day-close btn-text" @click="showDayDetail = false">关闭</text>
|
||||
</view>
|
||||
<view v-if="selectedRecord">
|
||||
<view v-if="selectedRecord.mode === 'drank'" class="day-record-info">
|
||||
@@ -101,9 +104,14 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="day-meta flex-between">
|
||||
<text class="text-caption">{{ getFeelingName(selectedRecord.feeling) }}</text>
|
||||
<text class="text-caption text-amber text-num">{{ selectedRecord.standardCupsTotal }} 标准杯</text>
|
||||
<view class="day-meta">
|
||||
<view class="day-meta-chip day-feeling-chip">
|
||||
<text class="day-feeling-text">{{ getFeelingName(selectedRecord.feeling) }}</text>
|
||||
</view>
|
||||
<view class="day-meta-chip day-cups-chip">
|
||||
<text class="day-cups-num text-num">{{ selectedRecord.standardCupsTotal }}</text>
|
||||
<text class="day-cups-unit">标准杯</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="day-action-row">
|
||||
<button class="btn-ghost day-action-btn" @click="editRecord">修改</button>
|
||||
@@ -120,8 +128,9 @@
|
||||
</view>
|
||||
<view v-else class="day-empty">
|
||||
<text class="text-caption">当天无记录</text>
|
||||
<button v-if="isSelectedToday" class="btn-primary day-record-btn" @click="goRecordToday">去记录</button>
|
||||
<button v-else class="btn-ghost" @click="backfillDate">补打卡</button>
|
||||
<button v-if="isSelectedToday" class="btn-primary day-record-btn" @click="goRecordToday">记录饮酒</button>
|
||||
<button v-else class="btn-ghost day-record-btn" @click="backfillDate">补打卡饮酒</button>
|
||||
<button class="btn-ghost day-abstain-btn" @click="markAbstain">未饮酒</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -132,7 +141,7 @@
|
||||
import DrinkCalendar from '../../components/DrinkCalendar.vue'
|
||||
import client from '../../common/api'
|
||||
import { GetCalendarReq, DeleteRecordReq, CreateRecordReq, GetRecordDetailReq } from 'HaveADrink'
|
||||
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath } from '../../common/utils'
|
||||
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath, calcLocalStreak } from '../../common/utils'
|
||||
import { FEELINGS, DRINK_CATEGORIES, DRINK_UNITS } from '../../common/constants'
|
||||
import { savePendingInvite, handlePendingInvite } from '../../common/invite'
|
||||
import themeMixin from '../../common/theme-mixin'
|
||||
@@ -236,6 +245,8 @@ export default {
|
||||
favCategory: s.favCategory ? String(s.favCategory) : null,
|
||||
categoryVariety: s.categoryVariety || 0
|
||||
}
|
||||
// 后端 streak 不区分饮酒/戒酒模式,拉取记录本地重算修正
|
||||
this.refreshLocalStreak()
|
||||
}
|
||||
|
||||
// 日历数据
|
||||
@@ -270,6 +281,22 @@ export default {
|
||||
// 切换月份时重新加载记录
|
||||
this.loadRecordsForMonth(year, month)
|
||||
},
|
||||
/** 后端 streak 不区分饮酒/戒酒模式,拉取全部记录后本地重算连续天数 */
|
||||
async refreshLocalStreak() {
|
||||
try {
|
||||
const resp = await client.GetRecords({ page: 1, pageSize: 100 })
|
||||
const payload = resp.data || resp
|
||||
const list = payload.list || []
|
||||
if (!list.length) return
|
||||
const { streak, streakType, drankStreak, abstainStreak } = calcLocalStreak(list)
|
||||
this.stats.streak = streak
|
||||
this.stats.streakType = streakType
|
||||
this.stats.drankStreak = drankStreak
|
||||
this.stats.abstainStreak = abstainStreak
|
||||
} catch (e) {
|
||||
console.warn('本地计算连续天数失败:', e)
|
||||
}
|
||||
},
|
||||
async loadRecordsForMonth(year, month) {
|
||||
try {
|
||||
const resp = await client.GetCalendar(new GetCalendarReq(year, month))
|
||||
@@ -415,7 +442,31 @@ export default {
|
||||
this.showDayDetail = false
|
||||
uni.navigateTo({ url: '/pages/record/record' })
|
||||
},
|
||||
|
||||
// 标记为未饮酒(直接创建 abstain 记录)
|
||||
async markAbstain() {
|
||||
const recordData = {
|
||||
date: this.selectedDate,
|
||||
mode: 'abstain',
|
||||
drinks: [],
|
||||
food: null,
|
||||
feeling: null,
|
||||
photos: [],
|
||||
visibility: 'friends',
|
||||
quote: ''
|
||||
}
|
||||
try {
|
||||
uni.showLoading({ title: '保存中...' })
|
||||
await client.CreateRecord(recordData)
|
||||
uni.hideLoading()
|
||||
this.showDayDetail = false
|
||||
uni.showToast({ title: '已记录未饮酒', icon: 'success' })
|
||||
this.loadData()
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.warn('标记未饮酒失败:', e)
|
||||
uni.showToast({ title: (e && e.msg) || '保存失败,请重试', icon: 'none' })
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -434,7 +485,7 @@ export default {
|
||||
|
||||
.greeting-text {
|
||||
display: block;
|
||||
font-size:38rpx;
|
||||
font-size:42rpx;
|
||||
font-weight: $fw-bold;
|
||||
color: $text-primary;
|
||||
}
|
||||
@@ -632,24 +683,83 @@ export default {
|
||||
align-items: flex-end;
|
||||
z-index: 100;
|
||||
padding: $sp-lg;
|
||||
animation: overlayIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes overlayIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.day-detail {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: $sp-xl;
|
||||
padding: $sp-md $sp-xl $sp-xl;
|
||||
color: $text-primary;
|
||||
border-radius: $radius-xl $radius-xl 0 0;
|
||||
border-radius: $radius-xl;
|
||||
/* 背景层次:底部卡片色 + 顶部琥珀光晕,日夜主题自适应 */
|
||||
background:
|
||||
radial-gradient(120% 60% at 50% 0%, var(--amber-glow, rgba(232, 168, 56, 0.15)) 0%, transparent 60%),
|
||||
linear-gradient(180deg, var(--bg-elevated, #28283E) 0%, var(--bg-card, #1A1A28) 55%);
|
||||
border: 2rpx solid var(--border-faint, rgba(255, 255, 255, 0.08));
|
||||
box-shadow: var(--shadow-lg);
|
||||
animation: sheetIn 0.28s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
@keyframes sheetIn {
|
||||
from { opacity: 0; transform: translateY(48rpx); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* 顶部拖拽把手 */
|
||||
.day-detail-handle {
|
||||
width: 64rpx;
|
||||
height: 8rpx;
|
||||
border-radius: $radius-full;
|
||||
background: var(--border-active, rgba(255, 255, 255, 0.12));
|
||||
margin: 0 auto $sp-md;
|
||||
}
|
||||
|
||||
.day-detail-header {
|
||||
margin-bottom: $sp-lg;
|
||||
}
|
||||
|
||||
.day-detail-date {
|
||||
position: relative;
|
||||
padding-left: $sp-md;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 6rpx;
|
||||
height: 70%;
|
||||
border-radius: $radius-full;
|
||||
background: linear-gradient(180deg, var(--amber-light, #F5C563), var(--amber-deep, #C47F17));
|
||||
}
|
||||
}
|
||||
|
||||
.day-close {
|
||||
padding: $sp-xs $sp-sm;
|
||||
}
|
||||
|
||||
.day-drinks {
|
||||
background: var(--bg-subtle, rgba(255, 255, 255, 0.03));
|
||||
border-radius: $radius-md;
|
||||
padding: $sp-xs $sp-md;
|
||||
}
|
||||
|
||||
.day-drink-item {
|
||||
padding: $sp-sm 0;
|
||||
padding: $sp-md 0;
|
||||
font-size: $fs-base;
|
||||
color: $text-primary;
|
||||
border-bottom: 2rpx solid var(--border-micro, rgba(255, 255, 255, 0.05));
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.day-drink-row {
|
||||
@@ -680,9 +790,44 @@ export default {
|
||||
}
|
||||
|
||||
.day-meta {
|
||||
display: flex;
|
||||
gap: $sp-sm;
|
||||
margin-top: $sp-lg;
|
||||
}
|
||||
|
||||
.day-meta-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $sp-xs;
|
||||
padding: $sp-sm $sp-md;
|
||||
border-radius: $radius-full;
|
||||
}
|
||||
|
||||
.day-feeling-chip {
|
||||
background: var(--bg-hover, rgba(255, 255, 255, 0.08));
|
||||
}
|
||||
|
||||
.day-feeling-text {
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
.day-cups-chip {
|
||||
background: var(--amber-glow, rgba(232, 168, 56, 0.15));
|
||||
border: 2rpx solid rgba(232, 168, 56, 0.25);
|
||||
}
|
||||
|
||||
.day-cups-num {
|
||||
font-size: $fs-lg;
|
||||
font-weight: $fw-bold;
|
||||
color: $amber;
|
||||
}
|
||||
|
||||
.day-cups-unit {
|
||||
font-size: $fs-xs;
|
||||
color: $amber;
|
||||
}
|
||||
|
||||
.day-abstain {
|
||||
text-align: center;
|
||||
padding: $sp-xl 0;
|
||||
@@ -702,6 +847,12 @@ export default {
|
||||
margin-top: $sp-lg;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.day-abstain-btn {
|
||||
color: $mint;
|
||||
border-color: rgba(94, 198, 160, 0.35);
|
||||
background: rgba(94, 198, 160, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.day-action-row {
|
||||
@@ -710,20 +861,37 @@ export default {
|
||||
margin-top: $sp-lg;
|
||||
}
|
||||
|
||||
/* 修改:琥珀主操作 */
|
||||
.day-action-btn {
|
||||
flex: 1;
|
||||
font-size: $fs-sm;
|
||||
color: $text-secondary;
|
||||
border-color: var(--border-active, rgba(255, 255, 255, 0.12));
|
||||
|
||||
&:first-child {
|
||||
color: $text-on-amber;
|
||||
background: linear-gradient(135deg, var(--amber-light, #F5C563), var(--amber-deep, #C47F17));
|
||||
border: none;
|
||||
box-shadow: var(--shadow-amber);
|
||||
}
|
||||
|
||||
/* 改为未饮酒:薄荷淡底 */
|
||||
&:last-child {
|
||||
color: $mint;
|
||||
background: rgba(94, 198, 160, 0.08);
|
||||
border: 2rpx solid rgba(94, 198, 160, 0.30);
|
||||
}
|
||||
}
|
||||
|
||||
.day-delete-btn {
|
||||
margin-top: $sp-md;
|
||||
width: 100%;
|
||||
font-size: $fs-sm;
|
||||
color: #e85d3a;
|
||||
background: rgba(232, 93, 58, 0.08);
|
||||
border: 2rpx solid rgba(232, 93, 58, 0.2);
|
||||
color: #E85D3A;
|
||||
background: rgba(232, 93, 58, 0.06);
|
||||
border: 2rpx solid rgba(232, 93, 58, 0.30);
|
||||
|
||||
&:active {
|
||||
background: rgba(232, 93, 58, 0.14);
|
||||
}
|
||||
}
|
||||
|
||||
.day-toggle-btn {
|
||||
|
||||
Reference in New Issue
Block a user