- 集成HaveADrink SDK版本从1.0.4升级至1.0.8 - 实现酒友圈API接口,替换原有的mock数据 - 添加地理位置权限配置(requiredPrivateInfos) - 重构API调用方式,统一使用client实例调用真实接口 - 更新WebSocket协议与SDK保持一致,支持聊天、输入状态、已读回执等功能 - 实现游标分页获取动态信息流 - 添加文件上传API支持图片上传 - 优化API错误处理,支持业务级错误提示 - 调整酒局状态显示,新增upcoming待开始状态 - 优化自我感觉标签映射逻辑,支持更多状态类型 - 更新websocket连接认证方式,使用Authorization header传递token - 添加服务端连接确认和被踢下线事件处理
186 lines
4.1 KiB
Vue
186 lines
4.1 KiB
Vue
<template>
|
||
<view class="event-card" @click="$emit('item-click', event)">
|
||
<!-- 状态标签 -->
|
||
<view class="event-status" :class="'status-' + event.status">
|
||
<text class="event-status-text">{{ statusLabel }}</text>
|
||
</view>
|
||
|
||
<!-- 标题 -->
|
||
<text class="event-title">{{ event.title }}</text>
|
||
|
||
<!-- 信息行 -->
|
||
<view class="event-info">
|
||
<view class="event-info-row">
|
||
<text class="event-info-icon">🕐</text>
|
||
<text class="event-info-text">{{ event.time }}</text>
|
||
</view>
|
||
<view class="event-info-row">
|
||
<text class="event-info-icon">📍</text>
|
||
<text class="event-info-text">{{ event.location }}</text>
|
||
</view>
|
||
<view class="event-info-row">
|
||
<text class="event-info-icon">👥</text>
|
||
<text class="event-info-text">{{ event.joined }}/{{ event.maxPeople }} 人已报名</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部:发起人 + 操作 -->
|
||
<view class="event-footer">
|
||
<view class="event-organizer">
|
||
<view class="event-org-avatar">
|
||
<text class="event-org-text">{{ event.organizer ? event.organizer.nickname[0] : '酒' }}</text>
|
||
</view>
|
||
<text class="event-org-name">{{ event.organizer ? event.organizer.nickname : '' }}</text>
|
||
</view>
|
||
<view class="event-action" v-if="event.status === 'open'">
|
||
<text class="event-action-text" v-if="event.isJoined">✓ 已报名</text>
|
||
<text class="event-action-text event-action-join" v-else>报名</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'EventCard',
|
||
props: {
|
||
event: { type: Object, default: () => ({}) }
|
||
},
|
||
emits: ['item-click'],
|
||
computed: {
|
||
statusLabel() {
|
||
const val = String(this.event.status).toLowerCase()
|
||
const map = { open: '报名中', upcoming: '待开始', ongoing: '进行中', ended: '已结束' }
|
||
return map[val] || '报名中'
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.event-card {
|
||
background: $bg-card;
|
||
border-radius: $radius-xl;
|
||
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
|
||
padding: $sp-xl;
|
||
margin-bottom: $sp-md;
|
||
position: relative;
|
||
overflow: hidden;
|
||
|
||
&:active {
|
||
background: $bg-card-alt;
|
||
}
|
||
}
|
||
|
||
.event-status {
|
||
display: inline-flex;
|
||
padding: 6rpx 16rpx;
|
||
border-radius: $radius-full;
|
||
margin-bottom: $sp-md;
|
||
|
||
&.status-open {
|
||
background: rgba(94,198,160,0.12);
|
||
}
|
||
&.status-upcoming {
|
||
background: rgba(139,133,184,0.12);
|
||
}
|
||
&.status-ongoing {
|
||
background: rgba(232,168,56,0.12);
|
||
}
|
||
&.status-ended {
|
||
background: $bg-elevated;
|
||
}
|
||
}
|
||
|
||
.event-status-text {
|
||
font-size: $fs-xs;
|
||
font-weight: $fw-medium;
|
||
|
||
.status-open & { color: $mint; }
|
||
.status-upcoming & { color: $lavender; }
|
||
.status-ongoing & { color: $amber; }
|
||
.status-ended & { color: $text-tertiary; }
|
||
}
|
||
|
||
.event-title {
|
||
display: block;
|
||
font-size: $fs-lg;
|
||
font-weight: $fw-bold;
|
||
color: $text-primary;
|
||
margin-bottom: $sp-lg;
|
||
}
|
||
|
||
.event-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: $sp-sm;
|
||
margin-bottom: $sp-lg;
|
||
}
|
||
|
||
.event-info-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: $sp-sm;
|
||
}
|
||
|
||
.event-info-icon {
|
||
font-size: $fs-sm;
|
||
width: 36rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.event-info-text {
|
||
font-size: $fs-sm;
|
||
color: $text-secondary;
|
||
}
|
||
|
||
.event-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-top: $sp-md;
|
||
border-top: 1rpx solid var(--divider-color, rgba(255,255,255,0.08));
|
||
}
|
||
|
||
.event-organizer {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: $sp-sm;
|
||
}
|
||
|
||
.event-org-avatar {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
border-radius: 50%;
|
||
background: $bg-elevated;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.event-org-text {
|
||
font-size: $fs-xs;
|
||
font-weight: $fw-bold;
|
||
color: $lavender;
|
||
}
|
||
|
||
.event-org-name {
|
||
font-size: $fs-sm;
|
||
color: $text-tertiary;
|
||
}
|
||
|
||
.event-action-text {
|
||
font-size: $fs-sm;
|
||
color: $text-tertiary;
|
||
padding: 8rpx 24rpx;
|
||
border-radius: $radius-full;
|
||
background: $bg-elevated;
|
||
}
|
||
|
||
.event-action-join {
|
||
color: $text-on-amber;
|
||
background: linear-gradient(135deg, $amber, $amber-deep);
|
||
font-weight: $fw-bold;
|
||
}
|
||
</style>
|