feat(line): 智电改造线路台账新增「线路数据」弹窗展示最近一次模拟量快照 - 后端新增GET /api/electricity-data/latest(按lineId取最大collect_time的全部模拟量行,RBAC device:list);前端electricityDataApi.getLatestByLine与ElectricityLatestSnapshot类型;台账页表格新增固定右侧「操作」列与「线路数据」按钮,点击弹出720px弹窗显示线路信息(线路/编码/采集时间)及模拟量表格(模拟量名称/类型/数值/单位),无数据时显示空态提示

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
This commit is contained in:
wkandClaude Sonnet 4.6 noreply@anthropic.com authored and trae-solo-agent committed 2026-10-24 15:13:56 +08:00
1 parent c92fc7f298
commit c8a4330f3b
3 files changed
+153 -2

No files matched your search

+87 -1
View File
@@ -140,6 +140,11 @@
<template v-else-if="column.key === 'syncedAt'">
<span>{{ formatTime(record.syncedAt) }}</span>
</template>
<template v-else-if="column.key === 'action'">
<a-button type="link" size="small" @click="handleViewData(record)">
线路数据
</a-button>
</template>
</template>
<template #emptyText>
@@ -149,9 +154,31 @@
</div>
</div>
</div>
<a-modal
v-model:open="analogModal.open"
:title="analogModal.title"
:width="720"
:footer="null"
>
<div v-if="analogModal.loading" class="modal-tip">加载中...</div>
<div v-else-if="!analogModal.snapshot || !analogModal.snapshot.hasData" class="modal-tip">暂无模拟量数据,可点击「同步线路」或等待定时同步后查看</div>
<template v-else>
<div class="modal-meta">
<span>线路:{{ analogModal.snapshot.lineName || '-' }}</span>
<span>编码:{{ analogModal.snapshot.lineCode || '-' }}</span>
<span>采集时间:{{ formatTime(analogModal.snapshot.collectTime) }}</span>
</div>
<a-table
:columns="analogColumns"
:data-source="analogModal.snapshot.list"
:pagination="false"
row-key="analogType"
size="small"
/>
</template>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { message } from 'ant-design-vue';
@@ -162,8 +189,10 @@ import {
} from '@ant-design/icons-vue';
import {
electricLineApi,
electricityDataApi,
type ElectricLine,
type ElectricLineQuery,
type ElectricityLatestSnapshot,
} from '@/api/device';
import { customerApi, type CustomerInfo } from '@/api/customer';
import { useTableScroll } from '@/composables/useTableScroll';
@@ -172,6 +201,25 @@ const { wrapperRef, tableHeight } = useTableScroll();
const loading = ref(false);
const syncing = ref(false);
const analogModal = reactive<{
open: boolean;
loading: boolean;
title: string;
snapshot: ElectricityLatestSnapshot | null;
}>({
open: false,
loading: false,
title: '线路模拟数据',
snapshot: null,
});
const analogColumns = [
{ title: '模拟量名称', dataIndex: 'analogName', key: 'analogName', ellipsis: true },
{ title: '类型', dataIndex: 'analogType', key: 'analogType', ellipsis: true, width: 100 },
{ title: '数值', dataIndex: 'analogValue', key: 'analogValue', align: 'center' as const, width: 120 },
{ title: '单位', dataIndex: 'analogUnit', key: 'analogUnit', align: 'center' as const, width: 80 },
];
const dataSource = ref<ElectricLine[]>([]);
const total = ref(0);
@@ -197,6 +245,7 @@ const columns = [
{ title: '生产日期', dataIndex: 'produceDate', key: 'produceDate', ellipsis: true, width: 120 },
{ title: '状态', dataIndex: 'status', key: 'status', align: 'center' as const, width: 80 },
{ title: '同步时间', dataIndex: 'syncedAt', key: 'syncedAt', ellipsis: true, width: 170 },
{ title: '操作', key: 'action', align: 'center' as const, fixed: 'right' as const, width: 100 },
];
const pagination = computed(() => ({
@@ -280,6 +329,25 @@ async function handleSync() {
}
}
async function handleViewData(record: ElectricLine) {
analogModal.open = true;
analogModal.loading = true;
analogModal.title = `线路数据 - ${record.lineName || record.lineCode}`;
analogModal.snapshot = null;
try {
const res: any = await electricityDataApi.getLatestByLine(record.id);
if (res.code === 200) {
analogModal.snapshot = res.data;
} else {
message.error(res.message || '获取模拟数据失败');
}
} catch (error) {
message.error('获取模拟数据失败,请稍后重试');
} finally {
analogModal.loading = false;
}
}
function formatTime(val?: string) {
if (!val) return '-';
const d = new Date(val);
@@ -517,4 +585,22 @@ function formatTime(val?: string) {
background: #136bfb;
border-color: #136bfb;
}
.modal-meta {
display: flex;
flex-wrap: wrap;
gap: 8px 24px;
font-size: 13px;
color: #5b6b7e;
margin-bottom: 12px;
}
.modal-meta span {
font-weight: 600;
color: #0d1c2c;
}
.modal-tip {
padding: 40px 0;
text-align: center;
color: #5b6b7e;
}
</style>