Files
SmartParks_visitore/components/VisitorDetailModal.vue

269 lines
6.6 KiB
Vue
Raw Permalink Normal View History

2025-08-21 11:23:54 +08:00
<template>
<!-- 弹窗容器 -->
<view class="visitor-modal" v-if="visible">
<!-- 遮罩层点击关闭 -->
<view class="modal-mask" @click="closeModal"></view>
<!-- 弹窗内容阻止遮罩层事件穿透 -->
<view class="modal-dialog" @click.stop>
<!-- 头部标题 + 关闭按钮 -->
<view class="dialog-header">
<text class="dialog-title">访客详情</text>
<text class="dialog-close" @click="closeModal">×</text>
</view>
<!-- 主体信息展示 -->
<view class="dialog-body">
<view class="info-item">
<text class="item-label">访客姓名</text>
<text class="item-value">{{ visitorInfo.visitorName || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">访客电话</text>
<text class="item-value">{{ visitorInfo.visitorPhone || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">所属公司</text>
<text class="item-value">{{ visitorInfo.visitorUnit || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">被访人</text>
<text class="item-value">{{ visitorInfo.interviewedPerson || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">联系电话</text>
<text class="item-value">{{ visitorInfo.interviewedPhone || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">被访单位</text>
<text class="item-value">{{ visitorInfo.interviewedUnit || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">拜访事由</text>
<text class="item-value">{{ visitorInfo.visitingReason || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">拜访时间</text>
<text class="item-value">{{ visitorInfo.visitingBeginTime || '无' }}</text>
</view>
<view class="info-item">
<text class="item-label">是否预约车位</text>
<text class="item-value">{{ visitorInfo.bookingParkingSpace ? '是' : '否' }}</text>
</view>
<view class="info-item">
<text class="item-label">预约状态</text>
<text
class="item-value status-tag"
:class="{
'status-confirmed': visitorInfo.serveStatus === 1,
'status-pending': visitorInfo.serveStatus === 0,
'status-rejected': visitorInfo.serveStatus === 2
}"
>
{{ formatServeStatus(visitorInfo.serveStatus) }}
</text>
</view>
<view class="info-item">
<text class="item-label">提交时间</text>
<text class="item-value">{{ visitorInfo.createTime || '无' }}</text>
</view>
</view>
<!-- 底部审核操作仅待确认时显示 -->
<view class="dialog-footer" v-if="showActionButtons">
<button
class="audit-btn reject"
@click="handleAudit('reject')"
:loading="loading"
>
{{ loading && auditType === 'reject' ? '驳回中...' : '驳回' }}
</button>
<button
class="audit-btn confirm"
@click="handleAudit('confirm')"
:loading="loading"
>
{{ loading && auditType === 'confirm' ? '确认中...' : '确认' }}
</button>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
// 是否显示弹窗
visible: {
type: Boolean,
default: false
},
// 访客数据
visitorInfo: {
type: Object,
default: () => ({})
},
// 是否显示审核按钮(默认仅“待确认”显示)
showActionButtons: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false, // 审核按钮加载状态
auditType: '' // 记录当前审核类型(确认/驳回)
}
},
methods: {
// 关闭弹窗
closeModal() {
this.$emit('close');
},
// 处理审核操作
handleAudit(type) {
this.loading = true;
this.auditType = type;
// 模拟接口请求(实际替换为真实接口)
setTimeout(() => {
this.loading = false;
this.closeModal(); // 关闭弹窗
// 通知父组件更新状态
this.$emit('audit', {
type: type,
visitorId: this.visitorInfo.id // 传递访客ID
});
// 提示用户
uni.showToast({
title: type === 'confirm' ? '确认成功' : '驳回成功',
icon: 'success'
});
}, 1500);
},
// 格式化服务状态
formatServeStatus(status) {
switch (status) {
case 0: return '待确认';
case 1: return '已确认';
case 2: return '已驳回';
default: return '未知';
}
}
}
}
</script>
<style scoped>
/* 弹窗容器 */
.visitor-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: flex-end;
align-items: flex-end;
z-index: 999;
}
/* 遮罩层 */
.modal-mask {
position: absolute;
width: 100%;
height: 100%;
}
/* 弹窗内容 */
.modal-dialog {
width: 100%;
background: #fff;
border-radius: 16px 16px 0 0;
overflow: hidden;
transform: translateY(100%);
animation: slideUp 0.3s forwards;
}
/* 弹窗滑入动画 */
@keyframes slideUp {
to {
transform: translateY(0);
}
}
/* 头部 */
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
background: #f8f8f8;
border-bottom: 1px solid #eee;
}
.dialog-title {
font-size: 17px;
font-weight: bold;
}
.dialog-close {
font-size: 24px;
color: #999;
}
/* 主体内容 */
.dialog-body {
padding: 16px;
}
.info-item {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.item-label {
width: 80px;
color: #666;
}
.item-value {
flex: 1;
color: #333;
}
.status-tag {
padding: 2px 8px;
border-radius: 4px;
color: #fff;
}
.status-pending {
background: #ff9900;
}
.status-confirmed {
background: #52c41a;
}
.status-rejected {
background: #ff4d4f;
}
/* 底部操作 */
.dialog-footer {
display: flex;
padding: 16px;
border-top: 1px solid #eee;
}
.audit-btn {
flex: 1;
margin: 0 8px;
padding: 12px 0;
border-radius: 8px;
color: #fff;
}
.reject {
background: #ff4d4f;
}
.confirm {
background: #52c41a;
}
</style>