Browse Source

Merge branch 'zhangtao' of gitadmin/tuoheng_lc_web into develop

tags/v1.0.0^2
zhangtao 2 years ago
parent
commit
7d9f6f2f49
24 changed files with 1111 additions and 93 deletions
  1. +2
    -2
      index.html
  2. +27
    -0
      src/api/report/index.js
  3. +37
    -0
      src/api/task/index.js
  4. BIN
      src/assets/images/icon-zanwuxinhao-60.png
  5. BIN
      src/assets/images/icon-zanwuzhibo-60.png
  6. BIN
      src/assets/images/plain.png
  7. +134
    -0
      src/components/BaseMap/BaseMap.vue
  8. +0
    -8
      src/router/guard/permission-guard.js
  9. +6
    -0
      src/utils/dictionary.js
  10. +44
    -9
      src/views/dashboard/components/AirCard.vue
  11. +2
    -2
      src/views/question-manage/question-list/tools/table.js
  12. +209
    -0
      src/views/report-manage/all-report/components/ReportDrawer.vue
  13. +44
    -2
      src/views/report-manage/all-report/index.vue
  14. +45
    -0
      src/views/report-manage/all-report/tools/search.js
  15. +105
    -0
      src/views/report-manage/all-report/tools/table.js
  16. +259
    -0
      src/views/task-manage/all-task/components/BaseMap.vue
  17. +3
    -1
      src/views/task-manage/all-task/components/DemandDrawer.vue
  18. +3
    -1
      src/views/task-manage/all-task/components/LiveDrawer.vue
  19. +7
    -7
      src/views/task-manage/all-task/components/VerifyDrawer.vue
  20. +2
    -3
      src/views/task-manage/all-task/index.vue
  21. +11
    -3
      src/views/task-manage/all-task/tools/table.js
  22. +35
    -7
      src/views/task-manage/question/components/ConfirmModal.vue
  23. +64
    -26
      src/views/task-manage/question/index.vue
  24. +72
    -22
      src/views/task-manage/question/tools/table.js

+ 2
- 2
index.html View File

@@ -10,8 +10,8 @@
<link rel="icon" href="/favicon.ico" />
<title><%= title %></title>

<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.21/skins/default/aliplayer-min.css" />
<script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.9.21/aliplayer-h5-min.js"></script>
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.23/skins/default/aliplayer-min.css" />
<script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.9.23/aliplayer-h5-min.js"></script>
</head>
<body>

+ 27
- 0
src/api/report/index.js View File

@@ -0,0 +1,27 @@
import { defAxios as request } from '@/utils/http'

/**
* @description: 获取报告列表
* @param {*} params
* @return {*}
*/
export function getReportList(params) {
return request({
url: '/report/page',
method: 'GET',
params
})
}

/**
* @description: 获取报告详情
* @param {*} params
* @return {*}
*/
export function getReportDetail(id) {
return request({
url: `/report/${id}`,
method: 'GET'
})
}


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

@@ -59,3 +59,40 @@ export function implement(id) {
method: 'PUT'
})
}

/**
* @description: 获取任务详情
* @param {*} id 任务id
* @return {*}
*/
export function getQuestionList(params) {
return request({
url: '/question/page',
method: 'GET',
params
})
}

/**
* @description: 问题确认/忽略
* @param {*} data
* @return {*}
*/
export function changeQuestionStatus(data) {
return request({
url: '/question/status',
method: 'PUT',
data
})
}
/**
* @description: 生成报告
* @param {*} 任务id
* @return {*}
*/
export function generateReport(id) {
return request({
url: `/report/generate/${id}`,
method: 'POST'
})
}

BIN
src/assets/images/icon-zanwuxinhao-60.png View File

Before After
Width: 60  |  Height: 60  |  Size: 1.5KB

BIN
src/assets/images/icon-zanwuzhibo-60.png View File

Before After
Width: 60  |  Height: 60  |  Size: 832B

BIN
src/assets/images/plain.png View File

Before After
Width: 36  |  Height: 36  |  Size: 1.7KB

+ 134
- 0
src/components/BaseMap/BaseMap.vue View File

@@ -0,0 +1,134 @@
<template>
<div class="main_container">
<div class="container-map" v-bind="getMapOptions" />
</div>
</template>
<script>
import { Map, View, Feature } from 'ol'
import 'ol/ol.css'
import { Tile, Vector as VectorLayer } from 'ol/layer'
import { XYZ, Vector as VectorSource } from 'ol/source'
import { transform, fromLonLat } from 'ol/proj'
import * as control from 'ol/control'
import Point from 'ol/geom/Point'
import { Style, Icon } from 'ol/style'
import plain from '@/assets/images/plain.png'

import { reactive, computed, toRefs, onMounted } from 'vue'

