470 lines
14 KiB
Vue
470 lines
14 KiB
Vue
<template>
|
||
<uni-popup ref="popup" type="center">
|
||
<view class="column center" style="width: 680rpx; background: #F7F7F7; border-radius: 10rpx; padding: 20rpx;">
|
||
|
||
<text style="">预约信息</text>
|
||
|
||
<view class="column card" style="width: 100%; height: 180rpx;">
|
||
<view class="row lable" style="margin-top: 20rpx; align-items: center; margin-left: 20rpx;">
|
||
<text>发起者</text>
|
||
<image :src="initiatorInfo.avatarImage || ''"
|
||
style="width: 50rpx; height: 50rpx; background-color: antiquewhite; border-radius: 50%; margin-left: 20rpx;"
|
||
mode=""></image>
|
||
<text style="margin-left: 15rpx;">{{ initiatorInfo.userName || '' }}</text>
|
||
</view>
|
||
<view class="row lable" style="margin-top: 30rpx; align-items: center; margin-left: 20rpx;">
|
||
<text>参与者</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>
|
||
</view>
|
||
|
||
</view>
|
||
|
||
</view>
|
||
|
||
|
||
<view class="column card lable" style="width: 100%;padding-bottom:20rpx;">
|
||
|
||
<view class="row lable" style="justify-content: space-between; margin: 20rpx;">
|
||
<text>开始时间</text>
|
||
<text>{{ formatTime(reservationData.start_time) }}</text>
|
||
</view>
|
||
<view class="row lable" style="justify-content: space-between; margin: 0 20rpx;">
|
||
<text>结束时间</text>
|
||
<text>{{ formatTime(reservationData.end_time) }}</text>
|
||
</view>
|
||
<text style="margin:20rpx 20rpx 0;">合计:{{
|
||
formatDuration(reservationData.duration_minutes) }}</text>
|
||
|
||
</view>
|
||
|
||
<view class="column card lable" style="width: 100%;">
|
||
<text style="margin: 20rpx 20rpx 10rpx;">房间号:{{ 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 card lable" style="width: 100%; ">
|
||
<text style="margin: 20rpx 20rpx 10rpx;">是否禁烟:{{
|
||
getSmokingText(reservationData.is_smoking) }}</text>
|
||
<text style="margin: 10rpx 20rpx;">性别:{{ getGenderText(reservationData.gender_limit) }}</text>
|
||
<text style="margin: 10rpx 20rpx;">年龄范围:{{
|
||
getAgeRangeText(reservationData.min_age, reservationData.max_age) }}</text>
|
||
<text style="margin: 10rpx 20rpx 20rpx;">信誉:≧{{ reservationData.credit_limit || 0 }}</text>
|
||
</view>
|
||
|
||
<view class="column card lable" style="width: 100%; ">
|
||
<text style="margin: 20rpx 20rpx 10rpx; ">鸽子费:{{ 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>
|
||
<button @click.stop open-type="share" style=" background-color:#00AC4E;color: #fff; height: 80rpx; flex: 1; background-color:#00AC4E; border-radius: 10rpx;margin-left: 20rpx;" class="center evaluate-btn"
|
||
:data-item="reservation">
|
||
<text class="evaluate-btn-text">分享</text>
|
||
</button>
|
||
|
||
</view>
|
||
<view class="row" v-if="isAddhandleJoin == 3" 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>
|
||
</view>
|
||
</uni-popup>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
import { userInfo, isLogin } from '@/common/server/user'
|
||
import { showModalConfirm, requestSubscribeMessage, requestPayment } from '@/common/utils'
|
||
import { getSubscribeMessage } from '@/common/server/config'
|
||
import { usePay } from '@/common/server/interface/user'
|
||
import { joinReservation, cancelReservation } from '@/common/server/interface/sq'
|
||
|
||
// 组件引用
|
||
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) => {
|
||
console.log("itemitemitemitem", item)
|
||
reservationData.value = item || {}
|
||
isAddhandleJoin.value = 0;
|
||
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;
|
||
}
|
||
}
|
||
var _joinInfo = item.participants.find(p => p.role === 0);
|
||
if (_joinInfo != null) {
|
||
if (userInfo.value.id == _joinInfo.user_id) {
|
||
isAddhandleJoin.value = 1;
|
||
}
|
||
}
|
||
}
|
||
popup.value.open()
|
||
}
|
||
|
||
// 关闭弹窗
|
||
const close = () => {
|
||
popup.value.close()
|
||
}
|
||
|
||
// 格式化时间
|
||
const formatTime = (timeStr) => {
|
||
if (!timeStr) return ''
|
||
// 将 "2025/09/13 21:09:43" 格式转换为 "2025/09/13 21:09"
|
||
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 getAgeRangeText = (minAge, maxAge) => {
|
||
if (minAge == 0 && maxAge == 0) {
|
||
return "不限";
|
||
}
|
||
let s = "";
|
||
if (minAge == 0) {
|
||
s = "不限";
|
||
} else {
|
||
s = minAge + "岁";
|
||
}
|
||
s += " ~ ";
|
||
if (maxAge == 0) {
|
||
s += "不限";
|
||
} else {
|
||
s += maxAge + "岁";
|
||
}
|
||
return s;
|
||
}
|
||
// 处理加入组局
|
||
const handleJoin = async () => {
|
||
// 检查登录状态
|
||
var isLoginSuccess = await isLogin();
|
||
if (!isLoginSuccess) {
|
||
close();
|
||
uni.navigateTo({
|
||
url: '/pages/me/login'
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 获取订阅消息
|
||
var messageId = await getSubscribeMessage(reservationData.value.deposit_fee);
|
||
console.log("messageId", messageId);
|
||
var subscribeMessage = await requestSubscribeMessage(messageId);
|
||
console.log("message", subscribeMessage);
|
||
|
||
// 显示加载状态
|
||
uni.showLoading({
|
||
title: '加入中...'
|
||
});
|
||
|
||
// 准备加入数据
|
||
const joinData = {
|
||
ReservationsId: reservationData.value.id,
|
||
important_data: {}
|
||
};
|
||
|
||
var resPay = null;
|
||
// 如果有鸽子费,需要先支付
|
||
if (reservationData.value.deposit_fee > 0) {
|
||
resPay = await usePay(reservationData.value.deposit_fee);
|
||
if (resPay == null) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '鸽子费订单创建失败,请重新尝试!',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
subscribeMessage.result.paymentId = resPay.paymentId;
|
||
}
|
||
|
||
// 准备重要数据
|
||
var important_data = "";
|
||
if (subscribeMessage.result != null) {
|
||
important_data = JSON.stringify(subscribeMessage.result);
|
||
}
|
||
joinData.important_data = important_data;
|
||
|
||
// 调用加入预约接口
|
||
const result = await joinReservation(joinData);
|
||
uni.hideLoading();
|
||
console.log("join result", result);
|
||
|
||
if (!result.success) {
|
||
uni.showToast({
|
||
title: result.message,
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 如果有鸽子费,进行支付
|
||
if (reservationData.value.deposit_fee > 0 && resPay != null) {
|
||
var payRes = await requestPayment(resPay);
|
||
if (payRes.success) {
|
||
uni.showToast({
|
||
title: '鸽子费支付成功,加入组局成功!',
|
||
icon: 'success'
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '鸽子费支付失败,请重新加入!',
|
||
icon: 'none'
|
||
});
|
||
await cancelReservation(result.data, "鸽子费支付失败,请重新加入!");
|
||
return;
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: '加入组局成功!',
|
||
icon: 'success'
|
||
});
|
||
}
|
||
|
||
// 关闭弹窗
|
||
close();
|
||
// 触发刷新列表事件
|
||
emit('refreshList');
|
||
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('加入组局失败:', error);
|
||
uni.showToast({
|
||
title: '加入失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
//取消组局
|
||
const cancelJoin = async () => {
|
||
var res = await showModalConfirm('提示', '确定要取消组局吗?')
|
||
if (res) {
|
||
try {
|
||
// 显示加载状态
|
||
uni.showLoading({
|
||
title: '取消中...'
|
||
});
|
||
|
||
// 调用取消预约接口
|
||
const result = await cancelReservation(reservationData.value.id, "发起者取消组局");
|
||
uni.hideLoading();
|
||
console.log("cancel result", result);
|
||
|
||
if (result.success) {
|
||
uni.showToast({
|
||
title: '取消组局成功!',
|
||
icon: 'success'
|
||
});
|
||
// 关闭弹窗
|
||
close();
|
||
// 触发刷新列表事件
|
||
emit('refreshList');
|
||
} else {
|
||
uni.showToast({
|
||
title: result.message,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('取消组局失败:', error);
|
||
uni.showToast({
|
||
title: '取消失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
}
|
||
//退出组局
|
||
const exitJoin = async () => {
|
||
var res = await showModalConfirm('提示', '确定要退出组局吗?')
|
||
if (res) {
|
||
try {
|
||
// 显示加载状态
|
||
uni.showLoading({
|
||
title: '退出中...'
|
||
});
|
||
|
||
// 调用取消预约接口(参与者退出)
|
||
const result = await cancelReservation(reservationData.value.id, "参与者退出组局");
|
||
uni.hideLoading();
|
||
console.log("exit result", result);
|
||
|
||
if (result.success) {
|
||
uni.showToast({
|
||
title: '退出组局成功!',
|
||
icon: 'success'
|
||
});
|
||
// 关闭弹窗
|
||
close();
|
||
// 触发刷新列表事件
|
||
emit('refreshList');
|
||
} else {
|
||
uni.showToast({
|
||
title: result.message,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading();
|
||
console.error('退出组局失败:', error);
|
||
uni.showToast({
|
||
title: '退出失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
}
|
||
// 打开用户信息弹窗
|
||
const openUserPop = (user) => {
|
||
// 触发父组件的用户信息弹窗事件
|
||
emit('openUserPop', user)
|
||
}
|
||
|
||
// 定义事件
|
||
const emit = defineEmits(['openUserPop', 'refreshList'])
|
||
|
||
// 暴露方法给父组件
|
||
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;
|
||
}
|
||
|
||
.card {
|
||
background: #FFFFFF;
|
||
box-shadow: 0rpx 0rpx 10rpx 4rpx rgba(0, 0, 0, 0.25);
|
||
border-radius: 30rpx 30rpx 30rpx 30rpx;
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.lable {
|
||
font-family: PingFang SC, PingFang SC;
|
||
font-size: 22rpx;
|
||
|
||
}
|
||
</style>
|