Browse Source

项目提交

luogang 10 months ago
parent
commit
44d038d19a

+ 17 - 0
ruoyi-modules/ruoyi-traffic/src/main/java/org/dromara/controller/SenEventsController.java

@@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.domain.bo.SenEventsObjectBo;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -200,4 +201,20 @@ public class SenEventsController extends BaseController {
     public R<List<HashMap<String,Object>>> eventsDealRateStat(@RequestParam String dateType) {
         return R.ok(senEventsService.eventsDealRateStat(dateType));
     }
+    /**
+     * 骑行违法分析
+     */
+    @SaCheckPermission("manage:events:list")
+    @GetMapping("/cycleEventStat")
+    public TableDataInfo<Map<String,Object>> cycleEventStat(SenEventsBo senEventsBo, PageQuery pageQuery) {
+        return senEventsService.cycleEventStat(senEventsBo,pageQuery);
+    }
+    /**
+     * 重点车辆分析
+     */
+    @SaCheckPermission("manage:events:list")
+    @GetMapping("/keyVehicleEventStat")
+    public TableDataInfo<Map<String,Object>> keyVehicleEventStat(SenEventsObjectBo bo, PageQuery pageQuery) {
+        return senEventsService.keyVehicleEventStat(bo,pageQuery);
+    }
 }

+ 9 - 0
ruoyi-modules/ruoyi-traffic/src/main/java/org/dromara/mapper/SenEventsMapper.java

@@ -3,12 +3,17 @@ package org.dromara.mapper;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.dromara.domain.SenAlgorithmConfig;
 import org.dromara.domain.SenEvents;
+import org.dromara.domain.SenEventsObject;
+import org.dromara.domain.vo.SenAlgorithmConfigVo;
 import org.dromara.domain.vo.SenEventsVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -47,4 +52,8 @@ public interface SenEventsMapper extends BaseMapperPlus<SenEvents, SenEventsVo>
     List<HashMap<String, Object>> eventsHourStat( @Param(Constants.WRAPPER) LambdaQueryWrapper<SenEvents> queryWrapper);
 
     List<HashMap<String, Object>> eventsDealRateStat(@Param(Constants.WRAPPER) LambdaQueryWrapper<SenEvents> queryWrapper);
+
+    Page<Map<String, Object>> cycleEventStat(Page<SenEvents>  page, @Param("ew") Wrapper<SenEvents> queryWrapper);
+
+    Page<Map<String, Object>> keyVehicleEventStat(Page<SenEventsObject> page, @Param("startDate") String startDate, @Param("endDate") String endDate, @Param("ew")LambdaQueryWrapper<SenEventsObject> queryWrapper);
 }

+ 9 - 0
ruoyi-modules/ruoyi-traffic/src/main/java/org/dromara/service/ISenEventsService.java

@@ -1,5 +1,6 @@
 package org.dromara.service;
 
+import org.dromara.domain.bo.SenEventsObjectBo;
 import org.dromara.domain.vo.SenEventsVo;
 import org.dromara.domain.bo.SenEventsBo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -116,4 +117,12 @@ public interface ISenEventsService {
      * 交通违法处置分析
      */
     List<HashMap<String, Object>> eventsDealRateStat(String dateType);
+    /**
+     * 骑行违法分析
+     */
+    TableDataInfo<Map<String, Object>> cycleEventStat(SenEventsBo senEventsBo, PageQuery pageQuery);
+    /**
+     * 重点车辆分析
+     */
+    TableDataInfo<Map<String, Object>> keyVehicleEventStat(SenEventsObjectBo bo, PageQuery pageQuery);
 }

+ 34 - 1
ruoyi-modules/ruoyi-traffic/src/main/java/org/dromara/service/impl/SenEventsServiceImpl.java

@@ -1,6 +1,5 @@
 package org.dromara.service.impl;
 
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -9,6 +8,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
+import org.dromara.domain.bo.SenEventsObjectBo;
+import org.dromara.domain.SenEventsObject;
 import org.dromara.system.domain.SysDictData;
 import org.dromara.system.mapper.SysDictDataMapper;
 import org.springframework.stereotype.Service;
