From fc633bd6fcb581ab2fe34f32d71023c2af017cb5 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 03 Apr 2025 17:20:16 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard

---
 src/views/SignMachineNest/MachineRight/MachineStatus.vue                                                   |   16 
 src/views/TaskManage/components/TaskLeft/TaskLeft.vue                                                      |   19 
 src/views/TaskManage/components/TaskLeft/TaskTotal.vue                                                     |  100 +++
 src/api/home/task.js                                                                                       |   52 +
 src/api/home/machineNest.js                                                                                |   20 
 .env.test                                                                                                  |    3 
 src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/JobRelatedEvents.vue |   92 +++
 src/views/TaskManage/components/TaskRight/TaskEvent.vue                                                    |  150 +++++
 src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue |  130 ++++
 src/views/TaskManage/components/TaskLeft/TaskIndustry.vue                                                  |  132 ++++
 src/views/SignMachineNest/MachineRight/MachineRight.vue                                                    |    0 
 src/views/TaskManage/components/TaskIntermediateContent/TaskIntermediateContent.vue                        |  148 +++++
 src/layout/Header.vue                                                                                      |    2 
 src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJob.vue                         |   74 ++
 src/views/TaskManage/components/TaskRight/TaskRight.vue                                                    |   25 
 src/store/modules/user.js                                                                                  |    1 
 src/views/SignMachineNest/MachineRight/MachineMonitor.vue                                                  |    0 
 src/api/home/common.js                                                                                     |   27 
 src/assets/images/signMachineNest/return.png                                                               |    0 
 src/views/SignMachineNest/MachineLeft/MachineLeft.vue                                                      |   46 +
 src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceEvent.vue                                 |   82 ++
 src/views/SignMachineNest/SignMachineNest.vue                                                              |    9 
 src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue                                            |    4 
 src/views/TaskManage/components/TaskRight/TaskTime.vue                                                     |  125 ++++
 .env.development                                                                                           |    2 
 /dev/null                                                                                                  |   87 ---
 src/views/SignMachineNest/MachineLeft/MachineData.vue                                                      |    0 
 src/views/SignMachineNest/MachineRight/MachineTableDetails/MachineTableDetails.vue                         |   75 ++
 src/views/TaskManage/components/SearchBox.vue                                                              |  192 ++++++
 .env.production                                                                                            |    2 
 src/views/SignMachineNest/MachineRight/InspectionRaskList.vue                                              |   10 
 src/views/TaskManage/TaskManage.vue                                                                        |    9 
 32 files changed, 1,523 insertions(+), 111 deletions(-)

diff --git a/.env.development b/.env.development
index d23312e..e59d6d9 100644
--- a/.env.development
+++ b/.env.development
@@ -5,4 +5,6 @@
 #开发环境代理地址(推荐本地新建文件 .env.development.local 来进行覆盖)
 # VITE_APP_API_URL = https://wrj.shuixiongit.com/api
 # VITE_APP_API_URL = http://192.168.1.7
+# ws地址
+VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
 
diff --git a/.env.production b/.env.production
index f641060..4a0e953 100644
--- a/.env.production
+++ b/.env.production
@@ -3,3 +3,5 @@
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
 VITE_BUILD_COMPRESS = gzip
+# ws地址
+VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
diff --git a/.env.test b/.env.test
index 04a567e..a429d58 100644
--- a/.env.test
+++ b/.env.test
@@ -1,4 +1,5 @@
 
 #测试环境配置
 VITE_APP_ENV = 'test'
-
+# ws地址
+VITE_APP_WS_API_URL = wss://wrj.shuixiongit.com/drone-wss/api/v1/ws
diff --git a/src/api/home/common.js b/src/api/home/common.js
new file mode 100644
index 0000000..367f845
--- /dev/null
+++ b/src/api/home/common.js
@@ -0,0 +1,27 @@
+import request from '@/axios'
+
+// 字典查询 行业 算法 工单类型
+export const getDictionary = params => {
+	return request({
+		url: `/blade-system/dict-biz/listByCodes?code=${params}`,
+		method: 'get',
+	})
+}
+
+// 区域
+export const deptsByAreaCode = params => {
+	return request({
+		url: `/blade-system/dept/deptsByAreaCode`,
+		method: 'get',
+		params,
+	})
+}
+
+// 获取机场信息
+export const getDockInfo = params => {
+	return request({
+		url: `/drone-device-core/dp/home/getDockInfo`,
+		method: 'get',
+		params,
+	})
+}
diff --git a/src/api/home/machineNest.js b/src/api/home/machineNest.js
index f69f70d..6abf443 100644
--- a/src/api/home/machineNest.js
+++ b/src/api/home/machineNest.js
@@ -46,3 +46,23 @@
 		params: {},
 	})
 }
