代码提交

This commit is contained in:
name
2025-09-25 13:32:47 +08:00
parent 63022ffecd
commit 66b650750a
132 changed files with 35432 additions and 0 deletions

View File

@@ -0,0 +1,701 @@
<template>
<!-- 配网计算 -->
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes">
<pane :size="20">
<PointTree :showSelect="false" @node-click="handleNodeClick" @init="handleNodeClick"></PointTree>
</pane>
<pane style="background-color: rgba(44, 46, 60, 0.1)" :size="100 - size">
<el-form :model="form" inline label-width="auto">
<el-form-item label="谐波类型">
<el-radio-group v-model="form.type">
<el-radio-button label="谐波电压" size="small" value="1" />
<el-radio-button label="谐波电流" size="small" value="0" />
</el-radio-group>
</el-form-item>
<el-form-item label="谐波次数">
<el-select v-model="form.index" filterable multiple :multiple-limit="5" collapse-tags collapse-tags-tooltip
clearable placeholder="请选择次数" style="width: 200px" size="small">
<el-option v-for="item in 49" :key="item" :label="item + 1 + '次'" :value="item + 1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="负荷数据">
<el-select v-model="form.loadDataId" clearable filterable placeholder="请选择负荷数据" style="width: 200px"
size="small">
<el-option v-for="item in loadDataOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<!-- <el-button type="primary" icon="el-icon-Plus" @click="push('/admin/division/aListOfLoadData')">
新增
</el-button> -->
<el-button type="primary" :icon="Select" @click="submit" size="small">确定</el-button>
</el-form-item>
</el-form>
<el-tabs v-model="activeName" v-if="showTabs" style="height: 740px">
<el-tab-pane v-for="(item, index) in tabList" :key="item" :label="item.label" :name="index"
style="height: 100%">
<div>
<div>
<span style="color: #fff">时间范围</span>
<el-date-picker v-model="item.time" class="mr10 ml10" type="daterange" start-placeholder="起始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" date-format="YYYY-MM-DD" time-format="YYYY-MM-DD"
value-format="YYYY-MM-DD" :disabled-date="handleDisabledDate" size="small" />
<el-button type="primary" :icon="CaretRight" @click="execute(item, index)" size="small">
执行
</el-button>
</div>
<div v-if="item.showEcahr == 1" class="harmonicButton">
<el-form :inline="true" v-model="item.form">
<el-form-item label="限值" v-if="item.showDynamic">
<el-input v-model="item.form.limit" placeholder="请选择限值" disabled style="width: 200px" size="small">
<template #append>
<el-button :icon="Edit" :class="[code == 0 ? 'frontBox' : '']" @click="setCode(0)" size="small" />
</template>
</el-input>
</el-form-item>
<el-form-item label="时间点一" v-if="item.showDynamic">
<el-input v-model="item.form.time1" placeholder="请选择时间点一" disabled style="width: 200px" size="small">
<template #append>
<el-button :icon="Edit" :class="[code == 1 ? 'frontBox' : '']" @click="setCode(1)" size="small" />
</template>
</el-input>
</el-form-item>
<el-form-item label="时间点二" v-if="item.showDynamic">
<el-input v-model="item.form.time2" placeholder="请选择时间点二" disabled style="width: 200px" size="small">
<template #append>
<el-button :icon="Edit" :class="[code == 2 ? 'frontBox' : '']" @click="setCode(2)" size="small" />
</template>
</el-input>
</el-form-item>
<el-button type="primary" :icon="Document" @click="generateFn" v-if="!item.showDynamic" size="small">
生成动态谐波责任数据
</el-button>
<el-button type="primary" :icon="Document" v-else @click="generateMetrics" size="small">
生成谐波责任指标
</el-button>
</el-form>
</div>
<div class="box" v-loading="loading" element-loading-background="#343849c7">
<MyEChart :options="item.options" v-if="item.showEcahr == 1" @group="group" />
<el-empty description="时间范围内无谐波数据" v-if="item.showEcahr == 2" />
</div>
<!-- 生成动态谐波责任数据 -->
<div class="box boxTab" v-loading="loading1" element-loading-background="#343849c7">
<MyEChart :options="item.dynamicOptions" style="flex: 1" v-if="item.showDynamic" />
<div style="width: 500px" v-if="item.showDynamic" class="tableBox">
<el-table :scrollbar-always-on="true" ref="tableRef" :data="item.dynamicData" height="280px"
size="small" :header-cell-style="{ textAlign: 'center' }" border>
<el-table-column prop="customerName" align="center" label="用户名(用户号)" />
<el-table-column prop="responsibilityData" align="center" label="责任数据(%)" width="120">
<template #default="scope">
{{
Math.floor(scope.row.responsibilityData * 10000) /
10000
}}
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</pane>
</splitpanes>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from "vue";
import "splitpanes/dist/splitpanes.css";
import { Splitpanes, Pane } from "splitpanes";
import PointTree from "@/components/tree/pointTree.vue";
import { Edit, Right } from "@element-plus/icons-vue";
import MyEChart from "@/components/echarts/MyEchart.vue";
import { timeFormat } from "@/utils/common";
import { yMethod } from "@/utils/echartMethod";
import { Select, CaretRight, Document } from "@element-plus/icons-vue";
import {
userDataList,
getHistoryHarmData,
getDynamicData,
getResponsibilityData,
} from "@/api/manage_wx";
const emit = defineEmits(["setTitle"]); // 打开弹窗
const visible = ref(false);
const size = ref(0);
const dotList: any = ref({});
const form: any = reactive({
type: "1",
index: [],
loadDataId: "",
});
const loadDataOptions: any = ref([]);
const code = ref(3);
const xAxisData = ref([]);
const loading = ref(false);
const loading1 = ref(false);
const tabList: any = ref([]);
const activeName = ref(0);
const xValue = ref("");
const showTabs = ref(false);
// 设置时间
const timeFrame = ref(["", ""]);
const openDialog = () => {
visible.value = true;
};
const handleNodeClick = (data: any) => {
if (data.level == 6) {
dotList.value = data;
setTimeout(() => {
emit("setTitle", data.alias);
}, 0)
}
};
// 处理日期禁用逻辑
const handleDisabledDate = (date) => {
// 定义时间边界
const startLimit = new Date(timeFrame.value[0]).getTime() - 86400000; //向前推1天
const endLimit = new Date(timeFrame.value[1]).setHours(23, 59, 59, 999);
// 如果日期不存在(选择今天时可能出现),不禁用
if (!date) return false;
// 禁用 2025-08-01 之前和 2025-08-31 之后的日期
return date.getTime() < startLimit || date.getTime() > endLimit;
};
// 这是按钮变色
const setCode = (num: number) => {
if (code.value == num) {
return (code.value = 3);
}
code.value = num;
};
// 确定
const submit = () => {
if (form.loadDataId == "") {
return ElMessage.warning("请选择负荷数据");
}
if (form.index.length == 0) {
return ElMessage.warning("请选择谐波次数");
}
if (form.index.length == 0) {
showTabs.value = false;
} else {
let timeList = loadDataOptions.value.filter(
(item: any) => item.id == form.loadDataId
)[0];
showTabs.value = true;
let list = JSON.parse(JSON.stringify(form.index)).sort((a, b) => a - b);
tabList.value = [];
list.forEach((item: any) => {
tabList.value.push({
label: item + "次谐波",
key: item,
time: [timeList.startTime, timeList.endTime],
showExecute: false,
form: {
limit: "",
time1: "",
time2: "",
},
showEcahr: 3, //1显示echart 2显示无数据 3什么都没有
options: {},
dynamicOptions: {}, //动态echarts
dynamicList: {}, //动态echarts
showDynamic: false, //动态执行展示
});
timeFrame.value = [timeList.startTime, timeList.endTime];
});
code.value = 3;
activeName.value = 0;
}
};
// 执行
const execute = async (item: any, index: number) => {
tabList.value[activeName.value].showDynamic = false;
loading.value = true;
await getHistoryHarmData({
searchBeginTime: item.time[0],
searchEndTime: item.time[1],
type: form.type,
time: item.key,
lineId: dotList.value.id,
})
.then((res: any) => {
if (res.code == "A0000") {
let [min, max] = yMethod(
res.data.historyData.map((item: any) => item.value + 0.1)
);
xAxisData.value = res.data.historyData.map((item: any) => item.time);
tabList.value[index].options = {
title: {
text: "",
},
xAxis: {
type: "time",
name: "时间",
axisLabel: {
formatter: {
day: "{MM}-{dd}",
month: "{MM}",
year: "{yyyy}",
},
},
// 刻度线样式
axisTick: {
lineStyle: {
color: "#fff", // 刻度线白色
},
},
// 轴线样式
axisLine: {
lineStyle: {
color: "#fff", // 轴线白色
},
},
},
tooltip: {
formatter(params: any) {
xValue.value = params[0].value[0];
let str = params[0].value[0] + "<br/>";
for (let i = 0; i < params.length; i++) {
str =
str +
params[i].marker +
params[i].seriesName +
"" +
params[i].value[1] +
"<br/>";
}
return str;
},
},
grid: {
top: 30,
right: 50,
},
legend: {
show: false,
},
yAxis: {
name: form.type == 1 ? "%" : "A",
min: min,
max: max,
},
toolbox: {
show: false,
},
series: [
{
name: item.key + (form.type == 1 ? "次谐波电压" : "次谐波电流"),
data: res.data.historyData.map((item: any) => [
item.time,
Math.floor(item.value * 10000) / 10000,
]),
type: "line",
symbol: "none",
markLine: {
symbol: "none", // 去除箭头
label: {
show: false, // 隐藏标签
},
data: [
{
yAxis: "",
},
{
xAxis: "",
},
{
xAxis: "",
},
],
// 样式配置
lineStyle: {
color: "red",
type: "dashed", // 虚线
},
},
},
],
};
tabList.value[index].showEcahr = 1; //显示echart
} else {
ElMessage.warning(res.message);
tabList.value[index].showEcahr = 2;
}
loading.value = false;
})
.catch(() => {
tabList.value[index].showEcahr = 2;
loading.value = false;
});
};
const resDataId = ref("");
// 生成动态谐波责任数据
const generateFn = async () => {
loading1.value = true;
await getDynamicData({
lineId: dotList.value.id,
searchBeginTime: tabList.value[activeName.value].time[0],
searchEndTime: tabList.value[activeName.value].time[1],
time: tabList.value[activeName.value].key,
type: form.type,
userDataId: form.loadDataId,
})
.then((res: any) => {
if (res.code == "A0000") {
resDataId.value = res.data.responsibilityDataIndex;
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
let [min, max] = yMethod(
res.data.datas.map((item: any) => item.valueDatas).flat()
);
let series: any[] = [];
let time: any[] = res.data.timeDatas.map((item: any) =>
timeFormat(item)
);
res.data.datas.forEach((item: any) => {
series.push({
name: item.customerName,
data: item.valueDatas.map((k: any, i: number) => [
time[i],
Math.floor(k * 10000) / 10000,
]),
type: "line",
symbol: "none",
});
});
tabList.value[activeName.value].dynamicOptions = {
title: {
text: "",
},
xAxis: {
type: "time",
name: "时间",
axisLabel: {
formatter: {
day: "{MM}-{dd}",
month: "{MM}",
year: "{yyyy}",
},
},
// 刻度线样式
axisTick: {
lineStyle: {
color: "#fff", // 刻度线白色
},
},
// 轴线样式
axisLine: {
lineStyle: {
color: "#fff", // 轴线白色
},
},
},
tooltip: {
formatter(params: any) {
let str = params[0].value[0] + "<br/>";
for (let i = 0; i < params.length; i++) {
str =
str +
params[i].marker +
params[i].seriesName +
"" +
params[i].value[1] +
"<br/>";
}
return str;
},
},
grid: {
top: 30,
},
legend: {
show: false,
},
yAxis: {
name: form.type == 1 ? "%" : "A",
min: min,
max: max,
},
toolbox: {
show: false,
},
options: {
series: series,
},
};
tabList.value[activeName.value].showDynamic = true;
} else {
ElMessage.warning(res.message);
}
loading1.value = false;
})
.catch(() => {
loading1.value = false;
});
loading1.value = false;
};
// 生成指标
const generateMetrics = async () => {
if (tabList.value[activeName.value].form.limit == "")
return ElMessage.warning("请选择限值!");
if (tabList.value[activeName.value].form.time1 == "")
return ElMessage.warning("请选择时间一!");
if (tabList.value[activeName.value].form.time2 == "")
return ElMessage.warning("请选择时间二!");
loading1.value = true;
await getResponsibilityData({
limitEndTime: tabList.value[activeName.value].form.time2,
limitStartTime: tabList.value[activeName.value].form.time1,
limitValue: tabList.value[activeName.value].form.limit,
resDataId: resDataId.value,
time: tabList.value[activeName.value].key,
type: form.type,
})
.then((res: any) => {
tabList.value[activeName.value].dynamicData = res.data.responsibilities;
let [min, max] = yMethod(
res.data.datas.map((item: any) => item.valueDatas).flat()
);
let series: any[] = [];
let time: any[] = res.data.timeDatas.map((item: any) => timeFormat(item));
res.data.datas.forEach((item: any) => {
series.push({
name: item.customerName,
data: item.valueDatas.map((k: any, i: number) => [
time[i],
Math.floor(k * 10000) / 10000,
]),
type: "line",
smooth: true,
symbol: "none",
});
});
tabList.value[activeName.value].dynamicOptions = {
title: {
text: "",
},
xAxis: {
type: "time",
name: "时间",
axisLabel: {
formatter: {
day: "{MM}-{dd}",
month: "{MM}",
year: "{yyyy}",
},
},
},
tooltip: {
formatter(params: any) {
let str = params[0].value[0] + "<br/>";
for (let i = 0; i < params.length; i++) {
str =
str +
params[i].marker +
params[i].seriesName +
"" +
params[i].value[1] +
"<br/>";
}
return str;
},
},
grid: {
top: 30,
},
legend: {
show: false,
},
yAxis: {
name: form.type == 1 ? "%" : "A",
min: min,
max: max,
},
toolbox: {
show: false,
},
options: {
series: series,
},
};
tabList.value[activeName.value].showDynamic = true;
})
.catch(() => {
loading1.value = false;
});
loading1.value = false;
};
// 监听echart点击
const group = (chart: any, myChartDom: any) => {
myChartDom.addEventListener("click", function (event: any) {
// 获取点击位置相对于图表容器的坐标
const rect = myChartDom.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const pointInPixel = [x, y];
// 转换为逻辑坐标(相对于图表坐标系)
const pointInGrid = chart.convertFromPixel({ gridIndex: 0 }, pointInPixel);
// 计算X轴和Y轴的对应数据
// 处理X轴数据分类轴
// 处理Y轴数据数值轴
let yValue = pointInGrid[1].toFixed(4);
// xValue = timeFormat(pointInGrid[0].toFixed(0) - 0)
if (code.value == 0) {
tabList.value[activeName.value].form.limit = yValue;
tabList.value[activeName.value].options.series[0].markLine.data[0].yAxis =
yValue;
chart.setOption(tabList.value[activeName.value].options);
} else if (code.value == 1) {
tabList.value[activeName.value].form.time1 = xValue.value;
tabList.value[activeName.value].options.series[0].markLine.data[1].xAxis =
xValue.value;
chart.setOption(tabList.value[activeName.value].options);
} else if (code.value == 2) {
tabList.value[activeName.value].form.time2 = xValue.value;
tabList.value[activeName.value].options.series[0].markLine.data[2].xAxis =
xValue.value;
chart.setOption(tabList.value[activeName.value].options);
}
// 控制台输出详细信息
// console.log('点击事件详情:', {
// X轴数据: xValue,
// Y轴数据: yValue
// })
});
};
onMounted(() => {
const dom = document.getElementById("navigation-splitpanes");
if (dom) {
size.value = Math.round((180 / dom.offsetHeight) * 100);
}
userDataList({
pageNum: 1,
pageSize: 10000,
searchValue: "",
}).then((res: any) => {
console.log(res.data);
loadDataOptions.value = res.data.records;
});
if (!dotList.value || !dotList.value.alias) {
dotList.value = { alias: "请选择监测点位" };
}
});
defineExpose({
openDialog,
});
</script>
<style scoped lang="scss">
@use "@/assets/scss/index.scss";
.box {
// height: calc((100vh - 190px) / 2);
height: 300px;
}
.boxTab {
display: flex;
}
.harmonicButton {
height: 42px;
margin-top: 10px;
display: flex;
justify-content: end;
align-items: center;
}
:deep(.el-tabs__content) {
height: calc(100vh - 265px);
}
:deep(.el-input-group__append, .el-input-group__prepend) {
background-color: #ffffff00;
padding: 0 17px;
}
:deep(.frontBox) {
background-color: var(--el-color-primary) !important;
color: #fff !important;
}
::v-deep(.el-tabs__item) {
color: #fff;
}
::v-deep(.el-tabs__item.is-active) {
color: var(--el-color-primary);
}
::v-deep(.el-tabs__nav-wrap::after) {
color: var(--el-color-primary);
}
::v-deep(.el-tabs__active-bar) {
color: var(--el-color-primary);
}
::v-deep(.splitpanes__splitter) {
background-color: rgba(44, 46, 60, 0.1) !important;
&:before {
background-color: #fff !important;
}
&:after {
background-color: #fffFFF80 !important;
}
}
::v-deep(.el-form-item) {
margin-bottom: 0px;
}
.currentPosition {
position: absolute;
top: -10px;
right: 10px;
font-size: 14px;
font-weight: 600;
}
</style>