提交 6c7a4d81 作者: 翁进城

补充README.md,优化项目架构

上级 dcb90362
.DS_Store
node_modules
!/node_modeuls/mmc/*
/dist
......
# 标准化鹰视模组
## 项目描述
基于城市之鹰的前端标准化组件库
## 项目部署
* yarn
`yarn ` 安装依赖
`yarn serve` 启动本地服务
`yarn dev:xx` 启动基于配置文件的本地服务
`yarn build` 构建生产包
`yarn build:xx` 构建基于配置文件的生产包
* npm&cnpm
`npm i` 安装依赖
`npm run serve` 启动本地服务
`npm run dev:xx` 启动基于配置文件的本地服务
`npm run build` 构建生产包
`npm run build:xx` 构建基于配置文件的生产包
## npm调试组件方法
* npm link (将npm包链接到本地全局目录(node_modules)下面)
* cd vue2 后执行 npm link mmc-stl-vue2 (在主项目中引用上一步挂到全局的软链接)
## 备注
生成目录树请安装
`npm install -g tree-node-cli`
执行以下命令生成
`treee -I "node_modules|.idea|objects|.git|.vscode|dist|.png|.jpg|.svg|.gif|.mp4|cesium|index.vue|index.js" -a > tree.txt --dirs-first -d -L 3`
## 项目结构
├── src 组件源码
│ ├── assets 资源文件
│ │ └── img
│ │ ├── fckernel
│ │ ├── home
│ │ ├── mount
│ │ ├── nest
│ │ ├── nest_v2
│ │ └── weather
│ ├── components 组件库
│ │ ├── MMCCodeDemo 源码案例组件
│ │ ├── MMCDataTransferPanel 数值面板组件
│ │ │ ├── assets
│ │ │ ├── components
│ │ │ ├── controlList
│ │ │ ├── controlMenu
│ │ │ ├── logger
│ │ │ └── videoTomap
│ │ ├── MMCPlayer 播放器组件
│ │ │ ├── assets
│ │ │ ├── components
│ │ │ └── lib
│ │ ├── MMCUavList 无人机列表组件
│ │ │ └── item
│ │ └── symbol-icon
│ ├── directives 指令库
│ ├── lib js依赖库
│ ├── observe
│ │ ├── fckernel
│ │ │ ├── methods
│ │ │ ├── nest
│ │ │ └── uav
│ │ └── fckernelVideos
│ │ ├── components
│ │ ├── data
│ │ └── methods
│ ├── plugins
│ │ └── MMCMQTT mqtt插件
│ └── style 全局样式
│ └── fonts
├── types ts需要的types
└── vue2 案例网站源码
├── public
│ ├── js
│ └── liveplayer
└── src
├── assets
├── components 公共组件
├── router 路由
└── views 页面
├── dataTransferPanel 数传面板页面
├── mount 挂载页面
├── mqtt mqtt页面
├── player 播放器页面
└── uavList 无人机列表页面
......@@ -107,6 +107,7 @@ export default {
}
}
.ball_box {
position: relative;
box-sizing: border-box;
width: 150px;
height: 150px;
......
<template>
<div class="throttle-gauge">
<PositionBall class="ball" :uav-data="uavData" />
<ThrottleValue :value="throttleValue" style="position: absolute; left: -70px; top: -70px;"></ThrottleValue>
<img class="img1" src="../../assets/ball2.png" />
<img class="img2" src="../../assets/ball2.png" />
</div>
</template>
<script>
import PositionBall from "../ball/index";
import ThrottleValue from "../throttleValue";
export default {
name: "throttleGauge",
components: {
PositionBall,
ThrottleValue,
},
props: {
uavData: {
type: Object,
default() {
return {};
},
},
throttleValue: {
type: Number,
default: 500,
},
},
};
</script>
<style scoped>
.throttle-gauge {
position: relative;
}
.img1 {
position: absolute;
left: -11px;
top: 34px;
width: 8px;
height: 9px;
z-index: 9999;
transform: rotate(110deg);
}
.img2 {
position: absolute;
left: -7px;
top: 36px;
width: 8px;
height: 9px;
z-index: 9999;
transform: rotate(-67deg);
}
</style>
\ No newline at end of file
<template>
<div class="w270 h270" id="ymfzDom"></div>
<div style="width: 270px; height: 270px;" ref="chart"></div>
</template>
<script>
let echarts = require("echarts");
export default {
name: 'throttleValue',
props: {
channelData: {
type: Object,
default: () => ({}),
value: {
type: Number,
default: 0,
},
},
data() {
......@@ -75,10 +76,13 @@ export default {
},
watch: {
channelData: {
value: {
immediate: true,
handler(value) {
if (value?.accelerator !== undefined) {
this.updateDom(value.accelerator);
if (value !== undefined) {
this.$nextTick(() => {
this.updateDom(value);
})
}
},
deep: true,
......@@ -90,12 +94,12 @@ export default {
},
methods: {
init() {
let chartDom = document.getElementById("ymfzDom");
let chartDom = this.$refs.chart;
let myChart = echarts.init(chartDom);
myChart.setOption(this.option);
},
updateDom(value) {
let chartDom = document.getElementById("ymfzDom");
let chartDom = this.$refs.chart;
let myChart = echarts.init(chartDom);
let value1 = value / 10;
let value2 = 100 - value1;
......@@ -163,10 +167,5 @@ export default {
};
</script>
<style>
#ymfzDom {
position: absolute;
left: -100px;
top: -32x;
}
<style scoped>
</style>
\ No newline at end of file
<!-- 飞控新版鹰视1027 -->
<template>
<div class="nest_controlBox">
<PositionBall class="pa ding" :uav-data="uavData" />
<ymfz :channelData="data"> </ymfz>
<img class="img2" src="./assets/ball2.png" />
<img class="img3" src="./assets/ball2.png" />
<div class="w900 h78 nest_control">
<throttleGauge :uavData="uavData" :throttleValue="throttleValue" style="transform: translateX(35px);"></throttleGauge>
<div class="nest_control">
<Info class="" :uav-data="uavData" :wsShow="wsShow" :isM300="device.goodsName == 'M300'"></Info>
<div class="xian" v-if="!device.goodsName == 'M300'"></div>
<battery v-if="uavBattery" :uav-battery="uavBattery" :device="device"></battery>
</div>
<div class="bizhang">
<obstacle :uav-data="uavData"></obstacle>
</div>
<obstacle :uav-data="uavData" style="transform: translateX(-35px);"></obstacle>
</div>
</template>
<script>
import PositionBall from "./components/ball/index";
import throttleGauge from './components/throttleGauge';
import Info from "./components/info/index";
import battery from "./components/battery/index";
import ymfz from "./components/ymfz";
import obstacle from "./components/obstacle";
export default {
......@@ -37,9 +30,9 @@ export default {
type: Object,
default: () => ({})
},
data: {
type: Object,
default: () => ({})
throttleValue: {
type: Number,
default: 0
},
device: {
type: Object,
......@@ -52,9 +45,8 @@ export default {
}
}
},
components: { PositionBall, Info, battery, ymfz, obstacle },
components: { Info, battery, obstacle, throttleGauge },
mounted(){
console.log(this.device,"infodevice");
},
computed: {
props_obj() {
......@@ -72,30 +64,13 @@ export default {
justify-content: center;
align-items: center;
pointer-events: none;
padding: 0 0px 0px 20px;
.nest_control {
display: flex;
align-items: center;
background: rgba(9, 32, 87, 0.7);
padding: 0 50px;
}
.img2{
position: absolute;
left: -36px;
top: calc(35%);
width: 8px;
height: 9px;
z-index: 9999;
transform: rotate(-75deg);
}
.img3{
position: absolute;
left: -40px;
top: calc(34%);
width: 8px;
height: 9px;
z-index: 9999;
transform: rotate(115deg);
}
}
.xian {
width: 0.3px;
......@@ -110,18 +85,4 @@ export default {
2 2;
margin: 10px 10px 0 0;
}
.bizhang {
box-sizing: border-box;
width: 150px;
height: 150px;
display: flex;
justify-content: space-between;
position: relative;
}
.kong {
width: 40px;
}
.ding{
left: -31px;
}
</style>
\ No newline at end of file
......@@ -12,7 +12,7 @@
:videoUrl="data.vUrl"
/>
<!-- <LivePlayer
<LivePlayer
v-if="fpvUrl.vUrl"
:class="{
vUrl: fullScreen,
......@@ -23,7 +23,7 @@
ref="fpvPlayer"
:controls="false"
:videoUrl="fpvUrl.vUrl"
/> -->
/>
</div>
</template>
......@@ -125,13 +125,13 @@ export default {
height: 100%;
object-fit: cover;
object-position: center center;
z-index: 1;
}
.small {
width: 300px;
height: 170px;
position: absolute;
right: 0;
z-index: 1;
}
.vjs-volume-panel,
.vjs-playback-rate,
......
......@@ -100,6 +100,18 @@ angleMap.forEach((value, key) => {
window.angleMap = angleMap;
export default {
name: 'obstacle',
props: {
obstacleData: {
type: Object,
default(){
return null; /* {
distances: [], //array<int>(36个值每10度一个与障碍物的距离厘米);
obsDistance: 0, //int(避障警告距离米)}
} */
}
}
},
data() {
//转化value为{indexs: [], count: 0}结构
const blockCount = {};
......@@ -118,25 +130,20 @@ export default {
},
};
},
computed: {
obstacle() {
return this.$store.state.fckernel.obstacle;
},
},
watch: {
obstacle: {
obstacleData: {
immediate: true,
handler() {
if(!this.obstacle){
if(!this.obstacleData){
return;
}
//显示块出发等级
const level = (this.obstacle.obsDistance * 100) / 3;
const level = (this.obstacleData.obsDistance * 100) / 3;
Object.keys(this.minDistance).forEach(i => {
this.minDistance[i] = -1;
})
//匹配每个10度对应的显示块
this.obstacle.distances.forEach((value, i) => {
this.obstacleData.distances.forEach((value, i) => {
//取得当前角度对应的显示块
const index = angleToBlock.get(i);
......
......@@ -17,7 +17,7 @@
</div>
<div v-show="!fullScreen" class="close" @click="onClose(data)">关闭</div>
</div>
<el-tooltip content="模式切换" placement="bottom" v-if="streamSelect !== 'QingLiu' && fpvUrl.vUrl">
<el-tooltip content="模式切换" placement="bottom" v-if="playerCom !== 'QingLiuPlayer' && fpvUrl.vUrl">
<div class="fpv-switch iconfont icon-moshiqiehuan modelStyle pointer" @click="onChangeFPV"></div>
</el-tooltip>
<components
......@@ -30,7 +30,7 @@
:raw_msg="raw_msg"
@debugInfo="onDebugInfo"
/>
<div class="info" v-if="showQingLiuInfo && streamSelect == 'QingLiu'">
<div class="info" v-if="showQingLiuInfo && playerCom == 'QingLiuPlayer'">
<div class="de">
<div class="title">bitrate:</div>
<div class="detail">{{ raw_msg ? raw_msg/1000 : "0"}}kbps</div>
......@@ -86,7 +86,7 @@
</div>
<div class="play">
<el-tooltip
v-if="streamSelect == 'QingLiu'"
v-if="playerCom == 'QingLiuPlayer'"
class="ql-info"
content="信息"
placement="bottom"
......@@ -98,7 +98,7 @@
<div v-else class="left ml24" style="margin-left: 124px; color: #fff;"></div>
<div class="ctrl-items">
<div class="ctrl-items-selects">
<el-select class="video_type mr24" v-model="streamSelect" placeholder="切换源">
<el-select class="video_type mr24" v-model="streamSelect" @change="fpvSmallWindow = true;" placeholder="切换源">
<el-option
v-for="item in streamOptions"
:key="item.value"
......@@ -119,8 +119,9 @@
<div class="pointer iconfont icon-quanping" @click="onFullScreen"></div>
</div>
</div>
<slot></slot>
<Obstacle :obstacleData="obstacleData" v-if="obstacleData"></Obstacle>
</div>
<slot></slot>
</div>
</div>
</template>
......@@ -132,12 +133,14 @@ import LiveNVRPlayer from "./components/livenvr/index.vue";
// import QingLiuPlayer from "./flv/index.vue";
import QingLiuPlayer from "./components/qingliu/index.vue";
import { to_moveMount } from "../../lib/to_moveMount";
import Obstacle from './components/obstacle';
export default {
name: "MMCPlayer",
components: {
QingLiuPlayer,
LiveNVRPlayer,
Obstacle
},
props: {
//网络类型
......@@ -159,6 +162,15 @@ export default {
type: String,
default: "",
},
obstacleData: {
type: Object,
default(){
return null; /* {
distances: [], //array<int>(36个值每10度一个与障碍物的距离厘米);
obsDistance: 0, //int(避障警告距离米)}
} */
}
}
},
data() {
return {
......@@ -243,7 +255,8 @@ export default {
this.streamSelect = this.streamOptions[0].value;
}
},
deep: true
deep: true,
immediate: true
},
},
mounted() {
......@@ -307,7 +320,7 @@ export default {
*/
play() {
if (this.playerCom === "LiveNVRPlayer") {
this.$refs.player.$refs["livePlayer"].pause();
this.$refs.player.$refs["livePlayer"].play();
}
},
/**
......@@ -315,7 +328,7 @@ export default {
*/
pause() {
if (this.playerCom === "LiveNVRPlayer") {
this.$refs.player.$refs["livePlayer"].play();
this.$refs.player.$refs["livePlayer"].pause();
}
},
/**
......@@ -499,6 +512,7 @@ export default {
}
}
.play {
z-index: 1;
position: absolute;
bottom: 0;
width: 100%;
......
......@@ -44,7 +44,7 @@ export default {
protocol,
clientId,
});
commit("setClient", client);
commit("setClientId", clientId);
......@@ -115,5 +115,23 @@ export default {
client.unsubscribe(topic);
}
},
/**
* 发布
* QoS 0:消息最多传递一次,如果当时客户端不可用,则会丢失该消息。
* QoS 1:消息传递至少 1 次。
* QoS 2:消息仅传送一次。
* @param {*} publication
* @param {*} callback
* @param {*} options
* @param {*} type
*/
publish({state}, {topic, message, callback, options = { qos: 0 }}) {
state.client.publish(
topic,
new TextEncoder().encode(JSON.stringify(message)),
options,
callback
);
},
},
};
\ No newline at end of file
......@@ -4,7 +4,7 @@ export default `
<MMCDataTransferPanel
:device="device"
:wsShow="wsShow"
:data="channelData"
:throttleValue="throttleValue"
:uav-battery="battery"
:uav-data="uavData"
></MMCDataTransferPanel>
......@@ -16,14 +16,12 @@ export default `
export default {
data(){
return {
device: {
device: {
cateName: 'px4'
},
wsShow: false,
channelData: {
accelerator: 50
},
battery: {
wsShow: false, //是否为地面站连接
throttleValue: 500, //油门值0-1000,中位500
battery: { //电池电量
voltage: 0,
id: ''
},
......
......@@ -3,7 +3,7 @@
<MMCDataTransferPanel
:device="device"
:wsShow="wsShow"
:data="channelData"
:throttleValue="throttleValue"
:uav-battery="battery"
:uav-data="uavData"
></MMCDataTransferPanel>
......@@ -19,9 +19,7 @@ export default {
cateName: 'px4'
},
wsShow: false,
channelData: {
accelerator: 50
},
throttleValue: 500,
battery: {
voltage: 0,
id: ''
......
export default `
依赖以下步骤
1.清流需要网站响应头中添加
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
2.需要将mmc-stl-vue2/components/MMCPlayer/lib/js和mmc-stl-vue2/components/MMCPlayer/lib/liveplayer复制到项目的public文件中
<template>
<div>
<el-form>
<el-form-item label="播放地址">
<el-input v-model="url"></el-input>
</el-form-item>
</el-form>
<MMCPlayer title="测试播放器" :streamOptions="streamOptions" @close="onClose"></MMCPlayer>
<MMCPlayer
title="测试播放器"
:streamOptions="streamOptions"
@close="onClose"
:obstacleData="obstacleData"
></MMCPlayer>
</div>
</template>
<script>
export default {
data(){
data() {
return {
url: '',
}
},
computed: {
streamOptions(){
return [
streamOptions: [
{
label: '播放源1',
value: this.url,
fpvUrl: ''
}
]
},
label: "播放源1",
value:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
fpvUrl:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
},
{
label: "播放源2",
value:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
fpvUrl:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
},
{
label: "播放源3",
value:
"pzsp://pzlink999bju.powzamedia.com:7788/live/ld/trans/test/mlinkm/channel1?ndselect=2&linkmode=8&fstusrd=1&us=1&wsinfo=pzlink999bju.powzamedia.com-13000&only-video=1&rct=500",
},
],
obstacleData: null,
/* {
distances: [], //array<int>(36个值每10度一个与障碍物的距离厘米);
obsDistance: 0, //int(避障警告距离米)}
} */
};
},
mounted() {
//模拟数据
setInterval(() => {
let data = {
distances: [],
obsDistance: 15,
};
for (let i = 0; i < 36; i++) {
data.distances.push(Math.random() * 10 * 100);
}
this.obstacleData = data;
}, 1000);
},
methods: {
onClose(){
alert('关闭')
}
}
}
onClose() {
alert("关闭");
},
},
};
</script>
<style lang="scss" scoped>
</style>
`;
\ No newline at end of file
<template>
<div>
<el-form>
<el-form-item label="播放地址">
<el-input v-model="url"></el-input>
</el-form-item>
</el-form>
<MMCPlayer title="测试播放器" :streamOptions="streamOptions" @close="onClose"></MMCPlayer>
<MMCPlayer
title="测试播放器"
:streamOptions="streamOptions"
@close="onClose"
:obstacleData="obstacleData"
></MMCPlayer>
</div>
</template>
<script>
export default {
data(){
data() {
return {
url: '',
}
},
computed: {
streamOptions(){
return [
streamOptions: [
{
label: '播放源1',
value: this.url,
fpvUrl: ''
}
]
},
label: "播放源1",
value:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
fpvUrl:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
},
{
label: "播放源2",
value:
"http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8",
fpvUrl:
"https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",
},
{
label: "播放源3",
value:
"pzsp://pzlink999bju.powzamedia.com:7788/live/ld/trans/test/mlinkm/channel1?ndselect=2&linkmode=8&fstusrd=1&us=1&wsinfo=pzlink999bju.powzamedia.com-13000&only-video=1&rct=500",
},
],
obstacleData: null,
/* {
distances: [], //array<int>(36个值每10度一个与障碍物的距离厘米);
obsDistance: 0, //int(避障警告距离米)}
} */
};
},
mounted() {
//模拟数据
setInterval(() => {
let data = {
distances: [],
obsDistance: 15,
};
for (let i = 0; i < 36; i++) {
data.distances.push(Math.random() * 10 * 100);
}
this.obstacleData = data;
}, 1000);
},
methods: {
onClose(){
alert('关闭')
}
}
}
onClose() {
alert("关闭");
},
},
};
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
......@@ -38,7 +38,7 @@ export default {
}
}
}
</script>
</s>
<style>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论