+
+// 设备-任务列表
+export const getDeviceJobList = (data,params) => {
+	return request({
+		url: `/drone-device-core/wayline/waylineJobInfo/jobList`,
+		method: 'post',
+		data,
+		params
+	})
+}
+
+// 设备-事件列表
+export const getDeviceEventList = (data,params) => {
+	return request({
+		url: `/drone-device-core/jobEvent/eventPage`,
+		method: 'post',
+		data,
+		params
+	})
+}
diff --git a/src/api/home/task.js b/src/api/home/task.js
new file mode 100644
index 0000000..3994d30
--- /dev/null
+++ b/src/api/home/task.js
@@ -0,0 +1,52 @@
+import request from '@/axios'
+
+// 任务总数统计
+export const totalJobNum = params => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/totalJobNum',
+		method: 'get',
+		params: params,
+	})
+}
+// 其他任务统计
+export const jobStatistics = data => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/jobStatistics',
+		method: 'post',
+		data: data,
+	})
+}
+// 行业任务统计
+export const industryJobNumPieChart = data => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/industryJobNumPieChart',
+		method: 'post',
+		data: data,
+	})
+}
+// 时间任务统计
+export const jobNumBar = data => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/jobNumBar',
+		method: 'post',
+		data: data,
+	})
+}
+// 事件任务统计
+export const jobEventBar = data => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/jobEventBar',
+		method: 'post',
+		data: data,
+	})
+}
+// 任务列表
+export const jobList = data => {
+	return request({
+		url: '/drone-device-core/wayline/waylineJobInfo/jobList?current=' + data.current + '&size=' + data.size,
+		method: 'post',
+		data: {},
+	})
+}
+
+
diff --git a/src/assets/images/signMachineNest/return.png b/src/assets/images/signMachineNest/return.png
new file mode 100644
index 0000000..5e98312
--- /dev/null
+++ b/src/assets/images/signMachineNest/return.png
Binary files differ
diff --git a/src/layout/Header.vue b/src/layout/Header.vue
index 5d4ee4b..7ded962 100644
--- a/src/layout/Header.vue
+++ b/src/layout/Header.vue
@@ -50,7 +50,7 @@
 ]);
 
 const handleClick = ({ path, name }) => {
-  if (!['首页', '任务管理'].includes(name)) return ElMessage.warning('正在开发中');
+  if (!['首页', '任务管理'].includes(name)) return ElMessage.warning('正在加急开发中...');
   // 更新 leftList 的 active 状态
   leftList.value.forEach(item => {
     item.active = item.path === path;
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 16ec216..9d50b4d 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -299,7 +299,6 @@
 			setToken(token)
 			state.token = token
 			setStore({ name: 'token', content: state.token })
-			console.log('顶顶顶111', token)
 			window.localStorage.setItem(ELocalStorageKey.Token, token)
 		},
 		SET_REFRESH_TOKEN: (state, refreshToken) => {
diff --git a/src/views/SignMachineNest/components/MachineLeft/InspectionRaskDetails.vue b/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
similarity index 98%
rename from src/views/SignMachineNest/components/MachineLeft/InspectionRaskDetails.vue
rename to src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
index 8f76038..7131337 100644
--- a/src/views/SignMachineNest/components/MachineLeft/InspectionRaskDetails.vue
+++ b/src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
@@ -14,7 +14,7 @@
 import { pxToRem } from '@/utils/rem';
 import CommonTitle from '@/components/CommonTitle.vue';
 import CommonDateTime from '@/components/CommonDateTime.vue';
-import { jobNumBar, eventNumPie } from '@/api/home/index.js'
+import { jobNumBar, eventNumPie } from '@/api/home'
 
 // 日期
 const currenDate = dayjs().format('YYYY-MM-DD');
@@ -230,4 +230,4 @@
         margin-top: 10px;
     }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/SignMachineNest/components/MachineLeft/MachineData.vue b/src/views/SignMachineNest/MachineLeft/MachineData.vue
similarity index 100%
rename from src/views/SignMachineNest/components/MachineLeft/MachineData.vue
rename to src/views/SignMachineNest/MachineLeft/MachineData.vue
diff --git a/src/views/SignMachineNest/MachineLeft/MachineLeft.vue b/src/views/SignMachineNest/MachineLeft/MachineLeft.vue
new file mode 100644
index 0000000..f746ffc
--- /dev/null
+++ b/src/views/SignMachineNest/MachineLeft/MachineLeft.vue
@@ -0,0 +1,46 @@
+<template>
+  <div class="machine-left">
+    <!--时间 天气-->
+    <common-weather></common-weather>
+    <!-- 机巢数据 -->
+    <MachineData></MachineData>
+    <div class="do-return" @click="goBack">
+      <img src="../../../assets/images/signMachineNest/return.png" alt="" />
+    </div>
+     <!--巡检任务详情-->
+     <InspectionRaskDetails></InspectionRaskDetails>
+  </div>
+</template>
+
+<script setup>
+import CommonWeather from '@/components/CommonWeather.vue';
+import MachineData from './MachineData.vue';
+import InspectionRaskDetails from './InspectionRaskDetails.vue';
+import { useRouter } from 'vue-router';
+import { useStore } from 'vuex';
+
+const router = useRouter();
+const store = useStore()
+
+const goBack = () => {
+  store.commit('setSingleUavHome', {});
+};
+</script>
+
+<style scoped lang="scss">
+.machine-left {
+  position: absolute;
+  top: 88px;
+  color: #e7f5ff;
+  .do-return {
+    position: absolute;
+    top: 50px;
+    right: -50px;
+    cursor: pointer;
+    img {
+      width: 40px;
+      height: 40px;
+    }
+  }
+}
+</style>
diff --git a/src/views/SignMachineNest/components/MachineRight/InspectionRaskList.vue b/src/views/SignMachineNest/MachineRight/InspectionRaskList.vue
similarity index 94%
rename from src/views/SignMachineNest/components/MachineRight/InspectionRaskList.vue
rename to src/views/SignMachineNest/MachineRight/InspectionRaskList.vue
index f7b3303..def807b 100644
--- a/src/views/SignMachineNest/components/MachineRight/InspectionRaskList.vue
+++ b/src/views/SignMachineNest/MachineRight/InspectionRaskList.vue
@@ -30,12 +30,12 @@
               </span>
             </div>
             <div class="left-b">
-              <img src="@/assets/images/signMachineNest/machineRight/date.png" alt="" />{{ item.begin_time }}
-              <img src="@/assets/images/signMachineNest/machineRight/name.png" alt="" />{{ item.creator_name || '' }}
+              <img src="../../../assets/images/signMachineNest/machineRight/date.png" alt="" />{{ item.begin_time }}
+              <img src="../../../assets/images/signMachineNest/machineRight/name.png" alt="" />{{ item.creator_name || '' }}
             </div>
           </div>
           <div class="right">
-            <img src="@/assets/images/signMachineNest/machineRight/return.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/return.png" alt="">
           </div>
         </div>
       </div>
@@ -51,7 +51,7 @@
 <script setup>
 import { Search } from '@element-plus/icons-vue';
 import CommonTitle from '@/components/CommonTitle.vue';
-import { getBeforeJob, getTodayJob } from '@/api/home/index.js'
+import { getBeforeJob, getTodayJob } from '@/api/home'
 
 const isMore = ref(true);
 // 控制加载状态
@@ -273,4 +273,4 @@
       }
     }
  }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/SignMachineNest/components/MachineRight/MachineMonitor.vue b/src/views/SignMachineNest/MachineRight/MachineMonitor.vue
similarity index 100%
rename from src/views/SignMachineNest/components/MachineRight/MachineMonitor.vue
rename to src/views/SignMachineNest/MachineRight/MachineMonitor.vue
diff --git a/src/views/SignMachineNest/components/MachineRight/MachineRight.vue b/src/views/SignMachineNest/MachineRight/MachineRight.vue
similarity index 100%
rename from src/views/SignMachineNest/components/MachineRight/MachineRight.vue
rename to src/views/SignMachineNest/MachineRight/MachineRight.vue
diff --git a/src/views/SignMachineNest/components/MachineRight/MachineStatus.vue b/src/views/SignMachineNest/MachineRight/MachineStatus.vue
similarity index 93%
rename from src/views/SignMachineNest/components/MachineRight/MachineStatus.vue
rename to src/views/SignMachineNest/MachineRight/MachineStatus.vue
index 16d9c0c..380ad0c 100644
--- a/src/views/SignMachineNest/components/MachineRight/MachineStatus.vue
+++ b/src/views/SignMachineNest/MachineRight/MachineStatus.vue
@@ -4,7 +4,7 @@
   <div :style="{ marginLeft: pxToRem(14) }">
     <div class="machine-status">
       <div class="info">
-        <img src="@/assets/images/signMachineNest/machineRight/wrj.png" alt="">
+        <img src="../../../assets/images/signMachineNest/machineRight/wrj.png" alt="">
         <div class="info-right">
           <div class="name">{{ osdVisible?.callsign || '--' }}</div>
           <div class="wz">
@@ -20,28 +20,28 @@
       <div class="status">
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/height.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/height.png" alt="">
             <span class="text">实时真高</span>
           </div>
           <div class="text-data">{{ detailInfo.height || '--' }}<span class="text">米</span></div>
         </div>
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/speed.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/speed.png" alt="">
             <span class="text">飞行速度</span>
           </div>
           <div class="text-data">{{ detailInfo.horizontal_speed }}<span class="text">米/秒</span></div>
         </div>
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/signal.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/signal.png" alt="">
             <span class="text">信号强度</span>
           </div>
           <div class="text-data">{{ detailInfo.quality }}</div>
         </div>
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/electricity.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/electricity.png" alt="">
             <span class="text">电池电量</span>
           </div>
           <div v-if="drone_charge_state.capacity_percent != 0" class="text-data">
@@ -51,14 +51,14 @@
         </div>
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/distance.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/distance.png" alt="">
             <span class="text">飞行距离</span>
           </div>
           <div class="text-data">{{ singleTotal.flight_mileage }}<span class="text">km</span></div>
         </div>
         <div class="card">
           <div>
-            <img src="@/assets/images/signMachineNest/machineRight/duration.png" alt="">
+            <img src="../../../assets/images/signMachineNest/machineRight/duration.png" alt="">
             <span class="text">飞行时长</span>
           </div>
           <div class="text-data">{{ singleTotal.hour_count }}<span class="text">h</span></div>
