| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- <template>
- <div class="p-4 flex flex-col gap-4">
- <NCard size="small">
- <DeviceSelector v-model:gateway-sn="gatewaySn" v-model:device="device" :env="env" />
- </NCard>
- <NCard size="small" title="读取设备信息(cmd=0)">
- <div class="flex flex-wrap gap-4 items-center">
- <NCheckboxGroup v-model:value="codes">
- <NCheckbox v-for="c in REALTIME_CODES" :key="c.code" :value="c.code" :label="`${c.code} ${c.name}`" />
- </NCheckboxGroup>
- <NButton type="primary" :disabled="!device || codes.length === 0" :loading="op.running.value" @click="read">
- 读取
- </NButton>
- </div>
- </NCard>
- <NCard v-if="op.detail.value" size="small" title="结果">
- <OperationProgress :detail="op.detail.value" :cancel="op.cancel" />
- <div class="mt-3 flex flex-col gap-4">
- <NCard v-for="item in op.detail.value.items" :key="item.code" size="small" embedded>
- <template #header>
- {{ item.code }} {{ item.name }}
- <NTag size="small" :type="item.ok ? 'success' : 'error'" class="ml-2">{{ item.resultDesc }}</NTag>
- </template>
- <NAlert v-if="item.decodeError" type="error" class="mb-2">解析失败:{{ item.decodeError }}</NAlert>
- <!-- code=2 基本信息 -->
- <NDescriptions v-if="item.code === 2 && item.decoded" bordered size="small" :column="4" label-placement="left">
- <NDescriptionsItem v-for="f in basicFields" :key="f.key" :label="f.label">{{ item.decoded[f.key] }}</NDescriptionsItem>
- </NDescriptions>
- <!-- code=1 故障总体信息 -->
- <template v-else-if="item.code === 1 && item.decoded">
- <NDescriptions bordered size="small" :column="4" label-placement="left" class="mb-3">
- <NDescriptionsItem label="最大记录数">{{ item.decoded.maxRecords }}</NDescriptionsItem>
- <NDescriptionsItem label="当前记录数">{{ item.decoded.currentRecords }}</NDescriptionsItem>
- <NDescriptionsItem label="最早故障(设备时间)">{{ item.decoded.earliestTime }}</NDescriptionsItem>
- <NDescriptionsItem label="最新故障(设备时间)">{{ item.decoded.latestTime }}</NDescriptionsItem>
- <NDescriptionsItem label="快照通道">{{ item.decoded.snapshotUsed }}/{{ item.decoded.snapshotTotal }}</NDescriptionsItem>
- <NDescriptionsItem label="采样通道">{{ item.decoded.sampleUsed }}/{{ item.decoded.sampleTotal }}</NDescriptionsItem>
- <NDescriptionsItem label="可配快照通道">{{ item.decoded.configSnapUsed }}/{{ item.decoded.configSnapTotal }}</NDescriptionsItem>
- <NDescriptionsItem label="可配采样通道">{{ item.decoded.configSampleUsed }}/{{ item.decoded.configSampleTotal }}</NDescriptionsItem>
- </NDescriptions>
- <div class="text-sm">快照通道含义:{{ hexList(item.decoded.snapshots.map((s: any) => s.meaning)) }}</div>
- <div class="text-sm">采样通道含义:{{ hexList(item.decoded.sampleMeanings) }}</div>
- <div class="text-sm">可配采样通道:{{ cfgList(item.decoded.configSamples) }}</div>
- <div v-if="item.decoded.configSnapTotal" class="text-sm">可配快照通道:{{ cfgList(item.decoded.configSnapshots) }}</div>
- </template>
- <!-- code=3 目录 -->
- <NDataTable
- v-else-if="item.code === 3 && item.decoded"
- size="small"
- :columns="dirColumns"
- :data="item.decoded"
- :max-height="320"
- />
- <NCollapse class="mt-2">
- <NCollapseItem title="原始 hexData" name="raw">
- <pre class="text-xs m-0 whitespace-pre-wrap break-all">{{ item.raw || '-' }}</pre>
- </NCollapseItem>
- </NCollapse>
- </NCard>
- </div>
- </NCard>
- <NCard size="small">
- <OperationHistory :env="env" kind="device_info" :gateway-sn="gatewaySn" :refresh-key="historyKey" @select="(r) => op.watch(r.id)" />
- </NCard>
- </div>
- </template>
- <script setup lang="ts">
- import { ref } from 'vue'
- import {
- NAlert,
- NButton,
- NCard,
- NCheckbox,
- NCheckboxGroup,
- NCollapse,
- NCollapseItem,
- NDataTable,
- NDescriptions,
- NDescriptionsItem,
- NTag,
- useMessage,
- } from 'naive-ui'
- import type { DataTableColumns } from 'naive-ui'
- import type {
- FaultRecordConfigurableChannel,
- FaultRecordDevice,
- FaultRecordDirectoryEntry,
- } from '@/service/faultRecord/interface'
- import DeviceSelector from '../common/DeviceSelector.vue'
- import OperationHistory from '../common/OperationHistory.vue'
- import OperationProgress from '../common/OperationProgress.vue'
- import { REALTIME_CODES, configDesc, errText, fmtHex } from '../common/constants'
- import { useFaultRecordEnv, useOperation } from '../common/useFaultRecord'
- const { env } = useFaultRecordEnv()
- const message = useMessage()
- const gatewaySn = ref('')
- const device = ref<FaultRecordDevice>()
- const codes = ref<number[]>([1, 2])
- const historyKey = ref(0)
- const op = useOperation(() => historyKey.value++)
- async function read() {
- if (!device.value) return
- try {
- await op.start({
- env: env.value,
- gatewaySn: gatewaySn.value,
- deviceType: device.value.type,
- deviceSn: device.value.sn,
- kind: 'device_info',
- codeList: [...codes.value].sort(),
- })
- historyKey.value++
- } catch (e) {
- message.error(`读取失败:${errText(e)}`)
- }
- }
- const basicFields = [
- { key: 'canProtocolVersion', label: 'CAN 协议版本' },
- { key: 'storageFormat', label: '存储格式版本' },
- { key: 'paramListVersion', label: '参数列表版本' },
- { key: 'maxSampleFrequency', label: '最大采样频率 Hz' },
- { key: 'sampleFrequency', label: '采样频率 Hz' },
- { key: 'totalPoints', label: '采样点总数' },
- { key: 'prePoints', label: '故障前采样点' },
- { key: 'postPoints', label: '故障后采样点' },
- ]
- const hexList = (list: number[]) => (list?.length ? list.map((v) => fmtHex(v)).join(' ') : '-')
- const cfgList = (list: FaultRecordConfigurableChannel[]) =>
- list?.length ? list.map((c) => configDesc(c)).join(',') : '-'
- const dirColumns: DataTableColumns<FaultRecordDirectoryEntry> = [
- { title: '序号', key: 'index', width: 70 },
- { title: '发生时间(设备时间)', key: 'time', width: 190 },
- { title: '触发源', key: 'triggerSource', render: (r) => `${fmtHex(r.triggerSource)} ${r.triggerSourceName ?? ''}` },
- { title: '参数版本', key: 'paramListVersion', width: 110 },
- ]
- </script>
|