@@ -267,4 +268,36 @@ public class SenEventsServiceImpl implements ISenEventsService {
         LambdaQueryWrapper<SenEvents> queryWrapper = buildDateWrapper(dateType);
         return baseMapper.eventsDealRateStat(queryWrapper);
     }
+    /**
+     * 骑行违法分析
+     */
+    @Override
+    public TableDataInfo<Map<String, Object>> cycleEventStat(SenEventsBo senEventsBo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SenEvents> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(senEventsBo.getPointName()), SenEvents::getPointName, senEventsBo.getPointName());
+        queryWrapper.ge(StringUtils.isNotBlank((CharSequence) senEventsBo.getParams().get("startDate")),SenEvents::getCreateTime, senEventsBo.getParams().get("startDate"))
+                .le(StringUtils.isNotBlank((CharSequence) senEventsBo.getParams().get("endDate")),SenEvents::getCreateTime, senEventsBo.getParams().get("endDate"));
+        Page<Map<String, Object>> result = baseMapper.cycleEventStat(pageQuery.build(), queryWrapper);
+         return TableDataInfo.build(result);
+    }
+    /**
+     * 重点车辆分析
+     */
+    @Override
+    public TableDataInfo<Map<String, Object>> keyVehicleEventStat(SenEventsObjectBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SenEventsObject> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(bo.getObjectId()), SenEventsObject::getObjectId, bo.getObjectId());
+        String startDate = null;
+        String endDate = null;
+        if(StringUtils.isNotBlank((CharSequence) bo.getParams().get("startDate"))){
+            startDate= (String) bo.getParams().get("startDate");
+        }
+        if(StringUtils.isNotBlank((CharSequence) bo.getParams().get("endDate"))){
+            endDate= (String) bo.getParams().get("endDate");
+        }
+//        queryWrapper.ge(StringUtils.isNotBlank((CharSequence) bo.getParams().get("startDate")),SenEventsObject::getCreateTime, bo.getParams().get("startDate"))
+//                .le(StringUtils.isNotBlank((CharSequence) bo.getParams().get("endDate")),SenEventsObject::getCreateTime, bo.getParams().get("endDate"));
+        Page<Map<String, Object>> result = baseMapper.keyVehicleEventStat(pageQuery.build(), startDate,endDate,queryWrapper);
+        return TableDataInfo.build(result);
+    }
 }

+ 78 - 0
ruoyi-modules/ruoyi-traffic/src/main/resources/mapper/SenEventsMapper.xml

@@ -20,6 +20,7 @@
         FROM sen_events
         ${ew.getCustomSqlSegment}
         GROUP BY event_type
+        ORDER BY name
     </select>
     <select id="motorInLanesTop10" resultType="java.util.HashMap">
         SELECT point_name AS pointName, COUNT(*) AS eventCount
@@ -302,4 +303,81 @@
         ORDER BY
         dict.dict_label;
     </select>
+    <select id="cycleEventStat" resultType="java.util.Map">
+        SELECT
+        pointName,
+        SUM(CASE WHEN event_type = 13 THEN count ELSE 0 END) AS nonMotorVehicleOnLane,
+        SUM(CASE WHEN event_type = 14 THEN count ELSE 0 END) AS nonMotorVehicleNoHelmet,
+        SUM(CASE WHEN event_type = 15 THEN count ELSE 0 END) AS pedestrianOnLane
+        FROM (
+        SELECT
+        point_name AS pointName,
+        event_type,
+        COUNT(*) AS count
+        FROM
+        sen_events
+        WHERE
+        event_type IN (13, 14, 15)
+        <if test="ew.getSqlSegment != null and ew.getSqlSegment != ''">
+            AND ${ew.getSqlSegment}
+        </if>
+        GROUP BY
+        pointName, event_type
+        ) sub
+        GROUP BY
+        pointName
+        ORDER BY
+        pointName
+    </select>
+    <select id="keyVehicleEventStat" resultType="java.util.Map">
+        WITH plate_counts AS (
+        SELECT
+        seo.object_id,
+        seo.object_type,
+        seo.object_attr,
+        se.event_type,
+        COUNT( se.id ) AS event_count
+        FROM
+        sen_events_object seo
+        LEFT JOIN sen_events se ON seo.event_id = se.id
+        WHERE
+        CAST( se.event_type AS UNSIGNED ) BETWEEN 5
+        AND 12
+        <if test="startDate!=null">
+            AND DATE ( se.create_time ) >=${startDate}
+        </if>
+        <if test="endDate!=null">
+            AND DATE ( se.create_time ) &lt;=${endDate}
+        </if>
+        GROUP BY
+        seo.object_id,
+        seo.object_type,
+        seo.object_attr,
+        se.event_type
+        ),
+        all_objects AS ( SELECT DISTINCT object_id, object_type, object_attr FROM sen_events_object seo   ${ew.getCustomSqlSegment}
+        ) SELECT
+        ao.object_id AS objectId,
+        ao.object_type AS objectType,
+        ao.object_attr AS objectAttr,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 5 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount5,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 6 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount6,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 7 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount7,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 8 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount8,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 9 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount9,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 10 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount10,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 11 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount11,
+        COALESCE ( SUM( CASE WHEN pc.event_type = 12 THEN pc.event_count ELSE 0 END ), 0 ) AS eventCount12
+        FROM
+        all_objects ao
+        LEFT JOIN plate_counts pc ON ao.object_id = pc.object_id
+        AND ao.object_type = pc.object_type
+        AND ao.object_attr = pc.object_attr
+        GROUP BY
+        objectId,
+        objectType,
+        objectAttr
+        ORDER BY
+        objectId
+    </select>
 </mapper>

