2025-08-12 09:33:22 +08:00

718 lines
16 KiB
Vue
Raw 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="nav-bar">
<view class="nav-left" @click="handleBack">
<u-icon name="arrow-left" size="44"></u-icon>
<text>返回</text>
</view>
<text class="nav-title">近山社区</text>
</view> -->
<view v-if="tabsReady">
<u-tabs :list="tabList" :current="currentTab" @change="handleTabChange" border="false"
active-color="#1989fa" bg-color="#f8f8f8"></u-tabs>
<!-- 会议室列表 -->
<view class="room-list" v-if="currentTab === 0">
<view v-if="meetingRoomList.length === 0" class="empty-container">
<text>暂无会议室数据 ({{ meetingRoomList }})</text>
</view>
<view class="room-item" v-for="(item, index) in meetingRoomList" :key="index"
@click="goDetail(item.roomInfo || item)">
<image class="room-img" :src="`${IMAGE_BASE_URL}`+item.imgs[0]">
</image>
<view class="room-info">
<view class="room-header">
<view class="room-name">{{ item.title}}</view>
<view class="room-status" :class="item.status == 2 ? 'available':''">可预约</view>
</view>
<view class="room-meta">
<view class="meta-item">
<u-icon name="account" size="30" color="#666"></u-icon>
<text>可容纳人数:{{ item.maxNum }}人</text>
</view>
</view>
</view>
</view>
</view>
<!-- 预约记录列表 -->
<view class="order-list" v-else>
<view v-if="orderList.length === 0" class="empty-container">
<noData />
</view>
<view class="order-item" v-for="(item, index) in orderList" :key="index">
<view class="order-header">
<view class="order-name">{{ item.roomInfo ? item.roomInfo.title : '会议室' }}</view>
<view class="order-status" :class="item.status == 0 ? 'available':''">
{{ getStatusText(item.status) }}
</view>
</view>
<view class="order-content">
<!-- <image class="room-img" :src="`${IMAGE_BASE_URL}`+item.imgs[0]"></image> -->
<view class="order-details">
<view class="detail-item">
<u-icon name="account" size="36" color="#666" class="detail-icon"></u-icon>
<text v-if="item.companyName==''">联系人: {{ item.userName }} ({{ item.userPhone }})</text>
<text v-else>负责人: {{ item.concatName }} ({{ item.concatPhone }})</text>
</view>
<view class="detail-item">
<u-icon name="calendar" size="36" color="#666" class="detail-icon"></u-icon>
<text>预约日期: {{ formatDate(item.createdAt) }}</text>
</view>
<view class="detail-item">
<u-icon name="clock" size="30" color="#666" class="detail-icon"></u-icon>
<text>时间段: {{`${item.startTime}~${item.endTime}`}}</text>
</view>
<view class="detail-item">
<u-icon name="tags" size="30" color="#666" class="detail-icon"></u-icon>
<text>事由主题: {{formatName(item.applyTheme)}}</text>
</view>
<view class="detail-item">
<u-icon name="pushpin" size="30" color="#666" class="detail-icon"></u-icon>
<text>申请场次及人数: {{`${item.counter}/${item.num}`}}</text>
</view>
<view class="detail-item" v-if="item.remark">
<u-icon name="edit-pen" size="36" color="#666" class="detail-icon"></u-icon>
<text>备注: {{ item.remark }}</text>
</view>
</view>
</view>
<view class="order-actions">
<!-- <u-button type="primary" plain @click="goDetail(item.roomInfo || item)">查看详情</u-button> -->
<u-button type="error" plain @click="cancelOrder(item.id)">
取消预约
</u-button>
</view>
</view>
</view>
</view>
<view v-else class="loading-container">
<u-loading-icon mode="circle" size="36"></u-loading-icon>
<text class="loading-text">加载会议室信息中...</text>
</view>
<!-- <u-popup :show="show" mode="center" :round="10">
<instructionVue @change='readChange'/>
<u-button type="primary" text="我已知晓" :disabled="hasReaded" @click="show=false"></u-button>
</u-popup> -->
<!-- 保持原有结构不变 -->
<view class="copyright-fixed">
<Copyright :footerHeight="'0'" />
</view>
</view>
</template>
<script>
import {
get,
post,
del
} from '@/utils/request';
import {
IMAGE_BASE_URL,
BASE_URL
} from '@/utils/config';
import {
formatTime,
formatRelativeTime
} from '@/utils/timeFormat';
import instructionVue from '../../components/instruction.vue';
import noData from '../../components/noData.vue'
import Copyright from '@/components/gx-copyright.vue';
import {
applyType,
usages,
thingThemes
} from '@/utils/dict.js'
export default {
components: {
instructionVue,
noData,
Copyright
},
data() {
return {
hasReaded: true,
checkboxValue1: [],
// 基本案列数据
checkboxList1: [{
name: '苹果',
disabled: false
},
{
name: '香蕉',
disabled: false
},
{
name: '橙子',
disabled: true
}
],
IMAGE_BASE_URL,
tabsReady: false,
show: true,
title: '使用说明',
content: '',
tabList: [{
name: '共享空间'
},
{
name: '预约记录'
}
],
currentTab: 0,
meetingRoomList: [],
orderList: [] // 新增单独订单列表
};
},
onLoad() {
this.getList();
// this.fetchMeetingRooms().then(() => {
// this.$nextTick(() => {
// this.tabsReady = true;
// });
// });
},
// mounted() {
// this.getList();
// },
computed: {
formattedOrderList() {
return this.orderList.map(item => ({
...item,
roomTitle: item.roomInfo ? item.roomInfo.title : '会议室',
hasImages: item.roomInfo && item.roomInfo.imgs && item.roomInfo.imgs.length > 0,
firstImage: item.roomInfo && item.roomInfo.imgs && item.roomInfo.imgs[0] ?
`${IMAGE_BASE_URL}${item.roomInfo.imgs[0]}` : ''
}))
}
},
methods: {
handleBack() {
// 固定跳转首页
uni.redirectTo({
url: '/pages/mine/index'
});
},
formatName(value) {
return thingThemes.getName(value)
},
handleTabChange(index) {
this.currentTab = index.index;
if (index.index == 1) {
this.getOrderList();
} else {
this.getList();
}
},
// 格式化日期
formatDate(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}`;
},
// 格式化时间段
formatTimeRange(startAt, endAt) {
if (!startAt || !endAt) return '';
const start = new Date(startAt);
const end = new Date(endAt);
return `${start.getHours()}:${start.getMinutes().toString().padStart(2, '0')} - ${end.getHours()}:${end.getMinutes().toString().padStart(2, '0')}`;
},
// 获取状态文本
getStatusText(status) {
const statusMap = {
1: '待提交',
2: '待审核',
3: '审核通过',
99: '审核不通过'
};
return statusMap[status] || '未知状态';
},
// 获取状态样式类
getStatusClass(status) {
const classMap = {
0: 'pending',
1: 'confirmed',
2: 'cancelled',
3: 'rejected',
4: 'completed'
};
return classMap[status] || '';
},
// 取消预约
async cancelOrder(orderId) {
try {
uni.showLoading({
title: '处理中...',
mask: true
});
const res = await del(`/api/v1/app_auth/metting-room/order/${orderId}`);
if (res?.success) {
uni.showToast({
title: '取消成功',
icon: 'success'
});
this.getOrderList();
} else {
uni.showToast({
title: res?.message || '取消失败',
icon: 'none'
});
}
} catch (err) {
uni.showToast({
title: '取消失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
},
goDetail(item) {
// 安全获取ID兼容各种可能的字段名
const id = item.id;
const isSelfStudy = item.title === '自习室' ? true : false
if (!id) {
uni.showToast({
title: '会议室信息异常',
icon: 'none'
});
return;
}
uni.navigateTo({
url: `/pages/meetingDetail/index?Id=${encodeURIComponent(id)}&isSelfStudy=${isSelfStudy}`, // 使用encodeURIComponent防止特殊字符问题
success: () => {
console.log('导航成功ID:', id);
},
fail: (err) => {
console.error('导航失败:', err);
uni.showToast({
title: '打开详情页失败',
icon: 'none'
});
}
});
},
// 获取会议室列表
async getList() {
try {
const res = await get('/api/v1/apps/home/metting-room', {
current: 1,
pageSize: 10,
});
if (res?.success) {
this.meetingRoomList = [...res.data];
this.tabsReady = true;
}
} catch (err) {
uni.showToast({
title: '加载列表失败',
icon: 'none'
});
} finally {
this.isLoading = false;
}
},
// 获取我的预约记录
async getOrderList() {
try {
const res = await get('/api/v1/app_auth/metting-room/order', {
current: 1,
pageSize: 10,
});
if (res?.success) {
this.orderList = [...res.data];
this.tabsReady = true;
}
} catch (err) {
console.error('获取我的求助失败:', err);
uni.showToast({
title: '加载列表失败',
icon: 'none'
});
} finally {
this.isLoading = false;
}
},
}
};
</script>
<style lang="scss" scoped>
// 定义变量
$primary-color: #1989fa;
$success-color: #07c160;
$warning-color: #ff976a;
$error-color: #ee0a24;
$text-color: #333;
$sub-text-color: #666;
$light-text-color: #999;
$border-color: #f0f0f0;
$bg-color: #f8f8f8;
$card-radius: 24rpx;
$tag-radius: 8rpx;
.container {
position: relative; // 添加相对定位
min-height: 100vh;
padding-bottom: 120rpx; // 为copyright留出空间
box-sizing: border-box; // 确保padding计算在高度内
padding: 0;
min-height: 100vh;
background-color: $bg-color;
.copyright-fixed {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 10; /* 防止被其他元素遮挡 */
}
.nav-bar {
display: flex;
align-items: center;
padding: 15px;
// background-color: #fff;
border-bottom: 1px solid #f5f5f5;
padding-top: 60rpx;
}
.nav-left {
display: flex;
align-items: center;
// margin-right: 10px;
}
.nav-title {
flex: 1;
text-align: center;
// font-weight: bold;
width: 100%;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 70vh;
.loading-text {
margin-top: 32rpx;
font-size: 30rpx;
color: $sub-text-color;
}
}
.room-list {
padding: 30rpx;
.room-item {
display: flex;
margin-bottom: 30rpx;
border-radius: $card-radius;
overflow: hidden;
background-color: #fff;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.04);
.room-img {
width: 240rpx;
height: 240rpx;
flex-shrink: 0;
}
.room-info {
flex: 1;
padding: 24rpx 30rpx;
display: flex;
flex-direction: column;
.room-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
.room-name {
font-size: 32rpx;
font-weight: bold;
color: $text-color;
}
.room-status {
font-size: 24rpx;
padding: 4rpx 16rpx;
border-radius: 20rpx;
&.available {
background-color: rgba($success-color, 0.1);
color: $success-color;
}
&.pending {
background-color: rgba($warning-color, 0.1);
color: $warning-color;
}
&.confirmed {
background-color: rgba($primary-color, 0.1);
color: $primary-color;
}
}
}
.room-meta {
display: flex;
margin: 16rpx 0 24rpx;
.meta-item {
display: flex;
align-items: center;
margin-right: 30rpx;
font-size: 26rpx;
color: $sub-text-color;
u-icon {
margin-right: 8rpx;
}
}
}
.room-facilities {
display: flex;
flex-wrap: wrap;
margin-top: auto;
.facility-tag {
font-size: 22rpx;
padding: 4rpx 16rpx;
margin-right: 16rpx;
margin-bottom: 10rpx;
border-radius: $tag-radius;
background-color: #f0f7ff;
color: $primary-color;
}
}
}
}
}
.order-list {
padding: 30rpx;
.order-item {
margin-bottom: 40rpx;
border-radius: $card-radius;
overflow: hidden;
background-color: #fff;
padding: 32rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.04);
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 24rpx;
border-bottom: 2rpx solid #f5f5f5;
.order-name {
font-size: 32rpx;
font-weight: bold;
color: $text-color;
}
.order-status {
font-size: 26rpx;
&.available {
background-color: rgba($success-color, 0.1);
color: $success-color;
}
&.pending {
color: $warning-color;
}
&.confirmed {
color: $success-color;
}
}
}
.order-details {
padding: 30rpx 0;
.detail-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
font-size: 28rpx;
color: $sub-text-color;
text {
padding-left: 30rpx;
}
.item-icon {
width: 50rpx;
height: 50rpx;
text-align: center !important;
padding-top: 20rpx;
}
.detail-icon {
display: flex;
align-items: center;
justify-content: center;
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.detail-text {
line-height: 1.5;
}
&:last-child {
margin-bottom: 0;
}
}
}
.order-actions {
display: flex;
justify-content: flex-end;
gap: 20rpx;
padding-top: 20rpx;
border-top: 2rpx solid #f5f5f5;
}
}
}
// 空状态提示
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 0;
.empty-icon {
font-size: 96rpx;
color: #ccc;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 30rpx;
color: $sub-text-color;
}
}
.order-content {
display: flex;
padding: 30rpx 0;
border-bottom: 2rpx solid #f5f5f5;
}
.order-img {
width: 240rpx;
height: 180rpx;
border-radius: 12rpx;
margin-right: 30rpx;
flex-shrink: 0;
}
.order-details {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.detail-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
font-size: 28rpx;
color: #666;
&:last-child {
margin-bottom: 0;
}
}
.detail-icon {
margin-right: 16rpx;
}
/* 状态样式补充 */
.order-status {
font-size: 26rpx;
padding: 4rpx 16rpx;
border-radius: 20rpx;
&.pending {
background-color: rgba(#ff976a, 0.1);
color: #ff976a;
}
&.confirmed {
background-color: rgba(#07c160, 0.1);
color: #07c160;
}
&.cancelled,
&.rejected {
background-color: rgba(#ee0a24, 0.1);
color: #ee0a24;
}
&.completed {
background-color: rgba(#1989fa, 0.1);
color: #1989fa;
}
}
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
.empty-icon {
color: #ccc;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 30rpx;
color: #999;
}
}
}
</style>