This commit is contained in:
GGJ
2024-02-27 16:21:40 +08:00
33 changed files with 3389 additions and 433 deletions

View File

@@ -0,0 +1,18 @@
import request from '@/utils/request'
// 事件分析 获取数据
export function getRunOnlineRateData(data) {
return request({
url: "/device-boot/communicate/getRunOnlineRateData",
method: "post",
data
});
}
// 事件分析 运行状态 获取数据
export function getComFlagInfoData(data) {
return request({
url: "/device-boot/communicate/getComFlagInfoData",
method: "post",
data
});
}

View File

@@ -0,0 +1,92 @@
import request from '@/utils/request'
//ITIC SEMI 获取数据
export function getPlot(data: any) {
return request({
url: '/event-boot/monitor/getPlot',
method: 'post',
data
})
}
//电压暂降表及密度 DISDIP 获取数据
export function IEC411(data) {
return request({
url: '/event-boot/monitor/IEC411',
method: 'post',
data
})
}
//电压暂降表及密度 IEC61000 获取数据
export function IEC28(data: any) {
return request({
url: '/event-boot/monitor/IEC28',
method: 'post',
data
})
}
//电压暂降表及密度 IEC61000 获取数据
export function eventDisdip(data: any) {
return request({
url: '/event-boot/monitor/eventDisdip',
method: 'post',
data
})
}
//电压暂降表及密度 暂降密度图 获取数据
export function getCoords(data: any) {
return request({
url: '/event-boot/monitor/getCoords',
method: 'post',
data
})
}
// 暂降分布统计 左 获取数据
export function getReasonTypeTime(data: any) {
return request({
url: '/event-boot/monitor/getReasonTypeTime',
method: 'post',
data
})
}
// 暂降分布统计 右 获取数据
export function getStatistic(data: any) {
return request({
url: '/event-boot/monitor/getStatistic',
method: 'post',
data
})
}
// 暂降分布统计 右 获取数据
export function getProbabilityDistribution(data: any) {
return request({
url: '/event-boot/monitor/getProbabilityDistribution',
method: 'post',
data
})
}
// 事件分析 获取数据
export function getMonitorEventAnalyseQuery(data: any) {
return request({
url: '/event-boot/monitor/getMonitorEventAnalyseQuery',
method: 'post',
data
})
}
// 事件分析 下载
export function downloadMonitorEventWaveFile(data: any) {
return request({
url: '/event-boot/monitor/downloadMonitorEventWaveFile',
method: 'post',
data: data.lineId,
responseType: 'blob'
})
}

View File

@@ -0,0 +1,20 @@
import request from '@/utils/request'
export function downloadWaveFile(data: any) {
return request({
url: '/event-boot/transient/downloadWaveFile',
method: 'post',
data: data.lineId,
responseType: 'blob'
})
}
// 事件分析 shushiboxi 获取数据
export function getMonitorEventAnalyseWave(data:any) {
return request({
url: "/event-boot/transient/getTransientAnalyseWave",
method: "post",
data
});
}

View File

@@ -1,13 +1,14 @@
<template>
<div ref="chartRef" class="my-chart" />
<div ref='chartRef' class='my-chart' />
</template>
<script setup lang="ts">
<script setup lang='ts'>
import { onBeforeUnmount, onMounted, ref, defineExpose, watch } from 'vue'
// import echarts from './echarts'
import * as echarts from 'echarts' // 全引入
import 'echarts-gl'
import 'echarts/lib/component/dataZoom'
import { color, gradeColor } from './color'
const chartRef = ref<HTMLDivElement>()
@@ -24,7 +25,7 @@ const initChart = () => {
chart?.dispose()
chart = echarts.init(chartRef.value as HTMLDivElement)
chart.setOption({
const options = {
title: {
left: 'center',
textStyle: {
@@ -35,7 +36,6 @@ const initChart = () => {
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
@@ -66,56 +66,65 @@ const initChart = () => {
itemHeight: 10,
...(props.options.legend || null)
},
grid: {
top: '50px',
left: '10px',
right: '60px',
bottom: '40px',
bottom: props.options.options?.dataZoom === null ? '10px' : '40px',
containLabel: true
},
xAxis: handlerXAxis(),
yAxis: handlerYAxis(),
dataZoom: [
xAxis: props.options.xAxis ? handlerXAxis() : null,
yAxis: props.options.yAxis ? handlerYAxis() : null,
dataZoom: props.options.dataZoom || [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100,
...(props.options.dataZoom || null)
end: 100
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100,
...(props.options.dataZoom || null)
end: 100
}
],
color: [
...(props.options.color || ''),
'#07CCCA ',
'#00BFF5',
'#FFBF00',
'#77DA63',
'#D5FF6B',
'#Ff6600',
'#FF9100',
'#5B6E96',
'#66FFCC',
'#B3B3B3'
],
color: props.options.color || color,
series: props.options.series,
...props.options.options
})
}
handlerBar(options)
// 处理柱状图
chart.setOption(options)
setTimeout(() => {
chart.resize()
},0)
}, 0)
}
const handlerBar = (options: any) => {
if (Array.isArray(options.series)) {
options.series.forEach((item: any) => {
if (item.type === 'bar') {
item.barMinHeight = 10
item.itemStyle = Object.assign(
{
color: (params: any) => {
if (params.value == 0 || params.value == 3.14159) {
return '#ccc'
} else {
return color[params.seriesIndex]
}
}
},
item.itemStyle
)
}
})
}
}
const handlerYAxis = () => {
let temp = {
type: 'value',
nameTextStyle: {
color: '#000'
},
@@ -175,8 +184,8 @@ const handlerXAxis = () => {
if (Array.isArray(props.options.xAxis)) {
return props.options.xAxis.map((item: any) => {
return {
...item,
...temp
...temp,
...item
}
})
} else {
@@ -203,7 +212,7 @@ watch(
)
</script>
<style lang="scss" scoped>
<style lang='scss' scoped>
.my-chart {
height: 100%;
width: 100%;

View File

@@ -0,0 +1,13 @@
export const color = [
'#07CCCA',
'#00BFF5',
'#FFBF00',
'#77DA63',
'#D5FF6B',
'#Ff6600',
'#FF9100',
'#5B6E96',
'#66FFCC',
'#B3B3B3'
]
export const gradeColor = ['#339966', '#FFCC33', '#CC0000']

View File

@@ -1,73 +0,0 @@
<template>
<Tree
ref="treRef"
@check-change="handleCheckChange"
:default-checked-keys="defaultCheckedKeys"
:show-checkbox="props.showCheckbox"
:data="tree"
/>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue'
import Tree from '../index.vue'
import { getDeviceTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config'
defineOptions({
name: 'govern/deviceTree'
})
const props = withDefaults(
defineProps<{
showCheckbox?: boolean
defaultCheckedKeys?: any
}>(),
{
showCheckbox: false,
defaultCheckedKeys: []
}
)
const emit = defineEmits(['init', 'checkChange'])
const config = useConfig()
const tree = ref()
const treRef = ref()
getDeviceTree().then(res => {
let arr: any[] = []
res.data.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
arr.push(item3)
})
})
})
tree.value = res.data
nextTick(() => {
if (arr.length) {
treRef.value.treeRef.setCurrentKey(arr[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr[0]
})
} else {
emit('init')
}
})
})
const handleCheckChange = (data: any, checked: any, indeterminate: any) => {
emit('checkChange', {
data,
checked,
indeterminate
})
}
</script>

View File

@@ -1,29 +0,0 @@
<template>
<Tree ref="treRef" :data="tree" />
</template>
<script setup lang="ts">
import { getMarketList } from '@/api/user-boot/user'
import Tree from '../index.vue'
import { useConfig } from '@/stores/config'
import { ref, reactive, nextTick } from 'vue'
const config = useConfig()
const tree = ref()
const treRef = ref()
const emit = defineEmits(['selectUser'])
getMarketList().then((res: any) => {
if (res.code === 'A0000') {
tree.value = res.data.map((item: any) => {
return {
...item,
icon: 'el-icon-User',
color: 'royalblue'
}
})
emit('selectUser', tree.value[0])
nextTick(() => {
treRef.value.treeRef.setCurrentKey(tree.value[0].id)
})
}
})
</script>
<style lang="scss" scoped></style>

View File

@@ -1,52 +0,0 @@
<template>
<Tree ref="treRef" :data="tree" />
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue'
import Tree from '../index.vue'
import { getLineTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config'
defineOptions({
name: 'govern/deviceTree'
})
const emit = defineEmits(['init'])
const config = useConfig()
const tree = ref()
const treRef = ref()
getLineTree().then(res => {
let arr: any[] = []
res.data.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-LocationFilled'
arr.push(item4)
})
})
})
})
tree.value = res.data
nextTick(() => {
if (arr.length) {
treRef.value.treeRef.setCurrentKey(arr[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr[0]
})
} else {
emit('init')
}
})
})
</script>

View File

