Parcourir la source

Merge branch 'zhangtao' of gitadmin/tuoheng_lc_web into develop

tags/v1.2.0
zhangtao il y a 1 an
Parent
révision
14e9e2c5b5
8 fichiers modifiés avec 177 ajouts et 620 suppressions
  1. +9
    -0
      src/api/dashboard/index.js
  2. +0
    -309
      src/components/clickController.vue
  3. +92
    -18
      src/layout/components/Header/index.vue
  4. +69
    -14
      src/views/dashboard/components/ControlPanel.vue
  5. +0
    -253
      src/views/dashboard/components/remoateSensing.vue
  6. +2
    -23
      src/views/dashboard/index.vue
  7. +3
    -1
      src/views/early-warning/fire/components/FireModal.vue
  8. +2
    -2
      src/views/task-manage/all-task/tools/table.js

+ 9
- 0
src/api/dashboard/index.js Voir le fichier

@@ -145,3 +145,12 @@ export function confirmWarning(params) {
})
}

// 预警已确认
export function emergencyList(params = { airportFlyType: 2, statusList: 2 }) {
return request({
url: `/mission/emergency/list`,
method: 'GET',
params
})
}


+ 0
- 309
src/components/clickController.vue Voir le fichier

@@ -1,309 +0,0 @@
<template>
<div class="control" :style="{ width: 2 * outerRadius + 'rem', height: 2 * outerRadius + 'rem' }">
<div class="vertical common" :style="{ top: `${iconDistance || 12}rem` }">
<slot name="top">
<UpOutlined class="common" />
</slot>
</div>
<div class="horizontal common" :style="{ left: `${iconDistance || 12}rem` }">
<slot name="left">
<LeftOutlined class="common" />
</slot>
</div>
<div class="vertical common" :style="{ bottom: `${iconDistance || 12}rem` }">
<slot name="bottom">
<DownOutlined class="common" />
</slot>
</div>
<div class="horizontal common" :style="{ right: `${iconDistance || 12}rem` }">
<slot name="right">
<RightOutlined class="common" />
</slot>
</div>
<span v-if="lock">
<span
v-for="item of 4"
:key="item"
class="divider"
:style="{ transform: `rotate(${ 45 * (2 * item + 1) }deg) translateX(${innerRadius}rem)`,width: outerRadius - innerRadius + 'rem',}"
/>
</span>
<div
class="circle"
:style="{
top: data.distanceY + 'rem',
left: data.distanceX + 'rem',
width: 2 * innerRadius + 'rem',
height: 2 * innerRadius + 'rem',
}"
/>
<div
class="mask base"
:style="{
width: 2 * outerRadius + 'rem',
height: 2 * outerRadius + 'rem',
}"
@mousedown="mousedown"
@mouseup="mouseup"
/>
</div>
</template>

