DeviceLogUploadRecordDrawer.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. <template>
  2. <a-drawer title="设备日志上传记录" placement="right" v-model:visible="sVisible" @update:visible="onVisibleChange"
  3. :width="800">
  4. <!-- 设备日志上传记录 -->
  5. <div class="device-log-upload-record-wrap">
  6. <div class="page-action-row">
  7. <a-button type="primary" @click="onUploadDeviceLog">上传日志</a-button>
  8. </div>
  9. <div class="device-log-upload-list">
  10. <a-table :columns="deviceLogUploadListColumns" :scroll="{ x: '100%', y: 600 }"
  11. :data-source="deviceUploadLogState.uploadLogList" :loading="deviceUploadLogState.loading"
  12. :pagination="deviceUploadLogState.paginationProp" @change="onDeviceUploadLogTableChange" rowKey="logs_id">
  13. <!-- 设备类型 -->
  14. <template #device_type="{ record }">
  15. <div>
  16. <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{
  17. DEVICE_NAME[getDeviceInfo(record).parents[0].device_model.device_model_key] }}</div>
  18. <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{
  19. DEVICE_NAME[getDeviceInfo(record).hosts[0].device_model.device_model_key] }}</div>
  20. </div>
  21. </template>
  22. <!-- 设备sn -->
  23. <template #device_sn="{ record }">
  24. <div>
  25. <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{
  26. getDeviceInfo(record).parents[0].sn }}</div>
  27. <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{
  28. getDeviceInfo(record).hosts[0].sn }}</div>
  29. </div>
  30. </template>
  31. <!-- 上传状态 -->
  32. <template #status="{ record }">
  33. <div>
  34. <div>
  35. <span class="circle-icon" :style="{ backgroundColor: getDeviceLogUploadStatus(record).color }"></span>
  36. {{ getDeviceLogUploadStatus(record).text }}
  37. </div>
  38. <div v-if="record.status === DeviceLogUploadStatusEnum.Uploading">
  39. <a-progress :percent="getLogProgress(record)" />
  40. </div>
  41. </div>
  42. </template>
  43. <!-- 操作 -->
  44. <template #action="{ record }">
  45. <div class="row-action">
  46. <a-tooltip title="查看详情">
  47. <FileTextOutlined @click="showDeviceLogDetail(record)" />
  48. </a-tooltip>
  49. <span v-if="record.status === DeviceLogUploadStatusEnum.Uploading">
  50. <a-tooltip title="取消">
  51. <StopOutlined @click="onCancelUploadDeviceLog(record)" />
  52. </a-tooltip>
  53. </span>
  54. <span v-else>
  55. <a-tooltip title="删除">
  56. <DeleteOutlined @click="onDeleteUploadDeviceLog(record)" />
  57. </a-tooltip>
  58. </span>
  59. </div>
  60. </template>
  61. </a-table>
  62. </div>
  63. </div>
  64. </a-drawer>
  65. <!-- 设备日志上传弹框 -->
  66. <DeviceLogUploadModal v-model:visible="deviceLogUploadModalVisible" :device="props.device"
  67. @upload-log-ok="onUploadLogOk"></DeviceLogUploadModal>
  68. <!-- 设备日志上传详情弹框 -->
  69. <DeviceLogDetailModal v-model:visible="deviceLogDetailModalVisible" :deviceLog="currentDeviceLog">
  70. </DeviceLogDetailModal>
  71. </template>
  72. <script lang="ts" setup>
  73. import { watchEffect, reactive, ref, defineProps, defineEmits } from 'vue'
  74. import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface'
  75. import { IPage } from '/@/api/http/type'
  76. import { Device, DOMAIN, DEVICE_NAME } from '/@/types/device'
  77. import DeviceLogUploadModal from './DeviceLogUploadModal.vue'
  78. import DeviceLogDetailModal from './DeviceLogDetailModal.vue'
  79. import { getDeviceUploadLogList, GetDeviceUploadLogListRsp, cancelDeviceLogUpload, deleteDeviceLogUpload } from '/@/api/device-log'
  80. import { StopOutlined, DeleteOutlined, FileTextOutlined } from '@ant-design/icons-vue'
  81. import { DeviceLogUploadStatusEnum, DeviceLogUploadStatusMap, DeviceLogUploadStatusColor, DeviceLogUploadInfo, DeviceLogUploadWsStatusMap, DeviceLogProgressInfo } from '/@/types/device-log'
  82. import { useDeviceLogUploadProgressEvent } from './use-device-log-upload-progress-event'
  83. import { Modal } from 'ant-design-vue'
  84. const props = defineProps<{
  85. visible: boolean,
  86. device: null | Device,
  87. }>()
  88. const emit = defineEmits(['update:visible'])
  89. const sVisible = ref(false)
  90. watchEffect(() => {
  91. sVisible.value = props.visible
  92. // 显示弹框时,获取设备日志上传记录信息
  93. if (props.visible) {
  94. getDeviceUploadLogInfo()
  95. }
  96. })
  97. function onVisibleChange(sVisible: boolean) {
  98. setVisible(sVisible)
  99. }
  100. function setVisible(v: boolean, e?: Event) {
  101. sVisible.value = v
  102. emit('update:visible', v, e)
  103. }
  104. // 日志列表
  105. const deviceLogUploadListColumns: ColumnProps[] = [
  106. { title: '上传时间', dataIndex: 'create_time', width: 100 },
  107. { title: '设备型号', dataIndex: 'device_type', width: 80, slots: { customRender: 'device_type' } },
  108. { title: '设备SN', dataIndex: 'device_sn', width: 120, slots: { customRender: 'device_sn' } },
  109. { title: '上传状态', dataIndex: 'status', width: 120, slots: { customRender: 'status' } },
  110. { title: '操作', dataIndex: 'actions', width: 80, slots: { customRender: 'action' } },
  111. ]
  112. const deviceUploadLogState = reactive({
  113. uploadLogList: [] as GetDeviceUploadLogListRsp[],
  114. loading: false,
  115. paginationProp: {
  116. pageSizeOptions: ['20', '50', '100'],
  117. showQuickJumper: true,
  118. showSizeChanger: true,
  119. pageSize: 50,
  120. current: 1,
  121. total: 0
  122. }
  123. })
  124. // 获取上传的设备日志
  125. async function getDeviceUploadLogInfo() {
  126. deviceUploadLogState.loading = true
  127. try {
  128. const { code, data } = await getDeviceUploadLogList({
  129. device_sn: props.device?.device_sn || '',
  130. page: deviceUploadLogState.paginationProp.current,
  131. page_size: deviceUploadLogState.paginationProp.pageSize
  132. })
  133. if (code === 0) {
  134. deviceUploadLogState.uploadLogList = data.list
  135. deviceUploadLogState.paginationProp.total = data.pagination.total
  136. deviceUploadLogState.paginationProp.current = data.pagination.page
  137. deviceUploadLogState.paginationProp.pageSize = data.pagination.page_size
  138. }
  139. deviceUploadLogState.loading = false
  140. } catch (error) {
  141. deviceUploadLogState.loading = false
  142. }
  143. }
  144. type Pagination = TableState['pagination']
  145. // 获取设备信息
  146. function getDeviceInfo(deviceLogItem: GetDeviceUploadLogListRsp) {
  147. const { device_topo: deviceTopo } = deviceLogItem
  148. return deviceTopo
  149. }
  150. // 获取上传状态
  151. function getDeviceLogUploadStatus(deviceLogItem: GetDeviceUploadLogListRsp) {
  152. const statusObj = {
  153. color: '',
  154. text: ''
  155. }
  156. const { status } = deviceLogItem
  157. statusObj.color = DeviceLogUploadStatusColor[status]
  158. statusObj.text = DeviceLogUploadStatusMap[status]
  159. return statusObj
  160. }
  161. // 获取上传进度
  162. function getLogProgress(deviceLogItem: GetDeviceUploadLogListRsp) {
  163. let percent = 0
  164. const { logs_progress } = deviceLogItem
  165. if (logs_progress && logs_progress.length > 0) {
  166. logs_progress.forEach(log => {
  167. percent += (log.progress || 0)
  168. })
  169. percent = percent / logs_progress.length
  170. }
  171. return Math.floor(percent)
  172. }
  173. // 设备日志上传进度更新
  174. function onDeviceLogUploadWs(data: DeviceLogUploadInfo) {
  175. const { sn, output } = data
  176. if (output) {
  177. const { files, status, logs_id: logId } = output || {}
  178. const deviceLogItem = deviceUploadLogState.uploadLogList.find(log => log.logs_id === logId)
  179. if (!deviceLogItem) return
  180. if (status) {
  181. deviceLogItem.status = DeviceLogUploadWsStatusMap[status]
  182. }
  183. if (files && files.length > 0) {
  184. const logsProgress = [] as DeviceLogProgressInfo[]
  185. files.forEach(file => {
  186. logsProgress.push({
  187. ...file,
  188. status: DeviceLogUploadWsStatusMap[file.status]
  189. })
  190. })
  191. deviceLogItem.logs_progress = logsProgress
  192. }
  193. }
  194. }
  195. useDeviceLogUploadProgressEvent(onDeviceLogUploadWs)
  196. // 搜索
  197. async function onDeviceUploadLogTableChange(page: Pagination) {
  198. deviceUploadLogState.paginationProp.current = page?.current || 1
  199. deviceUploadLogState.paginationProp.pageSize = page?.pageSize || 20
  200. await getDeviceUploadLogInfo()
  201. }
  202. // 查看上传设备日志详情
  203. const deviceLogDetailModalVisible = ref(false)
  204. const currentDeviceLog = ref({} as GetDeviceUploadLogListRsp)
  205. function showDeviceLogDetail(deviceLogItem: GetDeviceUploadLogListRsp) {
  206. if (!deviceLogItem) return
  207. currentDeviceLog.value = deviceLogItem
  208. deviceLogDetailModalVisible.value = true
  209. }
  210. // 取消上传设备日志
  211. async function onCancelUploadDeviceLog(deviceLogItem: GetDeviceUploadLogListRsp) {
  212. Modal.confirm({
  213. title: '取消日志上传',
  214. content: '您确认取消设备日志上传吗?',
  215. okType: 'danger',
  216. onOk() {
  217. cancelDeviceLogUploadOk()
  218. },
  219. })
  220. }
  221. async function cancelDeviceLogUploadOk() {
  222. const { code } = await cancelDeviceLogUpload({
  223. device_sn: props.device?.device_sn || '',
  224. module_list: [DOMAIN.DOCK, DOMAIN.DRONE],
  225. status: 'cancel'
  226. })
  227. if (code === 0) {
  228. await getDeviceUploadLogInfo()
  229. }
  230. }
  231. // 删除上传的设备日志
  232. function onDeleteUploadDeviceLog(deviceLogItem: GetDeviceUploadLogListRsp) {
  233. Modal.confirm({
  234. title: '删除上传日志',
  235. content: '您确认删除该条已上传设备日志吗?',
  236. okType: 'danger',
  237. onOk() {
  238. deleteUploadDeviceLogOk(deviceLogItem)
  239. },
  240. })
  241. }
  242. async function deleteUploadDeviceLogOk(deviceLogItem: GetDeviceUploadLogListRsp) {
  243. const { code } = await deleteDeviceLogUpload({
  244. device_sn: props.device?.device_sn || '',
  245. logs_id: deviceLogItem.logs_id
  246. })
  247. if (code === 0) {
  248. await getDeviceUploadLogInfo()
  249. }
  250. }
  251. // 上传日志
  252. const deviceLogUploadModalVisible = ref(false)
  253. function onUploadDeviceLog() {
  254. deviceLogUploadModalVisible.value = true
  255. }
  256. function onUploadLogOk() {
  257. // 刷新列表
  258. getDeviceUploadLogInfo()
  259. }
  260. </script>
  261. <style lang="scss" scoped>
  262. .device-log-upload-record-wrap {
  263. .page-action-row {
  264. display: flex;
  265. justify-content: space-between;
  266. width: 100%;
  267. }
  268. .device-log-upload-list {
  269. padding: 20px 0 10px;
  270. }
  271. .circle-icon {
  272. display: inline-block;
  273. width: 12px;
  274. height: 12px;
  275. margin-right: 3px;
  276. border-radius: 50%;
  277. vertical-align: middle;
  278. flex-shrink: 0;
  279. }
  280. .row-action {
  281. color: #2d8cf0;
  282. &>span {
  283. margin-right: 10px;
  284. }
  285. }
  286. }
  287. </style>