@@ -1,50 +1,50 @@
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="transition: all 0.3s; overflow: hidden">
<div :style="{ width: menuCollapse ? '40px' : props.width }" style='transition: all 0.3s; overflow: hidden'>
<Icon
v-show="menuCollapse"
@click="onMenuCollapse"
v-show='menuCollapse'
@click='onMenuCollapse'
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
size='18'
class='fold ml10 mt20 menu-collapse'
style='cursor: pointer'
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<el-input v-model="filterText" placeholder="请输入内容" clearable>
<div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'>
<div style='display: flex; align-items: center' class='mb10'>
<el-input v-model='filterText' placeholder='请输入内容' clearable>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
<Icon name='el-icon-Search' style='font-size: 16px' />
</template>
</el-input>
<Icon
@click="onMenuCollapse"
@click='onMenuCollapse'
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 menu-collapse"
style="cursor: pointer"
size='18'
class='fold ml10 menu-collapse'
style='cursor: pointer'
v-if='props.canExpand'
/>
</div>
<el-tree
style="flex: 1; overflow: auto"
ref="treeRef"
:props="defaultProps"
v-bind="$attrs"
style='flex: 1; overflow: auto'
ref='treeRef'
:props='defaultProps'
highlight-current
default-expand-all
:filter-node-method="filterNode"
node-key="id"
:filter-node-method='filterNode'
node-key='id'
v-bind='$attrs'
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<template #default='{ node, data }'>
<span class='custom-tree-node'>
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
:name='data.icon'
style='font-size: 16px'
:style='{ color: data.color }'
v-if='data.icon'
/>
<span style="margin-left: 4px">{{ node.label }}</span>
<span style='margin-left: 4px'>{{ node.label }}</span>
</span>
</template>
</el-tree>
@@ -52,7 +52,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang='ts' setup>
import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus'
import { ref, watch } from 'vue'
@@ -60,6 +60,7 @@ import { ref, watch } from 'vue'
defineOptions({
name: 'govern/tree'
})
interface Props {
width?: string
canExpand?: boolean
@@ -91,7 +92,7 @@ const treeRef = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef })
</script>
<style lang="scss" scoped>
<style lang='scss' scoped>
.cn-tree {
flex-shrink: 0;
display: flex;
@@ -100,16 +101,20 @@ defineExpose({ treeRef })
padding: 10px;
height: 100%;
width: 100%;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.menu-collapse {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;

View File

@@ -1,18 +1,26 @@
<template>
<div style='height: 100%;width: 100%;display: flex;flex-direction: column'>
<el-select v-model='formData.statisticalType' placeholder='请选择' style='min-width: unset;padding: 10px 10px 0'
@change='loadData'>
<el-option v-for='item in classificationData' :key='item.id' :label='item.name'
:value='item.id'></el-option>
<div class='point-tree' style='height: 100%; width: 100%; display: flex; flex-direction: column'>
<el-select
v-model='formData.statisticalType'
placeholder='请选择'
style='min-width: unset; padding: 10px 10px 0'
@change='loadData'
>
<el-option
v-for='item in classificationData'
:key='item.id'
:label='item.name'
:value='item.id'
></el-option>
</el-select>
<div style='flex: 1;overflow: hidden'>
<Tree ref='treRef' :data='tree' style='width: 100%;height: 100%' :canExpand='false' />
<div style='flex: 1; overflow: hidden'>
<Tree ref='treRef' :data='tree' style='width: 100%; height: 100%' :canExpand='false' v-bind='$attrs' />
</div>
</div>
</template>
<script lang='ts' setup>
import { ref, nextTick } from 'vue'
import { nextTick, onMounted, ref, useAttrs } from 'vue'
import Tree from '../index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useDictData } from '@/stores/dictData'
@@ -23,11 +31,11 @@ defineOptions({
name: 'pms/pointTree'
})
const emit = defineEmits(['init'])
const attrs = useAttrs()
const adminInfo = useAdminInfo()
const dictData = useDictData()
const config = useConfig()
const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Type'])
console.log(classificationData)
const tree = ref()
const treRef = ref()
const formData = ref({
@@ -40,13 +48,12 @@ const formData = ref({
statisticalType: classificationData[0].id,
scale: null
})
console.log(formData)
const loadData = () => {
let form = JSON.parse(JSON.stringify(formData.value))
form.statisticalType = classificationData.find((item: any) => item.id == form.statisticalType)
let nodeKey = ''
getTerminalTreeForFive(form).then(res => {
console.log(res)
let arr: any[] = []
res.data.forEach((item: any) => {
item.icon = 'fa-solid fa-synagogue'
item.color = config.getColorVal('elementUiPrimary')
@@ -59,7 +66,11 @@ const loadData = () => {
item3.children.forEach((item4: any) => {
item4.icon = 'fa-solid fa-tower-observation'
item4.color = config.getColorVal('elementUiPrimary')
item4.children.forEach((item5: any) => {
item4.children.forEach((item5: anyObj) => {
if ((!attrs['current-node-key']) && !nodeKey) {
nodeKey = item5.id
emit('init', item5)
}
item5.icon = 'fa-solid fa-location-dot'
item5.color = config.getColorVal('elementUiPrimary')
if (item5.comFlag === 0) {
@@ -75,42 +86,13 @@ const loadData = () => {
})
})
tree.value = res.data
if (nodeKey) {
nextTick(() => {
treRef.value.treeRef.setCurrentKey(nodeKey)
treRef.value.treeRef.setExpandedKeys(nodeKey)
})
}
})
}
loadData()
// getTerminalTreeForFive().then(res => {
// let arr: any[] = []
// res.data.forEach((item: any) => {
// item.icon = 'el-icon-HomeFilled'
// item.color = config.getColorVal('elementUiPrimary')
// item.children.forEach((item2: any) => {
// item2.icon = 'el-icon-List'
// item.color = config.getColorVal('elementUiPrimary')
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Platform'
// item3.color = config.getColorVal('elementUiPrimary')
// if (item3.comFlag === 1) {
// item3.color = '#e26257 !important'
// }
// item3.children.forEach((item4: any) => {
// item4.icon = 'el-icon-LocationFilled'
// arr.push(item4)
// })
// })
// })
// })
// tree.value = res.data
// nextTick(() => {
// if (arr.length) {
// treRef.value.treeRef.setCurrentKey(arr[0].id)
// // 注册父组件事件
// emit('init', {
// level: 2,
// ...arr[0]
// })
// } else {
// emit('init')
// }
// })
// })
</script>

View File

@@ -0,0 +1,132 @@
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }"
style='transition: all 0.3s; overflow: hidden'>
<Icon
v-show='menuCollapse'
@click='onMenuCollapse'
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size='18'
class='fold ml10 mt20 menu-collapse'
style='cursor: pointer'
/>
<div id='tree-index' class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'>
<div style='display: flex; align-items: center' class='mb10'>
<el-input v-model='filterText' placeholder='请输入内容' clearable>
<template #prefix>
<Icon name='el-icon-Search' style='font-size: 16px' />
</template>
</el-input>
<Icon
@click='onMenuCollapse'
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size='18'
class='fold ml10 menu-collapse'
style='cursor: pointer'
v-if='props.canExpand'
/>
</div>
<el-tree-v2
style='flex: 1; overflow: auto'
ref='treeRef'
:props='defaultProps'
highlight-current
default-expand-all
:filter-node-method='filterNode'
:height='treeHeight'
v-bind='$attrs'
>
<template #default='{ node, data }'>
<span class='custom-tree-node'>
<Icon
:name='data.icon'
style='font-size: 16px'
:style='{ color: data.color }'
v-if='data.icon'
/>
<span style='margin-left: 4px'>{{ node.label }}</span>
</span>
</template>
</el-tree-v2>
</div>
</div>
</template>
<script lang='ts' setup>
import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus'
import { onMounted, ref, watch } from 'vue'
defineOptions({
name: 'govern/tree'
})
interface Props {
width?: string
canExpand?: boolean
}
const props = withDefaults(defineProps<Props>(), {
width: '280px',
canExpand: true
})
const treeHeight = ref(0)
const { proxy } = useCurrentInstance()
const menuCollapse = ref(false)
const filterText = ref('')
const defaultProps = {
label: 'name',
value: 'id'
}
watch(filterText, val => {
treeRef.value!.filter(val)
})
const onMenuCollapse = () => {
menuCollapse.value = !menuCollapse.value
proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
}
const filterNode = (value: string, data: any) => {
if (!value) return true
return data.name.includes(value)
}
const treeRef = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef })
onMounted(
() => {
let dom = document.getElementById('tree-index')
if (dom) {
treeHeight.value = dom.offsetHeight - 68
}
}
)
</script>
<style lang='scss' scoped>
.cn-tree {
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
height: 100%;
width: 100%;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.menu-collapse {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;
}
</style>

View File

@@ -17,7 +17,6 @@ import { ElDialog } from 'element-plus'
import BaiduMap from 'vue-baidu-map-3x'
import ExcelJS from 'exceljs'
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
// 方式1NPM 安装,注入 ExcelJS 对象
VXETable.use(VXETablePluginExportXLSX, {
ExcelJS

View File

@@ -1 +1,2 @@
dialog 弹框标准模版
dialog 弹框标准模版
table 表格模版

175
src/template/table.vue Normal file
View File

@@ -0,0 +1,175 @@
<template>
<div class='default-main'>
<!-- 表头 -->
<TableHeader date-picker>
<template v-slot:select>
<el-form-item label='关键词:'>
<el-input
style='width: 240px'
v-model='tableStore.table.params.searchValue'
clearable
placeholder='仅根据用户名/登录名'
/>
</el-form-item>
</template>
<template v-slot:operation>
<el-button :icon='Plus' type='primary' @click='addUser'>添加</el-button>
</template>
</TableHeader>
<!-- 表格 -->
<Table ref='tableRef' />
<!-- 弹框 -->
<PopupEdit ref='popupEdit' />
</div>
</template>
<script setup lang='ts'>
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, provide, defineOptions } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import PopupEdit from './dialog.vue'
import { mainHeight } from '@/utils/layout'
// 注意名字不要重复若要保持页面存活名字需要和路由admin后面的字符保持一致
defineOptions({
name: 'auth/userlist'
})
const popupEdit = ref()
const tableStore = new TableStore({
// 若页面表格高度需要调整请修改publicHeight(内容区域除表格外其他内容的高度)
// publicHeight: 60,
url: '/user-boot/user/list',
method: 'POST',
column: [
{ title: '用户名称', field: 'name', minWidth: '130' },
{ title: '登录名', field: 'loginName', minWidth: '130' },
{ title: '角色', field: 'roleName', minWidth: '130' },
{ title: '部门', field: 'deptName', minWidth: '200' },
{ title: '电话', field: 'phoneShow', minWidth: '100' },
{ title: '注册时间', field: 'registerTime', minWidth: '130' },
{ title: '登录时间', field: 'loginTime', minWidth: '130' },
{ title: '类型', field: 'casualUserName', minWidth: '80' },
{
title: '状态',
field: 'state',
width: '100',
render: 'tag',
custom: {
0: 'danger',
1: 'success',
2: 'warning',
3: 'warning',
4: 'info',
5: 'danger'
},
replaceValue: {
0: '注销',
1: '正常',
2: '锁定',
3: '待审核',
4: '休眠',
5: '密码过期'
}
},
{
title: '操作',
width: '180',
render: 'buttons',
fixed: 'right',
buttons: [
{
name: 'edit',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
}
},
{
name: 'edit',
title: '修改密码',
type: 'primary',
icon: 'el-icon-Lock',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputType: 'password'
}).then(({ value }) => {
})
}
},
{
name: 'edit',
title: '激活',
type: 'primary',
icon: 'el-icon-Open',
render: 'basicButton',
disabled: row => {
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
},
click: row => {
}
},
{
name: 'edit',
title: '注销',
type: 'danger',
icon: 'el-icon-SwitchButton',
render: 'basicButton',
disabled: row => {
return row.state !== 1 && row.state !== 3
},
click: row => {
}
}
]
}
],
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {
item.deptName = item.deptName || '/'
item.phoneShow = item.phone || '/'
item.roleName = item.role.length ? item.role : '/'
switch (item.casualUser) {
case 0:
item.casualUserName = '临时用户'
break
case 1:
item.casualUserName = '长期用户'
break
default:
item.casualUserName = '/'
break
}
})
}
})
// 注入到子组件
provide('tableStore', tableStore)
// 默认参数 参数多的话可以使用Object.assign方法
tableStore.table.params.searchState = 1
tableStore.table.params.searchValue = ''
tableStore.table.params.casualUser = -1
tableStore.table.params.orderBy = ''
onMounted(() => {
// 加载数据
tableStore.index()
})
// 弹框
const addUser = () => {
popupEdit.value.open('新增用户')
}
</script>

View File

@@ -3,6 +3,7 @@ import createAxios from '@/utils/request'
import { requestPayload } from '@/utils/request'
import { Method } from 'axios'
import { mainHeight } from '@/utils/layout'
interface TableStoreParams {
url: string
pk?: string
@@ -39,7 +40,7 @@ export default class TableStore {
loadCallback: null,
resetCallback: null,
beforeSearchFun: null,
height: mainHeight(20 + (this.showPage ? 58 : 0)).height as string,
height: 0,
publicHeight: 0
})
@@ -55,6 +56,7 @@ export default class TableStore {
this.table.loadCallback = options.loadCallback || null
this.table.beforeSearchFun = options.beforeSearchFun || null
Object.assign(this.table.params, options.params)
this.table.height = mainHeight(20 + (this.showPage ? 58 : 0) + this.table.publicHeight).height as string
}
index() {

View File

@@ -23,7 +23,7 @@ const tableStore = new TableStore({
method: 'POST',
url: '/user-boot/user/checkUserList',
column: [
// { width: '60', type: 'checkbox' },
{ width: '60', type: 'checkbox' },
{ title: '名称', field: 'name' },
{ title: '登录名', field: 'loginName' },
{ title: '角色', field: 'roleName' },

View File

@@ -1,10 +1,351 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%' v-loading='loading'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<el-descriptions
class='mt2'
direction='vertical'
:column='4'
border
>
<el-descriptions-item align='center' label='名称'>{{ data.name }}</el-descriptions-item>
<el-descriptions-item align='center' label='事件总数'>{{ data.gs }}</el-descriptions-item>
<el-descriptions-item align='center' label='可容忍'>{{ data.krr }}</el-descriptions-item>
<el-descriptions-item align='center' label='不可容忍'> {{ data.bkrr }}</el-descriptions-item>
</el-descriptions>
<div style='flex: 1;' class='mt10'>
<my-echart :options='options' />
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getPlot } from '@/api/event-boot/monitor'
const datePickerRef = ref()
const loading = ref(true)
const monitoringPoint = useMonitoringPoint()
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: ''
})
const data = reactive({
name: '事件个数',
gs: 0,
krr: 0,
bkrr: 0
})
const options = ref({})
const init = () => {
loading.value = true
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
getPlot(formData).then(
(res: any) => {
const gongData = gongfunction(res.data.voltageToleranceCurveDataList)
data.gs = res.data.voltageToleranceCurveDataList.length
data.krr = gongData.pointI.length
data.bkrr = gongData.pointIun.length
console.log(gongData)
options.value = {
// backgroundColor: "#f9f9f9", //地图背景色深蓝
title: {
// text: `ITIC曲线(总统计:${gongData.pointI.length + gongData.pointIun.length}个,可容忍:${gongData.pointI.length}个,不可容忍:${gongData.pointIun.length}个)`
text: `ITIC曲线`
},
legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
x: 'left'
},
tooltip: {
trigger: 'item',
show: true,
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
borderWidth: 0,
formatter: function(a: any) {
var relVal = ''
relVal =
'<font style=\'color:' +
'\'>发生时间:' +
a.value[2] +
'</font><br/>'
relVal +=
'<font style=\'color:' +
'\'>持续时间:' +
a.value[0] +
's</font><br/>'
relVal +=
'<font style=\'color:' +
'\'>特征幅值:' +
a.value[1].toFixed(2) +
'%</font>'
return relVal
}
},
xAxis: [
{
type: 'log',
min: 0.001,
max: 1000,
splitLine: {
show: false
},
name: 's'
}
],
yAxis: [
{
type: 'value',
splitNumber: 10,
minInterval: 3,
name: '%'
}
],
options: {
dataZoom: null,
series: [
{
name: '上限',
type: 'line',
data: [
[0.001, 200],
[0.003, 140],
[0.003, 120],
[0.5, 120],
[0.5, 110],
[10, 110],
[1000, 110]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '下限',
type: 'line',
data: [
[0.02, 0],
[0.02, 70],
[0.5, 70],
[0.5, 80],
[10, 80],
[10, 90],
[1000, 90]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
data: gongData.pointI
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
data: gongData.pointIun
}
]
}
}
nextTick(() => {
loading.value = false
})
}
)
}
function gongfunction(arr: any) {
let standI = 0
let unstandI = 0
let standF = 0
let unstandF = 0
let total = 0
let pointIun = []
let pointI = []
let pointF = []
let pointFun = []
total = arr.length
if (total == 0) {
} else {
for (let i = 0; i < arr.length; i++) {
let point = []
let xx = arr[i].persistTime
let yy = arr[i].eventValue
let time = arr[i].time
let eventId = arr[i].eventId
// let index =arr[i].eventDetailIndex;
point = [xx, yy, time, eventId]
if (xx <= 0.003) {
let line = 0
line = 250 - 30000 * xx
if (yy > line) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.02) {
if (yy > 120) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.5) {
if (yy > 120 || yy < 70) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 10) {
if (yy > 110 || yy < 80) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else {
if (yy > 110 || yy < 90) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
}
if (xx < 0.05) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else if (xx < 0.2) {
if (yy > 50) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
} else if (xx < 0.5) {
if (yy > 70) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
} else {
if (yy > 80) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
}
}
}
return {
standI,
unstandI,
pointI,
pointIun,
standF,
unstandF,
pointF,
pointFun
}
}
onMounted(() => {
init()
})
</script>
<style></style>

View File

@@ -1,10 +1,337 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<el-descriptions
class='mt2'
direction='vertical'
:column='4'
border
>
<el-descriptions-item align='center' label='名称'>{{ data.name }}</el-descriptions-item>
<el-descriptions-item align='center' label='事件总数'>{{ data.gs }}</el-descriptions-item>
<el-descriptions-item align='center' label='可容忍'>{{ data.krr }}</el-descriptions-item>
<el-descriptions-item align='center' label='不可容忍'> {{ data.bkrr }}</el-descriptions-item>
</el-descriptions>
<div style='flex: 1;' class='mt10'>
<my-echart :options='options' />
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getPlot } from '@/api/event-boot/monitor'
const datePickerRef = ref()
const monitoringPoint = useMonitoringPoint()
const loading = ref(true)
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: ''
})
const data = reactive({
name: '事件个数',
gs: 0,
krr: 0,
bkrr: 0
})
const options = ref({})
const init = () => {
loading.value = true
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
getPlot(formData).then(
(res: any) => {
const gongData = gongfunction(res.data.voltageToleranceCurveDataList)
data.gs = res.data.voltageToleranceCurveDataList.length
data.krr = gongData.pointI.length
data.bkrr = gongData.pointIun.length
console.log(gongData)
options.value = {
// backgroundColor: "#f9f9f9", //地图背景色深蓝
title: {
text: `SEMI F47曲线`
},
legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
x: 'left'
},
tooltip: {
trigger: 'item',
show: true,
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
borderWidth: 0,
formatter: function(a: any) {
var relVal = ''
relVal =
'<font style=\'color:' +
'\'>发生时间:' +
a.value[2] +
'</font><br/>'
relVal +=
'<font style=\'color:' +
'\'>持续时间:' +
a.value[0] +
's</font><br/>'
relVal +=
'<font style=\'color:' +
'\'>特征幅值:' +
a.value[1].toFixed(2) +
'%</font>'
return relVal
}
},
xAxis: [
{
type: 'log',
min: 0.001,
max: 1000,
splitLine: {
show: false
},
name: 's'
}
],
yAxis: [
{
type: 'value',
max: function(value: any) {
return value.max + 20
},
splitNumber: 10,
minInterval: 0.1,
name: '%'
}
],
options: {
dataZoom: null,
series: [
{
name: '边界线',
type: 'line',
data: [
[0.05, 0],
[0.05, 50],
[0.2, 50],
[0.2, 70],
[0.5, 70],
[0.5, 80],
[10, 80],
[1000, 80]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
data: gongData.pointI
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
data: gongData.pointIun
}
]
}
}
nextTick(() => {
loading.value = false
})
}
)
}
function gongfunction(arr: any) {
let standI = 0
let unstandI = 0
let standF = 0
let unstandF = 0
let total = 0
let pointIun = []
let pointI = []
let pointF = []
let pointFun = []
total = arr.length
if (total == 0) {
} else {
for (let i = 0; i < arr.length; i++) {
let point = []
let xx = arr[i].persistTime
let yy = arr[i].eventValue
let time = arr[i].time
let eventId = arr[i].eventId
// let index =arr[i].eventDetailIndex;
point = [xx, yy, time, eventId]
if (xx <= 0.003) {
let line = 0
line = 250 - 30000 * xx
if (yy > line) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.02) {
if (yy > 120) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 0.5) {
if (yy > 120 || yy < 70) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else if (xx <= 10) {
if (yy > 110 || yy < 80) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
} else {
if (yy > 110 || yy < 90) {
unstandI++
pointIun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
} else {
standI++
pointI.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
}
}
if (xx < 0.05) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else if (xx < 0.2) {
if (yy > 50) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
} else if (xx < 0.5) {
if (yy > 70) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
} else {
if (yy > 80) {
standF++
pointF.push({
value: point,
itemStyle: { normal: { color: 'green' } }
})
} else {
unstandF++
pointFun.push({
value: point,
itemStyle: { normal: { color: 'red' } }
})
}
}
}
}
return {
standI,
unstandI,
pointI,
pointIun,
standF,
unstandF,
pointF,
pointFun
}
}
onMounted(() => {
init()
})
</script>
<style></style>

View File

@@ -1,10 +1,172 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<div style='flex: 1;' class='mt10'>
<my-echart :options='options' />
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getProbabilityDistribution } from '@/api/event-boot/monitor'
const datePickerRef = ref()
const monitoringPoint = useMonitoringPoint()
const loading = ref(true)
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: ''
})
const options = ref({})
const init = () => {
loading.value = true
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
getProbabilityDistribution(formData).then(
(res: any) => {
let data = res.data
let sisttime = data.sisttime
let persisttime = data.persisttime
options.value = {
backgroundColor: '#fff', //背景色,
title: {
text: '持续时间的概率分布函数',
x: 'center'
},
legend: {
show: true,
left: 10,
data: ['概率分布', '占比'],
textStyle: {
rich: {
a: {
verticalAlign: 'middle'
}
},
padding: [2, 0, 0, 0] //[上、右、下、左]
}
},
tooltip: {
//提示框组件
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
borderWidth: 0
},
calculable: true,
xAxis: [
{
type: 'category',
name: '暂降幅值',
nameGap: 10,
nameTextStyle: {
fontSize: 12
},
data: ['0.01', '0.1', '0.25', '0.5', '1', '3', '20', '60', '180']
}
],
yAxis: [
{
type: 'value',
name: '概率分布',
nameTextStyle: {
fontSize: 15
},
axisLabel: {
formatter: '{value}%'
},
axisLine: {
show: true
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
type: 'dashed',
opacity: 0.5
}
}
},
{
type: 'value',
name: '占比',
nameTextStyle: {
fontSize: 15
},
axisLine: {
show: true
},
splitLine: {
lineStyle: {
type: 'dashed',
opacity: 0.5
}
}
}
],
series: [
{
name: '概率分布',
type: 'line',
data: sisttime,
itemStyle: {
normal: { show: true }
}
},
{
name: '占比',
type: 'bar',
data: persisttime,
barWidth: 30,
itemStyle: {
normal: { show: true }
}
}
],
options: {
dataZoom: null
}
}
nextTick(() => {
loading.value = false
})
}
)
}
onMounted(() => {
init()
})
</script>
<style></style>

View File

@@ -1,10 +1,298 @@
<template>
<div class='default-main'>
<div v-loading='loading' class='dianyazanjiangbaojimidu'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<div class='mt10 dianyazanjiang'>
<div class='first'>
<div class='mb10'>DISDIP表格(国际发配电联盟UNIPEDE)</div>
<div style='flex: 1;overflow: hidden'>
<vxe-table v-bind='defaultAttribute' height='100%' size='mini' :data='firstData'>
<vxe-colgroup title='剩余电压' field='name' width='80px'></vxe-colgroup>
<vxe-colgroup title='持续事件'>
<vxe-column field='twentyMs' title='20ms'></vxe-column>
<vxe-column field='oneHundredMs' title='100ms'></vxe-column>
<vxe-column field='fiveHundredMs' title='500ms'></vxe-column>
<vxe-column field='oneS' title='1s'></vxe-column>
<vxe-column field='threeS' title='2s'></vxe-column>
<vxe-column field='twentyS' title='20s'></vxe-column>
<vxe-column field='sixtyS' title='60s'></vxe-column>
<vxe-column field='oneEightyS' title='180s'></vxe-column>
</vxe-colgroup>
</vxe-table>
</div>
</div>
<div class='second'>
<div class='mb10'>EC61000-4-11(用电终端的电压暂降抗度)</div>
<div style='flex: 1;overflow: hidden'>
<vxe-table v-bind='defaultAttribute' height='100%' size='mini' :data='secondData'>
<vxe-colgroup title='剩余电压' field='name' width='80px'></vxe-colgroup>
<vxe-colgroup title='持续事件'>
<vxe-column field='tenTwentyMs' title='10-20ms'></vxe-column>
<vxe-column field='twentyOneHundredMs' title='20-100ms'></vxe-column>
<vxe-column field='zeroPiontOneTwoS' title='0.1-0.2s'></vxe-column>
<vxe-column field='zeroPiontFive1S' title='0.2-0.5s'></vxe-column>
<vxe-column field='zeroPiontTwoFiveS' title='0.5-1s'></vxe-column>
<vxe-column field='role' title='>1s'></vxe-column>
</vxe-colgroup>
</vxe-table>
</div>
</div>
<div class='third'>
<div class='mb10'>IEC61000-2-8(公共用电暂降测量统计)</div>
<div style='flex: 1;overflow: hidden'>
<vxe-table v-bind='defaultAttribute' height='100%' size='mini' :data='thirdData'>
<vxe-colgroup title='剩余电压' field='name' width='120px'></vxe-colgroup>
<vxe-colgroup title='持续事件'>
<vxe-column field='q' title='0.01-0.1s' align='center'></vxe-column>
<vxe-column field='w' title='0.1-0.25s' align='center'></vxe-column>
<vxe-column field='e' title='0.25-0.5s' align='center'></vxe-column>
<vxe-column field='r' title='0.5-1s' align='center'></vxe-column>
<vxe-column field='t' title='1-3s' align='center'></vxe-column>
<vxe-column field='y' title='3-20s' align='center'></vxe-column>
<vxe-column field='u' title='20-60s' align='center'></vxe-column>
<vxe-column field='i' title='60-180s' align='center'></vxe-column>
</vxe-colgroup>
</vxe-table>
</div>
</div>
<div class='charts' id='charts'>
<MyEchart :options='options' />
</div>
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { eventDisdip, getCoords, IEC28, IEC411 } from '@/api/event-boot/monitor'
import { defaultAttribute } from '@/components/table/defaultAttribute'
const datePickerRef = ref()
const loading = ref(true)
const monitoringPoint = useMonitoringPoint()
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: ''
})
const options = ref({})
const firstData = ref([])
const secondData = ref([])
const thirdData = ref([])
const chartsData = ref([])
const init = () => {
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
loading.value = true
Promise.all([eventDisdip(formData), IEC411(formData), IEC28(formData), getCoords(formData)]).then(res => {
firstData.value = res[0].data
secondData.value = res[1].data
thirdData.value = res[2].data
chartsData.value = res[3].data
options.value = {
options: {
xAxis: null,
yAxis: null,
dataZoom: null,
backgroundColor: '#fff',
tooltip: {
trigger: 'axis'
},
title: {
text: '暂降密度图',
x: 'center'
},
toolbox: {
show: true,
feature: {
// dataView: { show: true },
// dataZoom: { show: true },
//restore: { show: true },
// saveAsImage: { show: true },
myFull: {
show: true,
title: '全屏查看',
icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
onclick: () => {
let element = document.getElementById('charts') as HTMLElement
// 全屏,如果已经全屏,则退出全屏
if (document.fullscreenElement) {
if (document.exitFullscreen) {
document.exitFullscreen()
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen()
}
}
}
}
}
},
visualMap: {
max: 20,
show: false,
inRange: {
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
}
},
xAxis3D: {
type: 'category',
name: '剩余电压(%)',
data: ['0-10', '10-20', '20-30', '30-40', '40-50', '50-60', '60-70', '70-80', '80-90', '90-100'],
axisLine: {
lineStyle: {
color: '#111'
}
},
axisLabel: {
color: '#111'
}
},
yAxis3D: {
type: 'category',
name: '持续时间(cyc)',
data: ['1cyc', '2cyc', '3cyc', '4cyc', '5cyc', '6~10cyc', '10~20cyc', '20~30cyc', '30~60cyc'],
nameTextStyle: {
color: '#111'
},
axisLine: {
show: true,
lineStyle: {
color: '#111'
}
},
axisLabel: {
color: '#111'
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: ['#111'],
type: 'dashed',
opacity: 0.5
}
}
},
zAxis3D: {
type: 'value',
splitNumber: 10,
minInterval: 10,
name: '次数'
},
grid3D: {
viewControl: {
projection: 'perspective',
distance: 250
},
boxWidth: 200,
boxDepth: 80,
light: {
main: {
intensity: 1.2
},
ambient: {
intensity: 0.3
}
}
},
series: [
{
type: 'bar3D',
data: chartsData.value.map(function(item: any) {
return {
value: [item['x'], item['y'], item['z']]
}
}),
shading: 'realistic',
label: {
show: false,
textStyle: {
fontSize: 16,
borderWidth: 1
}
},
itemStyle: {
opacity: 1
},
emphasis: {
label: {
textStyle: {
fontSize: 20,
color: '#900'
}
},
itemStyle: {
color: '#900'
}
}
}
]
}
}
loading.value = false
})
}
onMounted(() => {
init()
})
</script>
<style></style>
<style lang='scss'>
.dianyazanjiangbaojimidu {
display: flex;
flex-direction: column;
height: 100%;
overflow: scroll;
.dianyazanjiang {
flex: 1;
min-width: 1200px;
min-height: 800px;
display: grid;
grid-template-areas:
'first charts'
'second charts'
'third third '
'third third ';
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.first {
grid-area: first;
display: flex;
flex-direction: column;
overflow: hidden;
}
.second {
grid-area: second;
display: flex;
flex-direction: column;
overflow: hidden;
}
.third {
grid-area: third;
display: flex;
flex-direction: column;
overflow: hidden;
}
.charts {
grid-area: charts;
overflow: hidden;
}
}
}
</style>

