feat(statioin-page): action button group

This commit is contained in:
yangsy
2025-11-27 17:59:39 +08:00
parent f278a690c6
commit 7f9d868643
10 changed files with 294 additions and 45 deletions

View File

@@ -1,4 +1,3 @@
export * from './device-page';
export * from './global';
export * from './helper';
export * from './station-page';

View File

@@ -11,6 +11,10 @@ import { computed, ref } from 'vue';
const show = defineModel<boolean>('show', { default: false });
const emit = defineEmits<{
'after-leave': [];
}>();
const stationStore = useStationStore();
const { stationList } = storeToRefs(stationStore);
const deviceStore = useDeviceStore();
@@ -18,6 +22,11 @@ const { lineDevices } = storeToRefs(deviceStore);
const status = ref('');
const onAfterLeave = () => {
status.value = '';
emit('after-leave');
};
const { mutate: exportIcmp, isPending: loading } = useMutation({
mutationFn: async (params: { status: string }) => {
const data = await exportIcmpApi(params.status);
@@ -70,16 +79,8 @@ const deviceCount = computed(() => onlineDeviceCount.value + offlineDeviceCount.
</script>
<template>
<NModal v-model:show="show" preset="card" title="导出设备列表" @after-leave="() => (status = '')" style="width: 1000px">
<NModal v-model:show="show" preset="card" title="导出设备列表" @after-leave="onAfterLeave" style="width: 800px; height: 300px">
<template #default>
<NFlex justify="flex-end" align="center">
<NRadioGroup v-model:value="status">
<NRadio value="">全部</NRadio>
<NRadio value="10">在线</NRadio>
<NRadio value="20">离线</NRadio>
</NRadioGroup>
<NButton secondary :loading="loading" @click="() => exportIcmp({ status })">导出</NButton>
</NFlex>
<NGrid :cols="3" :x-gap="24" :y-gap="8">
<NGridItem>
<NStatistic label="全部设备" :value="deviceCount" />
@@ -92,6 +93,16 @@ const deviceCount = computed(() => onlineDeviceCount.value + offlineDeviceCount.
</NGridItem>
</NGrid>
</template>
<template #action>
<NFlex justify="flex-end" align="center">
<NRadioGroup v-model:value="status">
<NRadio value="">全部</NRadio>
<NRadio value="10">在线</NRadio>
<NRadio value="20">离线</NRadio>
</NRadioGroup>
<NButton secondary :loading="loading" @click="() => exportIcmp({ status })">导出</NButton>
</NFlex>
</template>
</NModal>
</template>

View File

@@ -2,4 +2,5 @@ export { default as DeviceAlarmDetailModal } from './device-alarm-detail-modal.v
export { default as DeviceExportModal } from './device-export-modal.vue';
export { default as DeviceParamsConfigModal } from './device-params-config-modal.vue';
export { default as OfflineDeviceDetailModal } from './offline-device-detail-modal.vue';
export { default as RecordCheckExportModal } from './record-check-export-modal.vue';
export { default as StationCard } from './station-card.vue';

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import { getRecordCheckApi, type NdmNvrResultVO, type Station } from '@/apis';
import { exportRecordDiagCsv, isNvrCluster, transformRecordChecks } from '@/helper';
import { useDeviceStore } from '@/stores';
import { useMutation } from '@tanstack/vue-query';
import { NButton, NGrid, NGridItem, NModal, NScrollbar, NSpin } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, toRefs } from 'vue';
const props = defineProps<{
stations: Station[];
}>();
const emit = defineEmits<{
'after-leave': [];
}>();
const show = defineModel<boolean>('show', { default: false });
const deviceStore = useDeviceStore();
const { lineDevices } = storeToRefs(deviceStore);
const { stations } = toRefs(props);
const nvrClusterRecord = computed(() => {
const clusterMap: Record<Station['code'], { stationName: Station['name']; clusters: NdmNvrResultVO[] }> = {};
stations.value.forEach((station) => {
clusterMap[station.code] = {
stationName: station.name,
clusters: [],
};
const stationDevices = lineDevices.value[station.code];
const nvrs = stationDevices?.['ndmNvr'] ?? [];
nvrs.forEach((nvr) => {
if (isNvrCluster(nvr)) {
clusterMap[station.code].clusters.push(nvr);
}
});
});
return clusterMap;
});
const { mutate: exportRecordDiags, isPending: exporting } = useMutation({
mutationFn: async (params: { clusters: NdmNvrResultVO[]; stationCode: Station['code'] }) => {
const { clusters, stationCode } = params;
if (clusters.length === 0) {
const stationName = nvrClusterRecord.value[stationCode].stationName;
window.$message.info(`${stationName} 没有录像诊断数据`);
return;
}
const checks = await getRecordCheckApi(clusters[0], 90, [], { stationCode: stationCode });
return checks;
},
onSuccess: (checks, { stationCode }) => {
if (!checks || checks.length === 0) return;
const recordDiags = transformRecordChecks(checks);
exportRecordDiagCsv(recordDiags, nvrClusterRecord.value[stationCode].stationName);
},
onError: (error) => {
console.error(error);
window.$message.error(error.message);
},
});
const onAfterLeave = () => {
emit('after-leave');
};
</script>
<template>
<NModal v-model:show="show" preset="card" title="导出录像诊断" @after-leave="onAfterLeave" style="width: 800px">
<template #default>
<NScrollbar style="height: 300px">
<NSpin size="small" :show="exporting">
<NGrid :cols="6">
<template v-for="({ stationName, clusters }, code) in nvrClusterRecord" :key="code">
<NGridItem>
<NButton text type="info" style="height: 30px" @click="() => exportRecordDiags({ clusters, stationCode: code })">{{ stationName }}</NButton>
</NGridItem>
</template>
</NGrid>
</NSpin>
</NScrollbar>
</template>
</NModal>
</template>
<style scoped lang="scss"></style>

View File

@@ -3,15 +3,18 @@ import type { Station, StationAlarmCounts, StationDevices } from '@/apis';
import { DeviceType } from '@/enums';
import { MoreOutlined, EllipsisOutlined } from '@vicons/antd';
import axios from 'axios';
import { NCard, NTag, NButton, NIcon, useThemeVars, NFlex, NText, NTooltip, NDropdown, type DropdownOption } from 'naive-ui';
import { NCard, NTag, NButton, NIcon, useThemeVars, NFlex, NTooltip, NDropdown, type DropdownOption, NCheckbox } from 'naive-ui';
import { toRefs, computed } from 'vue';
const props = defineProps<{
station: Station;
stationDevices?: StationDevices;
stationAlarmCounts?: StationAlarmCounts;
selectable?: boolean;
}>();
const selected = defineModel<boolean>('selected', { default: false });
const emit = defineEmits<{
'open-offline-device-detail-modal': [station: Station];
'open-device-alarm-detail-modal': [station: Station];
@@ -125,7 +128,8 @@ const theme = useThemeVars();
</template>
</template>
<template #header-extra>
<NFlex :size="4">
<NFlex :size="4" align="center">
<NCheckbox v-if="selectable" v-model:checked="selected" :disabled="!station.online" />
<NTag :type="station.online ? 'success' : 'error'" size="small">
{{ station.online ? '在线' : '离线' }}
</NTag>
@@ -149,7 +153,7 @@ const theme = useThemeVars();
<NFlex justify="end" align="center">
<span>
<span :style="{ color: onlineDeviceCount > 0 ? theme.successColor : '' }">在线 {{ onlineDeviceCount }} </span>
<NText depth="3"> · </NText>
<span> · </span>
<span :style="{ color: offlineDeviceCount > 0 ? theme.errorColor : '' }">离线 {{ offlineDeviceCount }} </span>
</span>
<NButton quaternary size="tiny" :focusable="false" style="visibility: hidden">