ProductTopic.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <ContentWrap>
  3. <el-tabs>
  4. <el-tab-pane label="基础通信 Topic">
  5. <Table
  6. :columns="columns1"
  7. :data="data1"
  8. :span-method="createSpanMethod(data1)"
  9. align="left"
  10. headerAlign="left"
  11. border="true"
  12. />
  13. </el-tab-pane>
  14. <el-tab-pane label="物模型通信 Topic">
  15. <Table
  16. :columns="columns2"
  17. :data="data2"
  18. :span-method="createSpanMethod(data2)"
  19. align="left"
  20. headerAlign="left"
  21. border="true"
  22. />
  23. </el-tab-pane>
  24. </el-tabs>
  25. </ContentWrap>
  26. </template>
  27. <script setup lang="ts">
  28. import { ProductVO } from '@/api/iot/product'
  29. const props = defineProps<{ product: ProductVO }>()
  30. // 定义列
  31. const columns1 = reactive([
  32. { label: '功能', field: 'function', width: 150 },
  33. { label: 'Topic 类', field: 'topicClass', width: 800 },
  34. { label: '操作权限', field: 'operationPermission', width: 100 },
  35. { label: '描述', field: 'description' }
  36. ])
  37. const columns2 = reactive([
  38. { label: '功能', field: 'function', width: 150 },
  39. { label: 'Topic 类', field: 'topicClass', width: 800 },
  40. { label: '操作权限', field: 'operationPermission', width: 100 },
  41. { label: '描述', field: 'description' }
  42. ])
  43. // TODO @haohao:这个,有没可能写到一个枚举里,方便后续维护? /Users/yunai/Java/yudao-ui-admin-vue3/src/views/ai/utils/constants.ts
  44. const data1 = computed(() => {
  45. if (!props.product || !props.product.productKey) return []
  46. return [
  47. {
  48. function: 'OTA 升级',
  49. topicClass: `/ota/device/inform/${props.product.productKey}/\${deviceName}`,
  50. operationPermission: '发布',
  51. description: '设备上报固件升级信息'
  52. },
  53. {
  54. function: 'OTA 升级',
  55. topicClass: `/ota/device/upgrade/${props.product.productKey}/\${deviceName}`,
  56. operationPermission: '订阅',
  57. description: '固件升级信息下行'
  58. },
  59. {
  60. function: 'OTA 升级',
  61. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/ota/firmware/get`,
  62. operationPermission: '发布',
  63. description: '设备上报固件升级进度'
  64. },
  65. {
  66. function: 'OTA 升级',
  67. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/ota/firmware/get`,
  68. operationPermission: '发布',
  69. description: '设备主动拉取固件升级信息'
  70. },
  71. {
  72. function: '设备标签',
  73. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/deviceinfo/update`,
  74. operationPermission: '发布',
  75. description: '设备上报标签数据'
  76. },
  77. {
  78. function: '设备标签',
  79. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/deviceinfo/update_reply`,
  80. operationPermission: '订阅',
  81. description: '云端响应标签上报'
  82. },
  83. {
  84. function: '设备标签',
  85. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/deviceinfo/delete`,
  86. operationPermission: '订阅',
  87. description: '设备删除标签信息'
  88. },
  89. {
  90. function: '设备标签',
  91. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/deviceinfo/delete_reply`,
  92. operationPermission: '订阅',
  93. description: '云端响应标签删除'
  94. },
  95. {
  96. function: '时钟同步',
  97. topicClass: `/ext/ntp/${props.product.productKey}/\${deviceName}/request`,
  98. operationPermission: '发布',
  99. description: 'NTP 时钟同步请求'
  100. },
  101. {
  102. function: '时钟同步',
  103. topicClass: `/ext/ntp/${props.product.productKey}/\${deviceName}/response`,
  104. operationPermission: '订阅',
  105. description: 'NTP 时钟同步响应'
  106. },
  107. {
  108. function: '设备影子',
  109. topicClass: `/shadow/update/${props.product.productKey}/\${deviceName}`,
  110. operationPermission: '发布',
  111. description: '设备影子发布'
  112. },
  113. {
  114. function: '设备影子',
  115. topicClass: `/shadow/get/${props.product.productKey}/\${deviceName}`,
  116. operationPermission: '订阅',
  117. description: '设备接收影子变更'
  118. },
  119. {
  120. function: '配置更新',
  121. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/config/push`,
  122. operationPermission: '订阅',
  123. description: '云端主动下推配置信息'
  124. },
  125. {
  126. function: '配置更新',
  127. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/config/get`,
  128. operationPermission: '发布',
  129. description: '设备端查询配置信息'
  130. },
  131. {
  132. function: '配置更新',
  133. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/config/get_reply`,
  134. operationPermission: '订阅',
  135. description: '云端响应配置信息'
  136. },
  137. {
  138. function: '广播',
  139. topicClass: `/broadcast/${props.product.productKey}/\${identifier}`,
  140. operationPermission: '订阅',
  141. description: '广播 Topic,identifier 为用户自定义字符串'
  142. }
  143. ]
  144. })
  145. const data2 = computed(() => {
  146. if (!props.product || !props.product.productKey) return []
  147. return [
  148. {
  149. function: '属性上报',
  150. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/event/property/post`,
  151. operationPermission: '发布',
  152. description: '设备属性上报'
  153. },
  154. {
  155. function: '属性上报',
  156. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/event/property/post_reply`,
  157. operationPermission: '订阅',
  158. description: '云端响应属性上报'
  159. },
  160. {
  161. function: '属性设置',
  162. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/service/property/set`,
  163. operationPermission: '订阅',
  164. description: '设备属性设置'
  165. },
  166. {
  167. function: '事件上报',
  168. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/event/\${tsl.event.identifier}/post`,
  169. operationPermission: '发布',
  170. description: '设备事件上报'
  171. },
  172. {
  173. function: '事件上报',
  174. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/event/\${tsl.event.identifier}/post_reply`,
  175. operationPermission: '订阅',
  176. description: '云端响应事件上报'
  177. },
  178. {
  179. function: '服务调用',
  180. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/service/\${tsl.service.identifier}`,
  181. operationPermission: '订阅',
  182. description: '设备服务调用'
  183. },
  184. {
  185. function: '服务调用',
  186. topicClass: `/sys/${props.product.productKey}/\${deviceName}/thing/service/\${tsl.service.identifier}_reply`,
  187. operationPermission: '发布',
  188. description: '设备端响应服务调用'
  189. }
  190. ]
  191. })
  192. // 通用的单元格合并方法生成器
  193. const createSpanMethod = (data: any[]) => {
  194. // 预处理,计算每个功能的合并行数
  195. const rowspanMap: Record<number, number> = {}
  196. let currentFunction = ''
  197. let startIndex = 0
  198. let count = 0
  199. data.forEach((item, index) => {
  200. if (item.function !== currentFunction) {
  201. if (count > 0) {
  202. rowspanMap[startIndex] = count
  203. }
  204. currentFunction = item.function
  205. startIndex = index
  206. count = 1
  207. } else {
  208. count++
  209. }
  210. })
  211. // 处理最后一组
  212. if (count > 0) {
  213. rowspanMap[startIndex] = count
  214. }
  215. // 返回 span 方法
  216. return ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
  217. if (columnIndex === 0) {
  218. // 仅对“功能”列进行合并
  219. const rowspan = rowspanMap[rowIndex] || 0
  220. if (rowspan > 0) {
  221. return {
  222. rowspan,
  223. colspan: 1
  224. }
  225. } else {
  226. return {
  227. rowspan: 0,
  228. colspan: 0
  229. }
  230. }
  231. }
  232. }
  233. }
  234. </script>