<script>
import {
DownOutlined,
UpOutlined,
LeftOutlined,
RightOutlined
} from '@vicons/antd'
import { computed, ref, toRaw, watch } from 'vue'
// import { mapActions, mapGetters } from 'vuex'
export default {
components: {
DownOutlined,
UpOutlined,
LeftOutlined,
RightOutlined
},
props: {
lock: {
type: Boolean,
default() {
return true
}
},
iconDistance: {
type: Number,
default() {
return 7 / 136.6
}
},
outerRadius: {
type: Number,
default() {
return 60 / 136.6
}
},
innerRadius: {
type: Number,
default() {
return 15 / 136.6
}
},
command: {
type: Object,
default() {
return {}
}
},
keyboardMode: {
type: Boolean,
default() {
return false
}
},
keyMap: {
type: Object,
default() {
return { 38: 'up', 39: 'right', 40: 'down', 37: 'left' }
}
}
},
setup(props, { emit }) {
const data = ref({
direction: null,
distanceX: 0,
distanceY: 0,
offsetX: 0,
offsetY: 0,
actualRemUnit: 0,
keycode: null
})
const circleDistance = computed(() => {
return props.outerRadius - props.innerRadius
})
data.value.distanceX = data.value.distanceY = circleDistance.value
function keyup(e) {
if (!props.keyboardMode || e.keyCode !== data.value.keyCode) return
const keys = Object.keys(toRaw(props.keyMap))
if (keys.includes(e.keyCode + '')) {
data.value.direction = null
emit('endAction')
}
data.value.keyCode = null
// this.updateRemoteControlling(false)
document.removeEventListener('keyup', keyup)
document.addEventListener('keydown', keydown)
}
function keydown(e) {
// if (this.remoteControlling || !this.keyboardMode) return
const direction = props.keyMap[e.keyCode]
if (!direction) return
// this.updateRemoteControlling(true)
data.value.direction = direction
data.value.keyCode = e.keyCode
document.removeEventListener('keydown', keydown)
document.addEventListener('keyup', keyup)
}
function mousedown(e) {
if (props.keyboardMode) return
data.value.actualRemUnit = parseFloat(document.documentElement.style.fontSize) || 4
const offset = e.target.parentNode.getBoundingClientRect()
data.value.offsetX = offset.left / data.value.actualRemUnit
data.value.offsetY = offset.top / data.value.actualRemUnit
const x = e.clientX / data.value.actualRemUnit - props.outerRadius - data.value.offsetX
const y = -(e.clientY / data.value.actualRemUnit - props.outerRadius - data.value.offsetY)
let deg = getTanDeg(x, y)
deg = deg === 360 ? 0 : deg
const { resultX, resultY } = getBoundary(
data.value.offsetX + props.outerRadius,
data.value.offsetY + props.outerRadius,
deg,
e.clientX / data.value.actualRemUnit,
e.clientY / data.value.actualRemUnit
)
data.value.distanceX = resultX - props.innerRadius
data.value.distanceY = resultY - props.innerRadius
let direction
if (deg > 45 && deg < 135) {
direction = 'right'
} else if (deg > 135 && deg < 225) {
direction = 'down'
} else if (deg > 225 && deg < 315) {
direction = 'left'
} else {
direction = 'up'
}
data.value.direction = direction
return deg
}
function mouseup() {
if (props.keyboardMode) return
data.value.distanceX = circleDistance.value
data.value.distanceY = circleDistance.value
data.value.direction = null
emit('endAction')
}
function getTanDeg(x, y) {
var result = Math.atan(x / y) / (Math.PI / 180)
if (result <= 0) {
if (y <= 0) {
result += 180
} else {
result += 360
}
} else {
if (y <= 0) {
result += 180
}
}
return result
}
function getBoundary(radX, radY, deg, X, Y) {
let resultX = X - radX
let resultY = Y - radY
const radian = (Math.PI * deg) / 180
const offsetX = circleDistance.value * Math.sin(radian)
const offsetY = circleDistance.value * Math.cos(radian)
if (Math.abs(offsetX) < Math.abs(resultX)) {
resultX = offsetX
resultY = -offsetY
}
if (deg === 0 || deg === 180) {
if (Math.abs(offsetY) < Math.abs(resultY)) {
resultX = offsetX
resultY = -offsetY
}
}
resultX += props.outerRadius
resultY += props.outerRadius
if (props.lock) {
if (
(deg >= 0 && deg <= 45) ||
(deg >= 315 && deg <= 360) ||
(deg >= 135 && deg <= 225)
) {
resultX = radX - data.value.offsetX
} else {
resultY = radY - data.value.offsetY
}
}
return {
resultX,
resultY: resultY
}
}

// computed: {
//
// // ...mapGetters(['remoteControlling'])
// },
watch(() => data.value.direction, (newValue) => {
if (newValue === null) return
emit('executeAction', props.command[newValue])
})
watch(() => props.keyboardMode, (flag) => {
if (flag) {
document.addEventListener('keydown', keydown)
} else {
document.removeEventListener('keydown', keydown)
}
})
return {
data,
circleDistance,
keyup,
keydown,
mouseup,
mousedown,
getTanDeg,
getBoundary
}
}
}
</script>

