1541 lines
41 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="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>