+ 3 - 3
ruoyi-modules/ruoyi-traffic/src/main/resources/mapper/SenMonitorTaskMapper.xml

@@ -32,9 +32,9 @@
         '交通' AS event_obj,
         0 AS deal_status,
         CASE
-        WHEN RAND() lt; 0.25 THEN '电子警察'
-        WHEN RAND() lt; 0.50 THEN '普通卡口'
-        WHEN RAND() lt; 0.75 THEN '不文明驾驶'
+        WHEN RAND() &lt; 0.25 THEN '电子警察'
+        WHEN RAND() &lt; 0.50 THEN '普通卡口'
+        WHEN RAND() &lt; 0.75 THEN '不文明驾驶'
         ELSE '其他'
         END AS datasource,
         1 AS create_by,

+ 22 - 0
traffic-ui/src/api/sense/events/index.ts

@@ -192,3 +192,25 @@ export const eventsDealRateStat = (params) => {
     params
   });
 };
+/**
+ *骑行违法分析
+ */
+
+export const cycleEventStat = (params) => {
+  return request({
+    url: '/manage/events/cycleEventStat',
+    method: 'get',
+    params
+  });
+};
+/**
+ *重点车辆违法分析
+ */
+
+export const keyVehicleEventStat = (params) => {
+  return request({
+    url: '/manage/events/keyVehicleEventStat',
+    method: 'get',
+    params
+  });
+};

+ 107 - 258
traffic-ui/src/views/analysis/cycling/index.vue

@@ -1,279 +1,128 @@
 <template>
-  <div class="eventStat">
-    <div class="eventStat-header">
-      <el-card>
-        <template #header>
-          <div class="event-category">
-            <span>监控点位违反统计</span>
-            <el-radio-group v-model="eventDateType" @change="getBarData" size="small">
-              <el-radio-button label="今天" value="1" />
-              <el-radio-button label="近7天" value="7" />
-              <el-radio-button label="近30天" value="30" />
-            </el-radio-group>
-          </div>
-        </template>
-        <BaseChart width="100%" height="250px" :option="barOptions" />
-      </el-card>
-      <el-card>
-        <template #header>
-          <div class="event-category">
-            <span>区域违法分布</span>
-            <el-radio-group v-model="regionDateType" @change="getPieData" size="small">
-              <el-radio-button label="今天" value="1" />
-              <el-radio-button label="近7天" value="7" />
-              <el-radio-button label="近30天" value="30" />
-            </el-radio-group>
-          </div>
-        </template>
-        <BaseChart width="100%" height="250px" :option="pieOptions" />
-      </el-card>
+  <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]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="90px">
+            <el-form-item label="监控点名称" prop="pointName">
+              <el-input v-model="queryParams.pointName" placeholder="请输入监控点名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="时间范围" prop="params">
+              <el-date-picker v-model="queryParams.params.date" value-format="YYYY-MM-DD" type="daterange"
+                range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" unlink-panels :shortcuts="shortcuts"
+                @change="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>
 
