Bladeren bron

feat:根据设备进行排期预览功能

lihao16 3 maanden geleden
bovenliggende
commit
ce4933eeb8

+ 4 - 1
smsb-modules/smsb-device/src/main/java/com/inspur/device/domain/vo/HttpHeartbeatRspVo.java

@@ -9,6 +9,9 @@ import lombok.Data;
 @Data
 public class HttpHeartbeatRspVo {
 
-    private String message;
+    /**
+     * 任务信息
+     */
+    private String taskInfo;
 
 }

+ 1 - 3
smsb-modules/smsb-device/src/main/java/com/inspur/device/service/impl/SmsbDeviceServiceImpl.java

@@ -447,9 +447,7 @@ public class SmsbDeviceServiceImpl implements ISmsbDeviceService {
         if (StringUtils.isEmpty(taskCache)) {
             return R.ok(rspVo);
         }
-        JSONObject rspJson = new JSONObject();
-        rspJson.set("taskInfo", taskCache);
-        rspVo.setMessage(rspJson.toString());
+        rspVo.setTaskInfo(taskCache);
         return R.ok(rspVo);
     }
 

+ 11 - 0
smsb-modules/smsb-source/src/main/java/com/inspur/source/controller/SmsbItemPushController.java

@@ -202,4 +202,15 @@ public class SmsbItemPushController extends BaseController {
     public R<Void> terminationTask(@RequestBody TerminationBo terminationBo) {
         return toAjax(smsbItemPushService.terminationTask(terminationBo));
     }
+
+    /**
+     * web 排期预览时间线
+     * @param deviceId
+     * @return
+     */
+    @GetMapping("/device/timeLine")
+    public R<List<DevicePushLineVo>> deviceTimeLine(@RequestParam Long deviceId,@RequestParam String startTime,
+                                                    @RequestParam String endTime) {
+        return smsbItemPushService.deviceTimeLine(deviceId,startTime,endTime);
+    }
 }

+ 33 - 0
smsb-modules/smsb-source/src/main/java/com/inspur/source/domain/vo/DevicePushLineVo.java

@@ -0,0 +1,33 @@
+package com.inspur.source.domain.vo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 排期预览,设备的时间线
+ *
+ * @author lihao16
+ */
+@Data
+public class DevicePushLineVo {
+
+    private Long deviceId;
+
+    private Date timePoint;
+
+    /**
+     * 时间类型 1、开始时间 2、结束时间
+     */
+    private Integer timeType;
+
+    private Long pushId;
+
+    private Long itemId;
+
+    private String itemName;
+
+    private Date startTime;
+
+    private Date endTime;
+}

+ 12 - 0
smsb-modules/smsb-source/src/main/java/com/inspur/source/mapper/SmsbItemPushPlaylineMapper.java

@@ -1,6 +1,7 @@
 package com.inspur.source.mapper;
 
 import com.inspur.source.domain.SmsbItemPushPlayline;
+import com.inspur.source.domain.vo.DevicePushLineVo;
 import com.inspur.source.domain.vo.SmsbItemPushPlaylineVo;
 import org.apache.ibatis.annotations.Param;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -34,6 +35,7 @@ public interface SmsbItemPushPlaylineMapper extends BaseMapperPlus<SmsbItemPushP
 
     /**
      * 前端设备获取时间线
+     *
      * @param startTime
      * @param endTime
      * @param deviceId
@@ -41,4 +43,14 @@ public interface SmsbItemPushPlaylineMapper extends BaseMapperPlus<SmsbItemPushP
      */
     List<SmsbItemPushPlaylineVo> selectPlayLineForFront(@Param("startTime") String startTime, @Param("endTime") String endTime,
                                                         @Param("deviceId") Long deviceId);
+
+    /**
+     * 获取设备时间线 web 排期预览
+     *
+     * @param deviceId
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    List<DevicePushLineVo> getDeviceTimeLine(@Param("deviceId") Long deviceId, @Param("startTime") String startTime, @Param("endTime") String endTime);
 }

+ 9 - 0
smsb-modules/smsb-source/src/main/java/com/inspur/source/service/ISmsbItemPushService.java

@@ -156,4 +156,13 @@ public interface ISmsbItemPushService {
      * @return
      */
     R<List<SmsbItemFileRelVo>> getPushSourceList(Long pushId);
