index.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <div class="p-4 flex flex-col gap-4">
  3. <NCard size="small">
  4. <DeviceSelector v-model:gateway-sn="gatewaySn" v-model:device="device" :env="env" />
  5. </NCard>
  6. <NCard size="small" title="读取设备信息(cmd=0)">
  7. <div class="flex flex-wrap gap-4 items-center">
  8. <NCheckboxGroup v-model:value="codes">
  9. <NCheckbox v-for="c in REALTIME_CODES" :key="c.code" :value="c.code" :label="`${c.code} ${c.name}`" />
  10. </NCheckboxGroup>
  11. <NButton type="primary" :disabled="!device || codes.length === 0" :loading="op.running.value" @click="read">
  12. 读取
  13. </NButton>
  14. </div>
  15. </NCard>
  16. <NCard v-if="op.detail.value" size="small" title="结果">
  17. <OperationProgress :detail="op.detail.value" :cancel="op.cancel" />
  18. <div class="mt-3 flex flex-col gap-4">
  19. <NCard v-for="item in op.detail.value.items" :key="item.code" size="small" embedded>
  20. <template #header>
  21. {{ item.code }} {{ item.name }}
  22. <NTag size="small" :type="item.ok ? 'success' : 'error'" class="ml-2">{{ item.resultDesc }}</NTag>
  23. </template>
  24. <NAlert v-if="item.decodeError" type="error" class="mb-2">解析失败:{{ item.decodeError }}</NAlert>
  25. <!-- code=2 基本信息 -->
  26. <NDescriptions v-if="item.code === 2 && item.decoded" bordered size="small" :column="4" label-placement="left">
  27. <NDescriptionsItem v-for="f in basicFields" :key="f.key" :label="f.label">{{ item.decoded[f.key] }}</NDescriptionsItem>
  28. </NDescriptions>
  29. <!-- code=1 故障总体信息 -->
  30. <template v-else-if="item.code === 1 && item.decoded">
  31. <NDescriptions bordered size="small" :column="4" label-placement="left" class="mb-3">
  32. <NDescriptionsItem label="最大记录数">{{ item.decoded.maxRecords }}</NDescriptionsItem>
  33. <NDescriptionsItem label="当前记录数">{{ item.decoded.currentRecords }}</NDescriptionsItem>
  34. <NDescriptionsItem label="最早故障(设备时间)">{{ item.decoded.earliestTime }}</NDescriptionsItem>
  35. <NDescriptionsItem label="最新故障(设备时间)">{{ item.decoded.latestTime }}</NDescriptionsItem>
  36. <NDescriptionsItem label="快照通道">{{ item.decoded.snapshotUsed }}/{{ item.decoded.snapshotTotal }}</NDescriptionsItem>
  37. <NDescriptionsItem label="采样通道">{{ item.decoded.sampleUsed }}/{{ item.decoded.sampleTotal }}</NDescriptionsItem>
  38. <NDescriptionsItem label="可配快照通道">{{ item.decoded.configSnapUsed }}/{{ item.decoded.configSnapTotal }}</NDescriptionsItem>
  39. <NDescriptionsItem label="可配采样通道">{{ item.decoded.configSampleUsed }}/{{ item.decoded.configSampleTotal }}</NDescriptionsItem>
  40. </NDescriptions>
  41. <div class="text-sm">快照通道含义:{{ hexList(item.decoded.snapshots.map((s: any) => s.meaning)) }}</div>
  42. <div class="text-sm">采样通道含义:{{ hexList(item.decoded.sampleMeanings) }}</div>
  43. <div class="text-sm">可配采样通道:{{ cfgList(item.decoded.configSamples) }}</div>
  44. <div v-if="item.decoded.configSnapTotal" class="text-sm">可配快照通道:{{ cfgList(item.decoded.configSnapshots) }}</div>
  45. </template>
  46. <!-- code=3 目录 -->
  47. <NDataTable
  48. v-else-if="item.code === 3 && item.decoded"
  49. size="small"
  50. :columns="dirColumns"
  51. :data="item.decoded"
  52. :max-height="320"
  53. />
  54. <NCollapse class="mt-2">
  55. <NCollapseItem title="原始 hexData" name="raw">
  56. <pre class="text-xs m-0 whitespace-pre-wrap break-all">{{ item.raw || '-' }}</pre>
  57. </NCollapseItem>
  58. </NCollapse>
  59. </NCard>
  60. </div>
  61. </NCard>
  62. <NCard size="small">
  63. <OperationHistory :env="env" kind="device_info" :gateway-sn="gatewaySn" :refresh-key="historyKey" @select="(r) => op.watch(r.id)" />
  64. </NCard>
  65. </div>
  66. </template>
  67. <script setup lang="ts">
  68. import { ref } from 'vue'
  69. import {
  70. NAlert,
  71. NButton,
  72. NCard,
  73. NCheckbox,
  74. NCheckboxGroup,
  75. NCollapse,
  76. NCollapseItem,
  77. NDataTable,
  78. NDescriptions,
  79. NDescriptionsItem,
  80. NTag,
  81. useMessage,
  82. } from 'naive-ui'
  83. import type { DataTableColumns } from 'naive-ui'
  84. import type {
  85. FaultRecordConfigurableChannel,
  86. FaultRecordDevice,
  87. FaultRecordDirectoryEntry,
  88. } from '@/service/faultRecord/interface'
  89. import DeviceSelector from '../common/DeviceSelector.vue'
  90. import OperationHistory from '../common/OperationHistory.vue'
  91. import OperationProgress from '../common/OperationProgress.vue'
  92. import { REALTIME_CODES, configDesc, errText, fmtHex } from '../common/constants'
  93. import { useFaultRecordEnv, useOperation } from '../common/useFaultRecord'
  94. const { env } = useFaultRecordEnv()
  95. const message = useMessage()
  96. const gatewaySn = ref('')
  97. const device = ref<FaultRecordDevice>()
  98. const codes = ref<number[]>([1, 2])
  99. const historyKey = ref(0)
  100. const op = useOperation(() => historyKey.value++)
  101. async function read() {
  102. if (!device.value) return
  103. try {
  104. await op.start({
  105. env: env.value,
  106. gatewaySn: gatewaySn.value,
  107. deviceType: device.value.type,
  108. deviceSn: device.value.sn,
  109. kind: 'device_info',
  110. codeList: [...codes.value].sort(),
  111. })
  112. historyKey.value++
  113. } catch (e) {
  114. message.error(`读取失败:${errText(e)}`)
  115. }
  116. }
  117. const basicFields = [
  118. { key: 'canProtocolVersion', label: 'CAN 协议版本' },
  119. { key: 'storageFormat', label: '存储格式版本' },
  120. { key: 'paramListVersion', label: '参数列表版本' },
  121. { key: 'maxSampleFrequency', label: '最大采样频率 Hz' },
  122. { key: 'sampleFrequency', label: '采样频率 Hz' },
  123. { key: 'totalPoints', label: '采样点总数' },
  124. { key: 'prePoints', label: '故障前采样点' },
  125. { key: 'postPoints', label: '故障后采样点' },
  126. ]
  127. const hexList = (list: number[]) => (list?.length ? list.map((v) => fmtHex(v)).join(' ') : '-')
  128. const cfgList = (list: FaultRecordConfigurableChannel[]) =>
  129. list?.length ? list.map((c) => configDesc(c)).join(',') : '-'
  130. const dirColumns: DataTableColumns<FaultRecordDirectoryEntry> = [
  131. { title: '序号', key: 'index', width: 70 },
  132. { title: '发生时间(设备时间)', key: 'time', width: 190 },
  133. { title: '触发源', key: 'triggerSource', render: (r) => `${fmtHex(r.triggerSource)} ${r.triggerSourceName ?? ''}` },
  134. { title: '参数版本', key: 'paramListVersion', width: 110 },
  135. ]
  136. </script>