bxztApp/packages/screen/src/views/RiskWarning/Dialog/warningSituationDialog.vue
2026-04-16 14:03:39 +08:00

590 lines
14 KiB
Vue

<template>
<base-dialog
v-model:visible="props.visible"
title="预警情况"
:table-data="tableData"
:table-columns="tableColumns"
:table-height="tableHeight"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@close="handleClose"
>
<!-- 筛选区域 -->
<template #filter>
<div class="filter-row">
<div class="filter-item">
<span class="filter-label">预警等级</span>
<el-select
v-model="filterForm.riskLeve"
placeholder="请选择"
class="filter-select el-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in warningLevelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="filter-item">
<span class="filter-label">影响区域</span>
<el-select
v-model="filterForm.countyName"
placeholder="请选择"
class="filter-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="filter-item">
<span class="filter-label">是否失效</span>
<el-select
v-model="filterForm.isEnded"
placeholder="请选择"
class="filter-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in isEndedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="filter-item">
<span class="filter-label">生效时间</span>
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
popper-class="custom-date-picker"
:teleported="false"
:prefix-icon="Calendar"
@change="handleDateChange"
/>
</div>
</div>
</template>
<!-- 预警等级列插槽 -->
<template #riskLeve="{ row }">
<span :class="['warning-level-tag', getWarningClass(row.riskLeve)]">{{
row.riskLeve
}}</span>
</template>
<!-- 影响点数量列插槽 -->
<template #impactCount="{ row }">
<span class="impact-count" @click="handleImpactClick(row)">{{
row.impactCount
}}</span>
</template>
</base-dialog>
</template>
<script setup>
import { ref, computed, watch, onMounted, inject } from "vue";
import { Close, Calendar } from "@element-plus/icons-vue";
import {
warningLevelOptions,
regionOptions,
isEndedOptions,
} from "../component/index.js";
import baseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
// 注入日期范围
const getdateRange = inject("getdateRange", ref([]));
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
warningitem: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(["update:visible", "close", "impactClick"]);
// 日期范围器
const dateRange = ref([]);
onMounted(() => {
// 如果弹窗初始就是打开状态,则初始化数据
if (props.visible) {
initDialogData();
}
});
// 监听 warningitem 变化,当弹窗重新打开时更新筛选条件
watch(
() => props.warningitem,
(newVal) => {
console.log("warningitem 变化:", newVal);
if (newVal && Object.keys(newVal).length > 0) {
filterForm.value.riskLeve = newVal.label || "";
currentPage.value = 1;
}
},
{ deep: true },
);
// 监听注入的日期范围变化
watch(
() => getdateRange.value,
(newVal) => {
console.log("warningSituationDialog.vue 日期范围变化:", newVal);
if (newVal && newVal.length === 2) {
dateRange.value = newVal;
filterForm.value.dateRange = newVal;
}
},
{ deep: true },
);
// 筛选表单
const filterForm = ref({
riskLeve: "",
countyName: "",
isEnded: "",
dateRange: dateRange.value,
});
// 处理日期范围变化
const handleDateChange = (val) => {
filterForm.value.dateRange = val;
};
// 预警等级选项
// 已从 index.js 导入
// 影响区域选项
// 已从 index.js 导入
// 是否结束选项
// 已从 index.js 导入
// 表格高度
const tableHeight = ref(300);
// 表格列配置
const tableColumns = ref([
{ prop: "index", label: "序号", width: "" },
{
prop: "riskLeve",
label: "预警等级",
width: "",
slot: "riskLeve",
},
{
label: "来源",
prop: "source",
width: "",
},
{ prop: "weatherType", label: "气象类型", width: "" },
{ prop: "countyName", label: "影响区域", width: "" },
{ prop: "warningTime", label: "生效时间", width: "" },
{ prop: "endTime", label: "失效时间", width: "" },
{
prop: "impactCount",
label: "影响点数量",
width: "",
slot: "impactCount",
},
]);
// 表格数据
const tableData = ref([]);
// 分页
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
// 加载状态
const loading = ref(false);
// 获取预警数据
const fetchWarningData = async () => {
loading.value = true;
try {
const params = {
offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
start: "",
end: "",
riskLevel: "",
weatherType: "",
isExpire: "",
countyName: "",
};
// 添加筛选条件
if (filterForm.value.riskLeve) {
params.riskLevel = filterForm.value.riskLeve;
}
if (filterForm.value.countyName) {
params.countyName = filterForm.value.countyName;
}
if (
filterForm.value.isEnded !== undefined &&
filterForm.value.isEnded !== ""
) {
params.isExpire = filterForm.value.isEnded;
}
if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
params.start = formatDateTime(filterForm.value.dateRange[0]);
params.end = formatDateTime(filterForm.value.dateRange[1]);
}
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_weather",
method: "GET",
params,
});
if (res.code === "00000" && res.data) {
// 处理返回数据
const list = res.data.data || res.data.records || [];
total.value = res.data.total || 0;
tableData.value = list.map((item, index) => ({
index: index + 1,
riskLeve: item.riskLeve || "-",
weatherType: item.weatherType || "-",
countyName: item.countyName || "-",
source: item.source || "-",
warningTime: item.startTime || "-",
endTime: item.endTime || "-",
impactCount: item.affectedCount || 0,
}));
} else {
tableData.value = [];
total.value = 0;
}
} catch (error) {
console.error("获取预警数据失败:", error);
tableData.value = [];
total.value = 0;
} finally {
loading.value = false;
}
};
// 格式化日期时间
const formatDateTime = (date) => {
if (!date) return "";
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const hours = String(d.getHours()).padStart(2, "0");
const minutes = String(d.getMinutes()).padStart(2, "0");
const seconds = String(d.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
// 获取预警等级样式类
const getWarningClass = (level) => {
const classMap = {
红色预警: "warning-red",
橙色预警: "warning-orange",
黄色预警: "warning-yellow",
蓝色预警: "warning-blue",
};
return classMap[level] || "";
};
// 关闭对话框
const handleClose = () => {
emit("update:visible", false);
emit("close");
};
// 点击影响点数量
const handleImpactClick = (item) => {
emit("impactClick", item);
emit("impactClickItem", {
...item,
dateRange: filterForm.value.dateRange || [],
riskLeve: filterForm.value.riskLeve || "",
});
};
// 分页操作
const handleSizeChange = (val) => {
pageSize.value = val;
console.log("分页大小变化:", val);
currentPage.value = 1;
fetchWarningData();
};
const handleCurrentChange = (val) => {
console.log("当前页码变化:", val);
currentPage.value = val;
fetchWarningData();
};
// 初始化弹窗数据
const initDialogData = () => {
// 设置日期范围
if (getdateRange.value && getdateRange.value.length === 2) {
dateRange.value = getdateRange.value;
}
// 如果有 warningitem 则设置筛选条件
if (props.warningitem && Object.keys(props.warningitem).length > 0) {
filterForm.value = {
riskLeve: props.warningitem.label || "",
countyName: props.warningitem.countyName || "",
isEnded: "",
dateRange: dateRange.value,
};
} else {
filterForm.value = {
riskLeve: "",
countyName: "",
isEnded: "",
dateRange: dateRange.value,
};
}
// 重置页码并获取数据
currentPage.value = 1;
console.log("初始化筛选条件:", filterForm.value);
fetchWarningData();
};
// 重置数据
const resetData = () => {
// 清空表格数据
tableData.value = [];
total.value = 0;
currentPage.value = 1;
// 清空筛选条件
filterForm.value = {
riskLeve: "",
countyName: "",
isEnded: "",
dateRange: [],
};
// 清空日期范围
dateRange.value = [];
};
// 监听visible变化
watch(
() => props.visible,
(newVal) => {
if (newVal) {
// 弹窗打开时,初始化数据
initDialogData();
} else {
// 弹窗关闭时,清空页面数据
resetData();
}
},
);
// 监听筛选条件变化(手动修改时触发,初始化时不触发)
watch(
() => filterForm.value,
(newVal, oldVal) => {
console.log("筛选条件变化:===========", newVal, oldVal);
// 只在旧值存在且不为空对象时触发(排除初始化情况)
if (oldVal && Object.keys(oldVal).length > 0) {
currentPage.value = 1;
fetchWarningData();
}
},
{ deep: true },
);
// 同步 dateRange 和 filterForm.dateRange
watch(
() => dateRange.value,
(newVal) => {
filterForm.value.dateRange = newVal;
},
{ deep: true },
);
watch(
() => filterForm.value.dateRange,
(newVal) => {
dateRange.value = newVal;
},
{ deep: true },
);
</script>
<style lang="scss" scoped>
// 筛选区域样式
.filter-item {
display: flex;
align-items: center;
gap: 8px;
.filter-label {
font-size: 13px;
color: rgba(255, 255, 255, 0.8);
white-space: nowrap;
}
.filter-select {
width: 120px;
:deep(.el-input__wrapper) {
background-color: rgba(30, 70, 120, 0.4);
border: 1px solid rgba(64, 169, 255, 0.3);
box-shadow: none;
border-radius: 4px;
width: 210px !important;
.el-input__inner {
color: #fff;
font-size: 13px;
&::placeholder {
color: rgba(255, 255, 255, 0.4);
}
}
.el-input__suffix {
.el-icon {
color: rgba(255, 255, 255, 0.6);
}
}
}
}
}
// 预警等级标签
.warning-level-tag {
display: inline-block;
padding: 2px 10px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
&.warning-red {
background-color: rgba(255, 77, 79, 0.2);
color: #ff4d4f;
border: 1px solid rgba(255, 77, 79, 0.4);
}
&.warning-orange {
background-color: rgba(255, 122, 0, 0.2);
color: #ff7a00;
border: 1px solid rgba(255, 122, 0, 0.4);
}
&.warning-yellow {
background-color: rgba(250, 219, 20, 0.2);
color: #fadb14;
border: 1px solid rgba(250, 219, 20, 0.4);
}
&.warning-blue {
background-color: rgba(64, 169, 255, 0.2);
color: #40a9ff;
border: 1px solid rgba(64, 169, 255, 0.4);
}
}
// 影响点数量
.impact-count {
color: #ff4d4f;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
&:hover {
color: #ff7875;
text-shadow: 0 0 8px rgba(255, 77, 79, 0.6);
}
}
// 筛选区域
.filter-section {
margin-bottom: vw(20);
.filter-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.filter-item {
.filter-select {
width: vw(150);
:deep(.el-input__wrapper) {
background-color: rgba(30, 70, 120, 0.4);
border: 1px solid rgba(64, 169, 255, 0.3);
box-shadow: none;
border-radius: vw(4);
.el-input__inner {
color: #fff;
font-size: vw(13);
&::placeholder {
color: rgba(255, 255, 255, 0.5);
}
}
.el-input__suffix {
.el-icon {
color: rgba(255, 255, 255, 0.6);
}
}
}
}
.search-btn {
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
border: none;
border-radius: vw(4);
padding: 0 vw(24);
height: vw(32);
font-size: vw(13);
&:hover {
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
}
}
}
}
:deep(.el-range-editor.el-input__wrapper) {
width: 240px !important;
height: 30px !important;
background-color: #122c46 !important;
}
</style>