Browse Source

feat: add export and self manage

hulinfei 1 year ago
parent
commit
cd2a339620

+ 55 - 0
src/api/unified.js

@@ -0,0 +1,55 @@
+import request from '@/utils/request.js'
+import {
+  add,
+  del,
+  update,
+  addTenant
+} from './base.js'
+
+export function addSelf (data) {
+  return add({
+    url: '/minio-data/manage/self/advertising/add',
+    method: 'POST',
+    data: addTenant(data)
+  })
+}
+
+export function getSelfByAdvertisingQuery (query) {
+  const { pageNum: pageIndex, pageSize, ...params } = query
+  return request({
+    url: '/minio-data/manage/self/advertising/pageQuery',
+    method: 'get',
+    params: {
+      pageIndex, pageSize,
+      ...params
+    }
+  })
+}
+
+export function updateSelf (data) {
+  return update({
+    url: '/minio-data/manage/self/advertising/update',
+    method: 'POST',
+    data
+  })
+}
+
+export function deleteSelf ({ id }) {
+  return del({
+    url: '/minio-data/manage/self/advertising/delete',
+    method: 'POST',
+    data: { ids: [id] }
+  })
+}
+
+export function uploadSelf (fromData, onUploadProgress) {
+  const tenant = addTenant()
+  fromData.append('tenant', tenant.tenant || '')
+  return add({
+    url: '/minio-data/manage/self/advertising/import',
+    method: 'POST',
+    data: fromData,
+    timeout: 0,
+    onUploadProgress
+  })
+}

+ 8 - 2
src/constant.js

@@ -523,7 +523,10 @@ export const AsyncTaskType = {
   SCREEN_ONLINE: 2,
   PEOPLE_COUNTING: 3,
   ONLINE_DURATION: 4,
-  ONLINE_DURATION_TOTAL: 5
+  ONLINE_DURATION_TOTAL: 5,
+  SELF_AD_PLAY: 20,
+  DEVICE_ONLINE: 21,
+  DEVICE_PLAY: 22
 }
 
 export const AsyncTaskTypeInfo = {
@@ -531,5 +534,8 @@ export const AsyncTaskTypeInfo = {
   [AsyncTaskType.SCREEN_ONLINE]: '大屏上下线记录',
   [AsyncTaskType.PEOPLE_COUNTING]: '人流量统计',
   [AsyncTaskType.ONLINE_DURATION]: '在线时长',
-  [AsyncTaskType.ONLINE_DURATION_TOTAL]: '总在线时长'
+  [AsyncTaskType.ONLINE_DURATION_TOTAL]: '总在线时长',
+  [AsyncTaskType.SELF_AD_PLAY]: '自营广告播放统计报表',
+  [AsyncTaskType.DEVICE_ONLINE]: '设备在线情况统计报表',
+  [AsyncTaskType.DEVICE_PLAY]: '设备播放时长统计报表'
 }

+ 12 - 0
src/router/index.js

@@ -515,6 +515,18 @@ export const asyncRoutes = [
       }
     ]
   },
+  {
+    path: '/un',
+    component: Layout,
+    meta: { icon: 'logger', title: '运营调度' },
+    children: [
+      {
+        path: 'self',
+        component: () => import('@/views/unified/self/index'),
+        meta: { title: '自营广告' }
+      }
+    ]
+  },
   {
     path: '/super',
     component: Layout,

+ 27 - 0
src/views/realm/report/api.js

@@ -177,6 +177,33 @@ export function addScreenBroadcastTask (data) {
   })
 }
 
