554 lines
13 KiB
Vue
554 lines
13 KiB
Vue
<template>
|
||
<view class="meeting-room-detail">
|
||
<!-- 顶部轮播图 -->
|
||
<u-swiper class="room-swiper" :list="list1" height="420" indicator indicatorMode="dot"
|
||
indicatorActiveColor="#2979ff" bgColor="#f8faff">
|
||
</u-swiper>
|
||
|
||
<!-- 会议室基本信息卡片 -->
|
||
<view class="info-card">
|
||
<view class="room-info">
|
||
<text class="room-name">{{detail.title}}</text>
|
||
<view class="meta-info">
|
||
<text class="room-capacity"> 可容纳 {{detail.maxNum}} 人</text>
|
||
</view>
|
||
<text class="room-desc" v-if="detail.description">{{detail.description}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 预订信息卡片 -->
|
||
<view class="booking-card">
|
||
<view class="card-header">
|
||
<text class="card-title">预订信息</text>
|
||
</view>
|
||
|
||
<!-- 日期选择 -->
|
||
<view class="date-section">
|
||
<view class="section-header">
|
||
<u-icon name="calendar" size="38" color="#2979ff"></u-icon>
|
||
<text class="section-title">选择日期</text>
|
||
</view>
|
||
<view class="date-display" @click="showCalendar = true">
|
||
<text>{{ formattedSelectedDate }}</text>
|
||
<u-icon name="arrow-right" color="#999"></u-icon>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 时间选择 -->
|
||
<view class="time-section">
|
||
<view class="section-header">
|
||
<u-icon name="clock" size="34" color="#2979ff"></u-icon>
|
||
<text class="section-title">选择时间段</text>
|
||
</view>
|
||
<view class="time-picker">
|
||
<view class="time-selector" @click="showStartTimePicker = true">
|
||
<text class="time-label">开始</text>
|
||
<view class="time-display">
|
||
{{ selectedStartTime }}
|
||
</view>
|
||
</view>
|
||
<view class="time-separator">—</view>
|
||
<view class="time-selector" @click="showEndTimePicker = true">
|
||
<text class="time-label">结束</text>
|
||
<view class="time-display">
|
||
{{ selectedEndTime }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 新增备注输入区域 -->
|
||
<view class="remark-section">
|
||
<view class="section-header">
|
||
<u-icon name="edit-pen" size="34" color="#2979ff"></u-icon>
|
||
<text class="section-title">备注信息</text>
|
||
</view>
|
||
<u--textarea
|
||
v-model="remark"
|
||
placeholder="请输入备注信息(选填)"
|
||
count
|
||
maxlength="200"
|
||
height="120"
|
||
border="none"
|
||
:customStyle="{background: '#f8f9fa', borderRadius: '12rpx', padding: '20rpx'}"
|
||
></u--textarea>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 预定须知卡片 -->
|
||
<view class="notice-card">
|
||
<view class="card-header">
|
||
<u-icon name="info-circle" size="34" color="#2979ff"></u-icon>
|
||
<text class="card-title">预订须知</text>
|
||
</view>
|
||
<view class="notice-list">
|
||
<view class="notice-item" v-for="(item, index) in noticeList" :key="index">
|
||
<text class="notice-index">{{ index + 1 }}.</text>
|
||
<text class="notice-content">{{ item }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部固定操作栏 -->
|
||
<view class="action-bar">
|
||
<u-button type="primary" shape="circle" @click="handleBook">立即预订</u-button>
|
||
</view>
|
||
|
||
<!-- 日历组件 -->
|
||
<u-calendar :key="calendarKey" :show="showCalendar" mode="single" :min-date="minDate" :max-date="maxDate"
|
||
@confirm="handleDateConfirm" @close="showCalendar = false" :mask-close-able="true"></u-calendar>
|
||
|
||
<!-- 时间选择器 -->
|
||
<u-datetime-picker :show="showStartTimePicker" v-model="startTimePickerValue" mode="time" format="HH:mm"
|
||
@confirm="handleStartTimeConfirm" @cancel="showStartTimePicker = false"></u-datetime-picker>
|
||
|
||
<u-datetime-picker :show="showEndTimePicker" v-model="endTimePickerValue" mode="time" format="HH:mm"
|
||
@confirm="handleEndTimeConfirm" @cancel="showEndTimePicker = false"></u-datetime-picker>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
get,
|
||
post
|
||
} from '@/utils/request';
|
||
import {
|
||
IMAGE_BASE_URL,
|
||
BASE_URL
|
||
} from '@/utils/config';
|
||
import {
|
||
formatTime,
|
||
formatRelativeTime
|
||
} from '@/utils/timeFormat';
|
||
export default {
|
||
data() {
|
||
const now = new Date();
|
||
const year = now.getFullYear();
|
||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||
const day = now.getDate().toString().padStart(2, '0');
|
||
|
||
// 计算默认开始/结束时间
|
||
let startHours = now.getHours();
|
||
let startMinutes = now.getMinutes() < 30 ? 30 : 0;
|
||
if (now.getMinutes() >= 30) startHours += 1;
|
||
if (startHours >= 24) startHours = 0;
|
||
|
||
let endHours = startHours + 1;
|
||
let endMinutes = startMinutes;
|
||
if (endHours >= 24) endHours = 0;
|
||
|
||
return {
|
||
// 会议室图片数组
|
||
list1: [],
|
||
detail: {},
|
||
|
||
// 日历控制(默认隐藏)
|
||
showCalendar: false,
|
||
calendarKey: 0,
|
||
|
||
// 时间选择器控制
|
||
showStartTimePicker: false,
|
||
showEndTimePicker: false,
|
||
|
||
// 使用字符串格式的时间
|
||
startTimePickerValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
||
endTimePickerValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
||
|
||
// 日期相关
|
||
selectedDate: `${year}-${month}-${day}`,
|
||
minDate: `${year}-${month}-${day}`,
|
||
maxDate: `${year + 1}-12-31`,
|
||
|
||
// 时间相关
|
||
selectedStartTime: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
||
selectedEndTime: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
||
startTimeValue: `${startHours.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`,
|
||
endTimeValue: `${endHours.toString().padStart(2, '0')}:${endMinutes.toString().padStart(2, '0')}`,
|
||
|
||
// 新增备注字段
|
||
remark: '',
|
||
|
||
noticeList: [
|
||
'每次预订时间单位为小时,最少0.5小时起预订。',
|
||
'使用优惠券支付,取消预订后优惠券会自动退还。',
|
||
'使用微信、支付宝支付,取消订单后需要转社区运营人员进行退款。',
|
||
'系统不支持自动退款。',
|
||
'场地搭建,则需在活动开始48小时前支付相应保证金,具体费用可与运营人员进行确认。'
|
||
],
|
||
Id: '',
|
||
};
|
||
},
|
||
onLoad(options) {
|
||
if (options && options.Id) {
|
||
this.Id = options.Id;
|
||
console.log("====", this.Id)
|
||
}
|
||
},
|
||
computed: {
|
||
formattedSelectedDate() {
|
||
if (!this.selectedDate) return '请选择日期';
|
||
|
||
const date = new Date(this.selectedDate);
|
||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||
const month = date.getMonth() + 1;
|
||
const day = date.getDate();
|
||
const weekday = weekdays[date.getDay()];
|
||
|
||
return `${month}月${day}日 ${weekday}`;
|
||
}
|
||
},
|
||
mounted() {
|
||
this.getDetail();
|
||
},
|
||
methods: {
|
||
// 获取详情页面
|
||
async getDetail() {
|
||
try {
|
||
const res = await get(`/api/v1/apps/home/metting-room/${this.Id}`);
|
||
if (!res || !res.success) {
|
||
throw new Error('获取详情失败');
|
||
}
|
||
console.log("======res", res)
|
||
// 如果有返回的图片数据,可以这样处理
|
||
if (res.data.imgs && res.data.imgs.length > 0) {
|
||
this.list1 = res.data.imgs.map(img => {
|
||
return img.startsWith('http') ? img : IMAGE_BASE_URL + img;
|
||
});
|
||
}
|
||
this.detail = {
|
||
...res.data
|
||
};
|
||
} catch (err) {
|
||
console.error('获取详情失败:', err);
|
||
}
|
||
},
|
||
handleDateConfirm(e) {
|
||
let selectedDate;
|
||
|
||
// 处理不同格式的返回值
|
||
if (Array.isArray(e)) {
|
||
selectedDate = e[0];
|
||
} else if (e.result && Array.isArray(e.result)) {
|
||
selectedDate = e.result[0];
|
||
} else if (typeof e === 'string') {
|
||
selectedDate = e;
|
||
} else {
|
||
selectedDate = e.date;
|
||
}
|
||
|
||
this.selectedDate = selectedDate;
|
||
this.showCalendar = false;
|
||
|
||
// 强制更新视图
|
||
this.$nextTick(() => {
|
||
this.calendarKey += 1;
|
||
});
|
||
},
|
||
|
||
handleStartTimeConfirm(e) {
|
||
this.selectedStartTime = e.value;
|
||
this.startTimePickerValue = e.value;
|
||
this.showStartTimePicker = false;
|
||
this.adjustEndTime();
|
||
},
|
||
|
||
handleEndTimeConfirm(e) {
|
||
this.selectedEndTime = e.value;
|
||
this.endTimePickerValue = e.value;
|
||
this.showEndTimePicker = false;
|
||
this.validateTime();
|
||
},
|
||
|
||
adjustEndTime() {
|
||
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
|
||
let [endH, endM] = this.selectedEndTime.split(':').map(Number);
|
||
|
||
const startTotal = startH * 60 + startM;
|
||
let endTotal = endH * 60 + endM;
|
||
|
||
if (endTotal <= startTotal) {
|
||
endTotal = startTotal + 60;
|
||
endH = Math.floor(endTotal / 60);
|
||
endM = endTotal % 60;
|
||
this.selectedEndTime = `${endH.toString().padStart(2, '0')}:${endM.toString().padStart(2, '0')}`;
|
||
this.endTimeValue = `${endH}:${endM}`;
|
||
this.endTimePickerValue = this.selectedEndTime;
|
||
}
|
||
},
|
||
|
||
validateTime() {
|
||
const [startH, startM] = this.selectedStartTime.split(':').map(Number);
|
||
const [endH, endM] = this.selectedEndTime.split(':').map(Number);
|
||
|
||
const duration = (endH * 60 + endM) - (startH * 60 + startM);
|
||
if (duration < 30) {
|
||
uni.showToast({
|
||
title: '最少预订30分钟',
|
||
icon: 'none'
|
||
});
|
||
this.adjustEndTime();
|
||
}
|
||
},
|
||
|
||
handleBook() {
|
||
this.validateTime();
|
||
|
||
// 构建预订信息对象
|
||
const bookingInfo = {
|
||
startAt: new Date(`${this.selectedDate} ${this.selectedStartTime}`),
|
||
endAt: new Date(`${this.selectedDate} ${this.selectedEndTime}`),
|
||
remark: this.remark,
|
||
roomId: this.Id
|
||
};
|
||
|
||
|
||
console.log('提交的预订信息:', bookingInfo);
|
||
|
||
uni.showToast({
|
||
title: `已预订 ${this.formattedSelectedDate} ${this.selectedStartTime}-${this.selectedEndTime}`,
|
||
icon: 'none'
|
||
});
|
||
|
||
// 这里可以添加实际的API调用
|
||
post('/api/v1/app_auth/metting-room/order/register',bookingInfo).then((res)=>{
|
||
console.log("===res",res)
|
||
if (!res || !res.success) {
|
||
throw new Error('会议室预定失败');
|
||
}
|
||
uni.showToast({
|
||
title: '会议室预定成功!',
|
||
icon: 'success'
|
||
});
|
||
this.remark = null;
|
||
setTimeout(()=>{
|
||
uni.navigateTo({
|
||
url: `/pages/meetingList/index`,
|
||
success: () => {
|
||
console.log('导航成功,ID:', id);
|
||
},
|
||
fail: (err) => {
|
||
console.error('导航失败:', err);
|
||
uni.showToast({
|
||
title: '打开详情页失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},4000)
|
||
|
||
|
||
})
|
||
// this.submitBooking(bookingInfo);
|
||
},
|
||
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.meeting-room-detail {
|
||
padding: 20rpx;
|
||
padding-bottom: 140rpx; /* 增大底部空间 */
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
/* 轮播图优化 */
|
||
.room-swiper {
|
||
width: 100%;
|
||
height: 420rpx;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
/* 卡片通用样式 */
|
||
.info-card,
|
||
.booking-card,
|
||
.notice-card {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
margin-bottom: 24rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
/* 会议室信息卡片 */
|
||
.room-info {
|
||
.room-name {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
.meta-info {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 20rpx;
|
||
margin-bottom: 16rpx;
|
||
|
||
text {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
|
||
.room-desc {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
|
||
/* 卡片标题 */
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 24rpx;
|
||
padding-bottom: 16rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
.card-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-left: 10rpx;
|
||
}
|
||
}
|
||
|
||
/* 日期选择区域 */
|
||
.date-section {
|
||
margin-bottom: 32rpx;
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-left: 8rpx;
|
||
}
|
||
|
||
.date-display {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 20rpx 24rpx;
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
/* 时间选择区域 */
|
||
.time-section {
|
||
margin-bottom: 32rpx;
|
||
|
||
.time-picker {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.time-selector {
|
||
flex: 1;
|
||
|
||
.time-label {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.time-display {
|
||
padding: 20rpx;
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.time-separator {
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
padding-top: 28rpx;
|
||
}
|
||
}
|
||
|
||
/* 新增备注区域 */
|
||
.remark-section {
|
||
margin-top: 24rpx;
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-left: 8rpx;
|
||
}
|
||
}
|
||
|
||
/* 预订须知 */
|
||
.notice-card {
|
||
.notice-list {
|
||
.notice-item {
|
||
display: flex;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.6;
|
||
|
||
.notice-index {
|
||
color: #2979ff;
|
||
font-weight: bold;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.notice-content {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
flex: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 底部操作栏 */
|
||
.action-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
padding: 20rpx;
|
||
background: #fff;
|
||
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
|
||
.u-button {
|
||
height: 88rpx; /* 增大高度 */
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
/* 动画效果 */
|
||
.time-display,
|
||
.date-display {
|
||
transition: all 0.2s;
|
||
|
||
&:active {
|
||
background: #eef2f7;
|
||
transform: scale(0.98);
|
||
}
|
||
}
|
||
</style> |