mahjong_group/components/com/page/reservation-item.vue
2025-09-13 09:49:10 +08:00

223 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="reservation-item reservation-box">
<view class="column reservation-inner" @click="openReservationPopup()">
<view class="row title title-row mt-10">
<view class="title">{{ reservation.title || '麻将预约' }}</view>
<view class="status-text" :style="getStatusStyle(reservation.status)">
{{ getStatusText(reservation.status) }}
</view>
</view>
<view class="row row-text row-center mt-10">
<text class="ml-20">{{ formatTimeRange(reservation.start_time, reservation.end_time) }}</text>
</view>
<view class="row row-center mt-10">
<text class="row-text ml-20">{{ reservation.room_name || '' }}</text>
</view>
<view class="row row-center mt-10">
<text class="row-text ml-20">已约牌友</text>
<image v-for="(participant, pIndex) in reservation.participants" :key="pIndex"
:src="participant.avatarImage || '/static/default-avatar.png'" class="avatar" mode="aspectFill" />
<view class="center evaluate-btn" v-if="reservation.status == 2" @click.stop="onEvaluate()">
<text class="evaluate-btn-text">牌友评价</text>
</view>
</view>
<view class="mt-20" style="height: 10rpx;"></view>
</view>
<!-- 评价弹窗由父页面控制 -->
</view>
</template>
<script setup>
// 仅负责展示与触发评价事件
import { inject } from 'vue'
const props = defineProps({
reservation: {
type: Object,
required: true
}
})
const emit = defineEmits(['evaluate', 'click'])
const onEvaluate = () => {
emit('evaluate', props.reservation)
// openEvaluatePop?.(props.reservation)
}
const formatTimeRange = (startTime, endTime) => {
if (!startTime || !endTime) return '时间未设置'
const start = new Date(startTime)
const end = new Date(endTime)
const startStr = `${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, '0')}-${String(start.getDate()).padStart(2, '0')} ${String(start.getHours()).padStart(2, '0')}:${String(start.getMinutes()).padStart(2, '0')}`
const endStr = `${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, '0')}-${String(end.getDate()).padStart(2, '0')} ${String(end.getHours()).padStart(2, '0')}:${String(end.getMinutes()).padStart(2, '0')}`
return `${startStr} ~ ${endStr}`
}
const getStatusText = (status) => {
const map = { 0: '待开始', 1: '进行中', 2: '已结束', 3: "已取消" }
return map[status] || '未知状态'
}
const getStatusStyle = (status) => {
const map = { 0: 'color: #1989FA', 1: 'color: #999', 2: 'color: #999', 3: 'color: #999' }
return map[status] || 'color: #999'
}
const openReservationPopup = () => {
emit('click', props.reservation)
// openReservationPopupf?.(props.reservation)
}
</script>
<style lang="scss" scoped>
.reservation-item {
background: linear-gradient(180deg, #D7F0DD 0%, #FFFFFF 100%);
box-shadow: 0rpx 0rpx 10rpx 0rpx rgba(0, 0, 0, 0.25);
border-radius: 46rpx 46rpx 46rpx 46rpx;
transition: transform 0.2s;
&:active {
transform: scale(0.98);
}
}
.reservation-box {
width: 100%;
border-radius: 25rpx;
background-color: #F2F3F5;
}
.reservation-inner {
width: 95%;
margin: 20rpx auto 20rpx;
}
.title {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 35rpx;
color: #322A2A;
text-align: left;
font-style: normal;
text-transform: none;
}
.title-row {
justify-content: space-between;
}
.row-text {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 30rpx;
color: #575757;
text-align: left;
font-style: normal;
text-transform: none;
}
.row-center {
align-items: center;
}
.mt-20 {
margin-top: 20rpx;
}
.mt-10 {
margin-top: 10rpx;
}
.ml-20 {
margin-left: 20rpx;
}
.avatar {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.status-text {
font-size: 24rpx;
}
.evaluate-btn {
width: 120rpx;
height: 30px;
background-color: #1989FA;
border-radius: 10rpx;
margin-left: auto;
}
.evaluate-btn-text {
font-size: 24rpx;
color: #FFFFFF;
}
.popup-container {
width: 650rpx;
background-color: #FFFFFF;
border-radius: 10rpx;
}
.popup-inner {
width: 90%;
margin: 0 auto 0;
}
.popup-title {
font-size: 26rpx;
margin-top: 30rpx;
text-align: center;
}
.popup-desc {
font-size: 24rpx;
margin-top: 20rpx;
}
.panel-box {
width: 100%;
background-color: #F2F3F5;
border-radius: 10rpx;
padding-top: 20rpx;
padding-bottom: 20rpx;
margin-top: 20rpx;
}
.down-icon {
width: 40rpx;
height: 40rpx;
margin-left: auto;
margin-right: 20rpx;
}
.font-24 {
font-size: 24rpx;
}
.action-row {
margin-top: 50rpx;
height: 80rpx;
color: #FFFFFF;
font-size: 28rpx;
}
.action-btn {
flex: 1;
background-color: #1989FA;
border-radius: 10rpx;
}
.info-tip {
font-size: 24rpx;
text-align: center;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
</style>