代码提交
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<!-- 谐波放大表格详情 -->
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
title="详情"
|
||||
draggable
|
||||
width="1000px"
|
||||
@close="handleCloseDialog"
|
||||
style="height: 600px"
|
||||
>
|
||||
<MyEChart :options="[]" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
|
||||
const visible = ref(false);
|
||||
const options = ref<any>(null);
|
||||
|
||||
const open = () => {
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
visible.value = false;
|
||||
options.value = null;
|
||||
};
|
||||
|
||||
// const showCharts = (row: any, valueType: number, name: string) => {
|
||||
// getHistoryLineData({
|
||||
// lineId: row.lineId,
|
||||
// number: row.number,
|
||||
// phaseType: row.phaseType,
|
||||
// searchTime: row.timeId,
|
||||
// targetCode: row.targetCode,
|
||||
// valueType,
|
||||
// }).then((res) => {
|
||||
// options.value = {
|
||||
// title: {
|
||||
// text:
|
||||
// row.subName +
|
||||
// " " +
|
||||
// row.lineName +
|
||||
// " " +
|
||||
// row.targetName +
|
||||
// " " +
|
||||
// row.phaseType +
|
||||
// "相" +
|
||||
// name,
|
||||
// },
|
||||
// legend: {
|
||||
// show: false,
|
||||
// },
|
||||
// xAxis: {
|
||||
// type: "category",
|
||||
// name: "时间",
|
||||
// data: res.data[0]?.value.map((item: any[]) => item[0]),
|
||||
// },
|
||||
// yAxis: {
|
||||
// name: "%",
|
||||
// type: "value",
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// name: name,
|
||||
// data: res.data[0]?.value.map((item: any[]) => item[1]),
|
||||
// type: "line",
|
||||
// },
|
||||
// ],
|
||||
// options: {
|
||||
// grid: {
|
||||
// top: "50px",
|
||||
// left: "40px",
|
||||
// right: "60px",
|
||||
// bottom: "10px",
|
||||
// containLabel: true,
|
||||
// },
|
||||
// dataZoom: null,
|
||||
// },
|
||||
// };
|
||||
// });
|
||||
// };
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="责任度计算"
|
||||
draggable
|
||||
width="1700px"
|
||||
style="height: 875px"
|
||||
@close="handleClose"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="currentPosition">
|
||||
当前位置:{{ alias || "" }}
|
||||
</div>
|
||||
<el-tabs v-model="activeName" class="demo-tabs">
|
||||
<el-tab-pane label="系统" name="1">
|
||||
<system @setTitle="setTitle" v-if="activeName == '1'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="配网" name="2">
|
||||
<distributionNetwork @setTitle="setTitle" v-if="activeName == '2'" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, reactive } from "vue";
|
||||
import distributionNetwork from "./distributionNetwork.vue";
|
||||
import system from "./system.vue";
|
||||
|
||||
const visible = ref(false);
|
||||
const alias = ref("");
|
||||
|
||||
const activeName = ref("1");
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
onMounted(() => {});
|
||||
const setTitle = (title: string) => {
|
||||
alias.value = title;
|
||||
};
|
||||
const emit = defineEmits(["showCalculation", "close-dialog"]); // 打开弹窗
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
// 通知父组件显示收集界面
|
||||
emit("showCalculation", false);
|
||||
emit("close-dialog"); // 关闭弹窗
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.currentPosition {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:close-on-click-modal="false"
|
||||
title="用采数据管理"
|
||||
draggable
|
||||
>
|
||||
<el-form label-width="auto" :model="form" inline class="formBox">
|
||||
<el-form-item label="关键字">
|
||||
<el-input
|
||||
v-model="form.searchValue"
|
||||
placeholder="关键字查询"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
size="small"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="mt5">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Search"
|
||||
size="small"
|
||||
@click="getTableData"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button type="primary" :icon="Plus" size="small" @click="uploadFile"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="400px"
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
v-loading="loading1"
|
||||
element-loading-background="#343849c7"
|
||||
border
|
||||
>
|
||||
<el-table-column prop="name" align="center" label="表名" />
|
||||
<el-table-column
|
||||
prop="startTime"
|
||||
align="center"
|
||||
label="起始时间"
|
||||
width="150"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="endTime"
|
||||
align="center"
|
||||
label="截止时间"
|
||||
width="150"
|
||||
/>
|
||||
<el-table-column prop="updateTime" align="center" label="更新时间" />
|
||||
<el-table-column fixed="right" align="center" label="操作" width="140">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
size="small"
|
||||
v-if="row.integrity == 1"
|
||||
@click="handleClick(row)"
|
||||
>完整性详情</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
size="small"
|
||||
@click.stop="handleDelete(row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
<!-- 详情 -->
|
||||
<completenessDetails ref="completenessDetailsRef" @close="close" />
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
draggable
|
||||
title="上传数据"
|
||||
width="500"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
action=""
|
||||
v-model:file-list="fileList"
|
||||
accept=".xlsx,.xls"
|
||||
:auto-upload="false"
|
||||
:on-change="choose"
|
||||
:limit="2"
|
||||
>
|
||||
<el-button type="primary" :icon="Upload" size="small">上传文件</el-button>
|
||||
</el-upload>
|
||||
<template #footer>
|
||||
<el-button @click="handleClose" size="small">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="submitupload"
|
||||
:loading="loading"
|
||||
size="small"
|
||||
>确认</el-button
|
||||
>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, reactive } from "vue";
|
||||
import completenessDetails from "./completenessDetails.vue";
|
||||
import type { UploadInstance } from "element-plus";
|
||||
import { Search, Plus, Upload, Download } from "@element-plus/icons-vue";
|
||||
import { useStore } from "vuex";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
import {
|
||||
userDataList,
|
||||
uploadUserData,
|
||||
deleteUserDataByIds,
|
||||
} from "@/api/manage_wx";
|
||||
const store = useStore();
|
||||
const visible = ref(false);
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const form = reactive({
|
||||
searchValue: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
|
||||
const completenessDetailsRef = ref();
|
||||
const dialogVisible = ref(false);
|
||||
const upload = ref<UploadInstance>();
|
||||
const fileList = ref([]);
|
||||
const loading = ref(false);
|
||||
const loading1 = ref(false);
|
||||
|
||||
// 关闭上传弹框
|
||||
const handleClose = () => {
|
||||
fileList.value = [];
|
||||
dialogVisible.value = false;
|
||||
visible.value = true;
|
||||
getTableData();
|
||||
};
|
||||
// 详情关闭弹框
|
||||
const close = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
// 新增
|
||||
const uploadFile = () => {
|
||||
dialogVisible.value = true;
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// 上传
|
||||
const choose = (e: any) => {
|
||||
upload.value!.clearFiles();
|
||||
setTimeout(() => {
|
||||
if (e.name.includes(".xls")) {
|
||||
fileList.value = [e];
|
||||
} else {
|
||||
ElMessage.warning("请上传Excel文件!");
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// 上传
|
||||
const submitupload = async () => {
|
||||
if (fileList.value.length == 0) {
|
||||
ElMessage.warning("请上传文件!");
|
||||
return;
|
||||
}
|
||||
ElMessage.info("上传中,请稍等...");
|
||||
const formData = new FormData();
|
||||
formData.append("file", fileList.value[0].raw);
|
||||
loading.value = true;
|
||||
uploadUserData(formData)
|
||||
.then((res) => {
|
||||
ElMessage.success("上传成功");
|
||||
loading.value = false;
|
||||
handleClose();
|
||||
// tableStore.index();
|
||||
})
|
||||
.catch((err) => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
// provide("tableStore", tableStore);
|
||||
// tableStore.table.params.searchValue = "";
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading1.value = true;
|
||||
// form.deptId = store.state.deptId;
|
||||
const res: any = await userDataList(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading1.value = false;
|
||||
};
|
||||
|
||||
// 完整性详情
|
||||
const handleClick = (row) => {
|
||||
visible.value = false;
|
||||
completenessDetailsRef.value.open(row);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm("确定删除?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
deleteUserDataByIds([row.id]).then(() => {
|
||||
ElMessage.success("删除成功");
|
||||
getTableData();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: "info",
|
||||
message: "删除取消",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"表名",
|
||||
"起始时间",
|
||||
"截止时间",
|
||||
"更新时间",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await userDataList({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.name,
|
||||
item.startTime,
|
||||
item.endTime,
|
||||
item.updateTime,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "用采数据管理");
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, "用采数据管理" + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
:deep(.el-upload-list__item-name) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.el-upload-list__item:hover) {
|
||||
.el-upload-list__item-name {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
title="完整性不足详情"
|
||||
:before-close="handleClose"
|
||||
width="1000px"
|
||||
>
|
||||
<div class="formBox">
|
||||
<el-form label-width="70px" :model="form" inline>
|
||||
<el-form-item label="关键字">
|
||||
<el-input
|
||||
style="width: 150px"
|
||||
v-model="form.searchValue"
|
||||
placeholder="关键字查询"
|
||||
clearable
|
||||
size="small"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Search"
|
||||
size="small"
|
||||
@click="getTableData"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="400px"
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
border
|
||||
>
|
||||
<el-table-column prop="userNo" align="center" label="户号" />
|
||||
<el-table-column prop="userName" align="center" label="用户名" />
|
||||
<el-table-column
|
||||
prop="lineNo"
|
||||
align="center"
|
||||
label="测量点局号"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="updateTime"
|
||||
align="center"
|
||||
label="日期"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="integrity"
|
||||
align="center"
|
||||
label="完整性(%)"
|
||||
width="130"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ Math.floor(row.integrity * 10000) / 100 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, onMounted } from "vue";
|
||||
import { Search, Download } from "@element-plus/icons-vue";
|
||||
import { userDataIntegrityList } from "@/api/manage_wx";
|
||||
import { useStore } from "vuex";
|
||||
import * as XLSX from "xlsx";
|
||||
const emits = defineEmits(["close"]);
|
||||
const store = useStore();
|
||||
const machineVisible = ref(false);
|
||||
const form = reactive({
|
||||
searchValue: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
userDataId: "",
|
||||
});
|
||||
const loading = ref(false);
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
//form表单校验规则
|
||||
const open = (row) => {
|
||||
machineVisible.value = true;
|
||||
form.searchValue = "";
|
||||
form.pageNum = 1;
|
||||
form.pageSize = 20;
|
||||
form.userDataId = row.id;
|
||||
|
||||
getTableData();
|
||||
};
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
const res: any = await userDataIntegrityList(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
const handleClose = () => {
|
||||
machineVisible.value = false;
|
||||
emits("close");
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
let columnExpor: any = [
|
||||
["户号", "用户名", "测量点局号", "日期", "完整性(%)"],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await userDataIntegrityList({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.userNo,
|
||||
item.userName,
|
||||
item.lineNo,
|
||||
item.updateTime,
|
||||
Math.floor(item.integrity * 10000) / 100,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "完整性不足详情");
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, "完整性不足详情" + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
title="暂降事件"
|
||||
width="1200px"
|
||||
>
|
||||
<div class="tableBox">
|
||||
<div style="display: flex;justify-content: flex-end;">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="443px"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
style="margin-top: 13px;"
|
||||
>
|
||||
<!-- <el-table-column type="index" align="center" label="序号" width="70" /> -->
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="startTime"
|
||||
align="center"
|
||||
label="发生时间"
|
||||
show-overflow-tooltip
|
||||
width="160"
|
||||
/>
|
||||
<el-table-column prop="stationName" align="center" label="变电站" />
|
||||
<el-table-column prop="lineName" align="center" label="监测点" />
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
label="用户"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<span>{{ scope.row.objName ? scope.row.objName : "/" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="eventType"
|
||||
align="center"
|
||||
label="触发类型"
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="featureAmplitude"
|
||||
align="center"
|
||||
label="残余电压(%)"
|
||||
width="100"
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<span>{{ (scope.row.featureAmplitude * 100).toFixed(2) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="duration"
|
||||
align="center"
|
||||
label="持续时间(S)"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column fixed="right" label="操作" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="trendCharts(scope.row)"
|
||||
>波形</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
<!-- 波形图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close="handleCloseTrend"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject } from "vue";
|
||||
import { eventListByLineId } from "@/api/manage_wx";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import * as XLSX from "xlsx";
|
||||
import { Download } from "@element-plus/icons-vue";
|
||||
|
||||
const machineVisible = ref(false);
|
||||
const form = reactive({
|
||||
lineId: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
searchBeginTime: "",
|
||||
searchEndTime: "",
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const loading = ref(false);
|
||||
const tableData = ref([]);
|
||||
import { useStore } from "vuex";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const trendVisible = ref(false);
|
||||
|
||||
const waveFormRef = ref();
|
||||
//点击波形图
|
||||
const trendCharts = (row: any) => {
|
||||
row.eventdetail_index = row.eventId;
|
||||
machineVisible.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open({
|
||||
...row,
|
||||
bdname: row.stationName,
|
||||
pointname: row.lineName,
|
||||
timeid: row.startTime,
|
||||
eventvalue: row.featureAmplitude,
|
||||
persisttime: row.duration,
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 关闭波形图
|
||||
const handleCloseTrend = () => {
|
||||
trendVisible.value = false;
|
||||
machineVisible.value = true;
|
||||
};
|
||||
const open = async (id: any) => {
|
||||
form.pageNum = 1;
|
||||
form.pageSize = 20;
|
||||
form.lineId = id;
|
||||
machineVisible.value = true;
|
||||
await init();
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
eventListByLineId({
|
||||
lineId: form.lineId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
}).then((res) => {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
init();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
init();
|
||||
};
|
||||
|
||||
// 暂降溯源导出
|
||||
const exportTable = async () => {
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"发生时间",
|
||||
"变电站",
|
||||
"监测点",
|
||||
"用户",
|
||||
"触发类型",
|
||||
"残余电压(%)",
|
||||
"持续时间(S)",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await eventListByLineId({
|
||||
lineId: form.lineId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.startTime,
|
||||
item.stationName,
|
||||
item.lineName,
|
||||
item.objName,
|
||||
item.eventType,
|
||||
(item.featureAmplitude * 100).toFixed(2),
|
||||
item.duration,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "暂降事件");
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, "暂降事件" + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,558 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
title="暂降事件"
|
||||
width="1000px"
|
||||
>
|
||||
<div class="tableBox">
|
||||
<el-form
|
||||
:inline="true"
|
||||
style="display: flex; justify-content: space-between"
|
||||
>
|
||||
<el-form-item label="关键字筛选">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="电站、测点、用户信息"
|
||||
></el-input>
|
||||
<el-popover placement="bottom" :width="550" trigger="click">
|
||||
<template #reference>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="DArrowRight"
|
||||
type="primary"
|
||||
style="margin-left: 10px"
|
||||
>更多</el-button
|
||||
>
|
||||
</template>
|
||||
|
||||
<el-form label-width="auto">
|
||||
<!-- <el-form-item label="关键字筛选">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="电站、测点、用户信息"
|
||||
></el-input>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="运维单位">
|
||||
<el-tree-select
|
||||
v-model="deptsIndex"
|
||||
:data="deptsList"
|
||||
:render-after-expand="false"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 150px"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
}"
|
||||
/>
|
||||
<!-- <el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="触发类型">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
v-model="eventForm.eventType"
|
||||
placeholder="请选择触发类型"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in eventTypeList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="残余电压百分比">
|
||||
<el-input-number
|
||||
v-model="eventForm.eventValueMin"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventValueMin = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>%</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
<span> < 残余电压 < </span>
|
||||
|
||||
<el-input-number
|
||||
v-model="eventForm.eventValueMax"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventValueMax = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>%</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item label="暂降持续事时间">
|
||||
<el-input-number
|
||||
v-model="eventForm.eventDurationMin"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="1000000"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventDurationMin = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>ms</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
<span> < 持续时间 < </span>
|
||||
|
||||
<el-input-number
|
||||
v-model="eventForm.eventDurationMax"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="1000000"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventDurationMax = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>ms</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="margin-right: -10px">
|
||||
<el-button size="small" :icon="Search" type="primary" @click="init()"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button size="small" :icon="RefreshLeft" @click="clearInit()"
|
||||
>重置</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
style="margin-right: 10px"
|
||||
>导出
|
||||
</el-button>
|
||||
<el-button
|
||||
style="margin-right: 10px"
|
||||
v-if="displayValue == 1"
|
||||
size="small"
|
||||
:icon="HelpFilled"
|
||||
type="primary"
|
||||
@click="handleAggregation"
|
||||
>溯源</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- <div style="float: right; margin-bottom: 9px" v-if="displayValue == 1">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="HelpFilled"
|
||||
type="primary"
|
||||
@click="handleAggregation"
|
||||
>聚合</el-button
|
||||
>
|
||||
</div> -->
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="443px"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<!-- <el-table-column type="index" align="center" label="序号" width="70" /> -->
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="startTime"
|
||||
align="center"
|
||||
label="发生时间"
|
||||
show-overflow-tooltip
|
||||
width="160"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="stationName"
|
||||
align="center"
|
||||
label="变电站"
|
||||
width="120"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="lineName"
|
||||
align="center"
|
||||
label="监测点"
|
||||
width="120"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
label="用户"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<span>{{ scope.row.objName ? scope.row.objName : "/" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="eventType"
|
||||
align="center"
|
||||
label="触发类型"
|
||||
width="90"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="featureAmplitude"
|
||||
align="center"
|
||||
label="残余电压(%)"
|
||||
width="90"
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<span>{{ (scope.row.featureAmplitude * 100).toFixed(2) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="duration"
|
||||
align="center"
|
||||
label="持续时间(S)"
|
||||
width="90"
|
||||
/>
|
||||
<el-table-column fixed="right" label="操作" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="trendCharts(scope.row)"
|
||||
>波形</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
<!-- 波形图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close="handleCloseTrend"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, onMounted, watch } from "vue";
|
||||
import {
|
||||
getEventList,
|
||||
processEvents,
|
||||
loginDeptTree,
|
||||
getDicDataByTypeCode,
|
||||
} from "@/api/manage_wx";
|
||||
import { HelpFilled } from "@element-plus/icons-vue";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import {
|
||||
DArrowRight,
|
||||
Search,
|
||||
RefreshLeft,
|
||||
Download,
|
||||
} from "@element-plus/icons-vue";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
// 定义 emit
|
||||
const emit = defineEmits(["aggregation-success"]);
|
||||
|
||||
const machineVisible = ref(false);
|
||||
const form = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const loading = ref(false);
|
||||
const tableData = ref([]);
|
||||
import { useStore } from "vuex";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const displayValue = ref();
|
||||
|
||||
const trendVisible = ref(false);
|
||||
|
||||
const waveFormRef = ref();
|
||||
|
||||
const open = async (val) => {
|
||||
displayValue.value = val;
|
||||
machineVisible.value = true;
|
||||
await init();
|
||||
};
|
||||
|
||||
// 查询
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const deptsList = ref([]); //部门列表
|
||||
const eventTypeList = ref([]); //触发类型
|
||||
const eventForm: any = reactive({
|
||||
eventValueMin: null,
|
||||
eventValueMax: null,
|
||||
eventDurationMin: null,
|
||||
eventDurationMax: null,
|
||||
eventType: null,
|
||||
});
|
||||
|
||||
const clearInit = async () => {
|
||||
searchValue.value = "";
|
||||
eventForm.eventValueMin = null;
|
||||
eventForm.eventValueMax = null;
|
||||
eventForm.eventDurationMin = null;
|
||||
eventForm.eventDurationMax = null;
|
||||
eventForm.eventType = null;
|
||||
deptsIndex.value = null;
|
||||
|
||||
await init();
|
||||
};
|
||||
|
||||
// 部门
|
||||
const initDept = () => {
|
||||
loginDeptTree({
|
||||
deptIndex: store.state.deptId,
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
// 触发类型
|
||||
const dicDataByTypeCode = () => {
|
||||
getDicDataByTypeCode({
|
||||
dictTypeCode: "Event_Statis",
|
||||
}).then((res: any) => {
|
||||
eventTypeList.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
getEventList({
|
||||
deptId: store.state.deptId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: form.pageNum,
|
||||
pageSize: form.pageSize,
|
||||
searchValue: searchValue.value,
|
||||
...eventForm,
|
||||
eventValueMin:
|
||||
eventForm.eventValueMin == null ? null : eventForm.eventValueMin / 100,
|
||||
eventValueMax:
|
||||
eventForm.eventValueMax == null ? null : eventForm.eventValueMax / 100,
|
||||
}).then((res) => {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleAggregation = (row: any) => {
|
||||
machineVisible.value = false;
|
||||
ElMessageBox.confirm(
|
||||
`是否确认对当前用户部门${store.state.timeValue[0]}至${store.state.timeValue[1]}之间的暂降事件进行溯源?`,
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
processEvents({
|
||||
deptId: store.state.deptId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: res.message,
|
||||
});
|
||||
// 通知父组件执行 initialAggregation
|
||||
emit("aggregation-success");
|
||||
} else {
|
||||
ElMessage({
|
||||
type: "warning",
|
||||
message: res.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((error) => {});
|
||||
};
|
||||
|
||||
//点击波形图
|
||||
const trendCharts = (row: any) => {
|
||||
row.eventdetail_index = row.eventId;
|
||||
machineVisible.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open({
|
||||
...row,
|
||||
bdname: row.stationName,
|
||||
pointname: row.lineName,
|
||||
timeid: row.startTime,
|
||||
eventvalue: row.featureAmplitude,
|
||||
persisttime: row.duration,
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 关闭波形图
|
||||
const handleCloseTrend = () => {
|
||||
trendVisible.value = false;
|
||||
machineVisible.value = true;
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
init();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
init();
|
||||
};
|
||||
|
||||
// 暂降溯源导出
|
||||
const exportTable = async () => {
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"发生时间",
|
||||
"变电站",
|
||||
"监测点",
|
||||
"用户",
|
||||
"触发类型",
|
||||
"残余电压(%)",
|
||||
"持续时间(S)",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await getEventList({
|
||||
deptId: store.state.deptId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
searchValue: searchValue.value,
|
||||
...eventForm,
|
||||
eventValueMin:
|
||||
eventForm.eventValueMin == null ? null : eventForm.eventValueMin / 100,
|
||||
eventValueMax:
|
||||
eventForm.eventValueMax == null ? null : eventForm.eventValueMax / 100,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.startTime,
|
||||
item.stationName,
|
||||
item.lineName,
|
||||
item.objName,
|
||||
item.eventType,
|
||||
(item.featureAmplitude * 100).toFixed(2),
|
||||
item.duration,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "暂降事件");
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, "暂降事件" + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initDept();
|
||||
dicDataByTypeCode();
|
||||
});
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,701 @@
|
||||
<template>
|
||||
<!-- 配网计算 -->
|
||||
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes">
|
||||
<pane :size="20">
|
||||
<PointTree :showSelect="false" @node-click="handleNodeClick" @init="handleNodeClick"></PointTree>
|
||||
</pane>
|
||||
|
||||
<pane style="background-color: rgba(44, 46, 60, 0.1)" :size="100 - size">
|
||||
|
||||
<el-form :model="form" inline label-width="auto">
|
||||
<el-form-item label="谐波类型">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio-button label="谐波电压" size="small" value="1" />
|
||||
<el-radio-button label="谐波电流" size="small" value="0" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="谐波次数">
|
||||
<el-select v-model="form.index" filterable multiple :multiple-limit="5" collapse-tags collapse-tags-tooltip
|
||||
clearable placeholder="请选择次数" style="width: 200px" size="small">
|
||||
<el-option v-for="item in 49" :key="item" :label="item + 1 + '次'" :value="item + 1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="负荷数据">
|
||||
<el-select v-model="form.loadDataId" clearable filterable placeholder="请选择负荷数据" style="width: 200px"
|
||||
size="small">
|
||||
<el-option v-for="item in loadDataOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<!-- <el-button type="primary" icon="el-icon-Plus" @click="push('/admin/division/aListOfLoadData')">
|
||||
新增
|
||||
</el-button> -->
|
||||
<el-button type="primary" :icon="Select" @click="submit" size="small">确定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="activeName" v-if="showTabs" style="height: 740px">
|
||||
<el-tab-pane v-for="(item, index) in tabList" :key="item" :label="item.label" :name="index"
|
||||
style="height: 100%">
|
||||
<div>
|
||||
<div>
|
||||
<span style="color: #fff">时间范围</span>
|
||||
<el-date-picker v-model="item.time" class="mr10 ml10" type="daterange" start-placeholder="起始时间"
|
||||
end-placeholder="结束时间" format="YYYY-MM-DD" date-format="YYYY-MM-DD" time-format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD" :disabled-date="handleDisabledDate" size="small" />
|
||||
<el-button type="primary" :icon="CaretRight" @click="execute(item, index)" size="small">
|
||||
执行
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="item.showEcahr == 1" class="harmonicButton">
|
||||
<el-form :inline="true" v-model="item.form">
|
||||
<el-form-item label="限值" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.limit" placeholder="请选择限值" disabled style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 0 ? 'frontBox' : '']" @click="setCode(0)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点一" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.time1" placeholder="请选择时间点一" disabled style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 1 ? 'frontBox' : '']" @click="setCode(1)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点二" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.time2" placeholder="请选择时间点二" disabled style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 2 ? 'frontBox' : '']" @click="setCode(2)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-button type="primary" :icon="Document" @click="generateFn" v-if="!item.showDynamic" size="small">
|
||||
生成动态谐波责任数据
|
||||
</el-button>
|
||||
<el-button type="primary" :icon="Document" v-else @click="generateMetrics" size="small">
|
||||
生成谐波责任指标
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="box" v-loading="loading" element-loading-background="#343849c7">
|
||||
<MyEChart :options="item.options" v-if="item.showEcahr == 1" @group="group" />
|
||||
<el-empty description="时间范围内无谐波数据" v-if="item.showEcahr == 2" />
|
||||
</div>
|
||||
<!-- 生成动态谐波责任数据 -->
|
||||
<div class="box boxTab" v-loading="loading1" element-loading-background="#343849c7">
|
||||
<MyEChart :options="item.dynamicOptions" style="flex: 1" v-if="item.showDynamic" />
|
||||
<div style="width: 500px" v-if="item.showDynamic" class="tableBox">
|
||||
<el-table :scrollbar-always-on="true" ref="tableRef" :data="item.dynamicData" height="280px"
|
||||
size="small" :header-cell-style="{ textAlign: 'center' }" border>
|
||||
<el-table-column prop="customerName" align="center" label="用户名(用户号)" />
|
||||
<el-table-column prop="responsibilityData" align="center" label="责任数据(%)" width="120">
|
||||
<template #default="scope">
|
||||
{{
|
||||
Math.floor(scope.row.responsibilityData * 10000) /
|
||||
10000
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, reactive } from "vue";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import PointTree from "@/components/tree/pointTree.vue";
|
||||
import { Edit, Right } from "@element-plus/icons-vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
import { timeFormat } from "@/utils/common";
|
||||
import { yMethod } from "@/utils/echartMethod";
|
||||
import { Select, CaretRight, Document } from "@element-plus/icons-vue";
|
||||
import {
|
||||
userDataList,
|
||||
getHistoryHarmData,
|
||||
getDynamicData,
|
||||
getResponsibilityData,
|
||||
} from "@/api/manage_wx";
|
||||
const emit = defineEmits(["setTitle"]); // 打开弹窗
|
||||
const visible = ref(false);
|
||||
const size = ref(0);
|
||||
const dotList: any = ref({});
|
||||
const form: any = reactive({
|
||||
type: "1",
|
||||
index: [],
|
||||
loadDataId: "",
|
||||
});
|
||||
|
||||
const loadDataOptions: any = ref([]);
|
||||
const code = ref(3);
|
||||
const xAxisData = ref([]);
|
||||
const loading = ref(false);
|
||||
const loading1 = ref(false);
|
||||
const tabList: any = ref([]);
|
||||
const activeName = ref(0);
|
||||
const xValue = ref("");
|
||||
const showTabs = ref(false);
|
||||
|
||||
// 设置时间
|
||||
const timeFrame = ref(["", ""]);
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleNodeClick = (data: any) => {
|
||||
if (data.level == 6) {
|
||||
dotList.value = data;
|
||||
setTimeout(() => {
|
||||
emit("setTitle", data.alias);
|
||||
}, 0)
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// 处理日期禁用逻辑
|
||||
const handleDisabledDate = (date) => {
|
||||
// 定义时间边界
|
||||
const startLimit = new Date(timeFrame.value[0]).getTime() - 86400000; //向前推1天
|
||||
const endLimit = new Date(timeFrame.value[1]).setHours(23, 59, 59, 999);
|
||||
|
||||
// 如果日期不存在(选择今天时可能出现),不禁用
|
||||
if (!date) return false;
|
||||
|
||||
// 禁用 2025-08-01 之前和 2025-08-31 之后的日期
|
||||
return date.getTime() < startLimit || date.getTime() > endLimit;
|
||||
};
|
||||
// 这是按钮变色
|
||||
const setCode = (num: number) => {
|
||||
if (code.value == num) {
|
||||
return (code.value = 3);
|
||||
}
|
||||
code.value = num;
|
||||
};
|
||||
|
||||
// 确定
|
||||
const submit = () => {
|
||||
if (form.loadDataId == "") {
|
||||
return ElMessage.warning("请选择负荷数据");
|
||||
}
|
||||
if (form.index.length == 0) {
|
||||
return ElMessage.warning("请选择谐波次数");
|
||||
}
|
||||
|
||||
if (form.index.length == 0) {
|
||||
showTabs.value = false;
|
||||
} else {
|
||||
let timeList = loadDataOptions.value.filter(
|
||||
(item: any) => item.id == form.loadDataId
|
||||
)[0];
|
||||
showTabs.value = true;
|
||||
let list = JSON.parse(JSON.stringify(form.index)).sort((a, b) => a - b);
|
||||
tabList.value = [];
|
||||
list.forEach((item: any) => {
|
||||
tabList.value.push({
|
||||
label: item + "次谐波",
|
||||
key: item,
|
||||
time: [timeList.startTime, timeList.endTime],
|
||||
showExecute: false,
|
||||
form: {
|
||||
limit: "",
|
||||
time1: "",
|
||||
time2: "",
|
||||
},
|
||||
showEcahr: 3, //1显示echart 2显示无数据 3什么都没有
|
||||
options: {},
|
||||
dynamicOptions: {}, //动态echarts
|
||||
dynamicList: {}, //动态echarts
|
||||
showDynamic: false, //动态执行展示
|
||||
});
|
||||
timeFrame.value = [timeList.startTime, timeList.endTime];
|
||||
});
|
||||
code.value = 3;
|
||||
activeName.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 执行
|
||||
const execute = async (item: any, index: number) => {
|
||||
tabList.value[activeName.value].showDynamic = false;
|
||||
loading.value = true;
|
||||
await getHistoryHarmData({
|
||||
searchBeginTime: item.time[0],
|
||||
searchEndTime: item.time[1],
|
||||
type: form.type,
|
||||
time: item.key,
|
||||
lineId: dotList.value.id,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
let [min, max] = yMethod(
|
||||
res.data.historyData.map((item: any) => item.value + 0.1)
|
||||
);
|
||||
xAxisData.value = res.data.historyData.map((item: any) => item.time);
|
||||
tabList.value[index].options = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
xValue.value = params[0].value[0];
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 50,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
series: [
|
||||
{
|
||||
name: item.key + (form.type == 1 ? "次谐波电压" : "次谐波电流"),
|
||||
data: res.data.historyData.map((item: any) => [
|
||||
item.time,
|
||||
Math.floor(item.value * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
|
||||
markLine: {
|
||||
symbol: "none", // 去除箭头
|
||||
label: {
|
||||
show: false, // 隐藏标签
|
||||
},
|
||||
data: [
|
||||
{
|
||||
yAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
],
|
||||
// 样式配置
|
||||
lineStyle: {
|
||||
color: "red",
|
||||
type: "dashed", // 虚线
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
tabList.value[index].showEcahr = 1; //显示echart
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
tabList.value[index].showEcahr = 2;
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
tabList.value[index].showEcahr = 2;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const resDataId = ref("");
|
||||
// 生成动态谐波责任数据
|
||||
const generateFn = async () => {
|
||||
loading1.value = true;
|
||||
await getDynamicData({
|
||||
lineId: dotList.value.id,
|
||||
searchBeginTime: tabList.value[activeName.value].time[0],
|
||||
searchEndTime: tabList.value[activeName.value].time[1],
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
userDataId: form.loadDataId,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
resDataId.value = res.data.responsibilityDataIndex;
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) =>
|
||||
timeFormat(item)
|
||||
);
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
}
|
||||
loading1.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
|
||||
// 生成指标
|
||||
const generateMetrics = async () => {
|
||||
if (tabList.value[activeName.value].form.limit == "")
|
||||
return ElMessage.warning("请选择限值!");
|
||||
if (tabList.value[activeName.value].form.time1 == "")
|
||||
return ElMessage.warning("请选择时间一!");
|
||||
if (tabList.value[activeName.value].form.time2 == "")
|
||||
return ElMessage.warning("请选择时间二!");
|
||||
loading1.value = true;
|
||||
await getResponsibilityData({
|
||||
limitEndTime: tabList.value[activeName.value].form.time2,
|
||||
limitStartTime: tabList.value[activeName.value].form.time1,
|
||||
limitValue: tabList.value[activeName.value].form.limit,
|
||||
resDataId: resDataId.value,
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
})
|
||||
.then((res: any) => {
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) => timeFormat(item));
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
// 监听echart点击
|
||||
const group = (chart: any, myChartDom: any) => {
|
||||
myChartDom.addEventListener("click", function (event: any) {
|
||||
// 获取点击位置相对于图表容器的坐标
|
||||
const rect = myChartDom.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
const pointInPixel = [x, y];
|
||||
// 转换为逻辑坐标(相对于图表坐标系)
|
||||
const pointInGrid = chart.convertFromPixel({ gridIndex: 0 }, pointInPixel);
|
||||
// 计算X轴和Y轴的对应数据
|
||||
|
||||
// 处理X轴数据(分类轴)
|
||||
|
||||
// 处理Y轴数据(数值轴)
|
||||
let yValue = pointInGrid[1].toFixed(4);
|
||||
// xValue = timeFormat(pointInGrid[0].toFixed(0) - 0)
|
||||
if (code.value == 0) {
|
||||
tabList.value[activeName.value].form.limit = yValue;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[0].yAxis =
|
||||
yValue;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 1) {
|
||||
tabList.value[activeName.value].form.time1 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[1].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 2) {
|
||||
tabList.value[activeName.value].form.time2 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[2].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
}
|
||||
// 控制台输出详细信息
|
||||
// console.log('点击事件详情:', {
|
||||
// X轴数据: xValue,
|
||||
// Y轴数据: yValue
|
||||
// })
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const dom = document.getElementById("navigation-splitpanes");
|
||||
if (dom) {
|
||||
size.value = Math.round((180 / dom.offsetHeight) * 100);
|
||||
}
|
||||
userDataList({
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
searchValue: "",
|
||||
}).then((res: any) => {
|
||||
console.log(res.data);
|
||||
loadDataOptions.value = res.data.records;
|
||||
});
|
||||
|
||||
if (!dotList.value || !dotList.value.alias) {
|
||||
dotList.value = { alias: "请选择监测点位" };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.box {
|
||||
// height: calc((100vh - 190px) / 2);
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.boxTab {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.harmonicButton {
|
||||
height: 42px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
height: calc(100vh - 265px);
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append, .el-input-group__prepend) {
|
||||
background-color: #ffffff00;
|
||||
padding: 0 17px;
|
||||
}
|
||||
|
||||
:deep(.frontBox) {
|
||||
background-color: var(--el-color-primary) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item.is-active) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__nav-wrap::after) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__active-bar) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.splitpanes__splitter) {
|
||||
background-color: rgba(44, 46, 60, 0.1) !important;
|
||||
|
||||
&:before {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
&:after {
|
||||
background-color: #fffFFF80 !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-form-item) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.currentPosition {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<!--谐波放大事件 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
:title="title"
|
||||
width="1200px"
|
||||
>
|
||||
<div class="tableBox">
|
||||
<div style="display: flex; justify-content: flex-end">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="443px"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
style="margin-top: 13px"
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="monitorName"
|
||||
align="center"
|
||||
label="监测点名称"
|
||||
width="120"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
align="center"
|
||||
label="用户"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="startTime"
|
||||
align="center"
|
||||
label="开始时间"
|
||||
width="140"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="endTime"
|
||||
align="center"
|
||||
label="结束时间"
|
||||
width="140"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="harmonicCount"
|
||||
align="center"
|
||||
label="次数"
|
||||
width="60"
|
||||
/>
|
||||
<el-table-column prop="phase" align="center" label="相别" width="60" />
|
||||
<el-table-column
|
||||
prop="duration"
|
||||
align="center"
|
||||
label="持续时间(min)"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ scope.row.duration / 60 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="vavgValue"
|
||||
align="center"
|
||||
label="电压标准值"
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="iavgValue"
|
||||
align="center"
|
||||
label="电流标准值"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ Math.floor(scope.row.iavgValue * 100) / 100 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="upScheme"
|
||||
align="center"
|
||||
label="处理措施"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="address" align="center" label="操作" width="60">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="arendChart(scope.row)"
|
||||
>趋势图</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
<TrendChart ref="trendChartRef" @close="machineVisible = true"></TrendChart>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, nextTick } from "vue";
|
||||
import { getDetail } from "@/api/manage_wx";
|
||||
import TrendChart from "./trendChart.vue";
|
||||
import { Download } from "@element-plus/icons-vue";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("谐波放大事件");
|
||||
const form = reactive({
|
||||
searchBeginTime: "",
|
||||
lineId: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
const loading = ref(false);
|
||||
const trendChartRef = ref();
|
||||
//form表单校验规则
|
||||
const open = (text: string, time?: any, lineId?: any) => {
|
||||
machineVisible.value = true;
|
||||
form.lineId = lineId;
|
||||
form.searchBeginTime = time;
|
||||
nextTick(() => {
|
||||
getTableData();
|
||||
});
|
||||
};
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
const res: any = await getDetail(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 趋势图
|
||||
const arendChart = (row: any) => {
|
||||
trendChartRef.value.open(row);
|
||||
machineVisible.value = false;
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"监测点名称",
|
||||
"用户",
|
||||
"开始时间",
|
||||
"结束时间",
|
||||
"次数",
|
||||
"相别",
|
||||
"持续时间(min)",
|
||||
"电压标准值",
|
||||
"电流标准值",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await getDetail({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.monitorName,
|
||||
item.objName,
|
||||
item.startTime,
|
||||
item.endTime,
|
||||
item.harmonicCount,
|
||||
item.phase,
|
||||
item.duration / 60,
|
||||
item.vavgValue,
|
||||
Math.floor(item.iavgValue * 100) / 100,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, "谐波放大事件");
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, "谐波放大事件" + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
1384
src/views/SagTraceResult_WX/components/eventStatistics/index.vue
Normal file
1384
src/views/SagTraceResult_WX/components/eventStatistics/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,667 @@
|
||||
<template>
|
||||
<!-- 配网计算 -->
|
||||
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes">
|
||||
<pane :size="20">
|
||||
<SystemTree :showSelect="false" @node-click="handleNodeClick" @init="handleNodeClick"></SystemTree>
|
||||
</pane>
|
||||
|
||||
<pane style="background-color: rgba(44, 46, 60, 0.1)" :size="100 - size">
|
||||
|
||||
<el-form :model="form" inline label-width="auto">
|
||||
<el-form-item label="谐波类型">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio-button label="谐波电压" size="small" value="1" />
|
||||
<el-radio-button label="谐波电流" size="small" value="0" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="谐波次数">
|
||||
<el-select v-model="form.index" filterable multiple :multiple-limit="5" collapse-tags
|
||||
collapse-tags-tooltip clearable placeholder="请选择次数" style="width: 200px" size="small">
|
||||
<el-option v-for="item in 49" :key="item" :label="item + 1 + '次'" :value="item + 1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<!-- <el-button type="primary" icon="el-icon-Plus" @click="push('/admin/division/aListOfLoadData')">
|
||||
新增
|
||||
</el-button> -->
|
||||
<el-button type="primary" :icon="Select" @click="submit" size="small">确定</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="activeName" v-if="showTabs" style="height: 740px">
|
||||
<el-tab-pane v-for="(item, index) in tabList" :key="item" :label="item.label" :name="index"
|
||||
style="height: 100%">
|
||||
<div>
|
||||
<div>
|
||||
<span style="color: #fff">时间范围</span>
|
||||
<el-date-picker v-model="item.time" class="mr10 ml10" type="daterange"
|
||||
start-placeholder="起始时间" end-placeholder="结束时间" format="YYYY-MM-DD"
|
||||
date-format="YYYY-MM-DD" time-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
|
||||
:disabled-date="handleDisabledDate" size="small" />
|
||||
<el-button type="primary" :icon="CaretRight" @click="execute(item, index)" size="small">
|
||||
执行
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="item.showEcahr == 1" class="harmonicButton">
|
||||
<el-form :inline="true" v-model="item.form">
|
||||
<el-form-item label="限值" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.limit" placeholder="请选择限值" disabled
|
||||
style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 0 ? 'frontBox' : '']"
|
||||
@click="setCode(0)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点一" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.time1" placeholder="请选择时间点一" disabled
|
||||
style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 1 ? 'frontBox' : '']"
|
||||
@click="setCode(1)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点二" v-if="item.showDynamic">
|
||||
<el-input v-model="item.form.time2" placeholder="请选择时间点二" disabled
|
||||
style="width: 200px" size="small">
|
||||
<template #append>
|
||||
<el-button :icon="Edit" :class="[code == 2 ? 'frontBox' : '']"
|
||||
@click="setCode(2)" size="small" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-button type="primary" :icon="Document" @click="generateFn" v-if="!item.showDynamic"
|
||||
size="small">
|
||||
生成动态谐波责任数据
|
||||
</el-button>
|
||||
<el-button type="primary" :icon="Document" v-else @click="generateMetrics" size="small">
|
||||
生成谐波责任指标
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="box" v-loading="loading" element-loading-background="#343849c7">
|
||||
<MyEChart :options="item.options" v-if="item.showEcahr == 1" @group="group" />
|
||||
<el-empty description="时间范围内无谐波数据" v-if="item.showEcahr == 2" />
|
||||
</div>
|
||||
<!-- 生成动态谐波责任数据 -->
|
||||
<div class="box boxTab" v-loading="loading1" element-loading-background="#343849c7">
|
||||
<MyEChart :options="item.dynamicOptions" style="flex: 1" v-if="item.showDynamic" />
|
||||
<div style="width: 500px" v-if="item.showDynamic" class="tableBox">
|
||||
<el-table :scrollbar-always-on="true" ref="tableRef" :data="item.dynamicData"
|
||||
height="280px" size="small" :header-cell-style="{ textAlign: 'center' }" border>
|
||||
<el-table-column prop="customerName" align="center" label="用户名(用户号)" />
|
||||
<el-table-column prop="responsibilityData" align="center" label="责任数据(%)"
|
||||
width="120">
|
||||
<template #default="scope">
|
||||
{{
|
||||
Math.floor(scope.row.responsibilityData * 10000) /
|
||||
10000
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, reactive } from "vue";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import SystemTree from "@/components/tree/systemTree.vue";
|
||||
import { Edit, Right } from "@element-plus/icons-vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
import { timeFormat } from "@/utils/common";
|
||||
import { yMethod } from "@/utils/echartMethod";
|
||||
import { Select, CaretRight, Document } from "@element-plus/icons-vue";
|
||||
import {
|
||||
getHistoryHarmData,
|
||||
getDynamicData,
|
||||
getResponsibilityData,
|
||||
} from "@/api/manage_wx";
|
||||
const visible = ref(false);
|
||||
const size = ref(0);
|
||||
const dotList: any = ref({});
|
||||
const form: any = reactive({
|
||||
type: "1",
|
||||
index: [],
|
||||
});
|
||||
|
||||
const code = ref(3);
|
||||
const xAxisData = ref([]);
|
||||
const loading = ref(false);
|
||||
const loading1 = ref(false);
|
||||
const tabList: any = ref([]);
|
||||
const activeName = ref(0);
|
||||
const xValue = ref("");
|
||||
const showTabs = ref(false);
|
||||
|
||||
// 设置时间
|
||||
const timeFrame = ref(["", ""]);
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleNodeClick = (data: any) => {
|
||||
if (data.level == 6) {
|
||||
dotList.value = data;
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// 处理日期禁用逻辑
|
||||
const handleDisabledDate = (date) => {
|
||||
return date.getTime() > Date.now();
|
||||
};
|
||||
// 这是按钮变色
|
||||
const setCode = (num: number) => {
|
||||
if (code.value == num) {
|
||||
return (code.value = 3);
|
||||
}
|
||||
code.value = num;
|
||||
};
|
||||
|
||||
// 确定
|
||||
const submit = () => {
|
||||
|
||||
if (form.index.length == 0) {
|
||||
return ElMessage.warning("请选择谐波次数");
|
||||
}
|
||||
|
||||
if (form.index.length == 0) {
|
||||
showTabs.value = false;
|
||||
} else {
|
||||
|
||||
showTabs.value = true;
|
||||
let list = JSON.parse(JSON.stringify(form.index)).sort((a, b) => a - b);
|
||||
tabList.value = [];
|
||||
list.forEach((item: any) => {
|
||||
tabList.value.push({
|
||||
label: item + "次谐波",
|
||||
key: item,
|
||||
showExecute: false,
|
||||
form: {
|
||||
limit: "",
|
||||
time1: "",
|
||||
time2: "",
|
||||
},
|
||||
showEcahr: 3, //1显示echart 2显示无数据 3什么都没有
|
||||
options: {},
|
||||
dynamicOptions: {}, //动态echarts
|
||||
dynamicList: {}, //动态echarts
|
||||
showDynamic: false, //动态执行展示
|
||||
});
|
||||
});
|
||||
code.value = 3;
|
||||
activeName.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 执行
|
||||
const execute = async (item: any, index: number) => {
|
||||
tabList.value[activeName.value].showDynamic = false;
|
||||
loading.value = true;
|
||||
await getHistoryHarmData({
|
||||
searchBeginTime: item.time[0],
|
||||
searchEndTime: item.time[1],
|
||||
type: form.type,
|
||||
time: item.key,
|
||||
lineId: dotList.value.id,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
let [min, max] = yMethod(
|
||||
res.data.historyData.map((item: any) => item.value + 0.1)
|
||||
);
|
||||
xAxisData.value = res.data.historyData.map((item: any) => item.time);
|
||||
tabList.value[index].options = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
xValue.value = params[0].value[0];
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 50,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
series: [
|
||||
{
|
||||
name: item.key + (form.type == 1 ? "次谐波电压" : "次谐波电流"),
|
||||
data: res.data.historyData.map((item: any) => [
|
||||
item.time,
|
||||
Math.floor(item.value * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
markLine: {
|
||||
symbol: "none", // 去除箭头
|
||||
label: {
|
||||
show: false, // 隐藏标签
|
||||
},
|
||||
data: [
|
||||
{
|
||||
yAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
],
|
||||
// 样式配置
|
||||
lineStyle: {
|
||||
color: "red",
|
||||
type: "dashed", // 虚线
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
tabList.value[index].showEcahr = 1; //显示echart
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
tabList.value[index].showEcahr = 2;
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
tabList.value[index].showEcahr = 2;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const resDataId = ref("");
|
||||
// 生成动态谐波责任数据
|
||||
const generateFn = async () => {
|
||||
loading1.value = true;
|
||||
await getDynamicData({
|
||||
lineId: dotList.value.id,
|
||||
searchBeginTime: tabList.value[activeName.value].time[0],
|
||||
searchEndTime: tabList.value[activeName.value].time[1],
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
resDataId.value = res.data.responsibilityDataIndex;
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) =>
|
||||
timeFormat(item)
|
||||
);
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
}
|
||||
loading1.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
|
||||
// 生成指标
|
||||
const generateMetrics = async () => {
|
||||
if (tabList.value[activeName.value].form.limit == "")
|
||||
return ElMessage.warning("请选择限值!");
|
||||
if (tabList.value[activeName.value].form.time1 == "")
|
||||
return ElMessage.warning("请选择时间一!");
|
||||
if (tabList.value[activeName.value].form.time2 == "")
|
||||
return ElMessage.warning("请选择时间二!");
|
||||
loading1.value = true;
|
||||
await getResponsibilityData({
|
||||
limitEndTime: tabList.value[activeName.value].form.time2,
|
||||
limitStartTime: tabList.value[activeName.value].form.time1,
|
||||
limitValue: tabList.value[activeName.value].form.limit,
|
||||
resDataId: resDataId.value,
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
})
|
||||
.then((res: any) => {
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) => timeFormat(item));
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
// 监听echart点击
|
||||
const group = (chart: any, myChartDom: any) => {
|
||||
myChartDom.addEventListener("click", function (event: any) {
|
||||
// 获取点击位置相对于图表容器的坐标
|
||||
const rect = myChartDom.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
const pointInPixel = [x, y];
|
||||
// 转换为逻辑坐标(相对于图表坐标系)
|
||||
const pointInGrid = chart.convertFromPixel({ gridIndex: 0 }, pointInPixel);
|
||||
// 计算X轴和Y轴的对应数据
|
||||
|
||||
// 处理X轴数据(分类轴)
|
||||
|
||||
// 处理Y轴数据(数值轴)
|
||||
let yValue = pointInGrid[1].toFixed(4);
|
||||
// xValue = timeFormat(pointInGrid[0].toFixed(0) - 0)
|
||||
if (code.value == 0) {
|
||||
tabList.value[activeName.value].form.limit = yValue;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[0].yAxis =
|
||||
yValue;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 1) {
|
||||
tabList.value[activeName.value].form.time1 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[1].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 2) {
|
||||
tabList.value[activeName.value].form.time2 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[2].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
}
|
||||
// 控制台输出详细信息
|
||||
// console.log('点击事件详情:', {
|
||||
// X轴数据: xValue,
|
||||
// Y轴数据: yValue
|
||||
// })
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const dom = document.getElementById("navigation-splitpanes");
|
||||
if (dom) {
|
||||
size.value = Math.round((180 / dom.offsetHeight) * 100);
|
||||
}
|
||||
|
||||
|
||||
if (!dotList.value || !dotList.value.alias) {
|
||||
dotList.value = { alias: "请选择监测点位" };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.box {
|
||||
// height: calc((100vh - 190px) / 2);
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.boxTab {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.harmonicButton {
|
||||
height: 42px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
height: calc(100vh - 265px);
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append, .el-input-group__prepend) {
|
||||
background-color: #ffffff00;
|
||||
padding: 0 17px;
|
||||
}
|
||||
|
||||
:deep(.frontBox) {
|
||||
background-color: var(--el-color-primary) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item.is-active) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__nav-wrap::after) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__active-bar) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.splitpanes__splitter) {
|
||||
background-color: rgba(44, 46, 60, 0.1) !important;
|
||||
|
||||
&:before {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
&:after {
|
||||
background-color: #fffFFF80 !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-form-item) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,982 @@
|
||||
<template>
|
||||
<!-- 配网计算 -->
|
||||
<splitpanes
|
||||
style="height: 100%"
|
||||
class="default-theme"
|
||||
id="navigation-splitpanes"
|
||||
>
|
||||
<pane :size="20">
|
||||
<PointTree
|
||||
:showSelect="false"
|
||||
@node-click="handleNodeClick"
|
||||
@init="handleNodeClick"
|
||||
></PointTree>
|
||||
</pane>
|
||||
|
||||
<pane style="background-color: rgba(44, 46, 60, 0.1)" :size="100 - size">
|
||||
<el-form :model="form" inline label-width="auto">
|
||||
<el-form-item label="用采用户">
|
||||
<el-tree-select
|
||||
v-model="form.userList"
|
||||
:data="dataTree"
|
||||
multiple
|
||||
filterable
|
||||
show-checkbox
|
||||
ref="treeRef"
|
||||
:props="defaultProps"
|
||||
node-key="id"
|
||||
size="small"
|
||||
popper-class="tree-select-popper"
|
||||
:popper-append-to-body="false"
|
||||
:default-expanded-keys="expandedKeys"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
clearable
|
||||
class="wide-tree-select"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="谐波类型">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio-button label="谐波电压" size="small" value="1" />
|
||||
<el-radio-button label="谐波电流" size="small" value="0" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="谐波次数">
|
||||
<el-select
|
||||
v-model="form.index"
|
||||
filterable
|
||||
multiple
|
||||
:multiple-limit="5"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
clearable
|
||||
placeholder="请选择次数"
|
||||
style="width: 200px"
|
||||
size="small"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in 49"
|
||||
:key="item"
|
||||
:label="item + 1 + '次'"
|
||||
:value="item + 1"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="负荷数据">
|
||||
<el-select v-model="form.loadDataId" clearable filterable placeholder="请选择负荷数据" style="width: 200px"
|
||||
size="small">
|
||||
<el-option v-for="item in loadDataOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item>
|
||||
<!-- <el-button type="primary" icon="el-icon-Plus" @click="push('/admin/division/aListOfLoadData')">
|
||||
新增
|
||||
</el-button> -->
|
||||
<el-button type="primary" :icon="Select" @click="submit" size="small"
|
||||
>确定</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="activeName" v-if="showTabs" style="height: 740px">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in tabList"
|
||||
:key="item"
|
||||
:label="item.label"
|
||||
:name="index"
|
||||
style="height: 100%"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
<span style="color: #fff">时间范围</span>
|
||||
<el-date-picker
|
||||
v-model="item.time"
|
||||
class="mr10 ml10"
|
||||
type="daterange"
|
||||
start-placeholder="起始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="YYYY-MM-DD"
|
||||
date-format="YYYY-MM-DD"
|
||||
time-format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:disabled-date="handleDisabledDate"
|
||||
size="small"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="CaretRight"
|
||||
@click="execute(item, index)"
|
||||
size="small"
|
||||
>
|
||||
执行
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="item.showEcahr == 1" class="harmonicButton">
|
||||
<el-form :inline="true" v-model="item.form">
|
||||
<el-form-item label="限值" v-if="item.showDynamic">
|
||||
<el-input
|
||||
v-model="item.form.limit"
|
||||
placeholder="请选择限值"
|
||||
disabled
|
||||
style="width: 200px"
|
||||
size="small"
|
||||
>
|
||||
<template #append>
|
||||
<el-button
|
||||
:icon="Edit"
|
||||
:class="[code == 0 ? 'frontBox' : '']"
|
||||
@click="setCode(0)"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点一" v-if="item.showDynamic">
|
||||
<el-input
|
||||
v-model="item.form.time1"
|
||||
placeholder="请选择时间点一"
|
||||
disabled
|
||||
style="width: 200px"
|
||||
size="small"
|
||||
>
|
||||
<template #append>
|
||||
<el-button
|
||||
:icon="Edit"
|
||||
:class="[code == 1 ? 'frontBox' : '']"
|
||||
@click="setCode(1)"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间点二" v-if="item.showDynamic">
|
||||
<el-input
|
||||
v-model="item.form.time2"
|
||||
placeholder="请选择时间点二"
|
||||
disabled
|
||||
style="width: 200px"
|
||||
size="small"
|
||||
>
|
||||
<template #append>
|
||||
<el-button
|
||||
:icon="Edit"
|
||||
:class="[code == 2 ? 'frontBox' : '']"
|
||||
@click="setCode(2)"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Document"
|
||||
@click="generateFn"
|
||||
v-if="!item.showDynamic"
|
||||
size="small"
|
||||
>
|
||||
生成动态谐波责任数据
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Document"
|
||||
v-else
|
||||
@click="generateMetrics"
|
||||
size="small"
|
||||
>
|
||||
生成谐波责任指标
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="box"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
>
|
||||
<MyEChart
|
||||
:options="item.options"
|
||||
v-if="item.showEcahr == 1"
|
||||
@group="group"
|
||||
/>
|
||||
<el-empty
|
||||
description="时间范围内无谐波数据"
|
||||
v-if="item.showEcahr == 2"
|
||||
/>
|
||||
</div>
|
||||
<!-- 生成动态谐波责任数据 -->
|
||||
<div
|
||||
class="box boxTab"
|
||||
v-loading="loading1"
|
||||
element-loading-background="#343849c7"
|
||||
>
|
||||
<MyEChart
|
||||
:options="item.dynamicOptions"
|
||||
style="flex: 1"
|
||||
v-if="item.showDynamic"
|
||||
/>
|
||||
<div
|
||||
style="width: 500px"
|
||||
v-if="item.showDynamic"
|
||||
class="tableBox"
|
||||
>
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
ref="tableRef"
|
||||
:data="item.dynamicData"
|
||||
height="280px"
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column
|
||||
prop="customerName"
|
||||
align="center"
|
||||
label="用户名(用户号)"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="responsibilityData"
|
||||
align="center"
|
||||
label="责任数据(%)"
|
||||
width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{
|
||||
Math.floor(scope.row.responsibilityData * 10000) / 10000
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, reactive, watch } from "vue";
|
||||
import "splitpanes/dist/splitpanes.css";
|
||||
import { Splitpanes, Pane } from "splitpanes";
|
||||
import PointTree from "@/components/tree/pointTree.vue";
|
||||
import { Edit, Right } from "@element-plus/icons-vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
import { timeFormat } from "@/utils/common";
|
||||
import { yMethod } from "@/utils/echartMethod";
|
||||
import { Select, CaretRight, Document } from "@element-plus/icons-vue";
|
||||
import {
|
||||
userDataList,
|
||||
getHistoryHarmData,
|
||||
getDynamicData,
|
||||
getResponsibilityData,
|
||||
getTerminalTreeForFive,
|
||||
} from "@/api/manage_wx";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
const store = useStore();
|
||||
const emit = defineEmits(["setTitle", "init"]); // 打开弹窗
|
||||
const visible = ref(false);
|
||||
const size = ref(0);
|
||||
const dotList: any = ref({});
|
||||
const form: any = reactive({
|
||||
type: "1",
|
||||
index: [],
|
||||
userList: [],
|
||||
});
|
||||
|
||||
const loadDataOptions: any = ref([]);
|
||||
const code = ref(3);
|
||||
const xAxisData = ref([]);
|
||||
const loading = ref(false);
|
||||
const loading1 = ref(false);
|
||||
const tabList: any = ref([]);
|
||||
const activeName = ref(0);
|
||||
const xValue = ref("");
|
||||
const showTabs = ref(false);
|
||||
|
||||
// 设置时间
|
||||
const timeFrame = ref(["", ""]);
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
// 添加已选择的节点ID列表
|
||||
const selectedNodeIds = ref<string[]>([]);
|
||||
|
||||
const handleNodeClick = (data: any) => {
|
||||
if (data.level == 6) {
|
||||
dotList.value = data;
|
||||
setTimeout(() => {
|
||||
emit("setTitle", data.alias);
|
||||
}, 0);
|
||||
// 保存选择的节点ID
|
||||
if (data.id) {
|
||||
selectedNodeIds.value = [data.id];
|
||||
}
|
||||
// 如果右侧已经选择了这个节点,则从右侧选择中移除
|
||||
const selectedUserIdIndex = form.userList.indexOf(data.id);
|
||||
if (selectedUserIdIndex > -1) {
|
||||
// 创建新数组以触发视图更新
|
||||
form.userList = form.userList.filter((id: string) => id !== data.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 添加一个方法来更新树节点的禁用状态
|
||||
const updateTreeDataDisabledState = () => {
|
||||
if (!dataTree.value || dataTree.value.length === 0) return;
|
||||
|
||||
const disableNodes = (nodes: any[]) => {
|
||||
if (!nodes || nodes.length === 0) return;
|
||||
|
||||
nodes.forEach((node) => {
|
||||
// 如果节点ID在已选择列表中,则禁用
|
||||
if (selectedNodeIds.value.includes(node.id)) {
|
||||
node.disabled = true;
|
||||
} else {
|
||||
// 如果之前被禁用但现在不在选择列表中,则启用
|
||||
if (node.hasOwnProperty("disabled")) {
|
||||
node.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 递归处理子节点
|
||||
if (node.children && node.children.length > 0) {
|
||||
disableNodes(node.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
disableNodes(dataTree.value);
|
||||
};
|
||||
|
||||
// 监听 selectedNodeIds 的变化,更新树节点状态
|
||||
watch(
|
||||
selectedNodeIds,
|
||||
() => {
|
||||
updateTreeDataDisabledState();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 处理日期禁用逻辑
|
||||
const handleDisabledDate = (date) => {
|
||||
// 定义时间边界
|
||||
const startLimit = new Date(timeFrame.value[0]).getTime() - 86400000; //向前推1天
|
||||
const endLimit = new Date(timeFrame.value[1]).setHours(23, 59, 59, 999);
|
||||
|
||||
// 如果日期不存在(选择今天时可能出现),不禁用
|
||||
if (!date) return false;
|
||||
|
||||
// 禁用 2025-08-01 之前和 2025-08-31 之后的日期
|
||||
return date.getTime() < startLimit || date.getTime() > endLimit;
|
||||
};
|
||||
// 这是按钮变色
|
||||
const setCode = (num: number) => {
|
||||
if (code.value == num) {
|
||||
return (code.value = 3);
|
||||
}
|
||||
code.value = num;
|
||||
};
|
||||
|
||||
// 确定
|
||||
const submit = () => {
|
||||
if (form.index.length == 0) {
|
||||
return ElMessage.warning("请选择谐波次数");
|
||||
}
|
||||
|
||||
if (form.index.length == 0) {
|
||||
showTabs.value = false;
|
||||
} else {
|
||||
showTabs.value = true;
|
||||
let list = JSON.parse(JSON.stringify(form.index)).sort((a, b) => a - b);
|
||||
tabList.value = [];
|
||||
list.forEach((item: any) => {
|
||||
tabList.value.push({
|
||||
label: item + "次谐波",
|
||||
key: item,
|
||||
showExecute: false,
|
||||
form: {
|
||||
limit: "",
|
||||
time1: "",
|
||||
time2: "",
|
||||
},
|
||||
showEcahr: 3, //1显示echart 2显示无数据 3什么都没有
|
||||
options: {},
|
||||
dynamicOptions: {}, //动态echarts
|
||||
dynamicList: {}, //动态echarts
|
||||
showDynamic: false, //动态执行展示
|
||||
});
|
||||
});
|
||||
code.value = 3;
|
||||
activeName.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 执行
|
||||
const execute = async (item: any, index: number) => {
|
||||
if (item.time == undefined) {
|
||||
return ElMessage.warning("请选择时间范围");
|
||||
}
|
||||
tabList.value[activeName.value].showDynamic = false;
|
||||
loading.value = true;
|
||||
await getHistoryHarmData({
|
||||
searchBeginTime: item.time[0],
|
||||
searchEndTime: item.time[1],
|
||||
type: form.type,
|
||||
time: item.key,
|
||||
lineId: dotList.value.id,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
let [min, max] = yMethod(
|
||||
res.data.historyData.map((item: any) => item.value + 0.1)
|
||||
);
|
||||
xAxisData.value = res.data.historyData.map((item: any) => item.time);
|
||||
tabList.value[index].options = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
xValue.value = params[0].value[0];
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 50,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
series: [
|
||||
{
|
||||
name: item.key + (form.type == 1 ? "次谐波电压" : "次谐波电流"),
|
||||
data: res.data.historyData.map((item: any) => [
|
||||
item.time,
|
||||
Math.floor(item.value * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
|
||||
markLine: {
|
||||
symbol: "none", // 去除箭头
|
||||
label: {
|
||||
show: false, // 隐藏标签
|
||||
},
|
||||
data: [
|
||||
{
|
||||
yAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
{
|
||||
xAxis: "",
|
||||
},
|
||||
],
|
||||
// 样式配置
|
||||
lineStyle: {
|
||||
color: "red",
|
||||
type: "dashed", // 虚线
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
tabList.value[index].showEcahr = 1; //显示echart
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
tabList.value[index].showEcahr = 2;
|
||||
}
|
||||
loading.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
tabList.value[index].showEcahr = 2;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const resDataId = ref("");
|
||||
// 生成动态谐波责任数据
|
||||
const generateFn = async () => {
|
||||
if (form.userList.length == 0) {
|
||||
return ElMessage.warning("请选择用采用户");
|
||||
}
|
||||
loading1.value = true;
|
||||
await getDynamicData({
|
||||
userDataId: "123",
|
||||
lineId: dotList.value.id,
|
||||
searchBeginTime: tabList.value[activeName.value].time[0],
|
||||
searchEndTime: tabList.value[activeName.value].time[1],
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
userList: form.userList,
|
||||
systemType: 1,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
resDataId.value = res.data.responsibilityDataIndex;
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) =>
|
||||
timeFormat(item)
|
||||
);
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
} else {
|
||||
ElMessage.warning(res.message);
|
||||
}
|
||||
loading1.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
|
||||
// 生成指标
|
||||
const generateMetrics = async () => {
|
||||
if (tabList.value[activeName.value].form.limit == "")
|
||||
return ElMessage.warning("请选择限值!");
|
||||
if (tabList.value[activeName.value].form.time1 == "")
|
||||
return ElMessage.warning("请选择时间一!");
|
||||
if (tabList.value[activeName.value].form.time2 == "")
|
||||
return ElMessage.warning("请选择时间二!");
|
||||
loading1.value = true;
|
||||
await getResponsibilityData({
|
||||
limitEndTime: tabList.value[activeName.value].form.time2,
|
||||
limitStartTime: tabList.value[activeName.value].form.time1,
|
||||
limitValue: tabList.value[activeName.value].form.limit,
|
||||
resDataId: resDataId.value,
|
||||
time: tabList.value[activeName.value].key,
|
||||
type: form.type,
|
||||
})
|
||||
.then((res: any) => {
|
||||
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
|
||||
let [min, max] = yMethod(
|
||||
res.data.datas.map((item: any) => item.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = res.data.timeDatas.map((item: any) => timeFormat(item));
|
||||
res.data.datas.forEach((item: any) => {
|
||||
series.push({
|
||||
name: item.customerName,
|
||||
data: item.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
smooth: true,
|
||||
symbol: "none",
|
||||
});
|
||||
});
|
||||
|
||||
tabList.value[activeName.value].dynamicOptions = {
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
name: form.type == 1 ? "%" : "A",
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
};
|
||||
|
||||
tabList.value[activeName.value].showDynamic = true;
|
||||
})
|
||||
.catch(() => {
|
||||
loading1.value = false;
|
||||
});
|
||||
loading1.value = false;
|
||||
};
|
||||
// 监听echart点击
|
||||
const group = (chart: any, myChartDom: any) => {
|
||||
myChartDom.addEventListener("click", function (event: any) {
|
||||
// 获取点击位置相对于图表容器的坐标
|
||||
const rect = myChartDom.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
const pointInPixel = [x, y];
|
||||
// 转换为逻辑坐标(相对于图表坐标系)
|
||||
const pointInGrid = chart.convertFromPixel({ gridIndex: 0 }, pointInPixel);
|
||||
// 计算X轴和Y轴的对应数据
|
||||
|
||||
// 处理X轴数据(分类轴)
|
||||
|
||||
// 处理Y轴数据(数值轴)
|
||||
let yValue = pointInGrid[1].toFixed(4);
|
||||
// xValue = timeFormat(pointInGrid[0].toFixed(0) - 0)
|
||||
if (code.value == 0) {
|
||||
tabList.value[activeName.value].form.limit = yValue;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[0].yAxis =
|
||||
yValue;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 1) {
|
||||
tabList.value[activeName.value].form.time1 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[1].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
} else if (code.value == 2) {
|
||||
tabList.value[activeName.value].form.time2 = xValue.value;
|
||||
tabList.value[activeName.value].options.series[0].markLine.data[2].xAxis =
|
||||
xValue.value;
|
||||
chart.setOption(tabList.value[activeName.value].options);
|
||||
}
|
||||
// 控制台输出详细信息
|
||||
// console.log('点击事件详情:', {
|
||||
// X轴数据: xValue,
|
||||
// Y轴数据: yValue
|
||||
// })
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const dom = document.getElementById("navigation-splitpanes");
|
||||
if (dom) {
|
||||
size.value = Math.round((180 / dom.offsetHeight) * 100);
|
||||
}
|
||||
userDataList({
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
searchValue: "",
|
||||
}).then((res: any) => {
|
||||
console.log(res.data);
|
||||
loadDataOptions.value = res.data.records;
|
||||
});
|
||||
|
||||
if (!dotList.value || !dotList.value.alias) {
|
||||
dotList.value = { alias: "请选择监测点位" };
|
||||
}
|
||||
});
|
||||
|
||||
const formData = ref({
|
||||
deptIndex: store.state.deptId,
|
||||
});
|
||||
|
||||
const dataTree = ref([]);
|
||||
const expandedKeys = ref([]);
|
||||
|
||||
const defaultProps = {
|
||||
label: "name",
|
||||
value: "id",
|
||||
disabled: "disabled",
|
||||
};
|
||||
|
||||
const treeRef = ref();
|
||||
|
||||
const loadData = () => {
|
||||
let form = JSON.parse(JSON.stringify(formData.value));
|
||||
getTerminalTreeForFive(form).then((res) => {
|
||||
console.log(res);
|
||||
|
||||
res.data = [
|
||||
{
|
||||
name: "电网拓扑",
|
||||
level: -1,
|
||||
id: 0,
|
||||
children: res.data,
|
||||
},
|
||||
];
|
||||
|
||||
// 查找第一层级的最后一个子节点
|
||||
const firstLevelChildren = res.data[0].children;
|
||||
if (firstLevelChildren && firstLevelChildren.length > 0) {
|
||||
let flag = true;
|
||||
|
||||
// 设置节点别名
|
||||
res.data.forEach((item: any) => {
|
||||
item.children.forEach((item2: any) => {
|
||||
item2.children.forEach((item3: any) => {
|
||||
item3.children.forEach((item4: any) => {
|
||||
item4.children.forEach((item5: any) => {
|
||||
if (item5.level == 7) {
|
||||
item5.children.forEach((item6: any) => {
|
||||
item6.disabled = false;
|
||||
item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`;
|
||||
});
|
||||
} else {
|
||||
if (flag) {
|
||||
expandedKeys.value = [item5.id];
|
||||
treeRef.value.setCurrentKey(item5.id);
|
||||
emit("init", item5);
|
||||
flag = false;
|
||||
}
|
||||
item5.disabled = false;
|
||||
item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dataTree.value = res.data;
|
||||
|
||||
// 更新禁用状态
|
||||
updateTreeDataDisabledState();
|
||||
});
|
||||
};
|
||||
|
||||
loadData();
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.box {
|
||||
// height: calc((100vh - 190px) / 2);
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.boxTab {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.harmonicButton {
|
||||
height: 42px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
height: calc(100vh - 265px);
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append, .el-input-group__prepend) {
|
||||
background-color: #ffffff00;
|
||||
padding: 0 17px;
|
||||
}
|
||||
|
||||
:deep(.frontBox) {
|
||||
background-color: var(--el-color-primary) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__item.is-active) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__nav-wrap::after) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__active-bar) {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep(.splitpanes__splitter) {
|
||||
background-color: rgba(44, 46, 60, 0.1) !important;
|
||||
|
||||
&:before {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
&:after {
|
||||
background-color: #ffffff80 !important;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-form-item) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.currentPosition {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// 树选择器下拉面板样式
|
||||
::v-deep(.tree-select-popper) {
|
||||
.el-select-dropdown__wrap {
|
||||
width: 400px; /* 设置你想要的宽度 */
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-tag__content){
|
||||
max-width: 90px;
|
||||
}
|
||||
|
||||
/* 树选择器本身的宽度控制 */
|
||||
::v-deep(.wide-tree-select) {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,230 @@
|
||||
<!-- 详情 -->
|
||||
<template>
|
||||
<el-dialog v-model="visible" :close-on-click-modal="false" title="详情" draggable width="1600px"
|
||||
@close="handleCloseDialog" style="height: 800px">
|
||||
<div class="default-main">
|
||||
<div class="title_1">
|
||||
<span class="monitoring-point">
|
||||
{{ props.detailsQuery.name || "" }}</span>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeName" @tab-change="generateFn">
|
||||
<el-tab-pane v-for="(item, index) in tabList" :key="index" :label="item.name + '次谐波'" style="height: 100%"
|
||||
:name="index" v-loading="loading">
|
||||
<div style="height: 680px; overflow-y: auto">
|
||||
<div class="box mb10" v-for="(value, i) in item.dynamicOptions" :key="i">
|
||||
<div class="boxTab">
|
||||
<MyEChart :options="item.dynamicOptions[i]" style="flex: 1" :style="{
|
||||
height: `calc((680px) / ${item.list.length == 0
|
||||
? 1
|
||||
: item.list.length > 1
|
||||
? 2
|
||||
: item.list.length
|
||||
} - 21px)`,
|
||||
}" />
|
||||
<div style="width: 500px" class="tableBox">
|
||||
<el-table ref="tableRef" :data="item.list[i]" size="small" :height="`calc((600px) / ${item.list.length == 0
|
||||
? 1
|
||||
: item.list.length > 1
|
||||
? 2
|
||||
: item.list.length
|
||||
} - 21px)`" :header-cell-style="{ textAlign: 'center' }" border>
|
||||
<el-table-column prop="customerName" align="center" label="用户名(用户号)" />
|
||||
<el-table-column prop="responsibilityData" align="center" label="责任数据(%)" width="120">
|
||||
<template #default="scope">
|
||||
{{
|
||||
Math.floor(scope.row.responsibilityData * 10000) / 10000
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, nextTick } from "vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
import { timeFormat } from "@/utils/common";
|
||||
import { yMethod } from "@/utils/echartMethod";
|
||||
import { displayHistoryData } from "@/api/manage_wx";
|
||||
|
||||
const props = defineProps<{
|
||||
detailsQuery?: any; // 根据实际类型调整
|
||||
}>();
|
||||
|
||||
// const height = mainHeight(155);
|
||||
const activeName = ref(0);
|
||||
const tabList: any = ref([]);
|
||||
|
||||
const visible: any = ref(false);
|
||||
|
||||
const loading: any = ref(false);
|
||||
const init = () => {
|
||||
let data =
|
||||
(Array.isArray(props.detailsQuery.time)
|
||||
? props.detailsQuery.time[0]
|
||||
: props.detailsQuery.time
|
||||
)?.split(",") ?? [];
|
||||
tabList.value = [];
|
||||
data.forEach((item: any) => {
|
||||
tabList.value.push({
|
||||
name: item,
|
||||
dynamicOptions: [],
|
||||
list: [],
|
||||
});
|
||||
});
|
||||
activeName.value = 0;
|
||||
generateFn(0);
|
||||
};
|
||||
|
||||
// 生成动态谐波责任数据
|
||||
const generateFn = async (e: any) => {
|
||||
if (tabList.value[e].dynamicOptions.length != 0) return;
|
||||
|
||||
loading.value = true;
|
||||
await displayHistoryData({
|
||||
id: props.detailsQuery.id,
|
||||
time: tabList.value[e].name,
|
||||
})
|
||||
.then((res: any) => {
|
||||
res.data.forEach((item: any) => {
|
||||
tabList.value[e].list.push(item.responsibilities);
|
||||
|
||||
let [min, max] = yMethod(
|
||||
item.datas.map((k: any) => k.valueDatas).flat()
|
||||
);
|
||||
let series: any[] = [];
|
||||
let time: any[] = item.timeDatas.map((k: any) => timeFormat(k));
|
||||
item.datas.forEach((k: any) => {
|
||||
series.push({
|
||||
name: k.customerName,
|
||||
data: k.valueDatas.map((k: any, i: number) => [
|
||||
time[i],
|
||||
Math.floor(k * 10000) / 10000,
|
||||
]),
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
smooth: true,
|
||||
});
|
||||
});
|
||||
tabList.value[e].dynamicOptions.push({
|
||||
title: {
|
||||
text: `时间:${item.limitSTime} 至${item.limitETime} 限值:${item.limitValue}`,
|
||||
},
|
||||
xAxis: {
|
||||
type: "time",
|
||||
name: "时间",
|
||||
axisLabel: {
|
||||
formatter: {
|
||||
day: "{MM}-{dd}",
|
||||
month: "{MM}",
|
||||
year: "{yyyy}",
|
||||
},
|
||||
},
|
||||
// 刻度线样式
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 刻度线白色
|
||||
},
|
||||
},
|
||||
|
||||
// 轴线样式
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff", // 轴线白色
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
formatter(params: any) {
|
||||
let str = params[0].value[0] + "<br/>";
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
str =
|
||||
str +
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
params[i].value[1] +
|
||||
"<br/>";
|
||||
}
|
||||
|
||||
return str;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
yAxis: {
|
||||
min: min,
|
||||
max: max,
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
options: {
|
||||
series: series,
|
||||
},
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
if (props.detailsQuery) {
|
||||
nextTick(() => {
|
||||
init();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// onMounted(() => {
|
||||
// init();
|
||||
// });
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.title_1 {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 65px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.monitoring-point {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.boxTab {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,653 @@
|
||||
<!-- 谐波放大表格详情 -->
|
||||
<template>
|
||||
<el-dialog v-model="visible" :close-on-click-modal="false" title="趋势图" draggable width="70%"
|
||||
@close="handleCloseDialog">
|
||||
<el-radio-group v-model="condition" size="small" @change="init">
|
||||
<el-radio-button label="谐波电压" value="42" />
|
||||
<el-radio-button label="谐波电流" value="43" />
|
||||
|
||||
</el-radio-group>
|
||||
<MyEChart v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.8)" :options="list[0]?.option"
|
||||
:style="`height:670px`" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import MyEChart from "@/components/echarts/MyEchart.vue";
|
||||
import { getHistoryResult } from "@/api/manage_wx/index";
|
||||
import { yMethod } from "@/utils/echartMethod";
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const options = ref<any>(null);
|
||||
const list = ref<any>([]);
|
||||
const traceability = ref<any>([]);
|
||||
const rowData: any = ref({});
|
||||
const condition: any = ref('42');
|
||||
|
||||
const open = async (row: any) => {
|
||||
rowData.value = row;
|
||||
condition.value = '42';
|
||||
visible.value = true;
|
||||
init()
|
||||
};
|
||||
const init = async () => {
|
||||
list.value = [];
|
||||
|
||||
loading.value = true;
|
||||
await getHistoryResult({
|
||||
lineId: [rowData.value.monitorId],
|
||||
searchBeginTime: rowData.value.startTime,
|
||||
searchEndTime: rowData.value.endTime,
|
||||
valueType: 4,
|
||||
harmonic: rowData.value.harmonicCount,
|
||||
ptType: 0,
|
||||
condition: [condition.value],
|
||||
}).then((res) => {
|
||||
shujuchuli(res);
|
||||
});
|
||||
}
|
||||
const shujuchuli = (res: any) => {
|
||||
list.value = [];
|
||||
let shujuData = res.data;
|
||||
shujuData.forEach((item: any, i: number) => {
|
||||
//判断是否存在暂降点
|
||||
|
||||
if (item.eventDetail == null) {
|
||||
let [min, max] = yMethod([item.minValue, item.maxValue, condition.value == '42' ? rowData.value.vavgValue : rowData.value.vavgValue.iavgValue]
|
||||
|
||||
);
|
||||
//判断是否有限值(有上下限)
|
||||
if (item.topLimit !== 0 && item.lowerLimit !== 0) {
|
||||
item.phaiscType.push("上限");
|
||||
item.phaiscType.push("下限");
|
||||
if (item.minValue !== null && item.maxValue !== null) {
|
||||
//最小值等于下限值
|
||||
//图列为A,B,C,上限,下限
|
||||
if (item.phaiscType.length == 5) {
|
||||
let avalue = [];
|
||||
let bvalue = [];
|
||||
let cvalue = [];
|
||||
let topLimit = [];
|
||||
let lowerLimit = [];
|
||||
item.maxValue = item.topLimit;
|
||||
item.minValue = item.lowerLimit;
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
avalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
avalue.push([]);
|
||||
}
|
||||
//判断存在缺失值b
|
||||
if (item.value[j][2] != undefined) {
|
||||
bvalue.push([item.value[j][0], item.value[j][2].toFixed(3)]);
|
||||
} else {
|
||||
bvalue.push([]);
|
||||
}
|
||||
//判断存在缺失值c
|
||||
if (item.value[j][3] != undefined) {
|
||||
cvalue.push([item.value[j][0], item.value[j][3].toFixed(3)]);
|
||||
} else {
|
||||
cvalue.push([]);
|
||||
}
|
||||
//上下限值
|
||||
topLimit.push([item.value[j][0], item.topLimit.toFixed(3)]);
|
||||
lowerLimit.push([item.value[j][0], item.lowerLimit.toFixed(3)]);
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
avalue = [];
|
||||
bvalue = [];
|
||||
cvalue = [];
|
||||
}
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
maxValue: max,
|
||||
minValue: min,
|
||||
avalue: avalue,
|
||||
bvalue: bvalue,
|
||||
cvalue: cvalue,
|
||||
topLimit: topLimit,
|
||||
lowerLimit: lowerLimit,
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
//图列为频率等,上限,下限
|
||||
if (item.phaiscType.length == 3) {
|
||||
let gvalue = [];
|
||||
let topLimit = [];
|
||||
let lowerLimit = [];
|
||||
item.maxValue = item.topLimit;
|
||||
item.minValue = item.lowerLimit;
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
gvalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
gvalue.push([]);
|
||||
}
|
||||
//上下限值
|
||||
topLimit.push([item.value[j][0], item.topLimit.toFixed(3)]);
|
||||
lowerLimit.push([item.value[j][0], item.lowerLimit.toFixed(3)]);
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
gvalue = [];
|
||||
}
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
maxValue: max,
|
||||
minValue: min,
|
||||
gvalue: gvalue,
|
||||
topLimit: topLimit,
|
||||
lowerLimit: lowerLimit,
|
||||
chufa: [],
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
} else {
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: null,
|
||||
avalue: [],
|
||||
bvalue: [],
|
||||
cvalue: [],
|
||||
topLimit: [],
|
||||
lowerLimit: [],
|
||||
chufa: [],
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
}
|
||||
//有上限值
|
||||
if (item.topLimit !== 0 && item.lowerLimit == 0) {
|
||||
item.phaiscType.push("上限");
|
||||
if (item.minValue !== null) {
|
||||
//最小值等于下限值
|
||||
//图列为A,B,C,上限
|
||||
if (item.phaiscType.length == 4) {
|
||||
let avalue = [];
|
||||
let bvalue = [];
|
||||
let cvalue = [];
|
||||
let topLimit = [];
|
||||
item.maxValue = item.topLimit;
|
||||
// item.minValue=item.lowerLimit
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
avalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
avalue.push([]);
|
||||
}
|
||||
//判断存在缺失值b
|
||||
if (item.value[j][2] != undefined) {
|
||||
bvalue.push([item.value[j][0], item.value[j][2].toFixed(3)]);
|
||||
} else {
|
||||
bvalue.push([]);
|
||||
}
|
||||
//判断存在缺失值c
|
||||
if (item.value[j][3] != undefined) {
|
||||
cvalue.push([item.value[j][0], item.value[j][3].toFixed(3)]);
|
||||
} else {
|
||||
cvalue.push([]);
|
||||
}
|
||||
//上限值
|
||||
topLimit.push([item.value[j][0], item.topLimit.toFixed(3)]);
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
avalue = [];
|
||||
bvalue = [];
|
||||
cvalue = [];
|
||||
}
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
maxValue: max,
|
||||
minValue: min,
|
||||
avalue: avalue,
|
||||
bvalue: bvalue,
|
||||
cvalue: cvalue,
|
||||
topLimit: topLimit,
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
//图列为频率等,上限
|
||||
if (item.phaiscType.length == 2) {
|
||||
let gvalue = [];
|
||||
let topLimit = [];
|
||||
item.maxValue = item.topLimit;
|
||||
// item.minValue=item.lowerLimit
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
gvalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
gvalue.push([]);
|
||||
}
|
||||
//上限值
|
||||
topLimit.push([item.value[j][0], item.topLimit.toFixed(3)]);
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
gvalue = [];
|
||||
}
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: min,
|
||||
maxValue: max,
|
||||
gvalue: gvalue,
|
||||
topLimit: topLimit,
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
} else {
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: null,
|
||||
avalue: [],
|
||||
bvalue: [],
|
||||
cvalue: [],
|
||||
topLimit: [],
|
||||
lowerLimit: [],
|
||||
chufa: [],
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
}
|
||||
|
||||
//无限值
|
||||
if (item.topLimit == 0 && item.lowerLimit == 0) {
|
||||
if (item.minValue !== null) {
|
||||
//最小值等于下限值
|
||||
//图列为A,B,C
|
||||
if (item.phaiscType.length == 3) {
|
||||
let avalue = [];
|
||||
let bvalue = [];
|
||||
let cvalue = [];
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
avalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
avalue.push([]);
|
||||
}
|
||||
//判断存在缺失值b
|
||||
if (item.value[j][2] != undefined) {
|
||||
bvalue.push([item.value[j][0], item.value[j][2].toFixed(3)]);
|
||||
} else {
|
||||
bvalue.push([]);
|
||||
}
|
||||
//判断存在缺失值c
|
||||
if (item.value[j][3] != undefined) {
|
||||
cvalue.push([item.value[j][0], item.value[j][3].toFixed(3)]);
|
||||
} else {
|
||||
cvalue.push([]);
|
||||
}
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
avalue = [];
|
||||
bvalue = [];
|
||||
cvalue = [];
|
||||
}
|
||||
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: min,
|
||||
maxValue: max,
|
||||
avalue: avalue,
|
||||
bvalue: bvalue,
|
||||
cvalue: cvalue,
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
//图列为频率等
|
||||
if (item.phaiscType.length == 1) {
|
||||
let gvalue = [];
|
||||
//判断数据是否存在
|
||||
if (item.value !== null) {
|
||||
for (let j = 0; j < item.value.length; j++) {
|
||||
//判断存在缺失值a
|
||||
if (item.value[j][1] != undefined) {
|
||||
gvalue.push([item.value[j][0], item.value[j][1].toFixed(3)]);
|
||||
} else {
|
||||
gvalue.push([]);
|
||||
}
|
||||
}
|
||||
//数据为空
|
||||
} else {
|
||||
gvalue = [];
|
||||
}
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: min,
|
||||
maxValue: max,
|
||||
gvalue: gvalue,
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
} else {
|
||||
let shuju = {
|
||||
id: "qushifenx" + i,
|
||||
title: item.lineName + "--" + item.targetName,
|
||||
targetName: item.targetName,
|
||||
legend: item.phaiscType,
|
||||
valueName: item.unit[0],
|
||||
minValue: null,
|
||||
avalue: [],
|
||||
bvalue: [],
|
||||
cvalue: [],
|
||||
topLimit: [],
|
||||
lowerLimit: [],
|
||||
chufa: [],
|
||||
};
|
||||
list.value.push(shuju);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rendering();
|
||||
};
|
||||
const rendering = () => {
|
||||
list.value.forEach((item: any) => {
|
||||
let opitonserise: any[] = [];
|
||||
item.legend.forEach((item2: any) => {
|
||||
if (
|
||||
item.avalue !== undefined &&
|
||||
(item2 == "A相" || item2 == "AB相" || item2 == "零序电压")
|
||||
) {
|
||||
let data = {
|
||||
name: item2,
|
||||
symbol: "none",
|
||||
symbolSize: 5,
|
||||
type: "line",
|
||||
smooth: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#DAA520",
|
||||
},
|
||||
},
|
||||
|
||||
data: item.avalue,
|
||||
};
|
||||
opitonserise.push(data);
|
||||
} else if (
|
||||
item.bvalue !== undefined &&
|
||||
(item2 == "B相" || item2 == "BC相" || item2 == "正序电压")
|
||||
) {
|
||||
let data = {
|
||||
name: item2,
|
||||
symbol: "none",
|
||||
symbolSize: 5,
|
||||
type: "line",
|
||||
smooth: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#2E8B57",
|
||||
},
|
||||
},
|
||||
|
||||
data: item.bvalue,
|
||||
};
|
||||
opitonserise.push(data);
|
||||
} else if (
|
||||
item.cvalue !== undefined &&
|
||||
(item2 == "C相" || item2 == "CA相" || item2 == "负序电压")
|
||||
) {
|
||||
let data = {
|
||||
name: item2,
|
||||
symbol: "none",
|
||||
symbolSize: 5,
|
||||
type: "line",
|
||||
smooth: true,
|
||||
barWidth: 22,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#A52a2a",
|
||||
},
|
||||
},
|
||||
data: item.cvalue,
|
||||
};
|
||||
opitonserise.push(data);
|
||||
}
|
||||
});
|
||||
if (item.valueName == undefined) {
|
||||
item.valueName = "无";
|
||||
}
|
||||
opitonserise[0].markLine = {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
lineStyle: {
|
||||
type: "dashed", //dotted、solid
|
||||
color: "#FF33FF",
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
color: "#fff",
|
||||
formatter: function (params) {
|
||||
return `标准值`;
|
||||
},
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: "标准值",
|
||||
yAxis: condition.value == '42' ? rowData.value.vavgValue : rowData.value.iavgValue,
|
||||
},
|
||||
],
|
||||
};
|
||||
// console.log("🚀 ~ rendering ~ row.value:", rowData.value);
|
||||
|
||||
// console.log("🚀 ~ rendering ~ opitonserise:", opitonserise);
|
||||
item.serise = opitonserise;
|
||||
});
|
||||
|
||||
getEcharts();
|
||||
};
|
||||
const getEcharts = () => {
|
||||
list.value.forEach((item: any, i: number) => {
|
||||
console.log("🚀 ~ getEcharts ~ item:", item)
|
||||
item.option = {
|
||||
backgroundColor: "#fff",
|
||||
title: {
|
||||
left: "center",
|
||||
text: item.title,
|
||||
},
|
||||
tooltip: {
|
||||
top: "10px",
|
||||
trigger: "axis",
|
||||
borderColor: "grey",
|
||||
style: {
|
||||
color: "#fff",
|
||||
fontSize: "15px",
|
||||
padding: 10,
|
||||
},
|
||||
formatter: function (params) {
|
||||
// console.log(params)
|
||||
let tips = "";
|
||||
tips += "时刻:" + params[0].data[0] + "</br/>";
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
if (params[i].seriesName != "暂降触发点") {
|
||||
tips +=
|
||||
params[i].marker +
|
||||
params[i].seriesName +
|
||||
":" +
|
||||
(params[i].value[1] - 0).toFixed(2) +
|
||||
"<br/>";
|
||||
}
|
||||
}
|
||||
return tips;
|
||||
},
|
||||
// axisPointer: {
|
||||
// type: "cross",
|
||||
// label: {
|
||||
// color: "#fff",
|
||||
// fontSize: 16,
|
||||
// },
|
||||
// },
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontStyle: "normal",
|
||||
opacity: 0.35,
|
||||
fontSize: 14,
|
||||
},
|
||||
backgroundColor: "rgba(0,0,0,0.55)",
|
||||
borderWidth: 0,
|
||||
},
|
||||
|
||||
legend: {
|
||||
right: 50,
|
||||
top: 25,
|
||||
verticalAlign: "top",
|
||||
enabled: true,
|
||||
itemDistance: 5,
|
||||
textStyle: {
|
||||
fontSize: "0.6rem",
|
||||
color: "#fff",
|
||||
rich: {
|
||||
a: {
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
},
|
||||
|
||||
padding: [0, 0, 0, 0], //[上、右、下、左]
|
||||
},
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "time",
|
||||
axisLine: {
|
||||
show: true,
|
||||
onZero: false,
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
fontFamily: "dinproRegular",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
toolbox: {
|
||||
show: false,
|
||||
feature: {
|
||||
dataZoom: {
|
||||
// bottom: '10px',
|
||||
yAxisIndex: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
min: item.minValue,
|
||||
max: item.maxValue,
|
||||
name: item.valueName,
|
||||
|
||||
|
||||
axisLine: {
|
||||
show: true,
|
||||
onZero: false, //-----------重点
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
// 使用深浅的间隔色
|
||||
type: "dashed",
|
||||
opacity: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
series: item.serise,
|
||||
};
|
||||
let aValues = [];
|
||||
let bValues = [];
|
||||
let CValues = [];
|
||||
let ZValues = [];
|
||||
|
||||
if (
|
||||
traceability.value.length > 0 &&
|
||||
traceability.value[0].value != null &&
|
||||
traceability.value[0].value.length > 0
|
||||
) {
|
||||
for (let i = 0; i < traceability.value[0].value.length; i++) {
|
||||
let T = traceability.value[0].value[i][0];
|
||||
let A = traceability.value[0].value[i][1];
|
||||
let B = traceability.value[0].value[i][2];
|
||||
let C = traceability.value[0].value[i][3];
|
||||
let Z = A + B + C;
|
||||
aValues.push([T, A > 0 ? 1 : A == 0 ? 0 : -1]);
|
||||
bValues.push([T, B > 0 ? 1 : B == 0 ? 0 : -1]);
|
||||
CValues.push([T, C > 0 ? 1 : C == 0 ? 0 : -1]);
|
||||
ZValues.push([T, Z > 0 ? 1 : Z == 0 ? 0 : -1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
visible.value = false;
|
||||
options.value = null;
|
||||
emit("close");
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
583
src/views/SagTraceResult_WX/components/manage/iframeDia.vue
Normal file
583
src/views/SagTraceResult_WX/components/manage/iframeDia.vue
Normal file
@@ -0,0 +1,583 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<!-- 使用 v-for 遍历四个角落 -->
|
||||
<div
|
||||
v-for="corner in corners"
|
||||
:key="corner.id"
|
||||
v-show="corner.show"
|
||||
:class="['corner', corner.className]"
|
||||
>
|
||||
<div class="content">
|
||||
<div class="title">{{ corner.title }}</div>
|
||||
<el-descriptions :column="1" size="small" label-width="70px" border>
|
||||
<el-descriptions-item
|
||||
v-for="(item, index) in corner.data"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
>
|
||||
<!-- {{ item.value }} -->
|
||||
<div v-html="item.value" v-if="item.label !== '暂降次数'"></div>
|
||||
<!-- 跑马灯 -->
|
||||
<div v-else style="display: flex">
|
||||
<div style="width: 30px">{{ corner.raceLists.length }}次</div>
|
||||
<div class="simple-marquee">
|
||||
<div class="marquee-content">
|
||||
<span
|
||||
style="margin-right: 15px"
|
||||
v-for="(event, index) in corner.raceLists"
|
||||
:key="index"
|
||||
@click="goToRace(event)"
|
||||
>{{
|
||||
index +
|
||||
1 +
|
||||
"、" +
|
||||
event.startTime +
|
||||
"发生" +
|
||||
event.eventType +
|
||||
"," +
|
||||
"残余电压:" +
|
||||
(event.featureAmplitude * 100).toFixed(2) +
|
||||
"%" +
|
||||
"," +
|
||||
"持续时间:" +
|
||||
event.duration +
|
||||
"S"
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<span class="close-btn" @click="closeCorner(corner.id)">
|
||||
<Close />
|
||||
</span>
|
||||
</div>
|
||||
<DipDetail ref="dipDetail"></DipDetail>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick, reactive } from "vue";
|
||||
import { clickImage, realTimeData } from "@/api/manage_wx";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import socketClient from "@/utils/webSocketClient";
|
||||
import DipDetail from "../eventStatistics/dipDetail.vue";
|
||||
|
||||
// 定义接收的 props
|
||||
const props = defineProps<{
|
||||
eventList?: [];
|
||||
}>();
|
||||
//开始创建webSocket客户端
|
||||
const dataSocket = reactive({
|
||||
socketServe: socketClient.Instance,
|
||||
});
|
||||
// 定义四个角落的数据
|
||||
const corners = ref([
|
||||
{
|
||||
id: "topLeft",
|
||||
title: "左上",
|
||||
className: "top-left",
|
||||
show: false,
|
||||
data: [] as { label: string; value: string }[],
|
||||
elementId: "", // 记录该角落对应的元素ID
|
||||
raceLists: [] as any[], // 为每个角落添加独立的跑马灯数据存储
|
||||
},
|
||||
{
|
||||
id: "topRight",
|
||||
title: "右上",
|
||||
className: "top-right",
|
||||
show: false,
|
||||
data: [] as { label: string; value: string }[],
|
||||
elementId: "",
|
||||
raceLists: [] as any[], // 为每个角落添加独立的跑马灯数据存储
|
||||
},
|
||||
// {
|
||||
// id: "bottomLeft",
|
||||
// title: "左下",
|
||||
// className: "bottom-left",
|
||||
// show: false,
|
||||
// data: [] as { label: string; value: string }[],
|
||||
// elementId: "",
|
||||
// },
|
||||
// {
|
||||
// id: "bottomRight",
|
||||
// title: "右下",
|
||||
// className: "bottom-right",
|
||||
// show: false,
|
||||
// data: [] as { label: string; value: string }[],
|
||||
// elementId: "",
|
||||
// },
|
||||
]);
|
||||
const steadyStateList = ref([]);
|
||||
|
||||
const selectedId = ref("");
|
||||
|
||||
// 内部响应式数据
|
||||
const eventList = ref([]);
|
||||
|
||||
// 点击跑马灯展示弹框
|
||||
const dipDetail = ref(null);
|
||||
|
||||
const handleClickImage = async (elementId: string) => {
|
||||
// 检查 elementId 是否有值,没有值则直接返回空数组
|
||||
if (!elementId) {
|
||||
eventList.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 发送点击图片请求
|
||||
const res = await clickImage({ lineId: elementId });
|
||||
|
||||
// 确保返回的数据是数组格式,并且过滤掉 null/undefined 元素
|
||||
let dataToStore: any[] = [];
|
||||
|
||||
if (Array.isArray(res.data)) {
|
||||
dataToStore = res.data.filter(
|
||||
(item) => item !== null && item !== undefined
|
||||
);
|
||||
} else if (res.data && Array.isArray(res.data.records)) {
|
||||
dataToStore = res.data.records.filter(
|
||||
(item) => item !== null && item !== undefined
|
||||
);
|
||||
} else if (res.data) {
|
||||
// 如果是单个对象且不为 null
|
||||
if (res.data !== null && res.data !== undefined) {
|
||||
dataToStore = [res.data];
|
||||
}
|
||||
}
|
||||
|
||||
eventList.value = dataToStore;
|
||||
} catch (error) {
|
||||
console.error("调用 clickImage 接口出错:", error);
|
||||
// 出错时设置为空数组,避免后续处理出错
|
||||
eventList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 监听 props 变化
|
||||
// watch(
|
||||
// () => props.eventList,
|
||||
// (newVal) => {
|
||||
// if (newVal && Array.isArray(newVal)) {
|
||||
// eventList.value = [...newVal];
|
||||
// dataLoaded.value = true;
|
||||
// } else {
|
||||
// dataLoaded.value = false;
|
||||
// }
|
||||
// },
|
||||
// { immediate: true, deep: true }
|
||||
// );
|
||||
|
||||
// 记录显示顺序,用于循环替换
|
||||
const displayOrder = ref<number[]>([]);
|
||||
|
||||
// 计算跑马灯动画时长(毫秒)
|
||||
const calculateMarqueeDuration = (corner) => {
|
||||
if (!corner.raceLists || corner.raceLists.length === 0) {
|
||||
return 25000; // 默认25秒
|
||||
}
|
||||
|
||||
// 计算所有事件文本的总长度
|
||||
let totalTextLength = 0;
|
||||
corner.raceLists.forEach((event, index) => {
|
||||
const text = `${index + 1}、${event.startTime}发生${
|
||||
event.eventType
|
||||
},残余电压:${(event.featureAmplitude * 100).toFixed(2)}%,持续时间:${
|
||||
event.duration
|
||||
}S`;
|
||||
totalTextLength += text.length;
|
||||
});
|
||||
|
||||
// 添加分隔符长度和边距
|
||||
const separatorLength =
|
||||
corner.raceLists.length > 1 ? (corner.raceLists.length - 1) * 15 : 0; // margin-right: 15px
|
||||
totalTextLength += separatorLength;
|
||||
|
||||
// 根据文本长度计算时长(减慢速度)
|
||||
// 将每字符需要的时间从50ms增加到80ms,最少8秒,最多90秒
|
||||
const duration = Math.min(Math.max(totalTextLength * 80, 8000), 90000);
|
||||
return duration;
|
||||
};
|
||||
|
||||
// 更新指定角落数据的函数
|
||||
const updateCornerData = (
|
||||
cornerIndex: number,
|
||||
dataItem: any,
|
||||
elementId: string
|
||||
) => {
|
||||
// 更新标题为 objName
|
||||
if (dataItem.objName) {
|
||||
corners.value[cornerIndex].title = dataItem.objName;
|
||||
} else {
|
||||
corners.value[cornerIndex].title = dataItem.stationName;
|
||||
}
|
||||
|
||||
// 格式化数据
|
||||
corners.value[cornerIndex].data = [
|
||||
{ label: "监测点", value: dataItem.lineName },
|
||||
// {
|
||||
// label: "暂降次数",
|
||||
// value: dataItem.eventIds.length,
|
||||
// },
|
||||
{
|
||||
label: "暂降次数",
|
||||
value: ``,
|
||||
},
|
||||
// { label: "稳态指标", value: "Ua:65.5 Ub:65.02 Uc:65.27 Uac:112.85 Uab:112.67 Ubc:112.85" },
|
||||
{
|
||||
label: "稳态指标",
|
||||
value: ``,
|
||||
},
|
||||
];
|
||||
|
||||
// 记录该角落对应的元素ID
|
||||
corners.value[cornerIndex].elementId = elementId;
|
||||
corners.value[cornerIndex].show = true;
|
||||
|
||||
// 设置动画时长
|
||||
nextTick(() => {
|
||||
const duration = calculateMarqueeDuration(corners.value[cornerIndex]);
|
||||
const marqueeElement = document.querySelector(
|
||||
`.${corners.value[cornerIndex].className} .marquee-content`
|
||||
);
|
||||
if (marqueeElement) {
|
||||
(marqueeElement as HTMLElement).style.setProperty(
|
||||
"--marquee-duration",
|
||||
`${duration}ms`
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 显示下一个角落的函数
|
||||
const showNextCorner = (elementId: string) => {
|
||||
// 检查该元素ID是否已经显示过
|
||||
const existingCornerIndex = corners.value.findIndex(
|
||||
(corner) => corner.elementId === elementId && corner.show
|
||||
);
|
||||
|
||||
if (existingCornerIndex !== -1) {
|
||||
// 如果该元素已经显示过,不更新数据
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保 eventList.value 是数组并且过滤掉 null/undefined 元素
|
||||
if (!Array.isArray(eventList.value)) {
|
||||
console.warn("eventList.value 不是数组格式:", eventList.value);
|
||||
return;
|
||||
}
|
||||
|
||||
// 过滤掉 null 和 undefined 元素,然后查找匹配项
|
||||
const validItems = eventList.value.filter(
|
||||
(item) => item !== null && item !== undefined
|
||||
);
|
||||
const dataItem = validItems.find((item) => item.lineId === elementId);
|
||||
|
||||
// 如果没有找到匹配的数据项,则不更新数据
|
||||
if (!dataItem) {
|
||||
console.warn("未找到匹配的数据项:", elementId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找一个未显示的角落
|
||||
const availableCornerIndex = corners.value.findIndex(
|
||||
(corner) => !corner.show
|
||||
);
|
||||
|
||||
if (availableCornerIndex !== -1) {
|
||||
// 有空闲角落,显示在该角落
|
||||
updateCornerData(availableCornerIndex, dataItem, elementId);
|
||||
// 将事件数据存储到该角落
|
||||
corners.value[availableCornerIndex].raceLists = dataItem.eventList || [];
|
||||
// 记录显示顺序
|
||||
displayOrder.value.push(availableCornerIndex);
|
||||
} else {
|
||||
// 没有空闲角落,按顺序替换角落
|
||||
// 获取需要替换的角落索引(循环替换)
|
||||
const replaceIndex = displayOrder.value.shift() || 0;
|
||||
updateCornerData(replaceIndex, dataItem, elementId);
|
||||
// 将事件数据存储到该角落
|
||||
corners.value[replaceIndex].raceLists = dataItem.eventList || [];
|
||||
// 将替换的索引重新加入队列末尾
|
||||
displayOrder.value.push(replaceIndex);
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭指定角落的函数
|
||||
const closeCorner = (id: string) => {
|
||||
const cornerIndex = corners.value.findIndex((c) => c.id === id);
|
||||
if (cornerIndex !== -1) {
|
||||
corners.value[cornerIndex].show = false;
|
||||
corners.value[cornerIndex].elementId = ""; // 清空元素ID记录
|
||||
|
||||
// 从显示顺序中移除该角落索引
|
||||
const orderIndex = displayOrder.value.indexOf(cornerIndex);
|
||||
if (orderIndex !== -1) {
|
||||
displayOrder.value.splice(orderIndex, 1);
|
||||
}
|
||||
}
|
||||
send();
|
||||
};
|
||||
|
||||
// 关闭所有角落的函数
|
||||
const closeAllCorners = () => {
|
||||
corners.value.forEach((corner) => {
|
||||
corner.show = false;
|
||||
corner.elementId = "";
|
||||
});
|
||||
displayOrder.value = [];
|
||||
};
|
||||
|
||||
// 组件挂载后初始化监听器
|
||||
onMounted(() => {
|
||||
init();
|
||||
// 初始化时不显示任何内容
|
||||
});
|
||||
|
||||
// 连接webSocket客户端
|
||||
const init = () => {
|
||||
if (!dataSocket.socketServe) {
|
||||
console.error("WebSocket 客户端实例不存在");
|
||||
return;
|
||||
}
|
||||
dataSocket.socketServe.connect(new Date().getTime());
|
||||
dataSocket.socketServe.registerCallBack("message", (res: any) => {
|
||||
if (res.type == 1) {
|
||||
//稳态指标数据
|
||||
let steadyState = JSON.parse(res.message);
|
||||
|
||||
// console.log(steadyState, "8990hhhhh");
|
||||
if (steadyState == null || steadyState.length == 0) return;
|
||||
steadyStateList.value = steadyState;
|
||||
corners.value.forEach((corner, index) => {
|
||||
let str = ``;
|
||||
steadyState
|
||||
.filter((item) => item.lineId == corner.elementId)
|
||||
.forEach((item) => {
|
||||
if (item.value == 3.1415926) {
|
||||
str += `<div>${item.statisticalName}:/</div>`;
|
||||
} else {
|
||||
str += `<div>${item.statisticalName}:${item.value}${item.unit}</div>`;
|
||||
}
|
||||
});
|
||||
|
||||
corner.data.length > 0
|
||||
? (corner.data[2].value = `<div style="max-height: 100px;overflow-y: auto;">${str} </div>`)
|
||||
: "";
|
||||
|
||||
// 更新跑马灯动画时长
|
||||
nextTick(() => {
|
||||
const duration = calculateMarqueeDuration(corner);
|
||||
const marqueeElement = document.querySelector(
|
||||
`.${corner.className} .marquee-content`
|
||||
);
|
||||
if (marqueeElement) {
|
||||
(marqueeElement as HTMLElement).style.setProperty(
|
||||
"--marquee-duration",
|
||||
`${duration}ms`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const time = ref(null);
|
||||
// 推送消息
|
||||
const send = () => {
|
||||
dataSocket.socketServe.send({
|
||||
pageId: selectedId.value,
|
||||
lineIdList: corners.value
|
||||
.filter((item) => item.show == true)
|
||||
.map((corner) => corner.elementId),
|
||||
});
|
||||
if (time.value) {
|
||||
clearTimeout(time.value);
|
||||
}
|
||||
if (
|
||||
corners.value
|
||||
.filter((item) => item.show == true)
|
||||
.map((corner) => corner.elementId).length == 0
|
||||
)
|
||||
return;
|
||||
time.value = setInterval(() => {
|
||||
dataSocket.socketServe.send({
|
||||
pageId: selectedId.value,
|
||||
lineIdList: corners.value
|
||||
.filter((item) => item.show == true)
|
||||
.map((corner) => corner.elementId),
|
||||
});
|
||||
}, 1000 * 60);
|
||||
};
|
||||
|
||||
const goToRace = (row) => {
|
||||
console.log(row.measurementPointId, "1222");
|
||||
dipDetail.value.open(row.measurementPointId);
|
||||
};
|
||||
|
||||
// 监听来自 iframe 的消息
|
||||
window.addEventListener("message", async function (event) {
|
||||
// 安全起见,可以验证消息来源(origin)
|
||||
// if (event.origin !== 'https://trusted-origin.com') return;
|
||||
|
||||
// 处理从 iframe 发送过来的消息
|
||||
if (event.data.action === "coreClick") {
|
||||
const clickedElementId = event.data.coreId;
|
||||
selectedId.value = event.data.selectedId;
|
||||
|
||||
// 调用接口获取最新数据
|
||||
await handleClickImage(clickedElementId);
|
||||
|
||||
// 根据接收到的元素LineId显示对应数据
|
||||
await showNextCorner(clickedElementId);
|
||||
|
||||
await send();
|
||||
}
|
||||
});
|
||||
|
||||
// 页面卸载时清除定时器
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(time.value);
|
||||
dataSocket.socketServe?.closeWs();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 走马灯样式 - 支持逐条显示 */
|
||||
.simple-marquee {
|
||||
width: 230px;
|
||||
height: 24px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.marquee-content {
|
||||
display: inline-block;
|
||||
padding-left: 100%;
|
||||
/* animation: marquee-single 15s linear infinite; */
|
||||
animation: marquee-single var(--marquee-duration, 25s) linear infinite;
|
||||
line-height: 24px;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #4877f6;
|
||||
}
|
||||
|
||||
@keyframes marquee-single {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* 鼠标悬停时暂停动画 */
|
||||
.simple-marquee:hover .marquee-content {
|
||||
animation-play-state: paused;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.corner {
|
||||
width: 340px;
|
||||
/* height: 135px; */
|
||||
background-color: #2b2d3a90;
|
||||
position: absolute;
|
||||
color: white;
|
||||
/* font-weight: bold; */
|
||||
/* 添加弹出动画 */
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
transition: all 0.4s ease-out;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 显示状态的样式 */
|
||||
.corner:not([style*="display: none"]):not([style*="display:none"]) {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.top-left {
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.top-right {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.bottom-left {
|
||||
top: 170px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.bottom-right {
|
||||
top: 170px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
/* text-align: center; */
|
||||
/* margin-bottom: 8px; */
|
||||
padding: 8px;
|
||||
/* color: #409eff; */
|
||||
border-bottom: 1px solid #444;
|
||||
background-color: #21232b;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.data-item {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.label {
|
||||
/* font-weight: bold; */
|
||||
width: 55px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 关闭按钮样式 */
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 14px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
651
src/views/SagTraceResult_WX/components/manage/index.vue
Normal file
651
src/views/SagTraceResult_WX/components/manage/index.vue
Normal file
@@ -0,0 +1,651 @@
|
||||
<template>
|
||||
<!-- 项目管理弹框 -->
|
||||
<el-dialog v-model="dialogVisible" title="项目管理" width="1600px">
|
||||
<!-- <el-card class="transparent-card"> -->
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div>
|
||||
<span style="width: 80px; color: #fff">项目名称</span>
|
||||
<el-input
|
||||
v-model.trim="projectName"
|
||||
maxlength="32"
|
||||
placeholder="请输入项目名称"
|
||||
show-word-limit
|
||||
style="width: 300px; margin-left: 10px"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<el-button :icon="Search" size="small" type="primary" @click="onSearch">
|
||||
查询</el-button
|
||||
>
|
||||
<!-- <el-button :icon="RefreshLeft" size="small" @click="onReset"
|
||||
>重置</el-button
|
||||
> -->
|
||||
<el-button :icon="Plus" size="small" type="primary" @click="onSubmitadd"
|
||||
>新增</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </el-card> -->
|
||||
<div
|
||||
style="
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding: 0 10px;
|
||||
margin-top: 10px;
|
||||
height: 660px;
|
||||
"
|
||||
>
|
||||
<el-row :gutter="12">
|
||||
<el-col
|
||||
:span="6"
|
||||
v-for="item in projectData"
|
||||
:key="item.id"
|
||||
class="mt10"
|
||||
>
|
||||
<el-card class="box-card" @click="querdata(item)" shadow="hover">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="display: flex; align-items: center; color: #fff"
|
||||
>{{ item.name }}
|
||||
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="修改项目"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon
|
||||
:size="20"
|
||||
class="color"
|
||||
style="cursor: pointer; margin-left: 5px"
|
||||
>
|
||||
<Edit @click="editd(item)" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
|
||||
<!-- <el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
content="修改项目"
|
||||
placement="top"
|
||||
>
|
||||
<Edit
|
||||
style="margin-left: 5px; width: 16px"
|
||||
class="xiaoshou color"
|
||||
@click="editd(item)"
|
||||
/> </el-tooltip
|
||||
> -->
|
||||
</span>
|
||||
<div style="display: flex; justify-content: end">
|
||||
<el-button
|
||||
v-if="item.active == 0"
|
||||
class="color"
|
||||
:icon="Compass"
|
||||
style="padding: 3px 0"
|
||||
type="text"
|
||||
@click="activeItem(item)"
|
||||
>激活</el-button
|
||||
>
|
||||
<el-button
|
||||
v-else
|
||||
class="color"
|
||||
style="padding: 3px 0; color: #82bd51"
|
||||
type="text"
|
||||
>已激活</el-button
|
||||
>
|
||||
<el-button
|
||||
class="color"
|
||||
:icon="Share"
|
||||
style="padding: 3px 0"
|
||||
type="text"
|
||||
@click="Aclick(item)"
|
||||
>设计</el-button
|
||||
>
|
||||
|
||||
<el-button
|
||||
:icon="Delete"
|
||||
style="padding: 3px 0; color: #c93434"
|
||||
type="text"
|
||||
@click="deleted(item)"
|
||||
>删除</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
v-if="item.fileContent"
|
||||
:src="item.fileContent"
|
||||
class="image xiaoshou"
|
||||
@click="imgData(item)"
|
||||
/>
|
||||
<el-empty v-else description="暂无设计" style="height: 220px" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- <template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
</div>
|
||||
</template> -->
|
||||
<div class="table-pagination">
|
||||
<el-pagination
|
||||
small
|
||||
:currentPage="params.pageNum"
|
||||
:page-size="params.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="params.total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 新增弹框 -->
|
||||
<el-dialog v-model="innerVisible" :title="dialogTitle" width="500px">
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
class="demo-ruleForm"
|
||||
:size="formSize"
|
||||
status-icon
|
||||
>
|
||||
<el-form-item label="项目名称" prop="name">
|
||||
<el-input
|
||||
v-model="ruleForm.name"
|
||||
maxlength="32"
|
||||
show-word-limit
|
||||
placeholder="请输入项目名称"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="工程项目" prop="projectIds">
|
||||
<el-select
|
||||
v-model="ruleForm.projectIds"
|
||||
placeholder="请选择"
|
||||
:popper-append-to-body="false"
|
||||
popper-class="custom-select-dropdown"
|
||||
>
|
||||
<el-option label="Zone one111" value="shanghai" />
|
||||
<el-option label="Zone two" value="beijing" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="项目排序" prop="orderBy">
|
||||
<el-input v-model="ruleForm.orderBy" placeholder="请输入" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="ruleForm.remark" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button size="small" type="primary" @click="submitForm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
<el-button size="small" @click="resetForm">取消</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
reactive,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
} from "vue";
|
||||
import {
|
||||
Search,
|
||||
RefreshLeft,
|
||||
Plus,
|
||||
Share,
|
||||
Delete,
|
||||
Edit,
|
||||
Compass,
|
||||
} from "@element-plus/icons-vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type { FormInstance, FormRules } from "element-plus";
|
||||
import {
|
||||
projectList,
|
||||
add,
|
||||
edit,
|
||||
active,
|
||||
getActive,
|
||||
} from "@/api/manage_wx/index";
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "project-change", project: { id: string; name: string }): void;
|
||||
}>();
|
||||
|
||||
const projectData = ref([]);
|
||||
|
||||
// 系统配置弹框
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const innerVisible = ref(false);
|
||||
|
||||
const projectName = ref("");
|
||||
|
||||
const dialogTitle = ref("新增项目");
|
||||
|
||||
const firstForm = ref({
|
||||
name: "",
|
||||
id: "",
|
||||
});
|
||||
|
||||
const params = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
interface RuleForm {
|
||||
name: string;
|
||||
projectIds: [];
|
||||
orderBy: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
const formSize = ref("default");
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
const ruleForm = reactive<RuleForm>({
|
||||
name: "",
|
||||
projectIds: [],
|
||||
orderBy: "100",
|
||||
remark: "",
|
||||
});
|
||||
|
||||
const rules = reactive<FormRules<RuleForm>>({
|
||||
name: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
|
||||
projectIds: [
|
||||
{
|
||||
required: true,
|
||||
message: "请选择",
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
orderBy: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入项目排序",
|
||||
trigger: "change",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
fetachData();
|
||||
});
|
||||
|
||||
// 创建一个专门发送数据到 iframe 的函数
|
||||
const sendToIframe = (type: string, data: any) => {
|
||||
try {
|
||||
// 确保数据可以被序列化
|
||||
const serializableData = JSON.parse(JSON.stringify(data));
|
||||
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: type,
|
||||
data: serializableData,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("发送到 iframe 失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetachData = async () => {
|
||||
const res = await projectList({
|
||||
pageNum: params.pageNum,
|
||||
pageSize: params.pageSize,
|
||||
searchValue: projectName.value,
|
||||
});
|
||||
// projectData.splice(0, projectData.length, ...res.records);
|
||||
projectData.value = res.data.records;
|
||||
params.total = res.data.total;
|
||||
|
||||
if (res.data.records.length > 0) {
|
||||
firstForm.value.id = res.data.records[0].id;
|
||||
firstForm.value.name = res.data.records[0].name;
|
||||
}
|
||||
};
|
||||
|
||||
// 查询
|
||||
const onSearch = () => {
|
||||
fetachData();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onReset = () => {
|
||||
projectName.value = "";
|
||||
fetachData();
|
||||
};
|
||||
|
||||
// 新增
|
||||
const onSubmitadd = () => {
|
||||
innerVisible.value = true;
|
||||
dialogTitle.value = "新增项目";
|
||||
// Object.assign(ruleForm, {}); 不生效
|
||||
Object.assign(ruleForm, {
|
||||
//生效,但是一个个赋值,麻烦
|
||||
id: "0944fe372e90daeefd040916a105ac8b",
|
||||
name: "",
|
||||
orderBy: "100",
|
||||
projectIds: ["1dd1b076e104f15459ac401fc1b902c4"],
|
||||
remark: "",
|
||||
});
|
||||
//Object.keys(ruleForm).forEach((key) => delete ruleForm[key]); //生效,但是有默认值的,一进去会直接报校验
|
||||
};
|
||||
|
||||
const querdata = (e: any) => {};
|
||||
|
||||
// 编辑修改
|
||||
const editd = (row: any) => {
|
||||
innerVisible.value = true;
|
||||
dialogTitle.value = "修改项目";
|
||||
// Object.assign(ruleForm, row);
|
||||
Object.assign(ruleForm, {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
orderBy: row.orderBy,
|
||||
projectIds: row.projectIds,
|
||||
remark: row.remark,
|
||||
});
|
||||
};
|
||||
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
if (dialogTitle.value == "新增项目") {
|
||||
getAdd();
|
||||
} else {
|
||||
getEdit();
|
||||
}
|
||||
console.log("submit!");
|
||||
} else {
|
||||
console.log("error submit!", fields);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getAdd = async () => {
|
||||
// const params = { ...ruleForm, id: "0944fe372e90daeefd040916a105ac8b" };
|
||||
const res: any = await add(ruleForm);
|
||||
if (res.code == "A0000") {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "新增成功!",
|
||||
});
|
||||
innerVisible.value = false;
|
||||
fetachData();
|
||||
} else {
|
||||
ElMessage({
|
||||
type: "error",
|
||||
message: res.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getEdit = async () => {
|
||||
const res: any = await edit(ruleForm);
|
||||
if (res.code == "A0000") {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "修改成功!",
|
||||
});
|
||||
innerVisible.value = false;
|
||||
fetachData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
innerVisible.value = false;
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
params.pageSize = size;
|
||||
//emit("refreshData"); // 触发父组件方法
|
||||
fetachData();
|
||||
};
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
params.pageNum = page;
|
||||
//emit("refreshData"); // 触发父组件方法
|
||||
fetachData();
|
||||
};
|
||||
|
||||
// 设计
|
||||
const Aclick = (e: any) => {
|
||||
// window.open("http://192.168.1.179:4001" + `/zutai/?id=${e.id}&&name=decodeURI(${e.name})&&flag=false`)
|
||||
// window.open(
|
||||
// window.location.origin +
|
||||
// `/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=true`
|
||||
// );
|
||||
// 无锡项目进去不展示数据绑定图元
|
||||
window.open(
|
||||
"http://192.168.1.179:4001" +
|
||||
`/zutai/?id=${e.id}&&name=${e.name}&&preview=false&&graphicDisplay=wx`
|
||||
);
|
||||
};
|
||||
// 删除
|
||||
const deleted = (e: any) => {
|
||||
ElMessageBox.confirm("此操作将永久删除该项目, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
let data = {
|
||||
id: e.id,
|
||||
name: e.name,
|
||||
status: "0",
|
||||
};
|
||||
edit(data).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "删除项目成功!",
|
||||
});
|
||||
}
|
||||
fetachData();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: "info",
|
||||
message: "已取消删除",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const imgData = (e: any) => {
|
||||
// window.open(window.location.origin + `/zutai/?id=${e.id}&&name=decodeURI(${e.name})&&flag=true`)
|
||||
// window.open(
|
||||
// window.location.origin +
|
||||
// `/zutai/?id=${e.id}&&name=${e.name}&&preview=true#/preview`
|
||||
// );
|
||||
window.open(
|
||||
"http://192.168.1.179:4001" +
|
||||
`/zutai/?id=${e.id}&&name=${e.name}&&preview=true&&graphicDisplay=wx#/preview`
|
||||
);
|
||||
};
|
||||
|
||||
// 获取激活
|
||||
const getActiveItem = () => {
|
||||
getActive({}).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
// 通知父组件
|
||||
emit("project-change", {
|
||||
id: res.data.id,
|
||||
name: res.data.name,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 激活
|
||||
const activeItem = (item: any) => {
|
||||
ElMessageBox.confirm("是否确认激活该项目?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
let data = {
|
||||
id: item.id,
|
||||
};
|
||||
active(data).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "激活成功!",
|
||||
});
|
||||
}
|
||||
fetachData().then(() => {
|
||||
getActiveItem();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: "info",
|
||||
message: "已取消激活",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const open = () => {
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.custom-select-dropdown {
|
||||
// background-color: transparent !important;
|
||||
width: 510px;
|
||||
}
|
||||
|
||||
.custom-select-dropdown .el-select-dropdown__list {
|
||||
// background-color: transparent !important;
|
||||
width: 500px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.item {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.clearfix::before,
|
||||
.clearfix::after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
clear: both;
|
||||
}
|
||||
.box-card {
|
||||
width: 100%;
|
||||
// box-shadow: var(--el-box-shadow-light)
|
||||
background-color: transparent; /* 设置背景颜色为透明 */
|
||||
border: 1px solid gray; /* 添加边框,可以根据需要调整颜色和宽度 */
|
||||
box-shadow: 0 2px 8px gray; /* 添加边框阴影 */
|
||||
}
|
||||
|
||||
.transparent-card {
|
||||
background-color: transparent; /* 设置背景颜色为透明 */
|
||||
border: 1px solid gray; /* 添加边框,可以根据需要调整颜色和宽度 */
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); /* 添加边框阴影 */
|
||||
}
|
||||
|
||||
.xiaoshou {
|
||||
cursor: pointer;
|
||||
}
|
||||
.setstyle {
|
||||
min-height: 200px;
|
||||
padding: 0 !important;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.color {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown__wrap) {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
:deep(.el-tree) {
|
||||
padding-top: 15px;
|
||||
padding-left: 10px;
|
||||
|
||||
// 不可全选样式
|
||||
.el-tree-node {
|
||||
.is-leaf + .el-checkbox .el-checkbox__inner {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.el-checkbox .el-checkbox__inner {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 13px 10px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.table-pagination {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background-color: var(--ba-bg-color-overlay);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-pagination__sizes) {
|
||||
.el-select {
|
||||
min-width: 128px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item .el-form-item__label) {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// :deep(.el-input__wrapper) {
|
||||
// background-color: transparent !important;
|
||||
// }
|
||||
|
||||
// :deep(.el-select__wrapper) {
|
||||
// background-color: transparent !important;
|
||||
// }
|
||||
|
||||
// :deep(.el-textarea__inner) {
|
||||
// background-color: transparent !important;
|
||||
// }
|
||||
|
||||
// :deep(.el-input .el-input__count .el-input__count-inner) {
|
||||
// background-color: transparent !important;
|
||||
// display: inline-block;
|
||||
// line-height: normal;
|
||||
// padding-left: 8px;
|
||||
// }
|
||||
</style>
|
||||
1015
src/views/SagTraceResult_WX/components/manage/securityDetail.vue
Normal file
1015
src/views/SagTraceResult_WX/components/manage/securityDetail.vue
Normal file
File diff suppressed because it is too large
Load Diff
118
src/views/SagTraceResult_WX/components/plan.vue
Normal file
118
src/views/SagTraceResult_WX/components/plan.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="plan">
|
||||
<!-- src=" http://192.168.1.128:3001/zutai/?id=44368e72a2e594d14ebaf317f0f6ad00&&name=decodeURI(APP测试项目)&&flag=true&&wxqr=true#/" -->
|
||||
<!-- <iframe
|
||||
src="http://192.168.1.62:8088/zutai/?id=0944fe372e90daeefd040916a105ac8b&&name=测试组态编辑器&&preview=true#/preview"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
></iframe> -->
|
||||
<!-- 添加加载事件监听 -->
|
||||
<iframe
|
||||
:src="iframeSrc"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
scrolling="no"
|
||||
id="iframeLeft"
|
||||
@load="onIframeLoad"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted, onUnmounted } from "vue";
|
||||
import { getActive } from "@/api/manage_wx/index";
|
||||
|
||||
const props = defineProps<{
|
||||
project: { id: string; name: string } | null;
|
||||
}>();
|
||||
|
||||
const iframeSrc = ref("");
|
||||
|
||||
// 监听 props 变化
|
||||
watch(
|
||||
() => props.project,
|
||||
(newVal) => {
|
||||
if (newVal && newVal.id && newVal.name) {
|
||||
// window.location.origin
|
||||
iframeSrc.value =
|
||||
"http://192.168.1.179:4001" +
|
||||
`/zutai/?id=${newVal.id}&&name=${encodeURIComponent(
|
||||
newVal.name
|
||||
)}&&preview=true&&display=true&&graphicDisplay=wx#/preview`;
|
||||
|
||||
// console.log("更新 iframeSrc:", iframeSrc.value);
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 监听来自 eventStatistics 组件的消息
|
||||
window.addEventListener("message", handleMessage);
|
||||
|
||||
getActive({}).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
// window.location.origin
|
||||
iframeSrc.value =
|
||||
"http://192.168.1.179:4001" +
|
||||
`/zutai/?id=${res.data.id}&&name=${encodeURIComponent(
|
||||
res.data.name
|
||||
)}&&preview=true&&display=true&&graphicDisplay=wx#/preview`;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理事件监听器
|
||||
window.removeEventListener("message", handleMessage);
|
||||
});
|
||||
|
||||
// iframe 加载完成回调 添加加载事件监听
|
||||
const onIframeLoad = () => {
|
||||
// console.log("iframe 加载完成");
|
||||
// 通知 securityDetail.vue 组件 iframe 已加载完成
|
||||
window.postMessage(
|
||||
{
|
||||
type: "IFRAME_LOADED",
|
||||
data: { loaded: true },
|
||||
},
|
||||
"*"
|
||||
);
|
||||
};
|
||||
|
||||
// 处理来自 eventStatistics 组件的消息
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
// 验证消息来源(在生产环境中应该验证 origin)
|
||||
// if (event.origin !== 'trusted-origin') return;
|
||||
|
||||
const { type, payload } = event.data;
|
||||
|
||||
if (type === "SEND_KEYS_TO_IFRAME") {
|
||||
// 将数据转发给 iframe
|
||||
sendKeysToIframe(payload);
|
||||
}
|
||||
};
|
||||
|
||||
// 向 iframe 发送 keyList 数据
|
||||
const sendKeysToIframe = (keyList: string[]) => {
|
||||
const iframe = document.getElementById("iframeLeft") as HTMLIFrameElement;
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{
|
||||
type: "ANALYSIS_KEYS",
|
||||
payload: keyList,
|
||||
},
|
||||
"*"
|
||||
); // 在生产环境中应该指定具体的域名而不是 '*'
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.plan {
|
||||
width: 100%;
|
||||
height: 990px;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
:title="title"
|
||||
width="1000px"
|
||||
>
|
||||
<div class="formBox">
|
||||
<el-form label-width="100px" :model="form" inline>
|
||||
<el-form-item label="关键字查询">
|
||||
<el-input
|
||||
v-model="form.searchValue"
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请输入关键字查询"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="运行状态">
|
||||
<el-select
|
||||
v-model="form.runFlag"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 160px"
|
||||
>
|
||||
<el-option label="投运" value="0" />
|
||||
<el-option label="热备用" value="1" />
|
||||
<el-option label="停运" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mt5">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Search"
|
||||
size="small"
|
||||
@click="getTableData"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="400px"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="devName" align="center" label="终端名称" />
|
||||
<el-table-column
|
||||
prop="stationName"
|
||||
align="center"
|
||||
label="所属电站"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="gdName"
|
||||
align="center"
|
||||
label="供电公司"
|
||||
width="120"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="ip"
|
||||
align="center"
|
||||
label="网络参数"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="manufacturer"
|
||||
align="center"
|
||||
label="所属厂家"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="runFlag"
|
||||
align="center"
|
||||
label="运行状态"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.runFlag == 0"
|
||||
size="small"
|
||||
type="primary"
|
||||
effect="dark"
|
||||
>投运</el-tag
|
||||
>
|
||||
<el-tag
|
||||
v-if="scope.row.runFlag == 1"
|
||||
size="small"
|
||||
type="info"
|
||||
effect="dark"
|
||||
>热备用</el-tag
|
||||
>
|
||||
<el-tag
|
||||
v-if="scope.row.runFlag == 2"
|
||||
size="small"
|
||||
type="danger"
|
||||
effect="dark"
|
||||
>停运</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="loginTime"
|
||||
align="center"
|
||||
label="投运时间"
|
||||
width="120"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import datePicker from "@/components/datePicker/index.vue";
|
||||
import { Search, Download } from "@element-plus/icons-vue";
|
||||
import { searchTree } from "xe-utils";
|
||||
import { devPage } from "@/api/manage_wx";
|
||||
import { useStore } from "vuex";
|
||||
import * as XLSX from "xlsx";
|
||||
const loading = ref(false);
|
||||
const store = useStore();
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("");
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
searchValue: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
deptId: "",
|
||||
runFlag: "",
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
|
||||
//form表单校验规则
|
||||
const openDev = (text: string, data?: any) => {
|
||||
title.value = text;
|
||||
machineVisible.value = true;
|
||||
form.searchValue = "";
|
||||
form.pageNum = 1;
|
||||
form.pageSize = 20;
|
||||
form.runFlag = "";
|
||||
getTableData();
|
||||
};
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
form.deptId = store.state.deptId;
|
||||
const res: any = await devPage(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
["终端名称", "所属电站", "供电公司", "网络参数", "所属厂家", "运行状态","投运时间"],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await devPage({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.devName,
|
||||
item.stationName,
|
||||
item.gdName,
|
||||
item.ip,
|
||||
item.manufacturer,
|
||||
item.runFlag == 0 ? "运行" : item.runFlag == 1 ? "热备用" : "停运",
|
||||
item.loginTime,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// getTableData();
|
||||
});
|
||||
defineExpose({ openDev });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
310
src/views/SagTraceResult_WX/components/scaleStatistics/index.vue
Normal file
310
src/views/SagTraceResult_WX/components/scaleStatistics/index.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<div class="titleBox">监测点规模统计</div>
|
||||
<div class="Box">
|
||||
<div class="eachartsBox">
|
||||
<div
|
||||
class="totalBox"
|
||||
@click="clickNum('站点详情')"
|
||||
style="background-color: #28a74570"
|
||||
>
|
||||
<div>
|
||||
<span>站点总数:</span>
|
||||
<span class="text">{{ statisticsObj.stationAll }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>运行站点数: </span>
|
||||
<span>{{ statisticsObj.stationRun }} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="eacharts1"
|
||||
ref="eacharts1"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="eachartsBox">
|
||||
<div
|
||||
class="totalBox"
|
||||
@click="clickNum('终端详情')"
|
||||
style="background-color: #07ccca70"
|
||||
>
|
||||
<div>
|
||||
<span>终端总数:</span>
|
||||
<span class="text">{{ statisticsObj.devAll }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>运行终端数: </span>
|
||||
<span>{{ statisticsObj.devRun }} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="eacharts2"
|
||||
ref="eacharts2"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
<div class="eachartsBox">
|
||||
<div
|
||||
class="totalBox"
|
||||
@click="clickNum('监测点详情')"
|
||||
style="background-color: #007bff70"
|
||||
>
|
||||
<div>
|
||||
<span>监测点总数:</span>
|
||||
<span class="text">{{ statisticsObj.lineAll }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>在线监测点数:</span>
|
||||
<span>{{ statisticsObj.lineRun }} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="eacharts3"
|
||||
ref="eacharts3"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
<Table ref="tableRef" />
|
||||
<DevTable ref="devTableRef" />
|
||||
<LineTable ref="lineTableRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance, reactive } from "vue";
|
||||
import { ledgerScale } from "@/api/manage_wx/index";
|
||||
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
import * as echarts from "echarts";
|
||||
import Table from "./table.vue";
|
||||
import DevTable from "./devTable.vue";
|
||||
import LineTable from "./lineTable.vue";
|
||||
import "echarts-liquidfill";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
|
||||
const eacharts1 = ref(null);
|
||||
const eacharts2 = ref(null);
|
||||
const eacharts3 = ref(null);
|
||||
const tableRef = ref();
|
||||
const devTableRef = ref();
|
||||
const lineTableRef = ref();
|
||||
const renderChart = (
|
||||
key: any,
|
||||
color: string,
|
||||
point: number,
|
||||
title: string,
|
||||
clickHandler: Function
|
||||
) => {
|
||||
var myChart = proxy.$echarts.init(key);
|
||||
myChart.setOption({
|
||||
title: [
|
||||
{
|
||||
text: title,
|
||||
x: title == "监测点在线率" ? "17%" : "22%",
|
||||
y: "60%",
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#fff",
|
||||
lineHeight: 14,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: "liquidFill",
|
||||
radius: "95%",
|
||||
center: ["50%", "50%"],
|
||||
color: [
|
||||
{
|
||||
type: "linear",
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: color + "80", // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: color,
|
||||
},
|
||||
],
|
||||
globalCoord: false,
|
||||
},
|
||||
],
|
||||
data: [point], // data个数代表波浪数
|
||||
backgroundStyle: {
|
||||
borderWidth: 1,
|
||||
color: "RGBA(51, 66, 127, 0.7)",
|
||||
},
|
||||
label: {
|
||||
fontSize: 20,
|
||||
color: "#fff",
|
||||
|
||||
position: ["50%", "45%"],
|
||||
},
|
||||
outline: {
|
||||
show: false,
|
||||
borderDistance: 10,
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: "#112165",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
// 注册图表点击事件
|
||||
myChart.on("click", clickHandler);
|
||||
};
|
||||
const clickNum = (title: string) => {
|
||||
if (title == "站点详情") {
|
||||
tableRef.value.open(title);
|
||||
}
|
||||
if (title == "终端详情") {
|
||||
devTableRef.value.openDev(title);
|
||||
}
|
||||
|
||||
if (title == "监测点详情") {
|
||||
lineTableRef.value.openLine(title);
|
||||
}
|
||||
// tableRef.value.open(title);
|
||||
// devTableRef.value.openDev(title);
|
||||
};
|
||||
|
||||
// 为每个图表创建专门的点击处理函数
|
||||
const handleStationChartClick = (params: any) => {
|
||||
// 打开站点详情
|
||||
tableRef.value.open("站点详情");
|
||||
};
|
||||
|
||||
const handleTerminalChartClick = (params: any) => {
|
||||
// 打开终端详情
|
||||
devTableRef.value.openDev("终端详情");
|
||||
};
|
||||
|
||||
const handleLineChartClick = (params: any) => {
|
||||
// 打开监测点详情
|
||||
lineTableRef.value.openLine("监测点详情");
|
||||
};
|
||||
|
||||
// 监测点规模统计
|
||||
const statisticsObj = reactive({
|
||||
devAll: "",
|
||||
devRun: "",
|
||||
lineAll: "",
|
||||
lineRun: "",
|
||||
stationAll: "",
|
||||
stationRun: "",
|
||||
});
|
||||
|
||||
// 场站在线率
|
||||
const stationOnlineRate = ref(0);
|
||||
// 终端在线率
|
||||
const terminalOnlineRate = ref(0);
|
||||
// 监测点在线率
|
||||
const onlineRate = ref(0);
|
||||
|
||||
onMounted(() => {
|
||||
// renderChart(eacharts1.value, "#28a745", stationOnlineRate.value, "场站在线率");
|
||||
// renderChart(eacharts2.value, "#07CCCA", terminalOnlineRate.value, "终端在线率");
|
||||
// renderChart(eacharts3.value, "#007bff", onlineRate.value, "监测点在线率");
|
||||
});
|
||||
|
||||
const initialData = () => {
|
||||
ledgerScale({ deptId: store.state.deptId }).then((res: any) => {
|
||||
if (res.code == "A0000") {
|
||||
Object.assign(statisticsObj, res.data);
|
||||
onlineRate.value = res.data.lineRun / res.data.lineAll;
|
||||
stationOnlineRate.value = res.data.stationRun / res.data.stationAll;
|
||||
terminalOnlineRate.value = res.data.devRun / res.data.devAll;
|
||||
renderChart(
|
||||
eacharts1.value,
|
||||
"#28a745",
|
||||
stationOnlineRate.value,
|
||||
"场站在线率",
|
||||
handleStationChartClick
|
||||
);
|
||||
renderChart(
|
||||
eacharts2.value,
|
||||
"#07CCCA",
|
||||
terminalOnlineRate.value,
|
||||
"终端在线率",
|
||||
handleTerminalChartClick
|
||||
);
|
||||
renderChart(
|
||||
eacharts3.value,
|
||||
"#007bff",
|
||||
onlineRate.value,
|
||||
"监测点在线率",
|
||||
handleLineChartClick
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
initialData,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.Box {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
height: 275px;
|
||||
|
||||
.eachartsBox {
|
||||
height: 95%;
|
||||
padding: 0 5px;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
place-items: center;
|
||||
grid-template-rows: 1.1fr 1fr;
|
||||
|
||||
.totalBox {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 80%;
|
||||
width: 105%;
|
||||
// margin: 10% auto;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
width: 100px;
|
||||
text-align: end;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
cursor: pointer;
|
||||
// text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- -->
|
||||
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="machineVisible" :title="title" width="1000px">
|
||||
<div class="formBox">
|
||||
<el-form label-width="100px" :model="form" inline>
|
||||
<el-form-item label="关键字查询">
|
||||
<el-input v-model="form.searchValue" clearable size="small" placeholder="请输入关键字查询" />
|
||||
</el-form-item>
|
||||
<el-form-item label="通讯状态">
|
||||
<el-select v-model="form.comFlag" clearable size="small" style="width: 160px">
|
||||
<el-option label="在线" value="1" />
|
||||
<el-option label="中断" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" size="small" @click="getTableData">查询</el-button>
|
||||
<el-button type="primary" :icon="Download" @click="exportTable" size="small">导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox">
|
||||
<el-table :scrollbar-always-on="true" :data="tableData" height="400px" size="small" v-loading="loading"
|
||||
element-loading-background="#343849c7" :header-cell-style="{ textAlign: 'center' }" border>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="lineName" align="center" label="监测点名称" width="140" />
|
||||
<el-table-column prop="stationName" align="center" label="所属电站" width="140" />
|
||||
<el-table-column prop="gdName" align="center" label="供电公司" width="120" />
|
||||
<el-table-column prop="voltageLevel" align="center" label="电压等级" width="100" />
|
||||
<el-table-column prop="comFlag" align="center" label="通讯状态" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-tag v-if="scope.row.comFlag == 1" size="small" type="primary" effect="dark">在线</el-tag>
|
||||
<el-tag v-if="scope.row.comFlag == 0" size="small" type="warning" effect="dark">中断</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="objName" align="center" label="用户" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination size="small" style="margin-top: 10px" :currentPage="form.pageNum" :page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]" background :layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total" @size-change="onTableSizeChange" @current-change="onTableCurrentChange"></el-pagination>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Search, Download } from "@element-plus/icons-vue";
|
||||
import { linePage } from "@/api/manage_wx";
|
||||
import { useStore } from "vuex";
|
||||
import * as XLSX from "xlsx";
|
||||
const loading = ref(false);
|
||||
const store = useStore();
|
||||
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("");
|
||||
const formRef = ref();
|
||||
const form = reactive({
|
||||
searchValue: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
deptId: "",
|
||||
comFlag: "",
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
|
||||
//form表单校验规则
|
||||
const openLine = (text: string, data?: any) => {
|
||||
title.value = text;
|
||||
machineVisible.value = true;
|
||||
form.searchValue = "";
|
||||
form.pageNum = 1;
|
||||
form.pageSize = 20;
|
||||
form.comFlag = "";
|
||||
getTableData();
|
||||
};
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
form.deptId = store.state.deptId;
|
||||
const res: any = await linePage(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"监测点名称",
|
||||
"所属电站",
|
||||
"供电公司",
|
||||
"电压等级",
|
||||
"通讯状态",
|
||||
"用户",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await linePage({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.lineName,
|
||||
item.stationName,
|
||||
item.gdName,
|
||||
item.voltageLevel,
|
||||
item.comFlag == 1 ? '在线' : '中断',
|
||||
item.objName,
|
||||
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// getTableData();
|
||||
});
|
||||
|
||||
defineExpose({ openLine });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
216
src/views/SagTraceResult_WX/components/scaleStatistics/table.vue
Normal file
216
src/views/SagTraceResult_WX/components/scaleStatistics/table.vue
Normal file
@@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<!--暂降 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="machineVisible"
|
||||
:title="title"
|
||||
width="1000px"
|
||||
>
|
||||
<div class="formBox">
|
||||
<el-form label-width="100px" :model="form" inline>
|
||||
<el-form-item label="关键字查询">
|
||||
<el-input
|
||||
v-model="form.searchValue"
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请输入关键字查询"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否监测">
|
||||
<el-select
|
||||
v-model="form.runFlag"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 160px"
|
||||
>
|
||||
<el-option label="是" value="0" />
|
||||
<el-option label="否" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mt5">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Search"
|
||||
size="small"
|
||||
@click="getTableData"
|
||||
>查询</el-button
|
||||
><el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="tableData"
|
||||
height="400px"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{
|
||||
(form.pageNum - 1) * form.pageSize + scope.$index + 1
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stationName" align="center" label="变电站名称" />
|
||||
<el-table-column prop="gdName" align="center" label="供电公司" />
|
||||
<el-table-column
|
||||
prop="stationVoltageLevel"
|
||||
align="center"
|
||||
label="电压等级"
|
||||
width="150"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="runFlag"
|
||||
align="center"
|
||||
label="是否监测"
|
||||
width="130"
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.runFlag == 0"
|
||||
size="small"
|
||||
type="primary"
|
||||
effect="dark"
|
||||
>是</el-tag
|
||||
>
|
||||
<el-tag v-else size="small" type="warning" effect="dark">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
size="small"
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Search, Download } from "@element-plus/icons-vue";
|
||||
import { stationPage } from "@/api/manage_wx";
|
||||
import { useStore } from "vuex";
|
||||
import * as XLSX from "xlsx";
|
||||
const store = useStore();
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("");
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
const form = reactive({
|
||||
searchValue: "",
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
deptId: "",
|
||||
runFlag: "",
|
||||
// startTime: "",
|
||||
// endTime: "",
|
||||
});
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
//form表单校验规则
|
||||
const open = (text: string, data?: any) => {
|
||||
title.value = text;
|
||||
machineVisible.value = true;
|
||||
form.searchValue = "";
|
||||
form.pageNum = 1;
|
||||
form.pageSize = 20;
|
||||
form.runFlag = "";
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
// 重新加载数据
|
||||
getTableData();
|
||||
};
|
||||
|
||||
const getTableData = async () => {
|
||||
loading.value = true;
|
||||
form.deptId = store.state.deptId;
|
||||
// form.startTime = store.state.timeValue[0];
|
||||
// form.endTime = store.state.timeValue[1];
|
||||
const res: any = await stationPage(form);
|
||||
|
||||
if (res.code == "A0000") {
|
||||
tableData.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [["变电站名称", "供电公司", "电压等级", "是否监测"]];
|
||||
|
||||
let list = [];
|
||||
|
||||
await stationPage({
|
||||
...form,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.stationName,
|
||||
item.gdName,
|
||||
item.stationVoltageLevel,
|
||||
item.runFlag == 0 ? "是" : "否",
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
// onMounted(() => {
|
||||
// getTableData();
|
||||
// });
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
129
src/views/SagTraceResult_WX/components/table.vue
Normal file
129
src/views/SagTraceResult_WX/components/table.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<!--右下 暂降事件聚合成功暂降事件聚合成功列表 -->
|
||||
<div class="plan">
|
||||
<div class="titleBox">
|
||||
事件列表
|
||||
<div class="titles">
|
||||
<div
|
||||
class="react-right"
|
||||
:class="flag == 0 ? 'titleClick' : ''"
|
||||
@click="flag = 0"
|
||||
>
|
||||
<span class="text"> 暂降</span>
|
||||
</div>
|
||||
<div
|
||||
class="react-right"
|
||||
:class="flag == 1 ? 'titleClick' : ''"
|
||||
@click="flag = 1"
|
||||
>
|
||||
<span class="text"> 谐波</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox" v-if="flag == 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="tableData"
|
||||
height="250px"
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column prop="date" align="center" label="时间" width="160" />
|
||||
<el-table-column
|
||||
prop="name"
|
||||
align="center"
|
||||
label="事件关联分析名称"
|
||||
width="160"
|
||||
/>
|
||||
<el-table-column prop="cj" align="center" label="事件关联分析描述" />
|
||||
|
||||
<el-table-column prop="address" align="center" label="操作" width="90">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" text> 影响范围 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="tableBox" v-if="flag == 1">
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="tableData"
|
||||
height="250px"
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column prop="date" align="center" label="时间" width="160" />
|
||||
<el-table-column
|
||||
prop="center"
|
||||
align="center"
|
||||
label="事件内容"
|
||||
|
||||
/>
|
||||
<!-- <el-table-column prop="cj" align="center" label="事件关联分析描述" /> -->
|
||||
|
||||
<el-table-column prop="address" align="center" label="操作" width="70">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" text> 编辑 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue";
|
||||
const flag = ref(0); // 0 for 暂降, 1 for 谐波
|
||||
const tableData = [
|
||||
{
|
||||
date: "2024-01-01 17:49:03",
|
||||
name: "2024-01-01 17:49:03.475",
|
||||
cj: "事件关联分析编号2024-01-01 17:49:03.475共包含1个事件",
|
||||
center:
|
||||
"监测点ID:xxxxxxxxx;起始时间:2024-01-01 17:49:03;结束时间:2024-01-01 17:49:03.475;触发类型:暂降;",
|
||||
},
|
||||
{
|
||||
date: "2024-01-02 19:28:40",
|
||||
name: "2024-01-02 19:28:40.090",
|
||||
cj: "事件关联分析编号2024-01-01 17:49:03.475共包含1个事件",
|
||||
center:
|
||||
"监测点ID:xxxxxxxxx;起始时间:2024-01-01 17:49:03;结束时间:2024-01-01 17:49:03.475;触发类型:暂降;",
|
||||
},
|
||||
{
|
||||
date: "2024-01-02 19:29:35",
|
||||
name: "2024-01-02 19:28:40.090",
|
||||
cj: "事件关联分析编号2024-01-01 17:49:03.475共包含1个事件",
|
||||
center:
|
||||
"监测点ID:xxxxxxxxx;起始时间:2024-01-01 17:49:03;结束时间:2024-01-01 17:49:03.475;触发类型:暂降;",
|
||||
},
|
||||
{
|
||||
date: "2024-01-02 19:29:52",
|
||||
name: "2024-01-02 19:28:40.090",
|
||||
cj: "事件关联分析编号2024-01-01 17:49:03.475共包含1个事件",
|
||||
center:
|
||||
"监测点ID:xxxxxxxxx;起始时间:2024-01-01 17:49:03;结束时间:2024-01-01 17:49:03.475;触发类型:暂降;",
|
||||
},
|
||||
{
|
||||
date: "2024-01-02 19:29:52",
|
||||
name: "2024-01-02 19:28:40.090",
|
||||
cj: "事件关联分析编号2024-01-01 17:49:03.475共包含1个事件",
|
||||
center:
|
||||
"监测点ID:xxxxxxxxx;起始时间:2024-01-01 17:49:03;结束时间:2024-01-01 17:49:03.475;触发类型:暂降;",
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.plan {
|
||||
width: 100%;
|
||||
height: 295px;
|
||||
.titles {
|
||||
margin-right: 10px;
|
||||
.react-right {
|
||||
width: 60px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
431
src/views/SagTraceResult_WX/index.vue
Normal file
431
src/views/SagTraceResult_WX/index.vue
Normal file
@@ -0,0 +1,431 @@
|
||||
<template>
|
||||
<div id="index" ref="appRef">
|
||||
<div class="bg">
|
||||
<dv-loading v-if="loading">Loading...</dv-loading>
|
||||
|
||||
<div v-else class="host-body">
|
||||
<!-- <div class="d-flex jc-center">
|
||||
<dv-decoration-10 class="dv-dec-10" :color="color[1]" />
|
||||
<div class="d-flex jc-center">
|
||||
<dv-decoration-8 class="dv-dec-8" :color="color[2]" />
|
||||
<div class="title">
|
||||
<span class="title-text" @click="handleTitleClick">{{
|
||||
title
|
||||
}}</span>
|
||||
</div>
|
||||
<dv-decoration-8
|
||||
class="dv-dec-8"
|
||||
:reverse="true"
|
||||
:color="color[2]"
|
||||
/>
|
||||
</div>
|
||||
<dv-decoration-10 class="dv-dec-10-s" :color="color[1]" />
|
||||
</div>
|
||||
|
||||
<div class="d-flex secondLine">
|
||||
<div class="react-right mr-3">
|
||||
<span class="text fw-b">
|
||||
{{ timeInfo.dateYear }} {{ timeInfo.dateWeek }}
|
||||
{{ timeInfo.dateDay }}</span
|
||||
>
|
||||
</div>
|
||||
<el-dropdown placement="bottom">
|
||||
|
||||
<el-icon :size="20" :color="color[0][1]">
|
||||
<Menu />
|
||||
</el-icon>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleClick('1')"
|
||||
>接线图配置</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div> -->
|
||||
<div class="d-flex jc-center">
|
||||
<div class="react-left">
|
||||
<span class="text fw-b">
|
||||
{{ timeInfo.dateYear }} {{ timeInfo.dateWeek }}
|
||||
{{ timeInfo.dateDay }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<dv-decoration-10 class="dv-dec-10" :color="color[1]" />
|
||||
<div class="d-flex jc-center">
|
||||
<dv-decoration-8 class="dv-dec-8" :color="color[2]" />
|
||||
<div class="title">
|
||||
<span class="title-text">{{ title }}</span>
|
||||
</div>
|
||||
<dv-decoration-8
|
||||
class="dv-dec-8"
|
||||
:reverse="true"
|
||||
:color="color[2]"
|
||||
/>
|
||||
</div>
|
||||
<dv-decoration-10 class="dv-dec-10-s" :color="color[1]" />
|
||||
</div>
|
||||
|
||||
<div class="d-flex secondLine">
|
||||
<div class="react-right mr-1">
|
||||
<span class="text fw-b" style="display: flex">
|
||||
<datePicker
|
||||
ref="datePickerRef"
|
||||
@timeChangeInfo="timeChangeInfo"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-icon
|
||||
size="22"
|
||||
:color="color[1][0]"
|
||||
class="mt-0.5 mt5"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<Menu @click="openDialog" />
|
||||
</el-icon>
|
||||
<Management
|
||||
ref="createRef"
|
||||
@project-change="onProjectChange"
|
||||
></Management>
|
||||
</div>
|
||||
<div class="body-box">
|
||||
<!-- 第三行数据 -->
|
||||
<div class="content-box">
|
||||
<dv-border-box-10 :color="color[0]" style="position: relative">
|
||||
<Plan :project="currentProject" />
|
||||
<!-- 将 flag 值传递给 SecurityDetail 组件 -->
|
||||
<!-- showDetail从SecurityDetail 组件传过来 -->
|
||||
<SecurityDetail
|
||||
ref="securityDetail"
|
||||
:current-flag="currentFlag"
|
||||
style="position: absolute; bottom: 0px; width: 100%"
|
||||
@show-detail-change="handleShowDetailChange"
|
||||
/>
|
||||
<IframeDia
|
||||
:event-list="eventListData as []"
|
||||
style="position: absolute; top: 0px; right: 0px; left: 0px"
|
||||
/>
|
||||
<!-- 图元颜色提示框 -->
|
||||
<div
|
||||
v-if="!showDetail"
|
||||
style="
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 40px;
|
||||
padding: 10px;
|
||||
"
|
||||
>
|
||||
<div style="display: flex">
|
||||
<img
|
||||
src="@/assets/icon/传输设备 (3).png"
|
||||
style="width: 20px; height: 20px"
|
||||
/>
|
||||
<div style="margin-left: 10px; font-size: 12px">监测点</div>
|
||||
</div>
|
||||
<div style="display: flex" v-if="currentFlag == 0">
|
||||
<img
|
||||
src="@/assets/icon/传输设备 (3).png"
|
||||
style="width: 20px; height: 20px"
|
||||
class="blink-basic"
|
||||
/>
|
||||
<div style="margin-left: 10px; font-size: 12px">
|
||||
暂降发生测点
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex" v-if="currentFlag == 1">
|
||||
<img
|
||||
src="@/assets/icon/传输设备 (4).png"
|
||||
style="width: 20px; height: 20px"
|
||||
class="blink-basic"
|
||||
/>
|
||||
<div style="margin-left: 10px; font-size: 12px">背景测点</div>
|
||||
</div>
|
||||
<div style="display: flex">
|
||||
<img
|
||||
src="@/assets/icon/传输设备 (2).png"
|
||||
style="width: 20px; height: 20px"
|
||||
class="blink-basic"
|
||||
/>
|
||||
<div style="margin-left: 10px; font-size: 12px">
|
||||
<span v-if="currentFlag == 0">暂降溯源关联测点</span>
|
||||
<span v-if="currentFlag == 1">责任测点</span>
|
||||
<span v-if="currentFlag == 2">发生谐波放大测点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex" v-if="currentFlag != 2">
|
||||
<img
|
||||
src="@/assets/icon/传输设备 (1).png"
|
||||
style="width: 20px; height: 20px"
|
||||
class="blink-basic"
|
||||
/>
|
||||
<div style="margin-left: 10px; font-size: 12px">
|
||||
{{
|
||||
currentFlag == 0 ? "暂降源测点" : "责任占比最高测点"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 还原按钮 -->
|
||||
<!-- <div>
|
||||
<el-button @click="back" icon="el-icon-Back">还原</el-button>
|
||||
</div> -->
|
||||
</dv-border-box-10>
|
||||
|
||||
<div class="content-left">
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<ScaleStatistics ref="scaleStatistics" />
|
||||
</dv-border-box-13>
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<EventStatistics
|
||||
ref="eventStatistics"
|
||||
@data-updated="handleDataUpdate"
|
||||
@flag-changed="handleFlagChange"
|
||||
@expand-detail="handleExpandDetail"
|
||||
/>
|
||||
</dv-border-box-13>
|
||||
<!-- <dv-border-box-13 :color="color[0]">
|
||||
<Table />
|
||||
</dv-border-box-13> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--index.vue-->
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, ref, reactive, onMounted, onUnmounted } from "vue";
|
||||
import { formatTime } from "@/utils/index"; //引入封装好的
|
||||
import useDraw from "@/utils/useDraw"; // 引入封装好的屏幕适配方法
|
||||
import { WEEK, title, subtitle, moduleInfo, color } from "@/constant/index_wx"; //引入封装的标题日期
|
||||
import { Menu } from "@element-plus/icons-vue";
|
||||
//页面组件
|
||||
import Plan from "./components/plan.vue"; // 引入计划组件
|
||||
import ScaleStatistics from "./components/scaleStatistics/index.vue"; // 引入计划组件
|
||||
import EventStatistics from "./components/eventStatistics/index.vue"; // 引入计划组件
|
||||
import Table from "./components/table.vue"; // 引入计划组件
|
||||
import datePicker from "@/components/datePicker/index.vue";
|
||||
import Management from "./components/manage/index.vue";
|
||||
import SecurityDetail from "./components/manage/securityDetail.vue";
|
||||
import IframeDia from "./components/manage/iframeDia.vue";
|
||||
|
||||
// 传给iframe页面的参数
|
||||
const currentProject = ref<{ id: string; name: string } | null>(null);
|
||||
|
||||
// 项目管理页面传过来的事件 点击激活 获取首页展示
|
||||
const onProjectChange = (project: { id: string; name: string }) => {
|
||||
currentProject.value = project;
|
||||
};
|
||||
|
||||
const smsQueriesRef = ref(); // 短信查询组件引用
|
||||
const smsConfigRef = ref(); // 短信查询组件引用
|
||||
const sendRef = ref(); // 短信查询组件引用
|
||||
// * 加载标识
|
||||
const loading = ref<boolean>(true);
|
||||
// * 时间内容
|
||||
const timeInfo: any = reactive({
|
||||
setInterval: 0,
|
||||
dateDay: "",
|
||||
dateYear: "",
|
||||
dateWeek: "",
|
||||
});
|
||||
|
||||
const scaleStatistics = ref();
|
||||
const eventStatistics = ref();
|
||||
const securityDetail = ref();
|
||||
// 适配处理
|
||||
const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw();
|
||||
|
||||
// 闪烁点list eventStatistics/index.vue
|
||||
const eventListData = ref([]);
|
||||
|
||||
// 添加用于存储当前 flag 值的响应式变量
|
||||
const currentFlag = ref(0);
|
||||
|
||||
// 添加 showDetail 响应式变量
|
||||
const showDetail = ref(false);
|
||||
|
||||
// 处理 showDetail 变化
|
||||
const handleShowDetailChange = (value: boolean) => {
|
||||
showDetail.value = value;
|
||||
};
|
||||
|
||||
// 处理 EventStatistics 组件传递过来的 flag 值变化
|
||||
const handleFlagChange = (flagValue: number) => {
|
||||
currentFlag.value = flagValue;
|
||||
};
|
||||
|
||||
// 处理数据更新
|
||||
const handleDataUpdate = (data: string[]) => {
|
||||
eventListData.value = data;
|
||||
};
|
||||
|
||||
// 初始化并获取数据
|
||||
const initComponents = () => {
|
||||
if (eventStatistics.value) {
|
||||
// eventStatistics.value.initHasEventList();
|
||||
|
||||
// 定时获取 eventList 数据并传递给 iframeDia
|
||||
const interval = setInterval(() => {
|
||||
const data = eventStatistics.value.getEventList();
|
||||
if (data && data.length > 0) {
|
||||
eventListData.value = data;
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理展开详情面板的函数
|
||||
const handleExpandDetail = (flagValue: number) => {
|
||||
// 设置当前 flag
|
||||
currentFlag.value = flagValue;
|
||||
// 通知 SecurityDetail 组件展开详情面板
|
||||
showDetail.value = true;
|
||||
// 同时通知 SecurityDetail 组件更新 showDetail 状态
|
||||
securityDetail.value?.setShowDetail(true);
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
cancelLoading();
|
||||
handleTime();
|
||||
// todo 屏幕适应
|
||||
windowDraw();
|
||||
calcRate();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
unWindowDraw();
|
||||
clearInterval(timeInfo.setInterval);
|
||||
});
|
||||
|
||||
// methods
|
||||
// todo 处理 loading 展示
|
||||
const cancelLoading = () => {
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// todo 处理时间监听
|
||||
const handleTime = () => {
|
||||
timeInfo.setInterval = setInterval(() => {
|
||||
const date = new Date();
|
||||
timeInfo.dateDay = formatTime(date, "HH: mm: ss");
|
||||
timeInfo.dateYear = formatTime(date, "yyyy-MM-dd");
|
||||
timeInfo.dateWeek = WEEK[date.getDay()];
|
||||
}, 1000);
|
||||
};
|
||||
// todo 处理菜单点击事件
|
||||
const handleClick = (type: string) => {
|
||||
if (type === "1") {
|
||||
smsQueriesRef.value.open("已发送短信查询");
|
||||
} else if (type === "2") {
|
||||
smsConfigRef.value.open("短信配置");
|
||||
} else if (type === "3") {
|
||||
sendRef.value.open("短信发送");
|
||||
}
|
||||
};
|
||||
|
||||
// 切换时间
|
||||
const timeChangeInfo = async () => {
|
||||
inquire();
|
||||
};
|
||||
const inquireTimer: any = ref(null);
|
||||
const inquire = async () => {
|
||||
// 清除上一次的定时器
|
||||
if (inquireTimer.value) {
|
||||
clearTimeout(inquireTimer.value);
|
||||
}
|
||||
|
||||
// 设置新的定时器,延迟300毫秒执行
|
||||
inquireTimer.value = setTimeout(async () => {
|
||||
scaleStatistics.value.initialData(); //监测点规模统计
|
||||
eventStatistics.value.init(); //暂降溯源统计
|
||||
securityDetail.value.init(); //报警信息详情
|
||||
// 定时获取 eventList 数据并传递给 iframeDia
|
||||
// initComponents()
|
||||
// 执行完毕后重置定时器变量
|
||||
inquireTimer.value = null;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 打开管理页面弹框
|
||||
const createRef = ref();
|
||||
const openDialog = () => {
|
||||
createRef.value.open();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/scss/SagTraceResult_WX.scss";
|
||||
.react-right {
|
||||
width: 460px !important;
|
||||
}
|
||||
.count {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 23px;
|
||||
background-color: #ff2501;
|
||||
color: #fff;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
padding: 0 3px;
|
||||
border-radius: 40%;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 25px;
|
||||
}
|
||||
.significant {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 15px;
|
||||
.count {
|
||||
top: -3px;
|
||||
left: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
}
|
||||
.react-left {
|
||||
position: absolute;
|
||||
left: 140px;
|
||||
top: 30px;
|
||||
font-size: 18px;
|
||||
line-height: 35px;
|
||||
}
|
||||
.titles {
|
||||
margin-right: 10px;
|
||||
.react-right {
|
||||
width: 50px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 35px !important;
|
||||
}
|
||||
|
||||
/* 基本闪烁效果 */
|
||||
.blink-basic {
|
||||
animation: blink 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
625
src/views/VoltageSag_BJ/components/alarm.vue
Normal file
625
src/views/VoltageSag_BJ/components/alarm.vue
Normal file
@@ -0,0 +1,625 @@
|
||||
<template>
|
||||
<div class="titleBox">电压暂降告警统计</div>
|
||||
<div class="Box" v-loading="loading" element-loading-background="#343849c7">
|
||||
<dv-border-box-7 :color="color[3]">
|
||||
<div class="eachartsBox eachartsBoxTop" style="place-items: center">
|
||||
<div class="totalBox" style="background-color: #28a74570">
|
||||
<div class="textTop" @click="openalarmPopUpBox(0, data.importId)">
|
||||
<span>{{ data.importNum || 0 }}</span>
|
||||
<span style="font-size: 13px">半导体及精密加工企业<br />监测总数</span>
|
||||
</div>
|
||||
<div
|
||||
class="textTop"
|
||||
@click="openalarmPopUpBox(0, data.otherImportId)"
|
||||
>
|
||||
<span>{{ data.otherImportNum || 0 }}</span>
|
||||
<span style="font-size: 13px">其他敏感用户<br />监测总数</span>
|
||||
</div>
|
||||
<div class="textTop" @click="openalarmPopUpBox(0, data.otherId)">
|
||||
<span>{{ data.otherNum || 0 }}</span>
|
||||
<span style="font-size: 13px">非敏感用户<br />监测总数</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="totalBox"
|
||||
style="background-color: #28a74570; margin-top: 10px"
|
||||
>
|
||||
<div class="textTop" @click="openalarmPopUpBox(1, data.importId)">
|
||||
<span>{{ data.importDevNum || 0 }}</span>
|
||||
<span style="font-size: 13px"
|
||||
>半导体及精密加工企业<br />受影响户数</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="textTop"
|
||||
@click="openalarmPopUpBox(1, data.otherImportId)"
|
||||
>
|
||||
<span>{{ data.otherImportDevNum || 0 }}</span>
|
||||
<span style="font-size: 13px">其他敏感用户<br />受影响户数</span>
|
||||
</div>
|
||||
<div class="textTop" @click="openalarmPopUpBox(1, data.otherId)">
|
||||
<span>{{ data.otherDevNum || 0 }}</span>
|
||||
<span style="font-size: 13px">非敏感用户<br />受影响户数</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dv-border-box-7>
|
||||
<dv-border-box-7 :color="color[3]">
|
||||
<div class="boxCenter" style="place-items: center">
|
||||
<div
|
||||
class="eacharts1"
|
||||
ref="eacharts1"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
</dv-border-box-7>
|
||||
</div>
|
||||
<!-- 弹框 -->
|
||||
<!-- <alarmPopUpBox ref="alarmPopUpBoxRef" />
|
||||
<!– 终端弹框 –>
|
||||
<sensitivePopUpBox ref="sensitivePopUpBoxRef" />-->
|
||||
|
||||
<!-- 弹框 -->
|
||||
<userLedgerPopUpBox ref="alarmPopUpBoxRef" />
|
||||
<!-- 终端弹框 -->
|
||||
<userEventPopUpBox ref="sensitivePopUpBoxRef" />
|
||||
|
||||
<alarmPopUpBox ref="alarmPopUpBoxRefEvent" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance } from "vue";
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
import { color } from "@/constant/index";
|
||||
import alarmPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/alarmPopUpBox.vue";
|
||||
import sensitivePopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/sensitivePopUpBox.vue";
|
||||
|
||||
import userLedgerPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/userLedgerPopUpBox.vue";
|
||||
import userEventPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/userEventPopUpBox.vue";
|
||||
import { rightEvent } from "@/api/statistics/index";
|
||||
import "echarts-liquidfill";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const loading = ref(false);
|
||||
const data: any = ref({});
|
||||
const eacharts1 = ref(null);
|
||||
|
||||
const alarmPopUpBoxRef = ref();
|
||||
const sensitivePopUpBoxRef = ref();
|
||||
|
||||
const alarmPopUpBoxRefEvent = ref();
|
||||
|
||||
const renderChart = (key: any) => {
|
||||
var myChart = proxy.$echarts.init(key);
|
||||
const color = ["#2E8B57", "#0a73ff", "#DAA520"];
|
||||
myChart.setOption({
|
||||
title: {
|
||||
text: "电压暂降用户分类统计(单位:次)",
|
||||
left: "center",
|
||||
top: "10",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
formatter: (params) => {
|
||||
let str = params.marker + params.name;
|
||||
return str;
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: "半导体及\n精密加工",
|
||||
// itemStyle: {
|
||||
// color: "#2E8B57",
|
||||
// },
|
||||
// label: {
|
||||
// rotate: "radial",
|
||||
// color: "#ffffff",
|
||||
// fontSize: 10,
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// name: "半导体(8次)",
|
||||
// value: 10,
|
||||
// itemStyle: {
|
||||
// color: "#2E8B57",
|
||||
// },
|
||||
// label: {
|
||||
// position: "outside",
|
||||
// fontSize: 10,
|
||||
// color: "#ffffff",
|
||||
// },
|
||||
// labelLine: {
|
||||
// show: true,
|
||||
// length1: 10,
|
||||
// smooth: true,
|
||||
// length2: 10,
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: "半导体(12次)",
|
||||
// value: 10,
|
||||
// itemStyle: {
|
||||
// color: "#2E8B57",
|
||||
// },
|
||||
// label: {
|
||||
// position: "outside",
|
||||
// fontSize: 10,
|
||||
// color: "#ffffff",
|
||||
// },
|
||||
// labelLine: {
|
||||
// show: true,
|
||||
// length1: 10,
|
||||
// smooth: true,
|
||||
// length2: 10,
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
|
||||
series: [
|
||||
{
|
||||
type: "sunburst",
|
||||
nodeClick: false,
|
||||
data: data.value.innerList.map((item, i) => {
|
||||
return {
|
||||
name: insertNewLine(item.name),
|
||||
itemStyle: {
|
||||
color: color[i],
|
||||
},
|
||||
parentId: item.children[0].parentId,
|
||||
label: {
|
||||
rotate: "radial",
|
||||
color: "#ffffff",
|
||||
fontSize: 11,
|
||||
lineHeight: 12,
|
||||
},
|
||||
children: item.children.map((k) => {
|
||||
return {
|
||||
name: k.name + `(${k.count})`,
|
||||
value: k.count,
|
||||
parentId: k.parentId,
|
||||
treeId: k.treeId,
|
||||
itemStyle: {
|
||||
color: color[i],
|
||||
},
|
||||
// label: {
|
||||
// position: "outside",
|
||||
// fontSize: 10,
|
||||
// distance: 20, // 调整标签与图形的距离
|
||||
// color: "#ffffff",
|
||||
// avoidLabelOverlap: true,
|
||||
// },
|
||||
// labelLine: {
|
||||
// show: true,
|
||||
// length: 10,
|
||||
// length2: 30,
|
||||
// },
|
||||
label: {
|
||||
position: "outside",
|
||||
distance: 20, // 增加距离避免重叠
|
||||
fontSize: 12,
|
||||
color: "#ffffff",
|
||||
avoidLabelOverlap: true, // 启用避让
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
smooth: true,
|
||||
minTurnAngle: 60,
|
||||
length: 10,
|
||||
length2: 10,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
}),
|
||||
radius: [0, "60%"],
|
||||
center: ["50%", "55%"],
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
normal: {
|
||||
label: {
|
||||
rotate: 0,
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
rich: {
|
||||
fontSize16: {
|
||||
fontSize: "16px",
|
||||
},
|
||||
fontSize12: {
|
||||
fontSize: "12px",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
levels: [
|
||||
{},
|
||||
{
|
||||
nodeClick: false,
|
||||
r0: "0%",
|
||||
r: "40%",
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
rotate: "tangential",
|
||||
},
|
||||
sort: null,
|
||||
},
|
||||
{
|
||||
r0: "40%",
|
||||
r: "60%",
|
||||
label: {
|
||||
align: "right",
|
||||
},
|
||||
},
|
||||
],
|
||||
sort: null,
|
||||
},
|
||||
],
|
||||
});
|
||||
myChart.on("click", function (params: any) {
|
||||
console.log("🚀 ~ renderChart ~ params:", params);
|
||||
alarmPopUpBoxRefEvent.value.open(
|
||||
params.data.parentId,
|
||||
params.data.treeId || ""
|
||||
);
|
||||
});
|
||||
};
|
||||
function insertNewLine(str) {
|
||||
// 检查字符串长度是否至少为4
|
||||
if (str.length < 4) {
|
||||
return str; // 长度不足4时直接返回原字符串
|
||||
}
|
||||
|
||||
// 计算插入位置(倒数第4位)
|
||||
const position = str.length - 4;
|
||||
|
||||
// 在指定位置插入\n并返回新字符串
|
||||
return str.substring(0, position) + "\n" + str.substring(position);
|
||||
}
|
||||
const openalarmPopUpBox = (event: any, id: string) => {
|
||||
if (event == 0) {
|
||||
alarmPopUpBoxRef.value.open(id);
|
||||
} else {
|
||||
sensitivePopUpBoxRef.value.open(id);
|
||||
}
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
|
||||
// 列表
|
||||
await rightEvent({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
data.value = res.data;
|
||||
// data.value = {
|
||||
// importId: "033b2aad6b6947b4aeb67fc6ecf267ca",
|
||||
// importNum: 419,
|
||||
// importDevNum: 65,
|
||||
// otherImportId: "7452d56b80b641af81748fca11ea48da",
|
||||
// otherImportNum: 2583,
|
||||
// otherImportDevNum: 381,
|
||||
// otherId: "2824e58eacba446abf7ef1415f6fe0a0",
|
||||
// otherNum: 1117,
|
||||
// otherDevNum: 190,
|
||||
// innerList: [
|
||||
// {
|
||||
// treeId: null,
|
||||
// parentId: null,
|
||||
// customId: null,
|
||||
// name: "其他干扰源用户",
|
||||
// code: null,
|
||||
// count: 0,
|
||||
// eventList: null,
|
||||
// children: [
|
||||
// {
|
||||
// treeId: "e61a9de99dd149c78314b4f571ab45b3",
|
||||
// parentId: "2824e58eacba446abf7ef1415f6fe0a0",
|
||||
// customId: null,
|
||||
// name: "变电站母线所带的干扰源用户",
|
||||
// code: null,
|
||||
// count: 1117,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// treeId: null,
|
||||
// parentId: null,
|
||||
// customId: null,
|
||||
// name: "其他敏感用户",
|
||||
// code: null,
|
||||
// count: 0,
|
||||
// eventList: null,
|
||||
// children: [
|
||||
// {
|
||||
// treeId: "8f257925fd6740c9972d74b23273f698",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "数据中心",
|
||||
// code: null,
|
||||
// count: 161,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "0351b2c3f7fa4ee0874b88bbf14ec94a",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "机场",
|
||||
// code: null,
|
||||
// count: 137,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "2891af9d6cfc4f3e8794c6ea244961fb",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "交通枢纽(公交场站、客运站、火车站等)",
|
||||
// code: null,
|
||||
// count: 662,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "9d4b431a7b8c411d9725519117e28b78",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "易燃易爆品制造",
|
||||
// code: null,
|
||||
// count: 10,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "b476c88dc5724d8ebfc695cc2183ddf0",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "金融",
|
||||
// code: null,
|
||||
// count: 10,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "13b030c4c6bb47068b9b1673122030ca",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "危险化学品",
|
||||
// code: null,
|
||||
// count: 151,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "5a025836e8104ae68f20a2950ef96712",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "医院",
|
||||
// code: null,
|
||||
// count: 650,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "7a681baf2e39451caba5da2b17d2425b",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "党政机关",
|
||||
// code: null,
|
||||
// count: 1664,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "82da40795f6e44c28a9aec6a7cf31e33",
|
||||
// parentId: "7452d56b80b641af81748fca11ea48da",
|
||||
// customId: null,
|
||||
// name: "大型场馆(体育场、剧院等)",
|
||||
// code: null,
|
||||
// count: 236,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// treeId: null,
|
||||
// parentId: null,
|
||||
// customId: null,
|
||||
// name: "半导体及精密加工",
|
||||
// code: null,
|
||||
// count: 0,
|
||||
// eventList: null,
|
||||
// children: [
|
||||
// {
|
||||
// treeId: "4f8b85fa810d4f188d12159f33bbe001",
|
||||
// parentId: "033b2aad6b6947b4aeb67fc6ecf267ca",
|
||||
// customId: null,
|
||||
// name: "精密加工",
|
||||
// code: null,
|
||||
// count: 335,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// {
|
||||
// treeId: "36d0f463ae4642f3b28c4380cc770882",
|
||||
// parentId: "033b2aad6b6947b4aeb67fc6ecf267ca",
|
||||
// customId: null,
|
||||
// name: "半导体制造",
|
||||
// code: null,
|
||||
// count: 113,
|
||||
// eventList: null,
|
||||
// children: null,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
|
||||
renderChart(eacharts1.value);
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
onMounted(() => {});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.Box {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 550px;
|
||||
grid-template-rows: 1fr 1.3fr;
|
||||
padding: 10px 10px 15px 10px;
|
||||
|
||||
.eachartsBox {
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
// display: grid;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
// gap: 5px;
|
||||
grid-template-columns: 1.3fr 1fr;
|
||||
|
||||
.totalBox {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 80%;
|
||||
width: 85%;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
|
||||
&:nth-child(1) {
|
||||
}
|
||||
.textBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
text-align: end;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.eachartsBoxTop {
|
||||
grid-template-columns: 1fr;
|
||||
.totalBox {
|
||||
width: 95%;
|
||||
height: 45%;
|
||||
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: 1.2fr 1fr 1fr;
|
||||
&:nth-child(1) {
|
||||
border-radius: 10px ;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
border-radius: 10px;
|
||||
}
|
||||
.textTop {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-right: 1px solid #fff;
|
||||
border-bottom: none;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
border-right: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(2) {
|
||||
// margin-top: 10px;
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
&:nth-child(1) {
|
||||
font-weight: 700;
|
||||
// margin-bottom: 5px;
|
||||
line-height: 30px;
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.boxCenter {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-rows: repeat(1, 1fr);
|
||||
.box {
|
||||
// height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-columns: 1.3fr 1fr;
|
||||
// place-items: center;
|
||||
|
||||
.totalBox {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 80%;
|
||||
width: 85%;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
border-radius: 10px;
|
||||
|
||||
margin: auto;
|
||||
.textBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
text-align: end;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- -->
|
||||
490
src/views/VoltageSag_BJ/components/bdMap.vue
Normal file
490
src/views/VoltageSag_BJ/components/bdMap.vue
Normal file
@@ -0,0 +1,490 @@
|
||||
<template>
|
||||
<div v-loading="loading" element-loading-background="#343849c7">
|
||||
<div class="iconBox">
|
||||
<div class="div">
|
||||
<img src="@/assets/jcd.png" alt="" />
|
||||
<span>变电站</span>
|
||||
</div>
|
||||
|
||||
<div class="div">
|
||||
<img src="@/assets/txycyzj.gif" alt="" />
|
||||
<span>暂降监测点</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bmSelect">
|
||||
<el-select
|
||||
v-model="value"
|
||||
@change="setIcon"
|
||||
placeholder="变电站筛选"
|
||||
filterable
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in siteList"
|
||||
:key="item.stationName"
|
||||
:label="item.stationName"
|
||||
:value="item.stationName"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<baidu-map
|
||||
ref="mapRef"
|
||||
class="bm-view"
|
||||
:max-zoom="15"
|
||||
:min-zoom="10"
|
||||
:zoom="zoom"
|
||||
@zoomend="syncCenterAndZoom"
|
||||
@moveend="checkMapData"
|
||||
@ready="handler"
|
||||
:center="center"
|
||||
:scroll-wheel-zoom="false"
|
||||
:double-click-zoom="false"
|
||||
|
||||
>
|
||||
<!-- 线-->
|
||||
<div v-if="zoom > 13">
|
||||
<bm-polyline
|
||||
:path="path"
|
||||
v-for="(path, index) in polyline"
|
||||
:key="index"
|
||||
></bm-polyline>
|
||||
</div>
|
||||
|
||||
<!-- 变电站-->
|
||||
<template v-if="zoom > 13">
|
||||
<bm-marker
|
||||
:position="path"
|
||||
v-for="path in siteList"
|
||||
:key="path.subId"
|
||||
:icon="path.icon"
|
||||
@click="markerClick(path)"
|
||||
></bm-marker>
|
||||
</template>
|
||||
<!-- 点 -->
|
||||
<div maxZoom="12">
|
||||
<bm-marker
|
||||
:position="path"
|
||||
v-for="path in areaLineInfo"
|
||||
:key="path.lineId"
|
||||
:icon="path.icon"
|
||||
@click="markerClick(path)"
|
||||
></bm-marker>
|
||||
</div>
|
||||
<bm-marker
|
||||
:position="infoWindowPoint"
|
||||
:icon="{ url: '1', size: { width: 0, height: 0 } }"
|
||||
>
|
||||
<bm-info-window
|
||||
:show="infoWindowPoint.show"
|
||||
@close="infoWindowPoint.show = false"
|
||||
>
|
||||
<el-descriptions
|
||||
:title="infoWindowPoint.lineName"
|
||||
style="min-width: 250px"
|
||||
:column="1"
|
||||
border
|
||||
v-if="infoWindowPoint.lineId"
|
||||
label-width="90px"
|
||||
>
|
||||
<el-descriptions-item label="供电区域">{{
|
||||
infoWindowPoint.gdName
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="上级电站">{{
|
||||
infoWindowPoint.stationName
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="上级母线">{{
|
||||
infoWindowPoint.busBarName
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="暂降次数">{{
|
||||
infoWindowPoint.eventCount
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item
|
||||
label="用户"
|
||||
v-if="infoWindowPoint.objName == null"
|
||||
>/</el-descriptions-item
|
||||
>
|
||||
<template v-else>
|
||||
<el-descriptions-item label="用户">
|
||||
<div class="descriptionsBox">
|
||||
<div
|
||||
v-for="(value, index) in infoWindowPoint.objName.split(
|
||||
';'
|
||||
)"
|
||||
style="white-space: nowrap"
|
||||
>
|
||||
{{ value }}
|
||||
</div>
|
||||
</div></el-descriptions-item
|
||||
>
|
||||
</template>
|
||||
</el-descriptions>
|
||||
<el-descriptions
|
||||
:title="infoWindowPoint.stationName"
|
||||
:column="1"
|
||||
v-else
|
||||
style="min-width: 250px"
|
||||
border
|
||||
>
|
||||
<!-- <el-descriptions-item
|
||||
:label="index == 0 ? '母线' : ''"
|
||||
v-for="(value, index) in infoWindowPoint.lineEventDetails"
|
||||
>
|
||||
{{ value.busBarName + `-` + value.lineName }}
|
||||
</el-descriptions-item> -->
|
||||
|
||||
<el-descriptions-item label="母线"
|
||||
><div class="descriptionsBox">
|
||||
<div
|
||||
v-for="(value, index) in infoWindowPoint.lineEventDetails"
|
||||
style="white-space: nowrap"
|
||||
>
|
||||
{{ value.busBarName + `-` + value.lineName }}
|
||||
</div>
|
||||
</div></el-descriptions-item
|
||||
>
|
||||
|
||||
<el-descriptions-item label="暂降次数">{{
|
||||
infoWindowPoint.eventCount
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</bm-info-window>
|
||||
</bm-marker>
|
||||
</baidu-map>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue";
|
||||
import { substationCount } from "@/api/statistics/index";
|
||||
import { useStore } from "vuex";
|
||||
// import { BmlMarkerClusterer } from "vue-baidu-map-3x";
|
||||
const store = useStore();
|
||||
const mapRef = ref<any>(null); // 地图容器的ref
|
||||
const mapInstance: any = ref(null); // 百度地图实例
|
||||
const BMapInstance: any = ref(null); // BMap对象
|
||||
const loading = ref(false);
|
||||
const dataList: any = ref([]);
|
||||
const polyline = ref<any>([]);
|
||||
const zoom = ref(12);
|
||||
const areaLineInfo = ref<any>([]);
|
||||
const siteList = ref<any>([]);
|
||||
const infoWindowPoint = ref<any>({
|
||||
lng: 0,
|
||||
lat: 0,
|
||||
show: false,
|
||||
});
|
||||
const center = ref({
|
||||
lng: 116.404367,
|
||||
lat: 39.915421,
|
||||
});
|
||||
const value = ref("");
|
||||
const handler = async ({ BMap, map }: any) => {
|
||||
if (!BMap.MarkerClusterer) {
|
||||
// await import("/offline/libs/MarkerClusterer_min.js");
|
||||
}
|
||||
mapInstance.value = map;
|
||||
BMapInstance.value = BMap;
|
||||
|
||||
// 监听地图容器的鼠标滚轮事件
|
||||
const mapDom = mapRef.value.$el; // 获取地图DOM元素
|
||||
mapDom.addEventListener("mousewheel", handleMapWheel, { passive: false });
|
||||
};
|
||||
|
||||
// 点击变电站\监测点
|
||||
const markerClick = (e: any) => {
|
||||
center.value.lng = e.lng;
|
||||
center.value.lat = e.lat + 0.01;
|
||||
zoom.value = 15;
|
||||
infoWindowPoint.value = e;
|
||||
infoWindowPoint.value.show = true;
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
loading.value = true;
|
||||
siteList.value = [];
|
||||
polyline.value = [];
|
||||
dataList.value = [];
|
||||
areaLineInfo.value = [];
|
||||
substationCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
dataList.value = res.data;
|
||||
let data = dataList.value;
|
||||
let r = 0.0035;
|
||||
let list = data.filter((item: any) => item.latitude != 0);
|
||||
list.forEach((item: any) => {
|
||||
// 变电站图标
|
||||
item.icon = {
|
||||
url: new URL("@/assets/jcd.png", import.meta.url).href,
|
||||
size: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
};
|
||||
if (
|
||||
item.lineEventDetails?.length > 10 &&
|
||||
item.lineEventDetails?.length < 100
|
||||
) {
|
||||
r = 0.0055;
|
||||
} else if (item.lineEventDetails.length >= 100) {
|
||||
r = 0.01055;
|
||||
}
|
||||
item.lng = item.longitude;
|
||||
item.lat = item.latitude;
|
||||
item.lineEventDetails.forEach((val: any, i: number) => {
|
||||
val.lng =
|
||||
item.longitude +
|
||||
r * Math.cos((2 * Math.PI * i) / item.lineEventDetails.length);
|
||||
val.lat =
|
||||
item.latitude +
|
||||
r * Math.sin((2 * Math.PI * i) / item.lineEventDetails.length);
|
||||
// 监测点图标
|
||||
val.icon = {
|
||||
url: "",
|
||||
size: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
};
|
||||
|
||||
val.icon.url = new URL("@/assets/txycyzj.gif", import.meta.url).href;
|
||||
polyline.value.push([
|
||||
{
|
||||
lng: item.lng,
|
||||
lat: item.lat,
|
||||
},
|
||||
{
|
||||
lng: val.lng,
|
||||
lat: val.lat,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
areaLineInfo.value.push(...item.lineEventDetails);
|
||||
});
|
||||
|
||||
siteList.value = list;
|
||||
|
||||
zoom.value = 12;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
const moveenFlag = ref(true);
|
||||
|
||||
const checkMapData = () => {
|
||||
if (!mapInstance.value || !BMapInstance.value || !moveenFlag.value) return;
|
||||
|
||||
// 获取地图容器
|
||||
const container = mapInstance.value.getContainer();
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
// 1. 获取所有图片瓦片
|
||||
const tiles = Array.from(container.querySelectorAll("img"));
|
||||
|
||||
// 2. 检查是否有离线地图瓦片
|
||||
const hasOfflineTiles = tiles.some((tile: any) => {
|
||||
// 确保tile是有效的DOM元素
|
||||
if (!tile || !tile.src) return false;
|
||||
|
||||
// 检查是否是离线瓦片
|
||||
return tile.src.includes("/plugin/offline/tiles/");
|
||||
});
|
||||
|
||||
// 3. 如果没有离线瓦片,回到默认位置
|
||||
if (!hasOfflineTiles) {
|
||||
console.warn("当前区域无离线地图数据,将返回默认位置");
|
||||
|
||||
// 使用正确的BMap.Point创建方式
|
||||
const point = new BMapInstance.value.Point(116.404367, 39.915421);
|
||||
|
||||
// 平滑移动并设置合适缩放级别
|
||||
mapInstance.value.panTo(point);
|
||||
mapInstance.value.setZoom(12);
|
||||
// zoom.value = 12;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("地图检测出错:", error);
|
||||
}
|
||||
}, 1000); // 适当缩短延迟时间
|
||||
};
|
||||
|
||||
// 处理地图滚轮缩放,修正scale导致的坐标偏移
|
||||
const handleMapWheel = (e: WheelEvent) => {
|
||||
e.preventDefault();
|
||||
if (!mapInstance.value || !BMapInstance.value) return;
|
||||
|
||||
// 1. 获取当前缩放比例(假设你通过scale变量控制,需替换为你的实际scale值)
|
||||
const scaleWidth: any = window.sessionStorage.getItem("scaleWidth"); // 你的水平缩放比例
|
||||
const scaleHeight: any = window.sessionStorage.getItem("scaleheight"); // 你的垂直缩放比例
|
||||
|
||||
// 2. 获取地图容器的位置和尺寸(原始DOM尺寸,未被scale影响)
|
||||
const rect = mapRef.value.$el.getBoundingClientRect();
|
||||
|
||||
// 3. 计算鼠标在地图容器内的原始坐标(未修正)
|
||||
const mouseXRaw = e.clientX - rect.left;
|
||||
const mouseYRaw = e.clientY - rect.top;
|
||||
|
||||
// 4. 修正坐标:除以缩放比例,得到scale前的原始坐标(地图实际识别的坐标)
|
||||
const mouseX = mouseXRaw / scaleWidth;
|
||||
const mouseY = mouseYRaw / scaleHeight;
|
||||
|
||||
// 5. 将修正后的坐标转换为百度地图的经纬度
|
||||
const point = new BMapInstance.value.Pixel(mouseX, mouseY);
|
||||
const lngLat = mapInstance.value.pixelToPoint(point); // 像素坐标转经纬度
|
||||
|
||||
// 6. 执行缩放(滚轮向上放大,向下缩小)
|
||||
const zoomDelta = e.deltaY < 0 ? 1 : -1; // 滚轮方向
|
||||
const newZoom = mapInstance.value.getZoom() + zoomDelta;
|
||||
if (newZoom < 10 || newZoom > 15) return; // 限制缩放范围(百度地图默认范围)
|
||||
|
||||
// 7. 缩放时保持鼠标指向的位置不变(核心:先缩放再移中心点)
|
||||
mapInstance.value.setZoom(newZoom);
|
||||
mapInstance.value.setCenter(lngLat); // 让鼠标指向的位置成为新中心
|
||||
};
|
||||
const syncCenterAndZoom = (e: any) => {
|
||||
zoom.value = e.target.getZoom();
|
||||
checkMapData();
|
||||
};
|
||||
//点击过滤位置
|
||||
const setIcon = (e: string) => {
|
||||
moveenFlag.value = false;
|
||||
siteList.value.forEach((item: any) => {
|
||||
if (item.stationName == e) {
|
||||
center.value.lng = item.lng;
|
||||
center.value.lat = item.lat + 0.01;
|
||||
infoWindowPoint.value = item;
|
||||
infoWindowPoint.value.show = true;
|
||||
zoom.value = 15;
|
||||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
moveenFlag.value = true;
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
init,
|
||||
setIcon,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 600px;
|
||||
}
|
||||
.bm-view {
|
||||
width: 99%;
|
||||
height: 590px;
|
||||
}
|
||||
.iconBox {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
z-index: 2000;
|
||||
width: 110px;
|
||||
height: 70px;
|
||||
padding: 10px;
|
||||
background: #ffffff10 !important;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
|
||||
font-size: 12px;
|
||||
|
||||
.div {
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
|
||||
img {
|
||||
height: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-descriptions__title) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.el-descriptions__content) {
|
||||
color: #fff;
|
||||
// width: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__body) {
|
||||
color: #fff;
|
||||
background-color: rgb(0 0 0 / 0%) !important;
|
||||
}
|
||||
:deep(.el-descriptions__label) {
|
||||
color: #fff;
|
||||
// display: inline-block;
|
||||
width: 80px;
|
||||
text-align: right; /* 右对齐 */
|
||||
}
|
||||
:deep(.BMap_pop .BMap_center) {
|
||||
background-color: #343849c7;
|
||||
}
|
||||
.descriptionsBox {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.BMap_cpyCtrl {
|
||||
display: none;
|
||||
}
|
||||
.anchorBL {
|
||||
display: none;
|
||||
} /* 地图容器样式 */
|
||||
.baidu-map-container {
|
||||
/* 消除可能的缝隙 */
|
||||
line-height: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
/* .BMap_pop div {
|
||||
background-color: #343849c7 !important;
|
||||
} */
|
||||
.BMap_top,
|
||||
.BMap_bottom {
|
||||
background-color: #343849c7 !important;
|
||||
}
|
||||
/* .BMap_pop div:nth-child(1) {
|
||||
background-color: #343849c7 !important;
|
||||
} */
|
||||
.BMap_pop > div:nth-child(1) > div,
|
||||
.BMap_pop > div:nth-child(3) > div,
|
||||
.BMap_pop > div:nth-child(5) > div,
|
||||
.BMap_pop > div:nth-child(7) > div {
|
||||
background-color: #343849c7 !important;
|
||||
}
|
||||
.BMap_pop > div:nth-child(8) > img {
|
||||
display: none;
|
||||
}
|
||||
.BMap_pop > div:nth-child(8) {
|
||||
/* 设置边框宽度和颜色,上边框为可见颜色,其他边框为透明 */
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
border-left: 20px solid transparent;
|
||||
border-right: 20px solid transparent;
|
||||
border-top: 20px solid #343849c7; /* 倒三角的颜色 */
|
||||
transform: translateX(-26px) translateY(24px);
|
||||
/* 可选:添加阴影增强视觉效果 */
|
||||
/* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); */
|
||||
}
|
||||
.bmSelect {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 2000;
|
||||
}
|
||||
</style>
|
||||
376
src/views/VoltageSag_BJ/components/bottomText.vue
Normal file
376
src/views/VoltageSag_BJ/components/bottomText.vue
Normal file
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 一般告警 -->
|
||||
<div class="scroll-box">
|
||||
<div class="scroll-content" ref="animatedRef"></div>
|
||||
</div>
|
||||
<!-- 紧急告警 -->
|
||||
<el-drawer
|
||||
class="urgent"
|
||||
modal-class="drawer"
|
||||
v-model="drawer"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
title="紧急告警"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div :class="urgentList.length > 0 ? 'bg-red' : ''">
|
||||
<div class="drawer-but">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="totalProcessing(1)"
|
||||
:icon="Check"
|
||||
>确认</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="totalProcessing(2)"
|
||||
:icon="Check"
|
||||
>一键确认</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="messageBox">
|
||||
<div
|
||||
class="mesModule"
|
||||
v-for="(item, index) in urgentList"
|
||||
:key="index"
|
||||
>
|
||||
<el-checkbox v-model="item.checked" value="" size="large" />
|
||||
<span
|
||||
class="iconfont icon-gaojing"
|
||||
:class="item.checked ? 'blue' : 'animate-flash-red'"
|
||||
></span>
|
||||
<div
|
||||
:style="{ color: item.checked ? '#0a73ff' : '#ff0000' }"
|
||||
style="font-weight: 650"
|
||||
@click="handleCurrentChange(item)"
|
||||
>
|
||||
<div>{{ item.timeid }}.{{ item.ms }}</div>
|
||||
<p class="mt5">
|
||||
{{ item.bdname }} {{ item.pointname }}发生{{
|
||||
filteWavetype(item.wavetype)
|
||||
}}事件,事件残余电压{{
|
||||
Math.floor(item.eventvalue * 10000) / 100
|
||||
}}%,持续时间:{{ item.persisttime }}s;
|
||||
</p>
|
||||
<p class="mt5" style="display: flex; font-size: 14px">
|
||||
<span
|
||||
style="width: 75px"
|
||||
:style="{ color: item.checked ? '#0a73ff' : '#ffc107' }"
|
||||
>
|
||||
影响范围: </span
|
||||
><span
|
||||
style="flex: 1"
|
||||
:style="{ color: item.checked ? '#0a73ff' : '#ffc107' }"
|
||||
>{{ item.objName }}</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<audio
|
||||
ref="audioRef"
|
||||
id="audioId"
|
||||
:src="mp3Src"
|
||||
loop
|
||||
controls
|
||||
hidden="true"
|
||||
></audio>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { Check } from "@element-plus/icons-vue";
|
||||
import { speak } from "@/utils/index";
|
||||
import { noDealEventList, lookEvent } from "@/api/statistics/index";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { useStore } from "vuex";
|
||||
import { color } from "echarts";
|
||||
|
||||
const store = useStore();
|
||||
const emit = defineEmits(["close", "handleCurrentChange"]);
|
||||
const drawer = ref(false);
|
||||
const broadcast: any = ref([]);
|
||||
const multipleSelection: any = ref();
|
||||
const urgentList: any = ref([]);
|
||||
const multipleTableRef = ref();
|
||||
const key: any = ref(0);
|
||||
const gradeValue: any = ref(0);
|
||||
const handleSelectionChange = (val: any) => {
|
||||
multipleSelection.value = val;
|
||||
};
|
||||
const mp3Src: any = new URL(`@/assets/mp3/9578.mp3`, import.meta.url);
|
||||
const audioRef: any = ref(null);
|
||||
const updateData = (row: any) => {
|
||||
console.log(
|
||||
`🚀 ~ updateData ~ !row.dept.split(",").includes(store.state.deptId:`,
|
||||
!row.dept.split(",").includes(store.state.deptId)
|
||||
);
|
||||
|
||||
if (!row.dept.split(",").includes(store.state.deptId)) return;
|
||||
broadcast.value.push(row);
|
||||
// // 语音播报数据
|
||||
// console.log(
|
||||
// "🚀 ~ updateData ~ store.state.seriousNotice == 1 || store.state.normalNotic == 1:",
|
||||
// store.state.seriousNotice == 1,
|
||||
// store.state.normalNotic == 1,
|
||||
// key.value,
|
||||
// row
|
||||
// );
|
||||
|
||||
// // 语音播报
|
||||
// if (store.state.normalNotic == 1) {
|
||||
// if (
|
||||
// broadcast.value[key.value].eventvalue >= 0.5 &&
|
||||
// broadcast.value[key.value].eventvalue < 0.9
|
||||
// ) {
|
||||
// speakBrowser(broadcast.value[key.value]);
|
||||
// }
|
||||
// }
|
||||
if (store.state.seriousNotice == 1) {
|
||||
speakBrowser(broadcast.value[key.value]);
|
||||
}
|
||||
key.value += 1;
|
||||
|
||||
urgentList.value.unshift({ ...row, checked: false });
|
||||
drawer.value = true;
|
||||
// }
|
||||
};
|
||||
const openDrawer = () => {
|
||||
drawer.value = true;
|
||||
};
|
||||
const openSignificant = () => {};
|
||||
const animatedRef = ref();
|
||||
|
||||
// 语音播报
|
||||
const speakBrowser = (item: any) => {
|
||||
if (store.state.voiceType == 2) {
|
||||
// setTimeout(() => {
|
||||
// audioRef.value && audioRef.value.play(); //播放
|
||||
// }, 500);
|
||||
|
||||
audioRef.value.play(); //没有就播放
|
||||
// audioRef.value.pause() //暂停
|
||||
} else if (store.state.voiceType == 1) {
|
||||
speak(
|
||||
` ${item.timeid}${item.bdname}${
|
||||
item.pointname
|
||||
}发生${filteWavetype(item.wavetype)}事件,事件特征幅值${Math.floor(
|
||||
item.eventvalue * 100
|
||||
)}%,持续时间:${item.persisttime}秒`,
|
||||
() => {
|
||||
// key.value += 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
// 确认总数据
|
||||
const totalProcessing = (number: number, id?: string) => {
|
||||
let list: any = [];
|
||||
if (number == 0) {
|
||||
//总数据确认
|
||||
if (multipleSelection.value == undefined) {
|
||||
return ElMessage.warning(`请选择需要确认的事件`);
|
||||
}
|
||||
list = multipleSelection.value.map((item: any) => item.eventdetail_index);
|
||||
} else if (number == 1) {
|
||||
//紧急告警确认
|
||||
list = urgentList.value
|
||||
.filter((item: any) => item.checked == true)
|
||||
.map((item: any) => item.eventdetail_index);
|
||||
} else if (number == 2) {
|
||||
//紧急告警全部确认
|
||||
list = urgentList.value.map((item: any) => item.eventdetail_index);
|
||||
} else if (number == 3) {
|
||||
list = [id];
|
||||
}
|
||||
if (list.length == 0) {
|
||||
return ElMessage.warning(`请选择需要确认的事件`);
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("请确认是否确认", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
lookEvent(list).then((res) => {
|
||||
list.forEach((id: any) => {
|
||||
urgentList.value = urgentList.value.filter(
|
||||
(item: any) => item.eventdetail_index != id
|
||||
);
|
||||
broadcast.value = broadcast.value.filter(
|
||||
(item: any) => item.eventdetail_index != id
|
||||
);
|
||||
});
|
||||
if (broadcast.value.length == 0) {
|
||||
audioRef.value.pause();
|
||||
}
|
||||
key.value -= list.length;
|
||||
if (urgentList.value.length == 0) {
|
||||
drawer.value = false;
|
||||
}
|
||||
return ElMessage({
|
||||
message: "确认成功",
|
||||
type: "success",
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
// 过滤数据
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
noDealEventList({
|
||||
deptId: store.state.deptId,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
eventtype: 0,
|
||||
}).then((res) => {
|
||||
res.data.forEach((item: any) => {
|
||||
// if (item.eventvalue < 0.5) {
|
||||
urgentList.value.unshift({ ...item, checked: false });
|
||||
});
|
||||
broadcast.value = res.data;
|
||||
key.value = res.data.length;
|
||||
if (urgentList.value.length > 0) {
|
||||
drawer.value = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleCurrentChange = (e: any) => {
|
||||
emit("handleCurrentChange", e.bdname);
|
||||
};
|
||||
// 关闭事件
|
||||
const handleClose = (done: (cancel?: boolean) => void) => {
|
||||
if (urgentList.value.length > 0) {
|
||||
return ElMessage.warning(`请优先确认告警事件。`);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
|
||||
setTimeout(() => {
|
||||
init();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
updateData,
|
||||
urgentList,
|
||||
broadcast,
|
||||
openDrawer,
|
||||
openSignificant,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.react-right {
|
||||
width: 500px !important;
|
||||
}
|
||||
|
||||
.drawer-but {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
padding: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.gradeInput {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-drawer__header) {
|
||||
margin-bottom: 0px;
|
||||
border-bottom: 1px solid #fff;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
:deep(.el-drawer__body) {
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.urgent) {
|
||||
width: 100% !important;
|
||||
height: 910px;
|
||||
}
|
||||
:deep(.drawer) {
|
||||
// border: 1px solid #ff0000;
|
||||
|
||||
width: 25%;
|
||||
height: 920px;
|
||||
top: 9%;
|
||||
overflow: hidden;
|
||||
left: auto !important;
|
||||
.el-drawer {
|
||||
border: 1px solid #ff0000;
|
||||
height: 910px !important;
|
||||
}
|
||||
.messageBox {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
height: 822px;
|
||||
padding: 0 10px;
|
||||
div {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 8px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #888; /* 滑块背景颜色 */
|
||||
border-radius: 5px; /* 滑块圆角 */
|
||||
}
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: #555; /* 悬停时滑块背景颜色 */
|
||||
}
|
||||
overflow-y: auto;
|
||||
.mesModule {
|
||||
margin-bottom: 10px;
|
||||
background-color: #00000085;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
p {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 24px !important;
|
||||
color: #ff0000;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.blue {
|
||||
color: #0a73ff;
|
||||
}
|
||||
</style>
|
||||
177
src/views/VoltageSag_BJ/components/config.vue
Normal file
177
src/views/VoltageSag_BJ/components/config.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<!--短信查询-->
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="machineVisible" :title="title" width="500">
|
||||
<div>
|
||||
<div style="height: 360px" class="smsConfig">
|
||||
<el-form :model="form" inline label-width="auto" class="mb10 ml30 mt20">
|
||||
<el-form-item label="屏幕通知">
|
||||
<el-radio-group v-model="form.screenNotic" size="small">
|
||||
<el-radio-button label="关闭" :value="0" />
|
||||
<el-radio-button label="开启" :value="1" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="严重事件语音通知">
|
||||
<el-radio-group v-model="form.seriousNotice" size="small">
|
||||
<el-radio-button label="关闭" :value="0" />
|
||||
<el-radio-button label="开启" :value="1" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="重要事件语音通知">
|
||||
<el-radio-group v-model="form.normalNotic" size="small">
|
||||
<el-radio-button label="关闭" :value="0" />
|
||||
<el-radio-button label="开启" :value="1" />
|
||||
</el-radio-group>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="语音类型">
|
||||
<el-radio-group v-model="form.voiceType" size="small">
|
||||
<el-radio-button label="人声" :value="1" />
|
||||
<el-radio-button label="音频" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="触发类型">
|
||||
<el-checkbox-group v-model="form.eventTypeList" size="small">
|
||||
<el-checkbox-button value="0" :key="0">扰动</el-checkbox-button>
|
||||
<el-checkbox-button value="1">暂降</el-checkbox-button>
|
||||
<el-checkbox-button value="2">暂升</el-checkbox-button>
|
||||
<el-checkbox-button value="3">中断</el-checkbox-button>
|
||||
<el-checkbox-button value="4">其他</el-checkbox-button>
|
||||
<el-checkbox-button value="5">录波</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="残余电压告警阈值">
|
||||
<el-input-number
|
||||
v-model="form.eventValue"
|
||||
:min="0"
|
||||
:max="0.9"
|
||||
:precision="1"
|
||||
:step="0.1"
|
||||
@change="(e) => (e == null ? (form.eventValue = 0.1) : null)"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="持续时间告警阈值">
|
||||
<el-input-number
|
||||
v-model="form.eventDuration"
|
||||
:min="0"
|
||||
:max="1000000"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="(e) => (e == null ? (form.eventDuration = 1) : null)"
|
||||
style="width: 200px"
|
||||
>
|
||||
<template #suffix>
|
||||
<span>ms</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-divider />
|
||||
<div style="text-align: center">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Tools"
|
||||
@click="setUp"
|
||||
class="mt10"
|
||||
size="small"
|
||||
>设置</el-button
|
||||
>
|
||||
<el-button :icon="Close" @click="setUp" class="mt10" size="small"
|
||||
>取消</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, inject } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Tools, Close } from "@element-plus/icons-vue";
|
||||
import { queryConfig, eventConfig } from "@/api/statistics/index";
|
||||
import { useStore } from "vuex";
|
||||
import { stopSpeak } from "@/utils/index";
|
||||
const store = useStore();
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("系统配置");
|
||||
//form表单校验规则
|
||||
const emit = defineEmits(["flushed"]);
|
||||
const open = (text: string, data?: any) => {
|
||||
// queryConfig().then((res) => {
|
||||
// form.value = res.data;
|
||||
// });
|
||||
form.value.seriousNotice = store.state.seriousNotice;
|
||||
form.value.normalNotic = store.state.normalNotic;
|
||||
form.value.voiceType = store.state.voiceType;
|
||||
form.value.screenNotic = store.state.screenNotic;
|
||||
form.value.eventTypeList = store.state.eventTypeList;
|
||||
form.value.eventValue = store.state.eventValue;
|
||||
form.value.eventDuration = store.state.eventDuration;
|
||||
machineVisible.value = true;
|
||||
};
|
||||
|
||||
const form = ref({
|
||||
seriousNotice: 1,
|
||||
normalNotic: 1,
|
||||
voiceType: 1,
|
||||
screenNotic: 1,
|
||||
eventTypeList: ["0", "1"],
|
||||
eventValue: 0.7,
|
||||
eventDuration: 5,
|
||||
});
|
||||
// 设置
|
||||
const setUp = () => {
|
||||
eventConfig(form.value).then((res) => {
|
||||
ElMessage.success("设置成功");
|
||||
store.dispatch("setConfig");
|
||||
if (
|
||||
form.value.normalNotic != store.state.normalNotic ||
|
||||
form.value.seriousNotice != store.state.seriousNotice ||
|
||||
form.value.voiceType != store.state.voiceType
|
||||
) {
|
||||
stopSpeak();
|
||||
}
|
||||
if (form.value.eventTypeList != store.state.eventTypeList) {
|
||||
emit("flushed");
|
||||
}
|
||||
|
||||
machineVisible.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.smsConfig {
|
||||
color: #fff;
|
||||
}
|
||||
.title {
|
||||
background-color: #0a73ff40;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-weight: 600;
|
||||
padding-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-left: 10px solid var(--el-color-primary);
|
||||
}
|
||||
:deep(.el-card__body) {
|
||||
padding: 10px !important;
|
||||
}
|
||||
:deep(.el-select) {
|
||||
min-width: 80px !important;
|
||||
}
|
||||
.checkbox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
:deep(.el-form-item__label, ) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.el-checkbox__label) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.el-form-item__label, ) {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
252
src/views/VoltageSag_BJ/components/endpointStatistics.vue
Normal file
252
src/views/VoltageSag_BJ/components/endpointStatistics.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<div class="titleBox">
|
||||
各区域终端运行状态
|
||||
<!-- <div class="titles">
|
||||
<div
|
||||
class="react-right"
|
||||
:class="time == 4 ? 'titleClick' : ''"
|
||||
@click="timeChange(4)"
|
||||
>
|
||||
<span class="text"> 周</span>
|
||||
</div>
|
||||
<div
|
||||
class="react-right"
|
||||
:class="time == 3 ? 'titleClick' : ''"
|
||||
@click="timeChange(3)"
|
||||
>
|
||||
<span class="text"> 月</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div v-loading="loading" element-loading-background="#343849c7">
|
||||
<!-- style="width: 450px; height: 285px" -->
|
||||
|
||||
<div
|
||||
class="eacharts1"
|
||||
ref="eacharts1"
|
||||
style="width: 100%; height: 330px"
|
||||
></div>
|
||||
</div>
|
||||
<!-- 详情弹框 -->
|
||||
<terminalPopUpBox ref="terminalPopUpBoxRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance, onUnmounted, markRaw } from "vue";
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
import * as echarts from "echarts";
|
||||
import terminalPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/terminalPopUpBox.vue";
|
||||
import { regionDevCount } from "@/api/statistics/index";
|
||||
import { isEqual } from "lodash";
|
||||
import { useStore } from "vuex";
|
||||
const terminalPopUpBoxRef = ref();
|
||||
const store = useStore();
|
||||
const eacharts1 = ref(null);
|
||||
const time = ref(4); //
|
||||
const dataSource = ref([]);
|
||||
const loading = ref(false);
|
||||
const myChart = ref(null);
|
||||
const renderChart = () => {
|
||||
// 如果实例存在,则销毁它
|
||||
if (myChart.value) {
|
||||
myChart.value.dispose();
|
||||
}
|
||||
myChart.value = markRaw(proxy.$echarts.init(eacharts1.value));
|
||||
|
||||
myChart.value.setOption({
|
||||
legend: {
|
||||
right: 10,
|
||||
top: 5,
|
||||
itemGap: 10,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
fontSize: 12,
|
||||
padding: [2, 0, 0, 0], //[上、右、下、左]
|
||||
itemWidth: 15,
|
||||
itemHeight: 10,
|
||||
},
|
||||
grid: {
|
||||
containLabel: true,
|
||||
left: "4%",
|
||||
right: "40",
|
||||
bottom: "15",
|
||||
top: "45",
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
show: true,
|
||||
},
|
||||
color: ["#28a74590", "#ff250070"],
|
||||
xAxis: {
|
||||
name: "区域",
|
||||
type: "category",
|
||||
show: true,
|
||||
boundaryGap: [20, 0], // 左侧留出空间
|
||||
splitLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
rotate: 45, // 旋转角度,如45度
|
||||
interval: 0, // 强制显示所有标签
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 10,
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
show: true, //不显示x轴
|
||||
onZero: false, // 不强制与Y轴0点对齐
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false, //不显示刻度
|
||||
},
|
||||
data: dataSource.value.map((item) => item.areaName),
|
||||
},
|
||||
|
||||
yAxis: [
|
||||
{
|
||||
name: "台",
|
||||
minInterval: 5,
|
||||
axisLabel: {
|
||||
color: "#fff",
|
||||
fontWeight: 400,
|
||||
fontSize: 10,
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
show: true, //不显示x轴
|
||||
lineStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false, //不显示刻度
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "在线终端",
|
||||
type: "bar",
|
||||
stack: "total",
|
||||
data: dataSource.value.map((item) => item.onLine),
|
||||
barMaxWidth: 20,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
// 使用函数形式的formatter进行判断
|
||||
formatter: function (params) {
|
||||
// 如果值为0则返回空字符串(不显示),否则显示数值
|
||||
return params.value === 0 ? "" : params.value;
|
||||
},
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "离线终端",
|
||||
type: "bar",
|
||||
stack: "total",
|
||||
data: dataSource.value.map((item) => item.offLine),
|
||||
barMaxWidth: 20,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
// 使用函数形式的formatter进行判断
|
||||
formatter: function (params) {
|
||||
// 如果值为0则返回空字符串(不显示),否则显示数值
|
||||
return params.value === 0 ? "" : params.value;
|
||||
},
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
// 添加点击事件
|
||||
myChart.value.off("click"); // 先移除之前的点击事件
|
||||
// 添加点击事件(修改后)
|
||||
myChart.value.on("click", function (params) {
|
||||
// 1. 只处理系列数据(柱状图)的点击,忽略图例等其他元素
|
||||
if (params.componentType !== "series") {
|
||||
return; // 非系列点击直接返回,避免执行后续逻辑
|
||||
}
|
||||
|
||||
// 2. 安全获取匹配的数据源(使用find替代filter,更高效)
|
||||
const matchedItem = dataSource.value.find(
|
||||
(item) => item.areaName === params.name
|
||||
);
|
||||
|
||||
// 3. 确保数据存在后再执行操作,避免undefined错误
|
||||
if (matchedItem && matchedItem.deptsIndex !== undefined) {
|
||||
terminalPopUpBoxRef.value.open(matchedItem.deptsIndex);
|
||||
}
|
||||
});
|
||||
};
|
||||
const init = () => {
|
||||
regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
let isSame = isEqual(dataSource.value, res.data);
|
||||
dataSource.value = res.data;
|
||||
|
||||
if (!isSame) {
|
||||
loading.value = true;
|
||||
renderChart();
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 保存定时器ID
|
||||
const timer = ref(null);
|
||||
onMounted(() => {
|
||||
// 保存定时器引用
|
||||
timer.value = setInterval(() => {
|
||||
init();
|
||||
}, 60000);
|
||||
});
|
||||
// 组件卸载时清除定时器
|
||||
onUnmounted(() => {
|
||||
if (timer.value) {
|
||||
clearInterval(timer.value);
|
||||
timer.value = null;
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.titles {
|
||||
margin-right: 10px;
|
||||
.react-right {
|
||||
width: 50px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
373
src/views/VoltageSag_BJ/components/eventStatistics.vue
Normal file
373
src/views/VoltageSag_BJ/components/eventStatistics.vue
Normal file
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<div class="titleBox">电能质量监测终端运行状态</div>
|
||||
<div class="Box" v-loading="loading" element-loading-background="#343849c7">
|
||||
<dv-border-box-7 :color="color[3]">
|
||||
<div class="eachartsBox eachartsBoxTop" style="place-items: center">
|
||||
<div class="totalBox">
|
||||
<div
|
||||
class="textTop"
|
||||
style="background-color: #28a74570"
|
||||
@click="openterminalPopUpBox('')"
|
||||
>
|
||||
<span>{{ data.allCount }}</span>
|
||||
<span>已安装终端数</span>
|
||||
</div>
|
||||
<div
|
||||
class="textTop"
|
||||
style="background-color: #28a74590"
|
||||
@click="openterminalPopUpBox('1')"
|
||||
>
|
||||
<span>{{ data.onLine }}</span>
|
||||
<span>在线终端数</span>
|
||||
</div>
|
||||
<div
|
||||
class="textTop"
|
||||
style="background-color: #ff250070"
|
||||
@click="openterminalPopUpBox('0')"
|
||||
>
|
||||
<span>{{ data.offLine }}</span>
|
||||
<span>离线终端数</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dv-border-box-7>
|
||||
<dv-border-box-7 :color="color[3]">
|
||||
<div class="boxCenter" style="place-items: center">
|
||||
<div
|
||||
class="eacharts1"
|
||||
ref="eacharts1"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
</dv-border-box-7>
|
||||
</div>
|
||||
<!-- 详情弹框 -->
|
||||
<terminalPopUpBox ref="terminalPopUpBoxRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance, onUnmounted } from "vue";
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
import { color } from "@/constant/index";
|
||||
import terminalPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/terminalPopUpBox.vue";
|
||||
import { devFlagCount } from "@/api/statistics/index";
|
||||
import "echarts-liquidfill";
|
||||
import { isEqual } from "lodash";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const loading = ref(false);
|
||||
const data: any = ref({
|
||||
alarmCount: 0,
|
||||
eventCount: 0,
|
||||
lookALarmCount: 0,
|
||||
lookNoticeCount: 0,
|
||||
lookWarnCount: 0,
|
||||
noticeCount: 0,
|
||||
warnCount: 0,
|
||||
});
|
||||
const eacharts1 = ref(null);
|
||||
|
||||
const terminalPopUpBoxRef = ref();
|
||||
const myChart = ref(null);
|
||||
const renderChart = (key: any) => {
|
||||
// 如果实例存在,则销毁它
|
||||
if (myChart.value) {
|
||||
myChart.value.dispose();
|
||||
}
|
||||
|
||||
myChart.value = proxy.$echarts.init(key);
|
||||
myChart.value.setOption({
|
||||
color: ["#28a74590", "#ff250070"],
|
||||
title: {
|
||||
text: "终端运行状态占比",
|
||||
left: "center",
|
||||
top: "10",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
right: 10,
|
||||
top: 10,
|
||||
itemGap: 10,
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
fontSize: 12,
|
||||
padding: [2, 0, 0, 0], //[上、右、下、左]
|
||||
itemWidth: 15,
|
||||
itemHeight: 10,
|
||||
data: ["在线终端", "离线终端"],
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: function (el) {
|
||||
return el.marker + el.name + " : " + el.value;
|
||||
},
|
||||
// formatter: "{b} : {c} ({d}%)",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
showEmptyCircle: true,
|
||||
type: "pie",
|
||||
center: ["50%", "55%"],
|
||||
radius: "55%",
|
||||
selectedOffset: 100, // 设置偏离距离
|
||||
minAngle: 10,
|
||||
|
||||
label: {
|
||||
show: true,
|
||||
overflow: "none",
|
||||
|
||||
formatter: function (data) {
|
||||
return (
|
||||
"{name|" +
|
||||
data.name +
|
||||
": " +
|
||||
data.value +
|
||||
"台" +
|
||||
"\n}" +
|
||||
" \n{value|占比:" +
|
||||
data.percent.toFixed(1) +
|
||||
"%}"
|
||||
);
|
||||
},
|
||||
rich: {
|
||||
name: {
|
||||
fontSize: 12,
|
||||
color: "#ffffff",
|
||||
},
|
||||
value: {
|
||||
fontSize: 12,
|
||||
color: "#ffffff",
|
||||
},
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
normal: {
|
||||
length: 15,
|
||||
length2: 0,
|
||||
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderColor: "#03060F",
|
||||
borderWidth: "5",
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: "在线终端",
|
||||
value: data.value.onLine,
|
||||
},
|
||||
{
|
||||
name: "离线终端",
|
||||
value: data.value.offLine,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
// 添加点击事件
|
||||
myChart.value.off("click"); // 先移除之前的点击事件
|
||||
myChart.value.on("click", function (params: any) {
|
||||
if (params.name == "在线终端") {
|
||||
openterminalPopUpBox("1");
|
||||
} else {
|
||||
openterminalPopUpBox("0");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const openterminalPopUpBox = (status: string) => {
|
||||
terminalPopUpBoxRef.value.open("", status);
|
||||
|
||||
// devFlagCountDetail({
|
||||
// deptId: store.state.deptId,
|
||||
// type: store.state.timeType,
|
||||
// }).then((res: any) => {
|
||||
|
||||
// })
|
||||
};
|
||||
const init = () => {
|
||||
devFlagCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
let isSame = isEqual(data.value, res.data);
|
||||
|
||||
data.value = res.data;
|
||||
if (!isSame) {
|
||||
loading.value = true;
|
||||
|
||||
renderChart(eacharts1.value);
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 保存定时器ID
|
||||
const timer = ref(null);
|
||||
onMounted(() => {
|
||||
// 保存定时器引用
|
||||
timer.value = setInterval(() => {
|
||||
init();
|
||||
}, 60000);
|
||||
});
|
||||
// 组件卸载时清除定时器
|
||||
onUnmounted(() => {
|
||||
if (timer.value) {
|
||||
clearInterval(timer.value);
|
||||
timer.value = null;
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.Box {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 550px;
|
||||
grid-template-rows: 1fr 2fr;
|
||||
padding: 10px 10px 15px 10px;
|
||||
|
||||
.eachartsBox {
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-columns: 1.3fr 1fr;
|
||||
|
||||
.totalBox {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
height: 80%;
|
||||
width: 85%;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
border-radius: 10px;
|
||||
|
||||
.textBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
text-align: end;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.eachartsBoxTop {
|
||||
grid-template-columns: 1fr;
|
||||
.totalBox {
|
||||
width: 92%;
|
||||
height: 70%;
|
||||
|
||||
grid-template-rows: 1fr;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
.textTop {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-radius: 10px 0 0 10px;
|
||||
// border-right: 1px solid #fff;
|
||||
border-bottom: none;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
border-radius: 0 10px 10px 0;
|
||||
// border-right: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(2) {
|
||||
// margin-top: 10px;
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
}
|
||||
&:nth-child(1) {
|
||||
font-weight: 700;
|
||||
// margin-bottom: 5px;
|
||||
line-height: 30px;
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.boxCenter {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-rows: repeat(1, 1fr);
|
||||
.box {
|
||||
// height: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
grid-template-columns: 1.3fr 1fr;
|
||||
// place-items: center;
|
||||
|
||||
.totalBox {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
height: 80%;
|
||||
width: 85%;
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
border-radius: 10px;
|
||||
|
||||
margin: auto;
|
||||
.textBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
// justify-content: center;
|
||||
&:nth-child(1) {
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
span {
|
||||
cursor: pointer;
|
||||
&:nth-child(1) {
|
||||
font-size: 14px;
|
||||
width: 120px;
|
||||
text-align: end;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- -->
|
||||
622
src/views/VoltageSag_BJ/components/informationTable.vue
Normal file
622
src/views/VoltageSag_BJ/components/informationTable.vue
Normal file
@@ -0,0 +1,622 @@
|
||||
<template>
|
||||
<div class="titleBox">暂降事件列表</div>
|
||||
|
||||
<el-form inline="true" class="positioning">
|
||||
<el-form-item label="关键字筛选" style="margin-right: 10px">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="电站、测点、用户信息"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="margin-right: 10px">
|
||||
<el-popover placement="bottom" :width="550" trigger="click">
|
||||
<template #reference>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="DArrowRight"
|
||||
type="primary"
|
||||
style="margin-right: 10px"
|
||||
>更多</el-button
|
||||
>
|
||||
</template>
|
||||
|
||||
<el-form label-width="auto">
|
||||
<el-form-item label="关键字筛选">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="电站、测点、用户信息"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="触发类型">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
v-model="eventForm.eventtype"
|
||||
placeholder="请选择触发类型"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in eventTypeList"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="残余电压百分比">
|
||||
<el-input-number
|
||||
v-model="eventForm.eventValueMin"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventValueMin = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>%</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
<span> < 残余电压 < </span>
|
||||
|
||||
<el-input-number
|
||||
v-model="eventForm.eventValueMax"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventValueMax = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>%</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item label="暂降持续事时间">
|
||||
<el-input-number
|
||||
v-model="eventForm.eventDurationMin"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="1000000"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventDurationMin = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>ms</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
<span> < 持续时间 < </span>
|
||||
|
||||
<el-input-number
|
||||
v-model="eventForm.eventDurationMax"
|
||||
:min="0"
|
||||
style="width: 150px"
|
||||
size="small"
|
||||
:max="1000000"
|
||||
:precision="1"
|
||||
:step="1"
|
||||
@change="
|
||||
(e) => (e == null ? (eventForm.eventDurationMax = 1) : null)
|
||||
"
|
||||
><template #suffix>
|
||||
<span>ms</span>
|
||||
</template></el-input-number
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-popover>
|
||||
<el-button
|
||||
style="margin-right: 10px"
|
||||
size="small"
|
||||
:icon="Search"
|
||||
type="primary"
|
||||
@click="init(true)"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button size="small" type="warn" :icon="RefreshLeft" @click="clearInit()">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div
|
||||
class="tableBox"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
>
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="dropList"
|
||||
height="270px"
|
||||
stripe
|
||||
highlight-current-row
|
||||
size="small"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<el-table-column type="index" width="60" align="center" label="序号">
|
||||
<template #default="scope">
|
||||
{{ (pageNum - 1) * pageSize + scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="timeid"
|
||||
align="center"
|
||||
label="发生时间"
|
||||
width="160"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope"
|
||||
>{{ scope.row.timeid }}.{{ scope.row.ms }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="bdname"
|
||||
align="center"
|
||||
label="变电站"
|
||||
show-overflow-tooltip
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
prop="pointname"
|
||||
align="center"
|
||||
label="监测点"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
align="center"
|
||||
label="用户"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="scope">{{ scope.row.objName || "/" }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="wavetype"
|
||||
align="center"
|
||||
width="70"
|
||||
label="触发类型"
|
||||
>
|
||||
<template #default="scope">
|
||||
|
||||
{{ filteWavetype(scope.row.wavetype) }}
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="eventvalue"
|
||||
align="center"
|
||||
label="残余电压"
|
||||
width="90"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ Math.floor(scope.row.eventvalue * 10000) / 100 }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="persisttime"
|
||||
align="center"
|
||||
label="持续时间"
|
||||
width="90"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ Math.floor(scope.row.persisttime * 1000) / 1000 }}s</template
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="address" align="center" label="操作" width="80">
|
||||
<template #default="scope">
|
||||
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click.stop="trendCharts(scope.row)"
|
||||
>
|
||||
波形
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 详情 -->
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="dialogVisible" title="详情" width="950">
|
||||
<div class="titleBox1">暂降事件信息</div>
|
||||
<el-descriptions
|
||||
:column="3"
|
||||
size="small"
|
||||
style="margin-bottom: 10px"
|
||||
label-width="120px"
|
||||
border
|
||||
>
|
||||
<el-descriptions-item label="发生时间"
|
||||
>{{ dataRow.timeid + "." + dataRow.ms }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="变电站"
|
||||
>{{ dataRow.bdname }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="监测点"
|
||||
>{{ dataRow.pointname }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户"
|
||||
>{{ dataRow.objName || "/" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="残余电压">
|
||||
{{ Math.floor(dataRow.eventvalue * 10000) / 100 }}%
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="持续时间">
|
||||
{{ dataRow.persisttime }}s
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div class="titleBox1 mt20">反馈信息</div>
|
||||
<el-descriptions
|
||||
:column="3"
|
||||
size="small"
|
||||
style="margin-bottom: 10px"
|
||||
label-width="120px"
|
||||
border
|
||||
>
|
||||
<el-descriptions-item label="是否影响敏感用户">
|
||||
<el-tag
|
||||
type="primary"
|
||||
v-if="detailList.isSensitive == 1"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>是
|
||||
</el-tag>
|
||||
<el-tag type="primary" v-else effect="dark">否</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item
|
||||
label="影响敏感用户名称"
|
||||
v-if="detailList.isSensitive == 1"
|
||||
>{{ detailList.objName || "/" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="影响原因" v-if="detailList.isSensitive == 1">
|
||||
{{ detailList.influenceFactors || "/" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理时间"
|
||||
>{{ detailList.dealDate || "/" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理方案"
|
||||
>{{ detailList.dealScheme || "/" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注"
|
||||
>{{ detailList.remark || "/" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div class="titleBox1 mt20">短信发送信息</div>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="detailList.msgList"
|
||||
height="300px"
|
||||
size="small"
|
||||
stripe
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column
|
||||
prop="sendTime"
|
||||
align="center"
|
||||
label="发送时间"
|
||||
width="160"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
prop="userName"
|
||||
align="center"
|
||||
label="接收人"
|
||||
width="100"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
prop="phone"
|
||||
align="center"
|
||||
label="手机号"
|
||||
width="100"
|
||||
sortable
|
||||
/>
|
||||
|
||||
<el-table-column prop="msgContent" label="发送内容" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 趋势图 -->
|
||||
<el-dialog :close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance, reactive, computed } from "vue";
|
||||
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useStore } from "vuex";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import { DArrowRight, Search,RefreshLeft } from "@element-plus/icons-vue";
|
||||
import { getDateRange } from "@/utils/index"; //引入封装好的
|
||||
const store = useStore();
|
||||
import {
|
||||
eventPage,
|
||||
eventMsgDetail,
|
||||
msgHandle,
|
||||
regionDevCount,
|
||||
} from "@/api/statistics/index";
|
||||
const emit = defineEmits(["handleCurrentChange"]);
|
||||
const dropList = ref([]);
|
||||
const waveFormRef = ref();
|
||||
const detailList: any = ref({});
|
||||
const dataRow: any = ref({});
|
||||
const trendVisible = ref(false);
|
||||
const form: any = ref({
|
||||
eventIndex: "", //id
|
||||
isSensitive: 1, //是否影响敏感用户不可为空
|
||||
influenceFactors: "", //原因
|
||||
dealDate: "", //处理时间
|
||||
dealScheme: "", //方案”
|
||||
remark: "", //备注
|
||||
});
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(20);
|
||||
const formRef = ref();
|
||||
const searchValue = ref("");
|
||||
|
||||
const feedbackVisible = ref(false); //反馈
|
||||
const dialogVisible = ref(false);
|
||||
const flag = ref(0);
|
||||
const total = ref(0);
|
||||
|
||||
const eventForm: any = reactive({
|
||||
eventValueMin: null,
|
||||
eventValueMax: null,
|
||||
eventDurationMin: null,
|
||||
eventDurationMax: null,
|
||||
eventtype: null,
|
||||
});
|
||||
const typeMap = {
|
||||
"0": "扰动",
|
||||
"1": "暂降",
|
||||
"2": "暂升",
|
||||
"3": "中断",
|
||||
"4": "其他",
|
||||
"5": "录波",
|
||||
};
|
||||
const eventTypeList = computed(() => {
|
||||
const availableTypes = store.state.eventTypeList.map((type) => String(type));
|
||||
// 过滤并生成选项(只包含availableTypes中的类型)
|
||||
return availableTypes
|
||||
.filter((type) => typeMap.hasOwnProperty(type)) // 确保类型在映射中存在
|
||||
.map((type) => ({
|
||||
value: type, // 选项值(字符串类型,与case匹配)
|
||||
label: typeMap[type], // 选项文本
|
||||
}));
|
||||
});
|
||||
|
||||
const deptsIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
// 反馈
|
||||
const feedback = (row: any) => {
|
||||
form.value = {
|
||||
eventIndex: row.eventdetail_index, //id
|
||||
isSensitive: 1, //是否影响敏感用户不可为空
|
||||
influenceFactors: "", //原因
|
||||
dealDate: getDateRange(6), //处理时间
|
||||
dealScheme: "", //方案”
|
||||
remark: "", //备注
|
||||
};
|
||||
feedbackVisible.value = true;
|
||||
};
|
||||
const loading = ref(false);
|
||||
// 提交反馈
|
||||
const onSubmit = () => {
|
||||
formRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
msgHandle(form.value).then((res) => {
|
||||
ElMessage({
|
||||
message: "反馈成功",
|
||||
type: "success",
|
||||
});
|
||||
init();
|
||||
feedbackVisible.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 详情
|
||||
const detail = (row: any) => {
|
||||
dataRow.value = row;
|
||||
eventMsgDetail({ eventId: row.eventdetail_index }).then((res) => {
|
||||
detailList.value = res.data;
|
||||
dialogVisible.value = true;
|
||||
});
|
||||
};
|
||||
//点击趋势图
|
||||
const trendCharts = (row: any) => {
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open(row);
|
||||
}, 500);
|
||||
};
|
||||
// 过滤数据
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
const handleCurrentChange = (val: any) => {
|
||||
emit("handleCurrentChange", val?.bdname);
|
||||
};
|
||||
const onTableSizeChange = (val: any) => {
|
||||
pageSize.value = val;
|
||||
init();
|
||||
};
|
||||
const onTableCurrentChange = (val: any) => {
|
||||
pageNum.value = val;
|
||||
init();
|
||||
};
|
||||
|
||||
|
||||
|
||||
const initDept = () => {
|
||||
regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
const clearInit = async () => {
|
||||
searchValue.value = "";
|
||||
eventForm.eventValueMin = null;
|
||||
eventForm.eventValueMax = null;
|
||||
eventForm.eventDurationMin = null;
|
||||
eventForm.eventDurationMax = null;
|
||||
eventForm.eventtype = null;
|
||||
deptsIndex.value = null;
|
||||
|
||||
await init(true);
|
||||
};
|
||||
|
||||
const init = async (flag?: boolean) => {
|
||||
if (flag) {
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
}
|
||||
loading.value = true;
|
||||
// 暂降事件列表
|
||||
await eventPage({
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
eventtype: null,
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
searchValue: searchValue.value,
|
||||
...eventForm,
|
||||
eventValueMin:
|
||||
eventForm.eventValueMin == null ? null : eventForm.eventValueMin / 100,
|
||||
eventValueMax:
|
||||
eventForm.eventValueMax == null ? null : eventForm.eventValueMax / 100,
|
||||
}).then((res) => {
|
||||
dropList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// renderChart();
|
||||
initDept();
|
||||
});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.form {
|
||||
.react-right {
|
||||
width: 50px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__content) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.titleBox1 {
|
||||
background-color: #0a73ff40;
|
||||
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-weight: 600;
|
||||
padding-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-left: 10px solid var(--el-color-primary);
|
||||
}
|
||||
|
||||
:deep(.el-button + .el-button) {
|
||||
margin-left: 2px !important;
|
||||
}
|
||||
:deep(.el-table__body tr.current-row > td.el-table__cell) {
|
||||
background-color: #456a91de !important;
|
||||
}
|
||||
.positioning {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
227
src/views/VoltageSag_BJ/components/map.vue
Normal file
227
src/views/VoltageSag_BJ/components/map.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<div v-loading="loading" element-loading-background="#343849c7">
|
||||
<MyEchartMap
|
||||
ref="EchartMap"
|
||||
style="width: 100%; height: 608px"
|
||||
:options="echartMapList"
|
||||
@clickMap="clickMap"
|
||||
></MyEchartMap>
|
||||
|
||||
<div class="legend">
|
||||
<div class="box">
|
||||
<!-- <div style="background-color: #0000ff"></div> -->
|
||||
<img src="@/assets/img/bdz.png" alt="" style="width: 18px" />
|
||||
<div>变电站</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 详情弹框 -->
|
||||
<tablePopUpMap ref="tablePopUpMapRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance } from "vue";
|
||||
import { substationCount } from "@/api/statistics/index";
|
||||
import tablePopUpMap from "@/views/VoltageSag_BJ/components/tablePopUpMap.vue";
|
||||
import "echarts-gl";
|
||||
import MyEchartMap from "@/components/MyEchartMap.vue";
|
||||
import { ElMessage, ElLoading } from "element-plus";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const EchartMap = ref();
|
||||
const dataList = ref([]);
|
||||
const loading = ref(false);
|
||||
const tablePopUpMapRef = ref();
|
||||
const echartMapList: any = ref({
|
||||
name: "",
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item", // 关键:3D 系列需设置为 'item'
|
||||
show: true, // 显式开启
|
||||
extraCssText: "z-index:9",
|
||||
// position: ['50%', '50%'],
|
||||
formatter: (params) => {
|
||||
if (!params.data) return "";
|
||||
const { name, value } = params.data;
|
||||
return `
|
||||
<div style=" border-radius: 4px;">
|
||||
<div style="font-weight: bold;">${name} </div>
|
||||
<div>监测点数量:${value[2]}个</div>
|
||||
<div>发生暂降次数:${value[3]}次</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
// 确保 3D 场景下不被遮挡
|
||||
zlevel: 100, // 提高层级,避免被地图或其他元素遮挡
|
||||
},
|
||||
|
||||
options: {
|
||||
series: [],
|
||||
},
|
||||
});
|
||||
const renderChart = () => {
|
||||
EchartMap.value.GetEchar("北京");
|
||||
|
||||
echartMapList.value.options.series = [
|
||||
{
|
||||
type: "scatter",
|
||||
mapName: "china",
|
||||
name: "变电站",
|
||||
coordinateSystem: "geo",
|
||||
symbol:
|
||||
"path://M96.86 877.95H159l69.55-398.25h-90.94v48.4h-28.23v-76.78l122.1-98.26V294.9h-93.79v48.4h-28.31v-76.7l122.1-98.42v-20.5c0-25.46 21.72-42.62 45.96-42.79l108.51-0.08c24.32 0 46.37 17.49 46.37 42.95v20.75l122.25 98.34v76.46h-28.39v-48.4h-93.87v58.32l122.25 98.26v49.37h-28.39v-21.23h-90.94l3.74 21.23H363.4l21.23-21.23H279.06l52.71 52.46 16.43-16.18-8.13 49.29-8.22-8.13-73.61 73.12 73.61 86.87 23.35-27.49h6.18v19.93l-17.89 21.15 17.89 21.15v27.33l-29.53-34.81-113.14 133.63h160.73v-187H875.7v187h50.84v40.75H96.78l0.08-40.75z m152.92-230.43l-36.52 209.62L320.3 730.65l-70.52-83.13z m25.71-146.5l-18.46 105.5 62.3-61.9-43.84-43.6z m5.93-73.05l40.02-56.61-40.02-56.61v113.22z m50.84-71.9l43.19-61.17h-86.46l43.27 61.17z m50.03-40.26L343 371.36l39.29 55.56V315.81z m-50.03 70.84l-45.64 64.67h91.35l-45.71-64.67z m-50.84-139.82l38.31-38.31-38.31-38.23v76.54z m50.84-50.84l41.32-41.32-82.64-0.08 41.32 41.4z m50.03-24.89l-37.5 37.5 37.5 37.5v-75z m-50.03 50.02l-45.47 45.47h90.86l-45.39-45.47z m100.05 166.1v64.18h79.63l-79.63-64.18z m-280.79 64.1h79.96v-64.26l-79.96 64.26z m280.79-248.83v64.02h79.63l-79.63-64.02zM151.6 266.51h79.88v-64.26l-79.88 64.26z m737.44 252.48h-98.42v-42.05h4.56v-21.88h-69.47v21.88h4.48v66.05h-10.66v-24H366.1l-20.5 125.35v27.09h563.94v-27.09l-20.5-125.35zM466.39 877.95h82.15v-148.2h-82.15v148.2z m283.15-148.2h-82.07v97.36h82.07v-97.36z m0 0", // 替换为实际图标路径
|
||||
|
||||
data: dataList.value.map((item) => {
|
||||
return {
|
||||
name: item.stationName,
|
||||
value: [
|
||||
item.longitude,
|
||||
item.latitude,
|
||||
item.lineCount,
|
||||
item.eventCount,
|
||||
],
|
||||
itemStyle: { color: "#00FF00 " },
|
||||
symbolSize: 15, //大小15px
|
||||
};
|
||||
}),
|
||||
// [
|
||||
// {
|
||||
// name: "点1",
|
||||
// value: ["116.345678", "39.876543", 0],
|
||||
// itemStyle: { color: "#00FF00 " },
|
||||
// symbolSize: 15, // 大小15px
|
||||
// },
|
||||
|
||||
// ],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
loading.value = true;
|
||||
|
||||
substationCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
dataList.value = res.data;
|
||||
|
||||
renderChart();
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const clickMap = (e: any) => {
|
||||
// console.log("🚀 ~ clickMap ~ e:", e);
|
||||
// console.log("🚀 ~ clickMap ~ e:", dataList.value);
|
||||
let list: any = dataList.value.filter((item: any) =>
|
||||
item.deptsName.includes(e == "西城" ? "城区" : e == "东城" ? "城区" : e)
|
||||
);
|
||||
console.log("🚀 ~ clickMap ~ list:", list);
|
||||
|
||||
if (list.length == 0) {
|
||||
ElMessage({
|
||||
message: "暂无数据",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: list[0].deptsName + "_详情",
|
||||
// eventList: list[0].eventList,
|
||||
// lineList: list[0].lineList,
|
||||
// noticeList: list[0].noticeList,
|
||||
// });
|
||||
// if (e.seriesName == "监测点数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_监测点",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// { prop: "stationName", label: "变电站" },
|
||||
// { prop: "devName", label: "终端名称" },
|
||||
// { prop: "busBarName", label: "母线名称" },
|
||||
// { prop: "lineName", label: "监测点名称" },
|
||||
// ],
|
||||
// });
|
||||
// } else if (e.seriesName == "暂降次数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_暂降",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// {
|
||||
// prop: "timeid",
|
||||
// label: "发生时间",
|
||||
// width: 180,
|
||||
// },
|
||||
// { prop: "bdname", label: "变电站" },
|
||||
// { prop: "pointname", label: "监测点" },
|
||||
// {
|
||||
// prop: "eventvalue",
|
||||
// label: "残余电压",
|
||||
// width: 100,
|
||||
// },
|
||||
// {
|
||||
// prop: "persisttime",
|
||||
// label: "持续时间",
|
||||
// width: 100,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// } else if (e.seriesName == "远程通知数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_远程通知",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// {
|
||||
// prop: "sendTime",
|
||||
// label: "发送时间",
|
||||
// width: 180,
|
||||
// },
|
||||
// { prop: "userName", label: "接受人", width: 100 },
|
||||
// { prop: "phone", label: "手机号", width: 100 },
|
||||
// { prop: "msgContent", label: "发送内容", align: "left" },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
};
|
||||
// 变电站变色
|
||||
const setIcon = (name: string) => {
|
||||
EchartMap.value.setIcon(name);
|
||||
};
|
||||
onMounted(() => {});
|
||||
defineExpose({
|
||||
init,
|
||||
setIcon,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.legend {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
bottom: 0px;
|
||||
width: 90px;
|
||||
height: 35px;
|
||||
font-size: 12px;
|
||||
.box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
div {
|
||||
&:nth-child(1) {
|
||||
width: 20px;
|
||||
height: 12px;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
786
src/views/VoltageSag_BJ/components/mapcopy.vue
Normal file
786
src/views/VoltageSag_BJ/components/mapcopy.vue
Normal file
@@ -0,0 +1,786 @@
|
||||
<template>
|
||||
<div v-loading="loading" element-loading-background="#343849c7">
|
||||
<echartMap
|
||||
ref="EchartMap"
|
||||
style="width: 100%; height: 608px"
|
||||
:options="echartMapList"
|
||||
@clickMap="clickMap"
|
||||
></echartMap>
|
||||
|
||||
<div class="legend">
|
||||
<div class="box" @click="EchartMap.setIcon('点23')">
|
||||
<!-- <div style="background-color: #0000ff"></div> -->
|
||||
<img src="@/assets/img/bdz1.png" alt="" style="width: 20px" />
|
||||
<div>变电站</div>
|
||||
</div>
|
||||
<div class="box" @click="EchartMap.setIcon('点13')">
|
||||
<div style="background-color: #ffa500"></div>
|
||||
<div>暂降次数</div>
|
||||
</div>
|
||||
<!-- <div class="box">
|
||||
<div style="background-color: #800080"></div>
|
||||
<div>远程通知数</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- 详情弹框 -->
|
||||
<tablePopUpMap ref="tablePopUpMapRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, getCurrentInstance } from "vue";
|
||||
import { mapCount } from "@/api/statistics/index";
|
||||
import tablePopUpMap from "@/views/VoltageSag_BJ/components/tablePopUpMap.vue";
|
||||
import { assignColorsByRank } from "@/utils/color";
|
||||
|
||||
import "echarts-gl";
|
||||
import echartMap from "@/components/echartMap3D.vue";
|
||||
import { ElMessage, ElLoading } from "element-plus";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const EchartMap = ref();
|
||||
const dataList = ref([]);
|
||||
const loading = ref(false);
|
||||
const tablePopUpMapRef = ref();
|
||||
const echartMapList: any = ref({
|
||||
name: "",
|
||||
title: {
|
||||
text: "",
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
trigger: "item", // 关键:3D 系列需设置为 'item'
|
||||
show: true, // 显式开启
|
||||
|
||||
// position: ['50%', '50%'],
|
||||
formatter: (params) => {
|
||||
if (!params.data || params.seriesType != "scatter3D") return "";
|
||||
const { name, value } = params.data;
|
||||
return `
|
||||
<div style=" border-radius: 4px;">
|
||||
<div style="font-weight: bold;">变电站1 ${name}</div>
|
||||
<div>监测点数量:10个</div>
|
||||
<div>发生暂降次数:10次</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
// 确保 3D 场景下不被遮挡
|
||||
zlevel: 100, // 提高层级,避免被地图或其他元素遮挡
|
||||
},
|
||||
|
||||
options: {
|
||||
series: [],
|
||||
},
|
||||
});
|
||||
const renderChart = () => {
|
||||
EchartMap.value.GetEchar("北京");
|
||||
const specialDepts = [
|
||||
"城区供电公司",
|
||||
"石景山区供电公司",
|
||||
"海淀区供电公司",
|
||||
"丰台区供电公司",
|
||||
];
|
||||
echartMapList.value.options.series = [
|
||||
{
|
||||
type: "map3D",
|
||||
map: "北京",
|
||||
viewControl: {
|
||||
autoRotate: false, // 关闭自动旋转
|
||||
center: [0, -10, 0], //位置
|
||||
beta: 45, //x轴旋转
|
||||
alpha: 50, //Y轴旋转
|
||||
},
|
||||
regionHeight: 2,
|
||||
light: {
|
||||
main: {
|
||||
color: "#ffffff",
|
||||
intensity: 1,
|
||||
shadow: false,
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#4D96FA",
|
||||
borderWidth: 1,
|
||||
borderColor: "#fff",
|
||||
opcity: 1,
|
||||
},
|
||||
|
||||
shading: "realistic", //简化着色模式('color' 比 'realistic' 性能更好)
|
||||
label: {
|
||||
show: true,
|
||||
position: "bottom",
|
||||
distance: 0, // 紧贴地面
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
},
|
||||
|
||||
postEffect: {
|
||||
enable: false, // 关闭后期特效(抗锯齿、 Bloom 等)
|
||||
},
|
||||
// 减少顶点计算
|
||||
polygonOffset: {
|
||||
factor: 1,
|
||||
units: 1,
|
||||
},
|
||||
// 启用 GPU 加速渲染
|
||||
renderOption: {
|
||||
useGPU: true, // 启用 GPU 渲染
|
||||
maxCache: 1000, // 缓存顶点数据
|
||||
vertexLimit: 50000, // 限制顶点数量
|
||||
},
|
||||
// 优化材质计算
|
||||
material: {
|
||||
color: "#4D96FA",
|
||||
opacity: 0.8,
|
||||
roughness: 0.2, // 粗糙度(数值越低性能越好)
|
||||
metalness: 0, // 金属度
|
||||
},
|
||||
|
||||
groundPlane: true,
|
||||
// ...地图配置
|
||||
},
|
||||
{
|
||||
name: "监测点",
|
||||
type: "scatter3D",
|
||||
coordinateSystem: "geo3D",
|
||||
|
||||
// 使用SVG路径作为自定义图标(示例为一个简单的标记图标)
|
||||
// symbolSize: 15, // 图标大小
|
||||
symbol:
|
||||
"path://M96.86 877.95H159l69.55-398.25h-90.94v48.4h-28.23v-76.78l122.1-98.26V294.9h-93.79v48.4h-28.31v-76.7l122.1-98.42v-20.5c0-25.46 21.72-42.62 45.96-42.79l108.51-0.08c24.32 0 46.37 17.49 46.37 42.95v20.75l122.25 98.34v76.46h-28.39v-48.4h-93.87v58.32l122.25 98.26v49.37h-28.39v-21.23h-90.94l3.74 21.23H363.4l21.23-21.23H279.06l52.71 52.46 16.43-16.18-8.13 49.29-8.22-8.13-73.61 73.12 73.61 86.87 23.35-27.49h6.18v19.93l-17.89 21.15 17.89 21.15v27.33l-29.53-34.81-113.14 133.63h160.73v-187H875.7v187h50.84v40.75H96.78l0.08-40.75z m152.92-230.43l-36.52 209.62L320.3 730.65l-70.52-83.13z m25.71-146.5l-18.46 105.5 62.3-61.9-43.84-43.6z m5.93-73.05l40.02-56.61-40.02-56.61v113.22z m50.84-71.9l43.19-61.17h-86.46l43.27 61.17z m50.03-40.26L343 371.36l39.29 55.56V315.81z m-50.03 70.84l-45.64 64.67h91.35l-45.71-64.67z m-50.84-139.82l38.31-38.31-38.31-38.23v76.54z m50.84-50.84l41.32-41.32-82.64-0.08 41.32 41.4z m50.03-24.89l-37.5 37.5 37.5 37.5v-75z m-50.03 50.02l-45.47 45.47h90.86l-45.39-45.47z m100.05 166.1v64.18h79.63l-79.63-64.18z m-280.79 64.1h79.96v-64.26l-79.96 64.26z m280.79-248.83v64.02h79.63l-79.63-64.02zM151.6 266.51h79.88v-64.26l-79.88 64.26z m737.44 252.48h-98.42v-42.05h4.56v-21.88h-69.47v21.88h4.48v66.05h-10.66v-24H366.1l-20.5 125.35v27.09h563.94v-27.09l-20.5-125.35zM466.39 877.95h82.15v-148.2h-82.15v148.2z m283.15-148.2h-82.07v97.36h82.07v-97.36z m0 0", // 替换为实际图标路径
|
||||
label: { show: false },
|
||||
emphasis: {
|
||||
label: { show: false },
|
||||
},
|
||||
|
||||
data: [
|
||||
{
|
||||
name: "点1",
|
||||
value: ["116.345678", "39.876543", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点2",
|
||||
value: ["116.456789", "39.987654", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点3",
|
||||
value: ["116.567890", "40.098765", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点6",
|
||||
value: ["116.123456", "39.654321", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点7",
|
||||
value: ["116.678901", "40.234567", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点9",
|
||||
value: ["116.345670", "40.345678", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
|
||||
{
|
||||
name: "点13",
|
||||
value: ["116.456788", "40.567890", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点15",
|
||||
value: ["116.123457", "40.678901", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点17",
|
||||
value: ["116.345671", "40.789012", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点21",
|
||||
value: ["116.456787", "40.012345", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点22",
|
||||
value: ["116.678903", "39.876543", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点23",
|
||||
value: ["116.123458", "40.123456", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点24",
|
||||
value: ["116.890125", "39.765432", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点25",
|
||||
value: ["116.345672", "40.234567", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点26",
|
||||
value: ["116.567894", "39.654321", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点29",
|
||||
value: ["116.456786", "40.456789", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点31",
|
||||
value: ["116.123459", "40.567890", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点33",
|
||||
value: ["116.345673", "40.678901", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点34",
|
||||
value: ["116.567895", "39.210987", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点37",
|
||||
value: ["116.456785", "40.890123", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点39",
|
||||
value: ["116.123451", "39.987654", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点41",
|
||||
value: ["116.345674", "39.876543", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点45",
|
||||
value: ["116.456784", "39.654321", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点46",
|
||||
value: ["116.678906", "40.345678", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点48",
|
||||
value: ["116.890128", "40.456789", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点50",
|
||||
value: ["116.567897", "40.567890", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点53",
|
||||
value: ["116.456783", "39.210987", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点58",
|
||||
value: ["116.567898", "39.987654", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点62",
|
||||
value: ["116.678908", "39.765432", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点63",
|
||||
value: ["116.123454", "40.234567", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点65",
|
||||
value: ["116.345677", "40.345678", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点71",
|
||||
value: ["116.123455", "40.678901", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点72",
|
||||
value: ["116.890131", "39.210987", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点73",
|
||||
value: ["116.345680", "40.789012", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点77",
|
||||
value: ["116.456790", "39.987654", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点78",
|
||||
value: ["116.678920", "40.012345", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点79",
|
||||
value: ["116.123460", "39.876543", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点80",
|
||||
value: ["116.890140", "40.123456", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点81",
|
||||
value: ["116.345685", "39.765432", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点82",
|
||||
value: ["116.567910", "40.234567", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点85",
|
||||
value: ["116.456795", "39.543210", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点86",
|
||||
value: ["116.678930", "40.456789", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
|
||||
{
|
||||
name: "点88",
|
||||
value: ["116.890150", "40.567890", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点90",
|
||||
value: ["116.567920", "40.678901", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点94",
|
||||
value: ["116.678940", "40.890123", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点97",
|
||||
value: ["116.345695", "40.012345", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
{
|
||||
name: "点98",
|
||||
value: ["116.567930", "39.876543", 0],
|
||||
itemStyle: { color: "#0000ff" },
|
||||
symbolSize: 15, // 大小15px
|
||||
},
|
||||
],
|
||||
// data: dataList.value
|
||||
// .filter((item: any) => {
|
||||
// if (item.lan) {
|
||||
// return item;
|
||||
// }
|
||||
// })
|
||||
// .map((item: any) => {
|
||||
// return {
|
||||
// name: item.deptsName,
|
||||
// value: [item.lan, item.lat, 0, item.lineCount],
|
||||
// list: item.lineList,
|
||||
// };
|
||||
// }),
|
||||
|
||||
// [
|
||||
// {
|
||||
// name: "大兴",
|
||||
// value: ["116.386537", "39.607924", 50],
|
||||
// },
|
||||
// {
|
||||
// name: "通州",
|
||||
// value: ["116.705424", "39.757376", 50],
|
||||
// },
|
||||
// ],
|
||||
// shading: "lambert",
|
||||
// label: {
|
||||
// show: false,
|
||||
// position: "top",
|
||||
// distance: 0.2, // 距离柱子顶部的距离
|
||||
// textStyle: {
|
||||
// fontSize: 14, // 设置字体大小为14px
|
||||
// // fontWeight: "bold", // 设置字体加粗
|
||||
// },
|
||||
// formatter: (params: any) => {
|
||||
// return params.value[2];
|
||||
// },
|
||||
// },
|
||||
|
||||
// emphasis: {
|
||||
// label: { show: true },
|
||||
// },
|
||||
},
|
||||
// {
|
||||
// name: "暂降次数",
|
||||
// type: "bar3D",
|
||||
// silent: true, // 默认显示
|
||||
// coordinateSystem: "geo3D",
|
||||
// zlevel: 1,
|
||||
// data: dataList.value
|
||||
// .filter((item: any) => {
|
||||
// if (item.lan) {
|
||||
// return item;
|
||||
// }
|
||||
// })
|
||||
// .map((item: any) => {
|
||||
// let num = specialDepts.includes(item.deptsName) ? 0.03 : 0.04;
|
||||
// return {
|
||||
// name: item.deptsName,
|
||||
// value: [item.lan + num, item.lat + num, item.eventCount],
|
||||
// list: item.eventList,
|
||||
// };
|
||||
// }),
|
||||
|
||||
// shading: "lambert",
|
||||
// label: {
|
||||
// show: true,
|
||||
// position: "top",
|
||||
// distance: 0.2, // 距离柱子顶部的距离
|
||||
|
||||
// textStyle: {
|
||||
// fontSize: 14, // 设置字体大小为14px
|
||||
// // fontWeight: "bold", // 设置字体加粗
|
||||
// },
|
||||
// formatter: (params: any) => {
|
||||
// return params.value[2];
|
||||
// },
|
||||
// },
|
||||
|
||||
// barSize: 0.8,
|
||||
// minHeight: 0.01,
|
||||
// itemStyle: {
|
||||
// color: "#FFA500",
|
||||
// },
|
||||
// emphasis: {
|
||||
// label: { show: true },
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: "远程通知数",
|
||||
// type: "bar3D",
|
||||
// silent: true, // 默认显示
|
||||
// coordinateSystem: "geo3D",
|
||||
|
||||
// data: dataList.value
|
||||
// .filter((item: any) => {
|
||||
// if (item.lan) {
|
||||
// return item;
|
||||
// }
|
||||
// })
|
||||
// .map((item: any) => {
|
||||
// let num = specialDepts.includes(item.deptsName) ? 0.04 : 0.06;
|
||||
// return {
|
||||
// name: item.deptsName,
|
||||
// value: [item.lan + num, item.lat + num, item.noticeCount],
|
||||
// list: item.noticeList,
|
||||
// };
|
||||
// }),
|
||||
|
||||
// shading: "lambert",
|
||||
// label: {
|
||||
// show: true,
|
||||
// position: "top",
|
||||
// distance: 0.2, // 距离柱子顶部的距离
|
||||
|
||||
// textStyle: {
|
||||
// fontSize: 14, // 设置字体大小为14px
|
||||
// fontWeight: 700, // 设置字体加粗
|
||||
// },
|
||||
// formatter: (params: any) => {
|
||||
// return params.value[2];
|
||||
// },
|
||||
// },
|
||||
|
||||
// barSize: 0.8,
|
||||
// minHeight: 0.01,
|
||||
// itemStyle: {
|
||||
// color: "#800080",
|
||||
// },
|
||||
// emphasis: {
|
||||
// label: { show: true },
|
||||
// },
|
||||
// },
|
||||
];
|
||||
};
|
||||
const init = () => {
|
||||
loading.value = true;
|
||||
// echartMapList.value.geo3Ds = {
|
||||
// regions: [
|
||||
// {
|
||||
// name: "平谷",
|
||||
// itemStyle: {
|
||||
// color: assignColorsByRank(800),
|
||||
// opacity: 1,
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
let regionsList = [];
|
||||
mapCount({ deptId: store.state.deptId, type: store.state.timeType }).then(
|
||||
(res: any) => {
|
||||
res.data.forEach((item: any) => {
|
||||
if (item.deptsName == "城区供电公司") {
|
||||
regionsList.push({
|
||||
name: "东城",
|
||||
value: item.eventList.length,
|
||||
});
|
||||
regionsList.push({
|
||||
name: "西城",
|
||||
value: item.eventList.length,
|
||||
});
|
||||
} else {
|
||||
regionsList.push({
|
||||
name: item.deptsName.replace("区供电公司", ""),
|
||||
value: item.eventList.length,
|
||||
});
|
||||
}
|
||||
|
||||
switch (item.deptsName) {
|
||||
case "大兴区供电公司":
|
||||
item.lan = 116.386537;
|
||||
item.lat = 39.607924;
|
||||
break;
|
||||
case "通州区供电公司":
|
||||
item.lan = 116.705424;
|
||||
item.lat = 39.757376;
|
||||
break;
|
||||
case "房山区供电公司":
|
||||
item.lan = 115.771153;
|
||||
item.lat = 39.703052;
|
||||
break;
|
||||
case "门头沟区供电公司":
|
||||
item.lan = 115.777329;
|
||||
item.lat = 39.990483;
|
||||
break;
|
||||
case "昌平区供电公司":
|
||||
item.lan = 116.171615;
|
||||
item.lat = 40.223036;
|
||||
break;
|
||||
case "延庆区供电公司":
|
||||
item.lan = 116.099058;
|
||||
item.lat = 40.533533;
|
||||
break;
|
||||
case "怀柔区供电公司":
|
||||
item.lan = 116.511466;
|
||||
item.lat = 40.370998;
|
||||
break;
|
||||
case "密云区供电公司":
|
||||
item.lan = 116.893304;
|
||||
item.lat = 40.465165;
|
||||
break;
|
||||
case "平谷区供电公司":
|
||||
item.lan = 117.094677;
|
||||
item.lat = 40.226792;
|
||||
break;
|
||||
case "顺义区供电公司":
|
||||
item.lan = 116.710987;
|
||||
item.lat = 40.15707;
|
||||
break;
|
||||
case "朝阳区供电公司":
|
||||
item.lan = 116.550205;
|
||||
item.lat = 39.873331;
|
||||
break;
|
||||
case "丰台区供电公司":
|
||||
item.lan = 116.279454;
|
||||
item.lat = 39.824133;
|
||||
break;
|
||||
case "石景山区供电公司":
|
||||
item.lan = 116.140426;
|
||||
item.lat = 39.934654;
|
||||
break;
|
||||
case "海淀区供电公司":
|
||||
item.lan = 116.238135;
|
||||
item.lat = 39.970893;
|
||||
break;
|
||||
case "城区供电公司":
|
||||
item.lan = 116.363685;
|
||||
item.lat = 39.898051;
|
||||
break;
|
||||
}
|
||||
});
|
||||
console.log("🚀 ~ init ~ regionsList:", assignColorsByRank(regionsList));
|
||||
|
||||
echartMapList.value.geo3Ds = {
|
||||
regions: [...assignColorsByRank(regionsList)],
|
||||
};
|
||||
dataList.value = res.data;
|
||||
|
||||
renderChart();
|
||||
loading.value = false;
|
||||
}
|
||||
);
|
||||
};
|
||||
const clickMap = (e: any) => {
|
||||
// console.log("🚀 ~ clickMap ~ e:", e);
|
||||
// console.log("🚀 ~ clickMap ~ e:", dataList.value);
|
||||
let list: any = dataList.value.filter((item: any) =>
|
||||
item.deptsName.includes(e == "西城" ? "城区" : e == "东城" ? "城区" : e)
|
||||
);
|
||||
console.log("🚀 ~ clickMap ~ list:", list);
|
||||
|
||||
if (list.length == 0) {
|
||||
ElMessage({
|
||||
message: "暂无数据",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: list[0].deptsName + "_详情",
|
||||
// eventList: list[0].eventList,
|
||||
// lineList: list[0].lineList,
|
||||
// noticeList: list[0].noticeList,
|
||||
// });
|
||||
// if (e.seriesName == "监测点数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_监测点",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// { prop: "stationName", label: "变电站" },
|
||||
// { prop: "devName", label: "终端名称" },
|
||||
// { prop: "busBarName", label: "母线名称" },
|
||||
// { prop: "lineName", label: "监测点名称" },
|
||||
// ],
|
||||
// });
|
||||
// } else if (e.seriesName == "暂降次数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_暂降",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// {
|
||||
// prop: "timeid",
|
||||
// label: "发生时间",
|
||||
// width: 180,
|
||||
// },
|
||||
// { prop: "bdname", label: "变电站" },
|
||||
// { prop: "pointname", label: "监测点" },
|
||||
// {
|
||||
// prop: "eventvalue",
|
||||
// label: "残余电压",
|
||||
// width: 100,
|
||||
// },
|
||||
// {
|
||||
// prop: "persisttime",
|
||||
// label: "持续时间",
|
||||
// width: 100,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// } else if (e.seriesName == "远程通知数") {
|
||||
// tablePopUpMapRef.value.open({
|
||||
// title: e.name + "_远程通知",
|
||||
// data: e.data.list,
|
||||
// columns: [
|
||||
// {
|
||||
// prop: "sendTime",
|
||||
// label: "发送时间",
|
||||
// width: 180,
|
||||
// },
|
||||
// { prop: "userName", label: "接受人", width: 100 },
|
||||
// { prop: "phone", label: "手机号", width: 100 },
|
||||
// { prop: "msgContent", label: "发送内容", align: "left" },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
};
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.legend {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
bottom: 0px;
|
||||
width: 90px;
|
||||
height: 50px;
|
||||
font-size: 12px;
|
||||
.box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
div {
|
||||
&:nth-child(1) {
|
||||
width: 20px;
|
||||
height: 12px;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
480
src/views/VoltageSag_BJ/components/popUpFrame/alarmPopUpBox.vue
Normal file
480
src/views/VoltageSag_BJ/components/popUpFrame/alarmPopUpBox.vue
Normal file
@@ -0,0 +1,480 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="85%"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级电站">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="bdIndex"
|
||||
placeholder="请选择上级电站"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bdList"
|
||||
:label="item.name"
|
||||
:value="item.subIndex"
|
||||
:key="item.subIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象大类">
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="bigObjType"
|
||||
clearable
|
||||
placeholder="请选择对象大类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bigObjTypeList.filter((item) => item.level == 2)"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象小类">
|
||||
<el-select
|
||||
size="small"
|
||||
clearable
|
||||
v-model="smallObjType"
|
||||
placeholder="请选择对象小类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in smallObjTypeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button :icon="RefreshLeft" @click="reset" size="small"
|
||||
>重置
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="timeid"
|
||||
label="发生时间"
|
||||
align="center"
|
||||
width="190"
|
||||
show-overflow-tooltip
|
||||
sortable
|
||||
>
|
||||
<template #default="scope"
|
||||
>{{ scope.row.timeid }}.{{ scope.row.ms }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="gdName"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="bdname"
|
||||
label="变电站"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="busName"
|
||||
label="监测母线"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="pointname"
|
||||
label="监测点"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
label="用户"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="wavetype"
|
||||
label="触发类型"
|
||||
align="center"
|
||||
width="90"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ filteWavetype(row.wavetype) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="eventvalue"
|
||||
label="残余电压"
|
||||
align="center"
|
||||
sortable
|
||||
width="100"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ Math.floor(row.eventvalue * 10000) / 100 }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="persisttime"
|
||||
label="持续时间"
|
||||
align="center"
|
||||
sortable
|
||||
width="100"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ Math.floor(row.persisttime * 1000) / 1000 }}s
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="操作"
|
||||
align="center"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="trendCharts(scope.row)"
|
||||
>
|
||||
波形
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 趋势图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close="dialogVisible = true"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import {
|
||||
rightEventOpenClone,
|
||||
getDicTree,
|
||||
regionDevCount,
|
||||
gdSelect,
|
||||
bdSelect,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search,RefreshLeft } from "@element-plus/icons-vue";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const waveFormRef = ref();
|
||||
const trendVisible = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("暂降事件_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const columns: any = ref([]);
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const bigObjType = ref("");
|
||||
const smallObjType = ref("");
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const bdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
const bdList = ref([]);
|
||||
|
||||
const bigObjTypeList = ref([]);
|
||||
|
||||
const open = async (bigObj: string = "", smallObj: string = "") => {
|
||||
reset()
|
||||
dialogVisible.value = true;
|
||||
loading.value = true;
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
|
||||
await bdSelect().then((res: any) => {
|
||||
bdList.value = res.data;
|
||||
});
|
||||
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
bigObjType.value = bigObj; // 清空搜索框
|
||||
|
||||
|
||||
|
||||
setTimeout(async () => {
|
||||
smallObjType.value = smallObj;
|
||||
await init();
|
||||
}, 100);
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
await rightEventOpenClone({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
bdId: bdIndex.value,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
const smallObjTypeList: any = computed(() => {
|
||||
smallObjType.value = "";
|
||||
return bigObjTypeList.value.filter((item: any) => {
|
||||
return item.parentId == bigObjType.value && item.level == 3;
|
||||
});
|
||||
});
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"发生时间",
|
||||
"供电区域",
|
||||
"变电站",
|
||||
"监测母线",
|
||||
"监测点",
|
||||
"用户",
|
||||
"触发类型",
|
||||
"残余电压",
|
||||
"持续时间",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await rightEventOpenClone({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.timeid + "." + item.ms,
|
||||
item.gdName,
|
||||
item.bdname,
|
||||
item.busName,
|
||||
item.pointname,
|
||||
item.objName,
|
||||
filteWavetype(item.wavetype),
|
||||
Math.floor(item.eventvalue * 10000) / 100 + "%",
|
||||
Math.floor(item.persisttime * 1000) / 1000 + "s",
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
//点击趋势图
|
||||
const trendCharts = (row: any) => {
|
||||
dialogVisible.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open(row);
|
||||
}, 500);
|
||||
};
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchValue.value = "";
|
||||
deptsIndex.value = "";
|
||||
gdIndex.value = "";
|
||||
bdIndex.value = "";
|
||||
bigObjType.value = "";
|
||||
smallObjType.value = "";
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
482
src/views/VoltageSag_BJ/components/popUpFrame/frequencyPopUp.vue
Normal file
482
src/views/VoltageSag_BJ/components/popUpFrame/frequencyPopUp.vue
Normal file
@@ -0,0 +1,482 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="70%"
|
||||
@close="close"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<!-- <el-form-item label="用户信息">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 140px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="请输入用户名称"
|
||||
></el-input>
|
||||
</el-form-item>-->
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级电站">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="bdIndex"
|
||||
placeholder="请选择上级电站"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bdList"
|
||||
:label="item.name"
|
||||
:value="item.subIndex"
|
||||
:key="item.subIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="对象大类">
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="bigObjType"
|
||||
clearable
|
||||
placeholder="请选择对象大类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bigObjTypeList.filter((item) => item.level == 2)"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象小类">
|
||||
<el-select
|
||||
size="small"
|
||||
clearable
|
||||
v-model="smallObjType"
|
||||
placeholder="请选择对象小类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in smallObjTypeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>-->
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="timeid"
|
||||
label="暂降发生时间"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
sortable
|
||||
>
|
||||
<template #default="scope"
|
||||
>{{ scope.row.timeid }}.{{ scope.row.ms }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="wavetype"
|
||||
label="暂降类型"
|
||||
align="center"
|
||||
width="70"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ filteWavetype(row.wavetype) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="eventvalue"
|
||||
label="残余电压"
|
||||
align="center"
|
||||
sortable
|
||||
width="90"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ Math.floor(row.eventvalue * 10000) / 100 }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="persisttime"
|
||||
label="持续时间"
|
||||
align="center"
|
||||
sortable
|
||||
width="100"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ Math.floor(row.persisttime * 1000) / 1000 }}s
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="gdName"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="160"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="bdname"
|
||||
label="变电站"
|
||||
align="center"
|
||||
width="160"
|
||||
/>
|
||||
|
||||
|
||||
<el-table-column
|
||||
prop="busName"
|
||||
label="监测母线"
|
||||
align="center"
|
||||
|
||||
/>
|
||||
<el-table-column
|
||||
prop="pointname"
|
||||
label="监测点"
|
||||
align="center"
|
||||
width="160"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="操作"
|
||||
align="center"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="trendCharts(scope.row)"
|
||||
>
|
||||
波形
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 趋势图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close="closeBox"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import {
|
||||
rightEventOpen,
|
||||
getDicTree,
|
||||
rightEventOpenForDetail,
|
||||
gdSelect,
|
||||
bdSelect,
|
||||
regionDevCount,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search } from "@element-plus/icons-vue";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
const emit = defineEmits(["closeDialog"]);
|
||||
const store = useStore();
|
||||
const waveFormRef = ref();
|
||||
const trendVisible = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("暂降事件_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const columns: any = ref([]);
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const bigObjType = ref("");
|
||||
const smallObjType = ref("");
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const bdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
const bdList = ref([]);
|
||||
const eventIds = ref([]);
|
||||
const flag = ref(true);
|
||||
const bigObjTypeList = ref([]);
|
||||
|
||||
const open = async (ids: any) => {
|
||||
eventIds.value = ids;
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
|
||||
await bdSelect().then((res: any) => {
|
||||
bdList.value = res.data;
|
||||
});
|
||||
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
searchValue.value = ""; // 清空搜索框
|
||||
dialogVisible.value = true;
|
||||
deptsIndex.value = ""; // 清空搜索框
|
||||
gdIndex.value = "";
|
||||
bdIndex.value = "";
|
||||
setTimeout(async () => {
|
||||
await init();
|
||||
}, 100);
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
|
||||
await rightEventOpenForDetail({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
bdId: bdIndex.value,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
|
||||
eventIds: eventIds.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
const smallObjTypeList: any = computed(() => {
|
||||
smallObjType.value = "";
|
||||
return bigObjTypeList.value.filter((item: any) => {
|
||||
return item.parentId == bigObjType.value && item.level == 3;
|
||||
});
|
||||
});
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"用户",
|
||||
"暂降类型",
|
||||
"发生时间",
|
||||
"残余电压",
|
||||
"持续时间",
|
||||
"供电区域",
|
||||
"变电站",
|
||||
"监测点",
|
||||
"监测母线",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await rightEventOpenForDetail({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.objName,
|
||||
filteWavetype(item.wavetype),
|
||||
item.timeid + "." + item.ms,
|
||||
Math.floor(item.eventvalue * 10000) / 100 + "%",
|
||||
item.persisttime + "s",
|
||||
item.gdName,
|
||||
item.bdname,
|
||||
item.pointname,
|
||||
item.busName,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
//点击趋势图
|
||||
const trendCharts = (row: any) => {
|
||||
dialogVisible.value = false;
|
||||
flag.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open(row);
|
||||
}, 500);
|
||||
};
|
||||
const close = () => {
|
||||
if (flag.value) emit("closeDialog");
|
||||
};
|
||||
const closeBox = () => {
|
||||
dialogVisible.value = true;
|
||||
setTimeout(() => {
|
||||
flag.value = true;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
397
src/views/VoltageSag_BJ/components/popUpFrame/sendPopUpBox.vue
Normal file
397
src/views/VoltageSag_BJ/components/popUpFrame/sendPopUpBox.vue
Normal file
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="85%"
|
||||
>
|
||||
<el-descriptions class="margin-top" :column="3" border label-width="90px">
|
||||
<el-descriptions-item label="用户">
|
||||
{{ obj.customerName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="对象类型" >
|
||||
{{ obj.smallObjType }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="供电区域" >
|
||||
{{ obj.gdName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="上级电站" :span="3">
|
||||
|
||||
<template v-if="obj.substationName">
|
||||
<el-tag
|
||||
v-for="(item, index) in obj.substationName.split(';')"
|
||||
:key="index"
|
||||
style="margin-right: 5px;"
|
||||
>
|
||||
{{ item }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="上级母线" :span="3">
|
||||
<template v-if="obj.busbarName">
|
||||
<el-tag type="success"
|
||||
v-for="(item, index) in obj.busbarName.split(';')"
|
||||
:key="index"
|
||||
style="margin:5px"
|
||||
>
|
||||
{{ item }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
|
||||
<div class="formFlex">
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="timeid"
|
||||
align="center"
|
||||
label="发生时间"
|
||||
width="190"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope"
|
||||
>{{ scope.row.timeid }}.{{ scope.row.ms }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="gdName"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="bdname"
|
||||
align="center"
|
||||
label="变电站"
|
||||
show-overflow-tooltip
|
||||
sortable
|
||||
width="170"
|
||||
/>
|
||||
|
||||
|
||||
<el-table-column
|
||||
prop="busName"
|
||||
label="上级母线"
|
||||
align="center"
|
||||
width="170"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="pointname"
|
||||
align="center"
|
||||
label="监测点"
|
||||
show-overflow-tooltip
|
||||
width="170"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="objName"
|
||||
align="center"
|
||||
label="用户"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="scope">{{ scope.row.objName || "/" }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="wavetype"
|
||||
align="center"
|
||||
width="90"
|
||||
label="触发类型"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ filteWavetype(scope.row.wavetype) }}
|
||||
<!-- </el-tag> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="eventvalue"
|
||||
align="center"
|
||||
label="残余电压"
|
||||
width="100"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ Math.floor(scope.row.eventvalue * 10000) / 100 }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="persisttime"
|
||||
align="center"
|
||||
label="持续时间"
|
||||
width="100"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ Math.floor(scope.row.persisttime * 1000) / 1000 }}s</template
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="操作"
|
||||
align="center"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="trendCharts(scope.row)"
|
||||
>
|
||||
波形
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
<!-- 趋势图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close=" dialogVisible = true;"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, nextTick, onMounted } from "vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import {
|
||||
rightImportOpenDetail,
|
||||
userEventList,
|
||||
getDicTree,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search } from "@element-plus/icons-vue";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const waveFormRef = ref();
|
||||
const trendVisible = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("暂降事件_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const columns: any = ref([]);
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const key: any = ref("");
|
||||
const searchValue = ref("");
|
||||
const eventList = ref([]);
|
||||
const obj: any = ref({}); // 初始化为空对象
|
||||
const bigObjTypeList = ref([]);
|
||||
const open = async (eventLis: any) => {
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
searchValue.value = eventLis.customId; // 清空搜索框
|
||||
eventList.value = eventLis.eventList;
|
||||
dialogVisible.value = true;
|
||||
await init();
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
|
||||
rightImportOpenDetail({
|
||||
deptId: store.state.deptId,
|
||||
searchValue: searchValue.value,
|
||||
}).then((res) => {
|
||||
obj.value = res.data;
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
userEventList({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
eventIds: eventList.value,
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
const formatterObj = (value: string) => {
|
||||
let tem = bigObjTypeList.value.find((it) => it.id == value);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"发生时间",
|
||||
"供电区域",
|
||||
"变电站",
|
||||
"监测母线",
|
||||
"监测点",
|
||||
"用户",
|
||||
"触发类型",
|
||||
"残余电压",
|
||||
"持续时间",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await userEventList({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
eventIds: eventList.value,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.timeid + "." + item.ms,
|
||||
item.gdName,
|
||||
item.bdname,
|
||||
item.busName,
|
||||
item.pointname,
|
||||
item.objName,
|
||||
filteWavetype(item.wavetype),
|
||||
Math.floor(item.eventvalue * 10000) / 100 + "%",
|
||||
Math.floor(item.persisttime * 1000) / 1000 + "s",
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
//点击趋势图
|
||||
const trendCharts = (row: any) => {
|
||||
dialogVisible.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open(row);
|
||||
}, 500);
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="dialogVisible" :title="title" width="85%">
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="用户">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 140px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="请输入用户"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级电站">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="bdIndex"
|
||||
placeholder="请选择上级电站"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bdList"
|
||||
:label="item.name"
|
||||
:value="item.subIndex"
|
||||
:key="item.subIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象大类">
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="bigObjType"
|
||||
clearable
|
||||
placeholder="请选择对象大类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bigObjTypeList.filter((item) => item.level == 2)"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象小类">
|
||||
<el-select
|
||||
size="small"
|
||||
clearable
|
||||
v-model="smallObjType"
|
||||
placeholder="请选择对象小类"
|
||||
style="width: 140px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in smallObjTypeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
:scrollbar-always-on="true"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="300"
|
||||
prop="customerName"
|
||||
label="用户"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="powerSupplyArea"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="150"
|
||||
:formatter="formatter"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="substationName"
|
||||
label="上级电站"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
width="250"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="info"
|
||||
label="上级母线"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="eventCount"
|
||||
label="暂降次数"
|
||||
align="center"
|
||||
width="100"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="clickable-cell" @click="handleCellClick(scope.row)">
|
||||
{{ scope.row.eventCount }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- <el-table-column prop="status" label="通讯状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.status == 1"
|
||||
type="success"
|
||||
size="mini"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>在线</el-tag
|
||||
>
|
||||
<el-tag
|
||||
v-else
|
||||
type="danger"
|
||||
size="mini"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>离线</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="终端在线率(%)"
|
||||
align="center"
|
||||
/>-->
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 弹框 -->
|
||||
<FrequencyPopUp ref="frequencyPopUpRef" @closeDialog="dialogVisible = true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import FrequencyPopUp from "@/views/VoltageSag_BJ/components/popUpFrame/frequencyPopUp.vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import {
|
||||
rightEventDevOpen,
|
||||
getDicTree,
|
||||
regionDevCount,
|
||||
gdSelect,
|
||||
bdSelect,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search } from "@element-plus/icons-vue";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("受影响用户_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const bigObjType = ref("");
|
||||
const smallObjType = ref("");
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const bdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
const bdList = ref([]);
|
||||
|
||||
const frequencyPopUpRef = ref();
|
||||
const bigObjTypeList = ref([]);
|
||||
|
||||
const open = async (deptID: string = "") => {
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
searchValue.value = ""; // 清空搜索框
|
||||
bigObjType.value = deptID; // 清空搜索框
|
||||
dialogVisible.value = true;
|
||||
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
|
||||
await bdSelect().then((res: any) => {
|
||||
bdList.value = res.data;
|
||||
});
|
||||
|
||||
deptsIndex.value = ""; // 清空搜索框
|
||||
gdIndex.value = "";
|
||||
bdIndex.value = "";
|
||||
|
||||
await init();
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
await rightEventDevOpen({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
bdId: bdIndex.value,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCellClick = (event: any) => {
|
||||
frequencyPopUpRef.value?.open(event.eventIds);
|
||||
dialogVisible.value = false
|
||||
};
|
||||
|
||||
const formatter = (row: any, column: any) => {
|
||||
const value = row[column.property];
|
||||
if (column.property == "powerSupplyArea") {
|
||||
let tem = gdList.value.find((it) => it.gdIndex == value);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const formatterExport = (val) => {
|
||||
let tem = gdList.value.find((it) => it.gdIndex == val);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
const smallObjTypeList: any = computed(() => {
|
||||
smallObjType.value = "";
|
||||
return bigObjTypeList.value.filter((item: any) => {
|
||||
return item.parentId == bigObjType.value && item.level == 3;
|
||||
});
|
||||
});
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
["用户", "供电区域", "上级电站", "上级母线", "暂降次数"],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await rightEventDevOpen({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.customerName,
|
||||
formatterExport(item.powerSupplyArea),
|
||||
item.substationName,
|
||||
item.info,
|
||||
item.eventCount,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.clickable-cell {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px; /* 下划线偏移量 */
|
||||
text-decoration-color: #fff; /* 下划线颜色 */
|
||||
text-decoration-thickness: 1px; /* 下划线粗细 */
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,411 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="80%"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="变电站">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="请输入变电站"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="终端名称">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="devName"
|
||||
size="small"
|
||||
placeholder="请输入终端名称"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="通讯状态">
|
||||
<el-select
|
||||
v-model="status"
|
||||
placeholder="请选择"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="在线" value="1"></el-option>
|
||||
<el-option label="离线" value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button :icon="RefreshLeft" @click="reset" size="small"
|
||||
>重置
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="deptName"
|
||||
label="运维单位"
|
||||
align="center"
|
||||
width="130"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="gdName"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="140"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="stationName"
|
||||
label="变电站"
|
||||
align="center"
|
||||
width="140"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="devName"
|
||||
label="终端名称"
|
||||
align="center"
|
||||
width="150"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="ip"
|
||||
label="终端IP"
|
||||
align="center"
|
||||
width="130"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="manufacturerName"
|
||||
label="厂家"
|
||||
align="center"
|
||||
width="130"
|
||||
/>
|
||||
<!-- <el-table-column prop="gdName" label="运维单位" align="center" width="100" />
|
||||
<el-table-column show-overflow-tooltip prop="gdName" label="检测周期" align="center" width="100" /> -->
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="status"
|
||||
label="通讯状态"
|
||||
align="center"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.status == 1"
|
||||
type="success"
|
||||
size="small"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>在线</el-tag
|
||||
>
|
||||
<el-tag
|
||||
v-else
|
||||
type="danger"
|
||||
size="small"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>离线</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="终端在线率(%)"
|
||||
align="center"
|
||||
width="120"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
prop="integrityRate"
|
||||
label="数据完整性(%)"
|
||||
align="center"
|
||||
width="120"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="logonTime"
|
||||
label="投运时间"
|
||||
align="center"
|
||||
width="170"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="thisTimeCheck"
|
||||
label="本次定检时间"
|
||||
align="center"
|
||||
width="170"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="nextTimeCheck"
|
||||
label="下次定检时间"
|
||||
align="center"
|
||||
width="170"
|
||||
sortable
|
||||
/>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, nextTick } from "vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import { devicePage, gdSelect } from "@/api/statistics/index";
|
||||
import { Download, Search,RefreshLeft } from "@element-plus/icons-vue";
|
||||
import { regionDevCount } from "@/api/statistics/index";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("终端_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const columns: any = ref([]);
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const key: any = ref("");
|
||||
const searchValue = ref("");
|
||||
const devName = ref("");
|
||||
|
||||
const status = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
|
||||
const open = async (deptID: string = "", type: string = "") => {
|
||||
reset();
|
||||
dialogVisible.value = true;
|
||||
loading.value = true;
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
searchValue.value = ""; // 清空搜索框
|
||||
deptsIndex.value = deptID; // 清空搜索框
|
||||
status.value = type; // 清空搜索框
|
||||
gdIndex.value = "";
|
||||
|
||||
await init();
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
await devicePage({
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
devName: devName.value,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
state: status.value,
|
||||
searchValue: searchValue.value,
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
[
|
||||
"运维单位",
|
||||
"供电区域",
|
||||
"变电站",
|
||||
"终端名称",
|
||||
"终端IP",
|
||||
"厂家",
|
||||
"通讯状态",
|
||||
"终端在线率(%)",
|
||||
"数据完整性(%)",
|
||||
"投运时间",
|
||||
"本次定检时间",
|
||||
"下次定检时间",
|
||||
],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await devicePage({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
devName: devName.value,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
state: status.value,
|
||||
searchValue: searchValue.value,
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.deptName,
|
||||
item.gdName,
|
||||
item.stationName,
|
||||
item.devName,
|
||||
item.ip,
|
||||
item.manufacturerName,
|
||||
item.status == 1 ? "在线" : "离线",
|
||||
item.onLineRate,
|
||||
item.integrityRate,
|
||||
item.logonTime,
|
||||
item.thisTimeCheck,
|
||||
item.nextTimeCheck,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
// 重置
|
||||
const reset = () => {
|
||||
deptsIndex.value = "";
|
||||
gdIndex.value = "";
|
||||
searchValue.value = "";
|
||||
devName.value = "";
|
||||
status.value = "";
|
||||
};
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,548 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="85%"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="用户">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 130px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="请输入用户"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级电站">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="bdIndex"
|
||||
placeholder="请选择上级电站"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bdList"
|
||||
:label="item.name"
|
||||
:value="item.subIndex"
|
||||
:key="item.subIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象大类">
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="bigObjType"
|
||||
clearable
|
||||
placeholder="请选择对象大类"
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bigObjTypeList.filter((item) => item.level == 2)"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象小类">
|
||||
<el-select
|
||||
size="small"
|
||||
clearable
|
||||
v-model="smallObjType"
|
||||
placeholder="请选择对象小类"
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in smallObjTypeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button :icon="RefreshLeft" @click="reset" size="small"
|
||||
>重置
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:data="dataList"
|
||||
height="500px"
|
||||
stripe
|
||||
:scrollbar-always-on="true"
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="60">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="300"
|
||||
prop="customerName"
|
||||
label="用户"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="smallObjType"
|
||||
label="对象类型"
|
||||
align="center"
|
||||
sortable
|
||||
width="200"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatterObj(row.smallObjType) }}
|
||||
</template></el-table-column
|
||||
>
|
||||
<el-table-column
|
||||
prop="powerSupplyArea"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="150"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatter(row.powerSupplyArea) }}
|
||||
</template></el-table-column
|
||||
>
|
||||
|
||||
<el-table-column
|
||||
prop="substationName"
|
||||
label="上级电站"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
width="250"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.substationName">
|
||||
<div
|
||||
v-for="(item, index) in row.substationName.split(';')"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="info"
|
||||
label="上级母线"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.info">
|
||||
<div v-for="(item, index) in row.info.split(';')" :key="index">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="eventCount"
|
||||
label="暂降次数"
|
||||
align="center"
|
||||
width="100"
|
||||
sortable
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="clickable-cell" @click="handleCellClick(scope.row)">
|
||||
{{ scope.row.eventCount }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- <el-table-column prop="status" label="通讯状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.status == 1"
|
||||
type="success"
|
||||
size="mini"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>在线</el-tag
|
||||
>
|
||||
<el-tag
|
||||
v-else
|
||||
type="danger"
|
||||
size="mini"
|
||||
:disable-transitions="false"
|
||||
effect="dark"
|
||||
>离线</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="onLineRate"
|
||||
label="终端在线率(%)"
|
||||
align="center"
|
||||
/>-->
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 弹框 -->
|
||||
<FrequencyPopUp ref="frequencyPopUpRef" @closeDialog="dialogVisible = true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import FrequencyPopUp from "@/views/VoltageSag_BJ/components/popUpFrame/frequencyPopUp.vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import {
|
||||
rightEventDevOpen,
|
||||
getDicTree,
|
||||
regionDevCount,
|
||||
gdSelect,
|
||||
bdSelect,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search, RefreshLeft } from "@element-plus/icons-vue";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("受影响用户_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const bigObjType = ref("");
|
||||
const smallObjType = ref("");
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const bdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
const bdList = ref([]);
|
||||
|
||||
const frequencyPopUpRef = ref();
|
||||
const bigObjTypeList = ref([]);
|
||||
|
||||
const open = async (deptID: string = "") => {
|
||||
reset();
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
|
||||
bigObjType.value = deptID; // 清空搜索框
|
||||
dialogVisible.value = true;
|
||||
loading.value = true;
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
|
||||
await bdSelect().then((res: any) => {
|
||||
bdList.value = res.data;
|
||||
});
|
||||
|
||||
|
||||
|
||||
await init();
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
await rightEventDevOpen({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
bdId: bdIndex.value,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCellClick = (event: any) => {
|
||||
frequencyPopUpRef.value?.open(event.eventIds);
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const formatter = (value: string) => {
|
||||
let tem = gdList.value.find((it) => it.gdIndex == value);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
const formatterObj = (value: string) => {
|
||||
let tem = bigObjTypeList.value.find((it) => it.id == value);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
const formatterExport = (val) => {
|
||||
let tem = gdList.value.find((it) => it.gdIndex == val);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
const smallObjTypeList: any = computed(() => {
|
||||
smallObjType.value = "";
|
||||
return bigObjTypeList.value.filter((item: any) => {
|
||||
return item.parentId == bigObjType.value && item.level == 3;
|
||||
});
|
||||
});
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 表头
|
||||
const columnExpor = [
|
||||
["用户", "对象类型", "供电区域", "上级电站", "上级母线", "暂降次数", "暂降发生时刻", "暂降类型","残余电压(%)","持续时间(s)","所属电站","监测母线"]
|
||||
];
|
||||
|
||||
await rightEventDevOpen({
|
||||
// 请求参数保持不变
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
exportFlag: true
|
||||
}).then((res) => {
|
||||
// 所有行数据(包含表头和内容)
|
||||
const allRows = [...columnExpor];
|
||||
// 合并单元格配置(存储合并规则)
|
||||
const merges = [];
|
||||
// 当前行索引(从表头后开始计算,表头占1行)
|
||||
let currentRowIndex = 1;
|
||||
|
||||
// 遍历每个主对象
|
||||
res.data.records.forEach((item) => {
|
||||
// 1. 提取基础信息(要合并的列)
|
||||
const baseInfo = [
|
||||
item.customerName, // 列0:用户
|
||||
formatterObj(item.smallObjType), // 列1:对象类型
|
||||
formatter(item.powerSupplyArea), // 列2:供电区域
|
||||
item.substationName, // 列3:上级电站
|
||||
item.info, // 列4:上级母线
|
||||
item.eventCount // 列5:暂降次数
|
||||
];
|
||||
|
||||
// 2. 处理事件列表
|
||||
const events = item.eventList || [];
|
||||
const eventCount = events.length;
|
||||
// 总合并行数 = 基础信息行 + 事件行数
|
||||
const mergeRows = eventCount > 0 ? eventCount + 1 : 1;
|
||||
|
||||
// 3. 添加基础信息行(第一行)
|
||||
allRows.push([
|
||||
...baseInfo,
|
||||
eventCount > 0 ? "(以下为暂降详情)" : "无暂降事件", // 暂降发生时刻列(提示文本)
|
||||
"" // 暂降类型列留空
|
||||
]);
|
||||
|
||||
// 4. 添加事件行(若有)
|
||||
events.forEach((event) => {
|
||||
// 事件行的基础信息列留空(后续会合并到基础信息行)
|
||||
allRows.push([
|
||||
"", "", "", "", "", "", // 基础信息列留空
|
||||
`${event.timeid}.${event.ms}`, // 暂降发生时刻
|
||||
filteWavetype(event.wavetype), // 暂降类型
|
||||
`${Number(event.eventvalue).toFixed(2)}`,
|
||||
`${event.persisttime}`,
|
||||
`${event.stationName}`,
|
||||
`${event.busBarName}`,
|
||||
]);
|
||||
});
|
||||
|
||||
// 5. 配置合并规则(基础信息列纵向合并)
|
||||
if (mergeRows > 1) {
|
||||
// 对列0到列5(基础信息列)设置合并
|
||||
for (let col = 0; col < 6; col++) {
|
||||
merges.push({
|
||||
s: { r: currentRowIndex, c: col }, // 合并起始位置(行,列)
|
||||
e: { r: currentRowIndex + mergeRows - 1, c: col } // 合并结束位置
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 更新当前行索引(跳过已处理的行)
|
||||
currentRowIndex += mergeRows;
|
||||
});
|
||||
|
||||
// 7. 创建工作表并应用合并规则
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(allRows);
|
||||
// 设置列宽
|
||||
worksheet["!cols"] = [
|
||||
{ wch: 15 }, // 用户
|
||||
{ wch: 12 }, // 对象类型
|
||||
{ wch: 12 }, // 供电区域
|
||||
{ wch: 15 }, // 上级电站
|
||||
{ wch: 12 }, // 上级母线
|
||||
{ wch: 10 }, // 暂降次数
|
||||
{ wch: 20 }, // 暂降发生时刻
|
||||
{ wch: 15 } // 暂降类型
|
||||
];
|
||||
// 应用合并规则
|
||||
worksheet["!merges"] = merges;
|
||||
|
||||
// 8. 导出文件
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
XLSX.writeFile(workbook, `${title.value}.xlsx`);
|
||||
});
|
||||
};
|
||||
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchValue.value = "";
|
||||
deptsIndex.value = "";
|
||||
gdIndex.value = "";
|
||||
bdIndex.value = "";
|
||||
bigObjType.value = "";
|
||||
smallObjType.value = "";
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.clickable-cell {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px; /* 下划线偏移量 */
|
||||
text-decoration-color: #fff; /* 下划线颜色 */
|
||||
text-decoration-thickness: 1px; /* 下划线粗细 */
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,452 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="dialogVisible"
|
||||
:title="title"
|
||||
width="85%"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="用户">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 130px"
|
||||
v-model="searchValue"
|
||||
size="small"
|
||||
placeholder="请输入用户"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="运维单位">
|
||||
<el-select
|
||||
v-model="deptsIndex"
|
||||
placeholder="请选择运维单位"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptsList"
|
||||
:label="item.deptsname"
|
||||
:value="item.deptsIndex"
|
||||
:key="item.deptsIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供电区域">
|
||||
<el-select
|
||||
v-model="gdIndex"
|
||||
placeholder="请选择供电区域"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gdList"
|
||||
:label="item.name"
|
||||
:value="item.gdIndex"
|
||||
:key="item.gdIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上级电站">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="bdIndex"
|
||||
placeholder="请选择上级电站"
|
||||
size="small"
|
||||
clearable
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bdList"
|
||||
:label="item.name"
|
||||
:value="item.subIndex"
|
||||
:key="item.subIndex"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象大类">
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="bigObjType"
|
||||
clearable
|
||||
placeholder="请选择对象大类"
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in bigObjTypeList.filter((item) => item.level == 2)"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="对象小类">
|
||||
<el-select
|
||||
size="small"
|
||||
clearable
|
||||
v-model="smallObjType"
|
||||
placeholder="请选择对象小类"
|
||||
style="width: 130px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in smallObjTypeList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mt5">
|
||||
<el-button type="primary" :icon="Search" @click="init" size="small"
|
||||
>查询
|
||||
</el-button>
|
||||
<el-button :icon="RefreshLeft" @click="reset" size="small"
|
||||
>重置
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true"
|
||||
:data="dataList"
|
||||
height="600px"
|
||||
stripe
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column label="序号" align="center" type="index" width="70">
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="customerName"
|
||||
label="用户"
|
||||
align="center"
|
||||
min-width="300"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="smallObjType"
|
||||
label="对象类型"
|
||||
align="center"
|
||||
sortable
|
||||
width="200"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatterObj(row.smallObjType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="deptName"
|
||||
label="运维单位"
|
||||
align="center"
|
||||
width="150"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="gdName"
|
||||
label="供电区域"
|
||||
align="center"
|
||||
width="200"
|
||||
show-overflow-tooltip
|
||||
sortable
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="station"
|
||||
label="上级电站"
|
||||
align="center"
|
||||
sortable
|
||||
width="290"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.station">
|
||||
<div v-for="(item, index) in row.station.split(';')" :key="index">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="info"
|
||||
label="上级母线"
|
||||
align="center"
|
||||
sortable
|
||||
width="400"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.info">
|
||||
<div v-for="(item, index) in row.info.split(';')" :key="index">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 趋势图 -->
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
draggable
|
||||
v-model="trendVisible"
|
||||
v-if="trendVisible"
|
||||
title="波形"
|
||||
width="70%"
|
||||
@close="dialogVisible = true"
|
||||
>
|
||||
<waveForm ref="waveFormRef" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import table2excel from "js-table2excel";
|
||||
import * as XLSX from "xlsx";
|
||||
import waveForm from "@/components/BX/waveForm.vue";
|
||||
import {
|
||||
rightEventOpen,
|
||||
getDicTree,
|
||||
regionDevCount,
|
||||
gdSelect,
|
||||
bdSelect,
|
||||
} from "@/api/statistics/index";
|
||||
import { Download, Search ,RefreshLeft} from "@element-plus/icons-vue";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const waveFormRef = ref();
|
||||
const trendVisible = ref(false);
|
||||
const dialogVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const title = ref("用户台账_详情");
|
||||
const dataList = ref([]); // 存储原始数据
|
||||
const columns: any = ref([]);
|
||||
const pageNum = ref(1); // 当前页
|
||||
const pageSize = ref(20); // 每页条数
|
||||
const total = ref(0); // 总条数
|
||||
const bigObjType = ref("");
|
||||
const smallObjType = ref("");
|
||||
const searchValue = ref("");
|
||||
const deptsIndex = ref("");
|
||||
const gdIndex = ref("");
|
||||
const bdIndex = ref("");
|
||||
const deptsList = ref([]);
|
||||
const gdList = ref([]);
|
||||
const bdList = ref([]);
|
||||
|
||||
const bigObjTypeList = ref([]);
|
||||
|
||||
const open = async (bigObj: string = "", smallObj: string = "") => {
|
||||
dialogVisible.value = true;
|
||||
reset()
|
||||
loading.value = true;
|
||||
await regionDevCount({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
startTime: store.state.timeValue[0],
|
||||
endTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
deptsList.value = res.data;
|
||||
});
|
||||
await gdSelect().then((res: any) => {
|
||||
gdList.value = res.data;
|
||||
});
|
||||
|
||||
await bdSelect().then((res: any) => {
|
||||
bdList.value = res.data;
|
||||
});
|
||||
|
||||
pageNum.value = 1;
|
||||
pageSize.value = 20;
|
||||
|
||||
bigObjType.value = bigObj; // 清空搜索框
|
||||
|
||||
|
||||
bdIndex.value = "";
|
||||
setTimeout(async () => {
|
||||
smallObjType.value = smallObj;
|
||||
await init();
|
||||
}, 100);
|
||||
};
|
||||
const init = async () => {
|
||||
loading.value = true;
|
||||
await rightEventOpen({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: deptsIndex.value || store.state.deptId,
|
||||
gdIndex: gdIndex.value,
|
||||
bdId: bdIndex.value,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}).then((res) => {
|
||||
dataList.value = res.data.records;
|
||||
total.value = res.data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onTableSizeChange = (size: number) => {
|
||||
pageSize.value = size;
|
||||
pageNum.value = 1;
|
||||
init();
|
||||
};
|
||||
onMounted(() => {
|
||||
getDicTree({
|
||||
code: "CUSTOM_USER",
|
||||
}).then((res) => {
|
||||
bigObjTypeList.value = res.data;
|
||||
});
|
||||
});
|
||||
const smallObjTypeList: any = computed(() => {
|
||||
smallObjType.value = "";
|
||||
return bigObjTypeList.value.filter((item: any) => {
|
||||
return item.parentId == bigObjType.value && item.level == 3;
|
||||
});
|
||||
});
|
||||
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
pageNum.value = page;
|
||||
init();
|
||||
};
|
||||
|
||||
const formatterObj = (value: string) => {
|
||||
let tem = bigObjTypeList.value.find((it) => it.id == value);
|
||||
if (tem) {
|
||||
return tem.name;
|
||||
}
|
||||
};
|
||||
|
||||
const filteWavetype = (wavetype: string) => {
|
||||
switch (wavetype + "") {
|
||||
case "0":
|
||||
return "扰动";
|
||||
case "1":
|
||||
return "暂降";
|
||||
case "2":
|
||||
return "暂升";
|
||||
case "3":
|
||||
return "中断";
|
||||
case "4":
|
||||
return "其他";
|
||||
case "5":
|
||||
return "录波";
|
||||
}
|
||||
};
|
||||
// 导出
|
||||
const exportTable = async () => {
|
||||
// 示例数据
|
||||
|
||||
let columnExpor: any = [
|
||||
["用户", "对象类型", "运维单位", "供电区域", "上级电站", "上级母线"],
|
||||
];
|
||||
|
||||
let list = [];
|
||||
|
||||
await rightEventOpen({
|
||||
bigObjType: bigObjType.value,
|
||||
smallObjType: smallObjType.value,
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchValue: searchValue.value,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
}).then((res) => {
|
||||
let data = res.data.records.map((item) => {
|
||||
return [
|
||||
item.customerName,
|
||||
formatterObj(item.smallObjType),
|
||||
item.deptName,
|
||||
item.gdName,
|
||||
item.station,
|
||||
item.info,
|
||||
];
|
||||
});
|
||||
list = [...columnExpor, ...data];
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(list);
|
||||
|
||||
worksheet["!cols"] = list.map((col) => ({ wch: 20 }));
|
||||
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
});
|
||||
};
|
||||
//点击趋势图
|
||||
const trendCharts = (row: any) => {
|
||||
dialogVisible.value = false;
|
||||
trendVisible.value = true;
|
||||
setTimeout(() => {
|
||||
waveFormRef.value?.open(row);
|
||||
}, 500);
|
||||
};
|
||||
// 重置
|
||||
const reset = () => {
|
||||
|
||||
searchValue.value = "";
|
||||
deptsIndex.value = "";
|
||||
gdIndex.value = "";
|
||||
bdIndex.value = "";
|
||||
bigObjType.value = "";
|
||||
smallObjType.value = "";
|
||||
|
||||
};
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
121
src/views/VoltageSag_BJ/components/sendTrends.vue
Normal file
121
src/views/VoltageSag_BJ/components/sendTrends.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div class="titleBox">重要敏感用户暂降告警统计</div>
|
||||
<div v-loading="loading" element-loading-background="#343849c7" class="pl10">
|
||||
<dv-scroll-ranking-board
|
||||
:config="config"
|
||||
color="#ccc"
|
||||
ref="rankingRef"
|
||||
style="width: 96%; height: 320px"
|
||||
/>
|
||||
</div>
|
||||
<!-- 弹框 -->
|
||||
<sendPopUpBox ref="sendPopUpBoxRef" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, onBeforeUnmount } from "vue";
|
||||
|
||||
import * as echarts from "echarts";
|
||||
import { color, deptId } from "@/constant/index";
|
||||
import { rightImportUser } from "@/api/statistics/index";
|
||||
import { useStore } from "vuex";
|
||||
import sendPopUpBox from "@/views/VoltageSag_BJ/components/popUpFrame/sendPopUpBox.vue";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const rankingRef = ref();
|
||||
const loading = ref(false);
|
||||
const config: any = ref({
|
||||
data: [
|
||||
// {
|
||||
// name: "长鑫集电",
|
||||
// value: 7,
|
||||
// },
|
||||
],
|
||||
unit: "次",
|
||||
color: "#0a73ff",
|
||||
rowNum: 7,
|
||||
});
|
||||
const sendPopUpBoxRef = ref();
|
||||
const init = () => {
|
||||
loading.value = true;
|
||||
config.value.data = [];
|
||||
rightImportUser({
|
||||
deptId: store.state.deptId,
|
||||
type: store.state.timeType,
|
||||
searchBeginTime: store.state.timeValue[0],
|
||||
searchEndTime: store.state.timeValue[1],
|
||||
}).then((res: any) => {
|
||||
// dataSource.value = res.data;
|
||||
|
||||
if (res.data.length > 0) {
|
||||
config.value.data = res.data.map((item) => {
|
||||
return {
|
||||
customId:item.customId,
|
||||
name: item.name,
|
||||
value: item.count,
|
||||
eventList: item.eventList,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// renderChart();
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
// 点击事件处理器
|
||||
let clickHandler = null;
|
||||
|
||||
// 处理点击事件
|
||||
const handleRowClick = (name) => {
|
||||
let eventList = config.value.data.filter((item) => item.name == name);
|
||||
sendPopUpBoxRef.value.open(eventList[0]);
|
||||
|
||||
// 这里可以使用获取到的名称进行后续操作
|
||||
};
|
||||
onMounted(() => {
|
||||
// 获取组件DOM
|
||||
const rankingEl = rankingRef.value?.$el;
|
||||
|
||||
if (rankingEl) {
|
||||
clickHandler = (e) => {
|
||||
// 查找点击的行元素(类名为row-item)
|
||||
const rowEl = e.target.closest(".row-item");
|
||||
if (rowEl) {
|
||||
// 查找行内的名称元素(类名为info-name)
|
||||
const nameEl = rowEl.querySelector(".info-name");
|
||||
if (nameEl) {
|
||||
// 获取并传递名称文本
|
||||
handleRowClick(nameEl.textContent.trim());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 添加事件监听
|
||||
rankingEl.addEventListener("click", clickHandler);
|
||||
}
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
const rankingEl = rankingRef.value?.$el;
|
||||
if (rankingEl && clickHandler) {
|
||||
rankingEl.removeEventListener("click", clickHandler);
|
||||
}
|
||||
});
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.titles {
|
||||
margin-right: 10px;
|
||||
.react-right {
|
||||
width: 50px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
:deep(.row-item) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
219
src/views/VoltageSag_BJ/components/smsQueries.vue
Normal file
219
src/views/VoltageSag_BJ/components/smsQueries.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<!--短信查询-->
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="machineVisible" :title="title" width="1200px" :before-close="handleClose">
|
||||
<div class="formBox">
|
||||
<div class="formLeft">
|
||||
<datePicker ref="datePickerRef" />
|
||||
<span>发送结果: </span>
|
||||
<el-select
|
||||
size="small"
|
||||
v-model="state"
|
||||
placeholder="请选择"
|
||||
style="width: 100px"
|
||||
clearable
|
||||
>
|
||||
<el-option label="成功" value="1" />
|
||||
<el-option label="失败" value="0" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" :icon="Search" size="small" @click="inquire"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
<!-- <el-button type="primary" :icon="Delete" size="small">删除</el-button> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox">
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="tableData"
|
||||
height="500px"
|
||||
size="small"
|
||||
stripe
|
||||
v-loading="loading"
|
||||
element-loading-background="#343849c7"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<!-- <el-table-column type="selection" align="center" width="45" /> -->
|
||||
<el-table-column label="序号" align="center" type="index" width="70" />
|
||||
<el-table-column
|
||||
prop="sendTime"
|
||||
align="center"
|
||||
label="时间"
|
||||
width="170"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="userName"
|
||||
align="center"
|
||||
label="接收人"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="phone"
|
||||
align="center"
|
||||
label="手机号"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sendResult"
|
||||
align="center"
|
||||
label="发送结果"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.sendResult === 1"
|
||||
size="small"
|
||||
type="success"
|
||||
effect="dark"
|
||||
>成功
|
||||
</el-tag>
|
||||
<el-tag v-else size="small" type="danger" effect="dark"
|
||||
>失败
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="msgContent" label="发送内容" />
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="form.pageNum"
|
||||
:page-size="form.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
background
|
||||
size="small"
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, nextTick } from "vue";
|
||||
import { hasSendMsgPage } from "@/api/statistics/index";
|
||||
import { ElMessage } from "element-plus";
|
||||
import datePicker from "@/components/datePicker/index.vue";
|
||||
import { Search, Download } from "@element-plus/icons-vue";
|
||||
import table2excel from "js-table2excel";
|
||||
const emit= defineEmits(["close"]);
|
||||
const machineVisible = ref(false);
|
||||
const title = ref("已发送短信查询");
|
||||
const datePickerRef = ref();
|
||||
const form = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const loading = ref(false);
|
||||
const state = ref("");
|
||||
const total = ref(0); // 假设总条数为100
|
||||
const tableData = ref([]);
|
||||
//form表单校验规则
|
||||
const inquire = () => {
|
||||
loading.value = true;
|
||||
hasSendMsgPage({
|
||||
...form,
|
||||
searchBeginTime: datePickerRef.value.timeValue[0],
|
||||
searchEndTime: datePickerRef.value.timeValue[1],
|
||||
sendResult: state.value,
|
||||
}).then((res) => {
|
||||
total.value = res.data.total;
|
||||
tableData.value = res.data.records;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const open = (text: string, data?: any) => {
|
||||
|
||||
machineVisible.value = true;
|
||||
nextTick(() => {
|
||||
inquire();
|
||||
});
|
||||
};
|
||||
const onTableSizeChange = (size: number) => {
|
||||
form.pageSize = size;
|
||||
// 重新加载数据
|
||||
inquire();
|
||||
};
|
||||
const onTableCurrentChange = (page: number) => {
|
||||
form.pageNum = page;
|
||||
// 重新加载数据
|
||||
inquire();
|
||||
};
|
||||
// 导出
|
||||
const exportTable = () => {
|
||||
let columnExpor: any = [
|
||||
{
|
||||
title: "时间",
|
||||
key: "sendTime",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
title: "接收人",
|
||||
key: "userName",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
title: "手机号",
|
||||
key: "phone",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
title: "发送结果",
|
||||
key: "sendResult",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
title: "发送内容",
|
||||
key: "msgContent",
|
||||
type: "text",
|
||||
},
|
||||
];
|
||||
|
||||
hasSendMsgPage({
|
||||
pageNum: 1,
|
||||
pageSize: total.value,
|
||||
searchBeginTime: datePickerRef.value.timeValue[0],
|
||||
searchEndTime: datePickerRef.value.timeValue[1],
|
||||
sendResult: state.value,
|
||||
}).then((res) => {
|
||||
setTimeout(() => {
|
||||
table2excel(
|
||||
columnExpor,
|
||||
res.data.records.filter(
|
||||
(item) => (item.sendResult = item.sendResult == 1 ? "成功" : "失败")
|
||||
), // 导出原始数据
|
||||
"已发短信"
|
||||
);
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
const handleClose = () => {
|
||||
emit("close", false);
|
||||
}
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.tableBox {
|
||||
padding: 0px !important;
|
||||
}
|
||||
.formBox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formLeft {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
631
src/views/VoltageSag_BJ/components/tablePopUpMap.vue
Normal file
631
src/views/VoltageSag_BJ/components/tablePopUpMap.vue
Normal file
@@ -0,0 +1,631 @@
|
||||
<template>
|
||||
<el-dialog :close-on-click-modal="false" draggable v-model="dialogVisible" :title="title" width="70%">
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
|
||||
<el-tab-pane
|
||||
:label="item.name"
|
||||
v-for="(item, index) in column"
|
||||
:name="item.key"
|
||||
>
|
||||
<el-form :inline="true" class="formFlex">
|
||||
<div>
|
||||
<el-form-item label="关键字筛选">
|
||||
<el-input
|
||||
clearable
|
||||
style="width: 150px"
|
||||
v-model="searchValue"
|
||||
@input="handleSearch"
|
||||
@clear="handleClear"
|
||||
size="small"
|
||||
placeholder="请输入搜索内容"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="通讯状态" v-if="activeName == '0'">
|
||||
<el-select
|
||||
v-model="runFlag"
|
||||
placeholder="请选择通讯状态"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="正常" value="1"></el-option>
|
||||
<el-option label="中断" value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="触发类型" v-if="activeName == '1'">
|
||||
<el-select
|
||||
v-model="wavetype"
|
||||
placeholder="请选择触发类型"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="扰动" value="0"></el-option>
|
||||
<el-option label="暂降" value="1"></el-option>
|
||||
<el-option label="暂升" value="2"></el-option>
|
||||
<el-option label="中断" value="3"></el-option>
|
||||
<el-option label="其他" value="4"></el-option>
|
||||
<el-option label="录波" value="5"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="触发类型" v-if="activeName == '1'">
|
||||
<el-select
|
||||
v-model="eventSeverity"
|
||||
placeholder="请选择触发类型"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="告警" value="1"></el-option>
|
||||
<el-option label="预警" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否远程通知" v-if="activeName == '1'">
|
||||
<el-select
|
||||
v-model="msgEventInfoSize"
|
||||
placeholder="请选择是否远程通知"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="是" value="1"></el-option>
|
||||
<el-option label="否" value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否处置" v-if="activeName == '2'">
|
||||
<el-select
|
||||
v-model="isHandle"
|
||||
placeholder="请选择是否处置"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="是" value="1"></el-option>
|
||||
<el-option label="否" value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="发送结果" v-if="activeName == '2'">
|
||||
<el-select
|
||||
v-model="sendResult"
|
||||
placeholder="请选择"
|
||||
size="small"
|
||||
clearable
|
||||
@change="
|
||||
handleSearch();
|
||||
handleClear();
|
||||
"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="成功" value="1"></el-option>
|
||||
<el-option label="失败" value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="exportTable"
|
||||
size="small"
|
||||
>导出
|
||||
</el-button>
|
||||
</el-form>
|
||||
<div class="tableBox" style="padding: 0">
|
||||
<el-table
|
||||
:scrollbar-always-on="true" :data="
|
||||
displayData.slice((pageNum - 1) * pageSize, pageNum * pageSize)
|
||||
"
|
||||
height="500px"
|
||||
stripe
|
||||
size="small"
|
||||
@sort-change="handleSortChange"
|
||||
:header-cell-style="{ textAlign: 'center' }"
|
||||
border
|
||||
>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
align="center"
|
||||
type="index"
|
||||
width="70"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(k, i) in item.columns"
|
||||
:prop="k.prop"
|
||||
show-overflow-tooltip
|
||||
:align="k.align || 'center'"
|
||||
:label="k.label"
|
||||
:width="k.width"
|
||||
:formatter="formatter"
|
||||
sortable
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="k.prop === 'lookFlag' || k.prop === 'isHandle'">
|
||||
<el-tag
|
||||
:type="row[k.prop] == 1 ? 'primary' : 'warning'"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>
|
||||
{{ row[k.prop] == 1 ? "是" : "否" }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else-if="k.prop === 'sendResult'">
|
||||
<el-tag
|
||||
:type="row[k.prop] == 1 ? 'success' : 'danger'"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>
|
||||
{{ row[k.prop] == 1 ? "成功" : "失败" }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else-if="k.prop === 'eventSeverity'">
|
||||
<el-tag
|
||||
:type="row[k.prop] == 1 ? 'danger' : 'warning'"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>
|
||||
{{ row[k.prop] == 1 ? "告警" : "预警" }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else-if="k.prop === 'runFlag'">
|
||||
<el-tag
|
||||
:type="row[k.prop] == 0 ? 'danger' : 'success'"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>
|
||||
{{ row[k.prop] == 0 ? "中断" : "正常" }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else-if="k.prop === 'devFlag'">
|
||||
<el-tag
|
||||
:type="
|
||||
row[k.prop] == 0
|
||||
? 'success'
|
||||
: row[k.prop] == 1
|
||||
? 'warning'
|
||||
: row[k.prop] == 2
|
||||
? 'danger'
|
||||
: row[k.prop] == 3
|
||||
? 'warning'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
effect="dark"
|
||||
>
|
||||
{{
|
||||
row[k.prop] == 0
|
||||
? "投运"
|
||||
: row[k.prop] == 1
|
||||
? "检修"
|
||||
: row[k.prop] == 2
|
||||
? "停运"
|
||||
: row[k.prop] == 3
|
||||
? "调试"
|
||||
: row[k.prop] == 4
|
||||
? "退运"
|
||||
: ""
|
||||
}}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else-if="k.prop === 'wavetype'">
|
||||
<!-- <el-tag
|
||||
:type="'primary'"
|
||||
:color="
|
||||
row[k.prop] == 0
|
||||
? '#E67E22'
|
||||
: row[k.prop] == 1
|
||||
? '#F39C12'
|
||||
: row[k.prop] == 2
|
||||
? '#7E57C2'
|
||||
: row[k.prop] == 3
|
||||
? '#C62828'
|
||||
: row[k.prop] == 4
|
||||
? '#757575'
|
||||
: row[k.prop] == 5
|
||||
? '#1E88E5'
|
||||
: ''
|
||||
"
|
||||
size="small"
|
||||
effect="dark"
|
||||
> -->
|
||||
{{
|
||||
row[k.prop] == 0
|
||||
? "扰动"
|
||||
: row[k.prop] == 1
|
||||
? "暂降"
|
||||
: row[k.prop] == 2
|
||||
? "暂升"
|
||||
: row[k.prop] == 3
|
||||
? "中断"
|
||||
: row[k.prop] == 4
|
||||
? "其他"
|
||||
: row[k.prop] == 5
|
||||
? "录波"
|
||||
: ""
|
||||
}}
|
||||
<!-- </el-tag> -->
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="margin-top: 10px"
|
||||
:currentPage="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200]"
|
||||
size="small"
|
||||
background
|
||||
:layout="'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="displayData.length"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="暂降次数" name="2">Config</el-tab-pane>
|
||||
<el-tab-pane label="远程通知数" name="3">Role</el-tab-pane> -->
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from "vue";
|
||||
import * as XLSX from "xlsx";
|
||||
import { Download } from "@element-plus/icons-vue";
|
||||
import table2excel from "js-table2excel";
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
const title = ref("");
|
||||
const activeName = ref("0");
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(20);
|
||||
const searchValue = ref("");
|
||||
const runFlag = ref("");
|
||||
const wavetype = ref("");
|
||||
const eventSeverity = ref("");
|
||||
const sendResult = ref("");
|
||||
const isHandle: any = ref("");
|
||||
const msgEventInfoSize: any = ref("");
|
||||
// 计算属性:根据搜索条件过滤后的数据
|
||||
const displayData = computed(() => {
|
||||
if (
|
||||
!searchValue.value.trim() &&
|
||||
!runFlag.value &&
|
||||
!wavetype.value &&
|
||||
!eventSeverity.value &&
|
||||
!msgEventInfoSize.value &&
|
||||
!sendResult.value &&
|
||||
!isHandle.value
|
||||
) {
|
||||
return column.value[activeName.value].data;
|
||||
}
|
||||
|
||||
const searchTerm = searchValue.value.trim().toLowerCase();
|
||||
|
||||
return column.value[activeName.value].data.filter((row: any) => {
|
||||
if (runFlag.value && row.runFlag != runFlag.value) return false;
|
||||
if (wavetype.value && row.wavetype != wavetype.value) return false;
|
||||
if (sendResult.value && row.sendResult != sendResult.value) return false;
|
||||
if (eventSeverity.value && row.eventSeverity != eventSeverity.value)
|
||||
return false;
|
||||
if (
|
||||
msgEventInfoSize.value &&
|
||||
!(msgEventInfoSize.value == 1
|
||||
? row.msgEventInfoSize > 0
|
||||
: row.msgEventInfoSize == 0)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
isHandle.value &&
|
||||
(isHandle.value == 0 ? row.isHandle == 1 : row.isHandle != isHandle.value)
|
||||
)
|
||||
return false;
|
||||
|
||||
return Object.values(row).some((value) => {
|
||||
if (value === null || value === undefined) return false;
|
||||
return String(value).toLowerCase().includes(searchTerm);
|
||||
});
|
||||
});
|
||||
});
|
||||
const column: any = ref([
|
||||
{
|
||||
name: "监测点数",
|
||||
key: "0",
|
||||
data: [],
|
||||
columns: [
|
||||
{ prop: "stationName", label: "变电站", sortable: true },
|
||||
{ prop: "devName", label: "终端名称" },
|
||||
{ prop: "busBarName", label: "母线名称" },
|
||||
{ prop: "lineName", label: "监测点名称" },
|
||||
{ prop: "runFlag", label: "通讯状态", width: 90 },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "暂降次数",
|
||||
key: "1",
|
||||
data: [],
|
||||
columns: [
|
||||
{
|
||||
prop: "timeid",
|
||||
label: "发生时间",
|
||||
width: 180,
|
||||
sortable: true,
|
||||
},
|
||||
{ prop: "bdname", label: "变电站", sortable: true },
|
||||
{ prop: "pointname", label: "监测点" },
|
||||
{ prop: "objName", label: "影响用户", width: 90 },
|
||||
{ prop: "wavetype", label: "触发类型", width: 90 },
|
||||
{
|
||||
prop: "eventvalue",
|
||||
label: "残余电压",
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
prop: "persisttime",
|
||||
label: "持续时间",
|
||||
width: 100,
|
||||
},
|
||||
{ prop: "eventSeverity", label: "告警类型", width: 90 },
|
||||
{ prop: "msgEventInfoSize", label: "远程通知数", width: 110 },
|
||||
],
|
||||
},
|
||||
// {
|
||||
// name: "远程通知",
|
||||
// key: "2",
|
||||
// data: [],
|
||||
// columns: [
|
||||
// {
|
||||
// prop: "sendTime",
|
||||
// label: "发送时间",
|
||||
// width: 180,
|
||||
// },
|
||||
// { prop: "userName", label: "接受人", width: 100 },
|
||||
// { prop: "phone", label: "手机号", width: 100 },
|
||||
// { prop: "msgContent", label: "发送内容", align: "left" },
|
||||
// { prop: "isHandle", label: "是否反馈", width: 100 },
|
||||
// { prop: "sendResult", label: "发送结果", width: 100 },
|
||||
// ],
|
||||
// },
|
||||
]);
|
||||
|
||||
const formatter = (row: any, column: any) => {
|
||||
const value = row[column.property];
|
||||
if (column.property == "timeid") {
|
||||
return row.timeid + "." + row.ms;
|
||||
} else if (column.property == "eventvalue") {
|
||||
return Math.floor(row.eventvalue * 10000) / 100 + "%";
|
||||
} else if (column.property == "persisttime") {
|
||||
return row.persisttime + "s";
|
||||
} else if (column.property == "objName") {
|
||||
return row.objName || "/";
|
||||
} else if (column.property == "wavetype") {
|
||||
return row.wavetype == 0
|
||||
? "扰动"
|
||||
: row.wavetype == 1
|
||||
? "暂降"
|
||||
: row.wavetype == 2
|
||||
? "暂升"
|
||||
: row.wavetype == 3
|
||||
? "中断"
|
||||
: row.wavetype == 4
|
||||
? "其他"
|
||||
: row.wavetype == 5
|
||||
? "录波"
|
||||
: "";
|
||||
}
|
||||
return value;
|
||||
};
|
||||
const handleClick = () => {
|
||||
searchValue.value = "";
|
||||
runFlag.value = "";
|
||||
wavetype.value = "";
|
||||
sendResult.value = "";
|
||||
isHandle.value = "";
|
||||
msgEventInfoSize.value = "";
|
||||
eventSeverity.value = "";
|
||||
pageSize.value = 20;
|
||||
pageNum.value = 1;
|
||||
};
|
||||
|
||||
|
||||
// 处理排序变化
|
||||
const handleSortChange = ({ prop, order }: any) => {
|
||||
// console.log("🚀 ~ handleSortChange ~ prop, order :", prop, order);
|
||||
if (prop && order) {
|
||||
// 根据当前排序条件对所有数据进行排序
|
||||
const list = dataListCopy.value[activeName.value].data.sort((a, b) => {
|
||||
if (order === "ascending") {
|
||||
return a[prop] > b[prop] ? 1 : -1;
|
||||
} else {
|
||||
return a[prop] < b[prop] ? 1 : -1;
|
||||
}
|
||||
});
|
||||
column.value[activeName.value].data = JSON.parse(JSON.stringify(list));
|
||||
}
|
||||
};
|
||||
const dataListCopy = ref([]);
|
||||
const open = (row: any) => {
|
||||
activeName.value = "0";
|
||||
handleClick();
|
||||
let list = JSON.parse(JSON.stringify(row));
|
||||
title.value = list.title;
|
||||
column.value[0].data = list.lineList;
|
||||
column.value[1].data = list.eventList;
|
||||
// column.value[2].data = list.noticeList;
|
||||
dataListCopy.value = JSON.parse(JSON.stringify(column.value));
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
// 导出
|
||||
const exportTable = () => {
|
||||
let columnExpor: any = [[]];
|
||||
column.value[activeName.value].columns.forEach((item: any) => {
|
||||
columnExpor[0].push(item.label);
|
||||
});
|
||||
let list = JSON.parse(JSON.stringify(displayData.value)).filter(
|
||||
(item: any) => {
|
||||
item.eventvalue = Math.floor(item.eventvalue * 10000) / 100 + "%";
|
||||
item.persisttime = item.persisttime + "s";
|
||||
item.devFlag =
|
||||
item.devFlag == 0
|
||||
? "投运"
|
||||
: item.devFlag == 1
|
||||
? "检修"
|
||||
: item.devFlag == 2
|
||||
? "停运"
|
||||
: item.devFlag == 3
|
||||
? "调试"
|
||||
: item.devFlag == 4
|
||||
? "退运"
|
||||
: "";
|
||||
item.wavetype =
|
||||
item.wavetype == 0
|
||||
? "扰动"
|
||||
: item.wavetype == 1
|
||||
? "暂降"
|
||||
: item.wavetype == 2
|
||||
? "暂升"
|
||||
: item.wavetype == 3
|
||||
? "中断"
|
||||
: item.wavetype == 4
|
||||
? "其他"
|
||||
: item.wavetype == 5
|
||||
? "录波"
|
||||
: "";
|
||||
item.eventSeverity = item.eventSeverity == 1 ? "告警" : "预警";
|
||||
item.objName = item.objName || "-";
|
||||
item.runFlag = item.runFlag == 0 ? "中断" : "正常";
|
||||
item.lookFlag = item.lookFlag == 1 ? "是" : "否";
|
||||
item.isHandle = item.isHandle == 1 ? "是" : "否";
|
||||
item.sendResult = item.sendResult == 1 ? "成功" : "失败";
|
||||
item.timeid = item.timeid + "." + item.ms;
|
||||
return item;
|
||||
}
|
||||
);
|
||||
list.forEach((item, i) => {
|
||||
columnExpor.push([]);
|
||||
column.value[activeName.value].columns.forEach((column) => {
|
||||
columnExpor[i + 1].push(item[column.prop]);
|
||||
});
|
||||
});
|
||||
|
||||
// 创建工作表
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(columnExpor);
|
||||
worksheet["!cols"] = columnExpor.map((col) => ({ wch: 20 }));
|
||||
// 创建工作簿
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, title.value);
|
||||
|
||||
// 写出文件
|
||||
XLSX.writeFile(workbook, title.value + ".xlsx");
|
||||
// let columnExpor: any = [];
|
||||
// column.value[activeName.value].columns.forEach((item: any) => {
|
||||
// columnExpor.push({
|
||||
// title: item.label,
|
||||
// key: item.prop,
|
||||
// type: "text",
|
||||
// });
|
||||
// });
|
||||
// let list = JSON.parse(
|
||||
// JSON.stringify(displayData.value)
|
||||
// ).filter((item: any) => {
|
||||
// item.eventvalue = Math.floor(item.eventvalue * 10000) / 100 + "%";
|
||||
// item.persisttime = item.persisttime + "s";
|
||||
// item.devFlag =
|
||||
// item.devFlag == 0
|
||||
// ? "投运"
|
||||
// : item.devFlag == 1
|
||||
// ? "检修"
|
||||
// : item.devFlag == 2
|
||||
// ? "停运"
|
||||
// : item.devFlag == 3
|
||||
// ? "调试"
|
||||
// : item.devFlag == 4
|
||||
// ? "退运"
|
||||
// : "";
|
||||
// item.wavetype =
|
||||
// item.wavetype == 0
|
||||
// ? "扰动"
|
||||
// : item.wavetype == 1
|
||||
// ? "暂降"
|
||||
// : item.wavetype == 2
|
||||
// ? "暂升"
|
||||
// : item.wavetype == 3
|
||||
// ? "中断"
|
||||
// : item.wavetype == 4
|
||||
// ? "其他"
|
||||
// : item.wavetype == 5
|
||||
// ? "录波"
|
||||
// : "";
|
||||
// item.eventSeverity = item.eventSeverity == 1 ? "告警" : "预警";
|
||||
// item.objName = item.objName || "-";
|
||||
// item.runFlag = item.runFlag == 0 ? "中断" : "正常";
|
||||
// item.lookFlag = item.lookFlag == 1 ? "是" : "否";
|
||||
// item.isHandle = item.isHandle == 1 ? "是" : "否";
|
||||
// item.sendResult = item.sendResult == 1 ? "成功" : "失败";
|
||||
// item.timeid = item.timeid + "." + item.ms;
|
||||
// return item;
|
||||
// });
|
||||
|
||||
// setTimeout(() => {
|
||||
// table2excel(
|
||||
// columnExpor,
|
||||
// list, // 导出原始数据
|
||||
// column.value[activeName.value].name
|
||||
// );
|
||||
// }, 500);
|
||||
};
|
||||
// 搜索处理函数
|
||||
const handleSearch = () => {
|
||||
console.log("搜索触发:", searchValue.value);
|
||||
pageNum.value = 1; // 重置页码为1
|
||||
};
|
||||
|
||||
// 清空搜索处理
|
||||
const handleClear = () => {
|
||||
console.log("清空搜索");
|
||||
// searchValue.value = "";
|
||||
pageNum.value = 1;
|
||||
};
|
||||
const onTableSizeChange = (val: any) => {
|
||||
pageSize.value = val;
|
||||
};
|
||||
const onTableCurrentChange = (val: any) => {
|
||||
pageNum.value = val;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.formFlex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
375
src/views/VoltageSag_BJ/index.vue
Normal file
375
src/views/VoltageSag_BJ/index.vue
Normal file
@@ -0,0 +1,375 @@
|
||||
<template>
|
||||
<div id="index" ref="appRef">
|
||||
<div
|
||||
class="bg"
|
||||
:class="
|
||||
store.state.screenNotic == 1
|
||||
? pushFlag
|
||||
? bottomTextRef?.urgentList.length > 0
|
||||
? 'bg-red'
|
||||
: ''
|
||||
: ''
|
||||
: ''
|
||||
"
|
||||
>
|
||||
<dv-loading v-if="loading">Loading...</dv-loading>
|
||||
|
||||
<div v-else class="host-body">
|
||||
<div class="d-flex jc-center">
|
||||
<div class="react-left">
|
||||
<span class="text fw-b">
|
||||
{{ timeInfo.dateYear }} {{ timeInfo.dateWeek }}
|
||||
{{ timeInfo.dateDay }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<dv-decoration-10 class="dv-dec-10" :color="color[1]" />
|
||||
<div class="d-flex jc-center">
|
||||
<dv-decoration-8 class="dv-dec-8" :color="color[2]" />
|
||||
<div class="title">
|
||||
<span class="title-text">{{ title }}</span>
|
||||
</div>
|
||||
<dv-decoration-8
|
||||
class="dv-dec-8"
|
||||
:reverse="true"
|
||||
:color="color[2]"
|
||||
/>
|
||||
</div>
|
||||
<dv-decoration-10 class="dv-dec-10-s" :color="color[1]" />
|
||||
</div>
|
||||
|
||||
<div class="d-flex secondLine">
|
||||
<div class="react-right mr-1">
|
||||
<span class="text fw-b" style="display: flex">
|
||||
<datePicker
|
||||
ref="datePickerRef"
|
||||
@timeChangeInfo="timeChangeInfo"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-dropdown placement="bottom">
|
||||
<el-icon :size="22" :color="color[1][0]" class="mt-0.5 mt5">
|
||||
<Menu />
|
||||
</el-icon>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<!-- <el-dropdown-item @click="handleClick('1')"
|
||||
>已发送短信查询</el-dropdown-item
|
||||
>
|
||||
|
||||
<el-dropdown-item @click="handleClick('2')"
|
||||
>模拟短信发送</el-dropdown-item
|
||||
> -->
|
||||
<el-dropdown-item @click="handleClick('3')"
|
||||
>系统配置</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="body-box">
|
||||
<!-- 第三行数据 -->
|
||||
<div class="content-box">
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<eventStatistics ref="eventStatisticsRef" />
|
||||
</dv-border-box-13>
|
||||
|
||||
<dv-border-box-10 :color="color[0]">
|
||||
<Map ref="mapRef" />
|
||||
<!-- <center-left /> -->
|
||||
</dv-border-box-10>
|
||||
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<alarm ref="alarmRef" />
|
||||
<!-- 紧急告警 -->
|
||||
|
||||
<div
|
||||
class="icon"
|
||||
v-if="!(bottomTextRef?.urgentList.length == 0)"
|
||||
:color="color[0][1]"
|
||||
:class="
|
||||
bottomTextRef?.urgentList.length > 0
|
||||
? 'animate-flash-red'
|
||||
: ''
|
||||
"
|
||||
@click="drawerClick"
|
||||
>
|
||||
<!-- <WarnTriangleFilled /> -->
|
||||
<span
|
||||
class="iconfont icon-gaojing"
|
||||
:style="{
|
||||
color:
|
||||
bottomTextRef?.urgentList.length > 0
|
||||
? '#ff0000'
|
||||
: color[0][1],
|
||||
}"
|
||||
></span>
|
||||
<span
|
||||
class="count"
|
||||
v-if="bottomTextRef?.urgentList.length > 0"
|
||||
>{{
|
||||
bottomTextRef?.urgentList.length > 99
|
||||
? "99+"
|
||||
: bottomTextRef?.urgentList.length
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</dv-border-box-13>
|
||||
</div>
|
||||
|
||||
<!-- 第四行数据 -->
|
||||
<div class="bototm-box">
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<endpointStatistics ref="endpointStatisticsRef" />
|
||||
|
||||
<!-- <bottom-left /> -->
|
||||
</dv-border-box-13>
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<informationTable
|
||||
ref="informationTableRef"
|
||||
@handleCurrentChange="handleCurrentChange"
|
||||
/>
|
||||
</dv-border-box-13>
|
||||
<dv-border-box-13 :color="color[0]">
|
||||
<sendTrends ref="sendTrendsRef" />
|
||||
</dv-border-box-13>
|
||||
</div>
|
||||
<!-- 底部 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<bottomText
|
||||
ref="bottomTextRef"
|
||||
@handleCurrentChange="handleCurrentChange"
|
||||
/>
|
||||
|
||||
<!-- 已发短信查询 -->
|
||||
<smsQueries
|
||||
ref="smsQueriesRef"
|
||||
v-if="smsQueriesFlag"
|
||||
@close="smsQueriesFlag = false"
|
||||
/>
|
||||
|
||||
<!-- 系统配置 -->
|
||||
<Config ref="ConfigRef" @flushed="inquire" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--index.vue-->
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
reactive,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
} from "vue";
|
||||
|
||||
import { formatTime, getDateRange, stopSpeak } from "@/utils/index"; //引入封装好的
|
||||
import useDraw from "@/utils/useDraw"; // 引入封装好的屏幕适配方法
|
||||
import { WEEK, title, subtitle, moduleInfo, color } from "@/constant/index"; //引入封装的标题日期
|
||||
import datePicker from "@/components/datePicker/index.vue";
|
||||
import { Menu, BellFilled, WarnTriangleFilled } from "@element-plus/icons-vue";
|
||||
//页面组件
|
||||
import eventStatistics from "./components/eventStatistics.vue"; //统计事件
|
||||
import endpointStatistics from "./components/endpointStatistics.vue"; //终端在线统计
|
||||
import sendTrends from "./components/sendTrends.vue"; //终端在线统计
|
||||
import informationTable from "./components/informationTable.vue"; //实时暂态信息
|
||||
import alarm from "./components/alarm.vue"; //实时暂态信息
|
||||
import Map from "./components/bdMap.vue"; //地图
|
||||
import smsQueries from "./components/smsQueries.vue"; // //短信查询
|
||||
import bottomText from "./components/bottomText.vue"; //边框组件
|
||||
import socketClient from "@/utils/webSocketClient";
|
||||
import { useStore } from "vuex";
|
||||
import Config from "./components/config.vue";
|
||||
|
||||
const store = useStore();
|
||||
const smsQueriesRef = ref(); // 短信查询组件引用
|
||||
const endpointStatisticsRef = ref(); // 终端在线统计组件引用
|
||||
const informationTableRef = ref(); // 实时暂态信息组件引用
|
||||
const sendTrendsRef = ref();
|
||||
const ConfigRef = ref();
|
||||
const eventStatisticsRef = ref();
|
||||
const alarmRef = ref();
|
||||
const mapRef = ref();
|
||||
//开始创建webSocket客户端
|
||||
const dataSocket = reactive({
|
||||
socketServe: socketClient.Instance,
|
||||
});
|
||||
const smsQueriesFlag = ref(false);
|
||||
const pushFlag = ref(true);
|
||||
const bottomTextRef = ref(); // 底部滚动组件引用
|
||||
// * 加载标识
|
||||
const loading = ref<boolean>(true);
|
||||
// * 时间内容
|
||||
const timeInfo: any = reactive({
|
||||
setInterval: 0,
|
||||
dateDay: "",
|
||||
dateYear: "",
|
||||
dateWeek: "",
|
||||
});
|
||||
const timeType = ref(3);
|
||||
// 适配处理
|
||||
const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw();
|
||||
// 连接webSocket客户端
|
||||
const init = () => {
|
||||
if (!dataSocket.socketServe) {
|
||||
console.error("WebSocket 客户端实例不存在");
|
||||
return;
|
||||
}
|
||||
dataSocket.socketServe.connect(new Date().getTime());
|
||||
dataSocket.socketServe.registerCallBack("message", (res: any) => {
|
||||
pushFlag.value = true;
|
||||
inquire();
|
||||
bottomTextRef.value?.updateData(res);
|
||||
});
|
||||
};
|
||||
// 打开重要告警弹框
|
||||
const drawerClick = () => {
|
||||
bottomTextRef.value?.openDrawer();
|
||||
};
|
||||
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
stopSpeak();
|
||||
|
||||
cancelLoading();
|
||||
|
||||
handleTime();
|
||||
// todo 屏幕适应
|
||||
windowDraw();
|
||||
calcRate();
|
||||
setTimeout(() => {
|
||||
store.dispatch("setConfig");
|
||||
}, 500);
|
||||
init();
|
||||
});
|
||||
const handleCurrentChange = (val: string) => {
|
||||
mapRef.value?.setIcon(val);
|
||||
};
|
||||
onUnmounted(() => {
|
||||
unWindowDraw();
|
||||
clearInterval(timeInfo.setInterval);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
dataSocket.socketServe?.closeWs();
|
||||
});
|
||||
|
||||
// methods
|
||||
// todo 处理 loading 展示
|
||||
const cancelLoading = () => {
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// todo 处理时间监听
|
||||
const handleTime = () => {
|
||||
timeInfo.setInterval = setInterval(() => {
|
||||
const date = new Date();
|
||||
timeInfo.dateDay = formatTime(date, "HH: mm: ss");
|
||||
timeInfo.dateYear = formatTime(date, "yyyy-MM-dd");
|
||||
timeInfo.dateWeek = WEEK[date.getDay()];
|
||||
}, 1000);
|
||||
};
|
||||
// todo 处理菜单点击事件
|
||||
const handleClick = (type: string) => {
|
||||
smsQueriesFlag.value = true;
|
||||
|
||||
setTimeout(() => {
|
||||
if (type === "3") {
|
||||
ConfigRef.value.open("系统配置");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
// 切换时间
|
||||
const timeChangeInfo = async () => {
|
||||
inquire();
|
||||
};
|
||||
const inquireTimer: any = ref(null);
|
||||
const inquire = async () => {
|
||||
// 清除上一次的定时器
|
||||
if (inquireTimer.value) {
|
||||
clearTimeout(inquireTimer.value);
|
||||
}
|
||||
|
||||
// 设置新的定时器,延迟300毫秒执行
|
||||
inquireTimer.value = setTimeout(async () => {
|
||||
eventStatisticsRef.value.init(); //电能质量监测终端运行状态
|
||||
endpointStatisticsRef.value.init(); //各区域终端运行状态
|
||||
mapRef.value.init(); //地图
|
||||
informationTableRef.value.init(true); //暂降事件列表
|
||||
sendTrendsRef.value.init();
|
||||
|
||||
alarmRef.value.init();
|
||||
|
||||
// 执行完毕后重置定时器变量
|
||||
inquireTimer.value = null;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
watch(store.state, (val) => {
|
||||
timeChangeInfo()
|
||||
}, {
|
||||
deep: true,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "@/assets/scss/index.scss";
|
||||
.react-right {
|
||||
width: 460px !important;
|
||||
}
|
||||
.count {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
left: 23px;
|
||||
background-color: #ff2501;
|
||||
color: #fff;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
padding: 0 3px;
|
||||
border-radius: 40%;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 25px;
|
||||
}
|
||||
.significant {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 15px;
|
||||
.count {
|
||||
top: -3px;
|
||||
left: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
}
|
||||
.react-left {
|
||||
position: absolute;
|
||||
left: 140px;
|
||||
top: 30px;
|
||||
font-size: 18px;
|
||||
line-height: 35px;
|
||||
}
|
||||
.titles {
|
||||
margin-right: 10px;
|
||||
.react-right {
|
||||
width: 50px !important;
|
||||
line-height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 35px !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user