移动端V1.0
This commit is contained in:
511
pages/OneStopCommunity/functionHouse/reservation.vue
Normal file
511
pages/OneStopCommunity/functionHouse/reservation.vue
Normal file
@@ -0,0 +1,511 @@
|
||||
<template>
|
||||
<view class="reservation">
|
||||
<view class="form-container">
|
||||
<form>
|
||||
<view class="form-item">
|
||||
<label>功能房</label>
|
||||
<input type="text" v-model="list.roomName" disabled placeholder-class="input-placeholder" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>主题</label>
|
||||
<input type="text" v-model="formData.rtTheme" placeholder="请输入活动主题" placeholder-class="input-placeholder" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>申请人</label>
|
||||
<input type="text" v-model="formData.rtCreatRole" placeholder="请输入申请人姓名" placeholder-class="input-placeholder" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>使用部门/学院</label>
|
||||
<picker mode="selector" :range="deptXZJGList" @change="handleDeptChange">
|
||||
<view class="picker">
|
||||
{{ formData.rtDepar || '请选择' }}
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>参与人数</label>
|
||||
<input type="number" v-model="formData.rtPeople" :placeholder="'最多可容纳'+list.roomCapacity+'人'" placeholder-class="input-placeholder" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>预约用途</label>
|
||||
<picker range-key="dictLabel" :value="rangeIndex" :range="Reserveduse" @change="classChange">
|
||||
<view class="uni-input">
|
||||
<text v-if="Reserveduse.length" class="val">{{Reserveduse[rangeIndex].dictLabel}}</text>
|
||||
<text v-else class="placeholder">请选择预约用途</text>
|
||||
<uni-icons type="down" size="16" color="#202020"></uni-icons>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<label>人员类型</label>
|
||||
<view class="trigger" @click="showDrawer = true">
|
||||
<view class="uni-input">
|
||||
<text v-if="selectedRoles.length">{{ selectedRoles.join(", ") }}</text>
|
||||
<text v-else class="placeholder">请选择人员类型</text>
|
||||
<uni-icons type="down" size="16" color="#202020"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
|
||||
<view class="time-selection">
|
||||
<view class="time-header">
|
||||
<text>选择时间段</text>
|
||||
<text><text style="color: red;">*</text>请选择可用时间段</text>
|
||||
</view>
|
||||
|
||||
<view class="time-slots">
|
||||
<view v-for="(item,index) in slotslist" :key="index" class="slot-item">
|
||||
<button @click="selectTimeSlot(item,index)"
|
||||
:disabled="item.isOccupy==1"
|
||||
:class="{
|
||||
'active': timeindex===index,
|
||||
'disabled': item.isOccupy==1,
|
||||
'warning': formData.rtPeople > list.roomCapacity
|
||||
}">
|
||||
{{item.openingHours}}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="usage-matters">
|
||||
<text>使用事项:</text>
|
||||
<text>{{list.roomMatter}}</text>
|
||||
</view>
|
||||
|
||||
<button type="primary"
|
||||
:disabled="isSubmitting || !isFormValid"
|
||||
class="submit-btn"
|
||||
@tap="onSubmit">
|
||||
{{isSubmitting ? '提交中...' : '提交预约'}}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 人员类型选择抽屉 -->
|
||||
<view v-if="showDrawer" class="drawer-overlay" @click="showDrawer = false"></view>
|
||||
<view v-if="showDrawer" class="drawer">
|
||||
<view class="drawer-header">
|
||||
<text>选择人员类型</text>
|
||||
<text class="drawer-close" @click="showDrawer = false">完成</text>
|
||||
</view>
|
||||
<view class="drawer-body">
|
||||
<uni-data-checkbox
|
||||
:multiple="true"
|
||||
v-model="selectedRoles"
|
||||
mode="tag"
|
||||
:map="{text:'dictLabel',value:'dictValue'}"
|
||||
:localdata="rolelist">
|
||||
</uni-data-checkbox>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
selectRtFuReservationTime,
|
||||
addRoomReservation,
|
||||
getXZJGDept
|
||||
} from '@/api/OneStopCommunity/room.js';
|
||||
import { getDicts } from '@/api/system/dict/data.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showDrawer: false,
|
||||
selectedRoles: [],
|
||||
isSubmitting: false,
|
||||
timeindex: null,
|
||||
formData: {
|
||||
rtTheme: "",
|
||||
rtCreatRole: "",
|
||||
rtDepar: "",
|
||||
rtPeople: "",
|
||||
},
|
||||
rangeIndex: 0,
|
||||
roomNo: "",
|
||||
rtTime: "",
|
||||
list: {},
|
||||
slotslist: [],
|
||||
Reserveduse: [],
|
||||
rolelist: [],
|
||||
deptXZJGList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isFormValid() {
|
||||
return (
|
||||
this.formData.rtTheme &&
|
||||
this.formData.rtCreatRole &&
|
||||
this.formData.rtDepar &&
|
||||
this.formData.rtPeople > 0 &&
|
||||
this.formData.rtPeople <= this.list.roomCapacity &&
|
||||
this.Reserveduse.length > 0 &&
|
||||
this.selectedRoles.length > 0 &&
|
||||
this.timeindex !== null
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDeptChange(e) {
|
||||
this.formData.rtDepar = this.deptXZJGList[e.detail.value];
|
||||
},
|
||||
classChange(e) {
|
||||
this.rangeIndex = e.detail.value;
|
||||
},
|
||||
selectTimeSlot(item, index) {
|
||||
this.timeindex = index;
|
||||
},
|
||||
async getXZJGDeptList() {
|
||||
try {
|
||||
const res = await getXZJGDept();
|
||||
//二级学院排列位置调整
|
||||
let depts = res.data;
|
||||
let quList = depts.slice(14,25)
|
||||
depts.splice(14,11);
|
||||
depts.splice(0, 0, ...quList);
|
||||
this.deptXZJGList = depts;
|
||||
//this.deptXZJGList = res.data;
|
||||
} catch (error) {
|
||||
console.error('获取部门列表失败:', error);
|
||||
uni.showToast({ title: '获取部门列表失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
async getlist() {
|
||||
try {
|
||||
const res = await selectRtFuReservationTime({
|
||||
roomNo: this.list.roomNo,
|
||||
rtTime: this.rtTime
|
||||
});
|
||||
this.slotslist = res.data || [];
|
||||
} catch (error) {
|
||||
console.error('获取时间段失败:', error);
|
||||
uni.showToast({ title: '获取可用时间段失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
async getReserved() {
|
||||
try {
|
||||
const res = await getDicts('routine_rtfureservations_rt_purpose');
|
||||
this.Reserveduse = res.data;
|
||||
} catch (error) {
|
||||
console.error('获取预约用途失败:', error);
|
||||
}
|
||||
},
|
||||
async getrole() {
|
||||
try {
|
||||
const res = await getDicts('routine_rtfureservation_rt_role');
|
||||
this.rolelist = res.data;
|
||||
} catch (error) {
|
||||
console.error('获取人员类型失败:', error);
|
||||
}
|
||||
},
|
||||
validateForm() {
|
||||
if (!this.formData.rtTheme) {
|
||||
uni.showToast({ title: '请输入活动主题', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.formData.rtCreatRole) {
|
||||
uni.showToast({ title: '请输入申请人姓名', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.formData.rtDepar) {
|
||||
uni.showToast({ title: '请选择使用部门/学院', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.formData.rtPeople || this.formData.rtPeople <= 0) {
|
||||
uni.showToast({ title: '请输入有效的参与人数', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.formData.rtPeople > this.list.roomCapacity) {
|
||||
uni.showToast({
|
||||
title: `人数超过限制(最多${this.list.roomCapacity}人)`,
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.Reserveduse.length || !this.Reserveduse[this.rangeIndex]) {
|
||||
uni.showToast({ title: '请选择预约用途', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.selectedRoles.length === 0) {
|
||||
uni.showToast({ title: '请选择人员类型', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.timeindex === null) {
|
||||
uni.showToast({ title: '请选择预约时间段', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
async onSubmit() {
|
||||
if (this.isSubmitting) return;
|
||||
|
||||
if (!this.validateForm()) return;
|
||||
|
||||
this.isSubmitting = true;
|
||||
|
||||
try {
|
||||
const form = {
|
||||
...this.formData,
|
||||
rtPurpose: this.Reserveduse[this.rangeIndex].dictLabel,
|
||||
rtRole: this.selectedRoles.join(","),
|
||||
roomNo: this.list.roomNo,
|
||||
roomName: this.list.roomName,
|
||||
rtNo: this.slotslist[this.timeindex].rtNo,
|
||||
rtTime: this.rtTime,
|
||||
rtTimePeriod: this.slotslist[this.timeindex].openingHours
|
||||
};
|
||||
|
||||
console.log('提交数据:', form);
|
||||
|
||||
const res = await addRoomReservation(form);
|
||||
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '预约成功' });
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({ url: "../appointment/index" });
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '预约失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('预约提交失败:', error);
|
||||
uni.showToast({ title: '预约提交失败', icon: 'none' });
|
||||
} finally {
|
||||
this.isSubmitting = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.rtTime = option.rtTime;
|
||||
this.list = JSON.parse(option.list);
|
||||
this.formData.roomName = this.list.roomName;
|
||||
|
||||
Promise.all([
|
||||
this.getlist(),
|
||||
this.getReserved(),
|
||||
this.getrole(),
|
||||
this.getXZJGDeptList()
|
||||
]).catch(error => {
|
||||
console.error('初始化失败:', error);
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.reservation {
|
||||
background-color: #f4f4f4;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 40rpx;
|
||||
|
||||
.form-container {
|
||||
padding: 40rpx;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
input, .picker {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
border: 1rpx solid #e1e1e1;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uni-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.val {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #b6b6b6;
|
||||
}
|
||||
}
|
||||
|
||||
.trigger {
|
||||
.uni-input {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
border: 1rpx solid #e1e1e1;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.time-selection {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
|
||||
.time-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
text:first-child {
|
||||
font-size: 32rpx;
|
||||
font-weight: 550;
|
||||
}
|
||||
|
||||
text:last-child {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.time-slots {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -10rpx;
|
||||
|
||||
.slot-item {
|
||||
width: 33.33%;
|
||||
padding: 10rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
button {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 26rpx;
|
||||
border-radius: 10rpx;
|
||||
background-color: #f9fbfc;
|
||||
color: #1890FF;
|
||||
border: 1rpx solid #1890FF;
|
||||
|
||||
&.active {
|
||||
background-color: #1890FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background-color: #f5f5f5;
|
||||
color: #c1c1c1;
|
||||
border-color: #e1e1e1;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
border-color: #ff9900;
|
||||
color: #ff9900;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.usage-matters {
|
||||
margin-top: 40rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
|
||||
text:first-child {
|
||||
font-weight: bold;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 50rpx;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
font-size: 32rpx;
|
||||
border-radius: 45rpx;
|
||||
background-color: #1890FF;
|
||||
|
||||
&[disabled] {
|
||||
background-color: #c1ccdf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
padding: 30rpx;
|
||||
z-index: 999;
|
||||
box-shadow: 0 -5rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.drawer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
text:first-child {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.drawer-close {
|
||||
color: #1890FF;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-body {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-placeholder {
|
||||
color: #b6b6b6;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user