2025-06-22 17:22:40 +08:00
|
|
|
|
<template>
|
2026-02-15 16:24:29 +08:00
|
|
|
|
<div>
|
|
|
|
|
|
<div class="pcs-tags">
|
|
|
|
|
|
<el-tag
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:type="selectedSectionKey ? 'info' : 'primary'"
|
|
|
|
|
|
:effect="selectedSectionKey ? 'plain' : 'dark'"
|
|
|
|
|
|
class="pcs-tag-item"
|
|
|
|
|
|
@click="handleTagClick('')"
|
|
|
|
|
|
>
|
|
|
|
|
|
全部
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
<el-tag
|
|
|
|
|
|
v-for="(group, index) in sectionGroups"
|
|
|
|
|
|
:key="index + 'dbTag'"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:type="selectedSectionKey === group.sectionKey ? 'primary' : 'info'"
|
|
|
|
|
|
:effect="selectedSectionKey === group.sectionKey ? 'dark' : 'plain'"
|
|
|
|
|
|
class="pcs-tag-item"
|
|
|
|
|
|
@click="handleTagClick(group.sectionKey)"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ group.displayName || "电表" }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</div>
|
2025-12-12 17:38:26 +08:00
|
|
|
|
<el-card
|
2026-02-15 16:24:29 +08:00
|
|
|
|
v-for="(group, index) in filteredSectionGroups"
|
|
|
|
|
|
:key="index + 'dbSection'"
|
|
|
|
|
|
class="sbjk-card-container list running-card-container"
|
|
|
|
|
|
shadow="always"
|
2025-12-12 17:38:26 +08:00
|
|
|
|
>
|
|
|
|
|
|
<div slot="header">
|
2026-02-15 16:24:29 +08:00
|
|
|
|
<span class="large-title">{{ group.displayName || "电表" }}</span>
|
2025-12-12 17:38:26 +08:00
|
|
|
|
<div class="info">
|
2026-02-15 16:24:29 +08:00
|
|
|
|
<div>状态:{{ group.statusText }}</div>
|
|
|
|
|
|
<div>数据更新时间:{{ group.updateTimeText }}</div>
|
2025-12-12 17:38:26 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-row class="device-info-row">
|
2026-02-15 16:24:29 +08:00
|
|
|
|
<el-col
|
|
|
|
|
|
v-for="(item, dataIndex) in group.items"
|
|
|
|
|
|
:key="dataIndex + 'dbField'"
|
|
|
|
|
|
:span="8"
|
|
|
|
|
|
class="device-info-col"
|
2026-02-16 13:41:41 +08:00
|
|
|
|
:class="{ 'field-disabled': !item.pointId }"
|
2026-02-15 16:24:29 +08:00
|
|
|
|
>
|
2026-02-16 13:41:41 +08:00
|
|
|
|
<div class="field-click-wrapper" @click="handleFieldClick(item)">
|
|
|
|
|
|
<span class="left">{{ item.fieldName }}</span>
|
|
|
|
|
|
<span class="right">
|
|
|
|
|
|
<i v-if="isPointLoading(item.fieldValue)" class="el-icon-loading point-loading-icon"></i>
|
|
|
|
|
|
<span v-else>{{ displayValue(item.fieldValue) | formatNumber }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
2026-01-23 14:18:22 +08:00
|
|
|
|
</el-col>
|
2025-12-12 17:38:26 +08:00
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-card>
|
2026-02-16 13:41:41 +08:00
|
|
|
|
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
:visible.sync="curveDialogVisible"
|
|
|
|
|
|
:title="curveDialogTitle"
|
|
|
|
|
|
width="1000px"
|
|
|
|
|
|
append-to-body
|
|
|
|
|
|
class="ems-dialog"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
destroy-on-close
|
|
|
|
|
|
@opened="handleCurveDialogOpened"
|
|
|
|
|
|
@closed="handleCurveDialogClosed"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="curve-tools">
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="curveCustomRange"
|
|
|
|
|
|
type="datetimerange"
|
|
|
|
|
|
value-format="yyyy-MM-dd HH:mm:ss"
|
|
|
|
|
|
range-separator="至"
|
|
|
|
|
|
start-placeholder="开始时间"
|
|
|
|
|
|
end-placeholder="结束时间"
|
|
|
|
|
|
style="width: 440px"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button type="primary" size="mini" :loading="curveLoading" @click="loadCurveData">查询</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-loading="curveLoading" ref="curveChartRef" style="height: 380px;"></div>
|
|
|
|
|
|
</el-dialog>
|
2025-08-15 14:13:54 +08:00
|
|
|
|
</div>
|
2025-06-22 17:22:40 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2026-02-16 13:41:41 +08:00
|
|
|
|
import * as echarts from "echarts";
|
2025-06-30 17:32:04 +08:00
|
|
|
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
2025-09-10 09:54:29 +08:00
|
|
|
|
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
2026-02-15 16:24:29 +08:00
|
|
|
|
import { getProjectDisplayData } from "@/api/ems/dzjk";
|
2026-02-16 13:41:41 +08:00
|
|
|
|
import { getDeviceList, getPointConfigCurve } from "@/api/ems/site";
|
2025-12-12 17:38:26 +08:00
|
|
|
|
|
2025-06-22 17:22:40 +08:00
|
|
|
|
export default {
|
2025-08-15 14:13:54 +08:00
|
|
|
|
name: "DzjkSbjkDb",
|
2025-12-12 17:38:26 +08:00
|
|
|
|
mixins: [getQuerySiteId, intervalUpdate],
|
2025-06-22 17:22:40 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2025-08-15 14:13:54 +08:00
|
|
|
|
loading: false,
|
2026-02-15 16:24:29 +08:00
|
|
|
|
displayData: [],
|
|
|
|
|
|
selectedSectionKey: "",
|
|
|
|
|
|
ammeterDeviceList: [],
|
2026-02-16 13:41:41 +08:00
|
|
|
|
curveDialogVisible: false,
|
|
|
|
|
|
curveDialogTitle: "点位曲线",
|
|
|
|
|
|
curveChart: null,
|
|
|
|
|
|
curveLoading: false,
|
|
|
|
|
|
curveCustomRange: [],
|
|
|
|
|
|
curveQuery: {
|
|
|
|
|
|
siteId: "",
|
|
|
|
|
|
pointId: "",
|
|
|
|
|
|
pointType: "data",
|
|
|
|
|
|
rangeType: "custom",
|
|
|
|
|
|
startTime: "",
|
|
|
|
|
|
endTime: "",
|
|
|
|
|
|
},
|
2026-02-15 16:24:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
moduleDisplayData() {
|
|
|
|
|
|
return (this.displayData || []).filter((item) => item.menuCode === "SBJK_DB");
|
|
|
|
|
|
},
|
|
|
|
|
|
dbTemplateFields() {
|
|
|
|
|
|
const source = this.moduleDisplayData || [];
|
|
|
|
|
|
const result = [];
|
|
|
|
|
|
const seen = new Set();
|
|
|
|
|
|
source.forEach((item) => {
|
|
|
|
|
|
const fieldName = String(item?.fieldName || "").trim();
|
|
|
|
|
|
if (!fieldName || seen.has(fieldName)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
seen.add(fieldName);
|
|
|
|
|
|
result.push(fieldName);
|
|
|
|
|
|
});
|
|
|
|
|
|
return result.length > 0 ? result : this.fallbackFields;
|
|
|
|
|
|
},
|
|
|
|
|
|
sectionGroups() {
|
|
|
|
|
|
const source = this.moduleDisplayData || [];
|
|
|
|
|
|
const devices = (this.ammeterDeviceList || []).length > 0
|
|
|
|
|
|
? this.ammeterDeviceList
|
|
|
|
|
|
: [{ deviceId: "", deviceName: "电表" }];
|
|
|
|
|
|
|
|
|
|
|
|
return devices.map((device, index) => {
|
|
|
|
|
|
const deviceId = String(device?.deviceId || device?.id || "").trim();
|
|
|
|
|
|
const sectionKey = deviceId || `AMMETER_${index}`;
|
|
|
|
|
|
const displayName = String(device?.deviceName || device?.name || deviceId || `电表${index + 1}`).trim();
|
|
|
|
|
|
const exactRows = source.filter((item) => String(item?.deviceId || "").trim() === deviceId);
|
|
|
|
|
|
const fallbackRows = source.filter((item) => !String(item?.deviceId || "").trim());
|
|
|
|
|
|
|
|
|
|
|
|
const exactValueMap = {};
|
|
|
|
|
|
exactRows.forEach((item) => {
|
|
|
|
|
|
const key = String(item?.fieldName || "").trim();
|
|
|
|
|
|
if (key) {
|
|
|
|
|
|
exactValueMap[key] = item;
|
2025-09-28 14:31:24 +08:00
|
|
|
|
}
|
2026-02-15 16:24:29 +08:00
|
|
|
|
});
|
|
|
|
|
|
const fallbackValueMap = {};
|
|
|
|
|
|
fallbackRows.forEach((item) => {
|
|
|
|
|
|
const key = String(item?.fieldName || "").trim();
|
|
|
|
|
|
if (key && fallbackValueMap[key] === undefined) {
|
|
|
|
|
|
fallbackValueMap[key] = item;
|
2025-09-28 14:31:24 +08:00
|
|
|
|
}
|
2026-02-15 16:24:29 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const items = (this.dbTemplateFields || []).map((fieldName) => {
|
|
|
|
|
|
const row = exactValueMap[fieldName] || fallbackValueMap[fieldName] || {};
|
|
|
|
|
|
return {
|
|
|
|
|
|
fieldName,
|
|
|
|
|
|
fieldValue: row.fieldValue,
|
|
|
|
|
|
valueTime: row.valueTime,
|
2026-02-16 13:41:41 +08:00
|
|
|
|
pointId: String(row?.dataPoint || "").trim(),
|
|
|
|
|
|
raw: row,
|
2026-02-15 16:24:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const statusItem = (items || []).find((it) => String(it.fieldName || "").includes("状态"));
|
|
|
|
|
|
const timestamps = [...exactRows, ...fallbackRows]
|
|
|
|
|
|
.map((it) => new Date(it?.valueTime).getTime())
|
|
|
|
|
|
.filter((ts) => !isNaN(ts));
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
sectionName: displayName,
|
|
|
|
|
|
sectionKey,
|
|
|
|
|
|
displayName,
|
|
|
|
|
|
deviceId,
|
|
|
|
|
|
items,
|
|
|
|
|
|
statusText: this.displayValue(statusItem ? statusItem.fieldValue : "-"),
|
|
|
|
|
|
updateTimeText: timestamps.length > 0 ? this.formatDate(new Date(Math.max(...timestamps))) : "-",
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
displaySectionGroups() {
|
|
|
|
|
|
if (this.sectionGroups.length > 0) {
|
|
|
|
|
|
return this.sectionGroups;
|
|
|
|
|
|
}
|
|
|
|
|
|
return [
|
2026-01-23 14:18:22 +08:00
|
|
|
|
{
|
2026-02-15 16:24:29 +08:00
|
|
|
|
sectionName: "电参量",
|
|
|
|
|
|
sectionKey: "电参量",
|
|
|
|
|
|
displayName: "电表",
|
|
|
|
|
|
items: this.fallbackFields.map((fieldName) => ({ fieldName, fieldValue: "-" })),
|
|
|
|
|
|
statusText: "-",
|
|
|
|
|
|
updateTimeText: "-",
|
2026-01-23 14:18:22 +08:00
|
|
|
|
},
|
2026-02-15 16:24:29 +08:00
|
|
|
|
];
|
|
|
|
|
|
},
|
|
|
|
|
|
filteredSectionGroups() {
|
|
|
|
|
|
const groups = this.displaySectionGroups || [];
|
|
|
|
|
|
if (!this.selectedSectionKey) {
|
|
|
|
|
|
return groups;
|
|
|
|
|
|
}
|
|
|
|
|
|
return groups.filter((group) => group.sectionKey === this.selectedSectionKey);
|
|
|
|
|
|
},
|
|
|
|
|
|
fallbackFields() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
"正向有功电能",
|
|
|
|
|
|
"反向有功电能",
|
|
|
|
|
|
"正向无功电能",
|
|
|
|
|
|
"反向无功电能",
|
|
|
|
|
|
"有功功率",
|
|
|
|
|
|
"无功功率",
|
|
|
|
|
|
];
|
|
|
|
|
|
},
|
2025-06-22 17:22:40 +08:00
|
|
|
|
},
|
2025-08-15 14:13:54 +08:00
|
|
|
|
methods: {
|
2026-02-16 13:41:41 +08:00
|
|
|
|
handleFieldClick(item) {
|
|
|
|
|
|
const pointId = String(item?.pointId || item?.raw?.dataPoint || "").trim();
|
|
|
|
|
|
if (!pointId) {
|
|
|
|
|
|
this.$message.warning("该字段未配置点位,无法查询曲线");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.openCurveDialog({
|
|
|
|
|
|
pointId,
|
|
|
|
|
|
title: item?.fieldName || pointId,
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
openCurveDialog({ pointId, title }) {
|
|
|
|
|
|
const range = this.getDefaultCurveRange();
|
|
|
|
|
|
this.curveCustomRange = range;
|
|
|
|
|
|
this.curveDialogTitle = `点位曲线 - ${title || pointId}`;
|
|
|
|
|
|
this.curveQuery = {
|
|
|
|
|
|
siteId: this.siteId,
|
|
|
|
|
|
pointId,
|
|
|
|
|
|
pointType: "data",
|
|
|
|
|
|
rangeType: "custom",
|
|
|
|
|
|
startTime: range[0],
|
|
|
|
|
|
endTime: range[1],
|
|
|
|
|
|
};
|
|
|
|
|
|
this.curveDialogVisible = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
handleCurveDialogOpened() {
|
|
|
|
|
|
if (!this.curveChart && this.$refs.curveChartRef) {
|
|
|
|
|
|
this.curveChart = echarts.init(this.$refs.curveChartRef);
|
|
|
|
|
|
}
|
|
|
|
|
|
this.loadCurveData();
|
|
|
|
|
|
},
|
|
|
|
|
|
handleCurveDialogClosed() {
|
|
|
|
|
|
if (this.curveChart) {
|
|
|
|
|
|
this.curveChart.dispose();
|
|
|
|
|
|
this.curveChart = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.curveLoading = false;
|
|
|
|
|
|
},
|
|
|
|
|
|
getDefaultCurveRange() {
|
|
|
|
|
|
const end = new Date();
|
|
|
|
|
|
const start = new Date(end.getTime() - 24 * 60 * 60 * 1000);
|
|
|
|
|
|
return [this.formatDateTime(start), this.formatDateTime(end)];
|
|
|
|
|
|
},
|
|
|
|
|
|
formatDateTime(date) {
|
|
|
|
|
|
const d = new Date(date);
|
|
|
|
|
|
const p = (n) => String(n).padStart(2, "0");
|
|
|
|
|
|
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
|
|
|
|
|
},
|
|
|
|
|
|
formatCurveTime(value) {
|
|
|
|
|
|
if (value === undefined || value === null || value === "") {
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
const raw = String(value).trim();
|
|
|
|
|
|
const normalized = raw
|
|
|
|
|
|
.replace("T", " ")
|
|
|
|
|
|
.replace(/\.\d+/, "")
|
|
|
|
|
|
.replace(/Z$/, "")
|
|
|
|
|
|
.replace(/([+-]\d{2}:?\d{2})$/, "")
|
|
|
|
|
|
.trim();
|
|
|
|
|
|
const matched = normalized.match(/^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2})/);
|
|
|
|
|
|
if (matched) {
|
|
|
|
|
|
return `${matched[1]} ${matched[2]}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
return normalized.slice(0, 16);
|
|
|
|
|
|
},
|
|
|
|
|
|
loadCurveData() {
|
|
|
|
|
|
if (!this.curveQuery.siteId || !this.curveQuery.pointId) {
|
|
|
|
|
|
this.$message.warning("点位信息不完整,无法查询曲线");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!this.curveCustomRange || this.curveCustomRange.length !== 2) {
|
|
|
|
|
|
this.$message.warning("请选择查询时间范围");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.curveQuery.startTime = this.curveCustomRange[0];
|
|
|
|
|
|
this.curveQuery.endTime = this.curveCustomRange[1];
|
|
|
|
|
|
const query = {
|
|
|
|
|
|
siteId: this.curveQuery.siteId,
|
|
|
|
|
|
pointId: this.curveQuery.pointId,
|
|
|
|
|
|
pointType: "data",
|
|
|
|
|
|
rangeType: "custom",
|
|
|
|
|
|
startTime: this.curveQuery.startTime,
|
|
|
|
|
|
endTime: this.curveQuery.endTime,
|
|
|
|
|
|
};
|
|
|
|
|
|
this.curveLoading = true;
|
|
|
|
|
|
getPointConfigCurve(query)
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
const rows = response?.data || [];
|
|
|
|
|
|
this.renderCurveChart(rows);
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
this.renderCurveChart([]);
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
this.curveLoading = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
renderCurveChart(rows = []) {
|
|
|
|
|
|
if (!this.curveChart) return;
|
|
|
|
|
|
const xData = rows.map((item) => this.formatCurveTime(item.dataTime));
|
|
|
|
|
|
const yData = rows.map((item) => item.pointValue);
|
|
|
|
|
|
this.curveChart.clear();
|
|
|
|
|
|
this.curveChart.setOption({
|
|
|
|
|
|
legend: {},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
containLabel: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: "axis",
|
|
|
|
|
|
axisPointer: {
|
|
|
|
|
|
type: "cross",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: "#333333",
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: "category",
|
|
|
|
|
|
data: xData,
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: "value",
|
|
|
|
|
|
},
|
|
|
|
|
|
dataZoom: [
|
|
|
|
|
|
{
|
|
|
|
|
|
type: "inside",
|
|
|
|
|
|
start: 0,
|
|
|
|
|
|
end: 100,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
start: 0,
|
|
|
|
|
|
end: 100,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: this.curveDialogTitle,
|
|
|
|
|
|
type: "line",
|
|
|
|
|
|
data: yData,
|
|
|
|
|
|
connectNulls: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!rows.length) {
|
|
|
|
|
|
this.$message.warning("当前时间范围暂无曲线数据");
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-02-15 16:24:29 +08:00
|
|
|
|
handleTagClick(sectionKey) {
|
|
|
|
|
|
this.selectedSectionKey = sectionKey || "";
|
|
|
|
|
|
},
|
|
|
|
|
|
displayValue(value) {
|
|
|
|
|
|
return value === undefined || value === null || value === "" ? "-" : value;
|
|
|
|
|
|
},
|
|
|
|
|
|
isPointLoading(value) {
|
|
|
|
|
|
return this.loading && (value === undefined || value === null || value === "" || value === "-");
|
|
|
|
|
|
},
|
|
|
|
|
|
formatDate(date) {
|
|
|
|
|
|
if (!(date instanceof Date) || isNaN(date.getTime())) {
|
|
|
|
|
|
return "-";
|
|
|
|
|
|
}
|
|
|
|
|
|
const p = (n) => String(n).padStart(2, "0");
|
|
|
|
|
|
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(
|
|
|
|
|
|
date.getMinutes()
|
|
|
|
|
|
)}:${p(date.getSeconds())}`;
|
|
|
|
|
|
},
|
|
|
|
|
|
resolveDbDisplayName(sectionName) {
|
|
|
|
|
|
const key = String(sectionName || "").trim();
|
|
|
|
|
|
if (!key) {
|
|
|
|
|
|
return "电表";
|
|
|
|
|
|
}
|
|
|
|
|
|
const list = this.ammeterDeviceList || [];
|
|
|
|
|
|
const matched = list.find((item) => {
|
|
|
|
|
|
const deviceId = String(item.deviceId || item.id || "").trim();
|
|
|
|
|
|
const deviceName = String(item.deviceName || item.name || "").trim();
|
|
|
|
|
|
return key === deviceId || key === deviceName;
|
|
|
|
|
|
});
|
|
|
|
|
|
if (matched) {
|
|
|
|
|
|
return matched.deviceName || matched.name || key;
|
|
|
|
|
|
}
|
|
|
|
|
|
return key;
|
2025-11-25 17:56:12 +08:00
|
|
|
|
},
|
2026-02-15 16:24:29 +08:00
|
|
|
|
getAmmeterDeviceList() {
|
|
|
|
|
|
return getDeviceList(this.siteId)
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
const list = response?.data || [];
|
|
|
|
|
|
this.ammeterDeviceList = list.filter((item) => item.deviceCategory === "AMMETER");
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
this.ammeterDeviceList = [];
|
|
|
|
|
|
});
|
2025-09-13 20:36:46 +08:00
|
|
|
|
},
|
2025-12-12 17:38:26 +08:00
|
|
|
|
updateData() {
|
2025-08-15 14:13:54 +08:00
|
|
|
|
this.loading = true;
|
2026-02-15 16:24:29 +08:00
|
|
|
|
Promise.all([getProjectDisplayData(this.siteId), this.getAmmeterDeviceList()])
|
|
|
|
|
|
.then(([response]) => {
|
|
|
|
|
|
this.displayData = response?.data || [];
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
this.loading = false;
|
|
|
|
|
|
});
|
2025-09-10 09:54:29 +08:00
|
|
|
|
},
|
|
|
|
|
|
init() {
|
2026-02-15 16:24:29 +08:00
|
|
|
|
this.updateData();
|
|
|
|
|
|
this.updateInterval(this.updateData);
|
2025-08-15 14:13:54 +08:00
|
|
|
|
},
|
2025-06-22 17:22:40 +08:00
|
|
|
|
},
|
2026-02-16 13:41:41 +08:00
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
if (this.curveChart) {
|
|
|
|
|
|
this.curveChart.dispose();
|
|
|
|
|
|
this.curveChart = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-08-15 14:13:54 +08:00
|
|
|
|
};
|
2025-06-22 17:22:40 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2025-09-22 17:57:30 +08:00
|
|
|
|
.sbjk-card-container {
|
2025-12-12 17:38:26 +08:00
|
|
|
|
&.list:not(:last-child) {
|
2025-09-26 14:47:45 +08:00
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
}
|
2026-02-15 16:24:29 +08:00
|
|
|
|
|
|
|
|
|
|
.info {
|
|
|
|
|
|
float: right;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
line-height: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pcs-tags {
|
|
|
|
|
|
margin: 0 0 12px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
align-items: center;
|
2025-06-22 17:22:40 +08:00
|
|
|
|
}
|
2025-09-17 14:52:08 +08:00
|
|
|
|
|
2026-02-15 16:24:29 +08:00
|
|
|
|
.pcs-tag-item {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-16 13:41:41 +08:00
|
|
|
|
.device-info-col {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.field-click-wrapper {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.device-info-col.field-disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
opacity: 0.8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.curve-tools {
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 16:24:29 +08:00
|
|
|
|
.point-loading-icon {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
transform-origin: center;
|
|
|
|
|
|
animation: pointLoadingSpinPulse 1.1s linear infinite;
|
|
|
|
|
|
}
|
|
|
|
|
|
@keyframes pointLoadingSpinPulse {
|
|
|
|
|
|
0% { opacity: 0.45; transform: rotate(0deg) scale(0.9); }
|
|
|
|
|
|
50% { opacity: 1; transform: rotate(180deg) scale(1.08); }
|
|
|
|
|
|
100% { opacity: 0.45; transform: rotate(360deg) scale(0.9); }
|
|
|
|
|
|
}
|
2025-06-22 17:22:40 +08:00
|
|
|
|
</style>
|