From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/iot/ota/task/OtaTaskDetail.vue | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 285 insertions(+), 0 deletions(-)
diff --git a/src/views/iot/ota/task/OtaTaskDetail.vue b/src/views/iot/ota/task/OtaTaskDetail.vue
new file mode 100644
index 0000000..950a3f9
--- /dev/null
+++ b/src/views/iot/ota/task/OtaTaskDetail.vue
@@ -0,0 +1,285 @@
+<template>
+ <Dialog v-model="dialogVisible" title="鍗囩骇浠诲姟璇︽儏" width="1200px" append-to-body>
+ <!-- 浠诲姟淇℃伅 -->
+ <ContentWrap title="浠诲姟淇℃伅" class="mb-20px">
+ <el-descriptions :column="3" v-loading="taskLoading" border>
+ <el-descriptions-item label="浠诲姟缂栧彿">{{ task.id }}</el-descriptions-item>
+ <el-descriptions-item label="浠诲姟鍚嶇О">{{ task.name }}</el-descriptions-item>
+ <el-descriptions-item label="鍗囩骇鑼冨洿">
+ <dict-tag :type="DICT_TYPE.IOT_OTA_TASK_DEVICE_SCOPE" :value="task.deviceScope" />
+ </el-descriptions-item>
+ <el-descriptions-item label="浠诲姟鐘舵��">
+ <dict-tag :type="DICT_TYPE.IOT_OTA_TASK_STATUS" :value="task.status" />
+ </el-descriptions-item>
+ <el-descriptions-item label="鍒涘缓鏃堕棿">
+ {{ task.createTime ? formatDate(task.createTime) : '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="浠诲姟鎻忚堪" :span="3">
+ {{ task.description }}
+ </el-descriptions-item>
+ </el-descriptions>
+ </ContentWrap>
+
+ <!-- 浠诲姟鍗囩骇璁惧缁熻 -->
+ <ContentWrap title="鍗囩骇璁惧缁熻" class="mb-20px">
+ <el-row :gutter="20" class="py-20px" v-loading="taskStatisticsLoading">
+ <el-col :span="6">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-blue-500">
+ {{ Object.values(taskStatistics).reduce((sum, count) => sum + (count || 0), 0) || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">鍗囩骇璁惧鎬绘暟</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-gray-400">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.PENDING.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">寰呮帹閫�</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-blue-400">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.PUSHED.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">宸叉帹閫�</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-yellow-500">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.UPGRADING.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">姝e湪鍗囩骇</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-green-500">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.SUCCESS.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">鍗囩骇鎴愬姛</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-red-500">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.FAILURE.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">鍗囩骇澶辫触</div>
+ </div>
+ </el-col>
+ <el-col :span="3">
+ <div class="text-center p-20px border border-solid border-gray-200 rounded bg-gray-50">
+ <div class="text-32px font-bold mb-8px text-gray-400">
+ {{ taskStatistics[IoTOtaTaskRecordStatusEnum.CANCELED.value] || 0 }}
+ </div>
+ <div class="text-14px text-gray-600">鍗囩骇鍙栨秷</div>
+ </div>
+ </el-col>
+ </el-row>
+ </ContentWrap>
+
+ <!-- 璁惧绠$悊 -->
+ <ContentWrap title="鍗囩骇璁惧璁板綍">
+ <!-- Tab 鍒囨崲 -->
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick" class="mb-15px">
+ <el-tab-pane v-for="tab in statusTabs" :key="tab.key" :label="tab.label" :name="tab.key" />
+ </el-tabs>
+ <!-- Tab 鍐呭 -->
+ <div v-for="tab in statusTabs" :key="tab.key" v-show="activeTab === tab.key">
+ <!-- 璁惧鍒楄〃 -->
+ <el-table
+ v-loading="recordLoading"
+ :data="recordList"
+ :stripe="true"
+ :show-overflow-tooltip="true"
+ >
+ <el-table-column label="璁惧鍚嶇О" align="center" prop="deviceName" />
+ <el-table-column label="褰撳墠鐗堟湰" align="center" prop="fromFirmwareVersion" />
+ <el-table-column label="鍗囩骇鐘舵��" align="center" prop="status" width="120">
+ <template #default="scope">
+ <dict-tag :type="DICT_TYPE.IOT_OTA_TASK_RECORD_STATUS" :value="scope.row.status" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鍗囩骇杩涘害" align="center" prop="progress" width="120">
+ <template #default="scope"> {{ scope.row.progress }}% </template>
+ </el-table-column>
+ <el-table-column label="鐘舵�佹弿杩�" align="center" prop="description" />
+ <el-table-column label="鏇存柊鏃堕棿" align="center" prop="updateTime" width="180">
+ <template #default="scope">
+ {{ formatDate(scope.row.updateTime) }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" width="80">
+ <template #default="scope">
+ <el-button
+ v-if="
+ [
+ IoTOtaTaskRecordStatusEnum.PENDING.value,
+ IoTOtaTaskRecordStatusEnum.PUSHED.value,
+ IoTOtaTaskRecordStatusEnum.UPGRADING.value
+ ].includes(scope.row.status)
+ "
+ link
+ type="danger"
+ @click="handleCancelUpgrade(scope.row)"
+ v-hasPermi="['iot:ota-task-record:cancel']"
+ >
+ 鍙栨秷
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <!-- 鍒嗛〉 -->
+ <Pagination
+ :total="recordTotal"
+ v-model:page="queryParams.pageNo"
+ v-model:limit="queryParams.pageSize"
+ @pagination="getRecordList"
+ />
+ </div>
+ </ContentWrap>
+ </Dialog>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed } from 'vue'
+import { TabsPaneContext } from 'element-plus'
+import { Dialog } from '@/components/Dialog'
+import { ContentWrap } from '@/components/ContentWrap'
+import Pagination from '@/components/Pagination/index.vue'
+import { IoTOtaTaskApi, OtaTask } from '@/api/iot/ota/task'
+import { IoTOtaTaskRecordApi, OtaTaskRecord } from '@/api/iot/ota/task/record'
+import { DICT_TYPE } from '@/utils/dict'
+import { IoTOtaTaskRecordStatusEnum } from '@/views/iot/utils/constants'
+import { formatDate } from '@/utils/formatTime'
+
+/** OTA 浠诲姟璇︽儏缁勪欢 */
+defineOptions({ name: 'OtaTaskDetail' })
+
+const message = useMessage() // 娑堟伅寮圭獥
+const dialogVisible = ref(false) // 寮圭獥鐨勬槸鍚﹀睍绀�
+
+const taskId = ref<number>() // 浠诲姟缂栧彿
+const taskLoading = ref(false) // 浠诲姟鍔犺浇鐘舵��
+const task = ref<OtaTask>({} as OtaTask) // 浠诲姟淇℃伅
+
+const taskStatisticsLoading = ref(false) // 浠诲姟缁熻鍔犺浇鐘舵��
+const taskStatistics = ref<Record<string, number>>({}) // 浠诲姟缁熻鏁版嵁
+
+const recordLoading = ref(false) // 璁板綍鍒楄〃鍔犺浇鐘舵��
+const recordList = ref<OtaTaskRecord[]>([]) // 璁板綍鍒楄〃鏁版嵁
+const recordTotal = ref(0) // 璁板綍鎬绘暟
+const queryParams = reactive({
+ pageNo: 1,
+ pageSize: 10,
+ taskId: undefined as number | undefined,
+ status: undefined as number | undefined
+}) // 鏌ヨ鍙傛暟
+const activeTab = ref('') // 褰撳墠婵�娲荤殑鏍囩椤�
+
+/** 鐘舵�佹爣绛鹃厤缃� */
+const statusTabs = computed(() => {
+ const tabs = [{ key: '', label: '鍏ㄩ儴璁惧' }]
+ Object.values(IoTOtaTaskRecordStatusEnum).forEach((status) => {
+ tabs.push({
+ key: status.value.toString(),
+ label: status.label
+ })
+ })
+ return tabs
+})
+
+/** 鑾峰彇浠诲姟璇︽儏 */
+const getTaskInfo = async () => {
+ if (!taskId.value) {
+ return
+ }
+ taskLoading.value = true
+ try {
+ task.value = await IoTOtaTaskApi.getOtaTask(taskId.value)
+ } finally {
+ taskLoading.value = false
+ }
+}
+
+/** 鑾峰彇缁熻鏁版嵁 */
+const getStatistics = async () => {
+ if (!taskId.value) {
+ return
+ }
+ taskStatisticsLoading.value = true
+ try {
+ taskStatistics.value = await IoTOtaTaskRecordApi.getOtaTaskRecordStatusStatistics(
+ undefined,
+ taskId.value
+ )
+ } finally {
+ taskStatisticsLoading.value = false
+ }
+}
+
+/** 鑾峰彇鍗囩骇璁板綍鍒楄〃 */
+const getRecordList = async () => {
+ if (!taskId.value) {
+ return
+ }
+ recordLoading.value = true
+ try {
+ queryParams.taskId = taskId.value
+ const data = await IoTOtaTaskRecordApi.getOtaTaskRecordPage(queryParams)
+ recordList.value = data.list || []
+ recordTotal.value = data.total || 0
+ } finally {
+ recordLoading.value = false
+ }
+}
+
+/** 鍒囨崲鏍囩 */
+const handleTabClick = (tab: TabsPaneContext) => {
+ const tabKey = tab.paneName as string
+ activeTab.value = tabKey
+ queryParams.pageNo = 1
+ queryParams.status = activeTab.value === '' ? undefined : parseInt(tabKey)
+ getRecordList()
+}
+
+/** 鍙栨秷鍗囩骇 */
+const emit = defineEmits(['success']) // 瀹氫箟 success 浜嬩欢锛岀敤浜庢搷浣滄垚鍔熷悗鐨勫洖璋�
+const handleCancelUpgrade = async (record: OtaTaskRecord) => {
+ try {
+ await message.confirm('纭瑕佸彇娑堣璁惧鐨勫崌绾т换鍔″悧锛�')
+ await IoTOtaTaskRecordApi.cancelOtaTaskRecord(record.id!)
+ message.success('鍙栨秷鎴愬姛')
+ // 鍒锋柊鏁版嵁
+ await getRecordList()
+ await getStatistics()
+ await getTaskInfo()
+ // 閫氱煡鐖剁粍浠跺埛鏂版暟鎹�
+ emit('success')
+ } catch (error) {
+ console.error('鍙栨秷鍗囩骇澶辫触', error)
+ }
+}
+
+/** 鎵撳紑寮圭獥 */
+const open = (id: number) => {
+ taskId.value = id
+ dialogVisible.value = true
+ // 閲嶇疆鏁版嵁
+ activeTab.value = ''
+ queryParams.pageNo = 1
+ queryParams.status = undefined
+
+ // 鍔犺浇鏁版嵁
+ getTaskInfo()
+ getStatistics()
+ getRecordList()
+}
+
+/** 鏆撮湶鏂规硶 */
+defineExpose({ open })
+</script>
--
Gitblit v1.8.0