<style lang="scss" scoped>
.control {
position: relative;
border-radius: 50%;
background: #3f3f3f;
color: rgba(255, 255, 255, 0.7);
.common {
width: 20px;
color: #fff;
font-size: 14px;
z-index: 1;
}
.vertical {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.horizontal {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.divider {
height: 1px;
background: #333435;
position: absolute;
top: 50%;
left: 50%;
transform-origin: 0 50%;
pointer-events: none;
}
.circle {
position: absolute;
border-radius: 50%;
background: #121416;
}
.mask {
position: absolute;
top: 0;
left: 0;
z-index: 5;
}
}
</style>

+ 92
- 18
src/layout/components/Header/index.vue Voir le fichier

@@ -5,47 +5,65 @@
<span class="header__name">{{ platFormTitle }}</span>
</div>

<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<div class="user_msg">
<n-image
class="user_avatar"
:src="getUserInfo.avatar"
preview-disabled
/>
<span class="user_name">{{ getUserInfo.realname }}</span>
<div class="header__tool">
<div class="header__scroll">
<div class="scroll__content">
<ul ref="scrollRef">
<li v-for="(item,index) in list" :key="index">
<n-ellipsis :tooltip="false">
{{ item.name }}
</n-ellipsis>
</li>
</ul>
</div>
<!-- <button class="scroll__button">1</button> -->
</div>
</n-dropdown>
<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<div class="user_msg">
<n-image
class="user_avatar"
:src="getUserInfo.avatar"
preview-disabled
/>
<span class="user_name">{{ getUserInfo.realname }}</span>
</div>
</n-dropdown>
</div>
</n-layout-header>
</template>

<script>
import { defineComponent, reactive, toRefs, computed } from 'vue'
import { defineComponent, ref, reactive, toRefs, computed } from 'vue'
import { useRouter } from 'vue-router'
import { EditOutlined, LogoutOutlined } from '@vicons/antd'
import { renderIcon } from '@/utils'
import { useUserStore } from '@/store/modules/user.js'
import { useSettingStore } from '@/store/modules/setting.js'
import setting from '@/setting/config.js'
import { emergencyList } from '@/api/dashboard/index.js'
export default defineComponent({
name: 'LayoutHeader',
setup() {
const router = useRouter()
const userStore = useUserStore()
const settingStore = useSettingStore()
const scrollRef = ref()
const data = reactive({
options: [
{
label: '修改密码',
key: 'edit',
icon: renderIcon(EditOutlined)
},
// {
// label: '修改密码',
// key: 'edit',
// icon: renderIcon(EditOutlined)
// },
{
label: '退出登录',
key: 'out',
icon: renderIcon(LogoutOutlined)
}
],
platFormTitle: setting.title
platFormTitle: setting.title,
num: 0,
list: []
})

const getUserInfo = computed(() => {
@@ -70,17 +88,41 @@ export default defineComponent({
}
}

const inspectionSroll = async() => {
const viewNum = 1
if (data.list.length >= (viewNum + data.num)) {
scrollRef.value.style.top = -(data.num * 30) + 'px'
data.num++
} else {
data.num = 0
scrollRef.value.style.top = 0
}
}

const queryList = async() => {
const res = await emergencyList()
if (res.code === 0) {
data.list = res.data
}
}

setInterval(() => {
queryList()
inspectionSroll()
}, 3000)

return {
...toRefs(data),
getUserInfo,
getLogoWidth,
handleSelect
handleSelect,
scrollRef
}
}
})
</script>

<style scoped>
<style lang="scss" scoped>
.layout__header {
padding: 0 20px;
background: #36475D;
@@ -88,6 +130,38 @@ export default defineComponent({
align-items: center;
justify-content: space-between;
}
.header__tool{
display: flex;
align-items: center;
.header__scroll{
width: 150px;
margin-right: 50px;
position: relative;
}
.scroll__content{
width: 150px;
height: 30px;
overflow: hidden;
position: absolute;
top: -15px;
z-index: 99;
ul{
position: absolute;
transition: all .5s;
}
li{
width: 150px;
line-height: 30px;
color: rgba(255,255,255,1);
cursor: pointer;
}
}
.scroll__button{
position: absolute;
right: 0;
transform: translate(0,-50%);
}
}
.header__title{
display: flex;
justify-content: flex-start;

+ 69
- 14
src/views/dashboard/components/ControlPanel.vue Voir le fichier

@@ -7,10 +7,15 @@
<DoubleRightOutlined />
</n-icon>
<div class="crcle__panel">
<div class="pannel__item item-1" @click="handleClick(1)" />
<div class="pannel__item item-2" @click="handleClick(2)" />
<div class="pannel__item item-3" @click="handleClick(3)" />
<div class="pannel__item item-4" @click="handleClick(4)" />
<div
v-for="(item,index) in cameraList"
:key="index"
class="pannel__item"
:class="`item-${index+1}`"
@mousedown="handleEvent('down',item)"
@mouseup="handleEvent('up',item)"
@mouseleave="handleEvent('leave',item)"
/>
<n-icon class="top" size="24" color="#fff">
<CaretUpFilled />
</n-icon>
@@ -44,10 +49,15 @@
<DoubleRightOutlined />
</n-icon>
<div class="crcle__panel">
<div class="pannel__item item-1" @click="handleClick(1)" />
<div class="pannel__item item-2" @click="handleClick(1)" />
<div class="pannel__item item-3" @click="handleClick(1)" />
<div class="pannel__item item-4" @click="handleClick(1)" />
<div
v-for="(item,index) in locusList"
:key="index"
class="pannel__item"
:class="`item-${index+1}`"
@mousedown="handleEvent('down',item.list,item.key)"
@mouseup="handleEvent('up',item.list,item.key)"
@mouseleave="handleEvent('leave',item.list,item.key)"
/>
<n-icon class="top" size="24" color="#fff">
<UpOutlined />
</n-icon>
@@ -117,8 +127,9 @@ export default defineComponent({
default: () => ['camera', 'locus']
}
},
emits: ['start', 'reset'],
setup(props, { emit }) {
const camera = reactive({
const data = reactive({
cameraShow: true,
locusShow: true,
config: {
@@ -132,21 +143,64 @@ export default defineComponent({
{ label: '下降', key: 'down' },
{ label: '平移', key: 'move' },
{ label: '自旋', key: 'redo' }
]
],
cameraList: [
{ yuntai: '01' },
{ yuntai: '04' },
{ yuntai: '02' },
{ yuntai: '03' }
],
locusList: [
{ list: { yaogan: '08', pwm: '' }, key: 'up' },
{ list: { yaogan: '11', pwm: '' }, key: 'redo' },
{ list: { yaogan: '09', pwm: '' }, key: 'down' },
{ list: { yaogan: '10', pwm: '' }, key: 'redo' }
],
moveList: [
{ list: { yaogan: '06', pwm: '' }, key: 'move' },
{ list: { yaogan: '05', pwm: '' }, key: 'move' },
{ list: { yaogan: '07', pwm: '' }, key: 'move' },
{ list: { yaogan: '04', pwm: '' }, key: 'move' }
],
hasEvent: false
})

const getMode = computed(() => {
return isArray(props.mode) ? props.mode : [props.mode]
})

const handleClick = (num) => {
console.log(num)
const handleEvent = (event, params, key) => {
let reset = {}
if (key) {
params.pwm = data.config[key]
reset = { yaogan: '12', pwm: '200' }
} else {
reset = { yuntai: '09' }
}
switch (event) {
case 'down':
data.hasEvent = true
emit('start', params)
break
case 'up':
if (data.hasEvent) {
emit('reset', reset)
data.hasEvent = false
}
break
case 'leave':
if (data.hasEvent) {
emit('reset', reset)
data.hasEvent = false
}
break
}
}

return {
...toRefs(camera),
...toRefs(data),
getMode,
handleClick
handleEvent
}
}
})
@@ -183,6 +237,7 @@ export default defineComponent({
}
.n-icon{
position: absolute;
pointer-events: none;
&.top{
left: 50%;
top: 25%;

+ 0
- 253
src/views/dashboard/components/remoateSensing.vue Voir le fichier

@@ -1,253 +0,0 @@
<template>
<div class="remoate-sensing">
<div class="keyboard-mode">
<svg-icon
class="keyboard"
:icon-class="data.keyboardMode ? 'keyboard_active' : 'keyboard'"
@click="changeMode"
/>
</div>
<div class="height-controller base-extrinsic">
<click-controller
:lock="true"
:outer-radius="40 / data.remUnit"
:inner-radius="8 / data.remUnit"
:command="{ left: 'movingToLeft', right: 'movingToRight', down: 'falling', up: 'rising' }"
:keyboard-mode="data.keyboardMode"
:key-map="{ 87: 'up', 68: 'right', 83: 'down', 65: 'left' }"
@endAction="endCommand"
@executeAction="executeCommand"
>
<template #right>
<RedoOutlined />
</template>
<template #left>
<UndoOutlined />
</template>
</click-controller>
<div class="title">高度控制</div>
</div>
<div class="displacement-controller base-extrinsic">
<click-controller
:lock="true"
:outer-radius="40 / data.remUnit"
:inner-radius="8 / data.remUnit"
:command="{ left: 'rollingToLeft', right: 'rollingToRight', down: 'MovingToBack', up: 'movingToForward' }"
:keyboard-mode="data.keyboardMode"
:key-map="{ 38: 'up', 39: 'right', 40: 'down', 37: 'left' }"
@endAction="endCommand"
@executeAction="executeCommand"
/>
<div class="title">平移控制</div>
</div>
<div class="pwm">
<n-row :align="'middle'">
<n-col :span="7">
<span>上升:</span>
</n-col>
<n-col :span="17">
<n-input-number v-model:value="data.pwm.up" size="tiny" :bordered="false" />
</n-col>
</n-row>
<n-row :align="'middle'">
<n-col :span="7">
<span>下降:</span>
</n-col>
<n-col :span="17">
<n-input-number v-model:value="data.pwm.down" size="tiny" />
</n-col>
</n-row>
<n-row :align="'middle'">
<n-col :span="7">
<span>平移:</span>
</n-col>
<n-col :span="17">
<n-input-number v-model:value="data.pwm.translating" size="tiny" />
</n-col>
</n-row>
<n-row :align="'middle'">
<n-col :span="7">
<span>自旋:</span>
</n-col>
<n-col :span="17">
<n-input-number v-model:value="data.pwm.rotating" size="tiny" />
</n-col>
</n-row>
</div>

</div>
</template>

<script>
import ClickController from '../../../components/clickController.vue'
import { RedoOutlined, UndoOutlined } from '@vicons/antd'
import { ArrowUpCircleOutline, ArrowDownCircleOutline } from '@vicons/ionicons5'
import droneCommand from '../../../utils/droneCommand'
import { ref } from 'vue'
const remoateSensing = {
rollingToRight: '无人机右移',
movingToForward: '无人机前进',
MovingToBack: '无人机后退',
rollingToLeft: '无人机左移',
rising: '无人机爬升',
falling: '无人机下降',
movingToLeft: '无人机左旋',
movingToRight: '无人机右移'
}
export default {
components: {
ClickController,
RedoOutlined,
UndoOutlined
},
inject: ['droneInfo'],
emits: ['endCommand', 'executeCommand'],
setup(props, { emit }) {
const data = ref({
remUnit: parseFloat(document.documentElement.style.fontSize) || 4,
keyboardMode: false,
height: 5,
pwm: {
up: 200,
down: 50,
rotating: 75,
translating: 100
},
action: ''
})
function changeMode() {
data.value.keyboardMode = !data.value.keyboardMode
}
function endCommand() {
emit('command', { order: droneCommand.stopAction, msg: '停止' + remoateSensing[data.value.action] + '操作' })
}
function executeCommand(action) {
const command = droneCommand[action]
if (action === 'rising') {
command.PWM = data.value.pwm.up
} else if (action === 'falling') {
command.PWM = data.value.pwm.down
} else if (action === 'movingToLeft' || action === 'movingToRight') {
command.PWM = data.value.pwm.rotating
} else {
command.PWM = data.value.pwm.translating
}
data.value.action = action
emit('command', { order: command, msg: remoateSensing[action] + '(' + command.PWM + ')' })
}
function fixedHeight() {
if (!data.value.height) return
emit('command', { order: { toAlt: data.value.height }, msg: '飞行至' + data.value.height + 'M高度' })
}
return {
data,
changeMode,
endCommand,
executeCommand,
fixedHeight,
ArrowUpCircleOutline,
ArrowDownCircleOutline
}
}
}
</script>

<style lang="scss" scoped>
.remoate-sensing {
display: flex;
align-items: center;
font-size:12PX;
pointer-events: auto;
.fixed-height {
// padding: 5px;
// width: 180px;
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #fff;
}
.height {
margin-top: 10px;
display: flex;
align-items: center;
div {

color: #fff;
}
}
.btn {
cursor: pointer;
font-size: 14px;
height: 26px;
width: 80px;
margin-top: 15px;
appearance: none;
outline: none;
background: #007aff;
border: none;
color: #fff;
}
}
.base-extrinsic {
height: 100%;
width: 86px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;

.title {
color: #fff;
}
}
.pwm {
height: 100%;
width: 120px;
color: #fff;
display: flex;
flex-direction: column;
justify-content: space-evenly;
margin-right: 10px;
.ant-row.ant-row-middle{
margin-bottom: 3px;
}
span {
color: #fff;
}
}
.keyboard {
height: 40px;
width: 40px;
cursor: pointer;
}
input,.ant-input-number {
background: #3b3e45;
border: none;
outline: none !important;
width: 80px;
height: 20px;
margin-right: 2px;
color: #fff;
box-shadow: none;
font-size: 12px;
padding: 0 5px;
box-sizing: border-box;
&::selection {
background: transparent;
}
&::-moz-selection {
background: #fff;
}
&:focus {
outline: none;
background-color: #3b3e45;
}
}
.ant-input-number-input{
height:20px;
}
}
</style>

+ 2
- 23
src/views/dashboard/index.vue Voir le fichier

@@ -2,6 +2,7 @@
<div class="basic">
<OneMap ref="Map" />
<Extend ref="extendRef" class="extend" @send="getmessage" />

</div>
</template>

@@ -30,27 +31,6 @@ export default {
ground_station_url: 'xxxxxxxxxxxxxxx'
}
})
function setCommandAndLog(params, errorMsg) {
// 权限认证
if (data.value.currentDroneInfo.auth === 1) {
$message.warning('用户无该机场操作权限!')
return
}
const base = { sid: data.value.currentDroneInfo.ground_station_url }
return this.$http.post('/airportControl/droneCommand', Object.assign(params, base)).then(res => {
if (res.data.code === 0) {
const data = res.data.data
if (data.value) {
// this.logList.unshift({ value: data.value, createTime: data.createTime, status: data.status, id: Date.now() })
}
return data
} else {
$message.error(errorMsg || res.data.msg)
}
}).catch(e => {
$message.error(errorMsg || e.message)
})
}
onMounted(() => {
extendRef.value.handleClick(0)
})
@@ -59,8 +39,7 @@ export default {
toSystem,
extendRef,
getmessage,
Map,
setCommandAndLog
Map
}
}
}

+ 3
- 1
src/views/early-warning/fire/components/FireModal.vue Voir le fichier

@@ -23,9 +23,10 @@
</n-gi>
</n-grid>
<p class="title">火灾核实记录</p>
<div>
<div class="content">
<p v-for="(item,index) in fireDetail.warningRecordVOList" :key="index" class="content">
{{ `${item.recordStartTime} ${item.airportName}执行任务,` }}
<span>查看详情</span>
</p>
</div>
<p class="title">处理记录</p>
@@ -119,6 +120,7 @@ export default defineComponent({
}
.content{
padding: 0 5px;
min-height: 32px;
font-size: 16px;
}
</style>

+ 2
- 2
src/views/task-manage/all-task/tools/table.js Voir le fichier

@@ -9,7 +9,7 @@ const tableRef = ref()
const searchParams = ref()

function handleSearch(params) {
searchParams.value = { ...params }
searchParams.value = { ...params, type: 1 }
tableRef.value.reFetch({ searchParams })
}

@@ -208,7 +208,7 @@ const data = reactive({
onClick: handleTaskDemand.bind(null, row)
},
auth: 'basic_list',
show: row.status === 4
show: row.status === 4 && row.aiVideoUrl && row.videoUrl
},
{
label: '问题核实',

Chargement…
Annuler
Enregistrer