Browse Source

预约入馆等新增

master
xuhuajiao 4 weeks ago
parent
commit
bd84a1ac2a
  1. 162
      pages.json
  2. 8
      pages/home/home.vue
  3. 10
      pages/user/user.vue
  4. 5
      static/iconfont.css
  5. BIN
      static/iconfont.ttf
  6. BIN
      static/images/lib.png
  7. 336
      subpkg/pages/booking-detail/booking-detail.vue
  8. 289
      subpkg/pages/booking-record/booking-record.vue
  9. 241
      subpkg/pages/seat-booking/seat-booking.vue

162
pages.json

@ -80,78 +80,96 @@
"navigationBarTitleText": "图书详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/book-list/book-list",
"style": {
"navigationBarTitleText": "图书列表"
}
},
{
"path": "pages/ranking/ranking",
"style": {
"navigationBarTitleText": "借阅排行榜"
}
},
{
"path": "pages/activity-list/activity-list",
"style": {
"navigationBarTitleText": "活动列表"
}
},
{
"path": "pages/activity-detail/activity-detail",
"style": {
"navigationBarTitleText": "活动详情"
}
},
{
"path": "pages/myLending/myLending",
"style": {
"navigationBarTitleText": "我的借阅",
"enablePullDownRefresh": true,
"onReachBottomDistance": 100
}
},
{
"path": "pages/feedback/feedback",
"style": {
"navigationBarTitleText": "读者留言"
}
},
{
"path": "pages/reader-card/reader-card",
"style": {
"navigationBarTitleText": "读者证"
}
},
{
"path": "pages/feedback-list/feedback-list",
"style": {
"navigationBarTitleText": "读者留言"
}
},
{
"path": "pages/feedback-detail/feedback-detail",
"style": {
"navigationBarTitleText": "留言详情"
}
},
{
"path": "pages/collect-list/collect-list",
"style": {
"navigationBarTitleText": "我的收藏",
"enablePullDownRefresh": true,
"onReachBottomDistance": 100
}
},
{
"path": "pages/user-info/user-info",
"style": {
"navigationBarTitleText": "个人资料"
}
}
]
},
{
"path": "pages/book-list/book-list",
"style": {
"navigationBarTitleText": "图书列表"
}
},
{
"path": "pages/ranking/ranking",
"style": {
"navigationBarTitleText": "借阅排行榜"
}
},
{
"path": "pages/activity-list/activity-list",
"style": {
"navigationBarTitleText": "活动列表"
}
},
{
"path": "pages/activity-detail/activity-detail",
"style": {
"navigationBarTitleText": "活动详情"
}
},
{
"path": "pages/myLending/myLending",
"style": {
"navigationBarTitleText": "我的借阅",
"enablePullDownRefresh": true,
"onReachBottomDistance": 100
}
},
{
"path": "pages/feedback/feedback",
"style": {
"navigationBarTitleText": "读者留言"
}
},
{
"path": "pages/reader-card/reader-card",
"style": {
"navigationBarTitleText": "读者证"
}
},
{
"path": "pages/feedback-list/feedback-list",
"style": {
"navigationBarTitleText": "读者留言"
}
},
{
"path": "pages/feedback-detail/feedback-detail",
"style": {
"navigationBarTitleText": "留言详情"
}
},
{
"path": "pages/collect-list/collect-list",
"style": {
"navigationBarTitleText": "我的收藏",
"enablePullDownRefresh": true,
"onReachBottomDistance": 100
}
},
{
"path": "pages/user-info/user-info",
"style": {
"navigationBarTitleText": "个人资料"
}
},
{
"path": "pages/seat-booking/seat-booking",
"style": {
"navigationBarTitleText": "座位预约"
}
},
{
"path": "pages/booking-detail/booking-detail",
"style": {
"navigationBarTitleText": "预约登记"
}
},
{
"path": "pages/booking-record/booking-record",
"style": {
"navigationBarTitleText": "预约座位记录"
}
}
]
}
]
}

8
pages/home/home.vue