+// 设备播放时长
+export function getDevicePlayTime (data) {
+  return send({
+    url: '/device/manage/play/statistics/export',
+    method: 'POST',
+    data: addTenant(data)
+  })
+}
+
+// 设备在线情况
+export function getDeviceOnlineInfo (data) {
+  return send({
+    url: '/device/manage/online/statistics/export',
+    method: 'POST',
+    data: addTenant(data)
+  })
+}
+
+// 自营广告播放
+export function getSelfPlay (params) {
+  return send({
+    url: '/minio-data/manage/self/play/export',
+    method: 'GET',
+    params: addTenant(params)
+  })
+}
+
 export function getServerAsyncTasks (query) {
   const { pageNum: pageIndex, pageSize, ...params } = query
   return request({

+ 84 - 0
src/views/realm/report/components/DeviceOnlineInfoDialog.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 { getDeviceOnlineInfo } from '../api.js'
+
+export default {
+  name: 'ScreenOnlineDialog',
+  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
+      }
+      getDeviceOnlineInfo({
+        deviceIdList: this.devices,
+        startDate: this.dateRange[0],
+        endDate: this.dateRange[1]
+      }).then(({ data: { type } }) => {
+        this.$emit('added', type)
+        done()
+      })
+    }
+  }
+}
+</script>

+ 100 - 0
src/views/realm/report/components/DevicePlayTimeDialog.vue

@@ -0,0 +1,100 @@
+<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 class="c-sibling-item--v u-required">
+            统计类型
+          </div>
+          <el-radio-group
+            v-model="radio"
+            class="c-sibling-item--v"
+          >
+            <el-radio :label="0">
+              按设备统计
+            </el-radio>
+            <el-radio :label="1">
+              按设备分组统计
+            </el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+    </template>
+  </confirm-dialog>
+</template>
+
+<script>
+import { parseTime } from '@/utils'
+import { getDevicePlayTime } from '../api.js'
+
+export default {
+  name: 'ScreenOnlineDialog',
+  data () {
+    return {
+      dateRange: null,
+      devices: [],
+      radio: 0
+    }
+  },
+  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
+      }
+      getDevicePlayTime({
+        deviceIdList: this.devices,
+        startDate: this.dateRange[0],
+        endDate: this.dateRange[1],
+        statisticsType: this.radio
+      }).then(({ data: { type } }) => {
+        this.$emit('added', type)
+        done()
+      })
+    }
+  }
+}
+</script>

+ 65 - 0
src/views/realm/report/components/SelfPlayDialog.vue

@@ -0,0 +1,65 @@
+<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 { getSelfPlay } from '../api.js'
+
+export default {
+  name: 'ContentDialog',
+  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() + 1)
+      getSelfPlay({
+        startDate: this.dateRange[0],
+        endDate: parseTime(endDate, '{y}-{m}-{d}')
+      }, time).then(({ data: { type } }) => {
+        this.$emit('added', type)
+        done()
+      })
+    }
+  }
+}
+</script>

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

@@ -119,6 +119,29 @@
         人流量统计
       </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="getDevicePlayTime"
+      >
+        设备播放时长
+      </button>
+      <button
+        class="o-button"
+        @click="getDeviceOnlineInfo"
+      >
+        设备在线情况
+      </button>
+      <button
+        class="o-button"
+        @click="getSelfPlay"
+      >
+        自营广告播放
+      </button>
+    </div>
     <div class="c-sibling-item--v u-font-size--sm u-bold">
       任务
     </div>
@@ -156,6 +179,18 @@
     <server-async-task-dialog ref="serverAsyncTaskDialog" />
     <device-status-dialog ref="deviceStatusDialog" />
     <device-warn-dialog ref="deviceWarnDialog" />
+    <device-play-time-dialog
+      ref="devicePlayTimeDialog"
+      @added="showServerAsyncTask"
+    />
+    <device-online-info-dialog
+      ref="deviceOnlineInfoDialog"
+      @added="showServerAsyncTask"
+    />
+    <self-play-dialog
+      ref="selfPlayDialog"
+      @added="showServerAsyncTask"
+    />
   </wrapper>
 </template>
 
