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