【类 型】:feat
【原 因】:1飞行数据删除功能 2导航栏取消添加 对拼等子页面显示 放到列表页显示 3.通过选飞机 直接到对拼页面 【过 程】: 【影 响】:
This commit is contained in:
parent
241a418e59
commit
8d06b53183
@ -243,7 +243,7 @@ export default {
|
||||
if (this.enableSaveToFile && typeof this.getData === 'function') {
|
||||
this.map.addControl(new SaveToFileControl({
|
||||
Data: this.getData,
|
||||
filename: `export_${Date.now()}.json`,
|
||||
filename: `飞行数据_${Date.now()}.json`,
|
||||
title: '保存当前数据',
|
||||
icon: '💾'
|
||||
}), 'top-left')
|
||||
@ -984,7 +984,7 @@ export default {
|
||||
* @param {obj} lonLat {lon:lon,lat:lat} 经纬度
|
||||
* @param {Number} zoom 地图放大率
|
||||
*/
|
||||
goto (lonLat, zoom = 18) {
|
||||
goto (lonLat, zoom = 12) {
|
||||
this.map.flyTo({
|
||||
center: lonLat,
|
||||
zoom: zoom,
|
||||
|
@ -87,7 +87,8 @@ const routes = [
|
||||
title: '机型添加',
|
||||
icon: 'el-icon-plus',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
tapName: 'plane',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -131,7 +132,8 @@ const routes = [
|
||||
title: '飞机添加',
|
||||
icon: 'el-icon-plus',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
tapName: 'plane',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -146,13 +148,14 @@ const routes = [
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/register/crosFrequency',
|
||||
path: '/register/crosFrequency/:shop_id/:plane_id',
|
||||
component: () => import('@/views/layout/components/main/register/crosFrequency'),
|
||||
meta: {
|
||||
title: '飞机对频',
|
||||
icon: 'el-icon-link',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
tapName: 'plane',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -273,7 +276,8 @@ const routes = [
|
||||
title: '站点添加',
|
||||
icon: 'el-icon-plus',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'plane'
|
||||
tapName: 'plane',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -383,7 +387,8 @@ const routes = [
|
||||
title: '账户添加',
|
||||
icon: 'iconfont icon-xinzengguanliyuan',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'admin'
|
||||
tapName: 'admin',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -461,7 +466,8 @@ const routes = [
|
||||
title: 'SPU添加',
|
||||
icon: 'iconfont icon-huoquchanpin',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'admin'
|
||||
tapName: 'admin',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -492,7 +498,8 @@ const routes = [
|
||||
title: 'SKU添加',
|
||||
icon: 'iconfont icon-sku1',
|
||||
roles: ['admin', 'editor'],
|
||||
tapName: 'admin'
|
||||
tapName: 'admin',
|
||||
hidden: true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1 +1 @@
|
||||
@import 'https://at.alicdn.com/t/c/font_3703467_17bw22w7wt3g.css'; //iconfont阿里巴巴
|
||||
@import 'https://at.alicdn.com/t/c/font_3703467_6zigre3tbm3.css'; //iconfont阿里巴巴
|
@ -178,6 +178,23 @@ export async function getFlyData (idArr, startTime, endTime) {
|
||||
const res = await api.post('getFlyDataByIdArr', params, 'Plane')
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract 删除指定的飞行数据记录
|
||||
* @param {Array} idArr 飞行数据记录ID数组
|
||||
* @returns 删除结果
|
||||
*/
|
||||
export async function deleteFlyData (idArr) {
|
||||
if (!Array.isArray(idArr) || idArr.length === 0) {
|
||||
throw new Error('参数错误,idArr 应为非空数组')
|
||||
}
|
||||
|
||||
const params = new URLSearchParams()
|
||||
params.append('idArr', idArr.join(',')) // 逗号分隔传给后端
|
||||
|
||||
const res = await api.post('deleteFlyDataByIdArr', params, 'Plane')
|
||||
return res
|
||||
}
|
||||
/**
|
||||
* @abstract 上传保存飞机飞行数据(解锁至加锁 即飞行结束触发)
|
||||
* @param {Object} data 包含 id, start_time, end_time, gps_path, distance, power_used
|
||||
|
@ -160,9 +160,7 @@ export function formatPrice (value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待 Mapbox 地图的画布容器(Canvas Container)准备就绪。
|
||||
* 因为 Mapbox 初始化是异步的,某些操作需要等待画布容器加载完成才能执行。
|
||||
*
|
||||
* @description:等待 Mapbox 地图的画布容器(Canvas Container)准备就绪。因为 Mapbox 初始化是异步的,某些操作需要等待画布容器加载完成才能执行。
|
||||
* @param {Object} map - Mapbox GL JS 地图实例对象
|
||||
* @param {number} maxRetry - 最大重试次数,防止无限等待,默认5次
|
||||
* @returns {Promise<HTMLElement>} 返回一个 Promise,成功时返回画布容器元素,失败时抛出错误
|
||||
@ -192,3 +190,32 @@ export function waitForMapCanvasReady (map, maxRetry = 5) {
|
||||
check(maxRetry)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 把对象保存为 JSON 文件并触发下载
|
||||
* @param {*} data - 要保存的对象数据
|
||||
* @param {string} filename - 下载的文件名,默认为 data_时间
|
||||
*/
|
||||
export function saveObjectToFile (data, filename = `data_${Date.now()}.json`) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
alert('无效的数据对象')
|
||||
return
|
||||
}
|
||||
|
||||
// 将对象格式化为 JSON 字符串
|
||||
const content = JSON.stringify(data, null, 2)
|
||||
|
||||
// 创建 Blob 对象
|
||||
const blob = new Blob([content], { type: 'application/json' })
|
||||
|
||||
// 创建一个临时下载链接
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = filename
|
||||
|
||||
// 模拟点击以触发下载
|
||||
link.click()
|
||||
|
||||
// 释放资源
|
||||
URL.revokeObjectURL(link.href)
|
||||
}
|
||||
|
@ -12,31 +12,27 @@
|
||||
<el-main class="border p-20">
|
||||
<el-form label-width="120px">
|
||||
<el-form-item label="物理ID">
|
||||
<el-tag :type="macAdd === null ? 'danger' : ''">{{ macAdd === null ? 'NoThing' : macAdd }}</el-tag>
|
||||
<el-tag :type="macAdd === null ? 'danger' : ''">
|
||||
{{ macAdd === null ? 'NoThing' : macAdd }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商铺分配">
|
||||
<el-select v-model="shop_id" filterable placeholder="请选择" @blur="air_id = ''; disabled = true"
|
||||
:disabled="macAdd === null ? true : false">
|
||||
<el-option v-for="item in shopList" :key="item.id" :label="item.name" :value="item.shop_id">
|
||||
<el-avatar class="vm" shape="square" :size="25"
|
||||
:src="$store.state.settings.host + '/Data/UploadFiles/logo/' + item.logo">
|
||||
</el-avatar>
|
||||
<span class="rspan">{{ item.name }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<span>{{ getShopName(shop_id) }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="飞机列表">
|
||||
<el-radio-group v-if="airList.length != 0" v-model="air_id" @change="disabled = false;">
|
||||
<el-radio class="m-b-10 m-l-0" v-for="item in airList" :key="item.id" :label="item.id" border>
|
||||
{{ item.name }}
|
||||
{{ item.macadd }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<span v-else>No data</span>
|
||||
|
||||
<el-form-item label="飞机信息">
|
||||
<span>{{ getAirName(plane_id) }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button icon="iconfont icon-jiekou m-r-5" :type="macAdd === null ? 'info' : 'primary'"
|
||||
@click="onSubmit" :disabled="macAdd === null ? 'disabled' : false">对频
|
||||
<el-button
|
||||
icon="iconfont icon-jiekou m-r-5"
|
||||
:type="macAdd === null ? 'info' : 'primary'"
|
||||
@click="onSubmit"
|
||||
:disabled="macAdd === null"
|
||||
>
|
||||
对频
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -44,7 +40,6 @@
|
||||
</el-container>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -56,54 +51,63 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
shop_id: null,
|
||||
air_id: null
|
||||
plane_id: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 获取商铺列表
|
||||
shopList () {
|
||||
return this.$store.state.shopList
|
||||
},
|
||||
// 过滤掉 不对应客户的 飞机列表
|
||||
airList () {
|
||||
return this.$store.state.airList.filter((item) => item.shop_id === this.shop_id)
|
||||
return this.$store.state.airList
|
||||
},
|
||||
// 对频信息 物理地址
|
||||
macAdd () {
|
||||
return this.$store.state.crosFrequency
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.shop_id = this.$route.params.shop_id
|
||||
this.plane_id = this.$route.params.plane_id
|
||||
console.log('shop_id:', this.shop_id, 'plane_id:', this.plane_id)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Description: 检查飞机发布过来的 mac地址 是否已经存在
|
||||
* @Return: bool
|
||||
* 获取商铺名称
|
||||
*/
|
||||
isMacAdd () {
|
||||
let b = false
|
||||
this.$store.state.airList.map((item) => {
|
||||
if (item.macadd === this.macAdd) {
|
||||
b = true
|
||||
}
|
||||
})
|
||||
return b
|
||||
getShopName (id) {
|
||||
const shop = this.shopList.find(item => item.shop_id === id)
|
||||
return shop ? shop.name : '未知商铺'
|
||||
},
|
||||
/**
|
||||
* @description: 提交表单
|
||||
* 获取飞机名称和 mac 地址
|
||||
*/
|
||||
getAirName (id) {
|
||||
const air = this.airList.find(item => item.id === id)
|
||||
return air ? `${air.name}` : '未知飞机'
|
||||
},
|
||||
/**
|
||||
* 检查是否已有同名 mac 地址
|
||||
*/
|
||||
isMacAdd () {
|
||||
return this.airList.some(item => item.macadd === this.macAdd)
|
||||
},
|
||||
/**
|
||||
* 提交表单
|
||||
*/
|
||||
onSubmit () {
|
||||
const params = { macAdd: this.macAdd, id: this.air_id }
|
||||
const params = { macAdd: this.macAdd, id: this.plane_id }
|
||||
if (this.isMacAdd()) {
|
||||
this.$confirm('已经有同名mac地址,请谨慎操作?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
apiCrosFrequency(params)// 对频
|
||||
apiCrosFrequency(params)
|
||||
}).catch(() => {
|
||||
this.$message.info('取消对频')
|
||||
})
|
||||
} else {
|
||||
apiCrosFrequency(params)// 对频
|
||||
apiCrosFrequency(params)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,6 +118,6 @@ export default {
|
||||
.rspan {
|
||||
float: right;
|
||||
color: #8492a6;
|
||||
font-size: 13px
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
|
364
src/views/layout/components/main/register/flyData copy.vue
Normal file
364
src/views/layout/components/main/register/flyData copy.vue
Normal file
@ -0,0 +1,364 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="fly-data-wrapper">
|
||||
<div class="top-bar">
|
||||
<DateRangePicker v-model="dateRange" class="m-r-20 m-b-20" />
|
||||
<el-radio-group v-model="radioClass">
|
||||
<el-radio-button label="作业架次"></el-radio-button>
|
||||
<el-radio-button label="飞行时长"></el-radio-button>
|
||||
<el-radio-button label="飞行距离"></el-radio-button>
|
||||
<el-radio-button label="消耗电量"></el-radio-button>
|
||||
<el-radio-button label="飞行轨迹"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="chart-area" v-if="flyDataList.length">
|
||||
<div v-if="boxShow" id="main" class="chart-container"></div>
|
||||
<map-box v-else ref="mapbox" @map-ready="onMapReady" :enableSaveToFile="true" :getData="() => flyDataList"/>
|
||||
</div>
|
||||
<div v-else class="no-data-tip">暂无数据</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import MapBox from '@/components/MapBox'
|
||||
import { getFlyData } from '@/utils/api/table'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
export default {
|
||||
name: 'FlyData',
|
||||
data () {
|
||||
const end = new Date()
|
||||
end.setHours(23, 59, 59, 999)
|
||||
const start = new Date()
|
||||
start.setDate(end.getDate() - 6)
|
||||
start.setHours(0, 0, 0, 0)
|
||||
|
||||
return {
|
||||
flyDataList: [],
|
||||
selectedPlaneIdArr: this.$store.state.app.toFlyDataIdArr,
|
||||
dateRange: [start, end],
|
||||
radioClass: '飞行时长',
|
||||
boxShow: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
DateRangePicker,
|
||||
MapBox
|
||||
},
|
||||
computed: {
|
||||
source () {
|
||||
if (!this.flyDataList.length) return []
|
||||
const start = this.dateRange[0]
|
||||
const end = this.dateRange[1]
|
||||
const rangeInMs = end - start
|
||||
const oneDay = 24 * 60 * 60 * 1000
|
||||
const oneYear = 365 * oneDay
|
||||
|
||||
let groupBy = 'day'
|
||||
if (rangeInMs > oneYear) {
|
||||
groupBy = 'year'
|
||||
} else if (rangeInMs > 30 * oneDay) {
|
||||
groupBy = 'month'
|
||||
}
|
||||
|
||||
const formatMap = {
|
||||
day: (d) => `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`,
|
||||
month: (d) => `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}`,
|
||||
year: (d) => `${d.getFullYear()}`
|
||||
}
|
||||
const formatFn = formatMap[groupBy]
|
||||
|
||||
const timeLabels = []
|
||||
const cursor = new Date(start.getTime())
|
||||
const endTime = end.getTime()
|
||||
|
||||
while (cursor.getTime() <= endTime) {
|
||||
timeLabels.push(formatFn(new Date(cursor)))
|
||||
if (groupBy === 'day') {
|
||||
cursor.setDate(cursor.getDate() + 1)
|
||||
} else if (groupBy === 'month') {
|
||||
cursor.setMonth(cursor.getMonth() + 1)
|
||||
} else if (groupBy === 'year') {
|
||||
cursor.setFullYear(cursor.getFullYear() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const groupedData = {}
|
||||
|
||||
const keyMap = {
|
||||
飞行时长: (item) => {
|
||||
if (!item.start_time || !item.end_time) return 0
|
||||
return Math.round((item.end_time - item.start_time) / 60) // 秒转分钟
|
||||
},
|
||||
飞行距离: (item) => Number(item.distance || 0),
|
||||
消耗电量: (item) => Number(item.power_used || 0),
|
||||
作业架次: () => 1 // 作业架次就是统计条数,固定1
|
||||
}
|
||||
|
||||
if (this.radioClass === '飞行轨迹') return []// 不处理轨迹数据
|
||||
|
||||
this.flyDataList.forEach(item => {
|
||||
const planeName = item.plane_name
|
||||
const date = new Date(item.start_time * 1000)
|
||||
const key = formatFn(date)
|
||||
|
||||
if (!groupedData[planeName]) groupedData[planeName] = {}
|
||||
if (!groupedData[planeName][key]) groupedData[planeName][key] = 0
|
||||
|
||||
groupedData[planeName][key] += keyMap[this.radioClass](item)
|
||||
})
|
||||
|
||||
const source = [['product', ...timeLabels]]
|
||||
|
||||
for (const planeName in groupedData) {
|
||||
const row = [planeName]
|
||||
for (const label of timeLabels) {
|
||||
row.push(groupedData[planeName][label] || 0)
|
||||
}
|
||||
source.push(row)
|
||||
}
|
||||
|
||||
return source
|
||||
},
|
||||
series () {
|
||||
const lineSeries = this.source.slice(1).map(() => ({
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
seriesLayoutBy: 'row',
|
||||
emphasis: { focus: 'series' }
|
||||
}))
|
||||
|
||||
const firstColumn = this.source[0]?.[1] || ''
|
||||
if (!firstColumn) return lineSeries
|
||||
|
||||
const pieSeries = {
|
||||
type: 'pie',
|
||||
id: 'pie',
|
||||
radius: '30%',
|
||||
center: ['50%', '25%'],
|
||||
emphasis: { focus: 'self' },
|
||||
label: {
|
||||
formatter: `{b}: {@[${firstColumn}]} ({d}%)`
|
||||
},
|
||||
encode: {
|
||||
itemName: 'product',
|
||||
value: firstColumn,
|
||||
tooltip: firstColumn
|
||||
}
|
||||
}
|
||||
|
||||
return [...lineSeries, pieSeries]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
watch: {
|
||||
flyDataList (newVal) {
|
||||
// 图表销毁和初始化
|
||||
if (!newVal.length && this.myChart) {
|
||||
this.myChart.dispose()
|
||||
this.myChart = null
|
||||
} else if (newVal.length) {
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
}
|
||||
// 多个飞机轨迹全部绘制
|
||||
if (!this.boxShow && newVal.length) {
|
||||
this.onMapReady()
|
||||
}
|
||||
},
|
||||
boxShow (val) {
|
||||
if (!val) {
|
||||
this.onMapReady()
|
||||
}
|
||||
},
|
||||
dateRange: {
|
||||
handler () {
|
||||
this.loadFlyData()
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
source (newVal) {
|
||||
if (Array.isArray(newVal) && newVal.length > 1) {
|
||||
this.initChart()
|
||||
}
|
||||
},
|
||||
radioClass (val) {
|
||||
if (val === '飞行轨迹') {
|
||||
this.boxShow = false
|
||||
} else {
|
||||
this.boxShow = true
|
||||
this.$nextTick(() => {
|
||||
this.initChart()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 地图组件回调地图加载完成后执行
|
||||
onMapReady () {
|
||||
this.drawAllPathsOnMap()
|
||||
},
|
||||
// 地图轨迹绘制
|
||||
drawAllPathsOnMap () {
|
||||
if (!this.$refs.mapbox) return
|
||||
|
||||
// 清理旧轨迹
|
||||
this.$refs.mapbox.clearMapElements(['path'], ['path'])
|
||||
|
||||
// 遍历所有飞行数据,绘制轨迹
|
||||
this.flyDataList.forEach(item => {
|
||||
if (!item.gps_path) return
|
||||
try {
|
||||
const pathArray = JSON.parse(item.gps_path)
|
||||
if (Array.isArray(pathArray) && pathArray.length > 0) {
|
||||
this.$refs.mapbox.createPathWithArray(pathArray)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('gps_path 解析失败', item.gps_path)
|
||||
}
|
||||
})
|
||||
|
||||
// 跳转到第一个轨迹的起点(经纬度)
|
||||
if (this.flyDataList.length > 0 && this.flyDataList[0].gps_path) {
|
||||
try {
|
||||
const firstPath = JSON.parse(this.flyDataList[0].gps_path)
|
||||
if (Array.isArray(firstPath) && firstPath.length > 0) {
|
||||
const [lon, lat] = firstPath[0]
|
||||
this.$refs.mapbox.goto({ lon, lat })
|
||||
}
|
||||
} catch (e) {
|
||||
// 解析失败不跳转
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取飞行数据
|
||||
async loadFlyData () {
|
||||
if (this.selectedPlaneIdArr.length === 0) {
|
||||
this.$router.push('/register/index')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.dateRange || this.dateRange.length !== 2) {
|
||||
this.$message.warning('请选择日期范围')
|
||||
return
|
||||
}
|
||||
|
||||
const startTimestamp = Math.floor(this.dateRange[0].getTime() / 1000)
|
||||
const endTimestamp = Math.floor(this.dateRange[1].getTime() / 1000)
|
||||
|
||||
const res = await getFlyData(this.selectedPlaneIdArr, startTimestamp, endTimestamp)
|
||||
if (res.data.status === 1) {
|
||||
this.flyDataList = res.data.dataList
|
||||
} else {
|
||||
this.$message.error(res.data.msg)
|
||||
}
|
||||
},
|
||||
initChart () {
|
||||
const chartDom = document.getElementById('main')
|
||||
if (!chartDom) return
|
||||
|
||||
if (this.myChart) {
|
||||
this.myChart.dispose()
|
||||
}
|
||||
|
||||
this.myChart = echarts.init(chartDom)
|
||||
|
||||
const firstColumnIndex = 1
|
||||
|
||||
this.myChart.setOption({
|
||||
legend: {},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
showContent: true
|
||||
},
|
||||
dataset: {
|
||||
source: this.source
|
||||
},
|
||||
xAxis: { type: 'category' },
|
||||
yAxis: {
|
||||
gridIndex: 0,
|
||||
name: this.radioClass === '飞行时长' ? '分钟' : this.radioClass === '飞行距离' ? '米' : this.radioClass === '消耗电量' ? '毫安' : (this.radioClass === '作业架次' ? '次' : '')
|
||||
},
|
||||
grid: { top: '55%' },
|
||||
series: [
|
||||
...this.source.slice(1).map(() => ({
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
seriesLayoutBy: 'row',
|
||||
emphasis: { focus: 'series' }
|
||||
})),
|
||||
{
|
||||
type: 'pie',
|
||||
id: 'pie',
|
||||
radius: '30%',
|
||||
center: ['50%', '25%'],
|
||||
emphasis: { focus: 'self' },
|
||||
label: {
|
||||
formatter: `{b}: {@[${firstColumnIndex}]} ({d}%)`
|
||||
},
|
||||
encode: {
|
||||
itemName: 'product',
|
||||
value: firstColumnIndex,
|
||||
tooltip: firstColumnIndex
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
this.myChart.on('updateAxisPointer', (event) => {
|
||||
const xAxisInfo = event.axesInfo[0]
|
||||
if (xAxisInfo) {
|
||||
const dimension = xAxisInfo.value + 1
|
||||
this.myChart.setOption({
|
||||
series: {
|
||||
id: 'pie',
|
||||
label: {
|
||||
formatter: `{b}: {@[${dimension}]} ({d}%)`
|
||||
},
|
||||
encode: {
|
||||
value: dimension,
|
||||
tooltip: dimension
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
this.myChart.resize()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/theme.scss";
|
||||
|
||||
.fly-data-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
flex: 0 0 auto;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.chart-area {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -8,9 +8,10 @@
|
||||
</span>
|
||||
<!-- 组合按钮 -->
|
||||
<el-button-group class="m-r-20 m-b-20">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="$router.replace('/site/add')">详情保存</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete"
|
||||
@click="deleteSite(countSelIdArr($refs.myTable.selection))">删除</el-button>
|
||||
<el-button type="primary" icon="iconfont icon-save-3-fill" @click="saveDataTOFile()">
|
||||
<font class="m-l-5">详情保存</font>
|
||||
</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="delFlyData()">删除</el-button>
|
||||
</el-button-group>
|
||||
<!-- 项目选择 -->
|
||||
<el-radio-group v-model="radioClass" class="m-r-20 m-b-20">
|
||||
@ -39,8 +40,9 @@
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import MapBox from '@/components/MapBox'
|
||||
import { getFlyData } from '@/utils/api/table'
|
||||
import { getFlyData, deleteFlyData } from '@/utils/api/table'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
import { saveObjectToFile } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'FlyData',
|
||||
@ -220,6 +222,41 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 删除飞行数据
|
||||
async delFlyData () {
|
||||
if (this.flyDataList.length === 0) {
|
||||
this.$message.warning('暂无数据可删除')
|
||||
return
|
||||
}
|
||||
const idArr = this.flyDataList.map(item => item.id)
|
||||
|
||||
this.$confirm('是否确认删除所有飞行数据?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
const res = await deleteFlyData(idArr)
|
||||
|
||||
if (res.data.status === 1) {
|
||||
this.$message.success(`飞行数据已删除: ${res.data.total} 条`)
|
||||
this.flyDataList = [] // 前端清空
|
||||
} else {
|
||||
this.$message.error(res.message || '删除失败')
|
||||
}
|
||||
this.flyDataList = []
|
||||
}).catch(() => {
|
||||
this.$message.info('已取消删除')
|
||||
})
|
||||
},
|
||||
// 保存数据到文件
|
||||
saveDataTOFile () {
|
||||
if (this.flyDataList.length === 0) {
|
||||
this.$message.warning('暂无数据可保存')
|
||||
return
|
||||
}
|
||||
const fileName = `飞行数据_${new Date().toISOString().slice(0, 10)}.json`
|
||||
saveObjectToFile(this.flyDataList, fileName)
|
||||
},
|
||||
// 地图组件回调地图加载完成后 执行
|
||||
onMapReady () {
|
||||
this.drawAllHistoricalPaths()
|
||||
|
@ -46,15 +46,16 @@
|
||||
{{ scope.row.apply_time | parseTime('{y}-{m}-{d}') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="controler" label="操作" width="380" min-width="380">
|
||||
<el-table-column prop="controler" label="操作" width="460" min-width="460">
|
||||
<template slot-scope="scope">
|
||||
<el-button-group>
|
||||
<el-button type="primary" class="iconfont icon-youxishoubing"
|
||||
@click="$router.replace(`/planes/index/${scope.row.id}/${scope.row.name}`)"><span
|
||||
class="m-l-5">操作</span></el-button>
|
||||
class="m-l-5">控制</span></el-button>
|
||||
<el-button type="warning" icon="el-icon-edit"
|
||||
@click="$router.replace(`/register/edit/${scope.row.id}`)">编辑</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="deleteAir([scope.row.id])">删除</el-button>
|
||||
<el-button type="success" icon="el-icon-link" @click="crosFrequencyToPage(form.shop_id,scope.row.id)">对频</el-button>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -149,6 +150,12 @@ export default {
|
||||
*/
|
||||
deleteAir (idArr) {
|
||||
this.$store.dispatch('fetchDelAir', idArr)
|
||||
},
|
||||
/**
|
||||
* @description: 跳转到对频页面
|
||||
*/
|
||||
crosFrequencyToPage (shopId, planeId) {
|
||||
this.$router.push(`/register/crosFrequency/${shopId}/${planeId}`)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
45
src/views/layout/components/main/video/index.vue
Normal file
45
src/views/layout/components/main/video/index.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<video
|
||||
ref="video"
|
||||
autoplay
|
||||
controls
|
||||
playsinline
|
||||
muted
|
||||
width="640"
|
||||
height="360"
|
||||
></video>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
url: 'http://82.156.122.87:80/rtc/v1/whep/?app=live&stream=083AF27BB2D0',
|
||||
sdk: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.startPlay()
|
||||
},
|
||||
methods: {
|
||||
async startPlay () {
|
||||
if (this.sdk) {
|
||||
this.sdk.close()
|
||||
this.sdk = null
|
||||
}
|
||||
|
||||
this.sdk = new window.SrsRtcWhipWhepAsync()
|
||||
this.$refs.video.srcObject = this.sdk.stream
|
||||
|
||||
try {
|
||||
const session = await this.sdk.play(this.url)
|
||||
console.log('播放成功,session:', session)
|
||||
} catch (e) {
|
||||
console.error('播放失败', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user