@@ -75,7 +75,7 @@
 import { EModeCode, EDockModeText, EModeText } from '@/utils/staticData/device';
 import { getLnglatAltitude } from '@/utils/cesium/mapUtil.js';
 import { useStore } from 'vuex';
-import MachineTableDetails from '@/views/SignMachineNest/components/MachineRight/components/MachineTableDetails.vue';
+import MachineTableDetails from '@/views/SignMachineNest/MachineRight/MachineTableDetails/MachineTableDetails.vue';
 
 const store = useStore();
 // 获取机巢信息
diff --git a/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceEvent.vue b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceEvent.vue
new file mode 100644
index 0000000..9797c3c
--- /dev/null
+++ b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceEvent.vue
@@ -0,0 +1,82 @@
+<template>
+	<el-divider content-position="left">相关事件 {{total}}次</el-divider>
+	<el-table :data="list" style="width: 100%">
+		<el-table-column prop="id" label="id" />
+		<el-table-column prop="event_name" label="名称" />
+		<el-table-column prop="media_type" label="类型" />
+		<el-table-column prop="ai_types" label="关联算法" />
+		<el-table-column prop="photo_url" label="图片url" />
+		<el-table-column prop="video_url" label="视频url" />
+		<el-table-column prop="status" label="状态">
+			<template #default="scope">
+				<el-tag v-if="scope.row.status === 0" type="info">待处理</el-tag>
+				<el-tag v-if="scope.row.status === 1" type="success">待分拨</el-tag>
+				<el-tag v-if="scope.row.status === 2" type="warning">待处理</el-tag>
+				<el-tag v-if="scope.row.status === 3" type="success">处理中</el-tag>
+				<el-tag v-if="scope.row.status === 4" type="success">已完成</el-tag>
+				<el-tag v-if="scope.row.status === 5" type="success">已完结</el-tag>
+			</template>
+		</el-table-column>
+    <el-table-column prop="event_dict_key" label="event_dict_key" />
+    <el-table-column prop="create_time" label="创建时间" />
+
+    <el-table-column label="操作" >
+      <template #default="scope">
+        <el-button type="primary" link @click="examine(scope.row)">审核</el-button>
+        <el-button type="primary" link @click="distribution(scope.row)">分拨</el-button>
+      </template>
+    </el-table-column>
+	</el-table>
+	<el-pagination
+		background
+		:page-sizes="[10, 20, 30, 50]"
+		v-model:current-page="sizeParams.current"
+		v-model:page-size="sizeParams.size"
+		layout="total, sizes, prev, pager, next, jumper"
+		:total="total"
+		@change="pageChange"
+	/>
+</template>
+<script setup>
+import { useStore } from 'vuex'
+import { getDeviceEventList } from '@/api/home/machineNest'
+import { ElMessage } from 'element-plus';
+
+
+const list = ref([])
+const params = ref({
+	device_sn: null,
+})
+const sizeParams = ref({
+	current: 1,
+	size: 10,
+})
+const store = useStore()
+const device_sn = computed(() => store.state.home.singleUavHome.device_sn)
+const total = ref(0)
+
+const distribution = row => {
+	ElMessage.warning('正在加急开发中...')
+}
+const examine = row => {
+  ElMessage.warning('正在加急开发中...')
+}
+
+const getList = () => {
+	params.value.device_sn = device_sn.value
+	getDeviceEventList(params.value, sizeParams.value).then(res => {
+		const resData = res?.data?.data || {}
+		list.value = resData.records
+		total.value = resData.total
+	})
+}
+const pageChange = val => {
+	sizeParams.value.current = val
+	getList()
+}
+
+onMounted(() => {
+	getList()
+})
+</script>
+<style scoped lang="scss"></style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJob.vue b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJob.vue
new file mode 100644
index 0000000..922d82c
--- /dev/null
+++ b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJob.vue
@@ -0,0 +1,74 @@
+<template>
+	<el-divider content-position="left">相关任务 {{ total }}次</el-divider>
+	<el-table :data="list" style="width: 100%">
+		<el-table-column prop="id" label="id" />
+		<el-table-column prop="name" label="名称" />
+		<el-table-column prop="industry_type_str" label="任务类型" />
+		<el-table-column prop="ai_type_str" label="关联算法" />
+		<el-table-column prop="event_number" label="事件工单" />
+		<el-table-column prop="remark" label="备注" />
+		<el-table-column prop="area_code" label="地区代码" />
+		<el-table-column prop="begin_time" label="开始时间" />
+		<el-table-column prop="end_time" label="结束时间" />
+		<el-table-column prop="creator_name" label="创建者" />
+		<el-table-column label="操作">
+			<template #default="scope">
+				<el-button type="primary" link @click="viewJob(scope.row)">查看</el-button>
+			</template>
+		</el-table-column>
+	</el-table>
+	<el-pagination
+		background
+		:page-sizes="[10, 20, 30, 50]"
+		v-model:current-page="sizeParams.current"
+		v-model:page-size="sizeParams.size"
+		layout="total, sizes, prev, pager, next, jumper"
+		:total="total"
+		@change="pageChange"
+	/>
+
+  <DeviceJobDetails v-model:show="deviceJobDetailsShow"/>
+
+</template>
+<script setup>
+import { useStore } from 'vuex'
+import { getDeviceJobList } from '@/api/home/machineNest'
+import DeviceJobDetails from './DeviceJobDetails/DeviceJobDetails.vue';
+
+const list = ref([])
+const params = ref({
+	device_sn: null,
+})
+const sizeParams = ref({
+	current: 1,
+	size: 10,
+})
+const store = useStore()
+const device_sn = computed(() => store.state.home.singleUavHome.device_sn)
+const total = ref(0)
+const deviceJobDetailsShow = ref(false)
+const jobId = ref(null)
+provide('jobId', jobId)
+const viewJob = (row) => {
+  jobId.value = row.id
+  deviceJobDetailsShow.value = true
+}
+
+const getList = () => {
+	params.value.device_sn = device_sn.value
+	getDeviceJobList(params.value, sizeParams.value).then(res => {
+		const resData = res?.data?.data || {}
+		list.value = resData.records
+		total.value = resData.total
+	})
+}
+
+const pageChange = val => {
+	sizeParams.value.current = val
+	getList()
+}
+onMounted(() => {
+	getList()
+})
+</script>
+<style scoped lang="scss"></style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
new file mode 100644
index 0000000..58304d5
--- /dev/null
+++ b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/DeviceJobDetails.vue
@@ -0,0 +1,130 @@
+<!-- 任务详情 -->
+<template>
+	<el-dialog
+		append-to-body
+		modal-class="detailsOfHistoricalTasks"
+		v-model="isShow"
+		title="历史任务详情"
+		:width="pxToRem(1500)"
+		:close-on-click-modal="false"
+		:destroy-on-close="true"
+	>
+		<div class="content">
+			<div class="contentLeft">
+				<el-divider content-position="left">详情</el-divider>
+				<div class="infoBox">
+					<div class="itemBox" v-for="item in infoList">
+						<div class="itemTitle">{{ item.name }}:</div>
+						<div class="itemValue">{{ item.value }}</div>
+					</div>
+				</div>
+				<JobRelatedEvents v-if="isShow" />
+				<el-divider content-position="left">任务成果 xxx个</el-divider>
+				<div class="imgListBox">
+					<div v-for="item in imgList" class="imgItem">xxx图片</div>
+				</div>
+			</div>
+			<div class="contentRight">map</div>
+		</div>
+	</el-dialog>
+</template>
+
+<script setup>
+import { pxToRem } from '@/utils/rem'
+import JobRelatedEvents from './JobRelatedEvents.vue'
+
+const isShow = defineModel('show')
+
+
+const imgList = ref([
+	{ name: '图片1', url: 'xxx' },
+	{ name: '图片1', url: 'xxx' },
+	{ name: '图片1', url: 'xxx' },
+	{ name: '图片1', url: 'xxx' },
+])
+
+const infoList = ref([
+	{ name: '任务编号', value: 'xxx' },
+	{ name: '任务所属机巢', value: 'xxx' },
+	{ name: '关联算法', value: 'xxx' },
+	{ name: '任务名称', value: 'xxx' },
+	{ name: '所属单位', value: 'xxx' },
+	{ name: '任务类型', value: 'xxx' },
+	{ name: '任务周期', value: 'xxx' },
+	{ name: '飞行事件', value: 'xxx' },
+	{ name: '任务频次', value: 'xxx' },
+	{ name: '任务描述', value: 'xxx' },
+])
+
+onMounted(() => {})
+</script>
+
+<style lang="scss">
+.detailsOfHistoricalTasks {
+	.el-dialog {
+		--el-dialog-margin-top: 5vh;
+	}
+
+	.el-pagination {
+		justify-content: center;
+		padding: 20px;
+	}
+
+	.el-dialog__body {
+		height: 80vh;
+	}
+}
+</style>
+
+<style lang="scss" scoped>
+.content {
+	display: flex;
+	height: 100%;
+
+	.contentLeft {
+		width: 900px;
+		overflow: auto;
+
+		.infoBox {
+			display: grid;
+			grid-template-columns: repeat(3, 1fr);
+			gap: 10px; // 列之间的间距
+			padding: 10px;
+
+			.itemBox {
+				background-color: #fff;
+				border: 1px solid #ddd;
+				border-radius: 4px;
+				padding: 15px;
+				box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+				display: flex;
+				align-items: center;
+			}
+
+			.itemTitle {
+				font-weight: bold;
+				color: #333;
+			}
+
+			.itemValue {
+				color: #666;
+			}
+		}
+
+		.imgListBox {
+			display: flex;
+
+			.imgItem {
+				width: 200px;
+				height: 200px;
+			}
+		}
+	}
+
+	.contentRight {
+		width: 0;
+		flex-grow: 1;
+		background: #19ad8d;
+	}
+}
+</style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/JobRelatedEvents.vue b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/JobRelatedEvents.vue
new file mode 100644
index 0000000..311ec84
--- /dev/null
+++ b/src/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJobDetails/JobRelatedEvents.vue
@@ -0,0 +1,92 @@
+<template>
+	<el-divider content-position="left">关联事件 {{total}}个</el-divider>
+	<el-table :data="list" style="width: 100%" >
+		<el-table-column prop="event_num" label="编号" />
+		<el-table-column prop="event_name" label="名称" />
+		<el-table-column prop="media_type" label="类型" />
+		<el-table-column prop="photo_url" label="图片url" />
+		<el-table-column prop="video_url" label="视频url" />
+		<el-table-column prop="remark" label="备注" />
+		<el-table-column prop="status" label="状态">
+			<template #default="scope">
+				<el-tag v-if="scope.row.status === 0" type="info">待处理</el-tag>
+				<el-tag v-if="scope.row.status === 1" type="success">待分拨</el-tag>
+				<el-tag v-if="scope.row.status === 2" type="warning">待处理</el-tag>
+				<el-tag v-if="scope.row.status === 3" type="success">处理中</el-tag>
+				<el-tag v-if="scope.row.status === 4" type="success">已完成</el-tag>
+				<el-tag v-if="scope.row.status === 5" type="success">已完结</el-tag>
+			</template>
+		</el-table-column>
+		<el-table-column prop="wayline_job_id" label="	任务id" />
+    <el-table-column label="操作" >
+      <template #default="scope">
+        <el-button type="primary" link @click="examine(scope.row)">审核</el-button>
+        <el-button type="primary" link @click="distribution(scope.row)">分拨</el-button>
+      </template>
+    </el-table-column>
+	</el-table>
+	<el-pagination
+		background
+		:page-sizes="[10, 20, 30, 50]"
+		v-model:current-page="sizeParams.current"
+		v-model:page-size="sizeParams.size"
+		layout="total, sizes, prev, pager, next, jumper"
+		:total="total"
+		@change="pageChange"
+	/>
+</template>
+<script setup>
+import { useStore } from 'vuex'
+import { getDeviceEventList } from '@/api/home/machineNest'
+import { ElMessage } from 'element-plus';
+
+const jobId = inject("jobId");
+
+const list = ref([
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+  {event_num:''},
+])
+const params = ref({
+	device_sn: null,
+})
+const sizeParams = ref({
+	current: 1,
+	size: 1,
+})
+const store = useStore()
+const child_sn = computed(() => store.state.home.singleUavHome.child_sn)
+const total = ref(10)
+
+const distribution = row => {
+	ElMessage.warning('正在加急开发中...')
+}
+const examine = row => {
+  ElMessage.warning('正在加急开发中...')
+}
+
+const getList = () => {
+	params.value.device_sn = child_sn.value
+	getDeviceEventList(params.value, sizeParams.value).then(res => {
+		const resData = res?.data?.data || {}
+		list.value = resData.records
+		total.value = resData.total
+	})
+}
+const pageChange = val => {
+	sizeParams.value.current = val
+	getList()
+}
+
+onMounted(() => {
+	// getList()
+})
+</script>
+<style scoped lang="scss"></style>
diff --git a/src/views/SignMachineNest/MachineRight/MachineTableDetails/MachineTableDetails.vue b/src/views/SignMachineNest/MachineRight/MachineTableDetails/MachineTableDetails.vue
new file mode 100644
index 0000000..0a20550
--- /dev/null
+++ b/src/views/SignMachineNest/MachineRight/MachineTableDetails/MachineTableDetails.vue
@@ -0,0 +1,75 @@
+<!-- 机巢列表详情 -->
+<template>
+	<el-dialog
+		modal-class="machineTableDetails"
+		v-model="isShowDetails"
+		title="机巢详情"
+		:width="pxToRem(1500)"
+		:close-on-click-modal="false"
+		:destroy-on-close="true"
+	>
+		<el-divider content-position="left">详情</el-divider>
+		<div class="infoBox">
+			<div class="itemBox" v-for="item in infoList">
+				<div class="itemTitle">{{ item.name }}:</div>
+				<div class="itemValue">{{ item.value }}</div>
+			</div>
+		</div>
+		<DeviceJob v-if="isShowDetails" />
+		<DeviceEvent v-if="isShowDetails" />
+	</el-dialog>
+</template>
+
+<script setup>
+import DeviceEvent from '@/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceEvent.vue'
+import DeviceJob from '@/views/SignMachineNest/MachineRight/MachineTableDetails/DeviceJob/DeviceJob.vue'
+import { pxToRem } from '@/utils/rem';
+
+const isShowDetails = defineModel('show')
+
+const infoList = ref([
+	{ name: '机巢名称', value: 'xxx' },
+	{ name: '机巢所属地区', value: 'xxx' },
+	{ name: '机巢状态', value: 'xxx' },
+	{ name: '任务成功', value: 'xxx' },
+	{ name: '机巢位置', value: 'xxx' },
+])
+
+onMounted(() => {})
+</script>
+
+<style lang="scss">
+.machineTableDetails {
+	.el-pagination {
+		text-align: left;
+		padding: 20px;
+	}
+}
+</style>
+
+<style lang="scss" scoped>
+.infoBox {
+	display: grid;
+	grid-template-columns: repeat(3, 1fr);
+	gap: 10px; // 列之间的间距
+	padding: 10px;
+
+	.itemBox {
+		background-color: #fff;
+		border: 1px solid #ddd;
+		border-radius: 4px;
+		padding: 15px;
+		box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+	}
+
+	.itemTitle {
+		font-weight: bold;
+		color: #333;
+	}
+
+	.itemValue {
+		margin-top: 5px;
+		color: #666;
+	}
+}
+</style>
diff --git a/src/views/SignMachineNest/SignMachineNest.vue b/src/views/SignMachineNest/SignMachineNest.vue
index 859a9e2..c2d013d 100644
--- a/src/views/SignMachineNest/SignMachineNest.vue
+++ b/src/views/SignMachineNest/SignMachineNest.vue
@@ -4,8 +4,8 @@
 </template>
 
 <script setup>
