personnel_management_mobile/pages/reserve/timeSelect.vue

327 lines
7.1 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 信息栏 -->
<view class="info-bar">
<view class="info-title">住房档案变更房屋坐落变更</view>
<view class="info-dept">公积金管理中心</view>
</view>
<!-- 日历 -->
<view class="calendar-wrap">
<view class="calendar-header">
<text class="week-item" v-for="week in weekList" :key="week">{{ week }}</text>
</view>
<view class="date-row" v-for="(row, index) in calendarList" :key="index">
<view class="date-item" :class="{
active: item && item.active,
has: item && item.isAvailable,
disabled: !item || !item.isAvailable
}" v-for="(item, idx) in row" :key="idx" @click="selectDate(item)">
<text class="date-num">{{ item ? getDay(item.date) : '无' }}</text>
<text class="date-status" v-if="item">{{ item.isAvailable ? '有' : '无' }}</text>
</view>
</view>
</view>
<!-- 时段 -->
<view class="time-list">
<view class="time-item" :class="{ selected: item.selected, disabled: item.remainingCount <= 0 }"
v-for="item in currentTimeSlots" :key="item.time" @click="selectTime(item)">
<view>{{ item.time }}</view>
<view>可预约 {{ item.remainingCount }}</view>
</view>
</view>
<!-- 底部 -->
<view class="footer-bar">
<view class="selected-info">已选:{{ selectedDate }} {{ selectedTime }}</view>
<view class="btn-box">
<button class="btn-gray" @click="handleGoBack">返回</button>
<button class="btn-blue" @click="handleNext">下一步</button>
</view>
</view>
</view>
</template>
<script>
import {
availableDate
} from '@/api/reserve.js'
export default {
data() {
return {
weekList: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
dateList: [],
calendarList: [],
currentTimeSlots: [],
selectedDate: "",
selectedTime: "",
itemData: {}
};
},
onLoad(options) {
this.itemData = JSON.parse(decodeURIComponent(options.data))
this.fetchData()
},
methods: {
fetchData() {
availableDate({
itemId: this.itemData.id
}).then(res => {
if (res.code === 200) {
this.dateList = res.data
this.initCalendar()
// 兼容无数据/首条不可选情况
const firstAva = this.dateList.find(item => item.isAvailable)
firstAva && this.selectDate(firstAva)
}
})
},
// 核心重写100%贴合需求 - 按weekDayName对列+跨周换行+今日为起点前后空
initCalendar() {
// 初始化两行(最多跨周展示两行,满足业务场景)
const row1 = Array(7).fill(null) // 第一行(今日所在周)
const row2 = Array(7).fill(null) // 第二行(跨周后的下一周)
// 星期转列索引映射(固定匹配表头)
const weekToCol = {
"星期一": 0,
"星期二": 1,
"星期三": 2,
"星期四": 3,
"星期五": 4,
"星期六": 5,
"星期日": 6
}
// 今日是列表第一条,获取今日所在星期列,作为展示起点
const today = this.dateList[0]
if (!today) {
this.calendarList = [row1, row2]
return
}
const todayCol = weekToCol[today.weekDayName]
// 遍历所有日期,按规则分配到对应行/列
this.dateList.forEach(item => {
const col = weekToCol[item.weekDayName]
if (col === undefined) return
// 规则:今日所在列及右侧 → 第一行;今日所在列左侧(跨周)→ 第二行
if (col >= todayCol) {
row1[col] = item
} else {
row2[col] = item
}
})
// 最终日历列表(仅保留有数据的行,无数据则不展示)
this.calendarList = [row1]
if (row2.some(item => item)) {
this.calendarList.push(row2)
}
},
getDay(date) {
if (!date) return "";
return date.split("-")[2];
},
formatDate(date) {
const arr = date.split("-");
return arr[0] + "-" + arr[1] + "-" + arr[2];
},
selectDate(item) {
if (!item || !item.isAvailable) return;
this.selectedTime = ''
this.dateList.forEach(i => (i.active = false));
item.active = true;
this.selectedDate = this.formatDate(item.date);
this.currentTimeSlots = (item.timeSlots || []).map(t => {
return {
...t,
selected: false
};
});
if (this.currentTimeSlots.length > 0) {
this.selectTime(this.currentTimeSlots[0]);
}
},
selectTime(item) {
if (item.remainingCount <= 0) return;
this.currentTimeSlots.forEach(t => (t.selected = false));
item.selected = true;
this.selectedTime = item.time;
},
handleGoBack() {
uni.navigateBack();
},
handleNext() {
if (!this.selectedDate || !this.selectedTime) {
uni.showToast({
title: "请选择完整",
icon: "none"
});
return;
}
const data = JSON.stringify(this.itemData)
const time = this.selectedDate + " " + this.selectedTime
uni.navigateTo({
url: `/pages/reserve/confirm?data=${encodeURIComponent(data)}&time=${time}`
});
}
}
};
</script>
<style scoped>
.container {
background: #f5f7fa;
min-height: 100vh;
}
.info-bar {
background: linear-gradient(90deg, rgba(49, 134, 255, 1), #53a8ff);
padding: 30rpx;
color: #fff;
}
.info-title {
font-size: 34rpx;
margin-bottom: 10rpx;
}
.info-dept {
font-size: 28rpx;
}
.calendar-wrap {
background: #fff;
margin: 20rpx;
border-radius: 16rpx;
padding: 20rpx;
border: 2rpx solid rgba(49, 134, 255, 1);
}
.calendar-header {
display: flex;
text-align: center;
margin-bottom: 20rpx;
}
.week-item {
flex: 1;
font-size: 30rpx;
font-weight: 500;
}
.date-row {
display: flex;
margin-bottom: 20rpx;
}
.date-item {
flex: 1;
width: 100rpx;
height: 100rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.date-item.has {
color: rgba(49, 134, 255, 1);
}
.date-item.active {
background: rgba(49, 134, 255, 1);
color: #fff;
}
.date-item.disabled {
color: #ccc;
}
.date-num {
font-size: 32rpx;
}
.date-status {
font-size: 24rpx;
}
.time-list {
padding: 20rpx;
}
.time-item {
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
margin-bottom: 16rpx;
display: flex;
justify-content: space-between;
font-size: 30rpx;
}
.time-item.selected {
background: #e8f3ff;
border: 2rpx solid rgba(49, 134, 255, 1);
}
.time-item.disabled {
color: #ccc;
}
.footer-bar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #fff;
padding: 20rpx 30rpx 40rpx;
margin-top: 20rpx;
}
.selected-info {
text-align: center;
font-size: 28rpx;
margin-bottom: 20rpx;
}
.btn-box {
display: flex;
gap: 30rpx;
}
.btn-gray {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background-color: rgba(242, 247, 255, 1);
color: rgba(49, 134, 255, 1);
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
border: 2rpx solid rgba(208, 227, 255, 1);
}
.btn-blue {
flex: 2;
height: 88rpx;
line-height: 88rpx;
background-color: rgba(49, 134, 255, 1);
color: #ffffff;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
border: 2rpx solid rgba(208, 227, 255, 1);
}
</style>