bxztApp/packages/screen/src/views/RiskWarning/Dialog/responsePointDetailDialog.vue

677 lines
14 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>
<!-- 响应点详情对话框 标题是影响点详情 -->
<base-dialog
v-model:visible="props.visible"
title="影响点详情"
:table-data="[]"
:table-columns="[]"
:table-height="0"
:total="0"
:current-page="1"
:page-size="10"
:z-index="2300"
:max-width="700"
:tableShow="false"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
<template #header>
<div class="content-wrapper">
<!-- 隐患点基本信息 -->
<div class="section">
<div class="section-title">
<span class="title-icon"></span>
隐患点基本信息
</div>
<div class="basic-info">
<div class="info-row three-col">
<div class="info-item">
<span class="info-label">所属区县</span>
<span class="info-value">{{ basicInfo.district }}</span>
</div>
<div class="info-item">
<span class="info-label">影响点等级</span>
<span class="info-value level-tag" :class="basicInfo.levelClass">
{{ basicInfo.level }}
</span>
</div>
<div class="info-item">
<span class="info-label">公路编号</span>
<span class="info-value">{{ basicInfo.roadCode }}</span>
</div>
</div>
<div class="info-row three-col">
<div class="info-item">
<span class="info-label">位置</span>
<span class="info-value">{{ basicInfo.location }}</span>
</div>
<div class="info-item">
<span class="info-label">风险点描述</span>
<span class="info-value">{{ basicInfo.riskDesc }}</span>
</div>
<div class="info-item">
<span class="info-label">采取措施</span>
<span class="info-value">{{ basicInfo.measures }}</span>
</div>
</div>
</div>
</div>
<!-- 照片 -->
<div class="section">
<div class="section-title">
<span class="title-icon"></span>
照片
</div>
<div class="photo-list">
<div
v-for="(photo, index) in photoList"
:key="index"
class="photo-item"
@click="previewImage(photo)"
>
<img :src="photo" alt="照片" />
</div>
</div>
</div>
<!-- 巡查记录 -->
<div class="section">
<div class="section-title">
<span class="title-icon"></span>
巡查记录
</div>
<div class="patrol-list">
<!-- 巡查记录列表 -->
<div v-for="(record, index) in patrolRecords" :key="index" class="patrol-record-item">
<div class="patrol-number">{{ index + 1 }}</div>
<div class="patrol-content">
<div class="patrol-row">
<div class="patrol-info">
<span class="patrol-label">巡查时间</span>
<span class="patrol-value">{{ record.time }}</span>
</div>
<div class="patrol-info">
<span class="patrol-label">巡查人</span>
<span class="patrol-value">{{ record.person }}</span>
</div>
</div>
<div class="patrol-row">
<span class="patrol-label">现场情况描述</span>
<span class="patrol-value">{{ record.situation }}</span>
</div>
<div class="patrol-row">
<span class="patrol-label">是否发现问题</span>
<span class="patrol-value">{{ record.hasIssue }}</span>
</div>
</div>
<div v-if="record.image" class="patrol-image" @click="previewImage(record.image)">
<img :src="record.image" alt="" />
</div>
</div>
</div>
</div>
</div>
</template>
</base-dialog>
<!-- 图片预览弹窗 -->
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
<div class="image-preview-container" @click.stop>
<img :src="previewImageUrl" alt="预览" />
<div class="close-preview-btn" @click="closePreview">
<el-icon><Close /></el-icon>
</div>
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
import { Close } from '@element-plus/icons-vue';
import baseDialog from '../component/baseDialog.vue';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
pointData: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(['update:visible', 'close', 'viewTrack']);
// 基本信息
const basicInfo = ref({
district: '合川区',
level: '一般隐患',
levelClass: 'level-normal',
roadCode: 'G348',
location: '丁吴路(K116+656至K116+739)',
riskDesc:
'泥岩风化严重,受雨水冲刷影响,常有强风化岩体散落于边沟或塌散于路面(路面处落石已清理),影响道路正常使用。[类型:路内风险点-边坡]',
measures: '拟对开裂边坡进行清方处理后,采取挂网喷射混凝土处理,部分路段增设挡土墙',
});
// 照片列表
const photoList = ref([
'https://via.placeholder.com/120x80/40a9ff/ffffff?text=照片1',
'https://via.placeholder.com/120x80/40a9ff/ffffff?text=照片2',
]);
// 巡查记录列表
const patrolRecords = ref([
{
time: '2026-03-28 14:30:00',
person: '刘伟',
situation: '现场通行正常、无异常情况发生。',
hasIssue: '否',
image: 'https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场1',
},
{
time: '2026-03-28 14:30:00',
person: '刘伟',
situation: '现场通行正常、无异常情况发生。',
hasIssue: '否',
image: 'https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场2',
},
]);
// 状态样式
const getStatusClass = status => {
if (status === '未回应') return 'status-unresponse';
if (status === '已回应') return 'status-response';
return '';
};
// 图片预览
const previewVisible = ref(false);
const previewImageUrl = ref('');
const previewImage = url => {
previewImageUrl.value = url;
previewVisible.value = true;
};
const closePreview = () => {
previewVisible.value = false;
previewImageUrl.value = '';
};
// 查看轨迹
const viewTrack = () => {
emit('viewTrack', patrolRecord.value);
};
// 关闭对话框
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
// 点击遮罩关闭已由base-dialog组件处理
// 监听visible变化
watch(
() => props.visible,
newVal => {
if (newVal && props.pointData) {
Object.assign(basicInfo.value, props.pointData);
}
}
);
</script>
<style lang="scss" scoped>
.content-wrapper {
height: 500px;
overflow-y: auto;
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(20, 46, 73, 0.3);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #142e49;
border-radius: 3px;
&:hover {
background: #1a3a5c;
}
}
// Firefox 滚动条样式
scrollbar-width: thin;
scrollbar-color: #142e49 rgba(20, 46, 73, 0.3);
}
// 区块
.section {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
// 区块标题
.section-title {
font-size: 15px;
font-weight: 600;
color: #fff;
margin-bottom: 12px;
display: flex;
align-items: center;
.title-icon {
color: #40a9ff;
margin-right: 6px;
}
}
// 基本信息
.basic-info {
background-color: rgba(30, 70, 120, 0.3);
border-radius: 8px;
padding: 16px 20px;
}
.info-row {
display: flex;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
&.three-col {
.info-item {
flex: 1;
}
}
}
.info-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.info-label {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
}
.info-value {
font-size: 13px;
color: rgba(255, 255, 255, 0.9);
line-height: 1.4;
&.level-tag {
display: inline-block;
padding: 2px 10px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
width: fit-content;
&.level-normal {
background-color: rgba(250, 219, 95, 0.2);
color: #fadb5f;
border: 1px solid rgba(250, 219, 95, 0.4);
}
&.level-serious {
background-color: rgba(255, 77, 79, 0.2);
color: #ff4d4f;
border: 1px solid rgba(255, 77, 79, 0.4);
}
}
&.status-unresponse {
color: #ff7a45;
}
&.status-response {
color: #52c41a;
}
}
// 照片列表
.photo-list {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.photo-item {
width: 120px;
height: 80px;
border-radius: 6px;
overflow: hidden;
cursor: pointer;
border: 1px solid rgba(64, 169, 255, 0.3);
transition: all 0.3s;
&:hover {
border-color: #40a9ff;
transform: scale(1.05);
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
// 巡查记录列表
.patrol-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.patrol-record-item {
display: flex;
align-items: flex-start;
gap: 12px;
background-color: rgba(30, 70, 120, 0.2);
border-radius: 8px;
padding: 16px;
}
.patrol-number {
width: 28px;
height: 28px;
border-radius: 50%;
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
color: #fff;
font-size: 14px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.patrol-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
.patrol-row {
display: flex;
flex-wrap: wrap;
gap: 16px;
&:first-child {
gap: 24px;
}
}
.patrol-info {
display: flex;
align-items: center;
gap: 8px;
}
.patrol-label {
font-size: 13px;
color: rgba(255, 255, 255, 0.6);
}
.patrol-value {
font-size: 13px;
color: rgba(255, 255, 255, 0.9);
}
.patrol-image {
width: 80px;
height: 60px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
border: 1px solid rgba(64, 169, 255, 0.3);
flex-shrink: 0;
&:hover {
border-color: #40a9ff;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
// 时间轴列表
.timeline-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.timeline-item {
display: flex;
gap: 12px;
position: relative;
&.patrol-item {
.timeline-content {
background-color: rgba(30, 70, 120, 0.3);
border-radius: 8px;
padding: 12px;
}
}
}
.timeline-marker {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #40a9ff;
flex-shrink: 0;
margin-top: 4px;
position: relative;
&::after {
content: '';
position: absolute;
top: 12px;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: calc(100% + 12px);
background-color: rgba(64, 169, 255, 0.3);
}
&.patrol {
background-color: #40a9ff;
}
&.dispatch {
background-color: #faad14;
}
&.warning {
background-color: #ff4d4f;
}
}
.timeline-item:last-child .timeline-marker::after {
display: none;
}
.timeline-content {
flex: 1;
padding-bottom: 8px;
}
.timeline-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.timeline-type {
font-size: 13px;
color: #40a9ff;
font-weight: 500;
}
.timeline-person {
font-size: 13px;
color: rgba(255, 255, 255, 0.9);
}
.timeline-time {
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
}
.timeline-status {
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
&.status-success {
color: #52c41a;
}
&.status-reject {
color: #ff4d4f;
}
}
.timeline-target {
font-size: 12px;
color: rgba(255, 255, 255, 0.7);
.target-name {
color: #40a9ff;
font-weight: 500;
}
}
// 详情内容
.timeline-detail {
margin-top: 8px;
}
.detail-row {
display: flex;
align-items: flex-start;
gap: 8px;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
}
.detail-label {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
white-space: nowrap;
}
.detail-text {
font-size: 12px;
color: rgba(255, 255, 255, 0.85);
flex: 1;
line-height: 1.5;
}
.detail-link {
font-size: 12px;
color: #40a9ff;
cursor: pointer;
text-decoration: underline;
&:hover {
color: #69c0ff;
}
}
.detail-image {
width: 80px;
height: 60px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
border: 1px solid rgba(64, 169, 255, 0.3);
margin-left: 12px;
flex-shrink: 0;
&:hover {
border-color: #40a9ff;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
// 图片预览
.image-preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
z-index: 1100;
}
.image-preview-container {
position: relative;
max-width: 80%;
max-height: 80%;
img {
max-width: 100%;
max-height: 80vh;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
}
.close-preview-btn {
position: absolute;
top: -40px;
right: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.8);
cursor: pointer;
font-size: 24px;
transition: color 0.3s;
&:hover {
color: #fff;
}
}
</style>