Browse Source

change dashboard

tags/v1.0.0^2
zhangtao 2 years ago
parent
commit
77da002b55
14 changed files with 290 additions and 120 deletions
  1. +13
    -1
      src/api/report/index.js
  2. +7
    -0
      src/api/task/index.js
  3. +0
    -0
      src/assets/images/lose-control.png
  4. +0
    -0
      src/assets/images/no-live.png
  5. +20
    -4
      src/components/Search/index.vue
  6. +19
    -5
      src/components/VideoPlayer/index.vue
  7. +3
    -1
      src/utils/handleData.js
  8. +41
    -10
      src/views/dashboard/components/AirCard.vue
  9. +32
    -4
      src/views/dashboard/components/VideoCard.vue
  10. +35
    -24
      src/views/report-manage/all-report/components/ReportDrawer.vue
  11. +2
    -0
      src/views/task-manage/all-task/components/TaskModal.vue
  12. +25
    -6
      src/views/task-manage/all-task/index.vue
  13. +74
    -62
      src/views/task-manage/all-task/tools/search.js
  14. +19
    -3
      src/views/task-manage/question/index.vue

+ 13
- 1
src/api/report/index.js View File

@@ -15,7 +15,7 @@ export function getReportList(params) {

/**
* @description: 获取报告详情
* @param {*} params
* @param {*} id
* @return {*}
*/
export function getReportDetail(id) {
@@ -25,3 +25,15 @@ export function getReportDetail(id) {
})
}

/**
* @description: 下载报告
* @param {*} id
* @return {*}
*/
export function reportDownload(id) {
return request({
url: `report/${id}/word`,
method: 'GET'
})
}


+ 7
- 0
src/api/task/index.js View File

@@ -96,3 +96,10 @@ export function generateReport(id) {
method: 'POST'
})
}

export function questionAnalyze(id) {
return request({
url: `/question/analyze/${id}`,
method: 'GET'
})
}

src/assets/images/icon-zanwuxinhao-60.png → src/assets/images/lose-control.png View File


src/assets/images/icon-zanwuzhibo-60.png → src/assets/images/no-live.png View File


+ 20
- 4
src/components/Search/index.vue View File