export default {
name: 'PositionMsg',
props: {
id: {
type: String,
default: 'map-track'
},
coordinate: {
type: Array,
required: true
}
},
emits: {},
setup(props, { emit }) {
const data = reactive({

mapData: null,
mapView: null
})
const getMapOptions = computed(() => {
return {
id: props.id
}
})
/**
* 初始化底图
*/
const initMap = function() {
const layers = [
new Tile({
visible: true,
source: new XYZ({
url: 'https://tianditu.t-aaron.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f82bb2fd8115c7fb576a8b2fcf738523'
})
})
]
data.mapView = new View({
maxZoom: 18,
zoom: 4,
center: transform([108.94043, 31.008173], 'EPSG:4326', 'EPSG:3857')
})
data.mapData = new Map({
layers: layers,
target: props.id,
view: data.mapView,
controls: control.defaults({
attribution: false,
rotate: false,
zoom: false
})
})
data.mapData.render()
}

function positionPoint(coordinate) {
data.mapView.animate(
{ center: transform(coordinate, 'EPSG:4326', 'EPSG:3857') },
{ zoom: 18 }
)
}

/**
* 加载矢量图层
*/
const getLayer = function(coordinate) {
const pointFeatures = []
const featureItem = new Feature(new Point(fromLonLat(coordinate)))
featureItem.setStyle(new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: plain,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
}))
pointFeatures.push(featureItem)
const pointSource = new VectorSource({
wrapX: false,
features: pointFeatures
})
const problemLayer = new VectorLayer({
source: pointSource,
zIndex: 12
})
positionPoint(coordinate)
data.mapData.addLayer(problemLayer)
}

onMounted(() => {
initMap()
})

return {
...toRefs(data),
getMapOptions,
initMap,
getLayer,
positionPoint

}
}
}
</script>
<style scoped>
.main_container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.container-map {
width: 100%;
height: 100%;
}
</style>

+ 0
- 8
src/router/guard/permission-guard.js View File