@ -88,9 +88,9 @@
</view>
<view class="menu-item" @click="toFeedback">
<view class="menu-icon">
<uni-icons custom-prefix="iconfont" type="icon-duzheliuyan" size="26"></uni-icons>
<uni-icons custom-prefix="iconfont" type="icon-ruguanyuyue" size="26"></uni-icons>
</view>
<view class="menu-label">读者留言</view>
<view class="menu-label">预约入馆</view>
</view>
<view class="menu-item" @click="onToUser">
<view class="menu-icon">
@ -452,7 +452,9 @@ export default {
});
},
toFeedback() {
this.checkBindAndNavigate("/subpkg/pages/feedback/feedback", "请您绑定读者证");
uni.navigateTo({
url: '/subpkg/pages/seat-booking/seat-booking'
});
},
//
toLibraryCard() {

10
pages/user/user.vue

@ -22,6 +22,10 @@
<image class="menu-icon" src="@/static/images/menu-jy.png" mode="scaleToFill" />
<text class="menu-txt">借阅</text>
</view>
<view class="menu-item" @click="toBookingRecord">
<image class="menu-icon" src="@/static/images/menu-jy.png" mode="scaleToFill" />
<text class="menu-txt">入馆</text>
</view>
</view>
</view>
@ -72,6 +76,12 @@ export default {
});
},
toBookingRecord() {
uni.navigateTo({
url: '/subpkg/pages/booking-record/booking-record'
});
},
async loadUserInfo() {
if (this.loading) return;
this.loading = true;

5
static/iconfont.css

@ -3,6 +3,7 @@
src: url('/static/iconfont.ttf') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
@ -11,6 +12,10 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-ruguanyuyue:before {
content: "\e61d";
}
.icon-xingming:before {
content: "\e646";
}

BIN
static/iconfont.ttf

BIN
static/images/lib.png

After

Width: 150  |  Height: 150  |  Size: 46 KiB

336
subpkg/pages/booking-detail/booking-detail.vue

@ -0,0 +1,336 @@
<template>
<view class="booking-detail">
<view class="section">
<view class="section-title">日期选择</view>
<view class="calendar">
<view class="calendar-header">
<text class="month">{{ currentYear }}{{ currentMonth }}</text>
</view>
<view class="calendar-weekdays">
<text v-for="day in weekdays" :key="day" class="weekday">{{ day }}</text>
</view>
<view class="calendar-days">
<view
v-for="(day, index) in calendarDays"
:key="index"
class="day-item"
:class="{
'other-month': !day.currentMonth,
'selected': day.date === selectedDate,
'disabled': !day.available,
'today': day.isToday
}"
@click="selectDate(day)"
>
<text class="day-num">{{ day.day }}</text>
<text v-if="day.available && !day.isToday" class="available-tag">开放日</text>
<text v-if="day.isToday" class="today-tag">今天</text>
</view>
</view>
</view>
</view>
<view class="section">
<view class="section-title">时间选择</view>
<view class="time-slots">
<view
v-for="slot in timeSlots"
:key="slot.id"
class="time-slot"
:class="{ 'selected': selectedTime === slot.time }"
@click="selectTime(slot)"
>
<text class="time-text">{{ slot.time }}</text>
<text v-if="slot.available" class="available-badge">可选</text>
<text v-else class="unavailable-badge">已满</text>
</view>
</view>
</view>
<view class="bottom-bar">
<button class="btn-primary" @click="confirmBooking">确认预约</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
currentYear: new Date().getFullYear(),
currentMonth: new Date().getMonth() + 1,
selectedDate: '',
selectedTime: '',
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
calendarDays: [],
timeSlots: [
{ id: 1, time: '09:15-12:45', available: true },
{ id: 2, time: '13:00-16:30', available: false },
{ id: 3, time: '16:45-20:15', available: true }
]
};
},
onLoad(options) {
this.generateCalendar();
},
methods: {
generateCalendar() {
const year = this.currentYear;
const month = this.currentMonth;
const firstDay = new Date(year, month - 1, 1);
const lastDay = new Date(year, month, 0);
const daysInMonth = lastDay.getDate();
const startWeekday = firstDay.getDay();
const today = new Date();
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const days = [];
const prevMonthLastDay = new Date(year, month - 1, 0).getDate();
for (let i = startWeekday - 1; i >= 0; i--) {
days.push({
day: prevMonthLastDay - i,
date: '',
currentMonth: false,
available: false,
isToday: false
});
}
const todayDate = new Date();
const availableDates = [];
for (let i = 0; i < 7; i++) {
const date = new Date(todayDate);
date.setDate(todayDate.getDate() + i);
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
availableDates.push(dateStr);
}
for (let i = 1; i <= daysInMonth; i++) {
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`;
const isAvailable = availableDates.includes(dateStr);
const isToday = dateStr === todayStr;
days.push({
day: i,
date: dateStr,
currentMonth: true,
available: isAvailable,
isToday: isToday
});
}
const remainingDays = 42 - days.length;
for (let i = 1; i <= remainingDays; i++) {
days.push({
day: i,
date: '',
currentMonth: false,
available: false,
isToday: false
});
}
this.calendarDays = days;
if (availableDates.length > 0) {
this.selectedDate = availableDates[0];
}
},
selectDate(day) {
if (!day.available || !day.currentMonth) return;
this.selectedDate = day.date;
},
selectTime(slot) {
if (!slot.available) return;
this.selectedTime = slot.time;
},
confirmBooking() {
if (!this.selectedDate) {
uni.showToast({ title: '请选择日期', icon: 'none' });
return;
}
if (!this.selectedTime) {
uni.showToast({ title: '请选择时间段', icon: 'none' });
return;
}
uni.showLoading({ title: '预约中...' });
setTimeout(() => {
uni.hideLoading();
uni.showModal({
title: '预约成功',
content: `您已成功预约\n日期:${this.selectedDate}\n时间:${this.selectedTime}`,
showCancel: false,
confirmText: '确定',
success: () => {
uni.navigateBack({ delta: 2 });
}
});
}, 1500);
}
}
};
</script>
<style lang="scss" scoped>
.booking-detail {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 70px;
}
.section {
background-color: #fff;
margin: 10px;
border-radius: 12px;
padding: 16px;
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 16px;
}
/* 日历 */
.calendar-header {
text-align: center;
margin-bottom: 12px;
}
.month {
font-size: 16px;
color: #333;
font-weight: bold;
}
.calendar-weekdays {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.weekday {
width: 14.28%;
text-align: center;
font-size: 13px;
color: #999;
}
.calendar-days {
display: flex;
flex-wrap: wrap;
}
.day-item {
width: 14.28%;
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 6px;
border-radius: 6px;
position: relative;
}
.day-item.other-month .day-num {
color: #ccc;
}
.day-item.disabled .day-num {
color: #ccc;
}
.day-item.selected {
background-color: #01a4fe;
}
.day-item.selected .day-num {
color: #fff;
font-size: 15px;
font-weight: bold;
}
.day-item.selected .available-tag,
.day-item.selected .today-tag {
color: rgba(255, 255, 255, 0.9);
font-size: 10px;
}
.day-item.today:not(.selected) {
background-color: #fff3cd;
}
.day-item.today:not(.selected) .day-num {
color: #856404;
}
.day-num {
font-size: 14px;
color: #333;
}
.available-tag {
font-size: 10px;
color: #01a4fe;
margin-top: 2px;
}
.today-tag {
font-size: 10px;
color: #856404;
margin-top: 2px;
}
/* 时间选择 */
.time-slots {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.time-slot {
width: calc(50% - 5px);
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px;
background-color: #f8f8f8;
border-radius: 8px;
border: 1px solid transparent;
}
.time-slot.selected {
background-color: #e8f4fd;
border-color: #01a4fe;
}
.time-text {
font-size: 14px;
color: #333;
}
.available-badge {
font-size: 12px;
color: #01a4fe;
background-color: #e8f4fd;
padding: 2px 8px;
border-radius: 10px;
}
.unavailable-badge {
font-size: 12px;
color: #999;
background-color: #f0f0f0;
padding: 2px 8px;
border-radius: 10px;
}
/* 底部按钮 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 10px;
background-color: #fff;
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1);
}
.btn-primary {
width: 100%;
height: 44px;
line-height: 44px;
background-color: #01a4fe;
color: #fff;
border-radius: 22px;
font-size: 15px;
border: none;
}
.btn-primary::after {
border: none;
}
</style>

289
subpkg/pages/booking-record/booking-record.vue

@ -0,0 +1,289 @@
<template>
<view class="activity-list">
<view class="tab-box">
<view
class="tab-item"
:class="{ active: currentTab === 0 }"
@click="switchTab(0)"
>
未开始
</view>
<view
class="tab-item"
:class="{ active: currentTab === 1 }"
@click="switchTab(1)"
>
进行中
</view>
<view
class="tab-item"
:class="{ active: currentTab === 2 }"
@click="switchTab(2)"
>
已结束
</view>
</view>
<scroll-view
scroll-y
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
lower-threshold="100"
class="scroll-view"
>
<view
class="activity-item"
v-for="item in displayList"
:key="item.id"
@click="toActivityDetail(item)"
>
<view class="activity-info">
<text class="title">{{ item.area }}</text>
<view class="item-info">
<text class="label">开始时间</text>
<text class="value">{{ item.startTime }}</text>
</view>
<view class="item-info">
<text class="label">结束时间</text>
<text class="value">{{ item.endTime }}</text>
</view>
<view class="item-info">
<text class="label">座位号</text>
<text class="value">{{ item.seatNumber }}</text>
</view>
<view class="item-info">
<text class="label">状态</text>
<text class="value status-tag" :class="item.statusClass">{{ item.statusText }}</text>
</view>
<view class="btn-box" v-if="item.status === 0">
<button class="activity-btn" type="primary" @click.stop="cancelAppoint(item)">
取消预约
</button>
</view>
</view>
</view>
<view class="empty-box" v-if="displayList.length === 0">
<uni-icons type="empty" size="80" color="#ccc"></uni-icons>
<text class="empty-text">{{ getEmptyText() }}</text>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
currentTab: 0,
activityList: [],
refreshing: false
};
},
computed: {
displayList() {
const statusMap = {
0: [0, '0', '未开始', 'pending'],
1: [1, '1', '进行中', 'ongoing'],
2: [2, '2', '已结束', 'ended']
};
const targetStatuses = statusMap[this.currentTab] || [];
return this.activityList.filter(item => {
const itemStatus = String(item.status);
return targetStatuses.some(status => String(status) === itemStatus);
});
}
},
onLoad() {
this.getActivityList();
},
methods: {
switchTab(index) {
this.currentTab = index;
},
getActivityList() {
this.refreshing = true;
setTimeout(() => {
const rawData = [
{id:1,area:'一楼自习区',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:0,statusText:'已预约'},
{id:2,area:'综合阅览一',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:1,statusText:'进行中'},
{id:4,area:'专题阅览室',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:0,statusText:'已预约'},
];
this.activityList = rawData.map(item => ({
...item,
statusClass: `status-${item.status}`
}));
this.refreshing = false;
}, 500);
},
onRefresh() {
this.getActivityList();
},
cancelAppoint(item) {
uni.showModal({
title: '提示',
content: `确定要取消${item.area}的预约吗?`,
success: (res) => {
if (res.confirm) {
uni.showToast({ title: '取消成功', icon: 'success' });
this.getActivityList();
}
}
})
},
toActivityDetail(item) {
uni.navigateTo({
url: "/subpkg/pages/activity-detail/activity-detail?item=" + encodeURIComponent(JSON.stringify(item))
});
},
getEmptyText() {
const textMap = {
0: '未开始',
1: '进行中',
2: '已结束'
}
return `暂无${textMap[this.currentTab]}的预约~`
}
},
};
</script>
<style lang="scss" scoped>
.activity-list {
padding: 0;
height: 100vh;
box-sizing: border-box;
background-color: #f5f5f5;
}
.tab-box {
display: flex;
background-color: #fff;
margin-bottom: 10px;
position: sticky;
top: 0;
z-index: 99;
}
.tab-item {
flex: 1;
text-align: center;
padding: 12px 0;
font-size: 15px;
color: #666;
position: relative;
}
.tab-item.active {
color: #01a4fe;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
width: 30px;
height: 3px;
background-color: #01a4fe;
bottom: 0;
left: 50%;
transform: translateX(-50%);
border-radius: 2px;
}
.scroll-view {
height: calc(100vh - 60px);
padding: 0 12px;
box-sizing: border-box;
}
.empty-box {
height: calc(100vh - 200px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.empty-text {
margin-top: 16px;
font-size: 14px;
color: #999;
}
.activity-item {
background: #fff;
border-radius: 12px;
margin-bottom: 12px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
cursor: pointer;
transition: transform 0.2s;
&:active {
transform: scale(0.98);
}
}
.activity-info {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 16px;
.title {
font-size: 16px;
font-weight: bold;
color: #222;
margin-bottom: 12px;
display: block;
}
.item-info {
display: flex;
padding: 4px 0;
font-size: 14px;
.label {
color: #666;
width: 72px;
}
.value {
color: #333;
flex: 1;
}
}
}
/* 正确的状态样式 */
.status-tag {
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
}
.status-tag.status-0 {
color: #01a4fe;
background: #e6f7ff;
}
.status-tag.status-1 {
color: #00b42a;
background: #e6ffed;
}
.status-tag.status-2 {
color: #999;
background: #f5f5f5;
}
.btn-box {
width: 100%;
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.activity-btn {
background-color: #01a4fe;
font-size: 13px;
border-radius: 6px;
padding: 0 14px;
height: 28px;
line-height: 28px;
}
</style>

241
subpkg/pages/seat-booking/seat-booking.vue

@ -0,0 +1,241 @@
<template>
<view class="seat-booking">
<!-- 顶部横幅 -->
<view class="banner">
<image class="banner-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image>
<view class="banner-overlay">
<text class="banner-text">葛店经济开发区图书馆预约</text>
</view>
</view>
<view class="content">
<!-- 场馆选择下拉框 -->
<!-- <view class="venue-select">
<picker :value="venueIndex" :range="venues" @change="onVenueChange">
<view class="picker-content">
<text>{{ venues[venueIndex] }}</text>
<uni-icons type="down" size="16" color="#666" />
</view>
</picker>
</view> -->
<!-- 楼层/区域卡片列表 -->
<view class="floor-list">
<view class="floor-item" v-for="floor in floorList" :key="floor.id">
<text class="floor-name">{{ floor.floor }}</text>
<div class="floor-info">
<view class="floor-left">
<text class="floor-title">{{ floor.title }}</text>
<image class="banner-bg" src="@/static/images/lib.png" mode="aspectFill"></image>
</view>
<view class="floor-right">
<text class="floor-desc">{{ floor.desc }}</text>
<view style="display: flex; justify-content: flex-end; width: 100%; text-align: end;">
<button class="booking-btn" @click="bookingFloor(floor)">预约</button>
</view>
</view>
</div>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
venueIndex: 0,
venues: ['所有场馆', '东馆', '西馆', '南馆'],
floorList: [
{
id: 1,
floor: '3楼',
title: '综合阅览一',
desc: '葛店图书馆三楼阅读广场共有464个座位,为读者提供备电源,读者可预约选择心仪的座位。区域采光良好,环境优美,读者可在休息时一览楼下的风景。',
image: '@/static/images/lib.png'
},
{
id: 2,
floor: '3楼',
title: '少儿阅览室',
desc: '少儿阅览室共有464个座位,为读者提供备电源、读者可自助选择位置,各个区采光良好,环境优美,读者可在休息时一览楼下的风景。',
image: '@/static/images/lib.png'
},
{
id: 3,
floor: '3楼',
title: '专题阅览室',
desc: '专题阅览室共有464个座位,为读者提供备电源、读者可自助选择位置,各个区采光良好,环境优美,读者可在休息时一览楼下的风景。',
image: '@/static/images/lib.png'
}
]
};
},
onLoad() {
this.loadSeatInfo();
},
methods: {
loadSeatInfo() {
console.log('加载座位信息');
},
onVenueChange(e) {
this.venueIndex = e.detail.value;
console.log('切换场馆:', this.venues[this.venueIndex]);
},
bookingFloor(floor) {
uni.navigateTo({
url: `/subpkg/pages/booking-detail/booking-detail?floor=${floor.floor}&title=${floor.title}`
});
}
}
};
</script>
<style lang="scss" scoped>
.seat-booking {
min-height: 100vh;
background-color: #f5f7fa;
}
/* 顶部横幅 */
.banner {
position: relative;
height: 140px;
}
.banner-bg {
width: 100%;
height: 100%;
}
.banner-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.banner-text {
color: #fff;
font-size: 20px;
font-weight: 500;
}
.content {
padding: 16px;
// margin-top: -20px;
position: relative;
z-index: 10;
}
/* 场馆选择下拉框 */
.venue-select {
display: flex;
justify-content: flex-end;
margin-bottom: 16px;
}
.picker-content {
display: flex;
align-items: center;
gap: 4px;
padding: 8px 16px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
color: #333;
}
/* 楼层卡片 */
.floor-list {
background-color: #fff;
border-radius: 12px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.floor-item {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #eee;
&:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
}
.floor-name {
display: block;
font-size: 16px;
font-weight: bold;
padding-bottom: 8px;
}
.floor-info{
display: inline-flex;
align-items: flex-start;
justify-content: space-between;
}
.floor-left {
position: relative;
width: 90px;
height: 100px;
border-radius: 8px;
margin-right: 12px;
}
.floor-image {
width: 90px;
height: 100px;
object-fit: cover;
}
.floor-title {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
padding: 4px 0;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
// font-weight: bold;
font-size: 12px;
// font-weight: bold;
}
.floor-right {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.floor-desc {
font-size: 13px;
color: #666;
line-height: 1.5;
margin-bottom: 8px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
.booking-btn {
background-color: #01a4fe;
color: #fff;
font-size: 14px;
padding: 0 20px;
border: none;
margin: 6px 0 0 0;
height: 30px;
line-height: 30px;
}
.booking-btn::after {
border: none;
}
</style>
Loading…
Cancel
Save