1541 lines
41 KiB
Vue
1541 lines
41 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="regulations-division">
|
|||
|
|
<!-- 搜索筛选区域 -->
|
|||
|
|
<div class="search-area">
|
|||
|
|
<div class="search-item">
|
|||
|
|
<span class="label">预警标题</span>
|
|||
|
|
<el-input v-model="searchForm.title" placeholder="请输入" clearable />
|
|||
|
|
</div>
|
|||
|
|
<div class="search-item">
|
|||
|
|
<span class="label">预警类型</span>
|
|||
|
|
<el-select v-model="searchForm.type" placeholder="全部" clearable>
|
|||
|
|
<el-option
|
|||
|
|
v-for="item in typeOptions"
|
|||
|
|
:key="item.value"
|
|||
|
|
:label="item.label"
|
|||
|
|
:value="item.value"
|
|||
|
|
/>
|
|||
|
|
</el-select>
|
|||
|
|
</div>
|
|||
|
|
<div class="search-item">
|
|||
|
|
<span class="label">预警级别</span>
|
|||
|
|
<el-select v-model="searchForm.level" placeholder="全部" clearable>
|
|||
|
|
<el-option
|
|||
|
|
v-for="item in levelOptions"
|
|||
|
|
:key="item.value"
|
|||
|
|
:label="item.label"
|
|||
|
|
:value="item.value"
|
|||
|
|
/>
|
|||
|
|
</el-select>
|
|||
|
|
</div>
|
|||
|
|
<div class="search-item">
|
|||
|
|
<span class="label">响应情况</span>
|
|||
|
|
<el-select v-model="searchForm.response" placeholder="全部" clearable>
|
|||
|
|
<el-option
|
|||
|
|
v-for="item in responseOptions"
|
|||
|
|
:key="item.value"
|
|||
|
|
:label="item.label"
|
|||
|
|
:value="item.value"
|
|||
|
|
/>
|
|||
|
|
</el-select>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 操作按钮区域 -->
|
|||
|
|
<div class="action-area">
|
|||
|
|
<el-button
|
|||
|
|
v-for="btn in actionButtons"
|
|||
|
|
:key="btn.key"
|
|||
|
|
:type="btn.type"
|
|||
|
|
:class="btn.class"
|
|||
|
|
@click="handleAction(btn.key)"
|
|||
|
|
>
|
|||
|
|
{{ btn.label }}
|
|||
|
|
</el-button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 数据表格 -->
|
|||
|
|
<div class="table-area">
|
|||
|
|
<el-table
|
|||
|
|
:data="tableData"
|
|||
|
|
stripe
|
|||
|
|
style="width: 100%"
|
|||
|
|
:header-cell-style="headerCellStyle"
|
|||
|
|
>
|
|||
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|||
|
|
<el-table-column
|
|||
|
|
prop="title"
|
|||
|
|
label="预警标题"
|
|||
|
|
min-width="200"
|
|||
|
|
show-overflow-tooltip
|
|||
|
|
/>
|
|||
|
|
<el-table-column prop="type" label="预警类型" width="100" align="center">
|
|||
|
|
<template #default="{ row }">
|
|||
|
|
<span :class="getTypeClass(row.type)">{{ row.type }}</span>
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
<el-table-column prop="sendTime" label="发送时间" width="160" align="center" />
|
|||
|
|
<el-table-column prop="effectTime" label="生效时间" width="160" align="center" />
|
|||
|
|
<el-table-column prop="receiveTime" label="接收时间" width="160" align="center" />
|
|||
|
|
<el-table-column
|
|||
|
|
prop="forwardTime"
|
|||
|
|
label="预警转发时间"
|
|||
|
|
width="160"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column prop="endTime" label="预警结束时间" width="160" align="center" />
|
|||
|
|
<el-table-column prop="affectRoad" label="影响路段" width="90" align="center" />
|
|||
|
|
<el-table-column prop="affectBridge" label="影响桥梁" width="90" align="center" />
|
|||
|
|
<el-table-column prop="affectTunnel" label="影响隧道" width="90" align="center" />
|
|||
|
|
<el-table-column prop="affectSlope" label="影响边坡" width="90" align="center" />
|
|||
|
|
<el-table-column prop="response" label="响应情况" width="90" align="center" />
|
|||
|
|
<el-table-column label="操作" width="80" align="center" fixed="right">
|
|||
|
|
<template #default="{ row }">
|
|||
|
|
<el-button link type="primary" size="small" @click="handleDetail(row)"
|
|||
|
|
>详情</el-button
|
|||
|
|
>
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
</el-table>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 分页 -->
|
|||
|
|
<div class="pagination-area">
|
|||
|
|
<el-pagination
|
|||
|
|
v-model:current-page="currentPage"
|
|||
|
|
v-model:page-size="pageSize"
|
|||
|
|
:page-sizes="[10, 20, 50, 100]"
|
|||
|
|
:total="total"
|
|||
|
|
layout="prev, pager, next, jumper"
|
|||
|
|
@size-change="handleSizeChange"
|
|||
|
|
@current-change="handleCurrentChange"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 生成报告对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="reportDialogVisible"
|
|||
|
|
title="生成报告"
|
|||
|
|
width="600px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
>
|
|||
|
|
<el-form :model="reportForm" label-width="100px">
|
|||
|
|
<el-form-item label="报告标题" required>
|
|||
|
|
<el-input v-model="reportForm.title" placeholder="请输入报告标题" />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="报告类型">
|
|||
|
|
<el-radio-group v-model="reportForm.type">
|
|||
|
|
<el-radio label="daily">日报</el-radio>
|
|||
|
|
<el-radio label="weekly">周报</el-radio>
|
|||
|
|
<el-radio label="monthly">月报</el-radio>
|
|||
|
|
</el-radio-group>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="报告内容">
|
|||
|
|
<el-input
|
|||
|
|
v-model="reportForm.content"
|
|||
|
|
type="textarea"
|
|||
|
|
:rows="4"
|
|||
|
|
placeholder="请输入报告内容"
|
|||
|
|
/>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
<template #footer>
|
|||
|
|
<el-button @click="reportDialogVisible = false">取消</el-button>
|
|||
|
|
<el-button type="primary" @click="confirmGenerateReport">确定</el-button>
|
|||
|
|
</template>
|
|||
|
|
</el-dialog>
|
|||
|
|
|
|||
|
|
<!-- 发布预警对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="publishDialogVisible"
|
|||
|
|
title="发布预警"
|
|||
|
|
width="700px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
class="publish-warning-dialog"
|
|||
|
|
>
|
|||
|
|
<div class="publish-warning-content">
|
|||
|
|
<!-- 上传按钮 -->
|
|||
|
|
<div class="upload-section">
|
|||
|
|
<el-button type="primary" class="upload-btn" @click="handleUploadWarning">
|
|||
|
|
上传
|
|||
|
|
</el-button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 气象信息 -->
|
|||
|
|
<div class="section-title">气象信息</div>
|
|||
|
|
|
|||
|
|
<el-form :model="publishForm" label-width="100px" class="publish-form">
|
|||
|
|
<!-- 预警时间 -->
|
|||
|
|
<el-form-item label="预警时间" class="time-item">
|
|||
|
|
<div class="time-range">
|
|||
|
|
<el-date-picker
|
|||
|
|
v-model="publishForm.startTime"
|
|||
|
|
type="datetime"
|
|||
|
|
placeholder="请选择开始时间"
|
|||
|
|
style="width: 48%"
|
|||
|
|
/>
|
|||
|
|
<span class="time-separator">-</span>
|
|||
|
|
<el-date-picker
|
|||
|
|
v-model="publishForm.endTime"
|
|||
|
|
type="datetime"
|
|||
|
|
placeholder="请选择结束时间"
|
|||
|
|
style="width: 48%"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
|
|||
|
|
<!-- 气象类型 -->
|
|||
|
|
<el-form-item label="气象类型">
|
|||
|
|
<el-select
|
|||
|
|
v-model="publishForm.weatherType"
|
|||
|
|
placeholder="请选择"
|
|||
|
|
style="width: 100%"
|
|||
|
|
>
|
|||
|
|
<el-option label="暴雨" value="rain" />
|
|||
|
|
<el-option label="大雾" value="fog" />
|
|||
|
|
<el-option label="冰雪" value="snow" />
|
|||
|
|
<el-option label="大风" value="wind" />
|
|||
|
|
<el-option label="高温" value="heat" />
|
|||
|
|
<el-option label="雷电" value="thunder" />
|
|||
|
|
</el-select>
|
|||
|
|
</el-form-item>
|
|||
|
|
|
|||
|
|
<!-- 预警等级 -->
|
|||
|
|
<el-form-item label="预警等级">
|
|||
|
|
<el-select
|
|||
|
|
v-model="publishForm.warningLevel"
|
|||
|
|
placeholder="请选择"
|
|||
|
|
style="width: 100%"
|
|||
|
|
>
|
|||
|
|
<el-option label="红色预警" value="red" />
|
|||
|
|
<el-option label="橙色预警" value="orange" />
|
|||
|
|
<el-option label="黄色预警" value="yellow" />
|
|||
|
|
<el-option label="蓝色预警" value="blue" />
|
|||
|
|
</el-select>
|
|||
|
|
</el-form-item>
|
|||
|
|
|
|||
|
|
<!-- 风险区县 -->
|
|||
|
|
<el-form-item label="风险区县" class="district-item">
|
|||
|
|
<div class="district-header">
|
|||
|
|
<span>已选择:{{ selectedDistricts.length }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="district-tags">
|
|||
|
|
<el-button
|
|||
|
|
v-for="district in districtOptions"
|
|||
|
|
:key="district.value"
|
|||
|
|
:class="[
|
|||
|
|
'district-btn',
|
|||
|
|
{ active: selectedDistricts.includes(district.value) },
|
|||
|
|
]"
|
|||
|
|
@click="toggleDistrict(district.value)"
|
|||
|
|
>
|
|||
|
|
{{ district.label }}
|
|||
|
|
</el-button>
|
|||
|
|
</div>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
</div>
|
|||
|
|
<template #footer>
|
|||
|
|
<el-button type="primary" @click="confirmPublishWarning">确认</el-button>
|
|||
|
|
<el-button @click="publishDialogVisible = false">取消</el-button>
|
|||
|
|
</template>
|
|||
|
|
</el-dialog>
|
|||
|
|
|
|||
|
|
<!-- 上传统计帮扶对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="uploadDialogVisible"
|
|||
|
|
title="上传统计帮扶数据"
|
|||
|
|
width="500px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
>
|
|||
|
|
<el-form :model="uploadForm" label-width="100px">
|
|||
|
|
<el-form-item label="选择文件" required>
|
|||
|
|
<el-upload
|
|||
|
|
class="upload-demo"
|
|||
|
|
drag
|
|||
|
|
action="#"
|
|||
|
|
:auto-upload="false"
|
|||
|
|
:before-upload="beforeUpload"
|
|||
|
|
:on-success="(res, file) => handleUploadSuccess(res, file, 'upload')"
|
|||
|
|
:on-error="handleUploadError"
|
|||
|
|
accept=".xls,.xlsx"
|
|||
|
|
>
|
|||
|
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
|||
|
|
<div class="el-upload__text">拖拽文件到此处或 <em>点击上传</em></div>
|
|||
|
|
<template #tip>
|
|||
|
|
<div class="el-upload__tip">只能上传Excel文件,且不超过10MB</div>
|
|||
|
|
</template>
|
|||
|
|
</el-upload>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="文件说明">
|
|||
|
|
<el-input
|
|||
|
|
v-model="uploadForm.description"
|
|||
|
|
type="textarea"
|
|||
|
|
:rows="3"
|
|||
|
|
placeholder="请输入文件说明"
|
|||
|
|
/>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
<template #footer>
|
|||
|
|
<el-button @click="uploadDialogVisible = false">取消</el-button>
|
|||
|
|
<el-button type="primary" @click="confirmUpload">上传</el-button>
|
|||
|
|
</template>
|
|||
|
|
</el-dialog>
|
|||
|
|
|
|||
|
|
<!-- 上传抽查人次对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="uploadPersonDialogVisible"
|
|||
|
|
title="上传抽查人次数据"
|
|||
|
|
width="500px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
>
|
|||
|
|
<el-form :model="uploadPersonForm" label-width="100px">
|
|||
|
|
<el-form-item label="选择文件" required>
|
|||
|
|
<el-upload
|
|||
|
|
class="upload-demo"
|
|||
|
|
drag
|
|||
|
|
action="#"
|
|||
|
|
:auto-upload="false"
|
|||
|
|
:before-upload="beforeUpload"
|
|||
|
|
:on-success="(res, file) => handleUploadSuccess(res, file, 'uploadPerson')"
|
|||
|
|
:on-error="handleUploadError"
|
|||
|
|
accept=".xls,.xlsx"
|
|||
|
|
>
|
|||
|
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
|||
|
|
<div class="el-upload__text">拖拽文件到此处或 <em>点击上传</em></div>
|
|||
|
|
<template #tip>
|
|||
|
|
<div class="el-upload__tip">只能上传Excel文件,且不超过10MB</div>
|
|||
|
|
</template>
|
|||
|
|
</el-upload>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="抽查日期" required>
|
|||
|
|
<el-date-picker
|
|||
|
|
v-model="uploadPersonForm.date"
|
|||
|
|
type="date"
|
|||
|
|
placeholder="选择日期"
|
|||
|
|
style="width: 100%"
|
|||
|
|
/>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="抽查人次">
|
|||
|
|
<el-input-number
|
|||
|
|
v-model="uploadPersonForm.count"
|
|||
|
|
:min="0"
|
|||
|
|
style="width: 100%"
|
|||
|
|
/>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
<template #footer>
|
|||
|
|
<el-button @click="uploadPersonDialogVisible = false">取消</el-button>
|
|||
|
|
<el-button type="primary" @click="confirmUploadPerson">上传</el-button>
|
|||
|
|
</template>
|
|||
|
|
</el-dialog>
|
|||
|
|
|
|||
|
|
<!-- 详情对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="detailDialogVisible"
|
|||
|
|
title="预警详情"
|
|||
|
|
width="1200px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
class="warning-detail-dialog"
|
|||
|
|
:show-close="true"
|
|||
|
|
>
|
|||
|
|
<div class="detail-content" v-if="currentRow" style="overflow: visible;">
|
|||
|
|
<!-- 基本信息 -->
|
|||
|
|
<div class="detail-section">
|
|||
|
|
<div class="section-title">基本信息</div>
|
|||
|
|
<div class="basic-info-box">
|
|||
|
|
<div class="info-row">
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">预警标题:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.title }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">预警类型:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.type }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">发送时间:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.sendTime }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-row">
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">生效时间:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.effectTime }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">接收时间:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.receiveTime }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">预警转发时间:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.forwardTime }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-row">
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">预警结束时间:</span>
|
|||
|
|
<span class="info-value">{{ currentRow.endTime || "-" }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-row full-width">
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">预警描述:</span>
|
|||
|
|
<span class="info-value">{{
|
|||
|
|
currentRow.description ||
|
|||
|
|
'重庆市气象台2026年1月19日21时00分发布"道路结冰黄色预警信号",预计1月19日21:00-20日9:00,丰都、万州、开州、城口、云阳、奉节、巫溪、巫山、武隆、彭水、石柱、黔江、酉阳、秀山等14个区县海拔800米以上的地区路表温度将低于0℃,并伴有降水,可能出现对交通有影响的道路结冰。'
|
|||
|
|
}}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="info-row full-width">
|
|||
|
|
<div class="info-item">
|
|||
|
|
<span class="info-label">响应措施:</span>
|
|||
|
|
<span class="info-value">{{
|
|||
|
|
currentRow.responseMeasures ||
|
|||
|
|
"立即启动防汛Ⅰ级应急响应,立即转移危险区群众,医疗机构做好应急准备"
|
|||
|
|
}}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 影响情况 -->
|
|||
|
|
<div class="detail-section">
|
|||
|
|
<div class="section-title">影响情况</div>
|
|||
|
|
<div class="filter-bar">
|
|||
|
|
<div class="filter-item">
|
|||
|
|
<span class="filter-label">驻地名称</span>
|
|||
|
|
<el-input
|
|||
|
|
v-model="detailFilter.stationName"
|
|||
|
|
placeholder=""
|
|||
|
|
style="width: 120px"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
<div class="filter-item">
|
|||
|
|
<span class="filter-label">响应情况</span>
|
|||
|
|
<el-select
|
|||
|
|
v-model="detailFilter.responseStatus"
|
|||
|
|
placeholder="全部"
|
|||
|
|
style="width: 100px"
|
|||
|
|
>
|
|||
|
|
<el-option label="全部" value="" />
|
|||
|
|
<el-option label="已响应" value="responded" />
|
|||
|
|
<el-option label="未响应" value="unresponded" />
|
|||
|
|
</el-select>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="table-wrapper">
|
|||
|
|
<el-table
|
|||
|
|
:data="filteredDetailData"
|
|||
|
|
style="width: 100%"
|
|||
|
|
:header-cell-style="detailHeaderCellStyle"
|
|||
|
|
:cell-style="detailCellStyle"
|
|||
|
|
stripe
|
|||
|
|
>
|
|||
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|||
|
|
<el-table-column
|
|||
|
|
prop="district"
|
|||
|
|
label="所属区县"
|
|||
|
|
width="100"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="roadCode"
|
|||
|
|
label="公路编号"
|
|||
|
|
width="100"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="startStake"
|
|||
|
|
label="起点桩号"
|
|||
|
|
width="100"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="endStake"
|
|||
|
|
label="止点桩号"
|
|||
|
|
width="100"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="affectType"
|
|||
|
|
label="影响类型"
|
|||
|
|
width="100"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="location"
|
|||
|
|
label="位置"
|
|||
|
|
min-width="200"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="responseTime"
|
|||
|
|
label="最新响应时间"
|
|||
|
|
width="160"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="urgeTime"
|
|||
|
|
label="最近催告时间"
|
|||
|
|
width="160"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
<el-table-column
|
|||
|
|
prop="trafficDept"
|
|||
|
|
label="交通部门负责人"
|
|||
|
|
width="120"
|
|||
|
|
align="center"
|
|||
|
|
/>
|
|||
|
|
</el-table>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</el-dialog>
|
|||
|
|
|
|||
|
|
<!-- 导出配置对话框 -->
|
|||
|
|
<el-dialog
|
|||
|
|
v-model="exportDialogVisible"
|
|||
|
|
title="导出数据"
|
|||
|
|
width="600px"
|
|||
|
|
:close-on-click-modal="false"
|
|||
|
|
>
|
|||
|
|
<el-form :model="exportConfig" label-width="100px">
|
|||
|
|
<el-form-item label="文件名">
|
|||
|
|
<el-input v-model="exportConfig.filename" placeholder="请输入文件名" />
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="导出格式">
|
|||
|
|
<el-radio-group v-model="exportConfig.format">
|
|||
|
|
<el-radio label="csv">CSV</el-radio>
|
|||
|
|
<el-radio label="excel">Excel</el-radio>
|
|||
|
|
<el-radio label="json">JSON</el-radio>
|
|||
|
|
</el-radio-group>
|
|||
|
|
</el-form-item>
|
|||
|
|
<el-form-item label="选择列">
|
|||
|
|
<el-checkbox-group v-model="exportConfig.selectedColumns">
|
|||
|
|
<el-checkbox v-for="col in exportColumns" :key="col.key" :label="col.key">
|
|||
|
|
{{ col.label }}
|
|||
|
|
</el-checkbox>
|
|||
|
|
</el-checkbox-group>
|
|||
|
|
</el-form-item>
|
|||
|
|
</el-form>
|
|||
|
|
<template #footer>
|
|||
|
|
<el-button @click="exportDialogVisible = false">取消</el-button>
|
|||
|
|
<el-button type="primary" @click="confirmExport">导出</el-button>
|
|||
|
|
</template>
|
|||
|
|
</el-dialog>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, reactive, onMounted, onUnmounted, watch, computed } from "vue";
|
|||
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|||
|
|
import { UploadFilled } from "@element-plus/icons-vue";
|
|||
|
|
|
|||
|
|
// 搜索表单
|
|||
|
|
const searchForm = reactive({
|
|||
|
|
title: "",
|
|||
|
|
type: "",
|
|||
|
|
level: "",
|
|||
|
|
response: "",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 对话框显示状态
|
|||
|
|
const reportDialogVisible = ref(false);
|
|||
|
|
const publishDialogVisible = ref(false);
|
|||
|
|
const uploadDialogVisible = ref(false);
|
|||
|
|
const uploadPersonDialogVisible = ref(false);
|
|||
|
|
const detailDialogVisible = ref(false);
|
|||
|
|
const exportDialogVisible = ref(false);
|
|||
|
|
|
|||
|
|
// 当前选中的行数据
|
|||
|
|
const currentRow = ref({});
|
|||
|
|
|
|||
|
|
// 导出配置
|
|||
|
|
const exportConfig = reactive({
|
|||
|
|
format: "csv",
|
|||
|
|
filename: "",
|
|||
|
|
selectedColumns: [
|
|||
|
|
"index",
|
|||
|
|
"title",
|
|||
|
|
"type",
|
|||
|
|
"sendTime",
|
|||
|
|
"effectTime",
|
|||
|
|
"receiveTime",
|
|||
|
|
"forwardTime",
|
|||
|
|
"endTime",
|
|||
|
|
"affectRoad",
|
|||
|
|
"affectBridge",
|
|||
|
|
"affectTunnel",
|
|||
|
|
"affectSlope",
|
|||
|
|
"response",
|
|||
|
|
],
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 可选导出列
|
|||
|
|
const exportColumns = [
|
|||
|
|
{ key: "index", label: "序号" },
|
|||
|
|
{ key: "title", label: "预警标题" },
|
|||
|
|
{ key: "type", label: "预警类型" },
|
|||
|
|
{ key: "sendTime", label: "发送时间" },
|
|||
|
|
{ key: "effectTime", label: "生效时间" },
|
|||
|
|
{ key: "receiveTime", label: "接收时间" },
|
|||
|
|
{ key: "forwardTime", label: "预警转发时间" },
|
|||
|
|
{ key: "endTime", label: "预警结束时间" },
|
|||
|
|
{ key: "affectRoad", label: "影响路段" },
|
|||
|
|
{ key: "affectBridge", label: "影响桥梁" },
|
|||
|
|
{ key: "affectTunnel", label: "影响隧道" },
|
|||
|
|
{ key: "affectSlope", label: "影响边坡" },
|
|||
|
|
{ key: "response", label: "响应情况" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 生成报告表单
|
|||
|
|
const reportForm = reactive({
|
|||
|
|
title: "",
|
|||
|
|
content: "",
|
|||
|
|
type: "daily",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 发布预警表单
|
|||
|
|
const publishForm = reactive({
|
|||
|
|
title: "",
|
|||
|
|
type: "",
|
|||
|
|
level: "",
|
|||
|
|
content: "",
|
|||
|
|
affectArea: [],
|
|||
|
|
startTime: "",
|
|||
|
|
endTime: "",
|
|||
|
|
weatherType: "",
|
|||
|
|
warningLevel: "",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 区县选项
|
|||
|
|
const districtOptions = [
|
|||
|
|
{ label: "万州区", value: "wanzhou" },
|
|||
|
|
{ label: "合川区", value: "hechuan" },
|
|||
|
|
{ label: "北碚区", value: "beibei" },
|
|||
|
|
{ label: "涪陵区", value: "fuling" },
|
|||
|
|
{ label: "渝中区", value: "yuzhong" },
|
|||
|
|
{ label: "江北区", value: "jiangbei" },
|
|||
|
|
{ label: "沙坪坝区", value: "shapingba" },
|
|||
|
|
{ label: "九龙坡区", value: "jiulongpo" },
|
|||
|
|
{ label: "南岸区", value: "nanan" },
|
|||
|
|
{ label: "渝北区", value: "yubei" },
|
|||
|
|
{ label: "巴南区", value: "banan" },
|
|||
|
|
{ label: "长寿区", value: "changshou" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 选中的区县
|
|||
|
|
const selectedDistricts = ref([]);
|
|||
|
|
|
|||
|
|
// 切换区县选择
|
|||
|
|
const toggleDistrict = (value) => {
|
|||
|
|
const index = selectedDistricts.value.indexOf(value);
|
|||
|
|
if (index > -1) {
|
|||
|
|
selectedDistricts.value.splice(index, 1);
|
|||
|
|
} else {
|
|||
|
|
selectedDistricts.value.push(value);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 上传预警文件
|
|||
|
|
const handleUploadWarning = () => {
|
|||
|
|
ElMessage.info("请选择要上传的预警文件");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 上传表单
|
|||
|
|
const uploadForm = reactive({
|
|||
|
|
file: null,
|
|||
|
|
description: "",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 上传抽查人次表单
|
|||
|
|
const uploadPersonForm = reactive({
|
|||
|
|
file: null,
|
|||
|
|
date: "",
|
|||
|
|
count: 0,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 详情弹窗筛选条件
|
|||
|
|
const detailFilter = reactive({
|
|||
|
|
stationName: "",
|
|||
|
|
responseStatus: "",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 详情影响情况数据
|
|||
|
|
const detailTableData = ref([
|
|||
|
|
{
|
|||
|
|
district: "万州区",
|
|||
|
|
roadCode: "G542",
|
|||
|
|
startStake: "K533+900",
|
|||
|
|
endStake: "K534+500",
|
|||
|
|
affectType: "路段",
|
|||
|
|
location: "广元-万州(K533+900至K534+500)",
|
|||
|
|
responseTime: "2026-01-20 21:39:53",
|
|||
|
|
urgeTime: "-",
|
|||
|
|
trafficDept: "张三",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
district: "涪陵区",
|
|||
|
|
roadCode: "G319",
|
|||
|
|
startStake: "K2380+130",
|
|||
|
|
endStake: "K2380+130",
|
|||
|
|
affectType: "边坡",
|
|||
|
|
location: "高雄-成都(K2380+130至K2380+130)",
|
|||
|
|
responseTime: "2026-01-20 21:39:53",
|
|||
|
|
urgeTime: "2026-01-20 21:39:53",
|
|||
|
|
trafficDept: "李四",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
district: "云阳县",
|
|||
|
|
roadCode: "G347",
|
|||
|
|
startStake: "K1661+450",
|
|||
|
|
endStake: "K1661+450",
|
|||
|
|
affectType: "桥梁",
|
|||
|
|
location: "南京-德令哈(K1661+450至K1661+450)",
|
|||
|
|
responseTime: "-",
|
|||
|
|
urgeTime: "2026-01-20 21:39:53",
|
|||
|
|
trafficDept: "王五",
|
|||
|
|
},
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 过滤后的详情数据
|
|||
|
|
const filteredDetailData = computed(() => {
|
|||
|
|
return detailTableData.value.filter((item) => {
|
|||
|
|
const matchStation =
|
|||
|
|
!detailFilter.stationName ||
|
|||
|
|
item.district.includes(detailFilter.stationName) ||
|
|||
|
|
item.location.includes(detailFilter.stationName);
|
|||
|
|
const matchResponse =
|
|||
|
|
!detailFilter.responseStatus ||
|
|||
|
|
(detailFilter.responseStatus === "responded" && item.responseTime !== "-") ||
|
|||
|
|
(detailFilter.responseStatus === "unresponded" && item.responseTime === "-");
|
|||
|
|
return matchStation && matchResponse;
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 详情表格表头样式
|
|||
|
|
const detailHeaderCellStyle = () => ({
|
|||
|
|
background: "#f5f7fa",
|
|||
|
|
color: "#303133",
|
|||
|
|
fontWeight: "bold",
|
|||
|
|
fontSize: "14px",
|
|||
|
|
padding: "12px 0",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 详情表格单元格样式
|
|||
|
|
const detailCellStyle = () => ({
|
|||
|
|
padding: "10px 0",
|
|||
|
|
fontSize: "13px",
|
|||
|
|
color: "#606266",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 预警类型选项
|
|||
|
|
const typeOptions = [
|
|||
|
|
{ label: "大雾预警", value: "fog" },
|
|||
|
|
{ label: "暴雨预警", value: "rain" },
|
|||
|
|
{ label: "冰雪预警", value: "snow" },
|
|||
|
|
{ label: "大风预警", value: "wind" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 预警级别选项
|
|||
|
|
const levelOptions = [
|
|||
|
|
{ label: "红色预警", value: "red" },
|
|||
|
|
{ label: "橙色预警", value: "orange" },
|
|||
|
|
{ label: "黄色预警", value: "yellow" },
|
|||
|
|
{ label: "蓝色预警", value: "blue" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 响应情况选项
|
|||
|
|
const responseOptions = [
|
|||
|
|
{ label: "已响应", value: "responded" },
|
|||
|
|
{ label: "未响应", value: "unresponded" },
|
|||
|
|
{ label: "响应中", value: "responding" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 操作按钮数据
|
|||
|
|
const actionButtons = [
|
|||
|
|
{ key: "generate", label: "生成报告", type: "primary", class: "btn-generate" },
|
|||
|
|
{ key: "publish", label: "发布预警", type: "primary", class: "btn-publish" },
|
|||
|
|
{ key: "upload", label: "上传统计帮扶", type: "primary", class: "btn-upload" },
|
|||
|
|
{
|
|||
|
|
key: "uploadPerson",
|
|||
|
|
label: "上传抽查人次",
|
|||
|
|
type: "primary",
|
|||
|
|
class: "btn-upload-person",
|
|||
|
|
},
|
|||
|
|
{ key: "export", label: "导出", type: "success", class: "btn-export" },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 表格数据
|
|||
|
|
const tableData = ref([
|
|||
|
|
{
|
|||
|
|
title: "重庆市忠县气象台发布大雾黄色预警[III级/较重]",
|
|||
|
|
type: "大雾预警",
|
|||
|
|
sendTime: "2026-03-10 16:50:02",
|
|||
|
|
effectTime: "2026-03-10 16:50:02",
|
|||
|
|
receiveTime: "2026-03-10 16:50:02",
|
|||
|
|
forwardTime: "2026-03-10 16:50:02",
|
|||
|
|
endTime: "-",
|
|||
|
|
affectRoad: "2",
|
|||
|
|
affectBridge: "3",
|
|||
|
|
affectTunnel: "2",
|
|||
|
|
affectSlope: "1",
|
|||
|
|
response: "1/2",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "重庆市忠县气象台发布大雾黄色预警[III级/较重]",
|
|||
|
|
type: "大雾预警",
|
|||
|
|
sendTime: "2026-03-10 16:50:02",
|
|||
|
|
effectTime: "2026-03-10 16:50:02",
|
|||
|
|
receiveTime: "2026-03-10 16:50:02",
|
|||
|
|
forwardTime: "2026-03-10 16:50:02",
|
|||
|
|
endTime: "-",
|
|||
|
|
affectRoad: "2",
|
|||
|
|
affectBridge: "3",
|
|||
|
|
affectTunnel: "2",
|
|||
|
|
affectSlope: "1",
|
|||
|
|
response: "1/2",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "重庆市忠县气象台发布大雾黄色预警[III级/较重]",
|
|||
|
|
type: "大雾预警",
|
|||
|
|
sendTime: "2026-03-10 16:50:02",
|
|||
|
|
effectTime: "2026-03-10 16:50:02",
|
|||
|
|
receiveTime: "2026-03-10 16:50:02",
|
|||
|
|
forwardTime: "2026-03-10 16:50:02",
|
|||
|
|
endTime: "-",
|
|||
|
|
affectRoad: "2",
|
|||
|
|
affectBridge: "3",
|
|||
|
|
affectTunnel: "2",
|
|||
|
|
affectSlope: "1",
|
|||
|
|
response: "1/2",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "重庆市忠县气象台发布大雾黄色预警[III级/较重]",
|
|||
|
|
type: "大雾预警",
|
|||
|
|
sendTime: "2026-03-10 16:50:02",
|
|||
|
|
effectTime: "2026-03-10 16:50:02",
|
|||
|
|
receiveTime: "2026-03-10 16:50:02",
|
|||
|
|
forwardTime: "2026-03-10 16:50:02",
|
|||
|
|
endTime: "-",
|
|||
|
|
affectRoad: "2",
|
|||
|
|
affectBridge: "3",
|
|||
|
|
affectTunnel: "2",
|
|||
|
|
affectSlope: "1",
|
|||
|
|
response: "1/2",
|
|||
|
|
},
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
// 分页
|
|||
|
|
const currentPage = ref(1);
|
|||
|
|
const pageSize = ref(10);
|
|||
|
|
const total = ref(100);
|
|||
|
|
|
|||
|
|
// 表头样式
|
|||
|
|
const headerCellStyle = () => ({
|
|||
|
|
background: "#f5f7fa",
|
|||
|
|
color: "#606266",
|
|||
|
|
fontWeight: "bold",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 获取预警类型样式类
|
|||
|
|
const getTypeClass = (type) => {
|
|||
|
|
const classMap = {
|
|||
|
|
大雾预警: "type-fog",
|
|||
|
|
暴雨预警: "type-rain",
|
|||
|
|
冰雪预警: "type-snow",
|
|||
|
|
大风预警: "type-wind",
|
|||
|
|
};
|
|||
|
|
return classMap[type] || "";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取标签类型
|
|||
|
|
const getTagType = (type) => {
|
|||
|
|
const typeMap = {
|
|||
|
|
大雾预警: "warning",
|
|||
|
|
暴雨预警: "primary",
|
|||
|
|
冰雪预警: "info",
|
|||
|
|
大风预警: "success",
|
|||
|
|
};
|
|||
|
|
return typeMap[type] || "";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出单条数据
|
|||
|
|
const handleExportSingle = () => {
|
|||
|
|
if (!currentRow.value) return;
|
|||
|
|
|
|||
|
|
const data = [currentRow.value];
|
|||
|
|
const headers = [
|
|||
|
|
"预警标题",
|
|||
|
|
"预警类型",
|
|||
|
|
"发送时间",
|
|||
|
|
"生效时间",
|
|||
|
|
"接收时间",
|
|||
|
|
"预警转发时间",
|
|||
|
|
"预警结束时间",
|
|||
|
|
"影响路段",
|
|||
|
|
"影响桥梁",
|
|||
|
|
"影响隧道",
|
|||
|
|
"影响边坡",
|
|||
|
|
"响应情况",
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const rows = data.map((item) => [
|
|||
|
|
item.title,
|
|||
|
|
item.type,
|
|||
|
|
item.sendTime,
|
|||
|
|
item.effectTime,
|
|||
|
|
item.receiveTime,
|
|||
|
|
item.forwardTime,
|
|||
|
|
item.endTime,
|
|||
|
|
item.affectRoad,
|
|||
|
|
item.affectBridge,
|
|||
|
|
item.affectTunnel,
|
|||
|
|
item.affectSlope,
|
|||
|
|
item.response,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
const csvContent = [headers.join(","), ...rows.map((row) => row.join(","))].join("\n");
|
|||
|
|
|
|||
|
|
const blob = new Blob(["\ufeff" + csvContent], { type: "text/csv;charset=utf-8;" });
|
|||
|
|
const link = document.createElement("a");
|
|||
|
|
link.href = URL.createObjectURL(blob);
|
|||
|
|
link.download = `预警详情_${new Date().toLocaleDateString()}.csv`;
|
|||
|
|
link.click();
|
|||
|
|
|
|||
|
|
ElMessage.success("导出成功");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 操作按钮点击
|
|||
|
|
const handleAction = (key) => {
|
|||
|
|
switch (key) {
|
|||
|
|
case "generate":
|
|||
|
|
handleGenerateReport();
|
|||
|
|
break;
|
|||
|
|
case "publish":
|
|||
|
|
handlePublishWarning();
|
|||
|
|
break;
|
|||
|
|
case "upload":
|
|||
|
|
handleUpload();
|
|||
|
|
break;
|
|||
|
|
case "uploadPerson":
|
|||
|
|
handleUploadPerson();
|
|||
|
|
break;
|
|||
|
|
case "export":
|
|||
|
|
handleExport();
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
console.log("未知操作:", key);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 生成报告
|
|||
|
|
const handleGenerateReport = () => {
|
|||
|
|
reportDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 确认生成报告
|
|||
|
|
const confirmGenerateReport = () => {
|
|||
|
|
if (!reportForm.title) {
|
|||
|
|
ElMessage.warning("请输入报告标题");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 模拟生成报告
|
|||
|
|
setTimeout(() => {
|
|||
|
|
ElMessage.success("报告生成成功");
|
|||
|
|
reportDialogVisible.value = false;
|
|||
|
|
// 重置表单
|
|||
|
|
reportForm.title = "";
|
|||
|
|
reportForm.content = "";
|
|||
|
|
reportForm.type = "daily";
|
|||
|
|
}, 500);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 发布预警
|
|||
|
|
const handlePublishWarning = () => {
|
|||
|
|
publishDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 新发布预警确认
|
|||
|
|
const handleNewPublishConfirm = (data) => {
|
|||
|
|
console.log("发布预警数据:", data);
|
|||
|
|
ElMessage.success("预警发布成功");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 确认发布预警
|
|||
|
|
const confirmPublishWarning = () => {
|
|||
|
|
if (!publishForm.title) {
|
|||
|
|
ElMessage.warning("请输入预警标题");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!publishForm.type) {
|
|||
|
|
ElMessage.warning("请选择预警类型");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!publishForm.level) {
|
|||
|
|
ElMessage.warning("请选择预警级别");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 模拟发布预警
|
|||
|
|
setTimeout(() => {
|
|||
|
|
ElMessage.success("预警发布成功");
|
|||
|
|
publishDialogVisible.value = false;
|
|||
|
|
// 重置表单
|
|||
|
|
publishForm.title = "";
|
|||
|
|
publishForm.type = "";
|
|||
|
|
publishForm.level = "";
|
|||
|
|
publishForm.content = "";
|
|||
|
|
publishForm.affectArea = [];
|
|||
|
|
}, 500);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 上传统计帮扶
|
|||
|
|
const handleUpload = () => {
|
|||
|
|
uploadDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 确认上传
|
|||
|
|
const confirmUpload = () => {
|
|||
|
|
if (!uploadForm.file) {
|
|||
|
|
ElMessage.warning("请选择要上传的文件");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 模拟上传
|
|||
|
|
setTimeout(() => {
|
|||
|
|
ElMessage.success("文件上传成功");
|
|||
|
|
uploadDialogVisible.value = false;
|
|||
|
|
// 重置表单
|
|||
|
|
uploadForm.file = null;
|
|||
|
|
uploadForm.description = "";
|
|||
|
|
}, 500);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 上传抽查人次
|
|||
|
|
const handleUploadPerson = () => {
|
|||
|
|
uploadPersonDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 确认上传抽查人次
|
|||
|
|
const confirmUploadPerson = () => {
|
|||
|
|
if (!uploadPersonForm.file) {
|
|||
|
|
ElMessage.warning("请选择要上传的文件");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!uploadPersonForm.date) {
|
|||
|
|
ElMessage.warning("请选择日期");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 模拟上传
|
|||
|
|
setTimeout(() => {
|
|||
|
|
ElMessage.success("抽查人次上传成功");
|
|||
|
|
uploadPersonDialogVisible.value = false;
|
|||
|
|
// 重置表单
|
|||
|
|
uploadPersonForm.file = null;
|
|||
|
|
uploadPersonForm.date = "";
|
|||
|
|
uploadPersonForm.count = 0;
|
|||
|
|
}, 500);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出数据
|
|||
|
|
const handleExport = () => {
|
|||
|
|
// 设置默认文件名
|
|||
|
|
exportConfig.filename = `预警数据_${new Date().toLocaleDateString()}`;
|
|||
|
|
exportDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 确认导出
|
|||
|
|
const confirmExport = () => {
|
|||
|
|
if (exportConfig.selectedColumns.length === 0) {
|
|||
|
|
ElMessage.warning("请至少选择一列数据");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 根据格式导出
|
|||
|
|
switch (exportConfig.format) {
|
|||
|
|
case "csv":
|
|||
|
|
exportToCSV();
|
|||
|
|
break;
|
|||
|
|
case "excel":
|
|||
|
|
exportToExcel();
|
|||
|
|
break;
|
|||
|
|
case "json":
|
|||
|
|
exportToJSON();
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
exportToCSV();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
exportDialogVisible.value = false;
|
|||
|
|
ElMessage.success("数据导出成功");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取导出列的标题
|
|||
|
|
const getExportHeaders = () => {
|
|||
|
|
return exportConfig.selectedColumns.map((key) => {
|
|||
|
|
const column = exportColumns.find((col) => col.key === key);
|
|||
|
|
return column ? column.label : key;
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 获取导出数据行
|
|||
|
|
const getExportRows = () => {
|
|||
|
|
return tableData.value.map((item, index) => {
|
|||
|
|
const row = {};
|
|||
|
|
exportConfig.selectedColumns.forEach((key) => {
|
|||
|
|
if (key === "index") {
|
|||
|
|
row[key] = index + 1;
|
|||
|
|
} else {
|
|||
|
|
row[key] = item[key] || "";
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return row;
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出为CSV
|
|||
|
|
const exportToCSV = () => {
|
|||
|
|
const headers = getExportHeaders();
|
|||
|
|
const rows = getExportRows();
|
|||
|
|
|
|||
|
|
const csvRows = rows.map((row) =>
|
|||
|
|
exportConfig.selectedColumns.map((key) => `"${row[key]}"`).join(",")
|
|||
|
|
);
|
|||
|
|
const csvContent = [headers.join(","), ...csvRows].join("\n");
|
|||
|
|
|
|||
|
|
const blob = new Blob(["\ufeff" + csvContent], { type: "text/csv;charset=utf-8;" });
|
|||
|
|
const link = document.createElement("a");
|
|||
|
|
link.href = URL.createObjectURL(blob);
|
|||
|
|
link.download = `${exportConfig.filename}.csv`;
|
|||
|
|
link.click();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出为Excel (使用CSV格式模拟,实际项目中可以使用xlsx库)
|
|||
|
|
const exportToExcel = () => {
|
|||
|
|
// 这里使用CSV格式作为Excel的替代
|
|||
|
|
// 实际项目中可以引入 xlsx 库来生成真正的Excel文件
|
|||
|
|
exportToCSV();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 导出为JSON
|
|||
|
|
const exportToJSON = () => {
|
|||
|
|
const data = getExportRows();
|
|||
|
|
const jsonContent = JSON.stringify(data, null, 2);
|
|||
|
|
const blob = new Blob([jsonContent], { type: "application/json;charset=utf-8;" });
|
|||
|
|
const link = document.createElement("a");
|
|||
|
|
link.href = URL.createObjectURL(blob);
|
|||
|
|
link.download = `${exportConfig.filename}.json`;
|
|||
|
|
link.click();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 查看详情
|
|||
|
|
const handleDetail = (row) => {
|
|||
|
|
currentRow.value = { ...row };
|
|||
|
|
detailDialogVisible.value = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 文件上传前处理
|
|||
|
|
const beforeUpload = (file) => {
|
|||
|
|
const isExcel =
|
|||
|
|
file.type === "application/vnd.ms-excel" ||
|
|||
|
|
file.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|||
|
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
|||
|
|
|
|||
|
|
if (!isExcel) {
|
|||
|
|
ElMessage.error("只能上传Excel文件!");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
if (!isLt10M) {
|
|||
|
|
ElMessage.error("文件大小不能超过10MB!");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 文件上传成功
|
|||
|
|
const handleUploadSuccess = (response, file, formType) => {
|
|||
|
|
if (formType === "upload") {
|
|||
|
|
uploadForm.file = file;
|
|||
|
|
} else if (formType === "uploadPerson") {
|
|||
|
|
uploadPersonForm.file = file;
|
|||
|
|
}
|
|||
|
|
ElMessage.success(`${file.name} 上传成功`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 文件上传失败
|
|||
|
|
const handleUploadError = (error, file) => {
|
|||
|
|
ElMessage.error(`${file.name} 上传失败`);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 分页大小改变
|
|||
|
|
const handleSizeChange = (val) => {
|
|||
|
|
console.log("每页条数:", val);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 页码改变
|
|||
|
|
const handleCurrentChange = (val) => {
|
|||
|
|
console.log("当前页:", val);
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.regulations-division {
|
|||
|
|
padding: 20px;
|
|||
|
|
background: #fff;
|
|||
|
|
min-height: 100vh;
|
|||
|
|
|
|||
|
|
// 搜索区域
|
|||
|
|
.search-area {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 20px;
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
|
|||
|
|
.search-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
|
|||
|
|
.label {
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #606266;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
:deep(.el-input) {
|
|||
|
|
width: 180px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
:deep(.el-select) {
|
|||
|
|
width: 140px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 操作按钮区域
|
|||
|
|
.action-area {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 10px;
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
.el-button {
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-generate {
|
|||
|
|
background: #409eff;
|
|||
|
|
border-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-publish {
|
|||
|
|
background: #409eff;
|
|||
|
|
border-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-upload {
|
|||
|
|
background: #409eff;
|
|||
|
|
border-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-upload-person {
|
|||
|
|
background: #409eff;
|
|||
|
|
border-color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-export {
|
|||
|
|
background: #67c23a;
|
|||
|
|
border-color: #67c23a;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 表格区域
|
|||
|
|
.table-area {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
:deep(.el-table) {
|
|||
|
|
border: 1px solid #ebeef5;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
|
|||
|
|
.el-table__header-wrapper {
|
|||
|
|
th {
|
|||
|
|
background: #f5f7fa;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 斑马纹样式
|
|||
|
|
.el-table__row--striped {
|
|||
|
|
background: #fafafa;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 预警类型样式
|
|||
|
|
.type-fog {
|
|||
|
|
color: #e6a23c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.type-rain {
|
|||
|
|
color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.type-snow {
|
|||
|
|
color: #909399;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.type-wind {
|
|||
|
|
color: #67c23a;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发布预警弹窗样式
|
|||
|
|
:deep(.publish-warning-dialog) {
|
|||
|
|
.el-dialog__header {
|
|||
|
|
text-align: center;
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 18px;
|
|||
|
|
padding-bottom: 10px;
|
|||
|
|
border-bottom: 1px solid #e4e7ed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.el-dialog__body {
|
|||
|
|
padding: 20px 30px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.publish-warning-content {
|
|||
|
|
.upload-section {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
.upload-btn {
|
|||
|
|
width: 100px;
|
|||
|
|
height: 36px;
|
|||
|
|
background: #409eff;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-title {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #303133;
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
padding-left: 10px;
|
|||
|
|
border-left: 4px solid #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.publish-form {
|
|||
|
|
.el-form-item {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
.el-form-item__label {
|
|||
|
|
color: #606266;
|
|||
|
|
font-weight: normal;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.time-item {
|
|||
|
|
.time-range {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 10px;
|
|||
|
|
|
|||
|
|
.time-separator {
|
|||
|
|
color: #909399;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.district-item {
|
|||
|
|
.district-header {
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
color: #606266;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.district-tags {
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
gap: 10px;
|
|||
|
|
|
|||
|
|
.district-btn {
|
|||
|
|
min-width: 80px;
|
|||
|
|
height: 32px;
|
|||
|
|
padding: 0 15px;
|
|||
|
|
border: 1px solid #dcdfe6;
|
|||
|
|
background: #fff;
|
|||
|
|
color: #606266;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
transition: all 0.3s;
|
|||
|
|
|
|||
|
|
&:hover {
|
|||
|
|
border-color: #409eff;
|
|||
|
|
color: #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.active {
|
|||
|
|
background: #409eff;
|
|||
|
|
border-color: #409eff;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.el-dialog__footer {
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 15px 20px 20px;
|
|||
|
|
border-top: 1px solid #e4e7ed;
|
|||
|
|
|
|||
|
|
.el-button {
|
|||
|
|
min-width: 100px;
|
|||
|
|
height: 36px;
|
|||
|
|
margin: 0 10px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 预警详情弹窗样式
|
|||
|
|
:deep(.warning-detail-dialog) {
|
|||
|
|
.el-dialog__header {
|
|||
|
|
padding: 15px 20px;
|
|||
|
|
border-bottom: 1px solid #e4e7ed;
|
|||
|
|
margin-right: 0;
|
|||
|
|
|
|||
|
|
.el-dialog__title {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #303133;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.el-dialog__body {
|
|||
|
|
padding: 20px;
|
|||
|
|
max-height: 70vh;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.detail-content {
|
|||
|
|
.detail-section {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
|
|||
|
|
.section-title {
|
|||
|
|
font-size: 15px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #303133;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
padding-left: 10px;
|
|||
|
|
border-left: 4px solid #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.basic-info-box {
|
|||
|
|
background: #f5f7fa;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
padding: 15px 20px;
|
|||
|
|
|
|||
|
|
.info-row {
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
&:last-child {
|
|||
|
|
margin-bottom: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.full-width {
|
|||
|
|
.info-item {
|
|||
|
|
flex: 1 1 100%;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-item {
|
|||
|
|
flex: 1 1 33.33%;
|
|||
|
|
min-width: 250px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: flex-start;
|
|||
|
|
line-height: 1.6;
|
|||
|
|
|
|||
|
|
.info-label {
|
|||
|
|
color: #606266;
|
|||
|
|
font-size: 13px;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
flex-shrink: 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-value {
|
|||
|
|
color: #303133;
|
|||
|
|
font-size: 13px;
|
|||
|
|
flex: 1;
|
|||
|
|
word-break: break-all;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.filter-bar {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 20px;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
padding: 10px 0;
|
|||
|
|
|
|||
|
|
.filter-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
|
|||
|
|
.filter-label {
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #606266;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-wrapper {
|
|||
|
|
border: 1px solid #ebeef5;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分页区域
|
|||
|
|
.pagination-area {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: flex-end;
|
|||
|
|
|
|||
|
|
:deep(.el-pagination) {
|
|||
|
|
.el-pagination__total {
|
|||
|
|
color: #606266;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.el-pager li {
|
|||
|
|
min-width: 32px;
|
|||
|
|
height: 32px;
|
|||
|
|
line-height: 32px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
margin: 0 4px;
|
|||
|
|
|
|||
|
|
&.active {
|
|||
|
|
background: #409eff;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:hover {
|
|||
|
|
color: #409eff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.btn-prev,
|
|||
|
|
.btn-next {
|
|||
|
|
min-width: 32px;
|
|||
|
|
height: 32px;
|
|||
|
|
line-height: 32px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|