SmartParks_visitore/components/VisitorDetailModal.vue
2025-08-21 11:23:54 +08:00

269 lines
6.6 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="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>