View File

@@ -1,20 +1,51 @@
<template>
<div class='default-main'>
<el-tabs v-model='activeName' type='border-card' class='demo-tabs'>
<el-tab-pane label='导航' name='1'>
</el-tab-pane>
<el-tab-pane label='事件统计' name='2'>
</el-tab-pane>
<el-tab-pane label='事件分析' name='3'>
</el-tab-pane>
<el-tab-pane label='运行情况' name='4'>
</el-tab-pane>
</el-tabs>
</div>
<el-tabs v-model='activeName' type='border-card' class='event-statistics' tab-position='left' :style='height'>
<el-tab-pane lazy label='ITIC曲线分析' name='1'>
<ITICquxianfenxi />
</el-tab-pane>
<el-tab-pane lazy label='SEMI F47 分析' name='2'>
<SEMIF47fenxi />
</el-tab-pane>
<el-tab-pane lazy label='电压暂降表及密度' name='3'>
<Dianyazanjiangbiaojimidu />
</el-tab-pane>
<el-tab-pane lazy label='暂降分布统计' name='4'>
<Zanjiangfenbutongji />
</el-tab-pane>
<el-tab-pane lazy label='暂降幅值概率分布' name='5'>
<Zanjiangfuzhigailvfenbu />
</el-tab-pane>
<el-tab-pane lazy label='持续时间概率分布' name='6'>
<Chixushijiangailvfenbu />
</el-tab-pane>
</el-tabs>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { mainHeight } from '@/utils/layout'
import ITICquxianfenxi from './ITICquxianfenxi/index.vue'
import SEMIF47fenxi from './SEMIF47fenxi/index.vue'
import Dianyazanjiangbiaojimidu from './dianyazanjiangbiaojimidu/index.vue'
import Zanjiangfenbutongji from './zanjiangfenbutongji/index.vue'
import Zanjiangfuzhigailvfenbu from './zanjiangfuzhigailvfenbu/index.vue'
import Chixushijiangailvfenbu from './chixushijiangailvfenbu/index.vue'
const activeName = ref('1')
const height = mainHeight(84)
</script>
<style></style>
<style lang='scss'>
.event-statistics {
.el-tabs__header.is-left {
margin-right: 0;
}
.el-tabs__content {
height: 100%;
.el-tab-pane {
height: 100%;
}
}
}
</style>