-    </div>
-    <el-card style="margin-top: 10px;">
+    <el-card shadow="never">
       <template #header>
-        <div class="event-category">
-          <span>每分钟{{ formatDict(eventType) }}统计</span>
-          <el-select v-model="eventType" @change="getLineData">
-            <el-option v-for="item in eventTypeOptions" :key="item.dictValue" :label="item.dictLabel"
-              :value="item.dictValue" />
-          </el-select>
-        </div>
+        <el-row :gutter="10" class="mb8">
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
       </template>
-      <BaseChart width="100%" height="250px" :option="lineOptions" />
-    </el-card>
-
 
+      <el-table v-loading="loading" :data="cyclingList">
+        <el-table-column label="监控点名称" align="center" width="150" show-overflow-tooltip prop="pointName" />
+        <el-table-column label="非机动车占机动车道" align="center" prop="nonMotorVehicleOnLane" />
+        <el-table-column label="非机动车不戴头盔" align="center" prop="nonMotorVehicleNoHelmet" />
+        <el-table-column label="行人走机动车道" align="center" prop="pedestrianOnLane" />
+      </el-table>
 
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
   </div>
 </template>
-<script setup lang="ts">
-import BaseChart from '@/components/BaseChart/index.vue'
-import { pointEventsStat, regionEventsStat, minuteEventsStat } from '@/api/sense/events/index'
-import { getDicts } from '@/api/system/dict/data/index'
-const pieData = ref([])
-const barData = ref([])
-const lineData = ref([])
-const eventTypeOptions = ref([])
-const eventType = ref('1')
-const eventDateType = ref('1')
-const regionDateType = ref('1')
-const pieOptions = computed(() => {
-  let options = {
-    tooltip: {
-      trigger: 'item'
-    },
-    legend: {
-      orient: 'vertical',
-      top: '8%',
-      right: 0,
-      itemWidth: 10,
-      itemHeight: 10,
-      itemGap: 10
-    },
-    grid: {
-    },
-    series: [
-      {
-        type: 'pie',
-        radius: '50%',
-        data: pieData.value,
-        center: ['40%', '50%'],
-        emphasis: {
-          itemStyle: {
-            shadowBlur: 10,
-            shadowOffsetX: 0,
-            shadowColor: 'rgba(0, 0, 0, 0.5)'
-          }
-        }
-      }
-    ]
-  };
-  return options
-})
-const barOptions = computed(() => {
-  const colors = [
-    "#FF5733",
-    "#7B3F00",
-    "#FFC300",
-    "#DAF7A6",
-    "#FF5733",
-    "#008080",
-    "#E8EAF6",
-    "#FFEEC1",
-    "#B39DDB",
-    "#4CAF50"
-  ];
-  const barObj = {}
-  barData.value.forEach(item => {
-    barObj[item.area_name] = item.event_count
-  })
-  let options = {
-    tooltip: {
-      trigger: 'axis',
-      axisPointer: {
-        type: 'shadow'
-      }
-    },
-    grid: {
-      left: '5%',
-      right: '3%',
-      bottom: 0,
-      top: '6%',
-      containLabel: true
-    },
-    xAxis: {
-      type: 'category',
-      data: Object.keys(barObj),
-      axisLabel: {
-        interval: 0,
-        // rotate: 15  // 表示倾斜的角度
-      }
-    },
-    yAxis: {
-      type: 'value'
-    },
-    series: [
-      {
-        data: Object.values(barObj),
-        type: 'bar',
-        barWidth: 20,
-        itemStyle: {
-          color: (params) => {
-            return colors[params.dataIndex]
-          }
-        },
-        label: {
-          show: true, // 显示数值
-          position: 'top' // 在顶部显示
-        }
 
-      }
-    ]
-  };
-  return options
-})
-const lineOptions = computed(() => {
-  const xData = lineData.value.map(item => item.time_format)
-  const yData = lineData.value.map(item => item.count)
-  const options = {
-    tooltip: {
-      trigger: 'axis',
-      appendToBody: true
-    },
-    grid: {
-      left: '1%',
-      right: '3%',
-      bottom: 0,
-      top: '22%',
-      containLabel: true
+<script setup name="cycling" lang="ts">
+import { cycleEventStat } from '@/api/sense/events';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const cyclingList = ref([])
+const loading = ref(true);
+const showSearch = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const shortcuts = [
+  {
+    text: '上周',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+      return [start, end]
     },
-    xAxis: {
-      type: 'category',
-      axisLabel: {
-        show: true,
-        interval: 0,//横轴信息全部显示
-        // margin: 5, //刻度标签与轴线之间的距离
-      },
-      data: xData
+  },
+  {
+    text: '上个月',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+      return [start, end]
     },
-    yAxis: {
-      type: 'value'
+  },
+  {
+    text: '前三个月',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+      return [start, end]
     },
-    series: [
-      // {
-      // name: '',
-      // type: 'line',
-      // symbol: 'circle', // 默认是空心圆(中间是白色的),改成实心圆
-      // showAllSymbol: true,
-      // symbolSize: 0,
-      // data: yData
-      // }
-      {
-        name: '',
-        data: yData,
-        type: 'pictorialBar',
-        barMinHeight: 50,
-        barCategoryGap: '80%',
-        symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z',
-        itemStyle: {
-          normal: {
-            color: '#65B1E9'
-          }
-        },
-      },
-    ]
-  };
-  return options
-})
-onMounted(() => {
-  getPieData()
-  getBarData()
-  getLineData()
-  getDicts('event_type').then(({ code, data }) => {
-    if (code === 200) {
-      eventTypeOptions.value = data || []
-    }
-  })
+  },
+]
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  pointName: undefined,
+  params: {
+    date: [],
+    startDate: '',
+    endDate: ''
+  }
 })
