Browse Source

Merge branch 'develop' of http://39.106.31.193:9211/mengff/jihe-hs into develop

wangqin
qingzhengli 7 months ago
parent
commit
bb2daeefc1
  1. 24
      ruoyi-ui/src/views/JiHeExpressway/components/Card2/Card.vue
  2. 1
      ruoyi-ui/src/views/JiHeExpressway/components/Video/Video.vue
  3. 1
      ruoyi-ui/src/views/JiHeExpressway/components/Video/index.vue
  4. 2
      ruoyi-ui/src/views/JiHeExpressway/components/Video/videoStream.js
  5. 41
      ruoyi-ui/src/views/JiHeExpressway/components/Video2/flv-stream.js
  6. 166
      ruoyi-ui/src/views/JiHeExpressway/components/Video2/index.vue
  7. 241
      ruoyi-ui/src/views/JiHeExpressway/components/Video2/videoStream.js
  8. 152
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/FatigueWakesUp/components/DeviceControlDialog.vue
  9. 1
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/FatigueWakesUp/index.vue
  10. 2
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DispatchLiaison/index.vue
  11. 237
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalProcess/index.vue
  12. 13
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/RealTimeVideo/index.vue
  13. 0
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/1.svg
  14. 0
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/2.svg
  15. 0
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/3.svg
  16. 0
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/4.svg
  17. 28
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/index.vue
  18. 24
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/index.vue
  19. 1
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/EventDetailDialog/index.vue
  20. 2
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/FormEvent/data.js
  21. 39
      ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/FormEvent/index.vue

24
ruoyi-ui/src/views/JiHeExpressway/components/Card2/Card.vue

