mahjong_group/components/com/index/ReservationPopup.vue
2025-09-11 05:30:19 +08:00

260 lines
9.0 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>
<uni-popup ref="popup" type="center">
<view class="column center"
style="width: 680rpx; background-color: white; border-radius: 10rpx; padding: 20rpx;">
<text style="">预约信息</text>
<view class="column"
style="width: 100%; height: 180rpx; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx;">
<view class="row" style="margin-top: 20rpx; align-items: center; margin-left: 20rpx;">
<text style="font-size: 22rpx;">发起者</text>
<image :src="initiatorInfo.avatarImage || ''"
style="width: 50rpx; height: 50rpx; background-color: antiquewhite; border-radius: 50%; margin-left: 20rpx;"
mode=""></image>
<text style="font-size: 20rpx; margin-left: 15rpx;">{{ initiatorInfo.userName || '' }}</text>
</view>
<view class="row" style="margin-top: 30rpx; align-items: center; margin-left: 20rpx;">
<text style="font-size: 22rpx;">参与者</text>
<view class="row" v-for="(item, index) in participantList" :key="index"
style="align-items: center;">
<view class="" style="position: relative; width: 50rpx; height: 50rpx; display: flex;">
<image :src="item.avatarImage || ''" @click="openUserPop(item)"
style="width: 50rpx; height: 50rpx; background-color: antiquewhite; border-radius: 50%; margin-left: 20rpx; position: absolute;"
mode=""></image>
<view v-if="item.userBlackStatus === 1" class="center"
style="width: 50rpx; height: 20rpx; background-color: #FFB7B7; position: absolute; left: 40%; top: -10rpx;">
<text style="font-size: 10rpx;">黑名单</text>
</view>
</view>
<text
style="font-size: 20rpx; margin-left: 30rpx; width: 100rpx; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{
item.userName || '' }}</text>
</view>
</view>
</view>
<view class="column"
style="width: 100%; height: 180rpx; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx;font-size: 22rpx;">
<view class="row" style="justify-content: space-between; margin: 20rpx;">
<text>开始时间</text>
<text>{{ formatTime(reservationData.start_time) }}</text>
</view>
<view class="row" style="justify-content: space-between; margin: 0 20rpx;">
<text>结束时间</text>
<text>{{ formatTime(reservationData.end_time) }}</text>
</view>
<text style="margin: 30rpx 20rpx 0;">合计:{{ formatDuration(reservationData.duration_minutes) }}</text>
</view>
<view class="column"
style="width: 100%; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx; font-size: 22rpx;">
<text style="margin: 20rpx 20rpx 10rpx; font-size: 24rpx;">房间号:{{ reservationData.room_name || ''
}}</text>
<text style="margin: 10rpx 20rpx;">人数:{{ reservationData.player_count || 0 }}人</text>
<text style="margin: 10rpx 20rpx;">玩法类型:{{ reservationData.game_type || '' }}</text>
<text style="margin: 10rpx 20rpx;">具体规则:{{ reservationData.game_rule || '' }}</text>
<text style="margin: 10rpx 20rpx 20rpx;">补充信息:{{ reservationData.extra_info || '无' }}</text>
</view>
<view class="column"
style="width: 100%; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx; font-size: 22rpx;">
<text style="margin: 20rpx 20rpx 10rpx; font-size: 24rpx;">是否禁烟:{{
getSmokingText(reservationData.is_smoking) }}</text>
<text style="margin: 10rpx 20rpx;">性别:{{ getGenderText(reservationData.gender_limit) }}</text>
<text style="margin: 10rpx 20rpx 20rpx;">信誉:≧{{ reservationData.credit_limit || 0 }}</text>
</view>
<view class="column"
style="width: 100%; background-color: #E3E2E2; margin-top: 20rpx; border-radius: 10rpx; font-size: 22rpx;">
<text style="margin: 20rpx 20rpx 10rpx; font-size: 24rpx;">鸽子费:{{ reservationData.deposit_fee || 0
}}元</text>
<text
style="margin: 10rpx 20rpx 20rpx; color: #9F9F9F;">组局成功后若有牌友未赴约,其鸽子费平均分给其他牌友。组局成功或失败后鸽子费将全额返还。</text>
</view>
<view class="row" v-if="isAddhandleJoin == 0" style="width: 100%; margin-top: 30rpx;">
<view class="center" @click="close"
style="height: 80rpx; flex: 1; background-color: #9F9F9F; border-radius: 10rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">关闭</text>
</view>
<view class="center" @click="handleJoin"
style="height: 80rpx; flex: 3; background-color: #1989FA; border-radius: 10rpx; margin-left: 20rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">参与组局</text>
</view>
</view>
<view class="row" v-if="isAddhandleJoin == 1" style="width: 100%; margin-top: 30rpx;">
<view class="center" @click="close"
style="height: 80rpx; flex: 1; background-color: #9F9F9F; border-radius: 10rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">关闭</text>
</view>
<view class="center" @click="exitJoin"
style="height: 80rpx; flex: 3; background-color: #1989FA; border-radius: 10rpx; margin-left: 20rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">退出组局</text>
</view>
</view>
<view class="row" v-if="isAddhandleJoin == 2" style="width: 100%; margin-top: 30rpx;">
<view class="center" @click="close"
style="height: 80rpx; flex: 1; background-color: #9F9F9F; border-radius: 10rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">关闭</text>
</view>
<view class="center" @click="cancelJoin"
style="height: 80rpx; flex: 3; background-color: #1989FA; border-radius: 10rpx; margin-left: 20rpx;">
<text style="font-size: 24rpx; font-weight: 600; color: white;">取消组局</text>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, computed } from 'vue'
import { userInfo } from '@/common/server/user'
import { showModalConfirm } from '@/common/utils'
// 组件引用
const popup = ref(null)
// 预约数据
const reservationData = ref({})
// 计算属性:发起者信息
const initiatorInfo = computed(() => {
if (reservationData.value.participants && reservationData.value.participants.length > 0) {
return reservationData.value.participants.find(p => p.role === 1) || {}
}
return {}
})
// 计算属性:参与者列表
const participantList = computed(() => {
if (reservationData.value.participants && reservationData.value.participants.length > 0) {
return reservationData.value.participants.filter(p => p.role === 0) || []
}
return []
});
var isAddhandleJoin = ref(0);
// 显示弹窗
const show = (item) => {
reservationData.value = item || {}
if (userInfo.value != null) {
var _initiatorInfo = item.participants.find(p => p.role === 1);
if (_initiatorInfo != null) {
if (userInfo.value.id == _initiatorInfo.user_id) {
isAddhandleJoin.value = 2;
}
}
}
popup.value.open()
}
// 关闭弹窗
const close = () => {
popup.value.close()
}
// 格式化时间
const formatTime = (timeStr) => {
if (!timeStr) return ''
// 将 "2025/09/13 21:09:43" 格式转换为 "2025/09/13 2109"
const date = new Date(timeStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
// 格式化时长
const formatDuration = (minutes) => {
if (!minutes) return '0分钟'
const hours = Math.floor(minutes / 60)
const mins = minutes % 60
if (hours > 0) {
return mins > 0 ? `${hours}小时${mins}分钟` : `${hours}小时`
}
return `${mins}分钟`
}
// 获取禁烟文本
const getSmokingText = (isSmoking) => {
return isSmoking === 1 ? '禁烟' : '不禁烟'
}
// 获取性别限制文本
const getGenderText = (genderLimit) => {
switch (genderLimit) {
case 0:
return '不限'
case 1:
return '男'
case 2:
return '女'
default:
return '不限'
}
}
// 处理加入组局
const handleJoin = () => {
// 触发父组件的加入事件
emit('join', reservationData.value)
}
const cancelJoin = async () => {
var res = await showModalConfirm('提示', '确定要取消组局吗?')
if (res) {
emit('cancelJoin', reservationData.value)
}
}
const exitJoin = async () => {
var res = await showModalConfirm('提示', '确定要退出组局吗?')
if (res) {
emit('exitJoin', reservationData.value)
}
}
// 打开用户信息弹窗
const openUserPop = (user) => {
// 触发父组件的用户信息弹窗事件
emit('openUserPop', user)
}
// 定义事件
const emit = defineEmits(['join', 'openUserPop', 'cancelJoin', 'exitJoin'])
// 暴露方法给父组件
defineExpose({
show,
close
})
</script>
<style lang="scss" scoped>
.column {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
</style>