-const getPieData = () => {
-  regionEventsStat({ dateType: regionDateType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      pieData.value = data || []
-    }
-  })
-}
-const getBarData = () => {
-  pointEventsStat({ dateType: eventDateType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      barData.value = data || []
-    }
-  })
-}
-const getLineData = () => {
-  minuteEventsStat({ eventType: eventType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      lineData.value = data || {}
-    }
-  })
-}
-const formatDict = (val) => {
-  let name = ''
-  eventTypeOptions.value.forEach(item => {
-    if (item.dictValue === val) {
-      name = item.dictLabel
-    }
-  })
-  return name
+const getList = async () => {
+  loading.value = true;
+  queryParams.value.params.startDate = ''
+  queryParams.value.params.endDate = ''
+  if (queryParams.value.params.date && queryParams.value.params.date.length) {
+    const [startDate, endDate] = queryParams.value.params.date
+    queryParams.value.params.startDate = startDate
+    queryParams.value.params.endDate = endDate
+  }
+  const res = await cycleEventStat(queryParams.value);
+  cyclingList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 
-</script>
-<style lang="scss" scoped>
-.eventStat {
-  padding: 10px;
-  height: 100%;
-  background-color: #F0F2F5;
-  position: relative;
-}
 
-.event-category {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
 
-  .el-select {
-    width: 250px;
-  }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
 }
 
-.eventStat-header {
-  display: flex;
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
 
-  .el-card {
-    flex: 1;
 
-    &:not(:first-child) {
-      margin-left: 10px;
-    }
-  }
-}
-</style>
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 114 - 258
traffic-ui/src/views/analysis/keyVehicles/index.vue

@@ -1,279 +1,135 @@
 <template>
-  <div class="eventStat">
-    <div class="eventStat-header">
-      <el-card>
-        <template #header>
-          <div class="event-category">
-            <span>监控点位违反统计</span>
-            <el-radio-group v-model="eventDateType" @change="getBarData" size="small">
-              <el-radio-button label="今天" value="1" />
-              <el-radio-button label="近7天" value="7" />
-              <el-radio-button label="近30天" value="30" />
-            </el-radio-group>
-          </div>
-        </template>
-        <BaseChart width="100%" height="250px" :option="barOptions" />
-      </el-card>
-      <el-card>
-        <template #header>
-          <div class="event-category">
-            <span>区域违法分布</span>
-            <el-radio-group v-model="regionDateType" @change="getPieData" size="small">
-              <el-radio-button label="今天" value="1" />
-              <el-radio-button label="近7天" value="7" />
-              <el-radio-button label="近30天" value="30" />
-            </el-radio-group>
-          </div>
-        </template>
-        <BaseChart width="100%" height="250px" :option="pieOptions" />
-      </el-card>
+  <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]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="90px">
+            <el-form-item label="车牌号" prop="objectId">
+              <el-input v-model="queryParams.objectId" placeholder="请输入车牌号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="时间范围" prop="params">
+              <el-date-picker v-model="queryParams.params.date" value-format="YYYY-MM-DD" type="daterange"
+                range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" unlink-panels :shortcuts="shortcuts"
+                @change="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>
 
-    </div>
-    <el-card style="margin-top: 10px;">
+    <el-card shadow="never">
       <template #header>
-        <div class="event-category">
-          <span>每分钟{{ formatDict(eventType) }}统计</span>
-          <el-select v-model="eventType" @change="getLineData">
-            <el-option v-for="item in eventTypeOptions" :key="item.dictValue" :label="item.dictLabel"
-              :value="item.dictValue" />
-          </el-select>
-        </div>
+        <el-row :gutter="10" class="mb8">
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
       </template>
-      <BaseChart width="100%" height="250px" :option="lineOptions" />
-    </el-card>
-
 
+      <el-table v-loading="loading" :data="cyclingList">
+        <el-table-column label="车牌" align="center" width="150" show-overflow-tooltip fixed="left" prop="objectId" />
+        <el-table-column label="品牌" align="center" width="100" prop="objectAttr" />
+        <el-table-column label="车辆类型" align="center" prop="objectType" />
+        <el-table-column label="违法变道" align="center" prop="eventCount5" />
+        <el-table-column label="压线行驶" align="center" prop="eventCount6" />
+        <el-table-column label="机动车逆行" align="center"width="100" prop="eventCount7" />
+        <el-table-column label="车辆闯禁" align="center" prop="eventCount8" />
+        <el-table-column label="违法停车" align="center" prop="eventCount9" />
+        <el-table-column label="占用非机动车道" align="center" width="120" prop="eventCount10" />
+        <el-table-column label="不按规定车道行驶" align="center" width="130" prop="eventCount11" />
+        <el-table-column label="货车右转必停" align="center" width="120" prop="eventCount12" />
+      </el-table>
 
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
   </div>
 </template>
-<script setup lang="ts">
-import BaseChart from '@/components/BaseChart/index.vue'
-import { pointEventsStat, regionEventsStat, minuteEventsStat } from '@/api/sense/events/index'
-import { getDicts } from '@/api/system/dict/data/index'
-const pieData = ref([])
-const barData = ref([])
-const lineData = ref([])
-const eventTypeOptions = ref([])
-const eventType = ref('1')
-const eventDateType = ref('1')
-const regionDateType = ref('1')
-const pieOptions = computed(() => {
-  let options = {
-    tooltip: {
-      trigger: 'item'
-    },
-    legend: {
-      orient: 'vertical',
-      top: '8%',
-      right: 0,
-      itemWidth: 10,
-      itemHeight: 10,
-      itemGap: 10
-    },
-    grid: {
-    },
-    series: [
-      {
-        type: 'pie',
-        radius: '50%',
-        data: pieData.value,
-        center: ['40%', '50%'],
-        emphasis: {
-          itemStyle: {
-            shadowBlur: 10,
-            shadowOffsetX: 0,
-            shadowColor: 'rgba(0, 0, 0, 0.5)'
-          }
-        }
-      }
-    ]
-  };
-  return options
-})
-const barOptions = computed(() => {
-  const colors = [
-    "#FF5733",
-    "#7B3F00",
-    "#FFC300",
-    "#DAF7A6",
-    "#FF5733",
-    "#008080",
-    "#E8EAF6",
-    "#FFEEC1",
-    "#B39DDB",
-    "#4CAF50"
-  ];
-  const barObj = {}
-  barData.value.forEach(item => {
-    barObj[item.area_name] = item.event_count
-  })
-  let options = {
-    tooltip: {
-      trigger: 'axis',
-      axisPointer: {
-        type: 'shadow'
-      }
-    },
-    grid: {
-      left: '5%',
-      right: '3%',
-      bottom: 0,
-      top: '6%',
-      containLabel: true
-    },
-    xAxis: {
-      type: 'category',
-      data: Object.keys(barObj),
-      axisLabel: {
-        interval: 0,
-        // rotate: 15  // 表示倾斜的角度
-      }
-    },
-    yAxis: {
-      type: 'value'
-    },
-    series: [
-      {
-        data: Object.values(barObj),
-        type: 'bar',
-        barWidth: 20,
-        itemStyle: {
-          color: (params) => {
-            return colors[params.dataIndex]
-          }
-        },
-        label: {
-          show: true, // 显示数值
-          position: 'top' // 在顶部显示
-        }
 
-      }
-    ]
-  };
-  return options
-})
-const lineOptions = computed(() => {
-  const xData = lineData.value.map(item => item.time_format)
-  const yData = lineData.value.map(item => item.count)
-  const options = {
-    tooltip: {
-      trigger: 'axis',
-      appendToBody: true
-    },
-    grid: {
-      left: '1%',
-      right: '3%',
-      bottom: 0,
-      top: '22%',
-      containLabel: true
+<script setup name="cycling" lang="ts">
+import { keyVehicleEventStat } from '@/api/sense/events';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const cyclingList = ref([])
+const loading = ref(true);
+const showSearch = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const shortcuts = [
+  {
+    text: '上周',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+      return [start, end]
     },
-    xAxis: {
-      type: 'category',
-      axisLabel: {
-        show: true,
-        interval: 0,//横轴信息全部显示
-        // margin: 5, //刻度标签与轴线之间的距离
-      },
-      data: xData
+  },
+  {
+    text: '上个月',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+      return [start, end]
     },
-    yAxis: {
-      type: 'value'
+  },
+  {
+    text: '前三个月',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+      return [start, end]
     },
-    series: [
-      // {
-      // name: '',
-      // type: 'line',
-      // symbol: 'circle', // 默认是空心圆(中间是白色的),改成实心圆
-      // showAllSymbol: true,
-      // symbolSize: 0,
-      // data: yData
-      // }
-      {
-        name: '',
-        data: yData,
-        type: 'pictorialBar',
-        barMinHeight: 50,
-        barCategoryGap: '80%',
-        symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z',
-        itemStyle: {
-          normal: {
-            color: '#65B1E9'
-          }
-        },
-      },
-    ]
-  };
-  return options
-})
-onMounted(() => {
-  getPieData()
-  getBarData()
-  getLineData()
-  getDicts('event_type').then(({ code, data }) => {
-    if (code === 200) {
-      eventTypeOptions.value = data || []
-    }
-  })
+  },
+]
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  objectId: undefined,
+  params: {
+    date: [],
+    startDate: '',
+    endDate: ''
+  }
 })
-const getPieData = () => {
-  regionEventsStat({ dateType: regionDateType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      pieData.value = data || []
-    }
-  })
-}
-const getBarData = () => {
-  pointEventsStat({ dateType: eventDateType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      barData.value = data || []
-    }
-  })
-}
-const getLineData = () => {
-  minuteEventsStat({ eventType: eventType.value }).then(({ code, data }) => {
-    if (code === 200) {
-      lineData.value = data || {}
-    }
-  })
-}
-const formatDict = (val) => {
-  let name = ''
-  eventTypeOptions.value.forEach(item => {
-    if (item.dictValue === val) {
-      name = item.dictLabel
-    }
-  })
-  return name
+const getList = async () => {
+  loading.value = true;
+  queryParams.value.params.startDate = ''
+  queryParams.value.params.endDate = ''
+  if (queryParams.value.params.date && queryParams.value.params.date.length) {
+    const [startDate, endDate] = queryParams.value.params.date
+    queryParams.value.params.startDate = startDate
+    queryParams.value.params.endDate = endDate
+  }
+  const res = await keyVehicleEventStat(queryParams.value);
+  cyclingList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
 }
 
-</script>
-<style lang="scss" scoped>
-.eventStat {
-  padding: 10px;
-  height: 100%;
-  background-color: #F0F2F5;
-  position: relative;
-}
 
-.event-category {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
 
-  .el-select {
-    width: 250px;
-  }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
 }
 
-.eventStat-header {
-  display: flex;
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
 
-  .el-card {
-    flex: 1;
 
-    &:not(:first-child) {
-      margin-left: 10px;
-    }
-  }
-}
-</style>
+
+onMounted(() => {
+  getList();
+});
+</script>