-import MachineLeft from './components/MachineLeft/MachineLeft.vue'
-import MachineRight from './components/MachineRight/MachineRight.vue';
+import MachineLeft from '@/views/SignMachineNest/MachineLeft/MachineLeft.vue'
+import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue';
 import { useConnectWebSocket } from '../../utils/websocket/connect-websocket';
 import { getWebsocketUrl } from '@/websocket/util/config';
 import { EBizCode } from '@/utils/staticData/enums.js';
@@ -31,7 +31,6 @@
 
 const messageHandler = (result) => {
   let payload = JSON.parse(result) // 为了兼容聊天消息
-  // console.log('payload', payload)
   if (!payload) return
   switch (payload.biz_code) {
     case EBizCode.GatewayOsd: {
@@ -83,6 +82,8 @@
   getFlightStatistics(singleUavHome.value.device_sn).then(res => {
     if (res.data.code !== 0) return;
     const result = res.data.data;
+    console.log(result);
+    console.log(result);
     store.commit('setSingleTotal', result);
   })
 };
@@ -95,4 +96,4 @@
 onUnmounted(() => {
   connectWs?.value?.close();
 });
-</script>
\ No newline at end of file
+</script>
diff --git a/src/views/SignMachineNest/components/MachineLeft/MachineLeft.vue b/src/views/SignMachineNest/components/MachineLeft/MachineLeft.vue
deleted file mode 100644
index 52adde4..0000000
--- a/src/views/SignMachineNest/components/MachineLeft/MachineLeft.vue
+++ /dev/null
@@ -1,24 +0,0 @@
-<template>
-  <div class="machine-left">
-    <!--时间 天气-->
-    <common-weather></common-weather>
-    <!-- 机巢数据 -->
-     <MachineData></MachineData>
-     <!--巡检任务详情-->
-     <InspectionRaskDetails></InspectionRaskDetails>
-  </div>
-</template>
-
-<script setup>
-import CommonWeather from '@/components/CommonWeather.vue';
-import MachineData from './MachineData.vue';
-import InspectionRaskDetails from './InspectionRaskDetails.vue';
-</script>
-
-<style scoped lang="scss">
-.machine-left {
-  position: absolute;
-  top: 88px;
-  color: #e7f5ff;
-}
-</style>
\ No newline at end of file
diff --git a/src/views/SignMachineNest/components/MachineRight/components/MachineTableDetails.vue b/src/views/SignMachineNest/components/MachineRight/components/MachineTableDetails.vue
deleted file mode 100644
index 9708b45..0000000
--- a/src/views/SignMachineNest/components/MachineRight/components/MachineTableDetails.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-<!-- 机巢列表详情 -->
-<template>
-  <div>
-
-  </div>
-  <el-dialog
-    v-model="isShowDetails"
-    title="机巢详情"
-    width="800px"
-    :close-on-click-modal="false"
-    :destroy-on-close="true"
-  >
-    <el-table :data="tableData" style="width: 100%">
-      <el-table-column prop="name" label="名称" />
-      <el-table-column prop="value" label="数值" />
-      <el-table-column prop="status" label="状态" />
-      <el-table-column prop="time" label="时间" />
-    </el-table>
-  </el-dialog>
-</template>
-
-<script setup>
-const props = defineProps({
-  dialogVisible: {
-    type: Boolean,
-    default: false,
-  },
-});
-
-const isShowDetails = defineModel('show')
-
-// const dialogVisible = ref(false);
-const tableData = ref([
-  {
-    name: '机巢1号',
-    value: '98%',
-    status: '正常',
-    time: '2024-03-20 10:00:00'
-  },
-  {
-    name: '电池状态',
-    value: '95%',
-    status: '正常',
-    time: '2024-03-20 10:00:00'
-  },
-  {
-    name: '信号强度',
-    value: '强',
-    status: '正常',
-    time: '2024-03-20 10:00:00'
-  }
-]);
-</script>
-
-<style lang="scss" scoped>
-// ... 其他样式 ...
-
-:deep(.el-dialog) {
-  background: linear-gradient(
-    270deg,
-    #1f3e7a 0%,
-    rgba(31, 62, 122, 0.95) 79%,
-    rgba(31, 62, 122, 0.9) 100%
-  );
-  .el-dialog__header {
-    color: #fff;
-    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
-    margin: 0;
-    padding: 15px 20px;
-    .el-dialog__title {
-      color: #fff;
-    }
-  }
-  .el-dialog__body {
-    color: #fff;
-    padding: 20px;
-  }
-  .el-table {
-    background-color: transparent;
-    --el-table-tr-bg-color: transparent;
-    --el-table-border-color: rgba(255, 255, 255, 0.1);
-    --el-table-header-bg-color: rgba(31, 62, 122, 0.5);
-    --el-table-header-text-color: #fff;
-    --el-table-text-color: #fff;
-  }
-}
-</style>
diff --git a/src/views/TaskManage/TaskManage.vue b/src/views/TaskManage/TaskManage.vue
index d649d9c..b67105d 100644
--- a/src/views/TaskManage/TaskManage.vue
+++ b/src/views/TaskManage/TaskManage.vue
@@ -1,11 +1,16 @@
 <script setup>
-
+import TaskLeft from "./components/TaskLeft/TaskLeft.vue";
+import TaskRight from "./components/TaskRight/TaskRight.vue";
+import TaskIntermediateContent from "./components/TaskIntermediateContent/TaskIntermediateContent.vue";
 </script>
 
 <template>
-  TaskManage
+  <TaskLeft/>
+  <TaskIntermediateContent />
+  <TaskRight/>
 </template>
 
+
 <style scoped lang="scss">
 
 </style>
diff --git a/src/views/TaskManage/components/SearchBox.vue b/src/views/TaskManage/components/SearchBox.vue
new file mode 100644
index 0000000..e02299d
--- /dev/null
+++ b/src/views/TaskManage/components/SearchBox.vue
@@ -0,0 +1,192 @@
+<template>
+  <div class="search-box">
+    <el-form :model="searchForm" inline>
+      <el-form-item label="任务名称">
+        <el-input v-model="searchForm.name" placeholder="请输入任务名称" clearable />
+      </el-form-item>
+      <el-form-item label="所属部门">
+        <el-select
+          v-model="searchForm.deptId"
+          placeholder="请选择部门"
+          clearable
+        >
+          <el-tree-select
+            v-model="searchForm.deptId"
+            :data="deptTreeData"
+            node-key="id"
+            :props="{
+              label: 'name',
+              children: 'children'
+            }"
+            check-strictly
+            clearable
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="周期">
+        <el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
+          <el-option label="日" value="日" />
+          <el-option label="周" value="周" />
+          <el-option label="月" value="月" />
+          <el-option label="年" value="年" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="任务状态">
+        <el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
+          <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="任务时间">
+        <el-date-picker
+          v-model="searchForm.dateRange"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+      <el-form-item label="任务算法">
+        <el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
+          <el-option label="识别火情" value="日" />
+          <el-option label="识别车辆" value="周" />
+          <el-option label="识别船只" value="月" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleSearch">查询</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script setup>
+import { getDictionary, deptsByAreaCode, getDockInfo } from '@/api/home/common';
+
+
+const searchForm = reactive({
+  name: '',
+  job_info_num: '',
+  status: '',
+  dateRange: []
+});
+const statusOptions = [
+  { label: '待执行', value: 1 },
+  { label: '执行中', value: 2 },
+  { label: '已完成', value: 3 },
+  { label: '已取消', value: 4 },
+  { label: '执行失败', value: 5 }
+];
+
+// 部门以及机巢
+const deptTreeData = ref([]);
+
+const emit = defineEmits(['search']);
+
+const handleSearch = () => {
+  emit('search', {
+    ...searchForm,
+    begin_time: searchForm.dateRange[0],
+    end_time: searchForm.dateRange[1]
+  });
+};
+
+const handleReset = () => {
+  searchForm.name = '';
+  searchForm.job_info_num = '';
+  searchForm.status = '';
+  searchForm.dateRange = [];
+  handleSearch();
+};
+
+// 请求字典字段
+const requestDictionary = () => {
+  getDictionary('SF,HYLB').then((res) => {
+    if (res.data.code !== 0) {
+      // 处理数据
+      console.log('111111',res.data)
+    }
+  });
+};
+
+// 处理部门数据为树形结构
+const handleDeptData = (data) => {
+  const buildTree = (items, parentId = 0) => {
+    const result = [];
+    for (const item of items) {
+      if (item.parent_id === parentId) {
+        const children = buildTree(items, item.id);
+        if (children.length) {
+          item.children = children;
+        }
+        result.push(item);
+      }
+    }
+    return result;
+  };
+  return buildTree(data);
+};
+// 部门信息
+const getDeptsByAreaCode = () => {
+  deptsByAreaCode().then((res) => {
+    if (res.data.code !== 0) {
+      deptTreeData.value = res.data;
+      // 处理数据
+      console.log('22222',res.data)
+    }
+  });
+};
+
+// 机巢信息
+const requestDockInfo = () => {
+  getDockInfo().then((res) => {
+    if (res.data.code !== 0) {
+      // 处理数据
+      console.log('33333',res.data)
+    }
+  });
+};
+
+
+onMounted(() => {
+  requestDictionary();
+  deptsByAreaCode();
+  requestDockInfo();
+});
+</script>
+
+<style lang="scss" scoped>
+.search-box {
+  position: absolute;
+  top: 120px;
+  left: 450px;
+  width: calc(100% - 400px - 400px - 100px);
+  height:60px;
+  color: #fff;
+  background: rgba(31, 62, 122, 0.35);
+  padding: 10px 20px;
+
+  :deep(.el-form) {
+    --el-text-color-regular: #fff;
+    
+    .el-form-item {
+      margin-bottom: 0;
+      margin-right: 20px;
+      
+      .el-form-item__label {
+        color: #fff;
+      }
+      
+      .el-input,
+      .el-select,
+      .el-date-editor {
+        width: 200px;
+        --el-input-bg-color: transparent;
+        --el-input-border-color: rgba(255, 255, 255, 0.3);
+        --el-input-text-color: #fff;
+        --el-input-placeholder-color: rgba(255, 255, 255, 0.5);
+      }
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskIntermediateContent/TaskIntermediateContent.vue b/src/views/TaskManage/components/TaskIntermediateContent/TaskIntermediateContent.vue
new file mode 100644
index 0000000..ccf669e
--- /dev/null
+++ b/src/views/TaskManage/components/TaskIntermediateContent/TaskIntermediateContent.vue
@@ -0,0 +1,148 @@
+<!-- 任务统计表格 -->
+<template>
+  <SearchBox></SearchBox>
+  <div class="task-intermediate-content">
+    <el-table :data="jobListData" style="width: 100%" height="calc(100vh - 180px)">
+      <el-table-column label="序号" width="60">
+        <template #default="scope">
+          {{ (jobListParams.page - 1) * jobListParams.limit + scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="job_info_num" label="任务编号" />
+      <el-table-column prop="name" label="任务名称"  />
+      <el-table-column prop="dept_name" label="所属部门"  />
+      <el-table-column prop="device_names" label="所属机巢"  />
+      <el-table-column prop="ai_type_str" label="关联算法"  />
+      <el-table-column prop="status" label="任务状态" >
+        <template #default="scope">
+          <el-tag :type="getStatusType(scope.row.status)">
+            {{ getStatusText(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="industry_type_str" label="任务类型" />
+      <el-table-column prop="event_number" label="关联事件" />
+      <el-table-column prop="begin_time" label="任务时间" />
+      <el-table-column prop="creator_name" label="创建人" />
+      <el-table-column label="操作" >
+        <template #default="scope">
+          <el-button link type="primary" @click="handleDetail(scope.row)">查看</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="pagination">
+      <el-pagination
+        v-model:current-page="jobListParams.page"
+        v-model:page-size="jobListParams.limit"
+        :page-sizes="[10, 20, 30, 50]"
+        layout="total, sizes, prev, pager, next"
+        :total="total"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import SearchBox from '../SearchBox.vue';
+import { jobList } from '@/api/home/task';
+
+const jobListParams = reactive({
+  page: 1,
+  limit: 10,
+});
+const jobListData = ref([]);
+const total = ref(0);
+
+// 获取任务列表
+const getJobList = () => {
+  jobList({current:1,size:10}).then(res => {
+    if (res.data.code !== 0) return;
+    jobListData.value = res.data.data.records;
+    total.value = res.data.data.total;
+  });
+};
+// 状态文字
+const getStatusText = (status) => {
+  const statusMap = {
+    1: '待执行',
+    2: '执行中',  
+    3: '已完成',
+    4: '已取消',
+    5: '执行失败'
+  };
+  return statusMap[status] || '未知';
+};
+
+// 状态标签类型
+const getStatusType = (status) => {
+  const typeMap = {
+    1: 'info',
+    2: 'warning',
+    3: 'success',
+    4: '',
+    5: 'danger'
+  };
+  return typeMap[status] || '';
+};
+
+// 查看详情
+const handleDetail = (row) => {
+  console.log('查看详情', row);
+};
+
+// 分页大小改变
+const handleSizeChange = (val) => {
+  jobListParams.limit = val;
+  getJobList();
+};
+
+// 页码改变
+const handleCurrentChange = (val) => {
+  jobListParams.page = val;
+  getJobList();
+};
+
+onMounted(() => {
+  getJobList();
+});
+</script>
+
+<style lang="scss" scoped>
+.task-intermediate-content {
+  position: absolute;
+  top: 190px;
+  width: calc(100% - 400px - 400px - 100px);
+  left: 450px;
+  height: 770px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  
+  :deep(.el-table) {
+    background-color: transparent;
+    --el-table-tr-bg-color: transparent;
+    --el-table-border-color: rgba(255, 255, 255, 0.1);
+    --el-table-header-bg-color: rgba(31, 62, 122, 0.5);
+    --el-table-header-text-color: #fff;
+    --el-table-text-color: #fff;
+    .el-table__body tr:hover > td {
+      background-color: rgba(31, 62, 122, 0.3) !important;
+    }
+  }
+
+  .pagination {
+    padding: 20px 0;
+    display: flex;
+    justify-content: flex-end;
+    
+    :deep(.el-pagination) {
+      --el-pagination-bg-color: transparent;
+      --el-pagination-text-color: #fff;
+      --el-pagination-button-color: #fff;
+      --el-pagination-hover-color: #409eff;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskLeft/TaskIndustry.vue b/src/views/TaskManage/components/TaskLeft/TaskIndustry.vue
new file mode 100644
index 0000000..f8f895f
--- /dev/null
+++ b/src/views/TaskManage/components/TaskLeft/TaskIndustry.vue
@@ -0,0 +1,132 @@
+<!-- 业务统计 -->
+ <template>
+  <common-title title="行业统计" :style="{ marginLeft: pxToRem(14) }"></common-title>
+  <div class="task-industry">
+    <div class="chart" ref="chartRef"></div>
+  </div>
+ </template>
+
+<script setup>
+import CommonTitle from '@/components/CommonTitle.vue';
+import * as echarts from 'echarts';
+import { industryJobNumPieChart } from '@/api/home/task';
+const chartRef = ref(null);
+let chart = null;
+
+const option = {
+  tooltip: {
+    trigger: 'item',
+    formatter: '{b}: {c} ({d}%)'
+  },
+  legend: {
+    orient: 'horizontal',
+    left: 'center',
+    bottom: '5%',
+    textStyle: {
+      color: '#fff',
+      fontSize: 12
+    },
+    itemWidth: 10,
+    itemHeight: 10,
+    itemGap: 10,
+    formatter: function(name) {
+      let data = option.series[0].data;
+      let total = 0;
+      let tarValue = 0;
+      for (let i = 0; i < data.length; i++) {
+        total += data[i].value;
+        if (data[i].name === name) {
+          tarValue = data[i].value;
+        }
+      }
+      let percentage = ((tarValue / total) * 100).toFixed(1);
+      return `${name} ${percentage}%`;
+    }
+  },
+  series: [
+    {
+      name: '行业统计',
+      type: 'pie',
+      radius: '60%',
+      center: ['35%', '50%'],
+      itemStyle: {
+        borderRadius: 4,
+        borderColor: 'rgba(255,255,255,0.2)',
+        borderWidth: 1
+      },
+      label: {
+        show: true,
+        position: 'inside',
+        formatter: '{c}',
+        fontSize: 12,
+        color: '#fff'
+      },
+      labelLine: {
+        show: false
+      },
+      emphasis: {
+        scale: true,
+        scaleSize: 10
+      }
+    }
+  ]
+};
+
+// 获取行业统计数据
+const getIndustryJobNumPieChart = () => {
+  industryJobNumPieChart().then(res => {
+    if (res.data.code !== 0) return;
+    const data = res.data.data.map(item => ({
+      name: item.name,
+      value: item.value,
+      itemStyle: {
+        color: getRandomColor()
+      }
+    }));
+    option.series[0].data = data;
+    chart.setOption(option);
+  });
+};
+
+// 生成随机颜色
+const getRandomColor = () => {
+  const colors = ['#1890FF', '#36CBCB', '#4ECB73', '#FBD437', '#F2637B', '#975FE5'];
+  return colors[Math.floor(Math.random() * colors.length)];
+};
+
+onMounted(() => {
+  chart = echarts.init(chartRef.value);
+  getIndustryJobNumPieChart();
+  
+  window.addEventListener('resize', () => {
+    chart?.resize();
+  });
+});
+
+onUnmounted(() => {
+  window.removeEventListener('resize', chart?.resize);
+  chart?.dispose();
+});
+</script>
+
+<style lang="scss" scoped>
+.task-industry {
+  font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+  margin-left: 29px;
+  padding: 16px 16px;
+  width: 340px;
+  height: 400px;
+  background: linear-gradient(
+    270deg,
+    rgba(31, 62, 122, 0) 0%,
+    rgba(31, 62, 122, 0.35) 21%,
+    #1f3e7a 100%
+  );
+  border-radius: 0px 0px 0px 0px;
+  opacity: 0.85;
+  .chart {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskLeft/TaskLeft.vue b/src/views/TaskManage/components/TaskLeft/TaskLeft.vue
new file mode 100644
index 0000000..f0117c5
--- /dev/null
+++ b/src/views/TaskManage/components/TaskLeft/TaskLeft.vue
@@ -0,0 +1,19 @@
+<template>
+  <div class="task-left">
+    <TaskTotal />
+    <TaskIndustry />
+  </div>
+</template>
+
+<script setup>
+import TaskTotal from './TaskTotal.vue';
+import TaskIndustry from './TaskIndustry.vue';
+</script>
+
+<style lang="scss" scoped>
+.task-left {
+  // width: 300px;
+  position: relative;
+  top: 20px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskLeft/TaskTotal.vue b/src/views/TaskManage/components/TaskLeft/TaskTotal.vue
new file mode 100644
index 0000000..ad69663
--- /dev/null
+++ b/src/views/TaskManage/components/TaskLeft/TaskTotal.vue
@@ -0,0 +1,100 @@
+<!-- 任务统计 -->
+<template>
+  <common-title title="任务统计" :style="{ marginLeft: pxToRem(14) }"></common-title>
+  <div class="task-total">
+    <div class="card" v-for="item in list">
+      <div>
+        <div class="value">{{ item.value }}</div>
+        <div class="name">{{item.name}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { pxToRem } from '@/utils/rem';
+import CommonTitle from '@/components/CommonTitle.vue';
+import { totalJobNum, jobStatistics  } from "@/api/home/task";
+
+const list = ref([
+  { name: '总任务数', value: '1888'},
+  { name: '计划执行', value: '18'},
+  { name: '执行中', value: '999'},
+  { name: '待执行', value: '8888'},
+  { name: '已执行', value: '666'},
+  { name: '执行失败', value: '2222'},
+]);
+
+// 获取任务统计总数
+const getTotalJobNum = () => {
+  totalJobNum().then((res) => {
+    if (res.data.code !== 0) returen;
+    list.value[0].value = res.data.data;
+  });
+};
+// 获取其他任务统计
+const getJobStatistics = () => {
+  jobStatistics().then((res) => {
+    if (res.data.code !== 0) returen;
+    list.value[1].value = res.data.data.planned_executions;
+    list.value[2].value = res.data.data.running_num;
+    list.value[3].value = res.data.data.pending_executions;
+    list.value[4].value = res.data.data.executed;
+    list.value[5].value = res.data.data.failed_executions;
+  });
+};
+
+onMounted(() => {
+  getTotalJobNum();
+  getJobStatistics();
+});
+</script>
+
+<style lang="scss" scoped>
+.task-total {
+  font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+  margin-left: 29px;
+  padding: 16px 16px;
+  width: 340px;
+  height: 400px;
+  background: linear-gradient(
+    270deg,
+    rgba(31, 62, 122, 0) 0%,
+    rgba(31, 62, 122, 0.35) 21%,
+    #1f3e7a 100%
+  );
+  border-radius: 0px 0px 0px 0px;
+  opacity: 0.85;
+  margin-bottom: 12px;
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  grid-template-rows: repeat(3, 1fr);
+  gap: 20px;
+  padding: 20px;
+  .card {
+    /* position: absolute;
+			top: 8px;
+			right: 10px;
+			width: 200px; */
+			display: flex;
+			flex-wrap: wrap;
+			gap: 8px;
+			justify-content: flex-start;
+			line-height: 22px;
+			padding: 0 10px 10px 0;
+      color: #ffffff;
+    .name {
+      font-family: Source Han Sans CN, Source Han Sans CN;
+      font-weight: 400;
+      font-size: 14px;
+      
+    }
+
+    .value {
+      font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+      font-weight: 400;
+      font-size: 26px;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskRight/TaskEvent.vue b/src/views/TaskManage/components/TaskRight/TaskEvent.vue
new file mode 100644
index 0000000..5600ec3
--- /dev/null
+++ b/src/views/TaskManage/components/TaskRight/TaskEvent.vue
@@ -0,0 +1,150 @@
+<!-- 任务事件统计 -->
+<template>
+  <common-title title="任务事件统计"></common-title>
+  <div class="task-event">
+    <div class="chart" ref="chartRef"></div>
+  </div>
+ </template>
+
+<script setup>
+import CommonTitle from '@/components/CommonTitle.vue';
+import * as echarts from 'echarts';
+import { jobEventBar } from '@/api/home/task';
+import dayjs from 'dayjs';
+
+// 日期
+const currenDate = dayjs().format('YYYY-MM-DD');
+const newTime = ref([currenDate, currenDate]);
+// 图表
+const chartRef = ref(null);
+let chart = null;
+
+const option = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  legend: {
+    data: ['任务', '事件'],
+    textStyle: {
+      color: '#fff'
+    },
+    bottom: '5%'
+  },
+  grid: {
+    top: '15%',
+    left: '3%',
+    right: '4%',
+    bottom: '15%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    axisLine: {
+      lineStyle: {
+        color: '#fff'
+      }
+    },
+    axisLabel: {
+      color: '#fff',
+      interval: 0,
+      rotate: 30
+    }
+  },
+  yAxis: {
+    type: 'value',
+    axisLine: {
+      lineStyle: {
+        color: '#fff'
+      }
+    },
+    splitLine: {
+      lineStyle: {
+        color: 'rgba(255, 255, 255, 0.1)'
+      }
+    },
+    axisLabel: {
+      color: '#fff'
+    }
+  },
+  series: [
+    {
+      name: '任务',
+      type: 'bar',
+      barWidth: '20%',
+      itemStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#1EE7E7' },
+          { offset: 1, color: 'rgba(30, 231, 231, 0.1)' }
+        ])
+      }
+    },
+    {
+      name: '事件',
+      type: 'bar',
+      barWidth: '20%',
+      itemStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#0070FF' },
+          { offset: 1, color: 'rgba(0, 112, 255, 0.1)' }
+        ])
+      }
+    }
+  ]
+};
+
+// 获取行业统计数据
+const getJobEventBar = (value,date_enum) => {
+  jobEventBar({date_enum}).then(res => {
+    if (res.data.code !== 0) return;
+    option.xAxis.data = res.data.data.map(item => item.name);
+    option.series[0].data = res.data?.data.map(item => item.data[0].value);
+    option.series[1].data = res.data?.data.map(item => item.data[1].value);
+    chart.setOption(option);
+  });
+};
+
+// 生成随机颜色
+const getRandomColor = () => {
+  const colors = ['#1890FF', '#36CBCB', '#4ECB73', '#FBD437', '#F2637B', '#975FE5'];
+  return colors[Math.floor(Math.random() * colors.length)];
+};
+
+onMounted(() => {
+  chart = echarts.init(chartRef.value);
+  getJobEventBar(newTime.value, 'CURRENT_YEAR');
+  
+  window.addEventListener('resize', () => {
+    chart?.resize();
+  });
+});
+
+onUnmounted(() => {
+  window.removeEventListener('resize', chart?.resize);
+  chart?.dispose();
+});
+</script>
+
+<style lang="scss" scoped>
+.task-event {
+  font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+  margin-left: 29px;
+  padding: 16px 16px;
+  width: 340px;
+  height: 400px;
+  background: linear-gradient(
+    270deg,
+    rgba(31, 62, 122, 0) 0%,
+    rgba(31, 62, 122, 0.35) 21%,
+    #1f3e7a 100%
+  );
+  border-radius: 0px 0px 0px 0px;
+  opacity: 0.85;
+  .chart {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskRight/TaskRight.vue b/src/views/TaskManage/components/TaskRight/TaskRight.vue
new file mode 100644
index 0000000..7a23af9
--- /dev/null
+++ b/src/views/TaskManage/components/TaskRight/TaskRight.vue
@@ -0,0 +1,25 @@
+<template>
+  <div class="task-right">
+    <TaskTime />
+    <TaskEvent />
+  </div>
+</template>
+
+<script setup>
+import TaskTime from './TaskTime.vue';
+import TaskEvent from './TaskEvent.vue';
+</script>
+
+<style scoped lang="scss">
+.task-right {
+  position: absolute;
+  top: 122px;
+  right: 31px;
+  width: 404px;
+
+  .titleBox {
+    width: 404px;
+    height: 43px;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/TaskManage/components/TaskRight/TaskTime.vue b/src/views/TaskManage/components/TaskRight/TaskTime.vue
new file mode 100644
index 0000000..48b9495
--- /dev/null
+++ b/src/views/TaskManage/components/TaskRight/TaskTime.vue
@@ -0,0 +1,125 @@
+<!-- 任务事件统计 -->
+<template>
+  <common-title title="任务时间统计"></common-title>
+  <div class="task-time">
+    <div class="chart" ref="chartRef"></div>
+  </div>
+ </template>
+
+<script setup>
+import CommonTitle from '@/components/CommonTitle.vue';
+import * as echarts from 'echarts';
+import { jobNumBar } from '@/api/home/task';
+import dayjs from 'dayjs';
+
+// 日期
+const currenDate = dayjs().format('YYYY-MM-DD');
+const newTime = ref([currenDate, currenDate]);
+
+const chartRef = ref(null);
+let chart = null;
+
+const option = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    top: '15%',
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    axisLine: {
+      lineStyle: {
+        color: '#fff'
+      }
+    },
+    axisLabel: {
+      color: '#fff',
+      interval: 0,
+      rotate: 30
+    }
+  },
+  yAxis: {
+    type: 'value',
+    axisLine: {
+      lineStyle: {
+        color: '#fff'
+      }
+    },
+    splitLine: {
+      lineStyle: {
+        color: 'rgba(255, 255, 255, 0.1)'
+      }
+    },
+    axisLabel: {
+      color: '#fff'
+    }
+  },
+  series: [
+    {
+      type: 'bar',
+      barWidth: '40%',
+      itemStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          { offset: 0, color: '#1EE7E7' },
+          { offset: 1, color: 'rgba(30, 231, 231, 0.1)' }
+        ])
+      }
+    }
+  ]
+};
+
+// 获取任务时间统计数据
+const getJobNumBar = (value,date_enum) => {
+  jobNumBar({date_enum}).then(res => {
+    if (res.data.code !== 0) return;
+    option.xAxis.data = res.data.data.map(item => item.name);
+    option.series[0].data = res.data.data.map(item => item.value);
+    chart.setOption(option);
+  });
+};
+
+
+onMounted(() => {
+  chart = echarts.init(chartRef.value);
+  getJobNumBar(newTime.value, 'CURRENT_YEAR');
+  
+  window.addEventListener('resize', () => {
+    chart?.resize();
+  });
+});
+
+onUnmounted(() => {
+  window.removeEventListener('resize', chart?.resize);
+  chart?.dispose();
+});
+</script>
+
+<style lang="scss" scoped>
+.task-time {
+  font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+  margin-left: 29px;
+  padding: 16px 16px;
+  width: 340px;
+  height: 400px;
+  background: linear-gradient(
+    270deg,
+    rgba(31, 62, 122, 0) 0%,
+    rgba(31, 62, 122, 0.35) 21%,
+    #1f3e7a 100%
+  );
+  border-radius: 0px 0px 0px 0px;
+  opacity: 0.85;
+  .chart {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3