View File

@@ -1,10 +1,324 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%' v-loading='loading'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<div style='flex: 1;' class='mt10 zanjiangfenbutongji'>
<my-echart :options='firstOptions' style='flex: 1;height: 100%' />
<div style='width: 712px;height: 100%;display: flex;flex-direction: column'>
<my-echart :options='secondOptions' style='flex: 1' />
<my-echart :options='thirdOptions' style='flex: 1' />
</div>
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getReasonTypeTime, getStatistic } from '@/api/event-boot/monitor'
import { color } from '@/components/echarts/color'
const datePickerRef = ref()
const loading = ref(true)
const monitoringPoint = useMonitoringPoint()
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: '',
flag: 1
})
const firstOptions = ref<any>({})
const secondOptions = ref<any>({})
const thirdOptions = ref<any>({})
const firstData = ref<any>([])
const secondData = ref<any>([])
const thirdData = ref<any>([])
const init = () => {
loading.value = true
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
formData.flag = datePickerRef.value.interval
Promise.all([getReasonTypeTime(formData), getStatistic(formData)]).then(res => {
firstData.value = res[0].data
secondData.value = res[1].data.reason
thirdData.value = res[1].data.types
initFirst()
initSecond()
initThird()
loading.value = false
})
}
const initFirst = () => {
let months = new Array()
let handle = new Array()
for (let i = 0; i < firstData.value.length; i++) {
if ((firstData.value[i].month == '01') || (i == 0)) {
if (formData.flag == 0) {
months[i] = firstData.value[i].month
} else {
months[i] = firstData.value[i].month + '-' + firstData.value[i].day
}
} else {
if (formData.flag == 0) {
months[i] = firstData.value[i].month
} else {
months[i] = firstData.value[i].month + '-' + firstData.value[i].day
}
}
handle[i] = firstData.value[i].times
}
firstOptions.value = {
backgroundColor: '#fff', //背景色,
title: {
text:
formData.flag == 3
? '月份统计'
: formData.flag == 2
? '季度统计'
: formData.flag == 1
? '年份统计'
: '',
x: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
formatter: function(params: any) {
let tips = ''
tips += '<font>时间:' + params[0].name + '</font><br/>'
tips += '<font>暂降次数:' + params[0].data + '</font>'
return tips
}
},
legend: {
data: ['暂降次数'],
x: 'right'
},
xAxis: [
{
type: 'category',
data: months,
name: '时间'
}
],
yAxis: [
{
type: 'value',
name: '次',
minInterval: 1
}
],
series: [
{
name: '暂降次数',
type: 'bar',
barMinHeight: 10,
itemStyle: {
normal: {
color: function(params: any) {
if (params.data == 0) {
return '#ccc'
} else {
return color[0]
}
},
label: {
show: true,
textStyle: {
label: { show: true, position: 'top' }
}
}
}
},
data: handle
}
]
}
}
const initSecond = () => {
let reaArray = []
let valueArray = []
secondData.value.reverse()
for (let i = 0; i < secondData.value.length; i++) {
reaArray.push(secondData.value[i].reason)
valueArray.push({
name: secondData.value[i].reason,
value: secondData.value[i].times
})
}
secondOptions.value = {
backgroundColor: '#fff', //背景色,
animation: false,
title: {
text: '暂降原因',
x: 'center'
},
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: reaArray
},
series: [
{
name: '暂降原因',
type: 'pie',
radius: '70%',
center: ['50%', '53%'],
label: {
normal: {
show: false
},
emphasis: {
show: true
}
},
lableLine: {
normal: {
show: false
},
emphasis: {
show: true
}
},
data: valueArray,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
}
const initThird = () => {
let typeArray = []
let valueArray = []
for (let i = 0; i < thirdData.value.length; i++) {
typeArray.push(thirdData.value[i].type)
valueArray.push({
name: thirdData.value[i].type,
value: thirdData.value[i].times
}
)
}
thirdOptions.value = {
backgroundColor: '#fff', //背景色,
animation: false,
title: {
text: '暂降类型',
x: 'center'
},
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: typeArray
},
series: [
{
name: '暂降类型',
type: 'pie',
radius: '70%',
center: ['50%', '60%'],
label: {
normal: {
show: false
},
emphasis: {
show: true
}
},
lableLine: {
normal: {
show: false
},
emphasis: {
show: true
}
},
data: valueArray,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
}
onMounted(() => {
init()
})
</script>
<style></style>
<style lang='scss'>
.zanjiangfenbutongji {
display: flex;
overflow: hidden;
}
</style>

View File

@@ -1,10 +1,184 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<div style='flex: 1;' class='mt10'>
<my-echart :options='options' />
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getProbabilityDistribution } from '@/api/event-boot/monitor'
const datePickerRef = ref()
const monitoringPoint = useMonitoringPoint()
const loading = ref(true)
const formData = reactive({
lineIndex: monitoringPoint.state.lineId,
startTime: '',
endTime: ''
})
const options = ref({})
const init = () => {
loading.value = true
formData.startTime = datePickerRef.value.timeValue[0]
formData.endTime = datePickerRef.value.timeValue[1]
getProbabilityDistribution(formData).then(
(res: any) => {
let data = res.data
let eventValue = data.eventvalue
let pereventValue = data.pereventvalue
options.value = {
backgroundColor: '#fff', //背景色,
title: {
text: '暂降幅值的概率分布函数',
x: 'center'
},
legend: {
show: true,
left: 10,
data: ['概率分布', '占比'],
textStyle: {
rich: {
a: {
verticalAlign: 'middle'
}
},
padding: [2, 0, 0, 0] //[上、右、下、左]
}
},
tooltip: {
//提示框组件
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
borderWidth: 0
},
calculable: true,
xAxis: [
{
type: 'category',
name: '暂降幅值',
nameGap: 10,
nameTextStyle: {
fontSize: 12
},
data: [
'0',
'10%',
'20%',
'30%',
'40%',
'50%',
'60%',
'70%',
'80%',
'90%',
'100%'
]
}
],
yAxis: [
{
type: 'value',
name: '概率分布',
nameTextStyle: {
fontSize: 15
},
axisLabel: {
formatter: '{value}%'
},
axisLine: {
show: true
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
type: 'dashed',
opacity: 0.5
}
}
},
{
type: 'value',
name: '占比',
nameTextStyle: {
fontSize: 15
},
axisLine: {
show: true
},
splitLine: {
lineStyle: {
type: 'dashed',
opacity: 0.5
}
}
}
],
series: [
{
name: '占比',
type: 'bar',
data: pereventValue,
barWidth: 30,
itemStyle: {
normal: { show: true }
}
},
{
name: '概率分布',
type: 'line',
data: eventValue,
itemStyle: {
normal: { show: true }
}
}
],
options: {
dataZoom: null
}
}
nextTick(() => {
loading.value = false
})
}
)
}
onMounted(() => {
init()
})
</script>
<style></style>

View File

@@ -1,10 +1,119 @@
<template>
<div class='default-main'>
<div>
<!-- 表头 -->
<TableHeader date-picker>
<template v-slot:operation>
<el-button :icon='Download' type='primary' @click='download'>波形下载</el-button>
</template>
</TableHeader>
<!-- 表格 -->
<Table ref='tableRef' :checkboxConfig='checkboxConfig' />
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { Download } from '@element-plus/icons-vue'
import { ref, onMounted, provide, reactive } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { mainHeight } from '@/utils/layout'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { useDictData } from '@/stores/dictData'
import { checkUser } from '@/api/user-boot/user'
import { VxeTablePropTypes } from 'vxe-table'
import { downloadWaveFile, getMonitorEventAnalyseWave } from '@/api/event-boot/transient'
const dictData = useDictData()
const eventTypeOptions = dictData.getBasicData('Event_Statis')
const monitoringPoint = useMonitoringPoint()
const tableStore = new TableStore({
publicHeight: 60,
url: '/event-boot/monitor/getMonitorEventAnalyseQuery',
method: 'POST',
column: [
{ width: '60', type: 'checkbox' },
{ title: '序号', type: 'seq', width: '60' },
{ title: '变电站名称', field: 'subName', minWidth: '130' },
{ title: '监测点名称', field: 'lineName', minWidth: '130' },
{ title: '网络参数', field: 'ip', minWidth: '130' },
{ title: '电压等级(kV)', field: 'voltageScale', width: '100' },
{ title: '暂降发生时刻', field: 'startTime', width: '200' },
{ title: '暂降类型', field: 'advanceType', minWidth: '130' },
{ title: '暂降原因', field: 'advanceReason', minWidth: '130' },
{ title: '触发类型', field: 'eventTypeName', minWidth: '80' },
{ title: '暂降(骤升)幅值(%)', field: 'featureAmplitude', minWidth: '80' },
{ title: '持续时间(s)', field: 'duration', minWidth: '80' },
{ title: '严重度', field: 'severity', minWidth: '80' },
{
title: '操作',
width: '180',
render: 'buttons',
fixed: 'right',
buttons: [
{
name: 'edit',
title: '波形查看',
type: 'primary',
icon: 'el-icon-Lock',
render: 'basicButton',
disabled: row => {
return row.fileFlag === 0
},
click: row => {
getMonitorEventAnalyseWave({
id: row.eventId,
systemType: 0,
type: 0
}).then(res => {
console.log(res)
ElMessage.error('暂无可下载的波形文件!')
})
}
}
]
}
],
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {
item.eventTypeName = eventTypeOptions.find(item2 => item2.id === item.eventType)?.name
item.featureAmplitude = (item.featureAmplitude * 100).toFixed(0)
})
}
})
provide('tableStore', tableStore)
tableStore.table.params.lineId = monitoringPoint.state.lineId
tableStore.table.params.searchState = 0
onMounted(() => {
// 加载数据
tableStore.index()
})
const checkboxConfig = reactive<VxeTablePropTypes.CheckboxConfig<any>>({
checkMethod: ({ row }) => {
return row.fileFlag === 1
}
})
const download = () => {
if (!tableStore.table.selection.length) {
ElMessage.warning('请选择数据')
return
}
downloadWaveFile({
lineId: tableStore.table.selection.map((item: any) => item.eventId)
}).then((res: any) => {
if (res.type == 'application/json') {
ElMessage.warning('暂无可下载的波形文件!')
return
}
ElMessage.success('下载中。。。!')
let blob = new Blob([res], { type: 'application/zip' }) // console.log(blob) // var href = window.URL.createObjectURL(blob); //创建下载的链接
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = '波形分析下载' // 设置下载的文件名
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
})
}
</script>
<style></style>

