Files
emsfront/src/views/ems/dzjk/sbjk/db/index.vue

280 lines
8.4 KiB
Vue
Raw Normal View History

<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"
>
<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>
2026-01-23 14:18:22 +08:00
</el-col>
2025-12-12 17:38:26 +08:00
</el-row>
</el-card>
2025-08-15 14:13:54 +08:00
</div>
</template>
<script>
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";
import { getDeviceList } from "@/api/ems/site";
2025-12-12 17:38:26 +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],
data() {
return {
2025-08-15 14:13:54 +08:00
loading: false,
2026-02-15 16:24:29 +08:00
displayData: [],
selectedSectionKey: "",
ammeterDeviceList: [],
};
},
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;
}
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;
}
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,
};
});
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-08-15 14:13:54 +08:00
methods: {
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-08-15 14:13:54 +08:00
};
</script>
<style scoped lang="scss">
.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-09-17 14:52:08 +08:00
2026-02-15 16:24:29 +08:00
.pcs-tag-item {
cursor: pointer;
}
.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); }
}
</style>