@@ -179,6 +214,9 @@ import ScreenBroadcastDialog from './components/ScreenBroadcastDialog.vue'
 import ServerAsyncTaskDialog from './components/ServerAsyncTaskDialog.vue'
 import DeviceStatusDialog from './components/DeviceStatusDialog.vue'
 import DeviceWarnDialog from './components/DeviceWarnDialog.vue'
+import DevicePlayTimeDialog from './components/DevicePlayTimeDialog.vue'
+import DeviceOnlineInfoDialog from './components/DeviceOnlineInfoDialog.vue'
+import SelfPlayDialog from './components/SelfPlayDialog.vue'
 
 export default {
   name: 'Report',
@@ -196,7 +234,10 @@ export default {
     ScreenBroadcastDialog,
     ServerAsyncTaskDialog,
     DeviceStatusDialog,
-    DeviceWarnDialog
+    DeviceWarnDialog,
+    DevicePlayTimeDialog,
+    DeviceOnlineInfoDialog,
+    SelfPlayDialog
   },
   computed: {
     ...mapGetters(['isGroupAdmin', 'isTopGroup'])
@@ -251,6 +292,15 @@ export default {
     },
     getDeviceWarnExcel () {
       this.$refs.deviceWarnDialog.show()
+    },
+    getDevicePlayTime () {
+      this.$refs.devicePlayTimeDialog.show()
+    },
+    getDeviceOnlineInfo () {
+      this.$refs.deviceOnlineInfoDialog.show()
+    },
+    getSelfPlay () {
+      this.$refs.selfPlayDialog.show()
     }
   }
 }

+ 253 - 0
src/views/unified/self/index.vue

