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

756 lines
20 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="2500"
:max-width="650"
: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">
<div class="info-item">
<span class="info-dot"></span>
<span class="info-label">所属区县</span>
<span class="info-value">{{ basicInfo.district }}</span>
</div>
<div class="info-item">
<span class="info-dot"></span>
<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-dot"></span>
<span class="info-label">公路编号</span>
<span class="info-value">{{ basicInfo.roadCode }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-dot"></span>
<span class="info-label">位置</span>
<span class="info-value">{{ basicInfo.location }}</span>
</div>
<div class="info-item">
<span class="info-dot"></span>
<span class="info-label">风险点描述</span>
<span class="info-value" :class="getStatusClass(basicInfo.riskDesc)">
{{ basicInfo.riskDesc }}
</span>
</div>
<div class="info-item">
<span class="info-dot"></span>
<span class="info-label">发现时间</span>
<span class="info-value">{{ basicInfo.findTime }}</span>
</div>
</div>
</div>
</div>
<!-- 照片 -->
<div class="section" v-if="photoList.length > 0">
<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" v-if="dynamicRecords.length > 0">
<div class="section-title">
<span class="title-icon"></span>
填报动态信息
</div>
<div class="timeline-list">
<div v-for="(record, index) in dynamicRecords" :key="index" class="timeline-item">
<div class="timeline-marker">{{ index + 1 }}</div>
<div class="timeline-content">
<div class="timeline-header">
<span class="timeline-type">{{ record.type }}</span>
</div>
<div class="timeline-detail">
<div class="detail-row">
<span class="detail-label">巡查时间</span>
<span class="detail-value">{{ record.patrolTime }}</span>
</div>
<div class="detail-row">
<span class="detail-label">巡查人</span>
<span class="detail-value">{{ record.patrolPerson }}</span>
</div>
<div class="detail-row">
<span class="detail-label">现场情况描述</span>
<span class="detail-value">{{ record.description }}</span>
<!-- <div
v-if="record.image"
class="detail-image"
@click="previewImage(record.image)"
>
<img :src="record.image" alt="" />
</div> -->
</div>
<div class="detail-row">
<span class="detail-label">是否发现问题</span>
<span
class="detail-value"
:class="record.hasProblem ? 'status-yes' : 'status-no'"
>
{{ record.hasProblem ? '是' : '否' }}
</span>
</div>
</div>
</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';
import { request } from '@/utils/request';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
pointData: {
type: Object,
default: () => ({}),
},
item: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(['update:visible', 'close']);
// 基本信息
const basicInfo = ref({
district: '',
level: '',
levelClass: '',
roadCode: '',
location: '',
riskDesc: '',
discoverTime: '',
});
watch(
() => props.item,
newVal => {
if (newVal) {
// 当弹窗打开时获取数据
getAffectedObjectTypeId(props.item);
}
}
);
// 照片列表
const photoList = ref([]);
// 动态记录
const dynamicRecords = ref([
// {
// type: '首报',
// patrolTime: '2026-03-28 14:30:00',
// patrolPerson: '刘伟',
// description: '设置警示标识,半幅通行',
// hasProblem: true,
// image: 'https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场',
// },
// {
// type: '续报',
// patrolTime: '2026-03-28 14:30:00',
// patrolPerson: '刘伟',
// description: '设置警示标识,半幅通行',
// hasProblem: false,
// image: null,
// },
]);
// 状态样式
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 handleClose = () => {
emit('update:visible', false);
emit('close');
};
const leveltext = level => {
if (level.includes('一') || level.includes('1')) return '一类';
if (level.includes('二') || level.includes('2')) return '二类';
if (level.includes('三') || level.includes('3')) return '三类';
if (level.includes('四') || level.includes('4')) return '四类';
if (level.includes('五') || level.includes('5')) return '五类';
if (level.includes('9')) return '未评定';
return '未评定';
};
// 点击遮罩关闭已由base-dialog组件处理
// 处理影响点类型数据
const getAffectedObjectTypeId = data => {
let pointType = props.item.pointType;
if (!data) {
basicInfo.value = {};
photoList.value = [];
dynamicRecords.value = [];
return;
}
if (pointType === '桥梁') {
// 更新基本信息 - 根据数据库字段映射
basicInfo.value = {
district: data.GL1_QXMC || '-', // 区县名称
level: leveltext(data.GL1_JSZKPJDJ) || '未评定', // 技术状况评级等级
levelClass:
data.GL1_JSZKPJDJ === '一类' || data.GL1_JSZKPJDJ === '二类'
? 'level-normal'
: 'level-serious', // 一二类为一般,三四五类为重大
roadCode: data.GL1_LXBH || '-', // 路线编号
location: data.GL1_QLMC || '-', // 桥梁名称作为位置
riskDesc: data.GL1_DQBH || '-', // 当前病害
discoverTime: data.GL1_JSZKPDRQ || '-', // 技术状况评定日期
};
// 更新照片列表 - 使用桥梁照片字段
const photos = [];
if (data.GL1_QLZMZFJ) {
photos.push(data.GL1_QLZMZFJ); // 桥梁正面照附件
}
if (data.GL1_QLLMZFJ) {
photos.push(data.GL1_QLLMZFJ); // 桥梁立面照附件
}
if (data.GL1_QLDXZFJ) {
photos.push(data.GL1_QLDXZFJ); // 桥梁典型照附件
}
if (data.GL1_QLZP) {
photos.push(data.GL1_QLZP); // 桥梁照片
}
photoList.value = photos.length > 0 ? photos : [];
// 更新动态记录 - 桥梁信息没有巡查记录,使用基础信息展示
// dynamicRecords.value = [
// {
// type: '桥梁信息',
// patrolTime: data.GL1_JCTCRQ || '-', // 建成通车日期
// patrolPerson: data.GL1_QLZRR || '-', // 桥梁责任人
// description: `桥梁全长:${data.GL1_QLQC || '-'}m跨径总长${data.GL1_KJZC || '-'}m上部结构${data.GL1_SBJGLXMC || '-'}`,
// hasProblem: false,
// image: null,
// },
// ];
} else if (pointType === '边坡') {
// 更新基本信息 - 根据边坡接口返回数据映射
basicInfo.value = {
district: data.GL1_QXMC || '-', // 区县名称
level: leveltext(data.GL1_FXDJ) || '未评定', // 风险等级
levelClass:
data.GL1_FXDJ?.includes('一级') || data.GL1_FXDJ?.includes('二级')
? 'level-normal'
: 'level-serious', // 一二级为一般,三四五级为重大
roadCode: data.GL1_LXBM || '-', // 路线编码
location: data.GL1_BPGC || '-', // 边坡概况
riskDesc: data.GL1_JCSSSZ || '-', // 监测设施设置
discoverTime: data.GL1_ZRRXM || '-', // 责任人姓名
};
// 更新照片列表 - 边坡照片字段
const photos = [];
if (data.GL1_ZRLXFS) {
photos.push(data.GL1_ZRLXFS); // 责任人联系方式可能包含图片URL
}
photoList.value = photos.length > 0 ? photos : [];
// 更新动态记录 - 边坡信息展示
// dynamicRecords.value = [
// {
// type: '边坡信息',
// patrolTime: data.GL1_BPPGC || '-', // 边坡坡高
// patrolPerson: data.GL1_ZRRXM || '-', // 责任人姓名
// description: `起点桩号:${data.GL1_QDZH || '-'},终点桩号:${data.GL1_ZDZH || '-'},起点经度:${data.GL1_QDJD || '-'},起点纬度:${data.GL1_QDWD || '-'},监测设施:${data.GL1_JCSSSZ || '-'},综合措施:${data.GL1_ZHXS || '-'}`,
// hasProblem: data.GL1_JCSSSZ !== '无' && data.GL1_JCSSSZ !== null,
// image: null,
// },
// ];
} else if (pointType === '隧道') {
// 更新基本信息 - 根据隧道数据库字段映射
basicInfo.value = {
district: data.GL1_QXMC || '-', // 区县名称
level: leveltext(data.GL1_PDDJ) || '未评定', // 评定等级
levelClass:
data.GL1_PDDJ === '一级' || data.GL1_PDDJ === '二级' ? 'level-normal' : 'level-serious', // 一二级为一般,三四五级为重大
roadCode: data.GL1_LXBH || '-', // 路线编号
location: data.GL1_SDMC || '-', // 隧道名称作为位置
riskDesc: data.GL1_BHMS || '-', // 病害描述
discoverTime: data.GL1_PDRQ || '-', // 评定日期
};
// 更新照片列表 - 使用隧道照片字段
const photos = [];
if (data.GL1_SDJDKFJS) {
photos.push(data.GL1_SDJDKFJS); // 隧道进洞口照片
}
if (data.GL1_SDCDKFJS) {
photos.push(data.GL1_SDCDKFJS); // 隧道出洞口照片
}
if (data.GL1_SDDXZP) {
photos.push(data.GL1_SDDXZP); // 隧道典型照片
}
if (data.GL1_TP) {
photos.push(data.GL1_TP); // 图片
}
photoList.value = photos.length > 0 ? photos : [];
// 更新动态记录 - 隧道信息展示
// dynamicRecords.value = [
// {
// type: '隧道信息',
// patrolTime: data.GL1_XCTCSJ || '-', // 修成通车时间
// patrolPerson: data.GL1_GLDW || '-', // 管理单位
// description: `隧道全长:${data.GL1_SDC || '-'}m隧道净宽${data.GL1_SDJK || '-'}m围岩等级${data.GL1_WYDJ || '-'},衬砌类型:${data.GL1_CQLXMC || '-'}`,
// hasProblem: false,
// image: null,
// },
// ];
} else if (pointType === '路段') {
// 更新基本信息 - 根据路段数据库字段映射
basicInfo.value = {
district: data.rawData.GL1_QXMC || '-', // 起点名称(区县)
level: data.rawData.GL1_FXDJ || '未评定', // 技术等级
levelClass: data.rawData.GL1_FXDJ, // 一二级为一般,三四五级为重大
roadCode: data.rawData.GL1_LXBH || '-', // 路线编号
location: data.pointLocation, // 起点到终点
riskDesc: data.rawData.GL1_FXMS || '-', // 风险点
discoverTime: data.rawData.GL1_SBSJ || '-', // 发现时间
};
// 更新照片列表 - 路段一般没有照片
photoList.value = [];
// 更新动态记录 - 路段信息展示
// dynamicRecords.value = [
// {
// type: '路段信息',
// patrolTime: data.GL1_TZSJ || '-', // 特征数据
// patrolPerson: data.GL1_XZDJ || '-', // 行政等级
// description: `路段长度:${data.GL1_LDLC || '-'}km路面宽度${data.GL1_LMKD || '-'}m路面类型${data.GL1_LMLX || '-'},车道数量:${data.GL1_CDSL || '-'}`,
// hasProblem: false,
// image: null,
// },
// ];
}
};
// 获取影响点详情数据
const getAffectedObjectDetail = async () => {
try {
let id = '';
let apiUrl = '';
const pointType = props.item?.pointType;
if (pointType === '桥梁') {
id = props.item?.rawData?.GL1_ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/bridge/${id}`;
} else if (pointType === '边坡') {
id = props.item?.rawData?.GL1_ID || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/slope/${id}`;
} else if (pointType === '隧道') {
id = props.item?.rawData?.GL1_ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/tunnel/${id}`;
} else if (pointType === '路段') {
id = props.item?.rawData?.GL1ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/road-section/${id}`;
}
if (!id || !apiUrl) {
console.warn('未找到影响点ID或API地址');
return;
}
const res = await request({
url: apiUrl,
method: 'GET',
});
console.log('影响点详情数据:', res);
if (res.code === '00000') {
getAffectedObjectTypeId(res.data || {});
}
} catch (error) {
console.error('获取影响点详情数据失败:', error);
}
};
// 监听visible变化
watch(
() => props.visible,
newVal => {
if (newVal) {
// 当弹窗打开时获取数据
// getAffectedObjectDetail();
}
}
);
</script>
<style lang="scss" scoped>
.content-wrapper {
height: 500px;
width: 600px;
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;
}
}
.info-item {
flex: 1;
display: flex;
align-items: flex-start;
gap: 6px;
}
.info-dot {
width: 6px;
height: 6px;
background-color: rgba(255, 255, 255, 0.4);
border-radius: 50%;
margin-top: 6px;
flex-shrink: 0;
}
.info-label {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
white-space: nowrap;
min-width: 70px;
}
.info-value {
font-size: 12px;
color: rgba(255, 255, 255, 0.9);
line-height: 1.4;
flex: 1;
&.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;
}
}
// 时间轴列表
.timeline-list {
display: flex;
flex-direction: column;
margin-bottom: 10px;
gap: 16px;
}
.timeline-item {
display: flex;
gap: 12px;
position: relative;
}
.timeline-marker {
width: 24px;
height: 24px;
border-radius: 50%;
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
color: #fff;
flex-shrink: 0;
margin-top: 2px;
}
.timeline-content {
flex: 1;
background-color: rgba(30, 70, 120, 0.3);
border-radius: 8px;
padding: 12px 16px;
}
.timeline-header {
margin-bottom: 10px;
}
.timeline-type {
font-size: 14px;
color: #40a9ff;
font-weight: 600;
}
// 详情内容
.timeline-detail {
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-row {
display: flex;
align-items: flex-start;
gap: 8px;
}
.detail-label {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
white-space: nowrap;
min-width: 90px;
}
.detail-value {
font-size: 12px;
color: rgba(255, 255, 255, 0.85);
flex: 1;
line-height: 1.5;
&.status-yes {
color: #52c41a;
}
&.status-no {
color: #ff7a45;
}
}
.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: 2600;
}
.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>