+
+    /**
+     * web 排期预览时间线
+     * @param deviceId
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    R<List<DevicePushLineVo>> deviceTimeLine(Long deviceId,String startTime,String endTime);
 }

+ 22 - 0
smsb-modules/smsb-source/src/main/java/com/inspur/source/service/impl/SmsbItemPushServiceImpl.java

@@ -466,6 +466,28 @@ public class SmsbItemPushServiceImpl implements ISmsbItemPushService {
         return null;
     }
 
+    @Override
+    public R<List<DevicePushLineVo>> deviceTimeLine(Long deviceId, String startTime, String endTime) {
+        List<DevicePushLineVo> results = new ArrayList<>();
+        List<DevicePushLineVo> dbDataList = smsbItemPushPlaylineMapper.getDeviceTimeLine(deviceId,startTime,endTime);
+        if (CollectionUtil.isEmpty(dbDataList)) {
+            return R.ok(results);
+        }
+        for (DevicePushLineVo dbData : dbDataList) {
+            DevicePushLineVo startPoint = new DevicePushLineVo();
+            DevicePushLineVo endPoint = new DevicePushLineVo();
+            BeanUtils.copyProperties(dbData, startPoint);
+            startPoint.setTimePoint(dbData.getStartTime());
+            startPoint.setTimeType(1);
+            BeanUtils.copyProperties(dbData, endPoint);
+            endPoint.setTimePoint(dbData.getEndTime());
+            endPoint.setTimeType(2);
+            results.add(startPoint);
+            results.add(endPoint);
+        }
+        return R.ok(results);
+    }
+
     @Override
     public R<Void> submitReview(Long pushId) {
         SmsbItemPush smsbItemPush = baseMapper.selectById(pushId);

+ 18 - 0
smsb-modules/smsb-source/src/main/resources/mapper/SmsbItemPushPlaylineMapper.xml

@@ -34,4 +34,22 @@
         </foreach>
     </delete>
 
+    <select id="getDeviceTimeLine" resultType="com.inspur.source.domain.vo.DevicePushLineVo">
+        SELECT
+            line.device_id,
+            line.start_time,
+            line.end_time,
+            line.push_id,
+            rel.item_id,
+            item.item_name
+        FROM
+            smsb_item_push_playline line
+        LEFT JOIN smsb_item_push_rel rel ON line.push_id = rel.push_id
+        LEFT JOIN smsb_item item ON item.id = rel.item_id
+        WHERE
+            line.device_id = #{deviceId} AND line.start_time <![CDATA[ >= ]]> #{startTime} and line.start_time <![CDATA[ <= ]]> #{endTime}
+        ORDER BY
+            start_time asc
+    </select>
+
 </mapper>

+ 8 - 1
smsb-plus-ui/src/api/smsb/source/item_push.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { ItemPushVO, ItemPushForm, ItemPushQuery } from '@/api/smsb/source/item_push_type';
+import {ItemPushVO, ItemPushForm, ItemPushQuery, DevicePushLineVo} from '@/api/smsb/source/item_push_type';
 
 /**
  * 查询内容发布列表
@@ -98,3 +98,10 @@ export const pushStatistics = () => {
     method: 'get'
   });
 };
+export const listDevicePushLine = (query: DevicePushLineVo) => {
+  return request({
+    url: '/source/itemPush/device/timeLine',
+    method: 'get',
+    params: query
+  });
+};

+ 22 - 0
smsb-plus-ui/src/api/smsb/source/item_push_type.ts

@@ -137,3 +137,25 @@ export interface ItemPushTimeRangeVO {
   start?: string;
   end?: string;
 }
+
+export interface DevicePushLineVo {
+
+  deviceId?: number | string;
+
+  timePoint?: number | string;
+
+  /**
+   * 时间类型 1、开始时间 2、结束时间
+   */
+  timeType?: number | string;
+
+  pushId?: number | string;
+
+  itemId?: number | string;
+
+  itemName?: number | string;
+
+  startTime?: number | string;
+
+  endTime?: number | string;
+}

+ 1 - 1
smsb-plus-ui/src/views/smsb/deviceLogPush/index.vue

@@ -88,7 +88,7 @@
     </el-dialog>
     <!-- 抓取结果对话框 -->
     <el-dialog :title="listDialog.title" v-model="listDialog.visible" width="1000px" style="height: 800px" append-to-body>
-      <el-table v-loading="listLoading" :data="deviceLogPushList">
+      <el-table v-loading="listLoading" border fit highlight-current-row :data="deviceLogPushList">
         <el-table-column label="设备名称" align="left" prop="deviceName" width="200" :show-overflow-tooltip="true"/>
         <el-table-column label="抓取时长" align="center" prop="duration" width="80"/>
         <el-table-column label="抓取结果" align="center" prop="logStatus" width="80">

+ 1 - 1
smsb-plus-ui/src/views/smsb/deviceTask/index.vue

@@ -76,7 +76,7 @@
     <!-- 添加或修改设备任务中心对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="700px" append-to-body>
       <div class="table-content" style="height: 600px">
