1541 lines
41 KiB
Vue
Raw Normal View History

<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>