Browse Source

feat(report): screen broadcast, screen online and people couting

Casper Dai 1 year ago
parent
commit
02aed8c84a

+ 49 - 1
src/views/realm/report/api.js

@@ -1,5 +1,5 @@
 import { parseTime } from '@/utils'
-import { downloadRequest } from '@/utils/request.js'
+import request, { downloadRequest } from '@/utils/request.js'
 import {
   send,
   addTenant
@@ -137,3 +137,51 @@ export function getDepartmentRangeOnlineDurationExcel (data, fileName = '') {
     download(response, `在线时长${parseTime(new Date(), '{y}{m}{d}{h}{i}{s}')}_${fileName}.xlsx`)
   })
 }
+
+// 人流量统计
+export function getPeopleCoutingExcel (data) {
+  return send({
+    url: '/camera/statistic/export',
+    method: 'POST',
+    data
+  }, downloadRequest).then(response => {
+    const startDateParts = data.startDate.split('-')
+    const endDateParts = data.endDate.split('-')
+    const fileName = data.startDate === data.endDate
+      ? `人流量统计${`${startDateParts[0]}年${startDateParts[1]}月${startDateParts[2]}日`}.xlsx`
+      : `人流量统计${`${startDateParts[0]}年${startDateParts[1]}月${startDateParts[2]}日`}-${`${endDateParts[0]}年${endDateParts[1]}月${endDateParts[2]}日`}.xlsx`
+    download(response, fileName)
+  })
+}
+
+// 大屏上下线记录
+export function getScreenOnlineExcel (data) {
+  return send({
+    url: '/device/screen/online/export',
+    method: 'POST',
+    data
+  }, downloadRequest).then(response => {
+    download(response, `${data.startDate}-${data.endDate}_大屏终端上下线记录.xlsx`)
+  })
+}
+
+// 大屏播出单
+export function addScreenBroadcastTask (data) {
+  return send({
+    url: '/device/screen/record/export',
+    method: 'POST',
+    data
+  })
+}
+
+export function getServerAsyncTasks (query) {
+  const { pageNum: pageIndex, pageSize, ...params } = query
+  return request({
+    url: '/device/async-task/page',
+    method: 'POST',
+    data: ({
+      pageIndex, pageSize,
+      ...params
+    })
+  })
+}

+ 2 - 1
src/views/realm/report/components/AccountDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="部门账号报表"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -22,7 +23,7 @@
 </template>
 
 <script>