@@ -0,0 +1,253 @@
+<template>
+  <wrapper
+    fill
+    margin
+    padding
+    background
+  >
+    <schema-table
+      ref="table"
+      :schema="schema"
+    />
+    <confirm-dialog
+      ref="editDialog"
+      :title="isEdit ? '编辑' : '新增'"
+      @confirm="onSave"
+    >
+      <div class="c-grid-form u-align-self--center">
+        <span class="c-grid-form__label u-required">
+          名称
+        </span>
+        <el-input
+          v-model.trim="selfFrom.name"
+          placeholder="最多30个字符"
+          maxlength="30"
+          clearable
+        />
+        <span class="c-grid-form__label">
+          备注
+        </span>
+        <el-input
+          v-model.trim="selfFrom.remark"
+          type="textarea"
+          maxlength="100"
+          :rows="4"
+          resize="none"
+          show-word-limit
+        />
+      </div>
+    </confirm-dialog>
+    <confirm-dialog
+      ref="uploadDialog"
+      title="新增导入文件"
+      @confirm="onUpload"
+    >
+      <el-upload
+        ref="upload"
+        class="o-upload l-flex__auto"
+        action="none"
+        :auto-upload="false"
+        :show-file-list="false"
+        :on-change="onChange"
+        accept=".xlsx"
+        drag
+      >
+        <div class="l-flex--row">
+          <i class="o-upload__icon el-icon-upload" />
+          <template v-if="upload.file">
+            <div class="u-color--blue">
+              {{ upload.file.name }}
+            </div>
+          </template>
+          <template v-else>
+            <span class="c-sibling-item">
+              拖拽文件到此或
+            </span>
+            <span class="c-sibling-item near u-color--blue">
+              点击选择文件
+            </span>
+          </template>
+        </div>
+      </el-upload>
+    </confirm-dialog>
+    <el-dialog
+      :visible.sync="showProgress"
+      custom-class="c-dialog--transparent"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-progress
+        class="u-align-self--stretch"
+        :percentage="progress"
+        :stroke-width="24"
+        text-inside
+        status="success"
+      />
+    </el-dialog>
+  </wrapper>
+</template>
+
+<script>
+import {
+  getSelfByAdvertisingQuery,
+  addSelf,
+  updateSelf,
+  deleteSelf,
+  uploadSelf
+} from '@/api/unified.js'
+
+export default {
+  data () {
+    return {
+      upload: {},
+      showProgress: false,
+      progress: 0,
+      selfFrom: {},
+      isEdit: false
+    }
+  },
+  computed: {
+    schema () {
+      return {
+        props: {
+          size: 'small'
+        },
+        list: getSelfByAdvertisingQuery,
+        buttons: [
+          { type: 'add', on: this.onAdd },
+          { type: 'add', label: '上传', on: this.uploadStreamingMedia }
+        ],
+        filters: [
+          { key: 'name', type: 'search', placeholder: '广告名称' },
+          { type: 'refresh' }
+        ],
+        cols: [
+          { prop: 'name', label: '广告名称' },
+          {
+            prop: 'status',
+            label: '状态',
+            render: (data, h) => h('el-switch', {
+              props: {
+                value: data.status,
+                size: 'mini',
+                'active-value': 1,
+                'active-color': '#13ce66',
+                'inactive-value': 0,
+                'inactive-color': '#ff4949'
+              },
+              // nativeOn: {
+              //   click: e => e.stopPropagation()
+              // },
+              nativeOn: {
+                click: val => {
+                  this.onStatus(data, val)
+                }
+              }
+            }),
+            width: 72,
+            align: 'center'
+          },
+          { prop: 'remark', label: '备注' },
+          {
+            type: 'invoke',
+            render: [
+              { label: '编辑', on: this.onView },
+              { label: '删除', on: this.onDel }
+            ],
+            width: 100
+          }
+        ]
+      }
+    }
+  },
+  methods: {
+    onStatus (asset) {
+      updateSelf({
+        id: asset.id,
+        name: asset.name,
+        remark: asset.remark,
+        status: asset.status === 1 ? 0 : 1
+      })
+        .then(() => {
+          asset.status = asset.status === 1 ? 0 : 1
+        })
+        .catch(() => {})
+    },
+    onAdd () {
+      this.isEdit = false
+      this.selfFrom = {
+        name: '',
+        remark: ''
+      }
+      this.$refs.editDialog.show()
+    },
+    onView (asset) {
+      this.isEdit = true
+      this.selfFrom = {
+        id: asset.id,
+        name: asset.name,
+        remark: asset.remark
+      }
+      this.$refs.editDialog.show()
+    },
+    onSave (done) {
+      const { name } = this.selfFrom
+      if (!name) {
+        this.$message({
+          type: 'warning',
+          message: '请填写广告名称'
+        })
+        return
+      }
+      (this.isEdit ? updateSelf : addSelf)(this.selfFrom).then(() => {
+        done()
+        this.$refs.table.pageTo(1)
+      })
+    },
+    onDel (asset) {
+      deleteSelf(asset).then(() => {
+        this.$refs.table.decrease(1)
+      })
+    },
+    uploadStreamingMedia () {
+      this.upload = {
+        file: null
+      }
+      this.$refs.uploadDialog.show()
+    },
+    onUpload (done) {
+      if (!this.upload.file) {
+        this.$message({
+          type: 'warning',
+          message: '请选择上传文件'
+        })
+        return
+      }
+      const formData = new FormData()
+      const { file } = this.upload
+      console.log(file)
+      formData.append('upload-file', file)
+      this.progress = 0
+      this.showProgress = true
+      uploadSelf(formData, ({ loaded, total }) => {
+        this.progress = Math.min(99, ((loaded * 100) / total) | 0)
+      })
+        .finally(() => {
+          this.progress = 100
+          this.showProgress = false
+        })
+        .then(() => {
+          done()
+          this.$refs.table.resetCondition()
+        })
+    },
+    onChange ({ raw }) {
+      this.$refs.upload.clearFiles()
+      this.upload.file = raw
+    },
+    onAdded (streamingMedia) {
+      this.$refs.table.resetCondition(streamingMedia)
+    }
+  }
+}
+</script>