大屏左侧数据完成调试
This commit is contained in:
parent
af40f7f464
commit
e01863a8cd
BIN
packages/screen/src/assets/RiskWarning_img/AI背景@2x.png
Normal file
BIN
packages/screen/src/assets/RiskWarning_img/AI背景@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 800 KiB |
BIN
packages/screen/src/assets/RiskWarning_img/标题@2x.png
Normal file
BIN
packages/screen/src/assets/RiskWarning_img/标题@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
BIN
packages/screen/src/assets/RiskWarning_img/矩形@2x.png
Normal file
BIN
packages/screen/src/assets/RiskWarning_img/矩形@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
packages/screen/src/assets/RiskWarning_img/路径 62@2x.png
Normal file
BIN
packages/screen/src/assets/RiskWarning_img/路径 62@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="AI预警处理结果"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="2200"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrapper">
|
||||
<!-- AI处理前预警 -->
|
||||
<div class="panel">
|
||||
<div class="center">
|
||||
<div class="panel-title" style="color: #18EFF7">AI处理前预警</div>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<div class="info-container">
|
||||
<div class="info-item">
|
||||
<span class="info-label">发布单位:</span>
|
||||
<span class="info-value">{{ beforeData.publishOrg }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">发布内容:</span>
|
||||
<span class="info-value">{{ beforeData.publishContent }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">生效时间:</span>
|
||||
<span class="info-value">{{ beforeData.effectiveTime }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">失效时间:</span>
|
||||
<span class="info-value">{{ beforeData.expireTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间AI标识 -->
|
||||
<div class="ai-center">
|
||||
<img
|
||||
class="ai-icon-img"
|
||||
src="../../../assets/RiskWarning_img/AI1@2x.png"
|
||||
alt="AI"
|
||||
/>
|
||||
<div class="ai-arrow">
|
||||
<el-icon color="#4FECFF"><DArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI处理后预警 -->
|
||||
<div class="panel after-panel panel1">
|
||||
<div class="center">
|
||||
<div class="panel-title" style="color: #18EFF7">AI处理后预警</div>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<!-- 标签页 -->
|
||||
<div class="tab-header">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === tab.key }"
|
||||
@click="activeTab = tab.key"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-container-tab">
|
||||
<!-- 标签内容 -->
|
||||
<div class="tab-content">
|
||||
<div class="info-item">
|
||||
<div class="info-label">预警等级;</div>
|
||||
<div class="info-value">{{ afterData.warningLevel }}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">预警信息;</div>
|
||||
<div class="info-value">{{ afterData.warningInfo }}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">预警详情;</div>
|
||||
<div class="info-value">{{ afterData.warningDetail }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close, DArrowRight } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
aiData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 标签页
|
||||
const tabs = ref([
|
||||
{ key: "frontline", label: "一线人员" },
|
||||
{ key: "district", label: "区县人员" },
|
||||
{ key: "handler", label: "处室人员" },
|
||||
{ key: "leader", label: "中心领导" },
|
||||
]);
|
||||
|
||||
const activeTab = ref("frontline");
|
||||
|
||||
// AI处理前数据
|
||||
const beforeData = ref({
|
||||
publishOrg: "潼南区预警中心",
|
||||
publishContent:
|
||||
'潼南区气象台2025年11月13日0时40分发布"暴雨蓝色预警信号",预计23日0:40-6:40,龙形、宝龙、上和、大佛、桂林、玉溪、米心、花岩、双江、古溪、群力、柏梓、崇龛、梓潼、太安等15个乡镇(街道)强降水趋于减弱,未来6小时累计雨量将达50~100毫米,最大小时雨强将达20~40毫米,局地伴有雷电、阵性大风,请各地注意防范。',
|
||||
effectiveTime: "2025-11-13 00:31:30.0",
|
||||
expireTime: "2025-11-13 00:31:30.0",
|
||||
});
|
||||
|
||||
// AI处理后数据
|
||||
const afterData = ref({
|
||||
warningLevel: "重庆市潼南气象台发布大雾黄色预警[III级/较重]",
|
||||
warningInfo:
|
||||
'潼南区区气象台发布暴雨红色预警,按照相关要求,启动I级防御响应,并请及时关注地质、水文等风险提示信息,落实主动封闭管控/"关停撒转"措施',
|
||||
warningDetail:
|
||||
"请立即按照2小时一次频率对你管养的重点路段/重点部位进行巡查,重点巡查较高及以上风险路段、涉灾隐患点、地质条件复杂路段、临河临崖路段/两区三厂、大型设施设备、取弃土(渣)场、砂石料场、涉水桥梁、富水隧道、围堰、支架脚手架、高切坡、滑坡处置等部位,重点关注涉水桥梁基础及墩台、不良地质隧道、隧道洞口边仰坡及侧切结构、高陡边坡支挡防护以及防排水设施,发现异常情况,立即向上报告,采取紧急排危、告警阻拦、吹哨撒转等措施,并及时报送工作开展情况。",
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.aiData) {
|
||||
Object.assign(beforeData.value, props.aiData.before);
|
||||
Object.assign(afterData.value, props.aiData.after);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 内容区域
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
// 面板
|
||||
.panel {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
.panel-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #40a9ff;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
width: 50%;
|
||||
background-image: url("../../../assets/RiskWarning_img/矩形@2x.png");
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
background-image: url("../../../assets/RiskWarning_img/AI背景@2x.png");
|
||||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
height: 85%;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
.info-container {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.info-container-tab {
|
||||
overflow-y: auto;
|
||||
height: 80%;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.6;
|
||||
|
||||
&.content-text {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 中间AI标识
|
||||
.ai-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 0 10px;
|
||||
.ai-icon-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.ai-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 20px rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
.ai-arrow {
|
||||
font-size: 32px;
|
||||
color: #40a9ff;
|
||||
animation: pulse 1.5s infinite;
|
||||
|
||||
:deep(.el-icon) {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
}
|
||||
|
||||
// 标签页
|
||||
.tab-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
|
||||
.tab-item {
|
||||
padding: 6px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
background-color: #1e4f70;
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
// background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
background: #18f2f9;
|
||||
border-color: #40a9ff;
|
||||
color: #075948;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,355 @@
|
||||
<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.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
: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.controlMeasure" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in controlMeasureOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 起止桩号列插槽 -->
|
||||
<template #stakeNo="{ row }">
|
||||
<el-tooltip :content="row.stakeNo" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ row.stakeNo }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 路况位置列插槽 -->
|
||||
<template #location="{ row }">
|
||||
<el-tooltip :content="row.location" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ row.location }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 管控措施列插槽 -->
|
||||
<template #controlMeasure="{ row }">
|
||||
<span :class="['control-tag', getControlClass(row.controlMeasure)]">{{ row.controlMeasure }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<span class="detail-link" @click="handleDetail(row)">详情</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, typeOptions, controlMeasureOptions } from "../component/index.js";
|
||||
import BaseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
type: "",
|
||||
controlMeasure: "",
|
||||
});
|
||||
|
||||
// 影响区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 类型选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 管控措施选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '50' },
|
||||
{ prop: 'region', label: '影响区域', width: '80' },
|
||||
{ prop: 'routeNo', label: '线路编号', width: '80' },
|
||||
{ prop: 'stakeNo', label: '起止桩号', width: '100', slot: 'stakeNo' },
|
||||
{ prop: 'location', label: '路况位置', width: '100', slot: 'location' },
|
||||
{ prop: 'occurrenceTime', label: '发生时间', width: '140' },
|
||||
{ prop: 'routeNo2', label: '线路编号', width: '80' },
|
||||
{ prop: 'type', label: '类型', width: '80' },
|
||||
{ prop: 'controlMeasure', label: '管控措施', width: '100', slot: 'controlMeasure' },
|
||||
{ prop: 'operation', label: '操作', width: '80', slot: 'operation' },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "巫溪县",
|
||||
routeNo: "G242",
|
||||
stakeNo: "336.800-338.850",
|
||||
location: "三星乡五斗村",
|
||||
occurrenceTime: "2025-08-11 04:53:42",
|
||||
routeNo2: "G242",
|
||||
type: "边坡坍塌",
|
||||
controlMeasure: "全幅封闭",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
routeNo: "G242",
|
||||
stakeNo: "338.800-338.850",
|
||||
location: "三星乡五斗村",
|
||||
occurrenceTime: "2025-08-11 04:53:42",
|
||||
routeNo2: "G242",
|
||||
type: "边坡坍塌",
|
||||
controlMeasure: "正常通行",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "沙坪坝区",
|
||||
routeNo: "G319",
|
||||
stakeNo: "120.500-122.000",
|
||||
location: "沙坪坝镇",
|
||||
occurrenceTime: "2025-08-10 14:30:00",
|
||||
routeNo2: "G319",
|
||||
type: "路面塌陷",
|
||||
controlMeasure: "半幅封闭",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "渝中区",
|
||||
routeNo: "G212",
|
||||
stakeNo: "88.200-89.100",
|
||||
location: "渝中大道",
|
||||
occurrenceTime: "2025-08-09 09:15:30",
|
||||
routeNo2: "G212",
|
||||
type: "桥梁损坏",
|
||||
controlMeasure: "限制通行",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 获取管控措施样式类
|
||||
const getControlClass = (measure) => {
|
||||
const classMap = {
|
||||
"全幅封闭": "control-close",
|
||||
"半幅封闭": "control-half",
|
||||
"正常通行": "control-normal",
|
||||
"限制通行": "control-limit",
|
||||
};
|
||||
return classMap[measure] || "";
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 省略号文本
|
||||
.ellipsis-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 管控措施标签
|
||||
.control-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.control-close {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.control-half {
|
||||
background-color: rgba(255, 122, 0, 0.2);
|
||||
color: #ff7a00;
|
||||
border: 1px solid rgba(255, 122, 0, 0.4);
|
||||
}
|
||||
|
||||
&.control-normal {
|
||||
background-color: rgba(82, 196, 26, 0.2);
|
||||
color: #52c41a;
|
||||
border: 1px solid rgba(82, 196, 26, 0.4);
|
||||
}
|
||||
|
||||
&.control-limit {
|
||||
background-color: rgba(250, 219, 20, 0.2);
|
||||
color: #fadb14;
|
||||
border: 1px solid rgba(250, 219, 20, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
// 详情链接
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<div v-if="visible" class="confirm-dialog-overlay" @click="handleOverlayClick">
|
||||
<div
|
||||
v-if="visible"
|
||||
class="confirm-dialog-overlay"
|
||||
@click="handleOverlayClick"
|
||||
>
|
||||
<div class="confirm-dialog" @click.stop>
|
||||
<!-- 四个角的装饰 -->
|
||||
<div class="corner corner-top-left"></div>
|
||||
<div class="corner corner-top-right"></div>
|
||||
<div class="corner corner-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">{{ title }}</div>
|
||||
@ -16,7 +25,7 @@
|
||||
|
||||
<!-- 按钮区域 -->
|
||||
<div class="dialog-footer">
|
||||
<el-button class="btn-cancel" @click="handleCancel">
|
||||
<el-button type="primary" class="btn-confirm" @click="handleCancel">
|
||||
{{ cancelText }}
|
||||
</el-button>
|
||||
<el-button type="primary" class="btn-confirm" @click="handleConfirm">
|
||||
@ -45,11 +54,11 @@ const props = defineProps({
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: "确定",
|
||||
default: "已拨打",
|
||||
},
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: "取消",
|
||||
default: "未拨打",
|
||||
},
|
||||
});
|
||||
|
||||
@ -89,18 +98,59 @@ const handleOverlayClick = () => {
|
||||
|
||||
.confirm-dialog {
|
||||
width: 80vw;
|
||||
max-width: 400px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
max-width: 300px;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(20, 50, 90, 0.95) 0%,
|
||||
rgba(10, 30, 60, 0.98) 100%
|
||||
);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
overflow: hidden;
|
||||
animation: dialogSlideIn 0.3s ease-out;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 90vw;
|
||||
max-width: 90vw;
|
||||
}
|
||||
// 四个角的装饰
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #40a9ff;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
|
||||
&.corner-top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dialogSlideIn {
|
||||
@ -120,7 +170,11 @@ const handleOverlayClick = () => {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
background: linear-gradient(90deg, rgba(64, 169, 255, 0.15) 0%, rgba(64, 169, 255, 0.05) 100%);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(64, 169, 255, 0.15) 0%,
|
||||
rgba(64, 169, 255, 0.05) 100%
|
||||
);
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
|
||||
.header-title {
|
||||
@ -0,0 +1,302 @@
|
||||
<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"
|
||||
:z-index="2200"
|
||||
@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.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.riskLevel" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in riskLevelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 驻地名称列插槽 -->
|
||||
<template #stationName="{ row }">
|
||||
<el-tooltip :content="row.stationName" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ row.stationName }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 所属项目列插槽 -->
|
||||
<template #project="{ row }">
|
||||
<el-tooltip :content="row.project" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ row.project }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 驻地风险等级列插槽 -->
|
||||
<template #riskLevel="{ row }">
|
||||
<span :class="['risk-tag', getRiskClass(row.riskLevel)]">{{ row.riskLevel }}</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, riskLevelOptions } from "../component/index.js";
|
||||
import BaseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
riskLevel: "",
|
||||
});
|
||||
|
||||
// 影响区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 风险等级选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '60' },
|
||||
{ prop: 'region', label: '影响区域', width: '100' },
|
||||
{ prop: 'stationName', label: '驻地名称', width: '200', slot: 'stationName' },
|
||||
{ prop: 'project', label: '所属项目', width: '200', slot: 'project' },
|
||||
{ prop: 'peopleCount', label: '驻地人数', width: '80' },
|
||||
{ prop: 'riskLevel', label: '驻地风险等级', width: '100', slot: 'riskLevel' },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "沙坪坝区",
|
||||
stationName: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)项目经理部",
|
||||
project: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)",
|
||||
peopleCount: 21,
|
||||
riskLevel: "Ⅳ级",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
stationName: "万州区项目经理部",
|
||||
project: "万州区公路改造项目",
|
||||
peopleCount: 15,
|
||||
riskLevel: "Ⅲ级",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "渝中区",
|
||||
stationName: "渝中区桥梁维护项目部",
|
||||
project: "渝中区桥梁维护工程",
|
||||
peopleCount: 8,
|
||||
riskLevel: "Ⅱ级",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "江北区",
|
||||
stationName: "江北区道路施工项目部",
|
||||
project: "江北区道路施工项目",
|
||||
peopleCount: 32,
|
||||
riskLevel: "Ⅰ级",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 获取风险等级样式类
|
||||
const getRiskClass = (level) => {
|
||||
const classMap = {
|
||||
"Ⅰ级": "risk-level-1",
|
||||
"Ⅱ级": "risk-level-2",
|
||||
"Ⅲ级": "risk-level-3",
|
||||
"Ⅳ级": "risk-level-4",
|
||||
};
|
||||
return classMap[level] || "";
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 省略号文本
|
||||
.ellipsis-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 风险等级标签
|
||||
.risk-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.risk-level-1 {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-2 {
|
||||
background-color: rgba(255, 122, 0, 0.2);
|
||||
color: #ff7a00;
|
||||
border: 1px solid rgba(255, 122, 0, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-3 {
|
||||
background-color: rgba(250, 219, 20, 0.2);
|
||||
color: #fadb14;
|
||||
border: 1px solid rgba(250, 219, 20, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-4 {
|
||||
background-color: rgba(82, 196, 26, 0.2);
|
||||
color: #52c41a;
|
||||
border: 1px solid rgba(82, 196, 26, 0.4);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,234 @@
|
||||
<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"
|
||||
:z-index="2300"
|
||||
@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.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, typeOptions } from "../component/index.js";
|
||||
import BaseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
type: "",
|
||||
});
|
||||
|
||||
// 影响区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 类型选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '50' },
|
||||
{ prop: 'district', label: '区县/镇街', width: '100' },
|
||||
{ prop: 'name', label: '姓名', width: '80' },
|
||||
{ prop: 'phone', label: '电话', width: '120' },
|
||||
{ prop: 'type', label: '类型', width: '100' },
|
||||
{ prop: 'role', label: '角色', width: '140' },
|
||||
{ prop: 'dispatchTime', label: '调度时间', width: '160' },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
district: "柏梓镇",
|
||||
name: "赵海浪",
|
||||
phone: "18623520681",
|
||||
type: "交通主管部门",
|
||||
role: "一般人员(路长履职)",
|
||||
dispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
district: "柏梓镇",
|
||||
name: "赵海浪",
|
||||
phone: "18623520681",
|
||||
type: "公路机构",
|
||||
role: "一般人员(路长履职)",
|
||||
dispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
district: "万州区",
|
||||
name: "王鑫",
|
||||
phone: "18623520682",
|
||||
type: "养护站",
|
||||
role: "站长",
|
||||
dispatchTime: "2025-08-10 14:30:00",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
district: "沙坪坝区",
|
||||
name: "李华",
|
||||
phone: "18623520683",
|
||||
type: "护路员",
|
||||
role: "一般人员",
|
||||
dispatchTime: "2025-08-09 09:15:30",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,233 @@
|
||||
<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"
|
||||
:z-index="2200"
|
||||
@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.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 调度数列插槽 -->
|
||||
<template #dispatchCount="{ row }">
|
||||
<span class="dispatch-count" @click="handleDispatchClick(row)">{{ row.dispatchCount }}</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions } from "../component/index.js";
|
||||
import BaseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits({
|
||||
"update:visible": (value) => typeof value === "boolean",
|
||||
"close": () => true,
|
||||
"dispatchClick": (item) => item !== undefined
|
||||
});
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
});
|
||||
|
||||
// 影响区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '60' },
|
||||
{ prop: 'region', label: '影响区域', width: '120' },
|
||||
{ prop: 'dispatchCount', label: '调度数', width: '100', slot: 'dispatchCount' },
|
||||
{ prop: 'lastDispatchTime', label: '最近调度时间', width: '160' },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "重庆市",
|
||||
dispatchCount: 1,
|
||||
lastDispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
dispatchCount: 1,
|
||||
lastDispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "沙坪坝区",
|
||||
dispatchCount: 3,
|
||||
lastDispatchTime: "2025-08-10 16:20:15",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "渝中区",
|
||||
dispatchCount: 2,
|
||||
lastDispatchTime: "2025-08-09 11:45:30",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击调度数
|
||||
const handleDispatchClick = (item) => {
|
||||
emit("dispatchClick", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
// 重置筛选表单
|
||||
filterForm.value.region = "";
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调度数字
|
||||
.dispatch-count {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,18 @@
|
||||
<template>
|
||||
<div v-if="visible" class="event-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="event-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">详情</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="详情"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="2200"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 事件基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
@ -116,7 +120,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
|
||||
@ -127,12 +132,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -211,10 +216,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
@ -229,68 +231,6 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.event-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2100;
|
||||
}
|
||||
|
||||
.event-dialog {
|
||||
width: 80vw;
|
||||
max-width: 700px;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区块
|
||||
.section {
|
||||
margin-bottom: 24px;
|
||||
@ -496,7 +436,7 @@ watch(
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1100;
|
||||
z-index: 2200;
|
||||
}
|
||||
|
||||
.image-preview-container {
|
||||
@ -532,7 +472,7 @@ watch(
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
.event-dialog {
|
||||
:deep(.base-dialog) {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
<template>
|
||||
<div v-if="visible" class="impact-detail-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="impact-detail-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">影响点详情</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="影响点详情"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="2500"
|
||||
:max-width="650"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 隐患点基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
@ -109,7 +114,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
|
||||
@ -120,12 +126,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -203,10 +209,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
@ -220,67 +223,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.impact-detail-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2500;
|
||||
}
|
||||
|
||||
.impact-detail-dialog {
|
||||
width: 80vw;
|
||||
max-width: 650px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区块
|
||||
.section {
|
||||
@ -556,13 +499,5 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
.impact-detail-dialog {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,428 @@
|
||||
<template>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="影响点情况"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="320"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="2000"
|
||||
:max-width="1200"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointType" size="small" placeholder="影响点类型" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in pointTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointLevel" size="small" placeholder="影响点等级" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in pointLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.region" size="small" placeholder="影响区域" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in regionOptionsWithAll"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 影响点等级列插槽 -->
|
||||
<template #pointLevel="{ row }">
|
||||
<span class="level-tag" :class="row.levelClass">{{ row.pointLevel }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 交通主管部门负责人列插槽 -->
|
||||
<template #trafficDept="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.trafficDept.name }}</span>
|
||||
<span class="person-phone">{{ row.trafficDept.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 公路机构责任人列插槽 -->
|
||||
<template #roadOrg="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.roadOrg.name }}</span>
|
||||
<span class="person-phone">{{ row.roadOrg.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 养护站负责人列插槽 -->
|
||||
<template #maintenance="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.maintenance.name }}</span>
|
||||
<span class="person-phone">{{ row.maintenance.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 护路员列插槽 -->
|
||||
<template #roadKeeper="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.roadKeeper.name }}</span>
|
||||
<span class="person-phone">{{ row.roadKeeper.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<span class="detail-link" @click="handleDetail(row)">详情</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, regionOptionsWithAll } from "../component/index.js";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
pointType: "",
|
||||
pointLevel: "",
|
||||
region: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "50px" },
|
||||
{ prop: "region", label: "影响区域", width: "80px" },
|
||||
{ prop: "pointType", label: "影响点类型", width: "80px" },
|
||||
{ prop: "pointLocation", label: "影响点位置", width: "180px" },
|
||||
{ prop: "pointLevel", label: "影响点等级", width: "90px", slot: "pointLevel" },
|
||||
{ prop: "trafficDept", label: "交通主管部门负责人", width: "130px", slot: "trafficDept" },
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "110px", slot: "roadOrg" },
|
||||
{ prop: "maintenance", label: "养护站负责人", width: "110px", slot: "maintenance" },
|
||||
{ prop: "roadKeeper", label: "护路员", width: "100px", slot: "roadKeeper" },
|
||||
{ prop: "operation", label: "操作", width: "60px", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 4;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
console.log("查询条件:", filterForm.value);
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 视频屏幕自适应 - 基于视口宽度动态调整
|
||||
@function vw($px) {
|
||||
@return calc($px / 1920 * 100vw);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: vw(16);
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, rgba(30, 70, 120, 0.6) 0%, rgba(20, 50, 90, 0.8) 100%);
|
||||
border: vw(2) solid rgba(64, 169, 255, 0.4);
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
.stat-label {
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: vw(28);
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格列样式
|
||||
.level-tag {
|
||||
display: inline-block;
|
||||
padding: vw(2) vw(8);
|
||||
border-radius: vw(4);
|
||||
font-size: vw(11);
|
||||
|
||||
&.level-normal {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-serious {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.person-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: vw(2);
|
||||
|
||||
.person-name {
|
||||
font-size: vw(12);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.person-phone {
|
||||
font-size: vw(11);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: vw(12);
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,19 @@
|
||||
<template>
|
||||
<div v-if="visible" class="response-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="response-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应点详情</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="响应点详情"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="1000"
|
||||
:max-width="700"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 隐患点基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
@ -114,7 +119,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
|
||||
@ -125,12 +131,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -240,10 +246,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
@ -257,67 +260,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.response-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.response-dialog {
|
||||
width: 80vw;
|
||||
max-width: 700px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区块
|
||||
.section {
|
||||
@ -657,22 +600,5 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.response-dialog::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.response-dialog::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.response-dialog::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.response-dialog::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,19 @@
|
||||
<template>
|
||||
<div v-if="visible" class="response-info-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="response-info-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应点详情</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="响应点详情"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="1000"
|
||||
:max-width="750"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
@ -137,7 +142,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
|
||||
@ -148,12 +154,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -274,10 +280,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
@ -291,67 +294,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.response-info-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.response-info-dialog {
|
||||
width: 80vw;
|
||||
max-width: 750px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区块
|
||||
.section {
|
||||
@ -694,22 +637,5 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.response-info-dialog::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.response-info-dialog::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.response-info-dialog::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.response-info-dialog::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="潼南三级路长明细"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="300"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="1000"
|
||||
:max-width="700"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 统计数据卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><User /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">路长总人数</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.total }}</span>
|
||||
<span class="value-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><OfficeBuilding /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">县级路长</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.county }}</span>
|
||||
<span class="value-unit">公里</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><MapLocation /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">乡、村路长</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.village }}</span>
|
||||
<span class="value-unit">次</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<div class="action-btns">
|
||||
<div class="action-btn" @click="handleView(row)">
|
||||
<el-icon><VideoCamera /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleVoice(row)">
|
||||
<el-icon><Microphone /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleCall(row)">
|
||||
<el-icon><Phone /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, VideoCamera, Microphone, Phone, ArrowLeft, ArrowRight, User, OfficeBuilding, MapLocation } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 统计数据
|
||||
const stats = ref({
|
||||
total: 1127,
|
||||
county: 216,
|
||||
village: 1099,
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "60px" },
|
||||
{ prop: "district", label: "区县/镇街", width: "120px" },
|
||||
{ prop: "name", label: "姓名", width: "100px" },
|
||||
{ prop: "phone", label: "电话", width: "120px" },
|
||||
{ prop: "role", label: "角色", width: "200px" },
|
||||
{ prop: "position", label: "职务", width: "100px" },
|
||||
{ prop: "operation", label: "操作", width: "120px", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{ id: 1, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 2, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 3, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 4, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 5, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 6, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 7, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 8, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 9, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 10, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 11, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 12, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 操作按钮
|
||||
const handleView = (item) => {
|
||||
console.log("查看视频:", item);
|
||||
};
|
||||
|
||||
const handleVoice = (item) => {
|
||||
console.log("语音通话:", item);
|
||||
};
|
||||
|
||||
const handleCall = (item) => {
|
||||
console.log("拨打电话:", item);
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: linear-gradient(135deg, rgba(30, 80, 140, 0.6) 0%, rgba(20, 60, 110, 0.8) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
|
||||
.card-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
.stat-icon {
|
||||
font-size: 18px;
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
.card-label {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 2px;
|
||||
|
||||
.value-num {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 6px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
.value-unit {
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮样式
|
||||
.action-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
|
||||
.action-btn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.15);
|
||||
border-radius: 2px;
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,448 @@
|
||||
<template>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="响应情况"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="200"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="1000"
|
||||
:max-width="1150"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响路段</div>
|
||||
<div class="stat-value">2432</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.pointType"
|
||||
placeholder="影响点类型"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.pointLevel"
|
||||
placeholder="影响点等级"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.isResponded"
|
||||
placeholder="是否回应"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in isRespondedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 影响点等级列插槽 -->
|
||||
<template #pointLevel="{ row }">
|
||||
<span class="level-tag" :class="row.levelClass">{{ row.pointLevel }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 交通主管部门负责人列插槽 -->
|
||||
<template #trafficDept="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.trafficDept.name }}</span>
|
||||
<span class="person-phone">{{ row.trafficDept.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 公路机构责任人列插槽 -->
|
||||
<template #roadOrg="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.roadOrg.name }}</span>
|
||||
<span class="person-phone">{{ row.roadOrg.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 养护站负责人列插槽 -->
|
||||
<template #maintenance="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.maintenance.name }}</span>
|
||||
<span class="person-phone">{{ row.maintenance.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 护路员列插槽 -->
|
||||
<template #roadKeeper="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.roadKeeper.name }}</span>
|
||||
<span class="person-phone">{{ row.roadKeeper.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 回应状态列插槽 -->
|
||||
<template #responseStatus="{ row }">
|
||||
<span class="response-status" :class="row.responseClass">{{ row.responseStatus }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 最新催告时间列插槽 -->
|
||||
<template #urgeTime="{ row }">
|
||||
<div class="time-info">
|
||||
<span class="time-date">{{ row.urgeTime.date }}</span>
|
||||
<span class="time-clock">{{ row.urgeTime.time }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<span class="detail-link" @click="handleDetail(row)">详情</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, isRespondedOptions } from "../component/index.js";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
pointType: "",
|
||||
pointLevel: "",
|
||||
isResponded: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "50px" },
|
||||
{ prop: "pointType", label: "影响点类型", width: "80px" },
|
||||
{ prop: "pointLocation", label: "影响点位置", width: "150px" },
|
||||
{ prop: "pointLevel", label: "影响点等级", width: "90px", slot: "pointLevel" },
|
||||
{ prop: "checkCount", label: "查次数", width: "60px" },
|
||||
{ prop: "trafficDept", label: "交通主管部门负责人", width: "120px", slot: "trafficDept" },
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "110px", slot: "roadOrg" },
|
||||
{ prop: "maintenance", label: "养护站负责人", width: "110px", slot: "maintenance" },
|
||||
{ prop: "roadKeeper", label: "护路员", width: "80px", slot: "roadKeeper" },
|
||||
{ prop: "responseStatus", label: "回应状态", width: "70px", slot: "responseStatus" },
|
||||
{ prop: "urgeTime", label: "最新催告时间", width: "110px", slot: "urgeTime" },
|
||||
{ prop: "operation", label: "操作", width: "50px", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
checkCount: 2,
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "1372386532" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
responseStatus: "已回应",
|
||||
responseClass: "status-responded",
|
||||
urgeTime: { date: "2026-03-28", time: "12:30:00" },
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
checkCount: 2,
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "1372386532" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
responseStatus: "已回应",
|
||||
responseClass: "status-responded",
|
||||
urgeTime: { date: "2026-03-28", time: "12:30:00" },
|
||||
},
|
||||
]);
|
||||
tableData.value.push(...tableData.value);
|
||||
tableData.value.push(...tableData.value);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.filter-select {
|
||||
width: 150px;
|
||||
|
||||
: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;
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格单元格样式
|
||||
.level-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
|
||||
&.level-normal {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-serious {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.person-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.person-name {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.person-phone {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.response-status {
|
||||
font-size: 12px;
|
||||
|
||||
&.status-responded {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-unresponded {
|
||||
color: #ff7a45;
|
||||
}
|
||||
}
|
||||
|
||||
.time-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.time-date {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.time-clock {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(30, 70, 120, 0.6) 0%,
|
||||
rgba(20, 50, 90, 0.8) 100%
|
||||
);
|
||||
border: 2px solid rgba(64, 169, 255, 0.4);
|
||||
border-radius: 8px;
|
||||
padding: 8px 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(64, 169, 255, 0.8);
|
||||
box-shadow: 0 0 20px rgba(64, 169, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,19 @@
|
||||
<template>
|
||||
<div v-if="visible" class="risk-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="risk-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">影响点详情</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="影响点详情"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="1000"
|
||||
:max-width="800"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<!-- 基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
@ -166,7 +171,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
|
||||
@ -177,12 +183,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -319,10 +325,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
@ -336,67 +339,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.risk-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.risk-dialog {
|
||||
width: 80vw;
|
||||
max-width: 800px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区块
|
||||
.section {
|
||||
@ -776,22 +719,5 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.risk-dialog::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.risk-dialog::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.risk-dialog::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.risk-dialog::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,614 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="visible"
|
||||
class="warning-dialog-overlay"
|
||||
@click="handleOverlayClick"
|
||||
>
|
||||
<div class="warning-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.warningLevel"
|
||||
placeholder="预警等级"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in warningLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.region"
|
||||
placeholder="影响区域"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in regionOptionsWithAll"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.isEnded"
|
||||
placeholder="是否结束"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in isEndedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.isResponded"
|
||||
placeholder="是否回应"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in isRespondedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:height="tableHeight"
|
||||
style="width: 100%"
|
||||
:header-cell-style="headerCellStyle"
|
||||
:cell-style="cellStyle"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table-column prop="weatherSource" label="气象来源" width="80" />
|
||||
<el-table-column prop="warningLevel" label="预警等级" width="100">
|
||||
<template #default="{ row }">
|
||||
<span class="warning-level" :class="row.levelClass">{{ row.warningLevel }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="region" label="影响区域" width="100" />
|
||||
<el-table-column prop="warningTime" label="预警时间" width="160" />
|
||||
<el-table-column prop="endTime" label="结束时间" width="160" />
|
||||
<el-table-column prop="impactPoints" label="影响点数量" width="100" />
|
||||
<el-table-column prop="called" label="已叫应" width="80">
|
||||
<template #default="{ row }">
|
||||
<span class="clickable-cell" @click="handleCalledClick(row)">{{ row.called }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="responded" label="已回应" width="80" />
|
||||
<el-table-column prop="notResponded" label="未回应" width="80" />
|
||||
<el-table-column prop="urged" label="已催告" width="80" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 30, 40]"
|
||||
:total="total"
|
||||
background
|
||||
layout="prev, pager, next, jumper, ->, total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, Search, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import {
|
||||
warningLevelOptions,
|
||||
regionOptionsWithAll,
|
||||
isEndedOptions,
|
||||
isRespondedOptions,
|
||||
} from "../component/index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "openImpactPoint"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
warningLevel: "",
|
||||
region: "",
|
||||
isEnded: "",
|
||||
isResponded: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "气象来源", width: "80px" },
|
||||
{ label: "预警等级", width: "100px" },
|
||||
{ label: "影响区域", width: "100px" },
|
||||
{ label: "预警时间", width: "160px" },
|
||||
{ label: "结束时间", width: "160px" },
|
||||
{ label: "影响点数量", width: "100px" },
|
||||
{ label: "已叫应", width: "80px" },
|
||||
{ label: "已回应", width: "80px" },
|
||||
{ label: "未回应", width: "80px" },
|
||||
{ label: "已催告", width: "80px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
weatherSource: "气象局",
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "万州区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 4,
|
||||
called: 2,
|
||||
responded: 2,
|
||||
notResponded: 2,
|
||||
urged: 22,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
weatherSource: "气象局",
|
||||
warningLevel: "橙色预警",
|
||||
levelClass: "level-orange",
|
||||
region: "涪陵区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 18,
|
||||
},
|
||||
]);
|
||||
tableData.value.push(...tableData.value);
|
||||
tableData.value.push(...tableData.value);
|
||||
tableData.value.push(...tableData.value);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格样式
|
||||
const headerCellStyle = () => {
|
||||
return {
|
||||
backgroundColor: '#1C4979',
|
||||
color: '#fff',
|
||||
fontSize: '14px',
|
||||
fontWeight: '500',
|
||||
textAlign: 'center',
|
||||
padding: '12px 16px',
|
||||
border: 'none'
|
||||
};
|
||||
};
|
||||
|
||||
const cellStyle = () => {
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
color: 'rgba(255, 255, 255, 0.85)',
|
||||
fontSize: '13px',
|
||||
textAlign: 'center',
|
||||
padding: '12px 16px',
|
||||
border: 'none'
|
||||
};
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 点击已叫应
|
||||
const handleCalledClick = () => {
|
||||
emit("responseStatus");
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
console.log("查询条件:", filterForm.value);
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.warning-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.warning-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(20, 50, 90, 0.95) 0%,
|
||||
rgba(10, 30, 60, 0.98) 100%
|
||||
);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(64, 169, 255, 0.2) 20%,
|
||||
rgba(64, 169, 255, 0.2) 80%,
|
||||
transparent 100%
|
||||
);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.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;
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::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: 4px;
|
||||
padding: 0 20px;
|
||||
height: 32px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-table) {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
.el-table__header-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__cell {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.el-table__header .el-table__cell {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-level {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.level-red {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.level-orange {
|
||||
background-color: rgba(255, 122, 69, 0.2);
|
||||
color: #ff7a45;
|
||||
border: 1px solid rgba(255, 122, 69, 0.4);
|
||||
}
|
||||
|
||||
&.level-yellow {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-blue {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
color: #40a9ff;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.clickable-cell {
|
||||
cursor: pointer;
|
||||
color: #40a9ff;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
:deep(.el-pagination) {
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__btn {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__item {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-table__body-wrapper) {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,577 @@
|
||||
<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.warningLevel"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
clearable
|
||||
size="small"
|
||||
>
|
||||
<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.region"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
clearable
|
||||
size="small"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in isEndedOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 预警等级列插槽 -->
|
||||
<template #warningLevel="{ row }">
|
||||
<span
|
||||
:class="[
|
||||
'warning-level-tag',
|
||||
getWarningClass(row.warningLevel),
|
||||
]"
|
||||
>{{ row.warningLevel }}</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 } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import {
|
||||
warningLevelOptions,
|
||||
regionOptions,
|
||||
isEndedOptions,
|
||||
} from "../component/index.js";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "impactClick"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
warningLevel: "",
|
||||
region: "",
|
||||
isEnded: "",
|
||||
dateRange: [],
|
||||
});
|
||||
|
||||
// 预警等级选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 影响区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 是否结束选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'index', label: '序号', width: '60' },
|
||||
{ prop: 'warningLevel', label: '预警等级', width: '100', slot: 'warningLevel' },
|
||||
{ prop: 'weatherType', label: '气象类型', width: '100' },
|
||||
{ prop: 'region', label: '行政区域', width: '100' },
|
||||
{ prop: 'warningTime', label: '预警时间', width: '160' },
|
||||
{ prop: 'endTime', label: '结束时间', width: '160' },
|
||||
{ prop: 'impactCount', label: '影响点数量', width: '100', slot: 'impactCount' },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
index: 1,
|
||||
warningLevel: "红色预警",
|
||||
weatherType: "暴雨",
|
||||
region: "重庆市",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactCount: 0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
index: 2,
|
||||
warningLevel: "橙色预警",
|
||||
weatherType: "暴雨",
|
||||
region: "万州区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactCount: 1,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
index: 3,
|
||||
warningLevel: "黄色预警",
|
||||
weatherType: "大风",
|
||||
region: "沙坪坝区",
|
||||
warningTime: "2025-08-10 16:20:15",
|
||||
endTime: "2025-08-10 20:30:00",
|
||||
impactCount: 3,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
index: 4,
|
||||
warningLevel: "蓝色预警",
|
||||
weatherType: "雷电",
|
||||
region: "渝中区",
|
||||
warningTime: "2025-08-09 09:15:30",
|
||||
endTime: "2025-08-09 12:00:00",
|
||||
impactCount: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
// 获取预警等级样式类
|
||||
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);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
padding: 0 24px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date-range-picker {
|
||||
: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;
|
||||
background: transparent;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-input) {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-separator) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 24px;
|
||||
|
||||
:deep(.el-table) {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
.el-table__header-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
width: 100% !important;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__cell {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
.el-table__header {
|
||||
width: 100% !important;
|
||||
}
|
||||
.el-table__header .el-table__cell {
|
||||
background-color: #1c4979;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// 预警等级标签
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
|
||||
:deep(.el-pagination) {
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__btn {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__item {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-table__body) {
|
||||
width: 100% !important;
|
||||
}
|
||||
// 隐藏滚动条
|
||||
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-table__body-wrapper) {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// 日期选择器弹出面板深色主题
|
||||
.el-picker-panel {
|
||||
background: rgba(20, 50, 90, 0.98) !important;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3) !important;
|
||||
|
||||
.el-picker-panel__content {
|
||||
color: #fff;
|
||||
|
||||
.el-date-table th {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
border-bottom-color: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
|
||||
.el-date-table td {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&.selected .el-date-table-cell {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
}
|
||||
|
||||
&.today span {
|
||||
color: #40a9ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.in-range,
|
||||
&.start-date,
|
||||
&.end-date {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-picker-panel__footer {
|
||||
border-top: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-button {
|
||||
background: rgba(30, 70, 120, 0.4);
|
||||
border-color: rgba(64, 169, 255, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-table--fit .el-table__inner-wrapper:before {
|
||||
width: 0% !important;
|
||||
}
|
||||
</style>
|
||||
@ -79,6 +79,7 @@
|
||||
"
|
||||
alt=""
|
||||
/>
|
||||
<span class="ml_10">{{ row.level }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -465,7 +466,7 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
@ -537,7 +538,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&.tag-red {
|
||||
@ -606,7 +607,7 @@ onUnmounted(() => {
|
||||
|
||||
td.el-table__cell {
|
||||
background: transparent;
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
padding: vw(5) vw(5);
|
||||
}
|
||||
|
||||
@ -41,19 +41,27 @@ const loadMapData = async () => {
|
||||
try {
|
||||
// 初始化地图
|
||||
|
||||
// 本地测试用,注释掉部署用的代码
|
||||
// 检查URL参数中是否有Map=dev
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isDev = urlParams.get('Map') === 'dev';
|
||||
|
||||
let geoJsonData;
|
||||
|
||||
if (isDev) {
|
||||
// 本地测试用
|
||||
const response = await fetch(GEOJSON_URL)
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
const geoJsonData = await response.json()
|
||||
|
||||
// 部署需要放开注释
|
||||
// const response = await axios.get('/aliyun-geo/bound/500000_full.json');
|
||||
// const geoJsonData = response.data;
|
||||
// if (!geoJsonData) {
|
||||
// throw new Error('地图数据为空');
|
||||
// }
|
||||
geoJsonData = await response.json()
|
||||
} else {
|
||||
// 部署用
|
||||
const response = await axios.get('/aliyun-geo/bound/500000_full.json');
|
||||
geoJsonData = response.data;
|
||||
if (!geoJsonData) {
|
||||
throw new Error('地图数据为空');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // 处理行政区划变更:渝北区和江北区合并为两江新区
|
||||
@ -164,16 +172,16 @@ const initMap = (geoJsonData) => {
|
||||
});
|
||||
|
||||
// 添加瓦片图层 - 使用深色样式
|
||||
const tileLayer = new window.L.TileLayer(
|
||||
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
||||
{
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
||||
subdomains: "abcd",
|
||||
maxZoom: 19,
|
||||
},
|
||||
);
|
||||
mapInstance.addLayer(tileLayer);
|
||||
// const tileLayer = new window.L.TileLayer(
|
||||
// "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
||||
// {
|
||||
// attribution:
|
||||
// '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
||||
// subdomains: "abcd",
|
||||
// maxZoom: 19,
|
||||
// },
|
||||
// );
|
||||
// mapInstance.addLayer(tileLayer);
|
||||
|
||||
// 添加 GeoJSON 图层
|
||||
geoJsonLayer = new window.L.GeoJSON(geoJsonData, {
|
||||
|
||||
@ -1,371 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="ai-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="ai-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">AI预警处理结果</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrapper">
|
||||
<!-- AI处理前预警 -->
|
||||
<div class="panel before-panel" style="background: linear-gradient(135deg, rgba(30, 80, 140, 0.6) 0%, rgba(20, 60, 110, 0.8) 100%);">
|
||||
<div class="panel-title">AI处理前预警</div>
|
||||
<div class="panel-content">
|
||||
<div class="info-item">
|
||||
<span class="info-label">发布单位:</span>
|
||||
<span class="info-value">{{ beforeData.publishOrg }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">发布内容:</span>
|
||||
<span class="info-value content-text">{{ beforeData.publishContent }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">生效时间:</span>
|
||||
<span class="info-value">{{ beforeData.effectiveTime }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">失效时间:</span>
|
||||
<span class="info-value">{{ beforeData.expireTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间AI标识 -->
|
||||
<div class="ai-center">
|
||||
<img class="ai-icon-img" src="../../../assets/RiskWarning_img/AI1@2x.png" alt="AI" />
|
||||
<div class="ai-arrow">
|
||||
<el-icon><DArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI处理后预警 -->
|
||||
<div class="panel after-panel panel1" style="background: #2699FF">
|
||||
<div class="panel-title" style="color:#fff">AI处理后预警</div>
|
||||
<div class="panel-content">
|
||||
<!-- 标签页 -->
|
||||
<div class="tab-header">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === tab.key }"
|
||||
@click="activeTab = tab.key"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签内容 -->
|
||||
<div class="tab-content">
|
||||
<div class="info-item">
|
||||
<span class="info-label">预警等级:</span>
|
||||
<span class="info-value">{{ afterData.warningLevel }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">预警信息:</span>
|
||||
<span class="info-value content-text">{{ afterData.warningInfo }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">预警详情:</span>
|
||||
<span class="info-value content-text">{{ afterData.warningDetail }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close, DArrowRight } from "@element-plus/icons-vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
aiData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 标签页
|
||||
const tabs = ref([
|
||||
{ key: "frontline", label: "一线人员" },
|
||||
{ key: "district", label: "区县人员" },
|
||||
{ key: "handler", label: "处室人员" },
|
||||
{ key: "leader", label: "中心领导" },
|
||||
]);
|
||||
|
||||
const activeTab = ref("frontline");
|
||||
|
||||
// AI处理前数据
|
||||
const beforeData = ref({
|
||||
publishOrg: "潼南区预警中心",
|
||||
publishContent: '潼南区气象台2025年11月13日0时40分发布"暴雨蓝色预警信号",预计23日0:40-6:40,龙形、宝龙、上和、大佛、桂林、玉溪、米心、花岩、双江、古溪、群力、柏梓、崇龛、梓潼、太安等15个乡镇(街道)强降水趋于减弱,未来6小时累计雨量将达50~100毫米,最大小时雨强将达20~40毫米,局地伴有雷电、阵性大风,请各地注意防范。',
|
||||
effectiveTime: "2025-11-13 00:31:30.0",
|
||||
expireTime: "2025-11-13 00:31:30.0",
|
||||
});
|
||||
|
||||
// AI处理后数据
|
||||
const afterData = ref({
|
||||
warningLevel: "重庆市潼南气象台发布大雾黄色预警[III级/较重]",
|
||||
warningInfo: '潼南区区气象台发布暴雨红色预警,按照相关要求,启动I级防御响应,并请及时关注地质、水文等风险提示信息,落实主动封闭管控/"关停撒转"措施',
|
||||
warningDetail: "请立即按照2小时一次频率对你管养的重点路段/重点部位进行巡查,重点巡查较高及以上风险路段、涉灾隐患点、地质条件复杂路段、临河临崖路段/两区三厂、大型设施设备、取弃土(渣)场、砂石料场、涉水桥梁、富水隧道、围堰、支架脚手架、高切坡、滑坡处置等部位,重点关注涉水桥梁基础及墩台、不良地质隧道、隧道洞口边仰坡及侧切结构、高陡边坡支挡防护以及防排水设施,发现异常情况,立即向上报告,采取紧急排危、告警阻拦、吹哨撒转等措施,并及时报送工作开展情况。",
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.aiData) {
|
||||
Object.assign(beforeData.value, props.aiData.before);
|
||||
Object.assign(afterData.value, props.aiData.after);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ai-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.ai-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
// 面板
|
||||
.panel {
|
||||
flex: 1;
|
||||
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
border-radius: 12px;
|
||||
padding: 1px;
|
||||
background: linear-gradient(135deg, rgba(64, 169, 255, 0.5) 0%, transparent 50%, rgba(64, 169, 255, 0.5) 100%);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #40a9ff;
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.6;
|
||||
|
||||
&.content-text {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 中间AI标识
|
||||
.ai-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 0 10px;
|
||||
.ai-icon-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.ai-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 20px rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
.ai-arrow {
|
||||
font-size: 32px;
|
||||
color: #40a9ff;
|
||||
animation: pulse 1.5s infinite;
|
||||
|
||||
:deep(.el-icon) {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
}
|
||||
|
||||
// 标签页
|
||||
.tab-header {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
|
||||
.tab-item {
|
||||
padding: 6px 14px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
// background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
background: #163B6C;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
376
packages/screen/src/views/RiskWarning/component/baseDialog.vue
Normal file
376
packages/screen/src/views/RiskWarning/component/baseDialog.vue
Normal file
@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="props.visible"
|
||||
class="base-dialog-overlay"
|
||||
:style="{ zIndex: props.zIndex }"
|
||||
@click="handleOverlayClick"
|
||||
>
|
||||
<div class="base-dialog" @click.stop :style="{ maxWidth: `${props.maxWidth}px` }">
|
||||
<!-- 四个角的装饰 -->
|
||||
<div class="corner corner-top-left"></div>
|
||||
<div class="corner corner-top-right"></div>
|
||||
<div class="corner corner-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">{{ props.title }}</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<div class="header-slot">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section" v-if="props.showFilter">
|
||||
<slot name="filter"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section" v-if="props.tableData.length > 0">
|
||||
<el-table
|
||||
:data="props.tableData"
|
||||
:height="props.tableHeight"
|
||||
style="width: 100%"
|
||||
:header-cell-style="headerCellStyle"
|
||||
:cell-style="cellStyle"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="column in props.tableColumns"
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
>
|
||||
<template v-if="column.slot" #default="{ row }">
|
||||
<slot :name="column.slot" :row="row"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination" v-if="props.showPagination && props.tableData.length > 0">
|
||||
<el-pagination
|
||||
:current-page="props.currentPage"
|
||||
:page-size="props.pageSize"
|
||||
:page-sizes="props.pageSizes"
|
||||
:total="props.total"
|
||||
background
|
||||
layout="prev, pager, next, jumper, ->, total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { ElTable, ElTableColumn, ElPagination } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "弹窗标题",
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1000,
|
||||
},
|
||||
maxWidth: {
|
||||
type: Number,
|
||||
default: 1000,
|
||||
},
|
||||
showFilter: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showPagination: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tableColumns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tableHeight: {
|
||||
type: Number,
|
||||
default: 300,
|
||||
},
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
default: () => [10, 20, 30, 40],
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "size-change", "current-change", "update:current-page", "update:page-size"]);
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 弹窗打开时的逻辑
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
emit("update:page-size", val);
|
||||
emit("size-change", val);
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
emit("update:current-page", val);
|
||||
emit("current-change", val);
|
||||
};
|
||||
|
||||
// 表格样式
|
||||
const headerCellStyle = () => {
|
||||
return {
|
||||
backgroundColor: "#1D5194",
|
||||
color: "#fff",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
padding: "5px 0px",
|
||||
border: "none",
|
||||
};
|
||||
};
|
||||
|
||||
const cellStyle = () => {
|
||||
return {
|
||||
backgroundColor: "#16334E",
|
||||
color: "rgba(255, 255, 255, 0.85)",
|
||||
fontSize: "13px",
|
||||
textAlign: "center",
|
||||
padding: "5px 0px",
|
||||
border: "none",
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.base-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
:deep(.el-table--small) {
|
||||
background: #16334E;
|
||||
}
|
||||
|
||||
.base-dialog {
|
||||
width: 80vw;
|
||||
max-height: 80vh;
|
||||
position: relative;
|
||||
background: #16334e;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
// 四个角的装饰
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #40a9ff;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
|
||||
&.corner-top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
width: 100%;
|
||||
|
||||
.header-title {
|
||||
background-image: url("../../../assets/RiskWarning_img/标题@2x.png");
|
||||
background-size: 100% 100%;
|
||||
background-position: right;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标题栏下方自定义插槽
|
||||
.header-slot {
|
||||
margin-bottom: 20px;
|
||||
padding: 0 24px;
|
||||
overflow-y: auto;
|
||||
max-height: 70vh;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
width: 100%;
|
||||
padding: 0 24px;
|
||||
background: #16334E
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
background: #16334E;
|
||||
|
||||
:deep(.el-pagination) {
|
||||
background: #16334E;
|
||||
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-pagination__btn {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__item {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,590 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="clearance-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="clearance-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">抢通情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">行政区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
: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.controlMeasure" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in controlMeasureOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 50px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.routeNo }}</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<el-tooltip :content="item.stakeNo" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ item.stakeNo }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<el-tooltip :content="item.location" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ item.location }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="td" style="width: 140px">{{ item.occurrenceTime }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.routeNo2 }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.type }}</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<span :class="['control-tag', getControlClass(item.controlMeasure)]">{{ item.controlMeasure }}</span>
|
||||
</div>
|
||||
<div class="td" style="flex: 1">
|
||||
<span class="detail-link" @click="handleDetail(item)">详情</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, typeOptions, controlMeasureOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
type: "",
|
||||
controlMeasure: "",
|
||||
});
|
||||
|
||||
// 行政区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 类型选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 管控措施选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "50px" },
|
||||
{ label: "行政区域", width: "80px" },
|
||||
{ label: "线路编号", width: "80px" },
|
||||
{ label: "起止桩号", width: "100px" },
|
||||
{ label: "路况位置", width: "100px" },
|
||||
{ label: "发生时间", width: "140px" },
|
||||
{ label: "线路编号", width: "80px" },
|
||||
{ label: "类型", width: "80px" },
|
||||
{ label: "管控措施", width: "100px" },
|
||||
{ label: "操作", flex: "1" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "巫溪县",
|
||||
routeNo: "G242",
|
||||
stakeNo: "336.800-338.850",
|
||||
location: "三星乡五斗村",
|
||||
occurrenceTime: "2025-08-11 04:53:42",
|
||||
routeNo2: "G242",
|
||||
type: "边坡坍塌",
|
||||
controlMeasure: "全幅封闭",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
routeNo: "G242",
|
||||
stakeNo: "338.800-338.850",
|
||||
location: "三星乡五斗村",
|
||||
occurrenceTime: "2025-08-11 04:53:42",
|
||||
routeNo2: "G242",
|
||||
type: "边坡坍塌",
|
||||
controlMeasure: "正常通行",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "沙坪坝区",
|
||||
routeNo: "G319",
|
||||
stakeNo: "120.500-122.000",
|
||||
location: "沙坪坝镇",
|
||||
occurrenceTime: "2025-08-10 14:30:00",
|
||||
routeNo2: "G319",
|
||||
type: "路面塌陷",
|
||||
controlMeasure: "半幅封闭",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "渝中区",
|
||||
routeNo: "G212",
|
||||
stakeNo: "88.200-89.100",
|
||||
location: "渝中大道",
|
||||
occurrenceTime: "2025-08-09 09:15:30",
|
||||
routeNo2: "G212",
|
||||
type: "桥梁损坏",
|
||||
controlMeasure: "限制通行",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 获取管控措施样式类
|
||||
const getControlClass = (measure) => {
|
||||
const classMap = {
|
||||
"全幅封闭": "control-close",
|
||||
"半幅封闭": "control-half",
|
||||
"正常通行": "control-normal",
|
||||
"限制通行": "control-limit",
|
||||
};
|
||||
return classMap[measure] || "";
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.clearance-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.clearance-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.ellipsis-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 管控措施标签
|
||||
.control-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.control-close {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.control-half {
|
||||
background-color: rgba(255, 122, 0, 0.2);
|
||||
color: #ff7a00;
|
||||
border: 1px solid rgba(255, 122, 0, 0.4);
|
||||
}
|
||||
|
||||
&.control-normal {
|
||||
background-color: rgba(82, 196, 26, 0.2);
|
||||
color: #52c41a;
|
||||
border: 1px solid rgba(82, 196, 26, 0.4);
|
||||
}
|
||||
|
||||
&.control-limit {
|
||||
background-color: rgba(250, 219, 20, 0.2);
|
||||
color: #fadb14;
|
||||
border: 1px solid rgba(250, 219, 20, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
// 详情链接
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,535 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="control-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="control-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">管控情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">行政区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.riskLevel" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in riskLevelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 200px">
|
||||
<el-tooltip :content="item.stationName" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ item.stationName }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="td" style="width: 200px">
|
||||
<el-tooltip :content="item.project" placement="top" :show-after="500">
|
||||
<span class="ellipsis-text">{{ item.project }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="td" style="width: 80px">{{ item.peopleCount }}</div>
|
||||
<div class="td" style="flex: 1">
|
||||
<span :class="['risk-tag', getRiskClass(item.riskLevel)]">{{ item.riskLevel }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, riskLevelOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
riskLevel: "",
|
||||
});
|
||||
|
||||
// 行政区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 风险等级选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "行政区域", width: "100px" },
|
||||
{ label: "驻地名称", width: "200px" },
|
||||
{ label: "所属项目", width: "200px" },
|
||||
{ label: "驻地人数", width: "80px" },
|
||||
{ label: "驻地风险等级", flex: "1" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "沙坪坝区",
|
||||
stationName: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)项目经理部",
|
||||
project: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)",
|
||||
peopleCount: 21,
|
||||
riskLevel: "Ⅳ级",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
stationName: "万州区项目经理部",
|
||||
project: "万州区公路改造项目",
|
||||
peopleCount: 15,
|
||||
riskLevel: "Ⅲ级",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "渝中区",
|
||||
stationName: "渝中区桥梁维护项目部",
|
||||
project: "渝中区桥梁维护工程",
|
||||
peopleCount: 8,
|
||||
riskLevel: "Ⅱ级",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "江北区",
|
||||
stationName: "江北区道路施工项目部",
|
||||
project: "江北区道路施工项目",
|
||||
peopleCount: 32,
|
||||
riskLevel: "Ⅰ级",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 获取风险等级样式类
|
||||
const getRiskClass = (level) => {
|
||||
const classMap = {
|
||||
"Ⅰ级": "risk-level-1",
|
||||
"Ⅱ级": "risk-level-2",
|
||||
"Ⅲ级": "risk-level-3",
|
||||
"Ⅳ级": "risk-level-4",
|
||||
};
|
||||
return classMap[level] || "";
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.control-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.control-dialog {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.ellipsis-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 风险等级标签
|
||||
.risk-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.risk-level-1 {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-2 {
|
||||
background-color: rgba(255, 122, 0, 0.2);
|
||||
color: #ff7a00;
|
||||
border: 1px solid rgba(255, 122, 0, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-3 {
|
||||
background-color: rgba(250, 219, 20, 0.2);
|
||||
color: #fadb14;
|
||||
border: 1px solid rgba(250, 219, 20, 0.4);
|
||||
}
|
||||
|
||||
&.risk-level-4 {
|
||||
background-color: rgba(82, 196, 26, 0.2);
|
||||
color: #52c41a;
|
||||
border: 1px solid rgba(82, 196, 26, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,478 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="dispatch-detail-overlay" @click="handleOverlayClick">
|
||||
<div class="dispatch-detail-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">调度区县情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">行政区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 50px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.district }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.name }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.phone }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.type }}</div>
|
||||
<div class="td" style="width: 140px">{{ item.role }}</div>
|
||||
<div class="td" style="flex: 1">{{ item.dispatchTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions, typeOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
type: "",
|
||||
});
|
||||
|
||||
// 行政区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 类型选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "50px" },
|
||||
{ label: "区县/镇街", width: "100px" },
|
||||
{ label: "姓名", width: "80px" },
|
||||
{ label: "电话", width: "120px" },
|
||||
{ label: "类型", width: "100px" },
|
||||
{ label: "角色", width: "140px" },
|
||||
{ label: "调度时间", flex: "1" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
district: "柏梓镇",
|
||||
name: "赵海浪",
|
||||
phone: "18623520681",
|
||||
type: "交通主管部门",
|
||||
role: "一般人员(路长履职)",
|
||||
dispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
district: "柏梓镇",
|
||||
name: "赵海浪",
|
||||
phone: "18623520681",
|
||||
type: "公路机构",
|
||||
role: "一般人员(路长履职)",
|
||||
dispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
district: "万州区",
|
||||
name: "王鑫",
|
||||
phone: "18623520682",
|
||||
type: "养护站",
|
||||
role: "站长",
|
||||
dispatchTime: "2025-08-10 14:30:00",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
district: "沙坪坝区",
|
||||
name: "李华",
|
||||
phone: "18623520683",
|
||||
type: "护路员",
|
||||
role: "一般人员",
|
||||
dispatchTime: "2025-08-09 09:15:30",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dispatch-detail-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2100;
|
||||
}
|
||||
|
||||
.dispatch-detail-dialog {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,465 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="dispatch-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="dispatch-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">调度区县情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">行政区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<span class="dispatch-count" @click="handleDispatchClick(item)">{{ item.dispatchCount }}</span>
|
||||
</div>
|
||||
<div class="td" style="flex: 1">{{ item.lastDispatchTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { regionOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "dispatchClick"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
region: "",
|
||||
});
|
||||
|
||||
// 行政区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "行政区域", width: "120px" },
|
||||
{ label: "调度数", width: "100px" },
|
||||
{ label: "最近调度时间", flex: "1" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "重庆市",
|
||||
dispatchCount: 1,
|
||||
lastDispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "万州区",
|
||||
dispatchCount: 1,
|
||||
lastDispatchTime: "2025-08-11 04:53:42",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "沙坪坝区",
|
||||
dispatchCount: 3,
|
||||
lastDispatchTime: "2025-08-10 16:20:15",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: "渝中区",
|
||||
dispatchCount: 2,
|
||||
lastDispatchTime: "2025-08-09 11:45:30",
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 点击调度数
|
||||
const handleDispatchClick = (item) => {
|
||||
emit("dispatchClick", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dispatch-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.dispatch-dialog {
|
||||
width: 80vw;
|
||||
max-width: 700px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.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: 140px;
|
||||
|
||||
: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;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
// 调度数字
|
||||
.dispatch-count {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,655 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="impact-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="impact-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">影响点情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointType" placeholder="影响点类型" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in pointTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointLevel" placeholder="影响点等级" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in pointLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.region" placeholder="行政区域" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in regionOptionsWithAll"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 50px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.pointType }}</div>
|
||||
<div class="td" style="width: 180px">{{ item.pointLocation }}</div>
|
||||
<div class="td" style="width: 90px">
|
||||
<span class="level-tag" :class="item.levelClass">{{ item.pointLevel }}</span>
|
||||
</div>
|
||||
<div class="td" style="width: 130px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.trafficDept.name }}</span>
|
||||
<span class="person-phone">{{ item.trafficDept.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 110px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.roadOrg.name }}</span>
|
||||
<span class="person-phone">{{ item.roadOrg.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 110px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.maintenance.name }}</span>
|
||||
<span class="person-phone">{{ item.maintenance.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.roadKeeper.name }}</span>
|
||||
<span class="person-phone">{{ item.roadKeeper.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 60px">
|
||||
<span class="detail-link" @click="handleDetail(item)">详情</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, regionOptionsWithAll } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
pointType: "",
|
||||
pointLevel: "",
|
||||
region: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "50px" },
|
||||
{ label: "行政区域", width: "80px" },
|
||||
{ label: "影响点类型", width: "80px" },
|
||||
{ label: "影响点位置", width: "180px" },
|
||||
{ label: "影响点等级", width: "90px" },
|
||||
{ label: "交通主管部门负责人", width: "130px" },
|
||||
{ label: "公路机构责任人", width: "110px" },
|
||||
{ label: "养护站负责人", width: "110px" },
|
||||
{ label: "护路员", width: "100px" },
|
||||
{ label: "操作", width: "60px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: "重庆市",
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "13708320801" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 4;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
console.log("查询条件:", filterForm.value);
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 视频屏幕自适应 - 基于视口宽度动态调整
|
||||
@function vw($px) {
|
||||
@return calc($px / 1920 * 100vw);
|
||||
}
|
||||
|
||||
.impact-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.impact-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1200px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: vw(12);
|
||||
padding: vw(24);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: vw(20);
|
||||
|
||||
.header-title {
|
||||
font-size: vw(20);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: vw(8) vw(40);
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: vw(2) solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: vw(32);
|
||||
height: vw(32);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: vw(20);
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: vw(16);
|
||||
margin-bottom: vw(20);
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, rgba(30, 70, 120, 0.6) 0%, rgba(20, 50, 90, 0.8) 100%);
|
||||
border: vw(2) solid rgba(64, 169, 255, 0.4);
|
||||
border-radius: vw(8);
|
||||
padding: vw(16) vw(20);
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(64, 169, 255, 0.8);
|
||||
box-shadow: 0 0 20px rgba(64, 169, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: vw(8);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: vw(28);
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: vw(8);
|
||||
overflow: hidden;
|
||||
margin-bottom: vw(20);
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: vw(12) vw(16);
|
||||
|
||||
.th {
|
||||
font-size: vw(13);
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: vw(12) vw(16);
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
min-height: vw(60);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: vw(12);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
padding: 0 vw(4);
|
||||
|
||||
.level-tag {
|
||||
display: inline-block;
|
||||
padding: vw(2) vw(8);
|
||||
border-radius: vw(4);
|
||||
font-size: vw(11);
|
||||
|
||||
&.level-normal {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-serious {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.person-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: vw(2);
|
||||
|
||||
.person-name {
|
||||
font-size: vw(12);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.person-phone {
|
||||
font-size: vw(11);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: vw(12);
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: vw(16);
|
||||
|
||||
.total {
|
||||
font-size: vw(13);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: vw(8);
|
||||
|
||||
.page-btn {
|
||||
min-width: vw(28);
|
||||
height: vw(28);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: vw(4);
|
||||
font-size: vw(12);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: vw(6);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: vw(3);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: vw(3);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,516 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="response-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="response-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">潼南三级路长明细</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计数据卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><User /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">路长总人数</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.total }}</span>
|
||||
<span class="value-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><OfficeBuilding /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">县级路长</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.county }}</span>
|
||||
<span class="value-unit">公里</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="card-icon">
|
||||
<el-icon class="stat-icon"><MapLocation /></el-icon>
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<div class="card-label">乡、村路长</div>
|
||||
<div class="card-value">
|
||||
<span class="value-num">{{ stats.village }}</span>
|
||||
<span class="value-unit">次</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ index + 1 }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.district }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.name }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.phone }}</div>
|
||||
<div class="td" style="flex: 1">{{ item.role }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.position }}</div>
|
||||
<div class="td" style="width: 120px">
|
||||
<div class="action-btns">
|
||||
<div class="action-btn" @click="handleView(item)">
|
||||
<el-icon><VideoCamera /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleVoice(item)">
|
||||
<el-icon><Microphone /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleCall(item)">
|
||||
<el-icon><Phone /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, VideoCamera, Microphone, Phone, ArrowLeft, ArrowRight, User, OfficeBuilding, MapLocation } from "@element-plus/icons-vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
// 统计数据
|
||||
const stats = ref({
|
||||
total: 1127,
|
||||
county: 216,
|
||||
village: 1099,
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "区县/镇街", width: "120px" },
|
||||
{ label: "姓名", width: "100px" },
|
||||
{ label: "电话", width: "120px" },
|
||||
{ label: "角色", flex: "1" },
|
||||
{ label: "职务", width: "100px" },
|
||||
{ label: "操作", width: "120px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{ id: 1, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 2, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 3, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 4, district: "万州区柏梓镇", name: "赵海浪", phone: "1862352068", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 5, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 6, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 7, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 8, district: "万州区李河镇", name: "王建国", phone: "1398324567", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 9, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 10, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 11, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
{ id: 12, district: "万州区分水镇", name: "刘志强", phone: "1387654321", role: "一般人员(路长履职)", position: "其他" },
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 4;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 操作按钮
|
||||
const handleView = (item) => {
|
||||
console.log("查看视频:", item);
|
||||
};
|
||||
|
||||
const handleVoice = (item) => {
|
||||
console.log("语音通话:", item);
|
||||
};
|
||||
|
||||
const handleCall = (item) => {
|
||||
console.log("拨打电话:", item);
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.response-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.response-dialog {
|
||||
width: 70vw;
|
||||
max-width: 700px;
|
||||
max-height: 80vh;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.header-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 4px 24px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: linear-gradient(135deg, rgba(30, 80, 140, 0.6) 0%, rgba(20, 60, 110, 0.8) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
|
||||
.card-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.15);
|
||||
border-radius: 4px;
|
||||
|
||||
.stat-icon {
|
||||
font-size: 18px;
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
.card-label {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 2px;
|
||||
|
||||
.value-num {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 6px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
.value-unit {
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 8px 12px;
|
||||
|
||||
.th {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 30vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 10px 12px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.action-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
|
||||
.action-btn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.15);
|
||||
border-radius: 2px;
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
|
||||
.total {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
|
||||
.page-btn {
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
// 滚动条角落
|
||||
.table-body::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
@ -1,697 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="visible"
|
||||
class="response-status-dialog-overlay"
|
||||
@click="handleOverlayClick"
|
||||
>
|
||||
<div class="response-status-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.pointType"
|
||||
placeholder="影响点类型"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.pointLevel"
|
||||
placeholder="影响点等级"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
v-model="filterForm.isResponded"
|
||||
placeholder="是否回应"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in isRespondedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 50px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.pointType }}</div>
|
||||
<div class="td" style="width: 150px">{{ item.pointLocation }}</div>
|
||||
<div class="td" style="width: 90px">
|
||||
<span class="level-tag" :class="item.levelClass">{{
|
||||
item.pointLevel
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="td" style="width: 60px">{{ item.checkCount }}</div>
|
||||
<div class="td" style="width: 120px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.trafficDept.name }}</span>
|
||||
<span class="person-phone">{{ item.trafficDept.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 110px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.roadOrg.name }}</span>
|
||||
<span class="person-phone">{{ item.roadOrg.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 110px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.maintenance.name }}</span>
|
||||
<span class="person-phone">{{ item.maintenance.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 80px">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ item.roadKeeper.name }}</span>
|
||||
<span class="person-phone">{{ item.roadKeeper.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 70px">
|
||||
<span class="response-status" :class="item.responseClass">{{
|
||||
item.responseStatus
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="td" style="width: 110px">
|
||||
<div class="time-info">
|
||||
<span class="time-date">{{ item.urgeTime.date }}</span>
|
||||
<span class="time-clock">{{ item.urgeTime.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td" style="width: 50px">
|
||||
<span class="detail-link" @click="handleDetail(item)">详情</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div
|
||||
class="page-btn"
|
||||
:class="{ disabled: currentPage === 1 }"
|
||||
@click="prevPage"
|
||||
>
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div
|
||||
class="page-btn"
|
||||
:class="{ disabled: currentPage === totalPages }"
|
||||
@click="nextPage"
|
||||
>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, isRespondedOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
pointType: "",
|
||||
pointLevel: "",
|
||||
isResponded: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "50px" },
|
||||
{ label: "影响点类型", width: "80px" },
|
||||
{ label: "影响点位置", width: "150px" },
|
||||
{ label: "影响点等级", width: "90px" },
|
||||
{ label: "查次数", width: "60px" },
|
||||
{ label: "交通主管部门负责人", width: "120px" },
|
||||
{ label: "公路机构责任人", width: "110px" },
|
||||
{ label: "养护站负责人", width: "110px" },
|
||||
{ label: "护路员", width: "80px" },
|
||||
{ label: "回应状态", width: "70px" },
|
||||
{ label: "最新催告时间", width: "110px" },
|
||||
{ label: "操作", width: "50px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
checkCount: 2,
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "1372386532" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
responseStatus: "已回应",
|
||||
responseClass: "status-responded",
|
||||
urgeTime: { date: "2026-03-28", time: "12:30:00" },
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
pointType: "边坡",
|
||||
pointLocation: "武汉-大理(K1452+951至K1462+209)",
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
checkCount: 2,
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "1372386532" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
responseStatus: "已回应",
|
||||
responseClass: "status-responded",
|
||||
urgeTime: { date: "2026-03-28", time: "12:30:00" },
|
||||
},
|
||||
]);
|
||||
tableData.value.push(...tableData.value);
|
||||
tableData.value.push(...tableData.value);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 4;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.response-status-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.response-status-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1150px;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(20, 50, 90, 0.95) 0%,
|
||||
rgba(10, 30, 60, 0.98) 100%
|
||||
);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(64, 169, 255, 0.2) 20%,
|
||||
rgba(64, 169, 255, 0.2) 80%,
|
||||
transparent 100%
|
||||
);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.filter-select {
|
||||
width: 150px;
|
||||
|
||||
: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;
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 0;
|
||||
|
||||
.th {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 12px 0px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.level-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
|
||||
&.level-normal {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-serious {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.person-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.person-name {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.person-phone {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.response-status {
|
||||
font-size: 12px;
|
||||
|
||||
&.status-responded {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-unresponded {
|
||||
color: #ff7a45;
|
||||
}
|
||||
}
|
||||
|
||||
.time-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.time-date {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.time-clock {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
.total {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(30, 70, 120, 0.6) 0%,
|
||||
rgba(20, 50, 90, 0.8) 100%
|
||||
);
|
||||
border: 2px solid rgba(64, 169, 255, 0.4);
|
||||
border-radius: 8px;
|
||||
padding: 8px 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(64, 169, 255, 0.8);
|
||||
box-shadow: 0 0 20px rgba(64, 169, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,665 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="warning-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="warning-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.warningLevel" placeholder="预警等级" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in warningLevelOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.region" placeholder="行政区域" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in regionOptionsWithAll"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.isEnded" placeholder="是否结束" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in isEndedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.isResponded" placeholder="是否回应" class="filter-select">
|
||||
<el-option
|
||||
v-for="option in isRespondedOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ index + 1 }}</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<span class="warning-level" :class="item.levelClass">{{ item.warningLevel }}</span>
|
||||
</div>
|
||||
<div class="td" style="width: 100px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 160px">{{ item.warningTime }}</div>
|
||||
<div class="td" style="width: 160px">{{ item.endTime }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.impactPoints }}</div>
|
||||
<div class="td clickable-cell" style="width: 80px" @click.stop="handleCalledClick(item)">{{ item.called }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.responded }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.notResponded }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.urged }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, Search, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { warningLevelOptions, regionOptionsWithAll, isEndedOptions, isRespondedOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "openImpactPoint"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
warningLevel: "",
|
||||
region: "",
|
||||
isEnded: "",
|
||||
isResponded: "",
|
||||
});
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "预警等级", width: "100px" },
|
||||
{ label: "行政区域", width: "100px" },
|
||||
{ label: "预警时间", width: "160px" },
|
||||
{ label: "结束时间", width: "160px" },
|
||||
{ label: "影响点数量", width: "100px" },
|
||||
{ label: "已叫应", width: "80px" },
|
||||
{ label: "已回应", width: "80px" },
|
||||
{ label: "未回应", width: "80px" },
|
||||
{ label: "已催告", width: "80px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "万州区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 4,
|
||||
called: 2,
|
||||
responded: 2,
|
||||
notResponded: 2,
|
||||
urged: 22,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
warningLevel: "橙色预警",
|
||||
levelClass: "level-orange",
|
||||
region: "涪陵区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 18,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "万盛区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 15,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
warningLevel: "黄色预警",
|
||||
levelClass: "level-yellow",
|
||||
region: "长寿区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 20,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "城口区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 15,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "城口区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 15,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "城口区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 15,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
warningLevel: "红色预警",
|
||||
levelClass: "level-red",
|
||||
region: "城口区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactPoints: 0,
|
||||
called: 0,
|
||||
responded: 0,
|
||||
notResponded: 0,
|
||||
urged: 15,
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 4;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 点击已叫应
|
||||
const handleCalledClick = () => {
|
||||
emit("responseStatus");
|
||||
};
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
console.log("查询条件:", filterForm.value);
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.warning-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.warning-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.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;
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::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: 4px;
|
||||
padding: 0 20px;
|
||||
height: 32px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 12px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
&.clickable-cell {
|
||||
cursor: pointer;
|
||||
color: #40a9ff;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.warning-level {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.level-red {
|
||||
background-color: rgba(255, 77, 79, 0.2);
|
||||
color: #ff4d4f;
|
||||
border: 1px solid rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
&.level-orange {
|
||||
background-color: rgba(255, 122, 69, 0.2);
|
||||
color: #ff7a45;
|
||||
border: 1px solid rgba(255, 122, 69, 0.4);
|
||||
}
|
||||
|
||||
&.level-yellow {
|
||||
background-color: rgba(250, 219, 95, 0.2);
|
||||
color: #fadb5f;
|
||||
border: 1px solid rgba(250, 219, 95, 0.4);
|
||||
}
|
||||
|
||||
&.level-blue {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
color: #40a9ff;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
.total {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
:deep(.el-select-dropdown) {
|
||||
background-color: rgba(20, 50, 90, 0.98);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-select-dropdown__item {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(64, 169, 255, 0.3);
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,676 +0,0 @@
|
||||
<template>
|
||||
<div v-if="visible" class="warning-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="warning-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">预警情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">预警等级</span>
|
||||
<el-select v-model="filterForm.warningLevel" placeholder="请选择" class="filter-select" clearable>
|
||||
<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.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<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>
|
||||
<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="filterForm.dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
class="date-range-picker"
|
||||
width="210px"
|
||||
style="width: 210px"
|
||||
clearable
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 50px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 100px">
|
||||
<span :class="['warning-level-tag', getWarningClass(item.warningLevel)]">{{ item.warningLevel }}</span>
|
||||
</div>
|
||||
<div class="td" style="width: 100px">{{ item.weatherType }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 160px">{{ item.warningTime }}</div>
|
||||
<div class="td" style="width: 160px">{{ item.endTime }}</div>
|
||||
<div class="td" style="flex: 1">
|
||||
<span class="impact-count" @click="handleImpactClick(item)">{{ item.impactCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { warningLevelOptions, regionOptions, isEndedOptions } from "./index.js";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "impactClick"]);
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
warningLevel: "",
|
||||
region: "",
|
||||
isEnded: "",
|
||||
dateRange: [],
|
||||
});
|
||||
|
||||
// 预警等级选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 行政区域选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 是否结束选项
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "50px" },
|
||||
{ label: "预警等级", width: "100px" },
|
||||
{ label: "气象类型", width: "100px" },
|
||||
{ label: "行政区域", width: "100px" },
|
||||
{ label: "预警时间", width: "160px" },
|
||||
{ label: "结束时间", width: "160px" },
|
||||
{ label: "影响点数量", flex: "1" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
warningLevel: "红色预警",
|
||||
weatherType: "暴雨",
|
||||
region: "重庆市",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactCount: 0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
warningLevel: "橙色预警",
|
||||
weatherType: "暴雨",
|
||||
region: "万州区",
|
||||
warningTime: "2025-08-11 04:53:42",
|
||||
endTime: "2025-08-11 04:53:42",
|
||||
impactCount: 1,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
warningLevel: "黄色预警",
|
||||
weatherType: "大风",
|
||||
region: "沙坪坝区",
|
||||
warningTime: "2025-08-10 16:20:15",
|
||||
endTime: "2025-08-10 20:30:00",
|
||||
impactCount: 3,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
warningLevel: "蓝色预警",
|
||||
weatherType: "雷电",
|
||||
region: "渝中区",
|
||||
warningTime: "2025-08-09 09:15:30",
|
||||
endTime: "2025-08-09 12:00:00",
|
||||
impactCount: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
|
||||
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
|
||||
|
||||
const visiblePages = computed(() => {
|
||||
const pages = [];
|
||||
const maxVisible = 5;
|
||||
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
|
||||
let end = Math.min(totalPages.value, start + maxVisible - 1);
|
||||
|
||||
if (end - start + 1 < maxVisible) {
|
||||
start = Math.max(1, end - maxVisible + 1);
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
return pages;
|
||||
});
|
||||
|
||||
// 获取预警等级样式类
|
||||
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 handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// 点击影响点数量
|
||||
const handleImpactClick = (item) => {
|
||||
emit("impactClick", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
const fetchData = () => {
|
||||
console.log("获取第", currentPage.value, "页数据");
|
||||
// 实际项目中调用API获取数据
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.warning-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.warning-dialog {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date-range-picker {
|
||||
: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;
|
||||
background: transparent;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-input) {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-separator) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
// 预警等级标签
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// 日期选择器弹出面板深色主题
|
||||
.el-picker-panel {
|
||||
background: rgba(20, 50, 90, 0.98) !important;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3) !important;
|
||||
|
||||
.el-picker-panel__content {
|
||||
color: #fff;
|
||||
|
||||
.el-date-table th {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
border-bottom-color: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
|
||||
.el-date-table td {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&.selected .el-date-table-cell {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
}
|
||||
|
||||
&.today span {
|
||||
color: #40a9ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.in-range,
|
||||
&.start-date,
|
||||
&.end-date {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-picker-panel__footer {
|
||||
border-top: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-button {
|
||||
background: rgba(30, 70, 120, 0.4);
|
||||
border-color: rgba(64, 169, 255, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -249,7 +249,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ref, onMounted, provide } from "vue";
|
||||
import useMapStore from "@/map/stores/mapStore";
|
||||
import { useMapBase } from "../cockpit/composables/useMapBase";
|
||||
import left from "./left.vue";
|
||||
@ -259,26 +259,26 @@ import top from "./top.vue";
|
||||
import ChongqingMap from "./component/ChongqingMap.vue";
|
||||
|
||||
// 引入所有弹窗组件
|
||||
import responseSituationDiaLog from "./component/responseSituationDiaLog.vue";
|
||||
import warningInfoDialog from "./component/warningInfoDialog.vue";
|
||||
import eventDetailDialog from "./component/eventDetailDialog.vue";
|
||||
import confirmDialog from "./component/confirmDialog.vue";
|
||||
import riskPointDetailDialog from "./component/riskPointDetailDialog.vue";
|
||||
import impactPointDialog from "./component/impactPointDialog.vue";
|
||||
import impactPointDetailDialog from "./component/impactPointDetailDialog.vue";
|
||||
import responsePointDetailDialog from "./component/responsePointDetailDialog.vue";
|
||||
import responsePointInfoDialog from "./component/responsePointInfoDialog.vue";
|
||||
import responseStatusDialog from "./component/responseStatusDialog.vue";
|
||||
import aiWarningResultDialog from "./component/aiWarningResultDialog.vue";
|
||||
import tongnanInfoDialog from "./component/tongnanInfoDialog.vue";
|
||||
import tongnanResponsibleDialog from "./component/tongnanResponsibleDialog.vue";
|
||||
import clearanceSituationDialog from "./component/clearanceSituationDialog.vue";
|
||||
import controlSituationDialog from "./component/controlSituationDialog.vue";
|
||||
import dispatchDetailDialog from "./component/dispatchDetailDialog.vue";
|
||||
import dispatchDistrictDialog from "./component/dispatchDistrictDialog.vue";
|
||||
import tongnanTeamDialog from "./component/tongnanTeamDialog.vue";
|
||||
import warningSituationDialog from "./component/warningSituationDialog.vue";
|
||||
import tunnelInfoDialog from "./component/tunnelInfoDialog.vue";
|
||||
import responseSituationDiaLog from "./Dialog/responseSituationDiaLog.vue";
|
||||
import warningInfoDialog from "./Dialog/warningInfoDialog.vue";
|
||||
import eventDetailDialog from "./Dialog/eventDetailDialog.vue";
|
||||
import confirmDialog from "./Dialog/confirmDialog.vue";
|
||||
import riskPointDetailDialog from "./Dialog/riskPointDetailDialog.vue";
|
||||
import impactPointDialog from "./Dialog/impactPointDialog.vue";
|
||||
import impactPointDetailDialog from "./Dialog/impactPointDetailDialog.vue";
|
||||
import responsePointDetailDialog from "./Dialog/responsePointDetailDialog.vue";
|
||||
import responsePointInfoDialog from "./Dialog/responsePointInfoDialog.vue";
|
||||
import responseStatusDialog from "./Dialog/responseStatusDialog.vue";
|
||||
import aiWarningResultDialog from "./Dialog/aiWarningResultDialog.vue";
|
||||
import tongnanInfoDialog from "./Dialog/tongnanInfoDialog.vue";
|
||||
import tongnanResponsibleDialog from "./Dialog/tongnanResponsibleDialog.vue";
|
||||
import clearanceSituationDialog from "./Dialog/clearanceSituationDialog.vue";
|
||||
import controlSituationDialog from "./Dialog/controlSituationDialog.vue";
|
||||
import dispatchDetailDialog from "./Dialog/dispatchDetailDialog.vue";
|
||||
import dispatchDistrictDialog from "./Dialog/dispatchDistrictDialog.vue";
|
||||
import tongnanTeamDialog from "./Dialog/tongnanTeamDialog.vue";
|
||||
import warningSituationDialog from "./Dialog/warningSituationDialog.vue";
|
||||
import tunnelInfoDialog from "./Dialog/tunnelInfoDialog.vue";
|
||||
|
||||
// 弹窗显示状态
|
||||
const dialogVisible = ref({
|
||||
@ -301,7 +301,7 @@ const dialogVisible = ref({
|
||||
dispatchDistrict: false,
|
||||
tongnanTeam: false,
|
||||
warningSituation: false,
|
||||
tunnelInfo: false,
|
||||
tunnelInfo: false
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
@ -333,6 +333,25 @@ const openConfirm = (config) => {
|
||||
// 中心信息卡片显示状态
|
||||
const showCenterCard = ref(false);
|
||||
|
||||
// 兄弟组件通信机制
|
||||
const refreshLeftData = ref(null);
|
||||
|
||||
// 提供刷新函数给子组件
|
||||
const setRefreshLeftData = (callback) => {
|
||||
refreshLeftData.value = callback;
|
||||
};
|
||||
|
||||
// 触发刷新函数
|
||||
const triggerRefreshLeftData = () => {
|
||||
if (refreshLeftData.value) {
|
||||
refreshLeftData.value();
|
||||
}
|
||||
};
|
||||
|
||||
// 提供通信机制给子组件
|
||||
provide('setRefreshLeftData', setRefreshLeftData);
|
||||
provide('triggerRefreshLeftData', triggerRefreshLeftData);
|
||||
|
||||
// ==================== 地图状态管理 ====================
|
||||
|
||||
const mapStore = useMapStore();
|
||||
@ -405,27 +424,27 @@ onMounted(() => {
|
||||
|
||||
.title_img2 {
|
||||
height: vw(40);
|
||||
min-height: 28px;
|
||||
min-height: 40px;
|
||||
width: auto;
|
||||
max-width: vw(300);
|
||||
width: vw(550);
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: vw(90);
|
||||
top: vw(60);
|
||||
width: 25%;
|
||||
height: calc(100% - #{vw(90)});
|
||||
height: calc(100% - #{vw(60)});
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: vw(90);
|
||||
top: vw(60);
|
||||
width: 25%;
|
||||
height: calc(100% - #{vw(90)});
|
||||
height: calc(100% - #{vw(60)});
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@ -485,14 +504,14 @@ onMounted(() => {
|
||||
pointer-events: none;
|
||||
|
||||
&.corner-top-left {
|
||||
top: vw(110);
|
||||
top: vw(60);
|
||||
left: vw(10);
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-top-right {
|
||||
top: vw(110);
|
||||
top: vw(60);
|
||||
right: vw(10);
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
@ -574,7 +593,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.info-unit {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
|
||||
@ -57,10 +57,10 @@
|
||||
>
|
||||
<div
|
||||
class="bar"
|
||||
:style="{ height: getBarHeight(item.value) + '%' }"
|
||||
:style="{ height: getBarHeight(item) + '%' }"
|
||||
></div>
|
||||
<div class="bar-value">{{ item.value }}</div>
|
||||
<div class="bar-label">{{ item.label }}</div>
|
||||
<div class="bar-value">{{ item.count }}</div>
|
||||
<div class="bar-label">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-x-label">类型</div>
|
||||
@ -71,13 +71,13 @@
|
||||
<div class="road-type-section">
|
||||
<div class="section-title">影响公路类型情况</div>
|
||||
<div class="road-type-cards">
|
||||
<div class="road-card">
|
||||
<span class="card-label">国省道:</span>
|
||||
<span class="card-value">100</span>
|
||||
</div>
|
||||
<div class="road-card">
|
||||
<span class="card-label">农村公路:</span>
|
||||
<span class="card-value">300</span>
|
||||
<div
|
||||
class="road-card"
|
||||
v-for="(item, index) in roadTypeData"
|
||||
:key="index"
|
||||
>
|
||||
<span class="card-label">{{ item.extension }}:</span>
|
||||
<span class="card-value">{{ item.count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -99,11 +99,15 @@
|
||||
:scroll="{ y: true }"
|
||||
>
|
||||
<el-table-column prop="name" label="区县名称" :min-width="vw(80)" />
|
||||
<el-table-column prop="road" label="路段" :min-width="vw(50)" />
|
||||
<el-table-column prop="bridge" label="桥梁" :min-width="vw(50)" />
|
||||
<el-table-column prop="tunnel" label="隧道" :min-width="vw(50)" />
|
||||
<el-table-column prop="slope" label="边坡" :min-width="vw(50)" />
|
||||
<el-table-column prop="project" label="项目" :min-width="vw(50)" />
|
||||
<el-table-column
|
||||
prop="roadSectionCount"
|
||||
label="路段"
|
||||
:min-width="vw(50)"
|
||||
/>
|
||||
<el-table-column prop="bridgeCount" label="桥梁" :min-width="vw(50)" />
|
||||
<el-table-column prop="tunnelCount" label="隧道" :min-width="vw(50)" />
|
||||
<el-table-column prop="slopeCount" label="边坡" :min-width="vw(50)" />
|
||||
<el-table-column prop="projectCount" label="项目" :min-width="vw(50)" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
@ -123,6 +127,7 @@
|
||||
size="small"
|
||||
popper-class="dark-date-picker"
|
||||
:prefix-icon="Calendar"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -157,13 +162,7 @@
|
||||
<div
|
||||
v-for="(item, index) in dispatchList"
|
||||
:key="index"
|
||||
class="dispatch-card"
|
||||
:class="{
|
||||
clickable:
|
||||
item.label === '国省道调度清单' ||
|
||||
item.label === '农村公路调度清单' ||
|
||||
item.label === '建设工程调度清单',
|
||||
}"
|
||||
class="dispatch-card clickable"
|
||||
@click="handleDispatchCardClick(item)"
|
||||
>
|
||||
<div class="card-num">
|
||||
@ -177,10 +176,55 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { ref, computed, onMounted, watch, inject } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
|
||||
import SectionHeader from "./component/sectionHeader.vue";
|
||||
// 导入图片资源
|
||||
import imgCall from "../../assets/RiskWarning_img/回应icon@2x.png";
|
||||
import imgReply from "../../assets/RiskWarning_img/已回应icon@2x.png";
|
||||
import imgRate from "../../assets/RiskWarning_img/回应率icon@2x.png";
|
||||
import imgDistrict from "../../assets/RiskWarning_img/区县icon@2x.png";
|
||||
import imgHelp from "../../assets/RiskWarning_img/响应图标5@2x.png";
|
||||
import imgCheck from "../../assets/RiskWarning_img/抽查人数icon@2x.png";
|
||||
|
||||
// 注入兄弟组件通信机制
|
||||
const setRefreshLeftData = inject('setRefreshLeftData');
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// loadData();
|
||||
// loadBarChartData();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
if (props.visible) {
|
||||
init();
|
||||
}
|
||||
|
||||
// 注册刷新函数给父组件
|
||||
if (setRefreshLeftData) {
|
||||
setRefreshLeftData(init);
|
||||
}
|
||||
});
|
||||
const init = () => {
|
||||
roadTypeLoad();
|
||||
districtLoadLoad();
|
||||
dispatchLoadLoad();
|
||||
loadData();
|
||||
loadBarChartData();
|
||||
};
|
||||
|
||||
const emit = defineEmits([
|
||||
"openWarningInfo",
|
||||
@ -215,94 +259,248 @@ const handleImpactDetailClick = () => {
|
||||
|
||||
// 点击调度清单卡片
|
||||
const handleDispatchCardClick = (item) => {
|
||||
if (item.label === "建设工程调度清单") {
|
||||
emit("showCenterCard", {
|
||||
type: "first",
|
||||
value: item.value,
|
||||
});
|
||||
} else if (item.label === "国省道调度清单") {
|
||||
if (item.label === dispatchList.value[0].label) {
|
||||
emit("showCenterCard", {
|
||||
type: "second",
|
||||
value: item.value,
|
||||
});
|
||||
} else if (item.label === "农村公路调度清单") {
|
||||
} else if (item.label === dispatchList.value[1].label) {
|
||||
emit("showCenterCard", {
|
||||
type: "third",
|
||||
value: item.value,
|
||||
});
|
||||
} else if (item.label === dispatchList.value[2].label) {
|
||||
emit("showCenterCard", {
|
||||
type: "first",
|
||||
value: item.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 导入图片资源
|
||||
import imgCall from "../../assets/RiskWarning_img/回应icon@2x.png";
|
||||
import imgReply from "../../assets/RiskWarning_img/已回应icon@2x.png";
|
||||
import imgRate from "../../assets/RiskWarning_img/回应率icon@2x.png";
|
||||
import imgDistrict from "../../assets/RiskWarning_img/区县icon@2x.png";
|
||||
import imgHelp from "../../assets/RiskWarning_img/响应图标5@2x.png";
|
||||
import imgCheck from "../../assets/RiskWarning_img/抽查人数icon@2x.png";
|
||||
|
||||
// 气象预警数据
|
||||
const weatherWarningData = ref([
|
||||
{ label: "红色预警", value: "", class: "red" },
|
||||
{ label: "橙色预警", value: "", class: "orange" },
|
||||
{ label: "黄色预警", value: "", class: "yellow" },
|
||||
{ label: "蓝色预警", value: "", class: "blue" },
|
||||
{ label: "红色预警", value: "0", class: "red" },
|
||||
{ label: "橙色预警", value: "0", class: "orange" },
|
||||
{ label: "黄色预警", value: "0", class: "yellow" },
|
||||
{ label: "蓝色预警", value: "0", class: "blue" },
|
||||
]);
|
||||
|
||||
// 影响点数据
|
||||
const impactData = ref([
|
||||
{ label: "路段", value: 830 },
|
||||
{ label: "桥梁", value: 312 },
|
||||
{ label: "隧道", value: 405 },
|
||||
{ label: "边坡", value: 634 },
|
||||
{ label: "项目", value: 523 },
|
||||
{ name: "路段", count: 830 },
|
||||
{ name: "桥梁", count: 312 },
|
||||
{ name: "隧道", count: 405 },
|
||||
{ name: "边坡", count: 634 },
|
||||
{ name: "项目", count: 523 },
|
||||
]);
|
||||
|
||||
// 日期范围选择器
|
||||
// 日期选择器变化事件
|
||||
const handleDateChange = (val) => {
|
||||
dateRange.value = val;
|
||||
dispatchLoadLoad();
|
||||
};
|
||||
// 日期选择器数据
|
||||
const dateRange = ref([]);
|
||||
// 调度清单数据
|
||||
const dispatchLoadLoad = async () => {
|
||||
try {
|
||||
// 处理日期参数,开始时间为当天00:00:00,结束时间为当天23:59:59
|
||||
let startTime = "";
|
||||
let endTime = "";
|
||||
|
||||
if (dateRange.value && dateRange.value.length === 2) {
|
||||
const startDate = new Date(dateRange.value[0]);
|
||||
const endDate = new Date(dateRange.value[1]);
|
||||
|
||||
// 开始时间设置为当天00:00:00
|
||||
startDate.setHours(0, 0, 0, 0);
|
||||
startTime = startDate.getTime();
|
||||
|
||||
// 结束时间设置为当天23:59:59
|
||||
endDate.setHours(23, 59, 59, 999);
|
||||
endTime = endDate.getTime();
|
||||
}
|
||||
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weather-warning/schedule-statistics",
|
||||
method: "GET",
|
||||
params: {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
},
|
||||
});
|
||||
console.log(res);
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data) {
|
||||
responseStats.value.forEach((item) => {
|
||||
if (item.label == "叫应总数") {
|
||||
item.value = data["noticeCount"] || 0;
|
||||
} else if (item.label == "已回应数") {
|
||||
item.value = data["replyCount"] || 0;
|
||||
} else if (item.label == "回应率") {
|
||||
item.value =
|
||||
data["replyPrecent"] >= 0 ? data["replyPrecent"] + "%" : 0;
|
||||
} else if (item.label == "调度区县数") {
|
||||
item.value = data["countyCount"] || 0;
|
||||
} else if (item.label == "线下帮扶数") {
|
||||
item.value = data["supportCount"] || 0;
|
||||
} else if (item.label == "抽查人次") {
|
||||
item.value = data["inspectionCount"] || 0;
|
||||
}
|
||||
});
|
||||
dispatchList.value.forEach((item) => {
|
||||
if (item.label == "国省道调度") {
|
||||
item.value = data["nationalRoadCount"] || 0;
|
||||
} else if (item.label == "农村公路调度") {
|
||||
item.value = data["ruralRoadCount"] || 0;
|
||||
} else if (item.label == "建设工程调度") {
|
||||
item.value = data["projectCount"] || 0;
|
||||
}
|
||||
});
|
||||
// responseStats.value = data;
|
||||
// dispatchList.value = data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载数据失败:", error);
|
||||
}
|
||||
};
|
||||
// 区县数据
|
||||
const districtLoadLoad = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weather-warning/affected-count/_by_county",
|
||||
method: "GET",
|
||||
});
|
||||
console.log(res);
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data) {
|
||||
districtData.value = data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载数据失败:", error);
|
||||
}
|
||||
};
|
||||
const roadTypeData = ref([]);
|
||||
// 公路类型数据
|
||||
const roadTypeLoad = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weather-warning/affected-count/_by_road",
|
||||
method: "GET",
|
||||
});
|
||||
console.log(res);
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data) {
|
||||
roadTypeData.value = data.reverse();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载数据失败:", error);
|
||||
}
|
||||
};
|
||||
// 加载气象预警和影响点数据
|
||||
const loadData = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weatherWarning/statistics",
|
||||
url: "/snow-ops-platform/weather-warning/warning-count",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data) {
|
||||
let obj = {};
|
||||
data.forEach((item) => {
|
||||
obj[item.name] = item.count || 0;
|
||||
});
|
||||
console.log(obj);
|
||||
weatherWarningData.value.forEach((item) => {
|
||||
if (item.label == "红色预警") {
|
||||
item.value = data.redWarningCount || 0;
|
||||
item.value =
|
||||
obj["warning-red-count"] + "/" + obj["warning-red-total"] ||
|
||||
"0/0";
|
||||
} else if (item.label == "橙色预警") {
|
||||
item.value = data.orangeWarningCount || 0;
|
||||
item.value =
|
||||
obj["warning-orange-count"] + "/" + obj["warning-orange-total"] ||
|
||||
"0/0";
|
||||
} else if (item.label == "黄色预警") {
|
||||
item.value = data.yellowWarningCount || 0;
|
||||
item.value =
|
||||
obj["warning-yellow-count"] + "/" + obj["warning-yellow-total"] ||
|
||||
"0/0";
|
||||
} else if (item.label == "蓝色预警") {
|
||||
item.value = data.blueWarningCount || 0;
|
||||
item.value =
|
||||
obj["warning-blue-count"] + "/" + obj["warning-blue-total"] ||
|
||||
"0/0";
|
||||
}
|
||||
});
|
||||
}
|
||||
if (data.impactData) {
|
||||
impactData.value = data.impactData;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载数据失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载柱状图数据
|
||||
const loadBarChartData = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weather-warning/affected-count",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data && Array.isArray(data)) {
|
||||
// 英文转中文映射
|
||||
const nameMap = {
|
||||
"road-section": "路段",
|
||||
bridge: "桥梁",
|
||||
tunnel: "隧道",
|
||||
slope: "边坡",
|
||||
project: "项目",
|
||||
Road: "路段",
|
||||
Bridge: "桥梁",
|
||||
Tunnel: "隧道",
|
||||
Slope: "边坡",
|
||||
Project: "项目",
|
||||
};
|
||||
|
||||
// 转换英文name为中文
|
||||
const convertedData = data.map((item) => {
|
||||
const name = nameMap[item.name] || item.name;
|
||||
return { ...item, name };
|
||||
});
|
||||
|
||||
impactData.value = convertedData;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载柱状图数据失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 计算最大值用于动态计算高度
|
||||
const maxValue = computed(() => {
|
||||
return Math.max(...impactData.value.map((item) => item.value));
|
||||
// 计算所有影响点的总和
|
||||
const totalValue = computed(() => {
|
||||
let total = 0;
|
||||
impactData.value.forEach((item) => {
|
||||
total += item.count || 0;
|
||||
});
|
||||
return total;
|
||||
});
|
||||
|
||||
// 计算每个柱子的高度百分比
|
||||
const getBarHeight = (value) => {
|
||||
// 确保最小高度为20%,最大高度为100%
|
||||
const height = (value / maxValue) * 100;
|
||||
return Math.min(100, Math.max(20, Math.round(height)));
|
||||
const actualValue = value.count || value.value;
|
||||
// 确保最小高度为10%,最大高度为100%
|
||||
const height = (actualValue / totalValue.value) * 200;
|
||||
// 确保高度差异明显,至少有5%的差异
|
||||
return Math.min(100, Math.max(10, Math.round(height)));
|
||||
};
|
||||
const handleAIClick = () => {
|
||||
emit("openAIResult");
|
||||
@ -319,17 +517,22 @@ const tableHeight = computed(() => {
|
||||
});
|
||||
|
||||
// 区县数据
|
||||
const districtData = [
|
||||
{ name: "江北区", road: 1, bridge: 1, tunnel: 1, slope: 8, project: 11 },
|
||||
{ name: "江北区", road: 1, bridge: 1, tunnel: 1, slope: 8, project: 11 },
|
||||
{ name: "南岸区", road: 1, bridge: 2, tunnel: 2, slope: 6, project: 12 },
|
||||
{ name: "九龙坡区", road: 2, bridge: 1, tunnel: 1, slope: 9, project: 9 },
|
||||
{ name: "九龙坡区", road: 2, bridge: 1, tunnel: 1, slope: 9, project: 9 },
|
||||
{ name: "万州区", road: 1, bridge: 2, tunnel: 2, slope: 11, project: 7 },
|
||||
];
|
||||
const districtData = ref([
|
||||
{ extension: "江北区", road: 1, bridge: 1, tunnel: 1, slope: 8, project: 11 },
|
||||
{ extension: "南岸区", road: 1, bridge: 2, tunnel: 2, slope: 6, project: 12 },
|
||||
{
|
||||
extension: "九龙坡区",
|
||||
road: 2,
|
||||
bridge: 1,
|
||||
tunnel: 1,
|
||||
slope: 9,
|
||||
project: 9,
|
||||
},
|
||||
{ extension: "万州区", road: 1, bridge: 2, tunnel: 2, slope: 11, project: 7 },
|
||||
]);
|
||||
|
||||
// 响应调度统计数据
|
||||
const responseStats = [
|
||||
const responseStats = ref([
|
||||
{
|
||||
label: "叫应总数",
|
||||
value: "15",
|
||||
@ -366,14 +569,14 @@ const responseStats = [
|
||||
iconClass: "icon-check",
|
||||
img: imgCheck,
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
// 调度清单数据
|
||||
const dispatchList = [
|
||||
{ label: "国省道调度清单", value: "341" },
|
||||
{ label: "农村公路调度清单", value: "210" },
|
||||
{ label: "建设工程调度清单", value: "120" },
|
||||
];
|
||||
const dispatchList = ref([
|
||||
{ label: "国省道调度", value: "341" },
|
||||
{ label: "农村公路调度", value: "210" },
|
||||
{ label: "建设工程调度", value: "120" },
|
||||
]);
|
||||
|
||||
const headerCellStyle = () => ({
|
||||
background: "rgba(64, 169, 255, 0.1)",
|
||||
@ -393,10 +596,6 @@ const cellStyle = () => ({
|
||||
textAlign: "center",
|
||||
lineHeight: "1.2",
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -534,7 +733,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(16);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
@ -596,7 +795,7 @@ onMounted(() => {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: vw(-10);
|
||||
font-size: vw(11);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
@ -661,7 +860,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.bar-value {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
font-weight: bold;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-bottom: vw(5);
|
||||
@ -677,13 +876,13 @@ onMounted(() => {
|
||||
rgba(64, 169, 255, 0.3) 100%
|
||||
);
|
||||
border-radius: 2px 2px 0 0;
|
||||
min-height: 20px;
|
||||
// min-height: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.bar-label {
|
||||
bottom: vw(-20);
|
||||
font-size: vw(10);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
transition: all 0.3s ease;
|
||||
position: absolute;
|
||||
@ -695,7 +894,7 @@ onMounted(() => {
|
||||
position: absolute;
|
||||
right: vw(-15);
|
||||
bottom: 0;
|
||||
font-size: vw(10);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
@ -831,7 +1030,7 @@ onMounted(() => {
|
||||
&::before {
|
||||
content: "←";
|
||||
color: #fff;
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -911,7 +1110,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
@ -967,7 +1166,7 @@ onMounted(() => {
|
||||
margin-bottom: vw(6);
|
||||
|
||||
.unit {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-weight: normal;
|
||||
margin-left: 2px;
|
||||
@ -975,7 +1174,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: vw(10);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +472,7 @@ const majorEvent = "0";
|
||||
align-items: center;
|
||||
.resource-label {
|
||||
width: 48%;
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-bottom: vw(2);
|
||||
}
|
||||
@ -483,7 +483,7 @@ const majorEvent = "0";
|
||||
color: #18F2F9;
|
||||
|
||||
.unit {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-weight: normal;
|
||||
margin-left: 2px;
|
||||
@ -516,8 +516,11 @@ const majorEvent = "0";
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
background: rgba(62, 106, 172, 0.36);
|
||||
box-shadow: inset 0px 0px 8px 0px #379bff;
|
||||
// background: rgba(62, 106, 172, 0.36);
|
||||
// box-shadow: inset 0px 0px 8px 0px #379bff;
|
||||
background-image: url("../../assets/RiskWarning_img/路径 62@2x.png");
|
||||
background-size: 100% 100%;
|
||||
background-position: right;
|
||||
gap: vw(8);
|
||||
|
||||
.control-item {
|
||||
@ -544,7 +547,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
@ -597,7 +600,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
.patrol-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
@ -667,7 +670,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
.rescue-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
@ -755,7 +758,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
.block-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@ -768,7 +771,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
.death-label {
|
||||
font-size: vw(10);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
@ -805,14 +808,14 @@ const majorEvent = "0";
|
||||
margin-bottom: vw(6);
|
||||
|
||||
.unit {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
font-weight: normal;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.damage-label {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@ -843,7 +846,7 @@ const majorEvent = "0";
|
||||
background-position: left;
|
||||
|
||||
.event-title {
|
||||
font-size: vw(12);
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
|
||||
@ -20,13 +20,28 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, watch, inject } from "vue";
|
||||
import { Calendar } from "@element-plus/icons-vue";
|
||||
|
||||
const emit = defineEmits(["openAIResult"]);
|
||||
|
||||
// 注入兄弟组件通信机制
|
||||
const triggerRefreshLeftData = inject('triggerRefreshLeftData');
|
||||
|
||||
const dateRange = ref([]);
|
||||
|
||||
// 监听 dateRange 变化
|
||||
watch(dateRange, (newVal, oldVal) => {
|
||||
// 只有当值真正发生变化时才触发
|
||||
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
|
||||
console.log('dateRange 发生变化:', newVal);
|
||||
// 触发兄弟组件刷新
|
||||
if (triggerRefreshLeftData) {
|
||||
triggerRefreshLeftData();
|
||||
}
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
const handleAIClick = () => {
|
||||
emit("openAIResult");
|
||||
};
|
||||
@ -88,8 +103,8 @@ const handleAIClick = () => {
|
||||
height: 2.6em !important;
|
||||
}
|
||||
:deep(.el-date-editor) {
|
||||
width: vw(200);
|
||||
max-width: vw(200);
|
||||
width: 180px;
|
||||
max-width: vw(350);
|
||||
background: #183c67;
|
||||
box-shadow: inset 0px 0px 8px 0px #4fecff;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user