-        <el-table v-loading="detailLoading" :data="deviceTaskDetailVOList">
+        <el-table v-loading="detailLoading" border fit highlight-current-row :data="deviceTaskDetailVOList">
           <el-table-column label="ID" align="left" prop="id" v-if="true" width="180"/>
           <el-table-column label="任务状态" align="center" prop="taskStatus">
             <template #default="scope">

+ 280 - 0
smsb-plus-ui/src/views/smsb/itemPlayLine/index.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+                :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]" :style="{ marginTop: '10px', height: '60px' }">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="设备名称" prop="name">
+              <el-input v-model="queryParams.name" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery"/>
+            </el-form-item>
+            <el-form-item label="设备SN" prop="serialNumber">
+              <el-input v-model="queryParams.serialNumber" placeholder="请输入设备SN" clearable @keyup.enter="handleQuery"/>
+            </el-form-item>
+            <el-form-item label="MAC" prop="mac">
+              <el-input v-model="queryParams.mac" placeholder="请输入设备MAC" clearable @keyup.enter="handleQuery"/>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <div class="table-content">
+        <el-table v-loading="loading" :data="deviceList">
+          <el-table-column label="" align="left" prop="" width="10"/>
+          <el-table-column label="设备ID" align="left" prop="id" width="175" v-if="true"/>
+          <el-table-column label="设备标识" align="left" width="250" prop="identifier"/>
+          <el-table-column label="设备名称" align="left" prop="name" :show-overflow-tooltip="true"/>
+          <el-table-column label="设备SN" align="left" prop="serialNumber" :show-overflow-tooltip="true"/>
+          <el-table-column label="设备MAC" align="left" prop="mac" width="220"/>
+          <el-table-column label="在线状态" width="150" align="center" prop="onlineStatus">
+            <template #default="scope">
+              <dict-tag :options="sys_device_online" :value="scope.row.onlineStatus"/>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="150" align="center" class-name="small-padding fixed-width">
+            <template #default="scope">
+              <el-tooltip content="开始抓取" placement="top">
+                <el-button link type="primary" icon="View" @click="handlePlayLine(scope.row)"
+                           v-hasPermi="['device:log:add']">排期预览
+                </el-button>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+                  v-model:limit="queryParams.pageSize" @pagination="getList"/>
+    </el-card>
+    <!-- 排期列表 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" style="height: 800px" width="1200px" append-to-body>
+      <div style="width: 100%;text-align: right;">
+        <el-date-picker v-model="dateRange" :clearable="false" @change="handleDateRangeChange" type="daterange"
+                        range-separator="-" start-placeholder="开始日期"
+                        end-placeholder="结束日期" class="date-picker"/>
+      </div>
+      <div style="height: 600px;margin-top: 10px">
+        <el-row>
+          <el-col :span="8" style="margin-top: 10px">
+            <el-empty v-if="emptyFlag" :description="'暂无排期'"></el-empty>
+            <el-timeline v-else style="max-width: 700px">
+              <el-timeline-item
+                v-for="(activity, index) in timeLineActivity"
+                :key="index"
+                :type="activity.type"
+                :color="activity.color"
+                :size="activity.size"
+                :hollow="activity.hollow"
+                :timestamp="activity.timestamp"
+                @click="handleTimelineItemClick(activity, index)"
+                style="cursor: pointer;"
+              >
+                {{ activity.content }}
+              </el-timeline-item>
+            </el-timeline>
+          </el-col>
+          <el-col :span="16">
+            <div>
+              <el-table :data="sourceList" border fit>
+                <el-table-column label="文件" align="left" prop="originalName" :show-overflow-tooltip="true"/>
+                <el-table-column label="类型" align="center" prop="type" width="80">
+                  <template #default="scope">
+                    <dict-tag :options="smsb_source_type" :value="scope.row.type"/>
+                  </template>
+                </el-table-column>
+                <el-table-column label="大小" align="center" prop="size" width="80"/>
+                <el-table-column label="预览" align="center" prop="screenshot" width="80">
+                  <template #default="scope">
+                    <div v-if="scope.row.type === 1">
+                      <!-- 图片类型 -->
+                      <image-preview :src="scope.row.screenshot" style="width: 40px; height: 40px; cursor: pointer"/>
+                    </div>
+                    <div v-else-if="scope.row.type === 2">
+                      <!-- 视频类型 -->
+                      <el-icon class="VideoPlay" @click="viewVideo(scope.row.screenshot)" size="40"
+                               style="cursor: pointer">
+                        <VideoPlay/>
+                      </el-icon>
+                    </div>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+    </el-dialog>
+
+    <!-- 用于展示播放的视频 -->
+    <el-dialog v-model="videoDialogVisible" v-if="videoDialogVisible" append-to-body title="视频预览">
+      <VideoPlayer :url="videoUrl"/>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Device" lang="ts">
+import {listDevice} from '@/api/smsb/device/device';
+import {DeviceQuery, DeviceVO} from '@/api/smsb/device/device_type';
+import {DeviceLogPushForm} from "@/api/smsb/device/logPush/types";
+import {TimelineItemProps} from "element-plus";
+import {getItemPushReview, listDevicePushLine} from "@/api/smsb/source/item_push";
+import {DevicePushLineVo} from "@/api/smsb/source/item_push_type";
+import {MinioDataVO} from "@/api/smsb/source/minioData_type";
+import VideoPlayer from '../../../components/VideoPlayer/index.vue'
+import {ref} from "vue";
+
+const {proxy} = getCurrentInstance() as ComponentInternalInstance;
+const {
+  sys_device_online, smsb_yes_no, smsb_device_log_status, smsb_source_type
+} = toRefs<any>(
+  proxy?.useDict('sys_device_online', 'smsb_yes_no', 'smsb_device_log_status', 'smsb_source_type')
+);
+const dateRange = ref<[Date, Date]>([null, null]);
+const deviceList = ref<DeviceVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const sourceList = ref<MinioDataVO[]>([]);
+const videoDialogVisible = ref(false);
+const videoUrl = ref('');
+const queryFormRef = ref<ElFormInstance>();
+const deviceId = ref<number | string>();
+const sourceListQuery = ref<DevicePushLineVo>();
+const emptyFlag = ref(true);
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+const initFormData: DeviceLogPushForm = {}
+const data = reactive<PageData<DeviceLogPushForm, DeviceQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: undefined,
+    serialNumber: undefined,
+    params: {}
+  },
+  rules: {}
+});
+
+interface ActivityType extends Partial<TimelineItemProps> {
+  content: string
+}
+
+const timeLineActivity = ref<ActivityType[]>([]);
+
+const {queryParams, form, rules} = toRefs(data);
+
+const viewVideo = (url: string) => {
+  videoUrl.value = url;
+  videoDialogVisible.value = true;
+};
+
+/** 查询设备列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listDevice(queryParams.value);
+  deviceList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+  videoDialogVisible.value = false;
+}
+
+// 添加时间线项点击处理函数
+const handleTimelineItemClick = async (activity: ActivityType, index: number) => {
+  // 在此处添加您需要的处理逻辑
+  // 例如:显示详细信息、跳转到相关页面等
+  const res = await getItemPushReview(activity.pushId);
+  sourceList.value = res.data.resourceList;
+};
+
+const handlePlayLine = async (row: DeviceVO) => {
+  dialog.title = "排期预览";
+  dialog.visible = true;
+  const today = new Date();
+  const startDate = new Date(today);
+  const endDate = new Date(today);
+  endDate.setDate(today.getDate() + 30);
+  dateRange.value = [startDate, endDate];
+  deviceId.value = row.id;
+  await getPlayLineData();
+}
+
+const handleDateRangeChange = () => {
+  getPlayLineData();
+}
+
+const getPlayLineData = async () => {
+  sourceList.value = [];
+  // 初始化 sourceListQuery 或创建一个新的对象
+  if (!sourceListQuery.value) {
+    sourceListQuery.value = {} as DevicePushLineVo;
+  }
+  sourceListQuery.value.deviceId = deviceId.value;
+  sourceListQuery.value.startTime = formatDate(dateRange.value[0]);
+  sourceListQuery.value.endTime = formatDate(dateRange.value[1]);
+  const res = await listDevicePushLine(sourceListQuery.value);
+  timeLineActivity.value = res.data.map((item: DevicePushLineVo) => {
+    return {
+      color: item.timeType === 1 ? 'green' : '#eee',
+      type: item.timeType === 1 ? 'primary' : '',
+      content: item.itemName,
+      timestamp: item.timePoint,
+      size: 'large',
+      hollow: false,
+      pushId: item.pushId
+    }
+  });
+  if (res.data.length > 0) {
+    emptyFlag.value = false;
+    const res1 = await getItemPushReview(res.data[0].pushId);
+    sourceList.value = res1.data.resourceList;
+  }else {
+    emptyFlag.value = true;
+  }
+};
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+}
+const formatDate = (date: Date): string => {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0');
+  const day = String(date.getDate()).padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 1 - 1
smsb-plus-ui/src/views/smsb/itemPush/index.vue

@@ -158,7 +158,7 @@
           </el-table>
         </el-col>
         <!--发布名称-->
-        <el-col :span="9" style="height: 570px; overflow: auto; border: 1px solid #eee; padding-left: 10px">
+        <el-col :span="9" style="height: 570px; overflow: auto; padding-left: 10px">
           <el-form ref="itemPushFormRef" :model="form" :rules="rules" style="margin-top: 5px" label-width="60px">
             <el-form-item label="名称" prop="name">
               <el-input v-model="form.name" placeholder="请输入名称" />