@ -1,5 +1,5 @@
<template>
<div class='Card'>
<div class="Card">
<Title :title="title">
<template #suffix>
<slot name="title-suffix" />
@ -12,27 +12,31 @@
</template>
<script>
import Title from "@screen/components/Title/index.vue"
import Title from "@screen/components/Title/index.vue";
export default {
name: 'Card',
name: "Card",
components: {
Title
Title,
},
props: {
title: {
type: String
}
}
}
type: String,
},
},
};
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.Card {
height: 100%;
width: 100%;
overflow: hidden;
background: linear-gradient(180deg, rgba(6, 66, 88, 0) 0%, rgba(6, 66, 88, .4) 93%);
background: linear-gradient(
180deg,
rgba(6, 66, 88, 0) 0%,
rgba(6, 66, 88, 0.4) 93%
);
display: flex;
flex-direction: column;

1
ruoyi-ui/src/views/JiHeExpressway/components/Video/Video.vue

@ -46,7 +46,6 @@ export default {
},
async mounted() {
// setTimeout(() => {
// this.$nextTick(() => {
this.playVideo();
this.$once("hook:beforeDestroy", () => this.player?.destroy());
// })

1
ruoyi-ui/src/views/JiHeExpressway/components/Video/index.vue

@ -13,6 +13,7 @@
</div>
</div>
<Transition name="fade" mode="out-in">
<Video :rangeIndex="rangeIndex" v-if="active === 'video'" class="video-stream" :pileNum="pileNum" :camId="camId"
:url="url" :videoType="videoType" />
<img v-else src="./view.png" />

2
ruoyi-ui/src/views/JiHeExpressway/components/Video/videoStream.js

@ -67,7 +67,6 @@ export async function openVideoStream(container, { camId, url } = {}) {
async function getUrl({ camId, url, pileNum, rangeIndex } = {}) {
// return testFlvUrl;
if (url) return url;
if (pileNum) {
let code, data, cameraData;
if (rangeIndex) {
@ -128,7 +127,6 @@ export class HttpLivePlayer {
this.container = container;
if (!flvJs.getFeatureList().mseLiveFlvPlayback)
return Message.error("浏览器不支持播放 flv 视频流");
getUrl(options).then((url) => {
this.url = url;
this.initLiveVideo();

41
ruoyi-ui/src/views/JiHeExpressway/components/Video2/flv-stream.js

@ -0,0 +1,41 @@
import flvJs from "flv.js";
import { getCameraStream } from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
/**
*
* @param {HTMLElement} container 容器
* @param {{camId?: string; url?: string}?} options {camId: 相机ID; url: 直播地址}
* @returns
*/
export async function openVideoStream(container, { camId, url } = {}) {
if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) return;
url = data.liveUrl;
}
if (!url) return;
const flvPlayer = flvJs.createPlayer({
type: "flv",
url: url,
isLive: true,
hasVideo: true,
hasAudio: true,
});
console.log(
"%c [ flvPlayer ]-26-「videoStream.js」",
"font-size:15px; background:#b2b540; color:#f6f984;",
flvPlayer
);
flvPlayer.attachMediaElement(container);
flvPlayer.load();
flvPlayer.play();
return flvPlayer;
}

166
ruoyi-ui/src/views/JiHeExpressway/components/Video2/index.vue

@ -0,0 +1,166 @@
<template>
<div class="video-container">
<div class="header">
<ElSelect @change="showVideo" v-model="cameraId">
<ElOption v-for="item in urls"
:key="item.id" :label="item.deviceName" :value="item.iotDeviceId">
</ElOption>
</ElSelect>
</div>
<Transition name="fade" mode="out-in">
<video controls autoplay muted class="video-stream" v-bind="$attrs" ref="videoContainerRef" />
</Transition>
</div>
</template>
<script>
import { HttpLivePlayer, openLiveVideo } from "./videoStream.js"
import {
getNearCameraNew,
} from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
export default {
name: 'VideoControls',
components: {
},
props: {
//
pileNum: {
type: String,
default: null
},
rangeIndex: {
type: String,
default: null
},
showHeader: {
type: Boolean,
default: true
}
},
data() {
return {
active: "video",
player: null,
urls:[],
cameraId: null
}
},
async mounted() {
this.playVideo();
this.$once("hook:beforeDestroy", () => this.player?.destroy());
},
methods: {
async playVideo() {
this.player?.destroy();
let {code,data} = await getNearCameraNew(this.pileNum).catch(() => ({}));
if (
code != 200 ||
(Array.isArray(data) ? !data?.length : !Object.keys(data || {}).length)
) {
Message.warning("未获取到附近的相机信息");
return;
}
if(data[this.rangeIndex]){
this.urls = data[this.rangeIndex]
this.cameraId = data[this.rangeIndex][0]['iotDeviceId']
this.showVideo();
}
},
showVideo(){
this.player = new HttpLivePlayer(this.$refs.videoContainerRef, { camId: this.cameraId});
}
}
}
</script>
<style lang='scss' scoped>
.video-container {
position: relative;
background-color: #000;
height: 240px;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.24s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.header {
width: 100%;
z-index: 999;
display: flex;
justify-content: space-between;
.radio {
background: #265A70;
border-radius: 41px 41px 41px 41px;
overflow: hidden;
opacity: 1;
border: 1px solid #3DE8FF;
font-size: 12px;
// font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 14px;
height: fit-content;
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
.active {
background-color: rgba(61, 232, 255, 1);
}
span {
background-color: rgba(38, 90, 112, 1);
padding: 4px 9px;
display: inline-block;
cursor: pointer;
&:hover {
background-color: rgba(61, 232, 255, 1);
}
}
}
.btn {
background: #265A70;
border-radius: 6px 6px 6px 6px;
opacity: 1;
border: 1px solid #3DE8FF;
font-size: 12px;
// font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 14px;
padding: 3px 9px;
cursor: pointer;
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
}
}
.video-stream,
img {
height: 100%;
max-height: 100%;
max-width: 100%;
}
.video-stream {
width: 100%;
}
}
</style>

241
ruoyi-ui/src/views/JiHeExpressway/components/Video2/videoStream.js

@ -0,0 +1,241 @@
import flvJs from "flv.js";
import mpegTsJs from "mpegts.js";
import { Message } from "element-ui";
// mpegts.js
import {
getCameraStream,
getNearCamera,
getNearCameraNew,
} from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
const ErrorTypesCn = {
NetworkError: "网络错误",
MediaError: "媒体错误",
OtherError: "其他错误",
};
/**
* flv 视频测试
* https://bilibili.github.io/flv.js/demo/
* https://www.zngg.net/tool/detail/FlvPlayer
* https://xqq.im/mpegts.js/demo/arib.html
*/
/**
* flv 视频流
*/
const testFlvUrl =
"https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-720p.flv";
// "https://v17.dogevideo.com/vcloud/17/v/20190424/1556036075_818c4125ec9c8cbc7a7a8a7cc1601512/1057/e51d88e79732fb952ebdbb4a57aa628a.flv?vkey=D9EAC2&tkey=17062414799ec7c466dc&auth_key=1706255879-zQK6JYToEeRiUark-0-6e363fb7709e783e64efc919d2267bdc";
/**
*
* @param {HTMLElement} container 容器
* @param {{camId?: string; url?: string}?} options {camId: 相机ID; url: 直播地址}
* @returns
*/
export async function openVideoStream(container, { camId, url } = {}) {
if (camId) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) return;
url = data.liveUrl;
}
if (!url) return;
// console.log(flvJs.getFeatureList().mseLivePlayback);
const player = flvJs.createPlayer({
type: "flv",
url: url,
isLive: true,
hasVideo: true,
hasAudio: true,
});
player.attachMediaElement(container);
player.load();
player.play();
player.on(flvJs.Events.ERROR, (e) => {});
return player;
}
async function getUrl({ camId} = {}) {
const { code, data } = await getCameraStream(camId).catch(() => ({}));
if (code != 200) {
Message.warning("未获取到当前相机的播放地址");
return;
}
let url = data.liveUrl;
if (!url) {
Message.warning("未获取到当前相机的播放地址");
return Promise.reject("获取 url 失败!");
}
return url;
}
export class HttpLivePlayer {
/**
* @type { flvJs.Player }
*/
player;
/**
* @type { HTMLVideoElement }
*/
container;
url;
// 解码 帧
lastDecodedFrames;
constructor(container, options) {
this.container = container;
if (!flvJs.getFeatureList().mseLiveFlvPlayback)
return Message.error("浏览器不支持播放 flv 视频流");
getUrl(options).then((url) => {
this.url = url;
this.initLiveVideo();
});
}
destroy() {
if (!this.player) return;
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.player.destroy();
this.player = null;
}
initLiveVideo() {
this.destroy();
this.player = null;
this.lastDecodedFrames = null;
if (!this.url) return;
this.player = flvJs.createPlayer(
{
type: "flv",
url: this.url,
isLive: true,
},
{
autoCleanupSourceBuffer: true,
// enableWorker: true, // 启用分离的线程进行转换
enableStashBuffer: false, // 关闭IO隐藏缓冲区 如果您需要实时(最小延迟)来进行实时流播放,则设置为false
stashInitialSize: 128,
isLive: true,
lazyLoad: true,
}
);
this.player.attachMediaElement(this.container);
this.player.load();
this.player.play();
// this.container.addEventListener("progress", () => {
// let end = this.player.buffered.end(0); //获取当前buffered值(缓冲区末尾)
// let delta = end - this.player.currentTime; //获取buffered与当前播放位置的差值
// // 延迟过大,通过跳帧的方式更新视频
// if (delta > 10 || delta < 0) {
// this.player.currentTime = this.player.buffered.end(0) - 1;
// return;
// }
// // 追帧
// if (delta > 1) {
// this.container.playbackRate = 1.1;
// } else {
// this.container.playbackRate = 1;
// }
// });
this.player.on(flvJs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
console.log("errorType", errorType);
console.log("errorDetail", errorDetail);
console.log("errorInfo", errorInfo);
Message.warning(
`视频流加载失败, ${ErrorTypesCn[errorType] || "其他错误"}`
);
let self = this;
setTimeout(() => {
self.initLiveVideo();
}, 300000);
});
// 视频断流
this.player.on(flvJs.Events.STATISTICS_INFO, (res) => {
if (this.lastDecodedFrames != res.decodedFrames) {
this.lastDecodedFrames = res.decodedFrames;
} else {
this.lastDecodedFrames = 0;
// this.destroy();
// this.initLiveVideo();
}
});
}
}
/**
* https://juejin.cn/post/6855577308271476743
* https://www.cnblogs.com/xiahj/p/flvExtend.html
* 使用 mpegTsJs
* @param {*} container
* @param {*} options
*/
export async function openLiveVideo(container, options) {
if (!mpegTsJs.getFeatureList().mseLivePlayback)
return Message.error("浏览器不支持播放 flv 视频流");
const url = await getUrl(options).catch(() => {});
console.log(
"%c [ url ]-212-「videoStream.js」",
"font-size:15px; background:#6f87e8; color:#b3cbff;",
url,
options
);
if (!url) return;
const player = mpegTsJs.createPlayer(
{
type: "flv",
url,
isLive: true,
},
{
autoCleanupSourceBuffer: true,
enableWorker: true, // 启用分离的线程进行转换
// enableStashBuffer: false, // 关闭IO隐藏缓冲区 如果您需要实时(最小延迟)来进行实时流播放,则设置为false
// stashInitialSize: 128,
isLive: true,
lazyLoad: true,
}
);
player.attachMediaElement(container);
container.addEventListener("play", () => {
try {
let end = player.buffered.end(0) - 1;
player.currentTime = end;
} catch (error) {}
});
player.load();
player.play();
return player;
}

152
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/FatigueWakesUp/components/DeviceControlDialog.vue

@ -3,133 +3,78 @@
<div class="DeviceControlDialog">
<ElTabs v-model="activeName" class="tabs" @tab-click="tabClick">
<ElTabPane label="一般模式" name="first">
<Form
v-model="formData"
class="form"
ref="FormConfigRef"
:formList="formList1"
column="1"
labelWidth="120px"
/>
<Form v-model="formData" class="form" ref="FormConfigRef" :formList="formList1" column="1"
labelWidth="120px" />
</ElTabPane>
<ElTabPane label="自定义模式" name="second">
<div style="display: flex; margin: 20px 0">
<!-- <div style="display: flex; margin: 20px 0">
<p style="width: 115px">工作时长():</p>
<el-input-number
v-model="onWorkStatus2"
:min="0"
:max="999"
label="工作时长(s分):"
></el-input-number>
</div>
<el-input-number v-model="onWorkStatus2" :min="0" :max="999" label="工作时长(s分):"></el-input-number>
</div> -->
<Table :data="tableData">
<ElTableColumn prop="ds" label="段数"></ElTableColumn>
<ElTableColumn prop="time" width="120" label="时间(毫秒)">
<template slot-scope="scope">
<div style="display: flex">
<el-input-number
style="width: 120px"
v-model="scope.row.time"
:min="0"
></el-input-number>
<el-input-number style="width: 120px" v-model="scope.row.time" :min="0"></el-input-number>
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="A" label="线路A">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.A"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.A" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="B" label="线路B">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.B"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.B" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="C" label="线路C">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.C"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.C" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="D" label="线路D">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.D"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.D" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="E" label="线路E">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.E"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.E" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="F" label="线路F">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.F"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.F" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="G" label="线路G">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.G"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.G" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
<ElTableColumn prop="H" label="线路H">
<template slot-scope="scope">
<el-switch
active-value="1"
inactive-value="0"
v-model="scope.row.H"
active-color="#13ce66"
inactive-color="#C9C9C9"
>
<el-switch active-value="1" inactive-value="0" v-model="scope.row.H" active-color="#13ce66"
inactive-color="#C9C9C9">
</el-switch>
</template>
</ElTableColumn>
@ -139,10 +84,8 @@
</div>
<template #footer>
<Button
style="background-color: rgba(0, 179, 204, 0.3)"
@click.native="(modelVisible = false), (submitting = false)"
>
<Button style="background-color: rgba(0, 179, 204, 0.3)"
@click.native="(modelVisible = false), (submitting = false)">
取消
</Button>
<Button @click.native="handleSubmit" :loading="submitting"> 确定 </Button>
@ -173,6 +116,7 @@ export default {
props: {
visible: Boolean,
deviceId: String,
productId: String
},
data() {
return {
@ -252,6 +196,10 @@ export default {
value: "6",
label: "SOS模式",
},
{
value: "7",
label: "自定义模式",
},
],
},
},
@ -341,16 +289,16 @@ export default {
async initData() {
//
let result = await this.requestURL("ASKMD");
if (result.data == 7) {
this.activeName = "second";
this.tabClick();
} else {
// if (result.data == 7) {
// this.activeName = "second";
// this.tabClick();
// } else {
this.formData.controlType = result.data + "" || "1";
//
let resultTime = await this.requestURL("ASKTM");
this.formData.onWorkStatus = resultTime.data || 0;
this.activeName = "first";
}
// }
},
async requestURL(functionId, options = {}) {
let result = await request({
@ -384,6 +332,7 @@ export default {
tData.push({ ...data, ds: item.property });
}
});
tData.sort((a, b) => a.ds.toUpperCase().localeCompare(b.ds.toUpperCase()));
this.tableData = tData;
} else {
//
@ -415,9 +364,11 @@ export default {
this.tableData.forEach((it, index) => {
rData.push({
functionId: "SETDF",
params: {
order: 7,
time: it.time,
numberOfSegments: this.duan[index],
numberOfSegments: it.ds || this.duan[index],
A: Number(it.A),
B: Number(it.B),
C: Number(it.C),
@ -426,25 +377,38 @@ export default {
F: Number(it.F),
G: Number(it.G),
H: Number(it.H),
}
});
});
//
await request({
let res = await request({
url: `/business/device/batchFunctions`,
method: "post",
// data: {
// deviceId: this.deviceId,
// functionId: "SETDF",
// params: rData,
// },
data: {
deviceId: this.deviceId,
functionId: "SETDF",
params: rData,
},
devices: [{
iotDeviceId: this.deviceId,
id: this.productId,
deviceType: 10
}],
functions: rData
}
});
//
let res = await this.requestURL("SETTM", { SET: this.onWorkStatus2 });
if (res.code == 200) {
Message.success("设置成功!");
this.$emit("update:value", false);
}
//
// let res = await this.requestURL("SETTM", { SET: this.onWorkStatus2 });
// if (res.code == 200) {
// Message.success("");
// this.$emit("update:value", false);
// }
}
},
},

1
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Dialogs/FatigueWakesUp/index.vue

@ -29,6 +29,7 @@
<DeviceControlDialog
v-model="deviceControlVisible"
:deviceId="dialogData.iotDeviceId"
:productId="dialogData.id"
/>
</Dialog>
</template>

2
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DispatchLiaison/index.vue

@ -105,9 +105,7 @@ export default {
res.data.forEach((element) => {
if (element.vehiclesMap.length > 0) {
element.vehiclesMap.forEach((item) => {
console.log(789, item);
this.vehicleTypeList.forEach((i) => {
console.log(456, i);
if (item.vehicleType == i.dictValue) {
item.vehicleText = "(" + i.dictLabel + ")";
}

237
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/DisposalProcess/index.vue

@ -1,38 +1,69 @@
<template>
<Card class='DisposalProcess' title="处置过程">
<Card class="DisposalProcess" title="处置过程">
<template #title-suffix>
<ButtonGradient class="title-button">
事件解除
</ButtonGradient>
<ButtonGradient class="title-button">
协同调度
</ButtonGradient>
<ButtonGradient class="title-button">
无需清障
</ButtonGradient>
<ButtonGradient class="title-button">
重要事件上报
</ButtonGradient>
<ButtonGradient class="title-button">
路赔
</ButtonGradient>
<ButtonGradient class="title-button special-button" @click.native="handleFullHeight">
<ButtonGradient class="title-button"> 事件解除 </ButtonGradient>
<ButtonGradient class="title-button"> 协同调度 </ButtonGradient>
<ButtonGradient class="title-button"> 无需清障 </ButtonGradient>
<ButtonGradient class="title-button"> 重要事件上报 </ButtonGradient>
<ButtonGradient class="title-button"> 路赔 </ButtonGradient>
<ButtonGradient
class="title-button special-button"
@click.native="handleFullHeight"
>
<template #prefix>
<div class="icon"
:style="{ backgroundImage: `url(${require(`./images/${isFullHeight ? 'reduce' : 'zoom'}.svg`)})` }" />
<div
class="icon"
:style="{
backgroundImage: `url(${require(`./images/${
isFullHeight ? 'reduce' : 'zoom'
}.svg`)})`,
}"
/>
</template>
</ButtonGradient>
</template>
<TimeLine1 :data="timeLine1List" :filterDistance="filterDistance" />
<TimeLine2 :data="timeLine2List" style="flex: 1;" />
<TimeLine2 :data="timeLine2List" style="flex: 1" />
<div v-if="!timeLine2List.length" class="no-data">暂无数据</div>
<div class="bottom">
<ElSelect value="" placeholder="请选择关键点" />
<RadioGroup :options="[{ key: 'input', label: '输入' }, { key: 'upload', label: '上传' }]" v-model="testRadio"
type="button" />
<ElInput v-model="test" placeholder="请输入调度指令" />
<ButtonGradient class="title-button special-button">
<ElSelect v-model="processId" placeholder="请选择关键点">
<ElOption
v-for="item in options"
:key="item.nodeNode"
:label="item.processNode"
:value="item.nodeNode"
>
</ElOption>
</ElSelect>
<RadioGroup
:options="[
{ key: 'input', label: '输入' },
{ key: 'upload', label: '上传' },
]"
v-model="testRadio"
type="button"
/>
<ElInput
v-if="testRadio == 'input'"
class="input"
v-model="context"
placeholder="请输入调度指令"
/>
<el-upload
v-if="testRadio == 'upload'"
class="input"
:headers="headers"
:action="uploadImgUrl"
:file-list="fileList"
:show-file-list="false"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
accept=".jpg,.jpeg,.png,.mp4"
>
<el-button class="input">点击上传</el-button>
</el-upload>
<ButtonGradient class="title-button special-button" @click="onSubmit">
发送
</ButtonGradient>
<ButtonGradient class="title-button special-button">
@ -43,19 +74,19 @@
</template>
<script>
import Card from "@screen/components/Card2/Card.vue";;
import ButtonGradient from '@screen/components/Buttons/ButtonGradient.vue';
import RadioGroup from '@screen/components/FormConfig/components/RadioGroup/index.vue';
import Card from "@screen/components/Card2/Card.vue";
import ButtonGradient from "@screen/components/Buttons/ButtonGradient.vue";
import RadioGroup from "@screen/components/FormConfig/components/RadioGroup/index.vue";
import { getToken } from "@/utils/auth";
import TimeLine1 from "@screen/components/TimeLine/TimeLine1/index";
import TimeLine2 from "@screen/components/TimeLine/TimeLine2/index";
import { provideMixin } from "./../../mixin"
import { provideMixin } from "./../../mixin";
import { timeLine2List } from "./data";
import request from "@/utils/request";
export default {
name: 'DisposalProcess',
name: "DisposalProcess",
inject: ["adpScale"],
mixins: [provideMixin],
components: {
@ -65,12 +96,13 @@ export default {
TimeLine2,
RadioGroup,
},
emit: ['fullHeight'],
emit: ["fullHeight"],
data() {
return {
test: null,
testRadio: "input",
timeLine1List: [],
// timeLine2List: Array.from({ length: 6 }).map(() => ({
// title: "",
// time: "2023-12-21 16:35:44",
@ -79,66 +111,136 @@ export default {
// posts: ''
// })),
timeLine2List: [],
isFullHeight: false
}
isFullHeight: false,
options: [],
processId: "",
context: "",
headers: {
Authorization: "Bearer " + getToken(),
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", //
fileList: [],
fileType: ["bmp", "gif", "jpg", "jpeg", "png", "mp4", "avi", "xmvb"],
imageUrl: "",
};
},
methods: {
filterDistance(distance) {
return 1 / this.adpScale.scaleX * distance
return (1 / this.adpScale.scaleX) * distance;
},
handleFullHeight() {
this.isFullHeight = !this.isFullHeight;
this.$emit('fullHeight', 'CrowdnessIndicatorRankings')
this.$emit("fullHeight", "CrowdnessIndicatorRankings");
},
async detailChange(data) {
const timelineData = await this.getDetail(data);
let processIdMap = {}
this.timeLine2List = timelineData.map(item => {
async detailChange(id) {
const timelineData = await this.getDetail(id);
let processIdMap = {};
processIdMap[item.processId] = new Date(item.operationTime).toLocaleTimeString();
this.timeLine2List = timelineData.map((item) => {
processIdMap[item.processId] = new Date(
item.operationTime
).toLocaleTimeString();
return {
// title: "",
time: item.operationTime ? new Date(item.operationTime).toLocaleString() : null,
time: item.operationTime
? new Date(item.operationTime).toLocaleString()
: null,
name: item.operator,
desc: item.context,
// posts: ''
}
});
this.timeLine1List = data.processConfigList.map((item) => {
return {
time: processIdMap[item.nodeNode],
label: item.processNode,
isActive: !!processIdMap[item.nodeNode],
};
});
// this.timeLine1List = data.processConfigList.map((item) => {
// return {
// time: processIdMap[item.nodeNode],
// label: item.processNode,
// isActive: !!processIdMap[item.nodeNode],
// };
// });
},
getDetail(data) {
getDetail(id) {
return request({
url: `/system/process/list`,
method: "GET",
params: {
eventId: data.id
}
eventId: id,
},
})
.then((result) => {
return result || [];
})
.catch((err) => []);
},
//
getProcessNode(eventId) {
return request({
url:
`/dc/system/event/getProcessNode/` +
"1a91d65cc31f4a9d90122888edb31043",
method: "GET",
})
.then((result) => {
if (result.code != 200) return [];
return result.rows || []
this.timeLine1List = result.data.map((item) => {
return {
time: item.operationTime,
label: item.processNode,
isActive: item.status == 1 ? true : false,
};
});
this.options = result.data.filter((item) => {
item.status == 0;
return item;
});
})
.catch((err) => []);
},
}
}
//
handleUploadSuccess(res, file) {
this.$message.success("上传成功");
this.imageUrl = res.url;
},
//
handleUploadError() {
this.$message.error("上传失败");
},
containsArrayElement(str, arr) {
return arr.filter((element) => str.includes(element));
},
onSubmit() {
let type = this.containsArrayElement(this.imageUrl, this.fileType);
console.log(type);
request({
url: `/system/process`,
method: "POST",
data: {
eventId: "1a91d65cc31f4a9d90122888edb31043",
processId: this.processId,
context: this.context,
file: this.imageUrl,
type: type.join(","),
},
})
.then((result) => {
if (result.code != 200) return [];
this.getProcessNode();
this.detailChange("1a91d65cc31f4a9d90122888edb31043");
})
.catch((err) => []);
},
},
async mounted() {
// this.getProcessNode();
// await this.detailChange("1a91d65cc31f4a9d90122888edb31043");
},
};
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.DisposalProcess {
::v-deep {
.content {
display: flex;
@ -153,15 +255,24 @@ export default {
background-size: 100% 100%;
width: 20px;
height: 20px;
transition: all .3s linear;
transition: all 0.3s linear;
}
}
.bottom {
display: grid;
grid-template-columns: .5fr auto 1fr 90px 90px;
grid-template-columns: 0.5fr auto 1fr 90px 90px;
width: 100%;
gap: 6px;
}
.input {
background-color: #0d5f79;
color: #f4f4f4;
border-radius: 2px;
line-height: 5px;
height: 26px;
font-size: 14px;
border: 0;
}
}
</style>

13
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/RealTimeVideo/index.vue

@ -1,19 +1,19 @@
<template>
<Card class='RealTimeVideo' title="实时视频">
<div class="item">
<Video class="item-video" :pileNum="detailData.stakeMark" />
<span>处置现场</span>
<Video v-if="detailData.stakeMark" class="item-video" :pileNum="detailData.stakeMark" rangeIndex="upCamera" :showHeader="false" />
<span>济南方向</span>
</div>
<div class="item">
<Video class="item-video" />
<span>感知视频</span>
<Video v-if="detailData.stakeMark" class="item-video" :pileNum="detailData.stakeMark" rangeIndex="downCamera" :showHeader="false" />
<span>菏泽方向</span>
</div>
</Card>
</template>
<script>
import Card from "@screen/components/Card2/Card.vue";;
import Video from "@screen/components/Video"
import Video from "@screen/components/Video2"
import { provideMixin } from "./../../mixin"
export default {
@ -32,7 +32,7 @@ export default {
::v-deep {
.content {
display: flex;
align-items: center;
align-items: flex-start;
justify-content: space-between;
gap: 9px;
}
@ -43,6 +43,7 @@ export default {
display: flex;
flex-direction: column;
height: 100%;
max-height: 250px;
align-items: center;
gap: 6px;

0
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/weChat.svg → ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/1.svg

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

0
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/message.svg → ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/2.svg

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/website.svg → ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/3.svg

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

0
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/weibo.svg → ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/images/4.svg

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

28
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/Cards/ReleaseInformation/index.vue

@ -1,7 +1,7 @@
<template>
<Card class='ReleaseInformation' title="信息发布">
<Form :formList="formList" column="1">
<template #platform="{ formData, data }">
<Form :formList="formList" column="1" ref="FormMsgRef" >
<template #type="{ formData, data }">
<CheckboxGroup :options="checkboxList" v-model="formData[data.key]">
<template v-for="item in checkboxList" #[item.key]="{ data }">
<div class="checkbox-content">
@ -25,7 +25,7 @@
</Descriptions> -->
<div class="bottom">
<ButtonGradient class="title-button special-button">
<ButtonGradient @click="confirm" class="title-button special-button">
一键发布
</ButtonGradient>
<!-- <ButtonGradient class="title-button special-button">
@ -42,6 +42,7 @@ import Form from '@screen/components/FormConfig';
import CheckboxGroup from '@screen/components/FormConfig/components/ElCheckboxGroup.vue';
import Descriptions from '@screen/components/Descriptions.vue';
import { provideMixin } from "./../../mixin"
import { method, result } from "lodash";
export default {
name: 'ReleaseInformation',
@ -64,10 +65,10 @@ export default {
],
checkboxValues: [],
checkboxList: [
{ key: 'weChat', label: '微信' },
{ key: 'message', label: '短信' },
{ key: 'website', label: '网站' },
{ key: 'weibo', label: '新浪' },
{ key: '1', label: '微信' },
{ key: '2', label: '短信' },
{ key: '3', label: '网站' },
{ key: '4', label: '新浪' },
],
formList: [{
label: "发布内容:",
@ -82,11 +83,22 @@ export default {
},
{
label: "发布平台:",
key: "platform",
key: "type",
type: "input",
default: []
}],
}
},
methods: {
async confirm(){
await this.$refs.FormMsgRef.validate()
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log("catch");
});
}
}
}
</script>

24
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/commandDispatch/index.vue

@ -1,5 +1,5 @@
<template>
<div class="CommandDispatch" :style="{ '--row': row }">
<div class="CommandDispatch" :style="{ '--row': row, height: '100%' }">
<component
:is="key"
v-for="(_, key) in gridAreaMap"
@ -24,8 +24,8 @@ const components = files.keys().reduce((components, key) => {
const originGridArea = {
EventInformation: "1 / 1 / span 12 / 1", // 1
DispatchLiaison: "13 / 1 / span 11 / 2", // 2
TrafficControl: "24 / 1 / span 10 / 2", //3
DispatchLiaison: "13 / 1 / span 8 / 2", // 213 / 1 / span 11 / 2
TrafficControl: "21 / 1 / span 13 / 2", //324 / 1 / span 10 / 2
CrowdnessIndicatorRankings: "1 / 2 / span 12 / 2", // / 1
DisposalProcess: "13 / 2 / span 21 / 2", //2
RealTimeVideo: "1 / 3 / span 9 / 3", //1
@ -42,7 +42,7 @@ export default {
props: {
detailId: {
type: [String, Number],
default: '96b9918efc01488cb22fa1d9d3236dfd',
default: "96b9918efc01488cb22fa1d9d3236dfd",
},
},
provide() {
@ -73,16 +73,20 @@ export default {
})
.then((result) => {
if (result.code != 200) return;
console.log(result.data)
console.log(result.data);
this.provideData.detail = result.data;
if(['设备设施隐患','非法上路','施工建设','服务区异常'].includes(result.data.eventName)){
const gridArea = {...originGridArea}
if (
["设备设施隐患", "非法上路", "施工建设", "服务区异常"].includes(
result.data.eventName
)
) {
const gridArea = { ...originGridArea };
//
gridArea['DispatchLiaison'] = '10 / 1 / span 20 / 2'
gridArea["DispatchLiaison"] = "10 / 1 / span 20 / 2";
delete gridArea.TrafficControl;
if(['设备设施隐患','非法上路'].includes(result.data.eventName)){
if (["设备设施隐患", "非法上路"].includes(result.data.eventName)) {
//
gridArea['RealTimeVideo'] = '1 / 3 / span 17 / 3'
gridArea["RealTimeVideo"] = "1 / 3 / span 17 / 3";
delete gridArea.ReleaseInformation;
}

1
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/EventDetailDialog/index.vue

@ -206,6 +206,7 @@ export default {
}
},
onSubmit() {
return;
let url = "/business/plans/list/warning/type";
if (this.activeName == "-1") {
url = "/business/plans/list/warning/type";

2
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/FormEvent/data.js

@ -842,6 +842,7 @@ export const tabConfigList = [
required: true,
options: {
options: [],
multiple: true,
},
visible: (data) => {
if (data?.eventSubclass == "3-2") {
@ -858,6 +859,7 @@ export const tabConfigList = [
required: true,
options: {
options: [],
multiple: true,
},
visible: (data) => {
if (data?.eventSubclass == "3-3") {

39
ruoyi-ui/src/views/JiHeExpressway/pages/control/event/event/FormEvent/index.vue

@ -2,37 +2,18 @@
<Dialog v-model="modelVisible" title="交通事故录入" width="1100px" top="14%">
<div class="EventDetailDialog">
<ElTabs v-model="activeName" @tab-click="handleChange">
<ElTabPane
v-for="(item, index) in tabConfigList"
:key="index"
:label="item.label"
:name="item.key"
/>
<ElTabPane v-for="(item, index) in tabConfigList" :key="index" :label="item.label" :name="item.key" />
</ElTabs>
<Transition name="fade">
<Form
class="form"
ref="FormConfigRef"
:formList="formConfig.list"
v-bind="getFormOptions"
labelWidth="120px"
/>
<Form class="form" ref="FormConfigRef" :formList="formConfig.list" v-bind="getFormOptions" labelWidth="120px" />
</Transition>
</div>
<template #footer>
<Button
style="background: #c9c9c9; padding: 0 24px"
@click.native="(modelVisible = false), (submitting = false)"
>取消</Button
>
<Button
style="padding: 0 24px"
@click.native="handleSubmit"
:loading="submitting"
>保存</Button
>
<Button style="background: #c9c9c9; padding: 0 24px"
@click.native="(modelVisible = false), (submitting = false)">取消</Button>
<Button style="padding: 0 24px" @click.native="handleSubmit" :loading="submitting">保存</Button>
</template>
</Dialog>
</template>
@ -180,12 +161,14 @@ export default {
} else {
formData.lang = "";
}
if (this.index == 2 && formData.dcEventTrafficControl.facilityId instanceof Array) {
let ids = formData.dcEventTrafficControl.facilityId.join(',');
formData.dcEventTrafficControl.facilityIds = ids
formData.dcEventTrafficControl.facilityId = ''
}
if (formData.endStakeMark && formData.endStakeMark[0] != null) {
let endStakeMark = formData.endStakeMark;
let strMark =
endStakeMark && endStakeMark.length > 0
? "K" + endStakeMark[0] + "+" + endStakeMark[1]
: "";
let strMark = endStakeMark && endStakeMark.length > 0 ? "K" + endStakeMark[0] + "+" + endStakeMark[1] : "";
if (this.index == 3) {
formData.dcEventTrafficCongestion.endStakeMark = strMark;
}

Loading…
Cancel
Save