@@ -36,7 +36,7 @@ export default {
default: () => []
}
},
emits: ['search', 'reset'],
emits: ['search', 'change', 'reset'],
setup(props, { emit }) {
const showItemNum = ref(30)
const len = ref(props.info.length - 1)
@@ -53,6 +53,7 @@ export default {
item.clearValue()
})
}
/* 地图选择事件 */
function handleSelect(data) {
form.value = {
...form.value,
@@ -61,6 +62,9 @@ export default {
}
const getFormOptions = computed(() => {
props.info.forEach((item) => {
// const hasInit = item.init || false
// const hasKey = Object.keys(form.value).includes(item.key)
// form.value[item.key] = hasInit ? (item.value || null) : hasKey ? form.value[item.key] : (item.value || null)
form.value[item.key] = item.value || null
})
return {
@@ -71,17 +75,28 @@ export default {
info: [...props.info]
}
})
watch(() => props.info, (value) => {
console.log(value)
})

watch(getFormOptions.value.form,
(value) => {
emit('change', getFormOptions.value.form)
})

function handleSearch() {
emit('search', getFormOptions.value.form)
}

function handleReset() {
initForm()
emit('reset', getFormOptions.value.form)
}

function setFormValue(params) {
Object.keys(params).forEach((key) => {
const index = unref(props).info.findIndex((item) => item.key === key)
form.value[key] = (props).info[index].value || null
})
}

function showMoreItem() {
showItemNum.value = showItemNum.value === len.value ? 3 : len.value
}
@@ -91,6 +106,7 @@ export default {
getFormOptions,
handleSearch,
handleReset,
setFormValue,
handleSelect,
itemRefs,
showMoreItem

+ 19
- 5
src/components/VideoPlayer/index.vue View File

@@ -1,10 +1,13 @@
<template>
<div :id="getPlayerId" />
<div v-if="isFailed">
<slot name="empty" />
</div>
<div v-else :id="getPlayerId" />
</template>

<script>

import { ref, computed, watch, onMounted, defineComponent } from 'vue'
import { defineComponent, ref, computed, watch, onMounted, nextTick } from 'vue'
export default defineComponent({
name: 'VideoPlayer',
props: {
@@ -15,9 +18,10 @@ export default defineComponent({
},
emits: ['timeUpdate', 'video-status'],
setup(props, { emit }) {
const videoPlayer = ref()
const videoPlayer = ref(null)
const hasInit = ref(false)
const isSeek = ref(false)
const isFailed = ref(false)
const toolComponent = Aliplayer.Component({
timeupdate(player, e) {
const currentTime = player.getCurrentTime()
@@ -36,6 +40,10 @@ export default defineComponent({
currentTime,
duration
})
},
error(player, e) {
disposeVideo()
isFailed.value = true
}
})
const getPlayerId = computed(() => {
@@ -84,12 +92,17 @@ export default defineComponent({
watch(
() => props.options,
(val) => {
isFailed.value = false
if (props.options.source && !hasInit.value) {
init()
nextTick(() => {
init()
})
}
if (hasInit.value) {
disposeVideo()
init()
nextTick(() => {
init()
})
}
}
)
@@ -99,6 +112,7 @@ export default defineComponent({
}
})
return {
isFailed,
getPlayerId,
getTime,
seekTime,

+ 3
- 1
src/utils/handleData.js View File

@@ -118,7 +118,9 @@ export function dataToSelect(data, optionsObj) {
const result = []
if (data && data.length) {
data.forEach((item) => {
const i = {}
const i = {
...item
}
i.label = item[optionsObj.label]
i.value = item[optionsObj.value]
if (item.children && item.children.length) {

+ 41
- 10
src/views/dashboard/components/AirCard.vue View File

@@ -16,7 +16,14 @@
</div>
<div class="card__video">
<div class="video__item">
<!-- <VideoPlayer :options="getVideoOptions.inner" /> -->
<VideoPlayer :options="getVideoOptions.inner">
<template #empty>
<div class="video__item--empty">
<img src="@/assets/images/lose-control.png">
<p>暂无信号</p>
</div>
</template>
</VideoPlayer>
</div>
<div class="video__item">
<div class="item__weather">
@@ -76,7 +83,7 @@ export default {
if (res.code === 0) {
const parm = res.data.wth?.parm || []
data.weatherList = parm.length !== 0 ? [
{ label: '天气', value: '' },
// { label: '天气', value: '' },
{ label: '气温', value: parm.tmp + '℃' },
{ label: '湿度', value: parm.hum + 'RH' },
{ label: '风度', value: parm.wspd + 'm/s' },
@@ -96,21 +103,25 @@ export default {

const getVideoOptions = computed(() => {
const row = data.airOptionsAll.find((item) => { return item.id === data.videoForm.airportId })
const live1 = 'https://live.play.t-aaron.com/live/THSBa_hd.m3u8'
const video1 = 'https://vod.play.t-aaron.com/af2f261d45fe4468bee5d4e501097405/53f0276aadc741909fd06c94484cd217-7184ea23b102c31c4a5e31d65206f539-fd.mp4'
const video2 = 'https://vod.play.t-aaron.com/408a38ee77ad4672b2b607e20a4e11d1/6d0d2ac3044a4992b4f2fe8563f75f20-0e1dfeb4f87ab08b10522d261f973f0d-fd.mp4'
return {
inner: {
id: 'video-inner',
width: '100%',
height: '100%',
source: row?.internalMonitorUrl,
isLive: true
},
outer: {
id: 'video-outer',
width: '100%',
height: '100%',
source: row?.externalMonitorUrl,
// source: row?.internalMonitorUrl,
source: row?.id === 2 ? live1 : video2,
isLive: true
}
// outer: {
// id: 'video-outer',
// width: '100%',
// height: '100%',
// source: row?.externalMonitorUrl,
// isLive: true
// }
}
})

@@ -145,6 +156,26 @@ export default {
&:first-child{
margin-right: 20px
}
.video__item--empty{
position: absolute;
width: 100%;
height: 100%;
background: rgba(3, 3, 3, 1);
img{
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%,-50%);
}
p{
position: absolute;
left: 50%;
top: 60%;
transform: translate(-50%,-50%);
font-size: 12px;
color: rgba(255, 255, 255, 1);
}
}
.item__weather{
position: absolute;
z-index: 100;

+ 32
- 4
src/views/dashboard/components/VideoCard.vue View File

@@ -18,12 +18,18 @@
</n-form>
</p>
</div>
<div class="card__video">
<div v-if="!hasLive" class="card__video">
<div class="card__video--empty">
<img src="@/assets/images/no-live.png">
<p>当前暂无直播</p>
</div>
</div>
<div v-else class="card__video">
<div class="video__item">
<!-- <VideoPlayer :options="getVideoOptions.origin" /> -->
<VideoPlayer :options="getVideoOptions.origin" />
</div>
<div class="video__item">
<!-- <VideoPlayer :options="getVideoOptions.analyse" /> -->
<VideoPlayer :options="getVideoOptions.analyse" />
</div>
</div>
</n-card>
@@ -46,7 +52,8 @@ export default {
},
airOptionsAll: [],
airOptions: [],
taskOptions: []
taskOptions: [],
hasLive: false
})

/**
@@ -113,12 +120,33 @@ export default {
.card__video{
display: flex;
height: calc(100% - 55px);
position: relative;
.video__item{
width: calc(50% - 10px);
&:first-child{
margin-right: 20px
}
}
.card__video--empty{
position: absolute;
width: 100%;
height: 100%;
background: rgba(3, 3, 3, 1);
img{
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%,-50%);
}
p{
position: absolute;
left: 50%;
top: 60%;
transform: translate(-50%,-50%);
font-size: 12px;
color: rgba(255, 255, 255, 1);
}
}
}
::v-deep(.n-form){
.n-form-item-feedback-wrapper{

+ 35
- 24
src/views/report-manage/all-report/components/ReportDrawer.vue View File

@@ -24,13 +24,13 @@
<n-gi><span>巡检方式</span></n-gi>
<n-gi><span>{{ reportDetail.lcName }}</span></n-gi>
<n-gi><span>巡检设备</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ reportDetail?.mission?.droneName }}</span></n-gi>
<n-gi><span>巡检开始时间</span></n-gi>
<n-gi><span>{{ reportDetail?.mission?.executionStartTime }}</span></n-gi>
<n-gi><span>巡检结束时间</span></n-gi>
<n-gi><span>{{ reportDetail?.mission?.executionEndTime }}</span></n-gi>
<n-gi><span>问题数量</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ questionNum }}</span></n-gi>
</n-grid>
</div>
</div>
@@ -41,13 +41,13 @@
<n-gi><span>巡检内容</span></n-gi>
<n-gi><span>巡检检查结果</span></n-gi>
<n-gi><span>林场问题图斑</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ problemsNum['type_1'] }}</span></n-gi>
<n-gi><span>病死树</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ problemsNum['type_2'] }}</span></n-gi>
<n-gi><span>人员活动</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ problemsNum['type_3'] }}</span></n-gi>
<n-gi><span>火灾隐患</span></n-gi>
<n-gi><span>-</span></n-gi>
<n-gi><span>{{ problemsNum['type_4'] }}</span></n-gi>
</n-grid>
</div>
</div>
@@ -60,7 +60,7 @@
<n-gi><span>坐标</span></n-gi>
<n-gi><span>{{ item.lng }},{{ item.lat }}</span></n-gi>
<n-gi><span>问题描述</span></n-gi>
<n-gi><span>{{ item.note ? item.note : '-' }}</span></n-gi>
<n-gi><span>{{ item.questionDesc ? item.questionDesc : '-' }}</span></n-gi>
<n-gi><span>问题图片</span></n-gi>
<n-gi><n-image :src="item.fileMarkerUrl" /></n-gi>
</n-grid>
@@ -68,7 +68,7 @@
<!-- </n-image-group> -->
</div>
<div class="report__operate">
<n-button type="primary">下载</n-button>
<n-button type="primary" @click="handleDownload">下载</n-button>
</div>
</div>
</n-drawer-content>
@@ -76,7 +76,7 @@
</template>

<script>
import { getReportDetail } from '@/api/report/index.js'
import { getReportDetail, reportDownload } from '@/api/report/index.js'
import { defineComponent, reactive, toRefs, computed, watch } from 'vue'

export default defineComponent({
@@ -99,13 +99,14 @@ export default defineComponent({
setup(props, { emit }) {
const data = reactive({
reportDetail: {},
weatherList: []
// problemsList: {
// 'type_1': 0,
// 'type_2': 0,
// 'type_3': 0,
// 'type_4': 0
// }
weatherList: [],
questionNum: 0,
problemsNum: {
'type_1': 0,
'type_2': 0,
'type_3': 0,
'type_4': 0
}
})

/* 获取抽屉的信息 */
@@ -129,18 +130,23 @@ export default defineComponent({
data.reportDetail = res.data
const parm = res.data.airWeather.wth?.parm || []
data.weatherList = parm.length !== 0 ? [
{ label: '天气', value: '' },
// { label: '天气', value: '' },
{ label: '气温', value: parm.tmp / 10 + '℃' },
{ label: '湿度', value: parm.hum / 10 + 'RH' },
{ label: '风度', value: parm.wspd + 'm/s' },
{ label: '风向', value: parm.wdir }
] : []
// data.problemsList = {
// 'type_1': 0,
// 'type_2': 0,
// 'type_3': 0,
// 'type_4': 0
// }
data.problemsNum = {
'type_1': 0,
'type_2': 0,
'type_3': 0,
'type_4': 0
}
data.questionNum = res.data.questionReportList.length
res.data.questionTypeInfo.forEach((item) => {
const key = `type_${item.type}`
data.problemsNum[key] = item.quantity
})
// data.reportDetail.questionReportList.forEach((item, index) => {
// if (index === 0)item.fileMarkerUrl = 'https://image.t-aaron.com/XJRW20220720165837/2022-07-20-17-07-34_frame-6563-6720_type-%E6%B0%B4%E7%94%9F%E6%A4%8D%E8%A2%AB_o3MORSWHXz5pQ8F9_s-live-XJRW20220720165837-a0ec218ddd884ffcadd4f3c8fc27d825_AI.jpg'
// if (index === 1)item.fileMarkerUrl = 'https://image.t-aaron.com/XJRW20220720165837/2022-07-20-17-04-30_frame-1802-1920_type-%E6%B0%B4%E7%94%9F%E6%A4%8D%E8%A2%AB_b0N6GXoM178nUxhC_s-live-XJRW20220720165837-a0ec218ddd884ffcadd4f3c8fc27d825_AI.jpg'
@@ -150,10 +156,15 @@ export default defineComponent({
}
})

function handleDownload() {
reportDownload(props.data.id)
}

return {
...toRefs(data),
getDrawerOptions,
handleDrawerColse
handleDrawerColse,
handleDownload
}
}
})

+ 2
- 0
src/views/task-manage/all-task/components/TaskModal.vue View File

@@ -108,6 +108,8 @@ export default defineComponent({
const params = {
...data.taskForm,
airportName: airportInfo.label,
droneId: airportInfo.droneId,
droneName: airportInfo.droneName,
inspectionLineName: airLineInfo.label
}
if (params.id) {

+ 25
- 6
src/views/task-manage/all-task/index.vue View File

@@ -1,7 +1,7 @@
<template>
<div>
<n-card>
<HeadSearch :info="search" @search="handleSearch" @reset="handleSearch" />
<HeadSearch ref="searchRef" :info="search" @search="handleSearch" @reset="handleSearch" @change="handleChange" />
<DataTable
ref="tableRef"
:columns="columns"
@@ -39,23 +39,26 @@

<script>
import table from './tools/table.js'
import search from './tools/search.js'
import { search, getAirOptions, getLineOptions, clearLineOptions } from './tools/search.js'
import HeadSearch from '@/components/Search/index.vue'
import DataTable from '@/components/DataTable/index.vue'
import TaskModal from './components/TaskModal.vue'
import LiveDrawer from './components/LiveDrawer.vue'
import DemandDrawer from './components/DemandDrawer.vue'
import VerifyDrawer from './components/VerifyDrawer.vue'
import { reactive, unref, toRefs } from 'vue'
import { reactive, ref, unref, toRefs } from 'vue'
import { getTaskList } from '@/api/task/index.js'

export default {
name: 'TaskAll',
components: { HeadSearch, DataTable, TaskModal, LiveDrawer, DemandDrawer, VerifyDrawer },
setup() {
getAirOptions()
const searchRef = ref()
const data = reactive({
search,
...toRefs(table)
...toRefs(search),
...toRefs(table),
airportId: null
})

/**
@@ -78,10 +81,26 @@ export default {
data.modalShow = true
}

function handleChange(value) {
console.log(value)
const { airportId } = value
if (data.airportId !== airportId) {
if (!airportId) {
clearLineOptions()
} else {
data.airportId = airportId
getLineOptions(airportId)
}
searchRef.value.setFormValue({ inspectionLine: null })
}
}

return {
...toRefs(data),
searchRef,
loadDataTable,
handleModal
handleModal,
handleChange
}
}
}

+ 74
- 62
src/views/task-manage/all-task/tools/search.js View File

@@ -1,69 +1,81 @@
import { reactive } from 'vue'
import { reactive, ref } from 'vue'
import { airportList, airportLine } from '@/api/dashboard/index.js'
import { dataToSelect } from '@/utils/handleData.js'
import { TASK_STATUS, TASK_TYPE } from '@/utils/dictionary.js'

const data = reactive([
{
label: '任务编号',
key: 'code',
props: {
placeholder: '请输入任务编号'
}
},
{
label: '任务名称',
key: 'name',
props: {
placeholder: '请输入任务名称'
}
},
{
label: '任务状态',
key: 'status',
type: 'select',
value: 'all',
props: {
placeholder: '请选择任务状态',
options: [
{ label: '全部', value: 'all' },
...TASK_STATUS
]
}
},
{
label: '巡检机场',
key: 'airportId',
type: 'select',
props: {
placeholder: '请选择任务状态',
options: [],
onUpdateValue: () => {
const index = data.findIndex((item) => item.key === 'route')
data[index].value = ''
const airOptions = ref([])
const lineOptions = ref([])
export const search = reactive({
search: [
{
label: '任务编号',
key: 'code',
props: {
placeholder: '请输入任务编号'
}
}
},
{
label: '巡检路线',
key: 'inspectionLine',
type: 'select',
props: {
placeholder: '请选择任务状态',
options: [],
onUpdateValue: () => {
},
{
label: '任务名称',
key: 'name',
props: {
placeholder: '请输入任务名称'
}
},
{
label: '任务状态',
key: 'status',
type: 'select',
value: 'all',
props: {
placeholder: '请选择任务状态',
options: [
{ label: '全部', value: 'all' },
...TASK_STATUS
]
}
},
{
label: '巡检机场',
key: 'airportId',
type: 'select',
props: {
placeholder: '请选择任务状态',
options: airOptions
}
},
{
label: '巡检路线',
key: 'inspectionLine',
type: 'select',
props: {
placeholder: '请选择任务状态',
options: lineOptions
}
},
{
label: '任务类型',
key: 'type',
type: 'select',
props: {
placeholder: '请选择任务状态',
options: TASK_TYPE
}
}
},
{
label: '任务类型',
key: 'type',
type: 'select',
value: 0,
props: {
placeholder: '请选择任务状态',
options: TASK_TYPE
}
}
])
]
})

export const getAirOptions = async function() {
const res = await airportList()
airOptions.value = dataToSelect(res.data, { label: 'name', value: 'droneId' })
}

export default data
// 获取角色列表
export const getLineOptions = async function(id) {
const res = await airportLine(id)
lineOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' })
}

// 获取角色列表
export const clearLineOptions = async function() {
lineOptions.value = []
}

+ 19
- 3
src/views/task-manage/question/index.vue View File

@@ -37,7 +37,7 @@ import HeadSearch from '@/components/Search/index.vue'
import DataTable from '@/components/DataTable/index.vue'
import ConfirmModal from './components/ConfirmModal.vue'
import PositionDrawer from './components/PositionDrawer.vue'
import { getQuestionList, generateReport } from '@/api/task/index.js'
import { getQuestionList, generateReport, questionAnalyze } from '@/api/task/index.js'
import { unref, reactive, toRefs } from 'vue'
export default {
name: 'QuestionPage',
@@ -115,8 +115,24 @@ export default {
* @description: 生成报告
* @return {*}
*/
function handleReported() {
generateReport(props.data.id)
async function handleReported() {
const res = await questionAnalyze(props.data.id)
if (res.code === 0) {
const { confirm, notreviewed } = res.data
if (notreviewed === 0) {
generateReport(props.data.id)
} else {
$dialog.confirm(
{
type: 'success',
title: '提示',
showIcon: false,
content: `已核实${confirm}条,未核实${notreviewed}条,是否提交并生成报告?`,
confirm: generateReport(props.data.id)
}
)
}
}
}

return {

Loading…
Cancel
Save