修改时间
This commit is contained in:
parent
e76590f61e
commit
193b9a1e0f
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
## Bug统计
|
||||
- **总数量**: 9个
|
||||
- **已修复**: 1个 ✅
|
||||
- **未修改**: 8个
|
||||
- **已修复**: 2个 ✅
|
||||
- **未修改**: 7个
|
||||
- **分类**: 后端问题 6个,前端问题 2个,前后端问题 3个
|
||||
|
||||
---
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
---
|
||||
|
||||
### cs110_24 - 已评价组局消息未消失
|
||||
**状态**: 未修改
|
||||
**状态**: ✅ 已修复
|
||||
**类型**: 后端
|
||||
**优先级**: 中
|
||||
|
||||
|
|
@ -48,11 +48,32 @@
|
|||
我的页面中,已结束的牌局在给牌友评价后,该组局消息没有消失。
|
||||
|
||||
**解决方案**:
|
||||
需要明确消失逻辑:
|
||||
- 所有参与者都完成评价后消息消失
|
||||
- 或者预约结束后7天自动消失
|
||||
- 需要产品确认具体的消失逻辑
|
||||
- uniapp\mahjong_group\pages\me\me-page.vue 我的页面
|
||||
用户只要评价过一次(不管评价了谁),这个预约就应该从"我的页面"中消失。如果用户还想继续评价其他人,可以去"预约记录"页面找到这个预约继续评价。
|
||||
|
||||
**修复内容**:
|
||||
1. **后端接口修改** (`server/CoreCms.Net.Web.WebApi/Controllers/SQController.cs`)
|
||||
- 修改`GetMyUseReservation`接口的SQL查询条件
|
||||
- 添加`NOT EXISTS`子查询,排除当前用户已经评价过的预约
|
||||
- 查询逻辑:如果用户对某个预约有评价记录,该预约就不会显示在"我的页面"中
|
||||
|
||||
2. **前端评价组件** (`uniapp/mahjong_group/components/com/page/reservation-evaluate.vue`)
|
||||
- 修改`submitEvaluate`方法
|
||||
- 评价成功后触发全局事件`evaluateSuccess`
|
||||
- 延迟1.5秒后关闭弹窗并通知刷新数据
|
||||
|
||||
3. **我的页面** (`uniapp/mahjong_group/pages/me/me-page.vue`)
|
||||
- 添加`onLoad`、`onUnload`生命周期导入
|
||||
- 在`onLoad`中监听`evaluateSuccess`事件
|
||||
- 收到事件后重新调用`loadCurrentAppointment()`刷新数据
|
||||
- 在`onUnload`中移除事件监听,避免内存泄漏
|
||||
|
||||
**修复逻辑**:
|
||||
- 用户评价任意一个人后,该预约立即从"我的页面"消失
|
||||
- 如需继续评价其他人,用户可前往"预约记录"页面查找
|
||||
- 保持页面简洁,避免已处理预约长期占用显示空间
|
||||
|
||||
**修复时间**: 2025-01-01
|
||||
**测试状态**: 待测试
|
||||
---
|
||||
|
||||
### cs120_1 - 时间段预约逻辑错误
|
||||
|
|
@ -238,7 +259,7 @@
|
|||
- cs120_9 - 鸽子费审核功能缺失
|
||||
|
||||
### 🟡 中优先级(影响用户体验)
|
||||
- cs110_24 - 已评价组局消息未消失
|
||||
- ✅ cs110_24 - 已评价组局消息未消失(已修复)
|
||||
- cs120_3 - 首页高度显示异常
|
||||
- cs120_4 - 房间卡片文字显示不全
|
||||
- cs120_5 - 签到后页面状态未刷新
|
||||
|
|
|
|||
|
|
@ -232,9 +232,6 @@ namespace CoreCms.Net.Model.Entities
|
|||
[Display(Name = "状态:0=待开始,1=锁定中,2=进行中,3=已结束,4=取消")]
|
||||
|
||||
[Required(ErrorMessage = "请输入{0}")]
|
||||
|
||||
|
||||
|
||||
public System.Int32 status { get; set; }
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<ReservationPopup ref="_reservationPopup" />
|
||||
<up-datetime-picker :show="_upDatesTimePicker.show" :filter="_upDatesTimePicker.filter"
|
||||
:formatter="_upDatesTimePicker.formatter" v-model="_upDatesTimePicker.value" mode="datetime"
|
||||
:minDate="_upDatesTimePicker.minDate" @cancel="_upDatesTimePicker.onCancel"
|
||||
:minDate="_upDatesTimePicker.minDate" :maxDate="_upDatesTimePicker.maxDate" @cancel="_upDatesTimePicker.onCancel"
|
||||
@confirm="_upDatesTimePicker.onConfirm" :title="_upDatesTimePicker.title"
|
||||
:hasInput="false"></up-datetime-picker>
|
||||
</view>
|
||||
|
|
@ -34,12 +34,14 @@ const openQianDaoPop = async (reservation) => {
|
|||
console.log("openQianDaoPop", reservation)
|
||||
_qianDaoPopup.value && _qianDaoPopup.value.show(reservation)
|
||||
}
|
||||
let maxt=Date.now() + 6 * 24 * 60 * 60 * 1000;
|
||||
const _upDatesTimePicker = ref({
|
||||
refId: null,
|
||||
show: false,
|
||||
value: Date.now(),
|
||||
title: '',
|
||||
minDate: Date.now(),
|
||||
maxDate: maxt, // 当前日期+7天
|
||||
filter: (mode, options) => {
|
||||
// console.log("filter", mode, options)
|
||||
if (mode == "minute") {
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ const handleJoin = () => {
|
|||
|
||||
.grid-item {
|
||||
width: 300rpx;
|
||||
height: 405rpx;
|
||||
height: 425rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: -4rpx 12rpx 7rpx 0rpx rgba(0, 0, 0, 0.25);
|
||||
border-radius: 27rpx;
|
||||
|
|
|
|||
899
uniapp/mahjong_group/pages/appointment/appointment-page-ls.vue
Normal file
899
uniapp/mahjong_group/pages/appointment/appointment-page-ls.vue
Normal file
|
|
@ -0,0 +1,899 @@
|
|||
<template>
|
||||
<com-page-container-base ref="_containerBase">
|
||||
<view class="content column">
|
||||
|
||||
<text class="page-title">发起预约</text>
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
<label-field label="预定时长">
|
||||
<tag-select :options="timeRange" v-model="timeRangeValue" @change="onTimeRangeChange" />
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<time-select-cell label="开始时间" icon="@@:app/static/time_start.png" @select="openUpDatesTimePicker">
|
||||
{{ getDayDescription(reservationInfo.start_time * 1000) }}
|
||||
</time-select-cell>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<time-select-cell label="结束时间" icon="@@:app/static/time_end.png" @select="openUpDatesTimePickerEnd">
|
||||
{{ getDayDescription(reservationInfo.end_time * 1000) }}
|
||||
</time-select-cell>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<time-select-cell label="房间" @select="openRoomPicker">
|
||||
{{ getRoomPickerName() }}
|
||||
</time-select-cell>
|
||||
</card-container>
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
|
||||
<label-field label="组局名称">
|
||||
<view class="input-wrapper">
|
||||
<up-input placeholder="请输入内容" border="surround" v-model="reservationInfo.title"></up-input>
|
||||
</view>
|
||||
</label-field>
|
||||
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="人数">
|
||||
<uni-data-select v-model="reservationInfo.player_count" :placeholder="peopleText"
|
||||
:localdata="peopleRange"></uni-data-select>
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="玩法类型">
|
||||
<uni-data-select v-model="reservationInfo.game_type" placeholder="请选择玩法类型"
|
||||
:localdata="gameTypeRange" @change="gameTypeRangeChange"></uni-data-select>
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="具体规则">
|
||||
<uni-data-select v-model="reservationInfo.game_rule" :placeholder="gameRuleText"
|
||||
:localdata="gameRuleRange" @change="gameRuleRangeChange"></uni-data-select>
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="其他补充">
|
||||
<view class="input-wrapper">
|
||||
<up-input placeholder="请输入其他补充内容" v-model="reservationInfo.extra_info"></up-input>
|
||||
</view>
|
||||
</label-field>
|
||||
|
||||
</card-container>
|
||||
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
<label-slect-field label="是否禁烟">
|
||||
<view style="height: 61rpx;display: flex;justify-content: left;align-items: center;">
|
||||
<com-appointment-radio-select :options="smokingOptions" v-model="reservationInfo.is_smoking" />
|
||||
</view>
|
||||
</label-slect-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-slect-field label="性别">
|
||||
<view style="height: 61rpx;display: flex;justify-content: left;align-items: center;">
|
||||
<com-appointment-radio-select :options="genderOptions" v-model="reservationInfo.gender_limit" />
|
||||
</view>
|
||||
</label-slect-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-slect-field label="年龄范围">
|
||||
<view @click="openAgePicker"
|
||||
style="height: 61rpx;display: flex;justify-content: left;align-items: center;"
|
||||
class="clickable-row">
|
||||
{{ getAgeRangeText() }}
|
||||
</view>
|
||||
</label-slect-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-slect-field label="信誉">
|
||||
<view class="flex-center-row" style="height: 61rpx;">
|
||||
<text class="inline-label" style="margin-top: 12rpx;">大于等于</text>
|
||||
<view class="counter-container">
|
||||
<view @click="decrement" :disabled="currentValue <= 0">
|
||||
<uni-icons type="minus" size="24" color="#00AC4E" />
|
||||
</view>
|
||||
<view class="counter-value">
|
||||
{{ currentValue.toFixed(1) }}
|
||||
</view>
|
||||
<view @click="increment" :disabled="currentValue >= 5">
|
||||
<uni-icons type="plus" size="24" color="#00AC4E" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</label-slect-field>
|
||||
</card-container>
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
|
||||
<label-slect-field label="鸽子费">
|
||||
<com-appointment-radio-select :options="depositOptions" v-model="reservationInfo.deposit_fee" />
|
||||
</label-slect-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<text class="note-text">鸽子费(保证金),参与人需缴纳鸽子费。若有参与者在预约后没有赴约,其鸽子费由在场的所有人平分。组局成功或失败后鸽子费将全额返还。</text>
|
||||
</card-container>
|
||||
|
||||
<view class="action-row">
|
||||
<view class="center reset-button" @click="resetForm">
|
||||
<text style="margin: 20rpx;">重置</text>
|
||||
</view>
|
||||
<view class="center submit-button action-submit" @click="submitReservation">
|
||||
<text style="margin: 20rpx; color: white;">发起预约</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="center note-container" @click="tipsShow">
|
||||
|
||||
<!-- <text class="muted-text">组局成功后,发起者可通过店员领取线下红包</text> -->
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
<com-appointment-picker-data ref="roomPickerRef" />
|
||||
<up-picker title="年龄范围选择" :show="agePickerVisible" :columns="agePickerColumns" :keyName="'text'"
|
||||
:defaultIndex="agePickerDefaultIndex" @confirm="onAgePickerConfirm" @cancel="() => agePickerVisible = false"
|
||||
@close="() => agePickerVisible = false"></up-picker>
|
||||
|
||||
<uni-popup ref="submitPopupRef" type="center">
|
||||
|
||||
<view style="width: 90vw;height:300rpx;background-color: #fff;border-radius: 20rpx;">
|
||||
<view>
|
||||
<view style="height: 80rpx;"></view>
|
||||
<view style="font-size: 32rpx;font-weight: 500;color: #000;text-align: center;">发起预约成功!</view>
|
||||
<view style="height:100rpx;"></view>
|
||||
<view style="display: flex;width: 100%;height:100rpx;">
|
||||
<button @click.stop open-type="share"
|
||||
style=" background-color:#00AC4E;color: #fff;width: 50%;height: 100%; background-color:#00AC4E;"
|
||||
class="center evaluate-btn" :data-item="reservation">
|
||||
<text class="evaluate-btn-text">分享给好友</text>
|
||||
</button>
|
||||
|
||||
<view
|
||||
style="width: 50%;height: 100%;background-color: #f7f7f7;display: flex;align-items: center;justify-content: center;"
|
||||
@click="submitPopupRef.close();">
|
||||
<text>关闭</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
</com-page-container-base>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
watch
|
||||
} from 'vue';
|
||||
import {
|
||||
getConfigData, getSubscribeMessage
|
||||
} from '@/common/server/config'
|
||||
import { usePay } from '@/common/server/interface/user'
|
||||
import {
|
||||
requestSubscribeMessage,
|
||||
requestPayment
|
||||
} from '@/common/utils'
|
||||
import {
|
||||
getDayDescription,
|
||||
ceilMinuteToNext5
|
||||
} from '@/common/system/timeUtile';
|
||||
import { isLogin } from '@/common/server/user'
|
||||
import {
|
||||
forEach,
|
||||
union
|
||||
} from 'lodash';
|
||||
import {
|
||||
|
||||
getDetail
|
||||
} from '@/common/server/index'
|
||||
|
||||
import TimeSelectCell from '@/components/com/appointment/time-select-cell.vue'
|
||||
import LabelField from '@/components/com/appointment/label-field.vue'
|
||||
import LabelSlectField from '@/components/com/appointment/label-slect-field.vue'
|
||||
import CardContainer from '@/components/com/appointment/card-container.vue'
|
||||
import TagSelect from '@/components/com/appointment/tag-select.vue'
|
||||
import ComAppointmentPickerData from '@/components/com/appointment/picker-data.vue'
|
||||
import ComAppointmentRadioSelect from '@/components/com/appointment/radio-select.vue'
|
||||
import {
|
||||
getReservationRoomList, addSQReservation, cancelReservation, canCreateSQReservation
|
||||
} from '@/common/server/interface/sq'
|
||||
const _containerBase = ref(null)
|
||||
const submitPopupRef = ref(null)
|
||||
// 年龄选择器状态
|
||||
const agePickerVisible = ref(false)
|
||||
const agePickerColumns = ref([[], []])
|
||||
const agePickerDefaultIndex = ref([0, 0])
|
||||
const reservationData = ref(null)
|
||||
const lineHeight = ref("15rpx")
|
||||
const timeRange = ref(["2小时", "3小时", "4小时", "自定义"])
|
||||
const timeRangeValue = ref("")
|
||||
// 房间选项
|
||||
const roomOptions = ref([])
|
||||
const roomPickerRef = ref(null)
|
||||
//提交表单数据
|
||||
const reservationInfo = ref({
|
||||
room_id: 0, //房间id 非空
|
||||
room_name: '请选择房间', //房间名称
|
||||
start_time: 0, //开始时间 时间戳 非空
|
||||
end_time: 0, //结束时间 时间戳 非空
|
||||
max_age: 0, //最大年龄 默认0
|
||||
min_age: 0, //最小年龄 非空
|
||||
title: '', //组局名称 非空
|
||||
extra_info: '', //其它说明 可为空
|
||||
game_rule: '', //具体规则 非空
|
||||
game_type: '', //玩法类型 非空
|
||||
gender_limit: 0, //性别限制
|
||||
is_smoking: 2, //是否禁烟
|
||||
credit_limit: 0, //信誉限制
|
||||
deposit_fee: 0, //鸽子费
|
||||
player_count: 0, //人数
|
||||
});
|
||||
//自动计算结束时间
|
||||
const onTimeRangeChange = async (val) => {
|
||||
timeRangeValue.value = val;
|
||||
console.log('timeRange change:', val)
|
||||
if (val != "") {
|
||||
await openUpDatesTimePicker(false);
|
||||
if (reservationInfo.value.start_time > 0) {
|
||||
var str = val;
|
||||
if (str == "2小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 2 * 60 * 60;
|
||||
} else if (str == "3小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 3 * 60 * 60;
|
||||
} else if (str == "4小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 4 * 60 * 60;
|
||||
} else {
|
||||
await openUpDatesTimePickerEnd(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const getRoomPickerName = () => {
|
||||
return reservationInfo.value.room_name;
|
||||
}
|
||||
const tipsShow = () => {
|
||||
submitPopupRef.value.open()
|
||||
}
|
||||
|
||||
const openUpDatesTimePicker = async (isManual = true) => {
|
||||
var now = reservationInfo.value.start_time * 1000;
|
||||
var min = Date.now();
|
||||
min += 1000 * 60 * 30;
|
||||
min = ceilMinuteToNext5(min).valueOf();
|
||||
if (reservationInfo.value.start_time == 0) {
|
||||
now = Date.now();
|
||||
now += 1000 * 60 * 30;
|
||||
now = ceilMinuteToNext5(now).valueOf();
|
||||
}
|
||||
const startTime = await _containerBase.value.openUpDatesTimePicker(now, min, "预约开始时间")
|
||||
// 直接设置到表单对象,毫秒转秒
|
||||
reservationInfo.value.start_time = Math.floor(startTime / 1000)
|
||||
// 手动选择时间则切换为"自定义"
|
||||
if (isManual) {
|
||||
timeRangeValue.value = "自定义"
|
||||
}
|
||||
}
|
||||
const openUpDatesTimePickerEnd = async (isManual = true) => {
|
||||
if (reservationInfo.value.start_time == 0) {
|
||||
uni.showToast({
|
||||
title: '请先选择开始时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
var now = reservationInfo.value.end_time * 1000;
|
||||
var min = (reservationInfo.value.start_time * 1000 + 1000 * 60 * 30);
|
||||
if (now == 0) {
|
||||
now = (reservationInfo.value.start_time * 1000 + 1000 * 60 * 30);
|
||||
}
|
||||
//minDate+1000*60*30 最小间隔30分钟
|
||||
const endTime = await _containerBase.value.openUpDatesTimePicker(now, min, "预约结束时间")
|
||||
// 直接设置到表单对象,毫秒转秒
|
||||
reservationInfo.value.end_time = Math.floor(endTime / 1000)
|
||||
// 手动选择时间则切换为"自定义"
|
||||
if (isManual) {
|
||||
timeRangeValue.value = "自定义"
|
||||
}
|
||||
}
|
||||
const maxPlayerCount = ref(0)
|
||||
const openRoomPicker = async () => {
|
||||
// 需先选择有效的开始/结束时间
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) {
|
||||
uni.showToast({
|
||||
title: '请先选择开始和结束时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (reservationInfo.value.end_time <= reservationInfo.value.start_time) {
|
||||
uni.showToast({
|
||||
title: '结束时间需晚于开始时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
// 无数据则尝试拉取
|
||||
if (!roomOptions.value || roomOptions.value.length === 0) {
|
||||
await tryLoadRooms()
|
||||
}
|
||||
if (!roomOptions.value || roomOptions.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '暂无可预约房间',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
const selected = await roomPickerRef.value.show({
|
||||
options: roomOptions.value,
|
||||
valueKey: 'id',
|
||||
labelKey: 'name',
|
||||
modelValue: reservationInfo.value.room_id
|
||||
})
|
||||
if (selected) {
|
||||
reservationInfo.value.room_id = selected.id
|
||||
reservationInfo.value.room_name = selected.name
|
||||
maxPlayerCount.value = selected.capacity
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const peopleRange = ref([])
|
||||
const peopleText = ref("请先选择房间");
|
||||
const gameTypeRange = ref([])
|
||||
const gameRuleRange = ref([])
|
||||
const gameRuleText = ref("请先选择玩法类型");
|
||||
const gameTypeRangeChange = (e) => {
|
||||
console.log('gameTypeRangeChange:', e)
|
||||
// gameRuleRange.value
|
||||
if (e == 0) {
|
||||
gameRuleRange.value = [];
|
||||
reservationInfo.value.game_rule = 0;
|
||||
gameRuleText.value = "请先选择玩法类型";
|
||||
} else {
|
||||
var f = gameTypeRange.value.find(it => it.value == e);
|
||||
console.log('f', f);
|
||||
gameRuleText.value = "请选择具体规则";
|
||||
var temp = [];
|
||||
|
||||
if (f.children != null && f.children.length > 0) {
|
||||
|
||||
f.children.forEach(e => {
|
||||
temp.push({
|
||||
value: e.id,
|
||||
text: e.name
|
||||
})
|
||||
})
|
||||
}
|
||||
gameRuleRange.value = temp;
|
||||
|
||||
}
|
||||
}
|
||||
const gameRuleRangeChange = (e) => {
|
||||
console.log('gameRuleRangeChange:', e)
|
||||
}
|
||||
|
||||
// 获取玩法类型文本
|
||||
const getGameTypeText = (gameTypeValue) => {
|
||||
if (!gameTypeValue || gameTypeValue === 0) {
|
||||
return '';
|
||||
}
|
||||
const gameType = gameTypeRange.value.find(item => item.value === gameTypeValue);
|
||||
return gameType ? gameType.text : '';
|
||||
}
|
||||
|
||||
// 获取具体规则文本
|
||||
const getGameRuleText = (gameRuleValue) => {
|
||||
if (!gameRuleValue || gameRuleValue === 0) {
|
||||
return '';
|
||||
}
|
||||
const gameRule = gameRuleRange.value.find(item => item.value === gameRuleValue);
|
||||
return gameRule ? gameRule.text : '';
|
||||
}
|
||||
|
||||
const smokingOptions = ref([
|
||||
{ value: 2, text: '不禁烟' },
|
||||
{ value: 1, text: '禁烟' },
|
||||
])
|
||||
const genderOptions = ref([
|
||||
{ value: 0, text: '不限' },
|
||||
{ value: 1, text: '男' },
|
||||
{ value: 2, text: '女' },
|
||||
])
|
||||
const depositOptions = ref([
|
||||
{ value: 0, text: '0元' },
|
||||
{ value: 5, text: '5元' },
|
||||
{ value: 10, text: '10元' },
|
||||
])
|
||||
|
||||
const currentValue = ref(0)
|
||||
|
||||
const increment = () => {
|
||||
if (currentValue.value < 5) {
|
||||
currentValue.value += 0.5
|
||||
if (currentValue.value > 5) {
|
||||
currentValue.value = 5
|
||||
}
|
||||
// 同步到表单对象
|
||||
reservationInfo.value.credit_limit = currentValue.value
|
||||
}
|
||||
}
|
||||
|
||||
const decrement = () => {
|
||||
if (currentValue.value > 0) {
|
||||
currentValue.value -= 0.5
|
||||
if (currentValue.value < 0) {
|
||||
currentValue.value = 0
|
||||
}
|
||||
// 同步到表单对象
|
||||
reservationInfo.value.credit_limit = currentValue.value
|
||||
}
|
||||
}
|
||||
|
||||
const changeLog = (e) => {
|
||||
console.log('change事件:', e)
|
||||
}
|
||||
|
||||
// 表单验证方法
|
||||
const validateForm = () => {
|
||||
const info = reservationInfo.value
|
||||
|
||||
// 必填字段验证
|
||||
if (!info.room_id || info.room_id === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择房间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.start_time || info.start_time === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择开始时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.end_time || info.end_time === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择结束时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (info.end_time <= info.start_time) {
|
||||
uni.showToast({
|
||||
title: '结束时间需晚于开始时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.title || info.title.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请输入组局名称',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.player_count || info.player_count === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择游玩人数',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.game_type || info.game_type === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择玩法类型',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (!info.game_rule || info.game_rule === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择具体规则',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
// 年龄范围验证(如果设置了年龄限制)
|
||||
if (info.min_age > 0 && info.max_age > 0 && info.min_age > info.max_age) {
|
||||
uni.showToast({
|
||||
title: '最小年龄不能大于最大年龄',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 提交预约方法
|
||||
const submitReservation = async () => {
|
||||
var isLoginSucces = await isLogin();
|
||||
if (!isLoginSucces) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/me/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 验证表单
|
||||
if (!validateForm()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
var messageId = await getSubscribeMessage(reservationInfo.value.deposit_fee);
|
||||
console.log("messageId", messageId);
|
||||
var subscribeMessage = await requestSubscribeMessage(messageId);
|
||||
console.log("message", subscribeMessage);
|
||||
|
||||
// 显示加载状态
|
||||
uni.showLoading({
|
||||
title: '提交中...'
|
||||
})
|
||||
|
||||
// 准备提交数据
|
||||
const submitData = {
|
||||
...reservationInfo.value,
|
||||
// 确保信誉限制同步
|
||||
credit_limit: currentValue.value,
|
||||
important_data: {}
|
||||
}
|
||||
|
||||
// 将玩法类型和具体规则从数字转换为字符串
|
||||
submitData.game_type = getGameTypeText(submitData.game_type);
|
||||
submitData.game_rule = getGameRuleText(submitData.game_rule);
|
||||
var important_data = "";
|
||||
if (subscribeMessage.result != null) {
|
||||
important_data = JSON.stringify(subscribeMessage.result);
|
||||
}
|
||||
submitData.important_data = important_data;
|
||||
// 检测是否能创建预约 ,如果不能创建则提示并中断
|
||||
const canCreateRes = await canCreateSQReservation(submitData)
|
||||
if (!canCreateRes || canCreateRes.canCreate !== true) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: (canCreateRes && canCreateRes.message) ? canCreateRes.message : '当前条件不可创建预约',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var resPay = null;
|
||||
if (submitData.deposit_fee > 0) {
|
||||
resPay = await usePay(submitData.deposit_fee);
|
||||
if (resPay == null) {
|
||||
uni.showToast({
|
||||
title: '鸽子费订单创建失败,请重新提交预约数据!',
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
subscribeMessage.result.paymentId = resPay.paymentId;
|
||||
if (subscribeMessage.result != null) {
|
||||
important_data = JSON.stringify(subscribeMessage.result);
|
||||
}
|
||||
submitData.important_data = important_data;
|
||||
}
|
||||
|
||||
// TODO: 调用后端API提交预约
|
||||
// 调用后端API提交预约
|
||||
const result = await addSQReservation(submitData)
|
||||
uni.hideLoading()
|
||||
console.log("result", result);
|
||||
if (!result.success) {
|
||||
uni.showToast({
|
||||
title: result.message,
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (submitData.deposit_fee > 0 && resPay != null) {
|
||||
var payRes = await requestPayment(resPay);
|
||||
if (payRes.success) {
|
||||
uni.showToast({
|
||||
title: '鸽子费支付成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
await cancelReservation(result.data, "鸽子费支付失败,请重新预约!");
|
||||
uni.showToast({
|
||||
title: '鸽子费支付失败,请重新预约!',
|
||||
icon: 'none'
|
||||
})
|
||||
return;
|
||||
}
|
||||
console.log("payRes", payRes);
|
||||
}
|
||||
var share_id = result.data;
|
||||
var detailData = await getDetail(share_id);
|
||||
if (detailData != null) {
|
||||
reservationData.value = detailData;
|
||||
tipsShow();
|
||||
} else {
|
||||
|
||||
// 提交成功
|
||||
uni.showToast({
|
||||
title: '预约提交成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
// 可以跳转到其他页面或重置表单
|
||||
// uni.navigateBack() // 返回上一页
|
||||
// 或者重置表单
|
||||
resetForm()
|
||||
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('提交预约失败:', error)
|
||||
uni.showToast({
|
||||
title: '提交失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单方法(可选)
|
||||
const resetForm = () => {
|
||||
reservationInfo.value = {
|
||||
room_id: 0,
|
||||
room_name: '请选择房间',
|
||||
start_time: 0,
|
||||
end_time: 0,
|
||||
max_age: 0,
|
||||
min_age: 0,
|
||||
title: '',
|
||||
extra_info: '',
|
||||
game_rule: '',
|
||||
game_type: '',
|
||||
gender_limit: 0,
|
||||
is_smoking: 2,
|
||||
credit_limit: 0,
|
||||
deposit_fee: 0,
|
||||
player_count: 0,
|
||||
}
|
||||
currentValue.value = 0
|
||||
timeRangeValue.value = ""
|
||||
gameRuleRange.value = []
|
||||
peopleRange.value = []
|
||||
peopleText.value = "请先选择房间"
|
||||
gameRuleText.value = "请先选择玩法类型"
|
||||
}
|
||||
|
||||
// 当开始或结束时间变化时自动刷新房间
|
||||
watch([() => reservationInfo.value.start_time, () => reservationInfo.value.end_time], async ([s, e]) => {
|
||||
await tryLoadRooms()
|
||||
})
|
||||
|
||||
watch(() => reservationInfo.value.room_id, async (newId, oldId) => {
|
||||
console.log('room_id changed:', oldId, '->', newId);
|
||||
if (newId == 0) {
|
||||
reservationInfo.value.player_count = 0;
|
||||
peopleRange.value = [];
|
||||
peopleText.value = "请先选择房间";
|
||||
} else {
|
||||
var t = [];
|
||||
peopleText.value = "请选择游玩人数";
|
||||
for (let i = 2; i <= maxPlayerCount.value; i++) {
|
||||
t.push({
|
||||
value: i,
|
||||
text: i + '人'
|
||||
});
|
||||
}
|
||||
console.log("peopleRange.value ", maxPlayerCount.value, t);
|
||||
if (reservationInfo.value.player_count > maxPlayerCount.value) {
|
||||
reservationInfo.value.player_count = 0;
|
||||
}
|
||||
peopleRange.value = t;
|
||||
}
|
||||
});
|
||||
|
||||
// 拉取可预约房间
|
||||
const tryLoadRooms = async () => {
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) return
|
||||
if (reservationInfo.value.end_time <= reservationInfo.value.start_time) return
|
||||
const list = await getReservationRoomList(reservationInfo.value.start_time, reservationInfo.value.end_time)
|
||||
// list.push()
|
||||
if (Array.isArray(list)) {
|
||||
roomOptions.value = Array.isArray(list) ? list : []
|
||||
} else {
|
||||
roomOptions.value = []
|
||||
}
|
||||
// 若当前选中房间不在可选列表中,则清空
|
||||
console.log("房间id==>", reservationInfo.value.room_id, "房间列表==>", roomOptions.value);
|
||||
|
||||
if (!roomOptions.value.some(it => it.id === reservationInfo.value.room_id)) {
|
||||
reservationInfo.value.room_id = 0;
|
||||
reservationInfo.value.room_name = '请选择房间';
|
||||
}
|
||||
}
|
||||
onLoad(async () => {
|
||||
const config = await getConfigData();
|
||||
console.log('config', config);
|
||||
if (config != null && config.config != null) {
|
||||
gameTypeRange.value = [...config.config.playingMethodOptions];
|
||||
}
|
||||
})
|
||||
onShow(async () => {
|
||||
// resetForm();
|
||||
})
|
||||
// 年龄列构建与显示/文案
|
||||
const buildAgeColumns = () => {
|
||||
const minList = [{ value: 0, text: '不限' }]
|
||||
for (let i = 18; i <= 80; i++) minList.push({ value: i, text: String(i) })
|
||||
const maxList = [{ value: 0, text: '不限' }]
|
||||
for (let i = 18; i <= 80; i++) maxList.push({ value: i, text: String(i) })
|
||||
agePickerColumns.value = [minList, maxList]
|
||||
}
|
||||
const getAgeRangeText = () => {
|
||||
const { min_age, max_age } = reservationInfo.value
|
||||
if (min_age == 0 && max_age == 0) {
|
||||
return '不限'
|
||||
}
|
||||
const minText = min_age === 0 ? '不限' : min_age + '岁'
|
||||
const maxText = max_age === 0 ? '不限' : max_age + '岁'
|
||||
return minText + ' - ' + maxText
|
||||
}
|
||||
const openAgePicker = () => {
|
||||
buildAgeColumns()
|
||||
// 计算默认索引
|
||||
const { min_age, max_age } = reservationInfo.value
|
||||
const [mins, maxs] = agePickerColumns.value
|
||||
const findIndexByValue = (arr, val) => {
|
||||
const idx = arr.findIndex(it => Number(it.value) === Number(val))
|
||||
return idx >= 0 ? idx : 0
|
||||
}
|
||||
agePickerDefaultIndex.value = [
|
||||
findIndexByValue(mins, min_age ?? 0),
|
||||
findIndexByValue(maxs, max_age ?? 0),
|
||||
]
|
||||
agePickerVisible.value = true
|
||||
}
|
||||
const onAgePickerConfirm = (e) => {
|
||||
// uview-plus up-picker confirm 回调 e.value 为两列所选对象数组
|
||||
const selected = e && e.value ? e.value : []
|
||||
const min = selected[0] ? Number(selected[0].value) : 0
|
||||
const max = selected[1] ? Number(selected[1].value) : 0
|
||||
// 若最小值大于最大值,自动交换或归零“不限”优先
|
||||
let minAge = min
|
||||
let maxAge = max
|
||||
if (minAge !== 0 && maxAge !== 0 && minAge > maxAge) {
|
||||
[minAge, maxAge] = [maxAge, minAge]
|
||||
}
|
||||
reservationInfo.value.min_age = minAge
|
||||
reservationInfo.value.max_age = maxAge
|
||||
agePickerVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
/* 页面标题 */
|
||||
.page-title {
|
||||
margin-top: 100rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 输入外层统一样式 */
|
||||
.input-wrapper {
|
||||
border: 1px solid #515151;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 可点击的行(年龄范围显示) */
|
||||
.clickable-row {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
/* 内联标签(信誉左侧“⼤于等于”) */
|
||||
.inline-label {
|
||||
font-size: 25.86rpx;
|
||||
width: 120rpx;
|
||||
}
|
||||
|
||||
/* 通用居中容器 */
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 提交按钮容器样式 */
|
||||
.submit-button {
|
||||
width: 90%;
|
||||
border-radius: 10rpx;
|
||||
margin: 30rpx auto 0;
|
||||
background-color: #00AC4E;
|
||||
}
|
||||
|
||||
/* 操作区一行布局:重置 + 发起 */
|
||||
.action-row {
|
||||
width: 90%;
|
||||
margin: 30rpx auto 0;
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.reset-button {
|
||||
flex: 0 0 30%;
|
||||
height: 88rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: #FFFFFF;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.action-submit {
|
||||
flex: 1 1 auto;
|
||||
height: 88rpx;
|
||||
margin: 0; /* 覆盖原有 submit-button 的外边距,使其与 reset 同行 */
|
||||
}
|
||||
|
||||
/* 备注容器及文本 */
|
||||
.note-container {
|
||||
width: 90%;
|
||||
margin: 20rpx auto 20rpx;
|
||||
}
|
||||
|
||||
.muted-text {
|
||||
color: #979797;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.note-text {
|
||||
font-size: 24rpx;
|
||||
margin-left: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.counter-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.counter-btn {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.minus-btn {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
.counter-value {
|
||||
width: 90rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.custom-select ::v-deep .uni-input-input {
|
||||
/* 正常状态下的边框颜色 */
|
||||
border: 1px solid #007aff !important;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.flex-center-row {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -8,46 +8,33 @@
|
|||
</view>
|
||||
<view class="column" style="overflow-y: auto;">
|
||||
<card-container marginTop="30rpx">
|
||||
<label-field label="日期">
|
||||
<view class="input-wrapper" style="padding: 15rpx 20rpx;" @click="openDatePicker">
|
||||
<text>{{ getDateDisplayText() }}</text>
|
||||
</view>
|
||||
<label-field label="预定时长">
|
||||
<tag-select :options="timeRange" v-model="timeRangeValue" @change="onTimeRangeChange" />
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="开始时间">
|
||||
<picker mode="time" :value="startTime" @change="onStartTimeChange">
|
||||
<view class="picker-value">{{ startTime || '请选择开始时间' }}</view>
|
||||
</picker>
|
||||
</label-field>
|
||||
<time-select-cell label="开始时间" icon="@@:app/static/time_start.png" @select="openUpDatesTimePicker">
|
||||
{{ getDayDescription(reservationInfo.start_time * 1000) }}
|
||||
</time-select-cell>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="结束时间">
|
||||
<view class="end-time-row">
|
||||
<picker mode="time" :value="endTime" @change="onEndTimeChange">
|
||||
<view class="picker-value">{{ endTime || '请选择结束时间' }}</view>
|
||||
</picker>
|
||||
<view class="next-day-toggle" v-if="startTime && endTime">
|
||||
<text class="next-day-label" :class="{ active: !isNextDay }" @click="setNextDay(false)">当天</text>
|
||||
<text class="next-day-divider">/</text>
|
||||
<text class="next-day-label" :class="{ active: isNextDay }" @click="setNextDay(true)">次日</text>
|
||||
</view>
|
||||
</view>
|
||||
</label-field>
|
||||
<time-select-cell label="结束时间" icon="@@:app/static/time_end.png" @select="openUpDatesTimePickerEnd">
|
||||
{{ getDayDescription(reservationInfo.end_time * 1000) }}
|
||||
</time-select-cell>
|
||||
<!-- 时长和跨时段信息显示 -->
|
||||
<view class="time-info" v-if="startTime && endTime && !timeError">
|
||||
<view class="time-info" v-if="reservationInfo.start_time && reservationInfo.end_time && !timeError">
|
||||
<view class="time-info-item">
|
||||
<text class="time-info-label">预计时长:</text>
|
||||
<text class="time-info-value">{{ calculateDuration() }}</text>
|
||||
<text class="time-info-value">{{ calculateDurationFromTimestamp() }}</text>
|
||||
</view>
|
||||
<view class="time-info-item">
|
||||
<text class="time-info-label">跨越时段:</text>
|
||||
<text class="time-info-value">{{ calculateCrossSlots() }}</text>
|
||||
<text class="time-info-value">{{ calculateCrossSlotsFromTimestamp() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 时间错误提示 -->
|
||||
<view class="time-error" v-if="timeError">
|
||||
<text>{{ timeError }}</text>
|
||||
</view>
|
||||
</card-container>
|
||||
</card-container>
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
|
||||
|
|
@ -155,9 +142,6 @@
|
|||
|
||||
</view>
|
||||
</view>
|
||||
<up-datetime-picker :show="datePickerVisible" v-model="datePickerValue" mode="date"
|
||||
:minDate="datePickerMinDate" :maxDate="datePickerMaxDate" title="选择日期" @confirm="onDatePickerConfirm"
|
||||
@cancel="() => datePickerVisible = false" @close="() => datePickerVisible = false"></up-datetime-picker>
|
||||
<up-picker title="年龄范围选择" :show="agePickerVisible" :columns="agePickerColumns" :keyName="'text'"
|
||||
:defaultIndex="agePickerDefaultIndex" @confirm="onAgePickerConfirm" @cancel="() => agePickerVisible = false"
|
||||
@close="() => agePickerVisible = false"></up-picker>
|
||||
|
|
@ -218,10 +202,16 @@
|
|||
import {
|
||||
getDetail
|
||||
} from '@/common/server/index'
|
||||
import {
|
||||
getDayDescription,
|
||||
ceilMinuteToNext5
|
||||
} from '@/common/system/timeUtile';
|
||||
|
||||
import LabelField from '@/components/com/appointment/label-field.vue'
|
||||
import LabelSlectField from '@/components/com/appointment/label-slect-field.vue'
|
||||
import CardContainer from '@/components/com/appointment/card-container.vue'
|
||||
import TimeSelectCell from '@/components/com/appointment/time-select-cell.vue'
|
||||
import TagSelect from '@/components/com/appointment/tag-select.vue'
|
||||
import ComAppointmentRadioSelect from '@/components/com/appointment/radio-select.vue'
|
||||
import {
|
||||
addSQReservation,
|
||||
|
|
@ -229,6 +219,7 @@
|
|||
canCreateSQReservation,
|
||||
getRoomDetail
|
||||
} from '@/common/server/interface/sq'
|
||||
const _containerBase = ref(null)
|
||||
const submitPopupRef = ref(null)
|
||||
// 年龄选择器状态
|
||||
const agePickerVisible = ref(false)
|
||||
|
|
@ -239,21 +230,14 @@
|
|||
const agePickerDefaultIndex = ref([0, 0])
|
||||
const reservationData = ref(null)
|
||||
const lineHeight = ref("15rpx")
|
||||
// 预定时长选择
|
||||
const timeRange = ref(["2小时", "3小时", "4小时", "自定义"])
|
||||
const timeRangeValue = ref("")
|
||||
// 房间页跳转相关
|
||||
const selectedDate = ref(null) // 选中的日期时间戳(秒级)
|
||||
const roomDetail = ref(null) // 房间详情数据
|
||||
const roomDetailLoading = ref(false) // 房间详情加载状态
|
||||
// 自由时间选择相关
|
||||
const startTime = ref('') // 开始时间 "HH:mm"
|
||||
const endTime = ref('') // 结束时间 "HH:mm"
|
||||
// 时间错误提示
|
||||
const timeError = ref('') // 时间错误提示
|
||||
const isNextDay = ref(false) // 结束时间是否为次日(用于通宵预约)
|
||||
// 日期选择器状态
|
||||
const datePickerVisible = ref(false)
|
||||
const datePickerValue = ref(Date.now())
|
||||
const datePickerMinDate = ref(Date.now()) // 最小日期为今天
|
||||
// 最大日期为未来7天(今天+未来6天)
|
||||
const datePickerMaxDate = ref(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).getTime())
|
||||
//提交表单数据
|
||||
const reservationInfo = ref({
|
||||
room_id: 0, //房间id 非空
|
||||
|
|
@ -275,224 +259,103 @@
|
|||
const getRoomPickerName = () => {
|
||||
return reservationInfo.value.room_name;
|
||||
}
|
||||
/**
|
||||
* 获取日期显示文本
|
||||
*/
|
||||
const getDateDisplayText = () => {
|
||||
if (!selectedDate.value) {
|
||||
return '请选择日期';
|
||||
}
|
||||
const date = new Date(selectedDate.value * 1000);
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
const tomorrow = new Date(today);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
const dayAfterTomorrow = new Date(today);
|
||||
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
|
||||
|
||||
let dateText = '';
|
||||
if (targetDate.getTime() === today.getTime()) {
|
||||
dateText = '今天';
|
||||
} else if (targetDate.getTime() === tomorrow.getTime()) {
|
||||
dateText = '明天';
|
||||
} else if (targetDate.getTime() === dayAfterTomorrow.getTime()) {
|
||||
dateText = '后天';
|
||||
} else {
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
dateText = `${month}月${day}日`;
|
||||
}
|
||||
|
||||
// 获取星期
|
||||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
const weekday = weekdays[date.getDay()];
|
||||
|
||||
return `${dateText} ${weekday}`;
|
||||
}
|
||||
/**
|
||||
* 打开日期选择器
|
||||
*/
|
||||
const openDatePicker = () => {
|
||||
if (selectedDate.value) {
|
||||
datePickerValue.value = selectedDate.value * 1000; // 转换为毫秒
|
||||
} else {
|
||||
datePickerValue.value = Date.now();
|
||||
}
|
||||
datePickerVisible.value = true;
|
||||
}
|
||||
/**
|
||||
* 日期选择器确认
|
||||
*/
|
||||
const onDatePickerConfirm = async (e) => {
|
||||
console.log('日期选择器确认事件:', e);
|
||||
console.log('datePickerValue.value:', datePickerValue.value);
|
||||
|
||||
// up-datetime-picker 的 confirm 事件返回的是对象 { value: 毫秒级时间戳, mode: 'date' }
|
||||
// 优先使用 v-model 绑定的 datePickerValue.value,因为它会在用户选择后自动更新
|
||||
let timestampMs = datePickerValue.value;
|
||||
|
||||
// 如果 v-model 的值无效,尝试从事件参数获取
|
||||
if (!timestampMs || isNaN(timestampMs) || timestampMs <= 0) {
|
||||
if (e && typeof e === 'object' && e.value !== undefined) {
|
||||
timestampMs = e.value;
|
||||
} else if (typeof e === 'number' && !isNaN(e) && e > 0) {
|
||||
timestampMs = e;
|
||||
|
||||
//自动计算结束时间
|
||||
const onTimeRangeChange = async (val) => {
|
||||
timeRangeValue.value = val;
|
||||
console.log('timeRange change:', val)
|
||||
if (val != "") {
|
||||
await openUpDatesTimePicker(false);
|
||||
if (reservationInfo.value.start_time > 0) {
|
||||
var str = val;
|
||||
if (str == "2小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 2 * 60 * 60;
|
||||
} else if (str == "3小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 3 * 60 * 60;
|
||||
} else if (str == "4小时") {
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 4 * 60 * 60;
|
||||
} else {
|
||||
await openUpDatesTimePickerEnd(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('提取的时间戳(毫秒):', timestampMs);
|
||||
|
||||
// 确保是数字类型且有效
|
||||
if (typeof timestampMs !== 'number' || isNaN(timestampMs) || timestampMs <= 0) {
|
||||
console.error('日期选择器返回的时间戳无效:', e, 'datePickerValue:', datePickerValue.value);
|
||||
}
|
||||
|
||||
const openUpDatesTimePicker = async (isManual = true) => {
|
||||
var now = reservationInfo.value.start_time * 1000;
|
||||
var min = Date.now();
|
||||
min += 1000 * 60 * 30;
|
||||
min = ceilMinuteToNext5(min).valueOf();
|
||||
if (reservationInfo.value.start_time == 0) {
|
||||
now = Date.now();
|
||||
now += 1000 * 60 * 30;
|
||||
now = ceilMinuteToNext5(now).valueOf();
|
||||
}
|
||||
const startTime = await _containerBase.value.openUpDatesTimePicker(now, min, "预约开始时间")
|
||||
// 直接设置到表单对象,毫秒转秒
|
||||
reservationInfo.value.start_time = Math.floor(startTime / 1000)
|
||||
// 手动选择时间则切换为"自定义"
|
||||
if (isManual) {
|
||||
timeRangeValue.value = "自定义"
|
||||
}
|
||||
// 清空时间错误
|
||||
timeError.value = ''
|
||||
// 验证时间
|
||||
validateTimeFromTimestamp()
|
||||
}
|
||||
|
||||
const openUpDatesTimePickerEnd = async (isManual = true) => {
|
||||
if (reservationInfo.value.start_time == 0) {
|
||||
uni.showToast({
|
||||
title: '日期选择失败,请重试',
|
||||
title: '请先选择开始时间',
|
||||
icon: 'none'
|
||||
});
|
||||
datePickerVisible.value = false;
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
// 将日期转换为当天的 0 点(只取日期,不取时间)
|
||||
const date = new Date(timestampMs);
|
||||
if (isNaN(date.getTime())) {
|
||||
console.error('日期转换失败:', timestampMs);
|
||||
uni.showToast({
|
||||
title: '日期格式错误',
|
||||
icon: 'none'
|
||||
});
|
||||
datePickerVisible.value = false;
|
||||
return;
|
||||
var now = reservationInfo.value.end_time * 1000;
|
||||
var min = (reservationInfo.value.start_time * 1000 + 1000 * 60 * 30);
|
||||
if (now == 0) {
|
||||
now = (reservationInfo.value.start_time * 1000 + 1000 * 60 * 30);
|
||||
}
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth();
|
||||
const day = date.getDate();
|
||||
const dateAtMidnight = new Date(year, month, day, 0, 0, 0);
|
||||
|
||||
// 转换为秒级时间戳
|
||||
const selectedTimestamp = Math.floor(dateAtMidnight.getTime() / 1000);
|
||||
|
||||
console.log('转换后的秒级时间戳:', selectedTimestamp);
|
||||
|
||||
// 验证转换后的时间戳是否有效
|
||||
if (isNaN(selectedTimestamp) || selectedTimestamp <= 0) {
|
||||
console.error('时间戳转换失败:', dateAtMidnight, selectedTimestamp);
|
||||
uni.showToast({
|
||||
title: '日期处理失败',
|
||||
icon: 'none'
|
||||
});
|
||||
datePickerVisible.value = false;
|
||||
return;
|
||||
//minDate+1000*60*30 最小间隔30分钟
|
||||
const endTime = await _containerBase.value.openUpDatesTimePicker(now, min, "预约结束时间")
|
||||
// 直接设置到表单对象,毫秒转秒
|
||||
reservationInfo.value.end_time = Math.floor(endTime / 1000)
|
||||
// 手动选择时间则切换为"自定义"
|
||||
if (isManual) {
|
||||
timeRangeValue.value = "自定义"
|
||||
}
|
||||
|
||||
// 如果是同一天,不需要重新加载
|
||||
if (selectedDate.value && selectedDate.value === selectedTimestamp) {
|
||||
datePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新选中的日期
|
||||
selectedDate.value = selectedTimestamp;
|
||||
|
||||
// 重置时间选择
|
||||
startTime.value = '';
|
||||
endTime.value = '';
|
||||
timeError.value = '';
|
||||
isNextDay.value = false; // 重置跨天标记
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
|
||||
// 重新加载房间详情
|
||||
if (reservationInfo.value.room_id) {
|
||||
console.log('重新加载房间详情, roomId:', reservationInfo.value.room_id, 'date:', selectedTimestamp);
|
||||
await loadRoomDetailForReservation(reservationInfo.value.room_id, selectedTimestamp);
|
||||
}
|
||||
|
||||
datePickerVisible.value = false;
|
||||
// 验证时间
|
||||
validateTimeFromTimestamp()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开始时间变更处理
|
||||
* 验证时间范围(基于时间戳)
|
||||
*/
|
||||
const onStartTimeChange = (e) => {
|
||||
startTime.value = e.detail.value;
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束时间变更处理
|
||||
*/
|
||||
const onEndTimeChange = (e) => {
|
||||
endTime.value = e.detail.value;
|
||||
// 自动判断是否需要切换到次日
|
||||
autoDetectNextDay();
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动检测是否需要切换到次日(当结束时间小于开始时间时)
|
||||
*/
|
||||
const autoDetectNextDay = () => {
|
||||
if (!startTime.value || !endTime.value) return;
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
const startMinutes = startH * 60 + startM;
|
||||
const endMinutes = endH * 60 + endM;
|
||||
|
||||
// 如果结束时间小于开始时间,自动切换到次日
|
||||
if (endMinutes <= startMinutes) {
|
||||
isNextDay.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置结束时间是否为次日
|
||||
*/
|
||||
const setNextDay = (value) => {
|
||||
isNextDay.value = value;
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证时间范围(支持跨天预约)
|
||||
*/
|
||||
const validateTimeRange = () => {
|
||||
const validateTimeFromTimestamp = () => {
|
||||
timeError.value = '';
|
||||
|
||||
if (!startTime.value || !endTime.value) {
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
const startMinutes = startH * 60 + startM;
|
||||
let endMinutes = endH * 60 + endM;
|
||||
const startTime = reservationInfo.value.start_time;
|
||||
const endTime = reservationInfo.value.end_time;
|
||||
|
||||
// 如果是次日,结束时间加24小时
|
||||
if (isNextDay.value) {
|
||||
endMinutes += 24 * 60;
|
||||
}
|
||||
// 计算时长(秒)
|
||||
const durationSeconds = endTime - startTime;
|
||||
|
||||
// 计算时长(分钟)
|
||||
const durationMinutes = endMinutes - startMinutes;
|
||||
|
||||
if (durationMinutes <= 0) {
|
||||
if (durationSeconds <= 0) {
|
||||
timeError.value = '结束时间必须晚于开始时间';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (durationMinutes < 60) {
|
||||
if (durationSeconds < 3600) {
|
||||
timeError.value = '预约时长不能少于1小时';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (durationMinutes > 720) {
|
||||
if (durationSeconds > 43200) {
|
||||
timeError.value = '预约时长不能超过12小时';
|
||||
return false;
|
||||
}
|
||||
|
|
@ -501,60 +364,17 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 构建时间戳(从时间选择器值,支持跨天预约)
|
||||
* 计算时长显示(基于时间戳)
|
||||
*/
|
||||
const buildTimeFromPicker = () => {
|
||||
if (!selectedDate.value || !startTime.value || !endTime.value) {
|
||||
return;
|
||||
}
|
||||
const calculateDurationFromTimestamp = () => {
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) return '-';
|
||||
|
||||
if (!validateTimeRange()) {
|
||||
// 清空时间戳
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
return;
|
||||
}
|
||||
const diffSeconds = reservationInfo.value.end_time - reservationInfo.value.start_time;
|
||||
|
||||
const date = new Date(selectedDate.value * 1000);
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
if (diffSeconds <= 0) return '-';
|
||||
|
||||
const startDateTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), startH, startM, 0);
|
||||
|
||||
// 如果是次日,结束时间加1天
|
||||
let endDateTime;
|
||||
if (isNextDay.value) {
|
||||
const nextDay = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, endH, endM, 0);
|
||||
endDateTime = nextDay;
|
||||
} else {
|
||||
endDateTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), endH, endM, 0);
|
||||
}
|
||||
|
||||
reservationInfo.value.start_time = Math.floor(startDateTime.getTime() / 1000);
|
||||
reservationInfo.value.end_time = Math.floor(endDateTime.getTime() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算时长显示(支持跨天预约)
|
||||
*/
|
||||
const calculateDuration = () => {
|
||||
if (!startTime.value || !endTime.value) return '-';
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
let endMinutes = endH * 60 + endM;
|
||||
|
||||
// 如果是次日,结束时间加24小时
|
||||
if (isNextDay.value) {
|
||||
endMinutes += 24 * 60;
|
||||
}
|
||||
|
||||
const diffMinutes = endMinutes - (startH * 60 + startM);
|
||||
|
||||
if (diffMinutes <= 0) return '-';
|
||||
|
||||
const hours = Math.floor(diffMinutes / 60);
|
||||
const mins = diffMinutes % 60;
|
||||
const hours = Math.floor(diffSeconds / 3600);
|
||||
const mins = Math.floor((diffSeconds % 3600) / 60);
|
||||
|
||||
if (mins === 0) {
|
||||
return `${hours}小时`;
|
||||
|
|
@ -563,14 +383,17 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* 计算跨越时段(支持跨天预约)
|
||||
* 计算跨越时段(基于时间戳)
|
||||
*/
|
||||
const calculateCrossSlots = () => {
|
||||
if (!startTime.value || !endTime.value) return '-';
|
||||
|
||||
const [startH] = startTime.value.split(':').map(Number);
|
||||
const [endH] = endTime.value.split(':').map(Number);
|
||||
const calculateCrossSlotsFromTimestamp = () => {
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) return '-';
|
||||
|
||||
const startDate = new Date(reservationInfo.value.start_time * 1000);
|
||||
const endDate = new Date(reservationInfo.value.end_time * 1000);
|
||||
|
||||
const startH = startDate.getHours();
|
||||
const endH = endDate.getHours();
|
||||
|
||||
const slots = [];
|
||||
const ranges = [
|
||||
{ name: '凌晨', start: 0, end: 6 },
|
||||
|
|
@ -579,7 +402,10 @@
|
|||
{ name: '晚上', start: 18, end: 24 }
|
||||
];
|
||||
|
||||
if (isNextDay.value) {
|
||||
// 检查是否跨天
|
||||
const isNextDay = endDate.getDate() !== startDate.getDate();
|
||||
|
||||
if (isNextDay) {
|
||||
// 跨天预约:当天的时段 + 次日的时段
|
||||
// 当天:从开始时间到24点
|
||||
for (const r of ranges) {
|
||||
|
|
@ -609,7 +435,58 @@
|
|||
|
||||
return slots.join('、') || '-';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置默认开始时间
|
||||
* @param {number} dateTimestamp 日期时间戳(秒级)
|
||||
*/
|
||||
const setDefaultStartTime = async (dateTimestamp) => {
|
||||
try {
|
||||
// 将日期时间戳转换为日期对象
|
||||
const selectedDate = new Date(dateTimestamp * 1000);
|
||||
const today = new Date();
|
||||
|
||||
// 判断是否是今天
|
||||
const isToday = selectedDate.toDateString() === today.toDateString();
|
||||
|
||||
let defaultStartTime;
|
||||
|
||||
if (isToday) {
|
||||
// 如果是今天,设置为当前时间后30分钟,并向上取整到5分钟的倍数
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() + 30); // 加30分钟
|
||||
defaultStartTime = ceilMinuteToNext5(now.getTime());
|
||||
} else {
|
||||
// 如果是其他日期,设置为当天的10:00
|
||||
const defaultTime = new Date(selectedDate);
|
||||
defaultTime.setHours(10, 0, 0, 0);
|
||||
defaultStartTime = defaultTime.getTime();
|
||||
}
|
||||
|
||||
// 设置开始时间(毫秒转秒)
|
||||
reservationInfo.value.start_time = Math.floor(defaultStartTime / 1000);
|
||||
|
||||
// 默认选择2小时时长
|
||||
timeRangeValue.value = "2小时";
|
||||
|
||||
// 自动计算结束时间(2小时后)
|
||||
reservationInfo.value.end_time = reservationInfo.value.start_time + 2 * 60 * 60;
|
||||
|
||||
// 验证时间设置
|
||||
validateTimeFromTimestamp();
|
||||
|
||||
console.log('设置默认时间:', {
|
||||
startTime: reservationInfo.value.start_time,
|
||||
endTime: reservationInfo.value.end_time,
|
||||
startTimeDisplay: getDayDescription(reservationInfo.value.start_time * 1000),
|
||||
endTimeDisplay: getDayDescription(reservationInfo.value.end_time * 1000)
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('设置默认开始时间失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const tipsShow = () => {
|
||||
submitPopupRef.value.open()
|
||||
}
|
||||
|
|
@ -786,7 +663,7 @@
|
|||
}
|
||||
|
||||
// 检查是否选择了时间
|
||||
if (!startTime.value || !endTime.value) {
|
||||
if (!reservationInfo.value.start_time || !reservationInfo.value.end_time) {
|
||||
uni.showToast({
|
||||
title: '请选择开始和结束时间',
|
||||
icon: 'none'
|
||||
|
|
@ -795,9 +672,9 @@
|
|||
}
|
||||
|
||||
// 检查时间是否有效
|
||||
if (timeError.value) {
|
||||
if (!validateTimeFromTimestamp()) {
|
||||
uni.showToast({
|
||||
title: timeError.value,
|
||||
title: timeError.value || '时间设置有误',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
|
|
@ -1050,10 +927,8 @@
|
|||
peopleText.value = savedPeopleText;
|
||||
|
||||
// 重置时间选择
|
||||
startTime.value = '';
|
||||
endTime.value = '';
|
||||
timeError.value = '';
|
||||
isNextDay.value = false; // 重置跨天标记
|
||||
timeRangeValue.value = ""
|
||||
timeError.value = ''
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
|
||||
|
|
@ -1063,7 +938,7 @@
|
|||
/**
|
||||
* 加载房间详情,用于预约页面
|
||||
*/
|
||||
const loadRoomDetailForReservation = async (roomId, date) => {
|
||||
const loadRoomDetailForReservation = async (roomId, date = null) => {
|
||||
console.log('loadRoomDetailForReservation 调用参数:', {
|
||||
roomId,
|
||||
date,
|
||||
|
|
@ -1071,19 +946,39 @@
|
|||
});
|
||||
|
||||
// 验证参数
|
||||
if (!roomId || !date) {
|
||||
if (!roomId) {
|
||||
console.error('loadRoomDetailForReservation 参数无效:', {
|
||||
roomId,
|
||||
date
|
||||
});
|
||||
uni.showToast({
|
||||
title: '参数错误',
|
||||
title: '房间ID参数错误',
|
||||
icon: 'none'
|
||||
});
|
||||
roomDetailLoading.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有日期,只设置房间基本信息
|
||||
if (!date) {
|
||||
// 设置基本的人数范围(假设最大4人)
|
||||
maxPlayerCount.value = 4;
|
||||
const t = [];
|
||||
peopleText.value = "请选择游玩人数";
|
||||
t.push({
|
||||
value: 1,
|
||||
text: '无需组局'
|
||||
});
|
||||
for (let i = 2; i <= 4; i++) {
|
||||
t.push({
|
||||
value: i,
|
||||
text: i + '人'
|
||||
});
|
||||
}
|
||||
peopleRange.value = t;
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保 date 是数字类型
|
||||
const dateTimestamp = Number(date);
|
||||
if (isNaN(dateTimestamp) || dateTimestamp <= 0) {
|
||||
|
|
@ -1146,41 +1041,30 @@
|
|||
gameTypeRange.value = [...config.config.playingMethodOptions];
|
||||
}
|
||||
|
||||
// 必须从房间页跳转,需要传入房间信息
|
||||
if (!options || !options.roomId) {
|
||||
uni.showToast({
|
||||
title: '参数错误,请从房间页进入',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
return;
|
||||
// 可以从房间页跳转,也可以直接进入
|
||||
if (options && options.roomId) {
|
||||
// 接收房间信息
|
||||
const roomId = Number(options.roomId);
|
||||
const roomName = decodeURIComponent(options.roomName || '未知房间');
|
||||
|
||||
if (roomId) {
|
||||
// 自动填充房间信息
|
||||
reservationInfo.value.room_id = roomId;
|
||||
reservationInfo.value.room_name = roomName;
|
||||
|
||||
// 如果有日期参数,设置默认开始时间
|
||||
if (options.date) {
|
||||
const date = Number(options.date);
|
||||
if (date) {
|
||||
// 加载房间详情,获取可预约时段和容量信息
|
||||
await loadRoomDetailForReservation(roomId, date);
|
||||
|
||||
// 设置默认开始时间为当天的合适时间
|
||||
await setDefaultStartTime(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 接收房间信息
|
||||
const roomId = Number(options.roomId);
|
||||
const roomName = decodeURIComponent(options.roomName || '未知房间');
|
||||
const date = Number(options.date);
|
||||
|
||||
if (!roomId || !date) {
|
||||
uni.showToast({
|
||||
title: '房间信息不完整',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
|
||||
// 自动填充房间信息
|
||||
reservationInfo.value.room_id = roomId;
|
||||
reservationInfo.value.room_name = roomName;
|
||||
selectedDate.value = date;
|
||||
|
||||
// 加载房间详情,获取可预约时段和容量信息
|
||||
await loadRoomDetailForReservation(roomId, date);
|
||||
})
|
||||
onShow(async () => {
|
||||
// resetForm();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user