@@ -1,11 +1,3 @@
/*
* @Author: whyafterme
* @Date: 2022-07-21 13:44:46
* @LastEditTime: 2022-07-27 09:04:01
* @LastEditors: whyafterme
* @Description:
* @FilePath: \forest\src\router\guard\permission-guard.js
*/
import { useUserStore } from '@/store/modules/user'
import { usePermissionStore } from '@/store/modules/permission'
import { NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '@/router/routes'

+ 6
- 0
src/utils/dictionary.js View File

@@ -22,6 +22,12 @@ export const QUESTION_TYPE = [
{ label: '火灾隐患', value: 4 }
]

export const QUESTION_STATUS = [
{ label: '已确认', value: 1 },
{ label: '已忽略', value: 2 },
{ label: '待确认', value: 3 }
]

export const USER_STATUS = [
{ label: '正常', value: 1 },
{ label: '禁用', value: 2 }

+ 44
- 9
src/views/dashboard/components/AirCard.vue View File

@@ -9,7 +9,7 @@
label-placement="left"
>
<n-form-item label="机场选择:" path="airportId">
<n-select v-model:value="videoForm.airportId" :options="airOptions" @change="getAirportInfo" />
<n-select v-model:value="videoForm.airportId" :options="airOptions" @update:value="getAirportInfo" />
</n-form-item>
</n-form>
</p>
@@ -19,7 +19,13 @@
<!-- <VideoPlayer :options="getVideoOptions.inner" /> -->
</div>
<div class="video__item">
<div class="item__weather">
<ul>
<li v-for="(item,index) in weatherList" :key="index">{{ item.label }}:{{ item.value }}</li>
</ul>
</div>
<!-- <VideoPlayer :options="getVideoOptions.outer" /> -->
<BaseMap ref="mapRef" :coordinate="coordinate" />
</div>
</div>
</n-card>
@@ -29,22 +35,26 @@
import { dataToSelect } from '@/utils/handleData.js'
import { airportList, airportWeather, airportTrack } from '@/api/dashboard/index.js'
import VideoPlayer from '@/components/VideoPlayer/index.vue'
import { reactive, computed, toRefs } from 'vue'
import BaseMap from '@/components/BaseMap/BaseMap.vue'
import { ref, reactive, computed, toRefs } from 'vue'

export default {
name: 'TaskCard',
components: { VideoPlayer },
components: { VideoPlayer, BaseMap },
setup() {
const mapRef = ref()
const data = reactive({
videoForm: {
airportId: null
},
airOptions: [],
airOptionsAll: []
airOptionsAll: [],
weatherList: [],
coordinate: [108.94043, 31.008173]
})

/**
* @description: 加载表格数据
* @description: 获取机场数据
* @param {*} res
* @return {*}
*/
@@ -59,14 +69,28 @@ export default {
})()

async function getAirportInfo(id) {
const airItem = data.airOptionsAll.find((item) => { return item.id === id })
const coordinate = [airItem?.longitude, airItem?.latitude]
markPoint(coordinate)
const res = await airportWeather(id)
if (res.code === 0) {
// 1
const parm = res.data.wth?.parm || []
data.weatherList = parm.length !== 0 ? [
{ label: '天气', value: '' },
{ label: '气温', value: parm.tmp + '℃' },
{ label: '湿度', value: parm.hum + 'RH' },
{ label: '风度', value: parm.wspd + 'm/s' },
{ label: '风向', value: parm.wdir }
] : []
}
}

const res2 = await airportTrack(id)
if (res2.code === 0) {
// 1
/* 地图标点 */
const markPoint = function(coordinate) {
try {
mapRef.value.getLayer(coordinate)
} catch (e) {
markPoint(coordinate)
}
}

@@ -92,6 +116,7 @@ export default {

return {
...toRefs(data),
mapRef,
loadAirport,
getAirportInfo,
getVideoOptions
@@ -116,9 +141,19 @@ export default {
height: calc(100% - 55px);
.video__item{
width: calc(50% - 10px);
position: relative;
&:first-child{
margin-right: 20px
}
.item__weather{
position: absolute;
z-index: 100;
padding: 5px 6px;
font-size: 12px;
right: 0;
color: rgba(255, 255, 255, 1);
background: rgba(0, 0, 0, 0.4);
}
}
}
::v-deep(.n-form){

+ 2
- 2
src/views/question-manage/question-list/tools/table.js View File

@@ -141,7 +141,7 @@ const data = reactive({
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row, 'preview')
onPositiveClick: getRowData.bind(null, row, 'preview')
},
auth: 'basic_list'
},
@@ -150,7 +150,7 @@ const data = reactive({
type: 'popconfirm',
tip: '是否删除该数据?',
props: {
onClick: handleRowDelete.bind(null, row)
onPositiveClick: handleRowDelete.bind(null, row)
},
ButtonProps: {
text: true,

+ 209
- 0
src/views/report-manage/all-report/components/ReportDrawer.vue View File

@@ -0,0 +1,209 @@
<template>
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse">
<n-drawer-content closable title="报告详情">
<div class="report__container">
<div class="report__item">
<p class="report__item--title">林场信息</p>
<div>
<n-grid :cols="2">
<n-gi><span>责任单位</span></n-gi>
<n-gi><span>{{ reportDetail.company }}</span></n-gi>
<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-grid>
</div>
</div>
<div class="report__item">
<p class="report__item--title">巡检信息</p>
<div>
<n-grid :cols="2">
<n-gi><span>气象信息</span></n-gi>
<n-gi><span v-for="(item,index) in weatherList" :key="index">&nbsp;{{ item.label }}: {{ item.value }}&nbsp;</span></n-gi>
<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>巡检开始时间</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-grid>
</div>
</div>
<div class="report__item">
<p class="report__item--title">巡检结果</p>
<div>
<n-grid :cols="2">
<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>病死树</span></n-gi>
<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>-</span></n-gi>
</n-grid>
</div>
</div>
<div class="report__item">
<p class="report__item--title">问题清单</p>
<!-- <n-image-group> -->
<div v-for="(item,index) in reportDetail.questionReportList" :key="index">
<p>问题{{ index + 1 }}</p>
<n-grid :cols="2">
<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>问题图片</span></n-gi>
<n-gi><n-image :src="item.fileMarkerUrl" /></n-gi>
</n-grid>
</div>
<!-- </n-image-group> -->
</div>
<div class="report__operate">
<n-button type="primary">下载</n-button>
</div>
</div>
</n-drawer-content>
</n-drawer>
</template>

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

export default defineComponent({
name: 'LiveDrawer',
props: {
/* 可见 */
visible: {
type: Boolean,
default: false
},
/* 选中的数据 */
data: {
type: Object,
default: () => {}
}
},
emits: {
'update:visible': null
},
setup(props, { emit }) {
const data = reactive({
reportDetail: {},
weatherList: []
// problemsList: {
// 'type_1': 0,
// 'type_2': 0,
// 'type_3': 0,
// 'type_4': 0
// }
})

/* 获取抽屉的信息 */
const getDrawerOptions = computed(() => {
return {
show: props.visible,
width: '100%',
placement: 'right'
}
})
/* 关闭抽屉 */
function handleDrawerColse() {
emit('update:visible', false)
}
watch(() => props.data,
(val) => {
if (val.id) {
getReportDetail(val.id)
.then(res => {
if (res.code === 0) {
data.reportDetail = res.data
const parm = res.data.airWeather.wth?.parm || []
data.weatherList = parm.length !== 0 ? [
{ 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.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'
// })
}
})
}
})

return {
...toRefs(data),
getDrawerOptions,
handleDrawerColse
}
}
})
</script>

<style scoped lang='scss'>
.report__container{
width: 900px;
margin: 0 auto 40px auto;
.report__item{
margin-bottom: 40px;
.report__item--title{
font-size: 18px;
color: #333333;
line-height: 44px;
}
.n-grid{
border-top: 1px solid rgba(216, 216, 216, 1);
border-left: 1px solid rgba(216, 216, 216, 1);
>div{
position: relative;
text-align: center;
font-size: 14px;
color: #333333;
line-height: 20px;
padding: 6px 12px;
word-wrap: break-word;
word-break: normal;
border-right: 1px solid rgba(216, 216, 216, 1);
border-bottom: 1px solid rgba(216, 216, 216, 1);
&:nth-child(2n-1){
span{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
background: rgba(228, 231, 237, 1);
}
}
}
}
.report__operate{
text-align: center;
}
}
::v-deep(.n-image){
width: 100%;
img{
width: 100%;
}
}
</style>

+ 44
- 2
src/views/report-manage/all-report/index.vue View File

@@ -1,14 +1,56 @@
<template>
<div>
全部报告
<n-card>
<HeadSearch :info="search" @search="handleSearch" @reset="handleSearch" />
<DataTable
ref="tableRef"
:columns="columns"
:row-key="(row) => row.id"
:request="loadDataTable"
size="large"
/>
</n-card>
</div>

<ReportDrawer v-model:visible="detailDrawer" :data="rowData" />

</template>

<script>
import table from './tools/table.js'
import search from './tools/search.js'
import HeadSearch from '@/components/Search/index.vue'
import DataTable from '@/components/DataTable/index.vue'
import ReportDrawer from './components/ReportDrawer.vue'
import { reactive, unref, toRefs } from 'vue'
import { getReportList } from '@/api/report/index.js'

export default {
name: 'AllReport',
name: 'TaskAll',
components: { HeadSearch, DataTable, ReportDrawer },
setup() {
const data = reactive({
search,
...toRefs(table)
})

/**
* @description: 加载表格数据
* @param {*} res
* @return {*}
*/
const loadDataTable = async(res) => {
const _params = {
...unref(data.searchParams),
...res
}
return await getReportList(_params)
}

return {
...toRefs(data),
loadDataTable
}
}
}


+ 45
- 0
src/views/report-manage/all-report/tools/search.js View File

@@ -0,0 +1,45 @@
import { reactive } from 'vue'
import { TASK_TYPE } from '@/utils/dictionary.js'

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

export default data


+ 105
- 0
src/views/report-manage/all-report/tools/table.js View File

@@ -0,0 +1,105 @@
import { TASK_TYPE } from '@/utils/dictionary.js'
import TableTags from '@/components/DataTable/tools/Tags.vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import { h, ref, reactive } from 'vue'

/* 注册table */
const tableRef = ref()
const searchParams = ref()

function handleSearch(params) {
searchParams.value = { ...params }
tableRef.value.reFetch({ searchParams })
}

/**
* @description: 获取数据及操作
* @param {*} row 单行数据
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑
* @return {*}
*/
function getRowData(row) {
data.rowData = row
data.detailDrawer = true
}

const data = reactive({
tableRef,
searchParams,
rowData: {},
detailDrawer: false,
handleSearch,

columns: [
{
title: '序号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center'
},
{
title: '报告编号',
key: 'reportNo',
align: 'center'
},
{
title: '生成时间',
key: 'generateTime',
align: 'center'
},
{
title: '任务名称',
key: 'missionName',
align: 'center'
},
{
title: '巡检机场',
key: 'airportName',
align: 'center'
},
{
title: '任务类型',
key: 'type',
align: 'center',
render(row) {
return h(TableTags, {
data: row.type,
filters: TASK_TYPE
})
}
},
{
title: '巡检时间',
key: 'executionStartTime',
align: 'center'
},
{
title: '查看',
align: 'center',
width: 150,
fixed: 'right',
render(row) {
return h(TableAction, {
actions: [
{
label: '巡检报告',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: getRowData.bind(null, row)
},
auth: 'basic_list'
}
],
align: 'center'
})
}
}

]
})

export default data

+ 259
- 0
src/views/task-manage/all-task/components/BaseMap.vue View File

@@ -0,0 +1,259 @@
<template>
<div class="main_container">
<div id="track" ref="map" />
</div>
</template>
<script>
import { reactive, toRefs, onMounted, ref } from 'vue'
import { Map, View } from 'ol'
import 'ol/ol.css'
import { Tile } from 'ol/layer'
import { XYZ } from 'ol/source'
import { transform } from 'ol/proj'
import * as control from 'ol/control'

export default {
name: 'PositionMsg',
props: {
data: {
type: Array,
default: () => {}
}
},
emits: {},
setup(props, { emit }) {
const data = reactive({
problemList: props.data, // 问题矢量点列表
problemData: {}, // 问题点数据
mapData: null,
mapView: null
})

/**
* 初始化底图
*/
const initMap = function() {
const layers = [
new Tile({
visible: true,
source: new XYZ({
url: 'https://tianditu.t-aaron.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f82bb2fd8115c7fb576a8b2fcf738523'
})
})
]

data.mapView = new View({
maxZoom: 18,
zoom: 4,
center: transform([108.94043, 31.008173], 'EPSG:4326', 'EPSG:3857')
})
data.mapData = new Map({
layers: layers,
target: 'track',
view: data.mapView,
controls: control.defaults({
attribution: false,
rotate: false,
zoom: false
})
})
data.mapData.render()
}

// function playTrack(map, view, id, hisTrackList) {
// let animating = false
// let distance = 0
// let lastTime
// let trackInfo = null
// let vectorLayer
// let changeTrack
// const initTrack = (coordinate) => {
// const route = new LineString(coordinate)
// const routeFeature = new Feature({
// type: 'route',
// geometry: route
// })
// const startMarker = new Feature({
// type: 'icon',
// geometry: new Point(route.getFirstCoordinate())
// })
// const endMarker = new Feature({
// type: 'icon',
// geometry: new Point(route.getLastCoordinate())
// })
// const position = startMarker.getGeometry().clone()
// const geoMarker = new Feature({
// type: 'geoMarker',
// geometry: position
// })
// geoMarker.setProperties({ type: 'geoMarker' }, false)

// const styles = {
// route: new Style({
// stroke: new Stroke({
// width: 3,
// color: 'red'
// })
// }),
// icon: new Style({
// image: new Icon({
// offset: [0, 0],
// offsetOrigin: 'bottom-right',
// src: require('@/assets/img/point.png'),
// scale: [0.9, 0.9]
// })
// }),
// geoMarker: new Style({
// image: new Icon({
// offset: [0, 0],
// offsetOrigin: 'bottom-right',
// src: require('@/assets/img/point.png'),
// scale: [0.5, 0.5]
// })
// })
// }
// if (this.vectorLayer) {
// this.vectorLayer.setSource(
// new VectorSource({
// features: [geoMarker, routeFeature]
// })
// )
// vectorLayer = this.vectorLayer
// } else {
// vectorLayer = new VectorLayer({
// source: new VectorSource({
// features: [geoMarker, routeFeature]
// }),
// style: function(feature) {
// return styles[feature.get('type')]
// }
// })
// }
// this.vectorLayer = vectorLayer
// map.addLayer(vectorLayer)
// // vectorLayer.on('postrender',changeTrack)
// vectorLayer.on('change', changeTrack)
// view.fit(route, { padding: [50, 50, 50, 50] })
// this.routeLayer = vectorLayer
// // startAnimation({vectorLayer,geoMarker})
// return {
// vectorLayer,
// geoMarker,
// route,
// styles,
// position
// }
// }
// if (hisTrackList.length > 1) {
// trackInfo = initTrack(hisTrackList)
// }
// changeTrack = (event) => {
// try {
// // trackInfo.route.appendCoordinate(coordinate);
// const vectorContext = getVectorContext(event)
// vectorContext.setStyle(trackInfo.styles.geoMarker)
// VectorContext.drawGeometry(trackInfo.position)
// vectorContext.drawGeometry(trackInfo.route)
// // tell OpenLayers to continue the postrender animation
// map.render()
// } catch {}
// }
// this.socket = setInterval(() => {
// this.$http.get(`/inspection/getFlightDataByInspectionId?inspectionId=${id}`)
// .then((res) => {
// const coordinate = fromLonLat([res.data?.data?.lng, res.data?.data?.lat])
// const unUseableCoordinate = !coordinate.every((item) => !isNaN(item))
// if (unUseableCoordinate) return
// // 赋值动态无人机坐标
// if (this.btnList[0].flag) {
// if (coordinate.length) {
// this.trajectoryList.lng = coordinate[0]
// this.trajectoryList.lat = coordinate[1]
// }
// }

// this.trackList.push(coordinate)
// if (this.trackList.length > 1 && !trackInfo) {
// this.initTrack(this.trackList)
// }
// if (trackInfo) {
// trackInfo.route.appendCoordinate(coordinate)
// trackInfo.vectorLayer.getSource().changed()
// trackInfo.position.setCoordinates(coordinate)
// }
// })
// }, 2000)
// const test = (event) => {
// const coordinate = toRaw(this.trackList).shift()
// if (!coordinate) return
// trackInfo.route.appendCoordinate(coordinate)
// const vectorContext = getVectorContext(event)
// vectorContext.setStyle(trackInfo.styles.geoMarker)
// vectorContext.drawGeometry(trackInfo.route)
// // tell OpenLayers to continue the postrender animation
// map.render()
// // if(!animating){
// // // startAnimation(trackInfo);
// // }
// }
// function moveFeature(event) {
// const speed = Number(50)
// const time = event.frameState.time
// const elapsedTime = time - lastTime
// distance = (distance + (speed * elapsedTime) / 1e6) % 2
// if (distance > 1) {
// stopAnimation(trackInfo)
// }
// lastTime = time

// const currentCoordinate = trackInfo.route.getCoordinateAt(
// distance > 1 ? 2 - distance : distance
// )
// trackInfo.position.setCoordinates(currentCoordinate)
// const vectorContext = getVectorContext(event)
// vectorContext.setStyle(trackInfo.styles.geoMarker)
// vectorContext.drawGeometry(trackInfo.position)
// // tell OpenLayers to continue the postrender animation
// map.render()
// }

// function stopAnimation(trackInfo) {
// const { vectorLayer, geoMarker } = trackInfo
// animating = false
// // Keep marker at current animation position
// geoMarker.setGeometry(trackInfo.position)
// vectorLayer.un('postrender', moveFeature)
// }
// function startAnimation(trackInfo) {
// const { vectorLayer, geoMarker } = trackInfo
// animating = true
// lastTime = Date.now()
// vectorLayer.on('postrender', moveFeature)
// // hide geoMarker and trigger map render through change event
// geoMarker.setGeometry(null)
// }
// }

onMounted(() => {
initMap()
})

return {
...toRefs(data)

}
}
}
</script>
<style scoped>
.main_container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
#track {
width: 100%;
height: 100%;
}
</style>

+ 3
- 1
src/views/task-manage/all-task/components/DemandDrawer.vue View File

@@ -1,16 +1,18 @@
<template>
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse">
<n-drawer-content closable title="轨迹回放">
轨迹回放
<BaseMap />
</n-drawer-content>
</n-drawer>
</template>

<script>
import BaseMap from './BaseMap.vue'
import { h, defineComponent, computed, reactive, toRefs } from 'vue'

export default defineComponent({
name: 'LiveDrawer',
components: { BaseMap },
props: {
/* 可见 */
visible: {

+ 3
- 1
src/views/task-manage/all-task/components/LiveDrawer.vue View File

@@ -1,16 +1,18 @@
<template>
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse">
<n-drawer-content closable title="飞行直播">
飞行直播
<BaseMap />
</n-drawer-content>
</n-drawer>
</template>

<script>
import BaseMap from './BaseMap.vue'
import { h, defineComponent, computed, reactive, toRefs } from 'vue'

export default defineComponent({
name: 'LiveDrawer',
components: { BaseMap },
props: {
/* 可见 */
visible: {

+ 7
- 7
src/views/task-manage/all-task/components/VerifyDrawer.vue View File

@@ -1,14 +1,14 @@
<template>
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse">
<n-drawer-content closable title="疑似问题核实">
<QuestionPage />
<QuestionPage :data="getMission" />
</n-drawer-content>
</n-drawer>
</template>

<script>
import QuestionPage from '@/views/task-manage/question/index.vue'
import { defineComponent, computed, reactive, toRefs } from 'vue'
import { defineComponent, computed } from 'vue'

export default defineComponent({
name: 'LiveDrawer',
@@ -29,10 +29,6 @@ export default defineComponent({
'update:visible': null
},
setup(props, { emit }) {
const data = reactive({

})

/* 获取抽屉的信息 */
const getDrawerOptions = computed(() => {
return {
@@ -41,13 +37,17 @@ export default defineComponent({
placement: 'right'
}
})
/* 获取选中的数据 */
const getMission = computed(() => {
return props.data
})
function handleDrawerColse() {
emit('update:visible', false)
}

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

+ 2
- 3
src/views/task-manage/all-task/index.vue View File

@@ -5,8 +5,8 @@
<DataTable
ref="tableRef"
:columns="columns"
:data="data"
:row-key="(row) => row.id"
:request="loadDataTable"
size="large"
>
<template #tableTitle>
@@ -55,8 +55,7 @@ export default {
setup() {
const data = reactive({
search,
...toRefs(table),
data: [{}]
...toRefs(table)
})

/**

+ 11
- 3
src/views/task-manage/all-task/tools/table.js View File

@@ -74,7 +74,15 @@ const data = reactive({

columns: [
{
title: '任务标号',
title: '序号',
key: 'key',
render: (_, index) => {
return `${index + 1}`
},
align: 'center'
},
{
title: '任务编号',
key: 'code',
align: 'center'
},
@@ -155,7 +163,7 @@ const data = reactive({
type: 'popconfirm',
tip: '是否删除该数据?',
props: {
onClick: handleRowDelete.bind(null, row)
onPositiveClick: handleRowDelete.bind(null, row)
},
ButtonProps: {
text: true,
@@ -168,7 +176,7 @@ const data = reactive({
type: 'popconfirm',
tip: '是否立即开始执行任务?',
props: {
onClick: handleImplement.bind(null, row)
onPositiveClick: handleImplement.bind(null, row)
},
ButtonProps: {
text: true,

+ 35
- 7
src/views/task-manage/question/components/ConfirmModal.vue View File

@@ -12,7 +12,7 @@
</n-icon>
<div class="carousel__container">
<label>问题描述</label>
<n-carousel ref="carouselRef" :show-dots="false">
<n-carousel ref="carouselRef" :default-index="selectIndex" :show-dots="false">
<img
v-for="item in getCarouselInfo"
:key="item.id"
@@ -38,6 +38,7 @@

<script>
import { QUESTION_TYPE } from '@/utils/dictionary.js'
import { changeQuestionStatus } from '@/api/task/index.js'
import { LeftOutlined, RightOutlined } from '@vicons/antd'
import Modal from '@/components/Modal/index.vue'
import { defineComponent, computed, ref, reactive, toRefs } from 'vue'
@@ -52,6 +53,10 @@ export default defineComponent({
data: {
type: Array,
default: () => null
},
selectRow: {
type: Object,
default: () => {}
}
},
emits: {
@@ -62,8 +67,9 @@ export default defineComponent({
setup(props, { emit }) {
const formRef = ref()
const data = reactive({
selectRow: props.data[0],
selectType: props.data[0].type,
selectRow: props.selectRow,
selectIndex: props.data.findIndex((item) => { return item.id === props.selectRow.id }),
selectType: props.selectRow.type,
QUESTION_TYPE
})
/* 获取弹窗的属性 */
@@ -72,8 +78,8 @@ export default defineComponent({
show: props.visible,
title: '问题确认',
width: 700,
negativeText: '忽略',
positiveText: '确认'
negativeText: data.selectRow.status !== 2 ? '忽略' : '',
positiveText: data.selectRow.status !== 1 ? '确认' : ''
}
})

@@ -109,10 +115,32 @@ export default defineComponent({
* @return {*}
*/
const handleConfirm = () => {
emit('update-data')
const params = {
id: [data.selectRow.id],
type: data.selectType,
status: 1
}
changeQuestionStatus(params)
.then(res => {
if (res.code === 0) {
data.selectRow.status = 1
emit('update-data')
}
})
}
const handleIgnore = () => {

const params = {
id: [data.selectRow.id],
type: data.selectType,
status: 2
}
changeQuestionStatus(params)
.then(res => {
if (res.code === 0) {
data.selectRow.status = 2
emit('update-data')
}
})
}

/* 关闭弹窗 */

+ 64
- 26
src/views/task-manage/question/index.vue View File

@@ -4,21 +4,26 @@
ref="tableRef"
:columns="columns"
:row-key="(row) => row.id"
:data="data"
size="large"
scroll-x="1200"
:request="loadDataTable"
:checked-row-keys="selectRowKeys"
@fetch-success="getTableData"
@update:checked-row-keys="handleRowsCheck"
>
<template #tableTitle>
<n-button @click="handleIgnoreBatch">忽略</n-button>
<n-button style="margin-right:20px" @click="handleIgnoreBatch">忽略</n-button>
<n-button type="primary" @click="handleConfirmBatch">
确认
</n-button>

</template>
<template #toolbar>
<n-button @click="handleReported">
{{ isReported ? '修改并生成报告': '提交并生成报告' }}
</n-button>
</template>
</DataTable>

<ConfirmModal v-if="confirmModal" v-model:visible="confirmModal" :data="pageData" @update-data="tableReload" />
<ConfirmModal v-if="confirmModal" v-model:visible="confirmModal" :data="pageData" :select-row="rowData" @update-data="handleSearch" />

<!-- 图片位置 -->
<position-drawer v-model:visible="positionDrawer" :data="rowData" />
@@ -32,28 +37,45 @@ 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 { ref, reactive, toRefs } from 'vue'
import { getQuestionList, generateReport } from '@/api/task/index.js'
import { unref, reactive, toRefs } from 'vue'
export default {
name: 'QuestionPage',
components: { HeadSearch, DataTable, ConfirmModal, PositionDrawer },
setup() {
props: {
data: {
type: Object,
default: () => {}
}
},
setup(props, { emit }) {
const data = reactive({
search,
...toRefs(table),
data: [
{ id: 1, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg', position: '软件园', type: 1 },
{ id: 2, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg', position: '东吉大道一号', type: 2 }
],
pageData: []

pageData: [],
isReported: props.data?.isReported || false
})

/**
* @description: 加载表格数据
* @param {*} res
* @return {*}
*/
const loadDataTable = async(res) => {
const _params = {
...unref(data.searchParams),
...res
}
if (_params.status === 'all') _params.status = ''
return await getQuestionList(_params)
}

/**
* @description:
* @return {*}
*/
function getTableData(list) {
data.pageData = list
data.pageData = list.items
}

/**
@@ -62,34 +84,50 @@ export default {
* @return {*}
*/
function handleRowsCheck(rowKeys) {
console.log(rowKeys)
data.selectRowKeys = rowKeys
}

/**
* @description: 批量忽略
* @return {*}
*/
function handleIgnoreBatch() {

if (data.selectRowKeys.length === 0) {
$message.error('请至少选择一条数据')
return
}
data.handleRowIgnore(data.selectRowKeys)
}

/**
* @description: 批量确认
* @return {*}
*/
function handleConfirmBatch() {

if (data.selectRowKeys.length === 0) {
$message.error('请至少选择一条数据')
return
}
data.handleRowConfirm(data.selectRowKeys)
}

const tableRef = ref()
/* 刷新表格数据 */
function tableReload(res) {
const _params = {
...res
}
tableRef.value.reFetch(_params)
/**
* @description: 生成报告
* @return {*}
*/
function handleReported() {
generateReport(props.data.id)
}

return {
...toRefs(data),
tableRef,
loadDataTable,
getTableData,
handleRowsCheck,
handleIgnoreBatch,
handleConfirmBatch,
tableReload
handleReported

}
}
}

+ 72
- 22
src/views/task-manage/question/tools/table.js View File

@@ -1,18 +1,49 @@
// import TableTags from '@/components/DataTable/tools/Tags.vue'
import { QUESTION_STATUS } from '@/utils/dictionary.js'
import TableTags from '@/components/DataTable/tools/Tags.vue'
import TableImage from '@/components/DataTable/tools/Image.vue'
import TableAction from '@/components/DataTable/tools/Action.vue'
import { h, reactive } from 'vue'
import { changeQuestionStatus } from '@/api/task/index.js'
import { h, ref, reactive } from 'vue'

/* 注册table */
const tableRef = ref()
const searchParams = ref()

function handleSearch(params) {
searchParams.value = { ...params }
tableRef.value.reFetch({ searchParams })
}

/* 问题忽略 */
function handleRowIgnore(row) {
data.rowData = row
console.log('问题忽略')
function handleRowIgnore(ids, type = '') {
const params = {
id: ids,
type: type,
status: 2
}
changeQuestionStatus(params)
.then(res => {
if (res.code === 0) {
data.selectRowKeys = []
handleSearch()
}
})
}

/* 问题确认 */
function handleRowConfirm(row) {
data.rowData = row
console.log('问题确认')
function handleRowConfirm(ids, type = '') {
const params = {
id: ids,
type: type,
status: 1
}
changeQuestionStatus(params)
.then(res => {
if (res.code === 0) {
data.selectRowKeys = []
handleSearch()
}
})
}

/* 位置 */
@@ -21,14 +52,21 @@ function handlePositionDrawer(row) {
data.positionDrawer = true
}

function handleImgPreview() {
function handleImgPreview(row) {
data.rowData = row
data.confirmModal = true
}

const data = reactive({
tableRef,
searchParams,
rowData: {},
selectRowKeys: [],
confirmModal: false,
positionDrawer: false,
handleSearch,
handleRowIgnore,
handleRowConfirm,
columns: [
{
type: 'selection'
@@ -40,19 +78,19 @@ const data = reactive({
},
{
title: '问题类型',
key: 'name',
key: 'questionName',
align: 'center'
},
{
title: '问题图片',
key: 'image',
key: 'fileMarkerUrl',
align: 'center',
render(row) {
return h(TableImage, {
images: {
width: 36,
height: 36,
src: row.image,
src: row.fileMarkerUrl,
previewDisabled: true,
onClick: handleImgPreview.bind(null, row)
}
@@ -62,7 +100,12 @@ const data = reactive({
{
title: '经纬度',
key: 'name',
align: 'center'
align: 'center',
render(row) {
return h(TableTags, {
data: [{ name: row.lng }, { name: row.lat }]
})
}
},
{
title: '位置',
@@ -79,8 +122,7 @@ const data = reactive({
text: true,
onClick: handlePositionDrawer.bind(null, row)
},
auth: 'basic_list',
show: row.status !== 1
auth: 'basic_list'
}
],
align: 'center'
@@ -89,13 +131,19 @@ const data = reactive({
},
{
title: '备注',
key: 'name',
key: 'note',
align: 'center'
},
{
title: '状态',
key: 'name',
align: 'center'
key: 'status',
align: 'center',
render(row) {
return h(TableTags, {
data: row.status,
filters: QUESTION_STATUS
})
}
},

{
@@ -111,26 +159,28 @@ const data = reactive({
type: 'popconfirm',
tip: '是否忽略该数据?',
props: {
onClick: handleRowIgnore.bind(null, row)
onPositiveClick: handleRowIgnore.bind(null, [row.id], row.type)
},
ButtonProps: {
text: true,
type: 'primary'
},
auth: 'basic_list'
auth: 'basic_list',
hidden: row.status === 2
},
{
label: '确认',
type: 'popconfirm',
tip: '是否确认该数据?',
props: {
onClick: handleRowConfirm.bind(null, row)
onPositiveClick: handleRowConfirm.bind(null, [row.id], row.type)
},
ButtonProps: {
text: true,
type: 'primary'
},
auth: 'basic_list'
auth: 'basic_list',
hidden: row.status === 1
}
],
align: 'center'

Loading…
Cancel
Save