Files
jg_app/src/pages/trafficAlerts/detail.vue
2026-04-10 17:10:36 +08:00

683 lines
15 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>
<div class="alert-detail-page">
<!-- 顶部导航栏 -->
<div class="nav-bar">
<van-icon name="arrow-left" class="nav-back" @click="goBack" />
<h1 class="nav-title">路况预警详情</h1>
<div class="nav-placeholder"></div>
</div>
<!-- 预警信息卡片 -->
<div class="detail-card">
<!-- 头部信息 -->
<div class="card-header">
<div class="header-left">
<span class="level-tag" :class="alertDetail.levelClass">
{{ alertDetail.level }}
</span>
<span class="alert-title">{{ alertDetail.title }}</span>
</div>
<span class="status-tag" :class="alertDetail.statusClass">
{{ alertDetail.status }}
</span>
</div>
<!-- 图片 -->
<div class="card-image" v-if="alertDetail.image">
<van-image
:src="alertDetail.image"
fit="cover"
class="alert-img"
/>
</div>
<!-- 详细信息 -->
<div class="card-details">
<div class="detail-item">
<van-icon name="clock" class="detail-icon" />
<span class="label">检测时间</span>
<span class="value">{{ alertDetail.time }}</span>
</div>
<div class="detail-item">
<van-icon name="location" class="detail-icon" />
<span class="label">检测地点</span>
<span class="value">{{ alertDetail.location }}</span>
</div>
<!-- 视频展示按钮 -->
<div class="video-btn-wrapper">
<van-button block round class="video-btn">
<van-icon name="video-o" class="video-icon" />
视频展示
</van-button>
</div>
</div>
</div>
<!-- 执行记录卡片 -->
<div class="record-card">
<div class="card-title">执行记录</div>
<!-- 蓝色边框卡片 -->
<div class="execution-box">
<!-- 绿色边框内层卡片 -->
<div class="info-box">
<div class="info-row">
<span class="info-label">执行时间</span>
<span class="info-value">03/29 09:30</span>
</div>
<div class="info-row">
<span class="info-text">交通指挥中心</span>
<span class="info-divider">|</span>
<span class="info-text">联系电话027-8888-8888</span>
</div>
<div class="info-row">
<span class="info-label">任务地点</span>
<span class="info-value">{{ alertDetail.location }}</span>
</div>
</div>
<!-- 任务描述 -->
<div class="task-desc">
协助疏导交通确保道路畅通维持现场秩序
</div>
<!-- 打卡情况 - 执行中和已完成状态显示 -->
<div v-if="status === '执行中' || status === '已完成'" class="checkin-box">
<div class="checkin-row">
<span class="checkin-date">11-16</span>
<span class="checkin-time">16:20:15</span>
<span class="checkin-type">签到打卡</span>
</div>
<div class="checkin-row">
<span class="checkin-label">打卡账号</span>
<span class="checkin-value">21515800</span>
</div>
<div class="checkin-row checkin-location">
<van-icon name="location" class="location-icon" />
<span>四川省德阳市旌阳区嘉明街道光兴街2号</span>
</div>
</div>
<!-- 按钮区域 -->
<!-- 已完成状态 - 显示三次反馈按钮 -->
<div v-if="status === '已完成'" class="feedback-buttons">
<van-button block round class="feedback-btn" @click="showFeedback(1)">
第一次反馈结果
</van-button>
<van-button block round class="feedback-btn" @click="showFeedback(2)">
第二次反馈结果
</van-button>
<van-button block round class="feedback-btn" @click="showFeedback(3)">
第三次反馈结果
</van-button>
</div>
<!-- 未执行状态 - 显示定位打卡按钮 -->
<div v-else-if="status === '未执行'" class="action-buttons">
<van-button block round type="primary" class="action-btn" @click="handleCheckIn">
定位打卡
</van-button>
</div>
<!-- 执行中状态 - 显示反馈按钮 -->
<div v-else-if="status === '执行中'" class="feedback-buttons">
<van-button block round class="feedback-btn success" @click="showFeedback(1)">
第一次反馈结果
</van-button>
<van-button block round class="feedback-btn success" @click="showFeedback(2)">
第二次反馈结果
</van-button>
<van-button block round type="primary" class="action-btn" @click="handleFeedback">
立即反馈
</van-button>
</div>
</div>
</div>
<!-- 反馈结果弹窗 -->
<van-popup v-model:show="showResultDialog" round position="center" class="feedback-popup">
<div class="popup-content">
<h2 class="popup-title">{{ currentFeedback.title }}</h2>
<div class="popup-info">
<p>反馈时间{{ currentFeedback.time }}</p>
</div>
<!-- 现场照片 -->
<div class="popup-section">
<p class="section-label">现场照片</p>
<div class="image-grid">
<van-image
v-for="(img, idx) in currentFeedback.images"
:key="idx"
:src="img"
fit="cover"
class="feedback-img"
/>
</div>
</div>
<!-- 场地视频 -->
<div class="popup-section">
<p class="section-label">场地视频</p>
<div class="video-item">
<van-icon name="video-o" class="video-icon" />
<span>视频 1</span>
</div>
</div>
<!-- 反馈内容 -->
<div class="popup-section">
<h3 class="content-title">反馈内容</h3>
<p class="content-text">{{ currentFeedback.content }}</p>
</div>
<!-- 关闭按钮 -->
<van-button block round class="close-btn" @click="closePopup">
关闭
</van-button>
</div>
</van-popup>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();
// 获取URL参数
const alertId = route.query.id || "1";
const status = route.query.status || "未执行";
// 反馈弹窗状态
const showResultDialog = ref(false);
const selectedFeedbackIndex = ref(1);
// 预警详情数据
const alertDetail = ref({
id: alertId,
level: "一级",
levelClass: "level-red",
title: "交通事故",
status: status,
statusClass: computed(() => {
if (status === "执行中") return "status-blue";
if (status === "已完成") return "status-green";
return "status-orange";
}).value,
image: "https://images.unsplash.com/photo-1772962622823-77778ff7b192?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHx0cmFmZmljJTIwYWNjaWRlbnQlMjBlbWVyZ2VuY3l8ZW58MXx8fHwxNzc0NjA1NzE3fDA&ixlib=rb-4.1.0&q=80&w=1080",
location: "解放大道光谷广场",
time: "03/29 08:00",
issuer: "110指挥中心",
phone: "027-110"
});
// 反馈数据
const feedbackData = {
1: {
title: "第一次反馈结果",
time: "03/29 10:15",
content: "已到达现场,正在疏导交通。现场车流量较大,已设置临时路障引导车辆分流。",
images: [
"https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=800&q=80",
"https://images.unsplash.com/photo-1486006920555-c77dcf18193c?w=800&q=80"
]
},
2: {
title: "第二次反馈结果",
time: "03/29 10:45",
content: "交通疏导进行中拥堵情况有所缓解。已联系拖车处理事故车辆预计15分钟后完全恢复通行。",
images: [
"https://images.unsplash.com/photo-1485833077593-4278bba3f11f?w=800&q=80",
"https://images.unsplash.com/photo-1502444330042-d1a1ddf9bb5b?w=800&q=80"
]
},
3: {
title: "第三次反馈结果",
time: "03/29 11:10",
content: "任务已完成,交通已恢复正常。事故车辆已清离现场,临时路障已撤除,道路完全畅通。",
images: [
"https://images.unsplash.com/photo-1464037866556-6812c9d1c72e?w=800&q=80",
"https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800&q=80"
]
}
};
const currentFeedback = computed(() => feedbackData[selectedFeedbackIndex.value] || feedbackData[1]);
// 返回
function goBack() {
router.back();
}
// 定位打卡
function handleCheckIn() {
router.push({
path: "/checkInPage",
query: { id: alertId }
});
}
// 立即反馈
function handleFeedback() {
router.push({
path: "/alert-handle",
query: { id: alertId, status: status }
});
}
// 显示反馈弹窗
function showFeedback(index) {
selectedFeedbackIndex.value = index;
showResultDialog.value = true;
}
// 关闭弹窗
function closePopup() {
showResultDialog.value = false;
}
</script>
<style lang="scss" scoped>
.alert-detail-page {
min-height: 100vh;
background: #f1f5f9;
padding-bottom: 100px;
}
.nav-bar {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
background: white;
border-bottom: 1px solid #e5e5e5;
padding: 12px 16px;
.nav-back {
font-size: 24px;
color: #333;
}
.nav-title {
font-size: 17px;
font-weight: 600;
color: #333;
}
.nav-placeholder {
width: 24px;
}
}
.detail-card,
.record-card {
margin: 16px;
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.detail-card {
padding: 16px;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
.header-left {
display: flex;
align-items: center;
gap: 8px;
}
.level-tag {
padding: 4px 8px;
border-radius: 8px;
font-size: 12px;
&.level-red {
background: #fee2e2;
color: #dc2626;
}
&.level-orange {
background: #ffedd5;
color: #ea580c;
}
&.level-blue {
background: #dbeafe;
color: #2563eb;
}
}
.alert-title {
font-size: 15px;
font-weight: 600;
color: #333;
}
.status-tag {
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
&.status-orange {
background: #fff7ed;
color: #ea580c;
border: 1px solid #fed7aa;
}
&.status-blue {
background: #eff6ff;
color: #2563eb;
border: 1px solid #bfdbfe;
}
&.status-green {
background: #f0fdf4;
color: #16a34a;
border: 1px solid #bbf7d0;
}
}
}
.card-image {
margin-bottom: 12px;
.alert-img {
width: 100%;
height: 180px;
border-radius: 12px;
}
}
.card-details {
.detail-item {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 14px;
&:last-child {
margin-bottom: 0;
}
.detail-icon {
font-size: 16px;
color: #2563eb;
margin-right: 8px;
}
.label {
color: #94a3b8;
}
.value {
color: #475569;
}
}
.video-btn-wrapper {
margin-top: 12px;
.video-btn {
height: 40px;
background: #2563eb;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
color: white;
.video-icon {
margin-right: 6px;
}
}
}
}
.record-card {
padding: 16px;
.card-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 12px;
}
}
.execution-box {
background: #eff6ff;
border: 2px solid #2563eb;
border-radius: 16px;
padding: 16px;
}
.info-box {
background: #f0fdf4;
border: 2px solid #16a34a;
border-radius: 12px;
padding: 10px;
.info-row {
display: flex;
flex-wrap: wrap;
margin-bottom: 6px;
font-size: 14px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #64748b;
}
.info-value {
color: #333;
font-weight: 500;
}
.info-text {
color: #64748b;
}
.info-divider {
color: #d1d5db;
margin: 0 4px;
}
}
}
.task-desc {
margin-top: 12px;
font-size: 15px;
color: #333;
font-weight: 600;
line-height: 1.5;
padding: 0 4px;
}
.checkin-box {
margin-top: 12px;
background: #f9fafb;
border-radius: 12px;
padding: 12px;
.checkin-row {
display: flex;
flex-wrap: wrap;
margin-bottom: 8px;
font-size: 14px;
&:last-child {
margin-bottom: 0;
}
.checkin-date,
.checkin-time {
color: #64748b;
}
.checkin-type {
color: #475569;
margin-left: 8px;
}
.checkin-label {
color: #64748b;
}
.checkin-value {
color: #333;
}
&.checkin-location {
color: #475569;
.location-icon {
font-size: 14px;
margin-right: 4px;
margin-top: 2px;
}
}
}
}
.feedback-buttons,
.action-buttons {
margin-top: 12px;
display: flex;
flex-direction: column;
gap: 8px;
.feedback-btn {
height: 40px;
background: #2563eb;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
color: white;
&.success {
background: #16a34a;
}
}
.action-btn {
height: 40px;
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
}
}
.feedback-popup {
width: 90%;
max-width: 400px;
max-height: 80vh;
overflow-y: auto;
}
.popup-content {
padding: 24px;
}
.popup-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin-bottom: 12px;
}
.popup-info {
margin-bottom: 16px;
font-size: 14px;
color: #64748b;
}
.popup-section {
margin-bottom: 16px;
.section-label {
font-size: 14px;
color: #64748b;
margin-bottom: 8px;
}
.content-title {
font-size: 15px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.content-text {
font-size: 14px;
color: #64748b;
line-height: 1.6;
}
}
.image-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
.feedback-img {
width: 100%;
height: 120px;
border-radius: 8px;
}
}
.video-item {
display: flex;
align-items: center;
gap: 8px;
background: #f9fafb;
padding: 12px;
border-radius: 8px;
.video-icon {
font-size: 20px;
color: #2563eb;
}
span {
font-size: 14px;
color: #64748b;
}
}
.close-btn {
height: 40px;
background: #e5e7eb;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 500;
color: #333;
margin-top: 16px;
&:active {
background: #d1d5db;
}
}
</style>