-import { getAccountExcel } from '../api'
+import { getAccountExcel } from '../api.js'
 
 export default {
   name: 'AccountDialog',

+ 7 - 7
src/views/realm/report/components/AuditDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="部门三审报表"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -12,7 +13,9 @@
           @change="onGroupChanged"
         />
         <div class="c-sibling-item far">
-          <div class="c-sibling-item--v u-required">日期范围</div>
+          <div class="c-sibling-item--v u-required">
+            日期范围
+          </div>
           <el-date-picker
             v-model="dateRange"
             class="c-sibling-item--v"
@@ -31,19 +34,19 @@
 
 <script>
 import { parseTime } from '@/utils'
-import { getAuditExcel } from '../api'
+import { getAuditExcel } from '../api.js'
 
 export default {
   name: 'AuditDialog',
   data () {
     return {
-      dateRange: []
+      dateRange: null
     }
   },
   computed: {
     pickerOptions () {
       return {
-        disabledDate: this.isDisableDate
+        disabledDate: date => date > Date.now()
       }
     }
   },
@@ -56,9 +59,6 @@ export default {
     onGroupChanged (group) {
       this.$group = group
     },
-    isDisableDate (date) {
-      return date > Date.now()
-    },
     onConfirm (done) {
       const time = this.dateRange[0] === this.dateRange[1] ? this.dateRange[0] : `${this.dateRange[0]}~${this.dateRange[1]}`
       getAuditExcel({

+ 7 - 7
src/views/realm/report/components/ContentDialog.vue

@@ -2,11 +2,14 @@
   <confirm-dialog
     ref="dialog"
     title="平台内容播放"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
       <div class="c-grid-form auto u-align-self--center">
-        <div class="c-grid-form__label u-required">日期范围</div>
+        <div class="c-grid-form__label u-required">
+          日期范围
+        </div>
         <el-date-picker
           v-model="dateRange"
           type="daterange"
@@ -23,19 +26,19 @@
 
 <script>
 import { parseTime } from '@/utils'
-import { getContentExcel } from '../api'
+import { getContentExcel } from '../api.js'
 
 export default {
   name: 'ContentDialog',
   data () {
     return {
-      dateRange: []
+      dateRange: null
     }
   },
   computed: {
     pickerOptions () {
       return {
-        disabledDate: this.isDisableDate
+        disabledDate: date => date > Date.now()
       }
     }
   },
@@ -45,9 +48,6 @@ export default {
       this.dateRange = [date, date]
       this.$refs.dialog.show()
     },
-    isDisableDate (date) {
-      return date > Date.now()
-    },
     onConfirm (done) {
       const time = this.dateRange[0] === this.dateRange[1] ? this.dateRange[0] : `${this.dateRange[0]}~${this.dateRange[1]}`
       const endDate = new Date(this.dateRange[1].replace(/-/g, '/'))

+ 6 - 6
src/views/realm/report/components/DeviceAdDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="设备广告播放"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -13,7 +14,9 @@
           @node-click="onDeviceChange"
         />
         <div class="c-sibling-item far">
-          <div class="c-sibling-item--v u-required">日期</div>
+          <div class="c-sibling-item--v u-required">
+            日期
+          </div>
           <el-date-picker
             v-model="date"
             class="c-sibling-item--v"
@@ -31,7 +34,7 @@
 
 <script>
 import { parseTime } from '@/utils'
-import { getDeviceAdExcel } from '../api'
+import { getDeviceAdExcel } from '../api.js'
 
 export default {
   name: 'DeviceAdDialog',
@@ -43,7 +46,7 @@ export default {
   computed: {
     pickerOptions () {
       return {
-        disabledDate: this.isDisableDate
+        disabledDate: date => date > Date.now()
       }
     }
   },
@@ -56,9 +59,6 @@ export default {
     onDeviceChange (device) {
       this.$device = device
     },
-    isDisableDate (date) {
-      return date > Date.now()
-    },
     onConfirm (done) {
       if (!this.$device) {
         this.$message({

+ 2 - 1
src/views/realm/report/components/MaterialConfigDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="部门资源报表"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -22,7 +23,7 @@
 </template>
 
 <script>
-import { getMaterialExcel } from '../api'
+import { getMaterialExcel } from '../api.js'
 
 export default {
   name: 'MaterialConfigDialog',

+ 10 - 8
src/views/realm/report/components/OnlineDurationDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="在线时长报表"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -12,13 +13,17 @@
           @change="onGroupChanged"
         />
         <div class="c-sibling-item far">
-          <div class="c-sibling-item--v u-required">日期范围</div>
+          <div class="c-sibling-item--v">
+            日期范围
+          </div>
           <el-date-picker
             v-model="dateRange"
             class="c-sibling-item--v"
             type="daterange"
             range-separator="至"
             value-format="yyyy-MM-dd"
+            start-placeholde="开始时间"
+            end-placeholde="结束时间"
             :picker-options="pickerOptions"
             :editable="false"
           />
@@ -30,27 +35,27 @@
 
 <script>
 import { mapGetters } from 'vuex'
-import { ONE_DAY } from '@/constant'
+import { ONE_DAY } from '@/constant.js'
 import { parseTime } from '@/utils'
 import {
   getOnlineDurationExcel,
   getRangeOnlineDurationExcel,
   getDepartmentOnlineDurationExcel,
   getDepartmentRangeOnlineDurationExcel
-} from '../api'
+} from '../api.js'
 
 export default {
   name: 'OnlineDurationDialog',
   data () {
     return {
-      dateRange: []
+      dateRange: null
     }
   },
   computed: {
     ...mapGetters(['tenant']),
     pickerOptions () {
       return {
-        disabledDate: this.isDisableDate
+        disabledDate: date => date > Date.now()
       }
     }
   },
@@ -63,9 +68,6 @@ export default {
     onGroupChanged (group) {
       this.$group = group
     },
-    isDisableDate (date) {
-      return date > Date.now()
-    },
     onConfirm (done) {
       const groupPath = this.$group.path
       if (this.dateRange) {

+ 62 - 0
src/views/realm/report/components/PeopleCountingDialog.vue

@@ -0,0 +1,62 @@
+<template>
+  <confirm-dialog
+    ref="dialog"
+    title="人流量统计"
+    confirm-text="下载"
+    @confirm="onConfirm"
+  >
+    <template #default>
+      <div class="c-grid-form auto u-align-self--center">
+        <div class="c-grid-form__label u-required">
+          日期范围
+        </div>
+        <el-date-picker
+          v-model="dateRange"
+          type="daterange"
+          range-separator="至"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions"
+          :editable="false"
+          :clearable="false"
+        />
+      </div>
+    </template>
+  </confirm-dialog>
+</template>
+
+<script>
+import { parseTime } from '@/utils'
+import { getPeopleCoutingExcel } from '../api.js'
+
+export default {
+  name: 'PeopleCoutingDialog',
+  data () {
+    return {
+      dateRange: null
+    }
+  },
+  computed: {
+    pickerOptions () {
+      return {
+        disabledDate: date => date > Date.now()
+      }
+    }
+  },
+  methods: {
+    show () {
+      const date = parseTime(new Date(), '{y}-{m}-{d}')
+      this.dateRange = [date, date]
+      this.$refs.dialog.show()
+    },
+    onConfirm (done) {
+      const time = this.dateRange[0] === this.dateRange[1] ? this.dateRange[0] : `${this.dateRange[0]}~${this.dateRange[1]}`
+      const endDate = new Date(this.dateRange[1].replace(/-/g, '/'))
+      endDate.setDate(endDate.getDate())
+      getPeopleCoutingExcel({
+        startDate: this.dateRange[0],
+        endDate: parseTime(endDate, '{y}-{m}-{d}')
+      }, time).then(done)
+    }
+  }
+}
+</script>

+ 10 - 8
src/views/realm/report/components/ProgramGuideDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="设备节目单"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -14,16 +15,16 @@
         />
         <div class="c-sibling-item far">
           <div class="c-sibling-item--v u-required">
-            日期
+            日期范围
           </div>
           <el-date-picker
-            v-model="date"
+            v-model="dateRange"
             class="c-sibling-item--v"
             type="daterange"
             value-format="yyyy-MM-dd"
             range-separator="至"
-            start-placeholder="开始日期"
-            end-placeholder="结束日期"
+            :editable="false"
+            :clearable="false"
           />
         </div>
       </div>
@@ -39,14 +40,15 @@ export default {
   name: 'ProgramGuideDialog',
   data () {
     return {
-      date: null,
+      dateRange: null,
       devices: []
     }
   },
   methods: {
     show () {
       this.devices = null
-      this.date = parseTime(new Date(), '{y}-{m}-{d}')
+      const date = parseTime(new Date(), '{y}-{m}-{d}')
+      this.dateRange = [date, date]
       this.$refs.dialog.show()
     },
     onChange (devices) {
@@ -62,8 +64,8 @@ export default {
       }
       getProgramGuideExcel({
         deviceIdList: this.devices,
-        startDate: this.date[0],
-        endDate: this.date[1]
+        startDate: this.dateRange[0],
+        endDate: this.dateRange[1]
       }).then(done)
     }
   }

+ 12 - 16
src/views/realm/report/components/ProgramPlaysDialog.vue

@@ -3,6 +3,7 @@
     ref="dialog"
     size="lg fixed"
     title="设备播放单"
+    confirm-text="下载"
     @confirm="onConfirm"
   >
     <template #default>
@@ -14,15 +15,14 @@
         />
         <div class="c-sibling-item far">
           <div class="c-sibling-item--v u-required">
-            日期
+            时间范围
           </div>
           <el-date-picker
-            v-model="date"
+            v-model="dateRange"
             class="c-sibling-item--v"
             type="datetimerange"
+            value-format="yyyy/MM/dd HH:mm:ss"
             range-separator="至"
-            start-placeholder="开始日期"
-            end-placeholder="结束日期"
             :default-time="['00:00:00', '23:59:59']"
           />
         </div>
@@ -39,27 +39,23 @@ export default {
   name: 'ProgramPlaysDialog',
   data () {
     return {
-      date: null,
+      dateRange: null,
       devices: []
     }
   },
   methods: {
     show () {
       this.devices = null
-      const currentDate = new Date()
-      const startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), 0, 0, 0)
-      const endDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), 23, 59, 59)
-      const formattedStartDate = parseTime(startDate, '{y}-{m}-{d} {h}:{i}:{s}')
-      const formattedEndDate = parseTime(endDate, '{y}-{m}-{d} {h}:{i}:{s}')
-      this.date = [formattedStartDate, formattedEndDate]
+      const date = parseTime(new Date(), '{y}/{m}/{d}')
+      this.dateRange = [
+        `${date} 00:00:00`,
+        `${date} 23:59:59`
+      ]
       this.$refs.dialog.show()
     },
     onChange (devices) {
       this.devices = devices.map(device => device.id)
     },
-    isDisableDate (date) {
-      return date > Date.now()
-    },
     onConfirm (done) {
       if (!this.devices || !this.devices.length) {
         this.$message({
@@ -70,8 +66,8 @@ export default {
       }
       getProgramPlaysExcel({
         deviceIdList: this.devices,
-        start: new Date(this.date[0]).getTime(),
-        util: new Date(this.date[1]).getTime()
+        start: new Date(this.dateRange[0]).getTime(),
+        util: new Date(this.dateRange[1]).getTime()
       }).then(done)
     }
   }

+ 84 - 0
src/views/realm/report/components/ScreenBroadcastDialog.vue

@@ -0,0 +1,84 @@
+<template>
+  <confirm-dialog
+    ref="dialog"
+    size="lg fixed"
+    title="大屏播出单"
+    confirm-text="添加任务"
+    @confirm="onConfirm"
+  >
+    <template #default>
+      <div class="l-flex__fill l-flex">
+        <device-tree
+          class="c-sibling-item c-sidebar u-width--xl"
+          checkbox
+          @change="onChange"
+        />
+        <div class="c-sibling-item far">
+          <div class="c-sibling-item--v u-required">
+            日期范围
+          </div>
+          <el-date-picker
+            v-model="dateRange"
+            class="c-sibling-item--v"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            range-separator="至"
+            :picker-options="pickerOptions"
+            :editable="false"
+            :clearable="false"
+          />
+        </div>
+      </div>
+    </template>
+  </confirm-dialog>
+</template>
+
+<script>
+import { parseTime } from '@/utils'
+import { addScreenBroadcastTask } from '../api.js'
+
+export default {
+  name: 'ScreenBroadcastDialog',
+  data () {
+    return {
+      dateRange: null,
+      devices: []
+    }
+  },
+  computed: {
+    pickerOptions () {
+      return {
+        disabledDate: date => date > Date.now()
+      }
+    }
+  },
+  methods: {
+    show () {
+      this.devices = null
+      const date = parseTime(new Date(), '{y}-{m}-{d}')
+      this.dateRange = [date, date]
+      this.$refs.dialog.show()
+    },
+    onChange (devices) {
+      this.devices = devices.map(device => device.id)
+    },
+    onConfirm (done) {
+      if (!this.devices || !this.devices.length) {
+        this.$message({
+          type: 'warning',
+          message: '请选择设备'
+        })
+        return
+      }
+      addScreenBroadcastTask({
+        deviceIdList: this.devices,
+        startDate: this.dateRange[0],
+        endDate: this.dateRange[1]
+      }).then(() => {
+        this.$emit('added')
+        done()
+      })
+    }
+  }
+}
+</script>

+ 81 - 0
src/views/realm/report/components/ScreenOnlineDialog.vue

@@ -0,0 +1,81 @@
+<template>
+  <confirm-dialog
+    ref="dialog"
+    size="lg fixed"
+    title="大屏上下线记录"
+    confirm-text="下载"
+    @confirm="onConfirm"
+  >
+    <template #default>
+      <div class="l-flex__fill l-flex">
+        <device-tree
+          class="c-sibling-item c-sidebar u-width--xl"
+          checkbox
+          @change="onChange"
+        />
+        <div class="c-sibling-item far">
+          <div class="c-sibling-item--v u-required">
+            日期范围
+          </div>
+          <el-date-picker
+            v-model="dateRange"
+            class="c-sibling-item--v"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            range-separator="至"
+            :picker-options="pickerOptions"
+            :editable="false"
+            :clearable="false"
+          />
+        </div>
+      </div>
+    </template>
+  </confirm-dialog>
+</template>
+
+<script>
+import { parseTime } from '@/utils'
+import { getScreenOnlineExcel } from '../api.js'
+
+export default {
+  name: 'ScreenOnlineDialog',
+  data () {
+    return {
+      date: null,
+      devices: []
+    }
+  },
+  computed: {
+    pickerOptions () {
+      return {
+        disabledDate: date => date > Date.now()
+      }
+    }
+  },
+  methods: {
+    show () {
+      this.devices = null
+      const date = parseTime(new Date(), '{y}-{m}-{d}')
+      this.dateRange = [date, date]
+      this.$refs.dialog.show()
+    },
+    onChange (devices) {
+      this.devices = devices.map(device => device.id)
+    },
+    onConfirm (done) {
+      if (!this.devices || !this.devices.length) {
+        this.$message({
+          type: 'warning',
+          message: '请选择设备'
+        })
+        return
+      }
+      getScreenOnlineExcel({
+        deviceIdList: this.devices,
+        startDate: this.dateRange[0],
+        endDate: this.dateRange[1]
+      }).then(done)
+    }
+  }
+}
+</script>

+ 59 - 0
src/views/realm/report/components/ServerAsyncTaskDialog.vue

@@ -0,0 +1,59 @@
+<template>
+  <table-dialog
+    ref="dialog"
+    size="lg fixed"
+    title="任务列表"
+    :schema="schema"
+  />
+</template>
+
+<script>
+import { AppletOrderType } from '@/constant.js'
+import { getServerAsyncTasks } from '../api.js'
+
+const TypeInfo = {
+  [AppletOrderType.PACKAGE]: '大屏播出单',
+  [AppletOrderType.SOON]: '大屏上下线记录',
+  [AppletOrderType.DAILY]: '人流量统计'
+}
+
+export default {
+  name: 'ServerAsyncTaskDialog',
+  data () {
+    return {
+      schema: {
+        list: getServerAsyncTasks,
+        autoRefreshEachPage: true,
+        refreshInterval: 5000,
+        cols: [
+          { label: '任务类型', render: ({ type }) => TypeInfo[type] },
+          { prop: 'createTime', label: '创建时间' },
+          { type: 'tag', render: ({ status }) => {
+            return {
+              type: ['primary', 'success', 'danger'][status],
+              label: ['进行中', '已完成', '下载失败'][status]
+            }
+          } },
+          { type: 'invoke', render: [
+            { label: '下载报表', allow: ({ status }) => status !== 0 && status !== 2, on: this.onDownload }
+          ], width: 160 }
+        ]
+      }
+    }
+  },
+  methods: {
+    show () {
+      this.$refs.dialog.show()
+    },
+    onDownload ({ downloadUrl }) {
+      const url = `${process.env.VUE_APP_MINIO}/${downloadUrl}`
+      const dom = document.createElement('a')
+      dom.href = url
+      dom.style.display = 'none'
+      document.body.appendChild(dom)
+      dom.click()
+      dom.parentNode.removeChild(dom)
+    }
+  }
+}
+</script>

+ 62 - 1
src/views/realm/report/index.vue

@@ -84,6 +84,40 @@
         播放清单
       </button>
     </div>
+    <div class="c-sibling-item--v u-font-size--sm u-bold">
+      考核报表
+    </div>
+    <div class="c-sibling-item--v near l-grid--info mini">
+      <button
+        class="o-button"
+        @click="addScreenBroadcastTask"
+      >
+        大屏播出单
+      </button>
+      <button
+        class="o-button"
+        @click="getScreenOnlineExcel"
+      >
+        大屏上下线记录
+      </button>
+      <button
+        class="o-button"
+        @click="getPeopleCoutingExcel"
+      >
+        人流量统计
+      </button>
+    </div>
+    <div class="c-sibling-item--v u-font-size--sm u-bold">
+      任务
+    </div>
+    <div class="c-sibling-item--v near l-grid--info mini">
+      <button
+        class="o-button"
+        @click="showServerAsyncTask"
+      >
+        查看任务进度/下载报表
+      </button>
+    </div>
     <material-config-dialog ref="materialConfigDialog" />
     <account-dialog ref="accountDialog" />
     <audit-dialog ref="auditDialog" />
@@ -92,6 +126,13 @@
     <device-ad-dialog ref="deviceAdDialog" />
     <program-plays-dialog ref="programPlaysDialog" />
     <online-duration-dialog ref="onlineDurationDialog" />
+    <people-counting-dialog ref="peopleCountingDialog" />
+    <screen-online-dialog ref="screenOnlineDialogDialog" />
+    <screen-broadcast-dialog
+      ref="screenBroadcastDialog"
+      @added="showServerAsyncTask"
+    />
+    <server-async-task-dialog ref="serverAsyncTaskDialog" />
   </wrapper>
 </template>
 
@@ -109,6 +150,10 @@ import ProgramGuideDialog from './components/ProgramGuideDialog.vue'
 import DeviceAdDialog from './components/DeviceAdDialog.vue'
 import ProgramPlaysDialog from './components/ProgramPlaysDialog.vue'
 import OnlineDurationDialog from './components/OnlineDurationDialog.vue'
+import PeopleCountingDialog from './components/PeopleCountingDialog.vue'
+import ScreenOnlineDialog from './components/ScreenOnlineDialog.vue'
+import ScreenBroadcastDialog from './components/ScreenBroadcastDialog.vue'
+import ServerAsyncTaskDialog from './components/ServerAsyncTaskDialog.vue'
 
 export default {
   name: 'Report',
@@ -120,7 +165,11 @@ export default {
     ProgramGuideDialog,
     DeviceAdDialog,
     OnlineDurationDialog,
-    ProgramPlaysDialog
+    ProgramPlaysDialog,
+    PeopleCountingDialog,
+    ScreenOnlineDialog,
+    ScreenBroadcastDialog,
+    ServerAsyncTaskDialog
   },
   computed: {
     ...mapGetters(['isGroupAdmin', 'isTopGroup'])
@@ -160,6 +209,18 @@ export default {
     },
     getDepartmentOnlineDurationExcel () {
       this.$refs.onlineDurationDialog.show()
+    },
+    getPeopleCoutingExcel () {
+      this.$refs.peopleCountingDialog.show()
+    },
+    getScreenOnlineExcel () {
+      this.$refs.screenOnlineDialogDialog.show()
+    },
+    addScreenBroadcastTask () {
+      this.$refs.screenBroadcastDialog.show()
+    },
+    showServerAsyncTask () {
+      this.$refs.serverAsyncTaskDialog.show()
     }
   }
 }