View File

@@ -1,33 +1,59 @@
<template>
<div class='default-main'>
<div class='default-main' style='position: relative'>
<el-tabs v-model='activeName' type='border-card' class='demo-tabs'>
<el-tab-pane label='导航' name='1' :style='height'>
<Navigation />
<el-tab-pane label='导航' name='1' :style='height' lazy>
<Navigation @changeTab='changeTab' />
</el-tab-pane>
<el-tab-pane label='事件统计' name='2'>
<el-tab-pane label='事件统计' name='2' lazy>
<EventStatistics />
</el-tab-pane>
<el-tab-pane label='事件分析' name='3'>
<el-tab-pane label='事件分析' name='3' lazy>
<EventStudy />
</el-tab-pane>
<el-tab-pane label='运行情况' name='4'>
<el-tab-pane label='运行情况' name='4' lazy :style='height'>
<RunningCondition />
</el-tab-pane>
</el-tabs>
<div class='monitoring-point'>当前位置{{ monitoringPoint.state.lineName }}</div>
</div>
</template>
<script setup lang='ts'>
import { defineOptions, ref } from 'vue'
import { defineOptions, ref, watch } from 'vue'
import Navigation from './navigation/index.vue'
import EventStatistics from './eventStatistics/index.vue'
import EventStudy from './eventStudy/index.vue'
import RunningCondition from './runningCondition/index.vue'
import { mainHeight } from '@/utils/layout'
import router from '@/router'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
defineOptions({
name: 'Descentsystem/monitoringpoint'
})
const monitoringPoint = useMonitoringPoint()
const height = mainHeight(82)
const activeName = ref('1')
watch(
() => router.currentRoute.value.query.lineId,
(newLineId, oldLineId) => {
if (!newLineId) return
// 在这里处理 lineId 的变化
monitoringPoint.setValue('lineId', router.currentRoute.value.query.lineId)
monitoringPoint.setValue('lineName', router.currentRoute.value.query.lineName)
},
{ immediate: true }
)
const changeTab = (e: string) => {
activeName.value = e
}
</script>
<style></style>
<style lang='scss'>
.monitoring-point {
position: absolute;
top: 12px;
right: 10px;
font-size: 12px;
font-weight: 700;
color: var(--el-color-primary);
}
</style>

