Files
admin-sjzx/src/views/pqs/bearingCapacity/evaluationList/components/photovoltaic.vue
2024-04-16 08:41:41 +08:00

579 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<splitpanes :style="{ height: height }" class="default-theme" id="navigation-splitpanes">
<pane :size="size">
<bearingTree
ref="TreeRef"
:default-expand-all="false"
:default-expanded-keys="monitoringPoint.state.lineId ? [monitoringPoint.state.lineId] : []"
:current-node-key="monitoringPoint.state.lineId"
@node-click="handleNodeClick"
@init="handleNodeClick"
></bearingTree>
</pane>
<pane style="background: #fff">
<el-form :inline="true" v-show="props.rowList.id == undefined">
<el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-Search" @click="onSubmit">查询</el-button>
<el-button type="primary" icon="el-icon-Download" @click="exportTemplate">导出模板</el-button>
<el-upload action="" :show-file-list="false" :auto-upload="false" :on-change="choose">
<el-button type="primary" class="ml10" icon="el-icon-Upload">离线导入</el-button>
</el-upload>
<!-- <el-button type="primary" class="ml10" icon="el-icon-Ticket" @click="modelTrain">
模型训练
</el-button> -->
</el-form-item>
</el-form>
<div v-loading="loading">
<el-descriptions class="mb10" title="基础数据" :column="2" size="" border>
<el-descriptions-item label="待评估用户" label-align="center" width="25%">
<el-select
v-model="user"
placeholder="请选择待评估用户"
size="small"
filterable
:disabled="props.rowList.id != undefined"
style="width: 240px"
value-key="userId"
@change="userChange"
>
<el-option v-for="item in userList" :key="item" :label="item.userName" :value="item" />
</el-select>
</el-descriptions-item>
<el-descriptions-item label="拟接入光伏容量(MVA)" label-align="center" width="25%">
{{ userData?.protocolCapacity }}
</el-descriptions-item>
<el-descriptions-item label="电压等级" label-align="center" width="25%">
{{ voltageLevelArr.filter(item => item.id === userData?.voltage)[0]?.name }}
</el-descriptions-item>
<el-descriptions-item label="额定容量(MVA)" label-align="center" width="25%">
{{ lineList?.standardCapacity }}
</el-descriptions-item>
</el-descriptions>
<el-tabs v-model="activeName" class="mb10" :style="`height: calc(${tabsHeight} / 2 + 50px)`">
<el-tab-pane label="有功功率" name="1" class="mt10">
<MyEChart :options="options1" />
</el-tab-pane>
<el-tab-pane label="无功功率" name="2" class="mt10">
<MyEChart :options="options2" />
</el-tab-pane>
<el-tab-pane label="谐波电流幅值" name="3" class="mt10">
<MyEChart :options="options3" />
</el-tab-pane>
<el-tab-pane label="首端电压模型参数" name="4">
<vxe-table height="auto" v-bind="defaultAttribute" :data="voltageList">
<!-- <vxe-column field="name" title="项别模型参数"></vxe-column> -->
<vxe-colgroup field="group0" title="模型参数">
<vxe-column field="name" width="180" title="项别"></vxe-column>
</vxe-colgroup>
<vxe-column field="c" title="C"></vxe-column>
<vxe-column field="a" title="a"></vxe-column>
<vxe-column field="b" title="b"></vxe-column>
</vxe-table>
</el-tab-pane>
</el-tabs>
<div class="bottomBox">
<el-row v-if="showAssess">
<el-col
:span="16"
:style="`height: calc(${tabsHeight} / 2 - ${
props.rowList.id == undefined ? 12 + 45 : 12
}px)`"
>
<vxe-table
style="flex: 1.5"
v-bind="defaultAttribute"
height="auto"
ref="xTable"
:data="tableData"
>
<vxe-colgroup field="group0" title="等级">
<vxe-column field="name" width="180" title="结果"></vxe-column>
</vxe-colgroup>
<vxe-column field="level1" title="安全">
<template #default="{ row }">
<Select v-if="row.level1 == 1" class="SelectIcon" />
<span v-else>{{ row.level1 }}</span>
</template>
</vxe-column>
<vxe-column field="level2" title="III级预警">
<template #default="{ row }">
<Select v-if="row.level2 == 1" class="SelectIcon" />
<span v-else>{{ row.level2 }}</span>
</template>
</vxe-column>
<vxe-column field="level3" title="II级预警">
<template #default="{ row }">
<Select v-if="row.level3 == 1" class="SelectIcon" />
<span v-else>{{ row.level3 }}</span>
</template>
</vxe-column>
<vxe-column field="level4" title="I级预警">
<template #default="{ row }">
<Select v-if="row.level4 == 1" class="SelectIcon" />
<span v-else>{{ row.level4 }}</span>
</template>
</vxe-column>
</vxe-table>
</el-col>
<el-col
:span="8"
:style="`height: calc(${tabsHeight} / 2 - ${
props.rowList.id == undefined ? 62 + 45 : 62
}px)`"
>
<MyEChart style="flex: 1" :options="pieCharts" />
</el-col>
</el-row>
<el-button
type="primary"
icon="el-icon-Document"
@click="assess"
v-show="showBtn && props.rowList.id == undefined"
>
承载能力评估
</el-button>
</div>
</div>
</pane>
</splitpanes>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, provide } from 'vue'
import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes'
import bearingTree from '@/components/tree/pqs/bearingTree.vue'
import DatePicker from '@/components/form/datePicker/index.vue'
import { mainHeight } from '@/utils/layout'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/stores/monitoringPoint'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { Select } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import {
queryCarryCapacityData,
uploadExcel,
queyDetailUser,
queryCarryCapacityQData,
queryCarryCapacityIData,
carryCapacityCal,
getExcelTemplate,
getLineDetailData,
modelTraining
} from '@/api/advance-boot/bearingCapacity'
import { useDictData } from '@/stores/dictData'
const props = defineProps(['rowList'])
const monitoringPoint = useMonitoringPoint()
const size = ref(20)
const dictData = useDictData()
const datePickerRef = ref()
const height = mainHeight(80).height
const tabsHeight = mainHeight(260).height
const voltageLevelArr = dictData.getBasicData('Dev_Voltage_Stand')
const tableData = ref([
{
name: '配变首端电压',
level1: '/',
level2: '/',
level3: '/',
level4: '/'
},
{
name: '配变功率因素',
level1: '/',
level2: '/',
level3: '/',
level4: '/'
},
{
name: '等效负载率最小值',
level1: '/',
level2: '/',
level3: '/',
level4: '/'
},
{
name: '各次谐波电流幅值',
level1: '/',
level2: '/',
level3: '/',
level4: '/'
}
])
const TreeRef = ref()
const voltageList: any = ref([])
const showAssess = ref(false)
const showBtn = ref(false)
const flag = ref(true)
const loading = ref(false)
const user = ref('')
const userList: any = ref([])
const lineList: any = ref([])
const options1 = ref({})
const options2 = ref({})
const options3 = ref({})
const pieCharts = ref({})
const activeName = ref('1')
const userData: any = ref({})
const stringMap: any = ref({})
const p_βminMap: any = ref({})
const i_βmax: any = ref({})
const q_βminMap: any = ref({})
const dotList: any = ref({
name: monitoringPoint.state.lineName.split('>')[3],
id: monitoringPoint.state.lineId,
level: 6
})
onMounted(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
size.value = Math.round((180 / dom.offsetHeight) * 100)
}
datePickerRef.value.setTimeOptions([{ label: '周', value: 4 }])
datePickerRef.value.setInterval(4)
info()
})
const info = () => {
queyDetailUser({
pageNum: 1,
pageSize: 1000,
userType: dictData.getBasicData('CARRY_CAPCITY_USER_TYPE', [
'Electrified_Rail_Users',
'Charging_Station_Users',
'Electric_Heating_Load_Users'
])[0]?.id
}).then(res => {
userList.value = res.data.records
user.value = userList.value[0] || {}
userData.value = res.data.records[0] || {}
})
}
// 查询
const onSubmit = async () => {
if (dotList.value.level != 6) {
return ElMessage.warning('请选择线路')
}
loading.value = true
let form = {
endTime: props.rowList.endTime || datePickerRef.value.timeValue[1],
lineId: props.rowList.lineId || dotList.value.id,
startTime: props.rowList.startTime || datePickerRef.value.timeValue[0],
userId: dictData.state.area[0].id
}
options1.value = {}
options2.value = {}
options3.value = {}
voltageList.value = []
showBtn.value = false
if (props.rowList.id != undefined) {
user.value = props.rowList
rendering(props.rowList)
}
Promise.all([queryCarryCapacityData(form), queryCarryCapacityQData(form), queryCarryCapacityIData(form)])
.then(res => {
// 有功功率
stringMap.value = res[0].data.stringMap
p_βminMap.value = res[0].data.p_βminMap
q_βminMap.value = res[1].data.q_βminMap
i_βmax.value = res[2].data.i_βmax
for (let k in res[0].data.stringMap) {
voltageList.value.push({
name: k,
c: res[0].data.stringMap[k][0],
a: res[0].data.stringMap[k][1],
b: res[0].data.stringMap[k][2]
})
}
setEChart(1, res[0].data.data, '有功功率', 'w')
setEChart(2, res[1].data.data, '无功功率', 'w')
setEChart(3, res[2].data.data, '谐波电流幅值', 'A')
showBtn.value = true
loading.value = false
// props.rowList.id != undefined
})
.catch(err => {
loading.value = false
})
}
// 用户变化
const userChange = (e: any) => {
userData.value = e
}
// 模型训练
const modelTrain = () => {
modelTraining({
endTime: datePickerRef.value.timeValue[1],
lineId: dotList.value.id,
startTime: datePickerRef.value.timeValue[0],
time: 0,
userId: dictData.state.area[0].id
}).then(res => {})
}
const setEChart = (val: any, data: any, text: string, name: string) => {
let options = {
title: {
text: text,
x: 'center',
textStyle: {
fontWeight: 'normal'
}
},
xAxis: {
data: data.filter(item => item.phaseType == 'A').map(item => item.time),
name: '时间',
position: 'bottom' // 设置 x 轴在底部
},
yAxis: {
type: 'value',
name: name,
max: Math.ceil(Math.max(...data.map(item => item.value))),
min: Math.floor(Math.min(...data.map(item => item.value)))
},
legend: {
data: ['A', 'B', 'C']
// selectedMode: false,
},
grid: {
top: '30px',
left: '30px'
},
color: ['#FFCC33', '#00CC00', '#CC0000'],
series: [
{
name: 'A',
type: 'line',
// smooth: true,
symbol: 'none',
data: data.filter(item => item.phaseType == 'A').map(item => item.value.toFixed(3))
},
{
name: 'B',
type: 'line',
// smooth: true,
symbol: 'none',
data: data.filter(item => item.phaseType == 'B').map(item => item.value.toFixed(3))
},
{
name: 'C',
type: 'line',
// smooth: true,
symbol: 'none',
data: data.filter(item => item.phaseType == 'C').map(item => item.value.toFixed(3))
}
]
}
val == 1
? (options1.value = options)
: val == 2
? (options2.value = options)
: val == 3
? (options3.value = options)
: ''
}
// 承载能力评估
const assess = () => {
if (dotList.value.level != 6) {
return ElMessage.warning('请选择线路')
}
carryCapacityCal({
endTime: datePickerRef.value.timeValue[1],
lineId: dotList.value.id,
startTime: datePickerRef.value.timeValue[0],
userId: userData.value.userId, //dictData.state.area[0].id,
i_βmax: i_βmax.value,
p_βminMap: p_βminMap.value,
q_βminMap: q_βminMap.value,
s_T: lineList.value.standardCapacity,
s_pv: userData.value.protocolCapacity,
scale: userData.value.voltage,
stringMap: stringMap.value
}).then((res: any) => {
rendering(res.data)
})
}
const rendering = (data: any) => {
let ChartsList = [
{
name: '安全',
value: 0
},
{
name: 'III级',
value: 0
},
{
name: 'II级',
value: 0
},
{
name: 'I级',
value: 0
},
{
name: '禁止接入',
value: 0
}
]
tableData.value[0][`level` + data.utlevel] = 1
tableData.value[1][`level` + data.pfTLevel] = 1
tableData.value[2][`level` + data.btlevel] = 1
tableData.value[3][`level` + data.ilevel] = 1
ChartsList[data.reslutLevel - 1].value = 1
showAssess.value = true
pieCharts.value = {
title: {
text: '承载能力评估结果',
x: 'center',
top: `30px`,
textStyle: {
fontWeight: 'normal'
}
},
legend: {
type: 'scroll',
orient: 'vertical',
left: 10,
top: '10%'
},
xAxis: {
show: false
},
yAxis: {
show: false
},
color: ['#77DA63', '#00BFF5', '#FFBF00', '#Ff6600', '#ff0000'],
dataZoom: { show: false },
series: [
{
type: 'pie',
center: ['60%', '70%'],
radius: ['35%', '48%'],
label: {
normal: {
show: false
}
},
data: ChartsList
}
]
}
}
// 下载模版
const exportTemplate = () => {
getExcelTemplate().then((res: any) => {
let blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
// link.download = "电压暂降事件分析报告"; // 设置下载的文件名
link.download = '数据模版' // 设置下载的文件名
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link)
})
}
// 离线导入
const choose = (e: any) => {
if (dotList.value.level != 6) {
return ElMessage.warning('请选择线路')
}
let form = {
endTime: datePickerRef.value.timeValue[1],
lineId: dotList.value.id,
startTime: datePickerRef.value.timeValue[0]
}
uploadExcel(e.raw, form).then(res => {
ElMessage.success('导入成功')
})
}
const handleNodeClick = (data: any, node: any) => {
if (flag.value) {
lineList.value = {}
dotList.value = data
if (data.level == 6) {
getLineDetailData({ id: data.id }).then((res: any) => {
lineList.value = res.data
})
}
}
if (props.rowList.userId != undefined && flag.value) {
TreeRef.value.setKey(props.rowList.lineId)
onSubmit()
flag.value = false
}
}
</script>
<style lang="scss" scoped>
.splitpanes.default-theme .splitpanes__pane {
background: #eaeef1;
}
.grid-content {
text-align: center;
}
.bottomBox {
position: relative;
.el-button {
position: absolute;
top: 0;
z-index: 1;
right: 10px;
}
}
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type) {
background: #f8f8f9;
}
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
top: 0;
left: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: top;
}
:deep(.vxe-table--header thead tr:last-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
bottom: 0;
right: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: bottom;
}
.SelectIcon {
height: 30px;
margin-top: 5px;
color: blue;
}
</style>