View File

@@ -1,29 +1,40 @@
<template>
<splitpanes style='height: 100%;' class='default-theme' id='navigation-splitpanes'>
<pane :size='size'>
<PointTree></PointTree>
<PointTree :default-expand-all='false'
:default-expanded-keys='monitoringPoint.state.lineId?[monitoringPoint.state.lineId]:[]'
:current-node-key='monitoringPoint.state.lineId'
@node-click='handleNodeClick'
@init='handleNodeClick'
></PointTree>
</pane>
<pane>
<Map></Map>
<Map v-bind='$attrs'></Map>
</pane>
</splitpanes>
</template>
<script setup lang='ts'>
import { defineOptions, onMounted, ref } from 'vue'
import { onMounted, ref } from 'vue'
import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes'
import PointTree from '@/components/tree/pms/pointTree.vue'
import Map from './map.vue'
import Tree from '@/components/tree/index.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
const monitoringPoint = useMonitoringPoint()
const size = ref(0)
onMounted(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
size.value = parseInt(240 / dom.offsetHeight * 100)
size.value = Math.round(240 / dom.offsetHeight * 100)
}
})
const handleNodeClick = (data: any, node: any) => {
if (data.level === 6) {
monitoringPoint.setValue('lineId', data.id)
}
}
</script>
<style lang='scss'>
.splitpanes.default-theme .splitpanes__pane {

View File

@@ -91,21 +91,16 @@
</el-descriptions-item>
<el-descriptions-item label='终端状态'>
{{
infoWindowPoint.runFlag == 0
? '投运'
: infoWindowPoint.runFlag == 1
? '热备用'
: '停运'
infoWindowPoint.runFlag == 0 ? '投运' : infoWindowPoint.runFlag == 1 ? '热备用' : '停运'
}}
</el-descriptions-item>
<el-descriptions-item label='通讯状态'>
{{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }}
</el-descriptions-item>
<el-descriptions-item>
<el-button type='primary' size='small'>查看监测点</el-button>
<el-button type='primary' size='small' @click='lookEvent'>
未处理事件({{ infoWindowPoint.noDealCount }})
</el-button>
<el-button type='primary' size='small' @click='changeTab("2")'>事件统计</el-button>
<el-button type='primary' size='small' @click='changeTab("3")'>事件分析</el-button>
<el-button type='primary' size='small' @click='changeTab("4")'>运行情况</el-button>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
@@ -122,17 +117,18 @@
<script setup lang='ts'>
import { BmlMarkerClusterer } from 'vue-baidu-map-3x'
import { ref } from 'vue'
import { nextTick, ref, watch } from 'vue'
import { getAreaLineInfo } from '@/api/event-boot/areaInfo'
import DatePicker from '@/components/form/datePicker/index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
const emit = defineEmits(['changeTab'])
const monitoringPoint = useMonitoringPoint()
const adminInfo = useAdminInfo()
const datePickerRef = ref()
const zoom = ref(11)
const loading = ref(true)
const popupEvent = ref()
const params = ref({
deptIndex: '',
monitorFlag: 2,
@@ -233,10 +229,18 @@ const handler = async ({ BMap, map }: any) => {
areaLineInfo.value.push(...item.children)
})
siteList.value = data
center.value.lng = areaLineInfo.value[0].lng
center.value.lat = areaLineInfo.value[0].lat
infoWindowPoint.value = areaLineInfo.value[0]
infoWindowPoint.value.show = true
watch(
() => monitoringPoint.state.lineId,
(newLineId, oldLineId) => {
let value = areaLineInfo.value.find((item: any) => item.lineId == newLineId)
center.value.lng = value.lng
center.value.lat = value.lat
infoWindowPoint.value = value
infoWindowPoint.value.show = true
monitoringPoint.setValue('lineName', value.manufacturer + '>' + value.gdName + '>' + value.subName + '>' + value.lineName)
},
{ immediate: true }
)
zoom.value = 15
setTimeout(() => {
loading.value = false
@@ -250,12 +254,8 @@ const markerClick = (e: any) => {
infoWindowPoint.value = e
infoWindowPoint.value.show = true
}
const lookEvent = (e: any) => {
popupEvent.value.open({
id: infoWindowPoint.value.lineId,
searchBeginTime: datePickerRef.value.timeValue[0],
searchEndTime: datePickerRef.value.timeValue[1]
})
const changeTab = (e: string) => {
emit('changeTab', e)
}
</script>
<style lang='scss' scoped>

View File

@@ -1,10 +1,321 @@
<template>
<div class='default-main'>
<div style='display: flex;flex-direction: column;height: 100%' v-loading='loading'>
<el-form :inline='true'>
<el-form-item label='日期'>
<DatePicker ref='datePickerRef'></DatePicker>
</el-form-item>
<el-form-item>
<el-button type='primary' @click='init'>查询</el-button>
</el-form-item>
</el-form>
<div style='flex: 1;' class='mt10 zanjiangfenbutongji'>
<div
style='position: absolute; right: 10px; top: 10px; z-index: 2;display: flex;align-items: center;font-size: 12px'>
<el-tag style='width: 20px;height: 12px' :style='{background: gradeColor[2]}'></el-tag>
<span class='ml2' :style='{color: gradeColor[2]}'> {{ 'X<60%' }} </span>
<el-tag class='ml10' style='width: 20px;height: 12px' :style='{background: gradeColor[1]}'></el-tag>
<span class='ml2' :style='{color: gradeColor[1]}'>{{ '60%≤X<90%' }} </span>
<el-tag class='ml10' style='width: 20px;height: 12px' :style='{background: gradeColor[0]}'></el-tag>
<span class='ml2' :style='{color: gradeColor[0]}'> {{ 'X≥90 %' }}</span>
</div>
<my-echart :options='secondOptions' style='flex: 1;height: 100%' />
<my-echart :options='firstOptions' style='flex: 1;height: 100%' />
</div>
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { nextTick, onMounted, reactive, ref } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/views/pms/voltageSags/monitoringPoint/online/store'
import { getComFlagInfoData, getRunOnlineRateData } from '@/api/device-boot/communicate'
import { gradeColor } from '@/components/echarts/color'
const datePickerRef = ref()
const loading = ref(true)
const monitoringPoint = useMonitoringPoint()
const formData = reactive({
id: monitoringPoint.state.lineId,
searchBeginTime: '',
searchEndTime: '',
timeFlag: 1
})
const firstOptions = ref<any>({})
const secondOptions = ref<any>({})
const firstData = ref<any>([])
const secondData = ref<any>([])
const init = () => {
loading.value = true
formData.searchBeginTime = datePickerRef.value.timeValue[0]
formData.searchEndTime = datePickerRef.value.timeValue[1]
formData.timeFlag = datePickerRef.value.interval
Promise.all([getRunOnlineRateData(formData), getComFlagInfoData(formData)]).then(res => {
firstData.value = res[0].data
secondData.value = res[1].data
initFirst()
initSecond()
loading.value = false
})
}
const initFirst = () => {
let months = new Array()
let handle = new Array()
let year = firstData.value[0].year
for (let i = 0; i < firstData.value.length; i++) {
if (formData.timeFlag == 0) {
months[i] = firstData.value[i].month
months[0] = firstData.value[i].month + '\n' + '(' + year + ')'
} else {
months[i] = firstData.value[i].month + '-' + firstData.value[i].day
months[0] = firstData.value[i].month + '-' + firstData.value[i].day + '\n' + '(' + year + ')'
}
handle.push(firstData.value[i].onlineRate)
}
firstOptions.value = {
title: {
text: '在线率统计',
x: 'center',
textStyle: {
fontWeight: 'normal'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
formatter: function(params: any) {
let tips = ''
tips += '时间:' + year + '-' + params[0].name + '</br/>'
for (let i = 0; i < params.length; i++) {
if (params[i].value == 3.14159) {
tips += '在线率' + ':暂无数据<br/>'
} else {
tips += '在线率' + ':' + params[i].value + '%<br/>'
}
}
return tips
}
},
xAxis: [
{
type: 'category',
data: months,
name: '时间',
nameTextStyle: {
verticalAlign: 'top', //标题位置
padding: [-5, 0, 0, -10]
},
splitLine: {
show: false
},
axisLine: {
show: true
}
}
],
yAxis: [
{
min: 0,
max: 100,
type: 'value',
name: '%',
axisLine: {
show: true
},
splitLine: {
show: false,
lineStyle: {
// 使用深浅的间隔色
type: 'dashed',
opacity: 0.5
}
}
}
],
series: [
{
type: 'bar',
data: handle,
itemStyle: {
color: (params: any) => {
if (params.value == 3.14159) {
return '#ccc'
} else {
if (params.value < 60) {
return gradeColor[2]
} else if (params.value < 90) {
return gradeColor[1]
} else {
return gradeColor[0]
}
}
}
},
markLine: {
silent: false,
symbol: 'circle',
data: [
{
yAxis: 100,
lineStyle: {
color: gradeColor[0]
},
label: {
position: 'end',
formatter: '100%'
}
},
{
yAxis: 90,
lineStyle: {
color: gradeColor[1]
},
label: {
position: 'end',
formatter: '90%'
}
},
{
yAxis: 60,
lineStyle: {
color: gradeColor[2]
},
label: {
position: 'end',
formatter: '60%'
}
}
]
}
}
]
}
}
const initSecond = () => {
let list = secondData.value.type
let items = secondData.value.updateTime
for (let i = 0; i < items.length; i++) {
if (i != 0) {
i
items[i] = items[i].slice(11)
} else if (i == 0) {
let date = items[i].slice(11)
let t = items[i].slice(0, 10)
items[i] = '(' + date + ')' + '\n' + t
}
}
secondOptions.value = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.35)',
formatter: function(params: any) {
let res = '时间: ' + params[0].name + '<br/>运行状态:'
let texts = ''
if (params[0].value === 2 || params[0].value === '2') {
texts = '退出'
} else if (params[0].value === 0 || params[0].value === '0') {
texts = '中断'
} else if (params[0].value === 1 || params[0].value === '1') {
texts = '正常'
}
res = res + texts
return res
}
},
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
end: 100,
bottom: '25px'
},
{ height: 13, start: 0, bottom: '25px', end: 100 }
],
xAxis: {
name: '时间',
type: 'category',
data: items,
boundaryGap: false
},
yAxis: {
name: '状态',
type: 'value',
axisLine: {
show: true
},
axisLabel: {
show: true,
textStyle: {
color: 'blue'
},
// 这里重新定义就可以
formatter: function(value: number) {
let texts = []
if (value === 2) {
texts.push('退出')
} else if (value === 0) {
texts.push('中断')
} else if (value === 1) {
texts.push('正常')
}
return texts
}
}
},
series: [
{
name: '运行状态',
type: 'line',
step: 'end',
data: list
}
]
}
}
onMounted(() => {
init()
})
</script>
<style></style>
<style lang='scss'>
.zanjiangfenbutongji {
position: relative;
display: flex;
overflow: hidden;
}
</style>

View File

@@ -0,0 +1,24 @@
import { reactive } from 'vue'
import { defineStore } from 'pinia'
interface MonitoringPoint {
lineId: string
lineName: string
}
export const useMonitoringPoint = defineStore(
'monitoringPoint',
() => {
const state: MonitoringPoint = reactive({
lineId: '',
lineName: '',
})
const setValue = (key: keyof MonitoringPoint, val: any) => {
state[key] = val
}
return { state, setValue }
},
{
persist: true
}
)

View File

@@ -1,149 +1,149 @@
<template>
<div style="padding: 10px; display: flex; height: 100%" v-loading="loading">
<div style="position: relative; flex: 1">
<div style="display: none">
<DatePicker ref="datePickerRef"></DatePicker>
<div style='padding: 10px; display: flex; height: 100%' v-loading='loading'>
<div style='position: relative; flex: 1'>
<div style='display: none'>
<DatePicker ref='datePickerRef'></DatePicker>
</div>
<div class="iconBox">
<div class="div">
<img src="@/assets/jcd.png" alt="" />
<div class='iconBox'>
<div class='div'>
<img src='@/assets/jcd.png' alt='' />
<span>变电站</span>
</div>
<div class="div">
<img src="@/assets/rby.png" alt="" />
<div class='div'>
<img src='@/assets/rby.png' alt='' />
<span>热备用</span>
</div>
<div class="div">
<img src="@/assets/ty.png" alt="" />
<div class='div'>
<img src='@/assets/ty.png' alt='' />
<span>停运</span>
</div>
<div class="div">投运</div>
<div class="div" style="padding-left: 10px">
<div class='div'>投运</div>
<div class='div' style='padding-left: 10px'>
<span>通讯正常</span>
</div>
<div class="div" style="padding-left: 20px">
<img src="@/assets/txzcyzj.gif" alt="" />
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzcyzj.gif' alt='' />
<span>有暂降</span>
</div>
<div class="div" style="padding-left: 20px">
<img src="@/assets/txzcwzj.png" alt="" />
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzcwzj.png' alt='' />
<span>无暂降</span>
</div>
<div class="div" style="padding-left: 10px">
<div class='div' style='padding-left: 10px'>
<span>通讯异常</span>
</div>
<div class="div" style="padding-left: 20px">
<img src="@/assets/txycyzj.gif" alt="" />
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txycyzj.gif' alt='' />
<span>有暂降</span>
</div>
<div class="div" style="padding-left: 20px">
<img src="@/assets/txzdwzj.png" alt="" />
<div class='div' style='padding-left: 20px'>
<img src='@/assets/txzdwzj.png' alt='' />
<span>无暂降</span>
</div>
</div>
<div class="selectBox">
<div class='selectBox'>
<el-select
@change="pointChange"
:popper-append-to-body="false"
@change='pointChange'
:popper-append-to-body='false'
filterable
clearable
v-model="lineId"
placeholder="输入监测点名称查询"
v-model='lineId'
placeholder='输入监测点名称查询'
>
<el-option
v-for="item in areaLineInfo"
:key="item.lineId"
:label="item.lineName"
:value="item.lineId"
v-for='item in areaLineInfo'
:key='item.lineId'
:label='item.lineName'
:value='item.lineId'
></el-option>
</el-select>
</div>
<baidu-map
class="bm-view"
:zoom="zoom"
:map-click="false"
:scroll-wheel-zoom="true"
:center="center"
@ready="handler"
@zoomend="syncCenterAndZoom"
class='bm-view'
:zoom='zoom'
:map-click='false'
:scroll-wheel-zoom='true'
:center='center'
@ready='handler'
@zoomend='syncCenterAndZoom'
>
<bm-map-type
:map-types="['BMAP_NORMAL_MAP', 'BMAP_HYBRID_MAP']"
anchor="BMAP_ANCHOR_TOP_RIGHT"
anchor='BMAP_ANCHOR_TOP_RIGHT'
></bm-map-type>
<!-- 线-->
<bm-polyline :path="path" v-for="(path, index) in polyline" :key="index"></bm-polyline>
<bm-polyline :path='path' v-for='(path, index) in polyline' :key='index'></bm-polyline>
<!-- 变电站-->
<template v-if="zoom > 12">
<template v-if='zoom > 12'>
<bm-marker
:position="path"
v-for="path in siteList"
:key="path.subId"
:icon="path.icon"
@click="markerClick(path)"
:position='path'
v-for='path in siteList'
:key='path.subId'
:icon='path.icon'
@click='markerClick(path)'
></bm-marker>
</template>
<!-- 点 -->
<BmlMarkerClusterer>
<bm-marker
:position="path"
v-for="path in areaLineInfo"
:key="path.lineId"
:icon="path.icon"
@click="markerClick(path)"
:position='path'
v-for='path in areaLineInfo'
:key='path.lineId'
:icon='path.icon'
@click='markerClick(path)'
></bm-marker>
</BmlMarkerClusterer>
<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" :column="1" v-if="infoWindowPoint.lineId">
<el-descriptions-item label="供电公司">{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label="变电站">{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label="母线">{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label="网络参数">
<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' :column='1' v-if='infoWindowPoint.lineId'>
<el-descriptions-item label='供电公司'>{{ infoWindowPoint.gdName }}</el-descriptions-item>
<el-descriptions-item label='变电站'>{{ infoWindowPoint.subName }}</el-descriptions-item>
<el-descriptions-item label='母线'>{{ infoWindowPoint.voltageName }}</el-descriptions-item>
<el-descriptions-item label='网络参数'>
{{ infoWindowPoint.ip }}
</el-descriptions-item>
<el-descriptions-item label="PT变化">{{ infoWindowPoint.pt2 }}</el-descriptions-item>
<el-descriptions-item label="CT变化">{{ infoWindowPoint.ct2 }}</el-descriptions-item>
<el-descriptions-item label="生产厂家">
<el-descriptions-item label='PT变化'>{{ infoWindowPoint.pt2 }}</el-descriptions-item>
<el-descriptions-item label='CT变化'>{{ infoWindowPoint.ct2 }}</el-descriptions-item>
<el-descriptions-item label='生产厂家'>
{{ infoWindowPoint.manufacturer }}
</el-descriptions-item>
<el-descriptions-item label="终端状态">
<el-descriptions-item label='终端状态'>
{{
infoWindowPoint.runFlag == 0
? '投运'
: infoWindowPoint.runFlag == 1
? '热备用'
: '停运'
? '热备用'
: '停运'
}}
</el-descriptions-item>
<el-descriptions-item label="通讯状态">
<el-descriptions-item label='通讯状态'>
{{ infoWindowPoint.comFlag == 0 ? '中断' : '正常' }}
</el-descriptions-item>
<el-descriptions-item>
<el-button type="primary" size="small">查看监测点</el-button>
<el-button type="primary" size="small" @click="lookEvent">
<el-button type='primary' size='small' @click='lookPoint'>查看监测点</el-button>
<el-button type='primary' size='small' @click='lookEvent'>
未处理事件({{ infoWindowPoint.noDealCount }})
</el-button>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
:title="infoWindowPoint.subName"
:column="1"
v-else-if="infoWindowPoint.subId"
style="padding-top: 10px"
:title='infoWindowPoint.subName'
:column='1'
v-else-if='infoWindowPoint.subId'
style='padding-top: 10px'
></el-descriptions>
</bm-info-window>
</bm-marker>
</baidu-map>
</div>
<div style="width: 600px; height: 100%">
<Right :params="params" v-if="params.deptIndex"></Right>
<div style='width: 600px; height: 100%'>
<Right :params='params' v-if='params.deptIndex'></Right>
</div>
<PopupEvent ref="popupEvent"></PopupEvent>
<PopupEvent ref='popupEvent'></PopupEvent>
</div>
</template>
<script setup lang="ts">
<script setup lang='ts'>
import { BmlMarkerClusterer } from 'vue-baidu-map-3x'
import { ref } from 'vue'
import { mainHeight } from '@/utils/layout'
@@ -152,6 +152,7 @@ import DatePicker from '@/components/form/datePicker/index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import Right from './right.vue'
import PopupEvent from './popupEvent.vue'
import router from '@/router'
defineOptions({
name: 'Descentsystem/overview'
@@ -295,8 +296,19 @@ const lookEvent = (e: any) => {
searchEndTime: datePickerRef.value.timeValue[1]
})
}
const lookPoint = () => {
console.log(infoWindowPoint.value)
router.replace({
name: 'Descentsystem/monitoringpoint',
query: {
lineId: infoWindowPoint.value.lineId,
lineName: infoWindowPoint.value.manufacturer + '>' + infoWindowPoint.value.gdName + '>' + infoWindowPoint.value.subName + '>' + infoWindowPoint.value.lineName
}
})
}
</script>
<style lang="scss" scoped>
<style lang='scss' scoped>
.bm-view {
width: 100%;
height: 100%;