You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
672 lines
21 KiB
672 lines
21 KiB
<template>
|
|
<div class="HomeFrameControl">
|
|
<ElPopover trigger="manual" :value="activeIcon === 'FrameControl'" :visibleArrow="false" placement="left"
|
|
popper-class="global-input-search-popover" @hide="onHide()">
|
|
<Button :class="['btn', { 'btn-active': activeIcon }]" slot="reference"
|
|
@click.native="handleClick('FrameControl')">
|
|
<img src="@screen/images/home-FrameControl/FrameControl.svg" />
|
|
</Button>
|
|
<el-tabs v-model="tabAction" @tab-click="tabClick">
|
|
<el-tab-pane label="批量管控" name="1">{{ }}</el-tab-pane>
|
|
<el-tab-pane label="定时管控" name="2"></el-tab-pane>
|
|
<el-tab-pane label="管控记录" name="3"></el-tab-pane>
|
|
</el-tabs>
|
|
<div class="body">
|
|
<div class="title">批量控制</div>
|
|
<span class="close" @click="() => { this.activeIcon = null; }">
|
|
<i class="el-icon-close" />
|
|
</span>
|
|
<div v-if="tabAction === '1'" style="width:70vw; min-height: 500px;">
|
|
<Form v-model="data" labelWidth="90px" column="2" class="form" ref="FormConfigRef" :formList="formList" />
|
|
<component ref="ControlComponent" :is="componentMap[DeviceTopics[data.deviceType]]" :isMultiControl="true"
|
|
:visible="true" :selectItems="data.childType" @update:activeIcon="(val) => { this.activeIcon = val }"
|
|
@update:submitting="(val) => { submitting = val }"></component>
|
|
<div v-if="hiddenDevices.indexOf(componentMap[DeviceTopics[data.deviceType]]) == -1" class="footer">
|
|
<Button @click.native="submitClick" :loading="submitting">
|
|
确认
|
|
</Button>
|
|
<Button style="background-color: rgba(0, 179, 204, 0.3)" @click.native="cancelClick"> 取消 </Button>
|
|
</div>
|
|
</div>
|
|
<div v-if="tabAction === '2'" style="width:70vw;height: 500px; overflow-y:auto" class="cardPanel">
|
|
<Empty v-if="!data.length" class="no-data" style="position: absolute">暂无数据</Empty>
|
|
<template v-else>
|
|
<div class="cardBox" v-for="(item, index) in data2" :key="index">
|
|
<Card :buttonIcon="null" :keyMap="keyMap" :cardData="item" class="card" buttonText="详情">
|
|
<template #form-remark="{ data }">
|
|
<div class="remark">
|
|
{{ data.remark }}
|
|
</div>
|
|
</template>
|
|
<template #button>
|
|
<el-switch v-model="item.status" active-color="#0BD" inactive-color="#999" active-value="0"
|
|
inactive-value="1" @change="(value) => handleSwitcherChange(value, item) ">
|
|
</el-switch>
|
|
<Button @click.native="() => goStrategy(item)">
|
|
查看
|
|
</Button>
|
|
</template>
|
|
</Card>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
<div v-if="tabAction === '3'" style="width:70vw;height: 500px;display: flex;flex-direction: column; justify-content: center;align-items: flex-start;" >
|
|
<Form v-model="dataRecord" style="width:100%;" labelWidth="90px" column="2" class="form" ref="FormRecordRef" :formList="formRecord" />
|
|
<Table :data="tableData" height="500px" style="margin: 20px;width:95%">
|
|
<ElTableColumn label="管控时间" prop="operTime" width="300"/>
|
|
<ElTableColumn label="设备名称" prop="dcDeviceName"/>
|
|
<ElTableColumn label="管控方式" prop="operType" width="200"/>
|
|
<ElTableColumn label="操作人" prop="operName" width="200"/>
|
|
<ElTableColumn label="执行结果" prop="stakeMark" width="150" >
|
|
<template slot-scope="scope">
|
|
<el-popover
|
|
placement="top-start"
|
|
width="400"
|
|
trigger="hover"
|
|
:content="scope.row.jsonResult">
|
|
<el-button slot="reference" class="btnResult">查看</el-button>
|
|
</el-popover>
|
|
</template>
|
|
</ElTableColumn>
|
|
</Table>
|
|
|
|
<!-- 分页 -->
|
|
<div class="footer" style="margin-top:-20px;margin-bottom: 30px">
|
|
<ElPagination @current-change="bindRecord" @size-change="onSizeChange" width="'100%'" :page-sizes="[10, 20, 30, 40, 50]"
|
|
:page-size="searchData.pageSize" :current-page.sync="searchData.pageNum" layout="total, sizes, prev, pager, next"
|
|
:total="tableTotal" class="Pagination">
|
|
</ElPagination>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ElPopover>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Button from "@screen/components/Buttons/Button.vue";
|
|
import Form from "@screen/components/FormConfig";
|
|
import Card from "@screen/components/Card1/index.vue";
|
|
import * as PresetFormItems from "@screen/common/PresetFormItems.js";
|
|
import { merge, cloneDeep } from "lodash";
|
|
import { markerClusterIns } from "@screen/pages/Home/components/RoadAndEvents/utils/map.js"
|
|
import { ChildTypes } from "@screen/utils/enum.js"
|
|
import { getDeviceList } from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js";
|
|
import { delay } from "@screen/utils/common";
|
|
import { initSearch } from "@screen/utils/enum/common.js"
|
|
import SmartDeviceParams from "@screen/pages/Home/components/Dialogs/SmartDevice/components/DeviceParamsMulti.vue";
|
|
import BroadcastParam from "@screen/pages/Home/components/Dialogs/Broadcast/components/BroadcastParamMulti.vue";
|
|
import FatigueWakesUpParam from "@screen/pages/Home/components/Dialogs/FatigueWakesUp/components/DeviceParam.vue";
|
|
import DrivingGuidanceParam from "@screen/pages/Home/components/Dialogs/DrivingGuidance/components/DeviceParam.vue";
|
|
import InfoBoardParam from "@screen/pages/Home/components/InfoBoard/InfoBoard.vue";
|
|
import request from "@/utils/request";
|
|
import { DeviceForMap } from "@screen/pages/Home/components/RoadAndEvents/utils/buttonEvent";
|
|
import { Message } from "element-ui";
|
|
import Table from '@screen/components/Table.vue';
|
|
import moment from "moment";
|
|
import _ from "lodash";
|
|
import Pagination from '@screen/components/Pagination.vue';
|
|
|
|
const componentMap = {
|
|
"设备箱": "SmartDeviceParams", "语音广播": "BroadcastParam", "疲劳唤醒": "FatigueWakesUpParam",
|
|
"行车诱导": "DrivingGuidanceParam", "情报板": "InfoBoardParam",
|
|
} //DeviceTopics[deviceType]
|
|
// , , "合流区": undefined,
|
|
const hiddenDevices = ["SmartDeviceParams", "InfoBoardParam"];
|
|
const controlMulti = Object.keys(componentMap);//6种批量控制
|
|
const DeviceTopics = {};//6种批量控制 事件专题 {key:label}
|
|
|
|
Object.keys(DeviceForMap).forEach(DeviceLabel => {
|
|
controlMulti.indexOf(DeviceLabel) !== -1 && (DeviceTopics[DeviceForMap[DeviceLabel].deviceType] = DeviceLabel);
|
|
});
|
|
const deviceTypeDefault = Object.keys(DeviceTopics)[1];
|
|
async function setDeviceOptions(config, filterData, formList) {
|
|
const data = await getDeviceList(config.deviceType, filterData).then(async (data) => {
|
|
await delay(600);
|
|
return data;
|
|
});
|
|
formList[4].options.options = data.map(item => {
|
|
return { label: `${item.deviceName}`, value: JSON.stringify({ id: item.id, iotDeviceId: item.iotDeviceId, deviceType: item.deviceType, otherConfig: item.otherConfig }), disabled: item.deviceState != 1 }
|
|
})
|
|
};
|
|
function changeHandle(data, formList) {
|
|
const filterData = {};
|
|
data.direction && (filterData.direction = data.direction);
|
|
data.startStakeMark && (filterData.startStakeMark = data.startStakeMark);
|
|
data.endStakeMark && (filterData.endStakeMark = data.endStakeMark);
|
|
setDeviceOptions({ deviceType: data.deviceType }, filterData, formList);
|
|
data.childType = undefined;
|
|
}
|
|
export default {
|
|
name: "HomeFrameControl",//设备控制
|
|
components: {
|
|
Button,
|
|
Form,
|
|
Card,
|
|
Table,
|
|
SmartDeviceParams,
|
|
BroadcastParam,
|
|
FatigueWakesUpParam,
|
|
DrivingGuidanceParam,
|
|
InfoBoardParam
|
|
},
|
|
watch: {
|
|
dataRecord(e) {
|
|
this.bindRecord()
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
Enum_ControlType: [
|
|
{ key: "0", label: "手动控制" },
|
|
{ key: "1", label: "定时控制" },
|
|
{ key: "2", label: "批量控制" },
|
|
{ key: "3", label: "预案控制" }
|
|
],
|
|
activeIcon: null,
|
|
data: {},
|
|
hiddenDevices,
|
|
submitting: false,
|
|
formList: [
|
|
{
|
|
label: "设备类型:",
|
|
key: "deviceType",
|
|
type: "select",
|
|
default: deviceTypeDefault,
|
|
options: {
|
|
clearable: true,
|
|
options: Object.keys(DeviceTopics).map(key => { return { label: DeviceTopics[key], value: key } }),
|
|
},
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
if (data.deviceType) changeHandle(data, formList);
|
|
else data.childType = undefined;
|
|
}
|
|
},
|
|
},
|
|
{
|
|
label: "设备方向:",
|
|
key: "direction",
|
|
type: "select",
|
|
options: {
|
|
options: [
|
|
{ key: "1", label: "菏泽方向" },
|
|
{ key: "3", label: "济南方向" },
|
|
{ key: "2", label: "双向" },
|
|
],
|
|
},
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
data.deviceType && changeHandle(data, formList);
|
|
}
|
|
},
|
|
},
|
|
merge({}, PresetFormItems.startStation,
|
|
{
|
|
options: {
|
|
options: [
|
|
{
|
|
prefix: {
|
|
text: "K",
|
|
style: {
|
|
color: "#3DE8FF",
|
|
},
|
|
},
|
|
key: "startStakeMark[0]",
|
|
default: initSearch.startStakeMark[0],
|
|
rules: [
|
|
{
|
|
message: "请补全桩号",
|
|
callback(value, data) {
|
|
console.log(value, data.startStakeMark);
|
|
if (
|
|
!((value + "")?.trim() && (data.startStakeMark[1] + "")?.trim())
|
|
)
|
|
return false;
|
|
else return true;
|
|
},
|
|
},
|
|
],
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
data.deviceType && changeHandle(data, formList);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
prefix: {
|
|
text: "+",
|
|
style: {
|
|
color: "#3DE8FF",
|
|
},
|
|
},
|
|
default: initSearch.startStakeMark[1],
|
|
key: "startStakeMark[1]",
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
data.deviceType && changeHandle(data, formList);
|
|
}
|
|
},
|
|
},
|
|
],
|
|
}
|
|
}),
|
|
merge({}, PresetFormItems.endStation, {
|
|
options: {
|
|
options: [
|
|
{
|
|
prefix: {
|
|
text: "K",
|
|
style: {
|
|
color: "#3DE8FF",
|
|
},
|
|
},
|
|
key: "endStakeMark[0]",
|
|
default: initSearch.endStakeMark[0],
|
|
rules: [
|
|
{
|
|
message: "请补全桩号",
|
|
callback(value, data) {
|
|
if (
|
|
!((value + "")?.trim() && (data.endStakeMark[1] + "")?.trim())
|
|
)
|
|
return false;
|
|
else return true;
|
|
},
|
|
},
|
|
],
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
data.deviceType && changeHandle(data, formList);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
prefix: {
|
|
text: "+",
|
|
style: {
|
|
color: "#3DE8FF",
|
|
},
|
|
},
|
|
default: initSearch.endStakeMark[1],
|
|
key: "endStakeMark[1]",
|
|
ons: { //on监听 element事件
|
|
change(value, ...args) {
|
|
const { data, formList } = args.slice(-1)[0]; //data 为数据 formList为传入的配置项
|
|
data.deviceType && changeHandle(data, formList);
|
|
}
|
|
},
|
|
},
|
|
],
|
|
}
|
|
}),
|
|
{
|
|
label: "设备名称:",
|
|
key: "childType",
|
|
type: "select",
|
|
isAlone: true,
|
|
width: '100%',
|
|
options: {
|
|
clearable: true,
|
|
options: [],
|
|
multiple: true,
|
|
["collapse-tags"]: true
|
|
},
|
|
visible: data => {
|
|
return true;
|
|
},
|
|
},
|
|
// {
|
|
// label: "控制操作:",
|
|
// key: "controlOp",
|
|
// type: "select",
|
|
// default: null,
|
|
// options: {
|
|
// clearable: true,
|
|
// options: [{
|
|
// label: "在线",
|
|
// value: "1"
|
|
// }, {
|
|
// label: "离线",
|
|
// value: "0"
|
|
// }]
|
|
// },
|
|
// },
|
|
],
|
|
DeviceTopics,
|
|
componentMap,
|
|
tabAction: "1",
|
|
data:[],
|
|
keyMap: [
|
|
{
|
|
key: "groupName",
|
|
label: "标题",
|
|
},
|
|
{
|
|
key: "remark",
|
|
label: "描述",
|
|
},
|
|
],
|
|
data2:[], //批量管控
|
|
dataRecord:{
|
|
operType: "0",
|
|
operTime:[]
|
|
},
|
|
formRecord:[
|
|
{
|
|
label: "管控方式:",
|
|
key: "operType",
|
|
type: "select",
|
|
options: {
|
|
options: [
|
|
{ key: "0", label: "手动控制" },
|
|
{ key: "1", label: "定时控制" },
|
|
{ key: "2", label: "批量控制" },
|
|
{ key: "3", label: "预案控制" }
|
|
],
|
|
},
|
|
},
|
|
{
|
|
label: "管控时间:",
|
|
key: "operTime",
|
|
required: false,
|
|
type: "datePicker",
|
|
options: {
|
|
style: "width: 96%",
|
|
type: "datetimerange",
|
|
format: "yyyy-MM-dd HH:mm:ss",
|
|
valueFormat: "yyyy-MM-dd HH:mm:ss",
|
|
},
|
|
},
|
|
],
|
|
tableTotal: 0,
|
|
tableData:[],
|
|
searchData: {
|
|
pageSize: 20,
|
|
pageNum: 1,
|
|
},
|
|
digResultVisible: false
|
|
}
|
|
},
|
|
// inject: ["activeDeviceTypes"],
|
|
// watch: {
|
|
// activeDeviceTypes: {
|
|
// handler(val) {
|
|
// const activeTopicOptions = []
|
|
// this.activeDeviceTypes.filter(activeDeviceType => {
|
|
// const match = activeDeviceType.match(/路测设备_(\d+)/);
|
|
// if (match) {
|
|
// const deviceType = match[1];
|
|
// DeviceTopics[deviceType] && activeTopicOptions.push({ label: DeviceTopics[deviceType], value: deviceType });
|
|
|
|
// }
|
|
// });
|
|
// this.formList[0].options.options = activeTopicOptions;
|
|
|
|
// },
|
|
// immediate: true,
|
|
// deep: true
|
|
// }
|
|
// },
|
|
mounted() {
|
|
changeHandle(this.data, this.formList);
|
|
},
|
|
methods: {
|
|
onHide(){
|
|
this.data['deviceType']=deviceTypeDefault;
|
|
changeHandle(this.data, this.formList);
|
|
},
|
|
submitClick() {
|
|
this.$refs.ControlComponent?.handleSubmit();
|
|
},
|
|
cancelClick() {
|
|
this.activeIcon = null;
|
|
},
|
|
tabClick() {
|
|
if(this.tabAction === '2'){
|
|
this.bindTimeing();
|
|
} else if(this.tabAction === '3'){
|
|
this.dataRecord.operTime = [moment().startOf('month').format('YYYY-MM-DD 00:00:00'),moment().endOf('month').format('YYYY-MM-DD 23:59:59'),]
|
|
this.bindRecord();
|
|
} else if(this.tabAction === '1'){
|
|
// this.data['deviceType']=deviceTypeDefault;
|
|
// changeHandle(this.data, this.formList);
|
|
}
|
|
},
|
|
handleClick(type) {
|
|
this.activeIcon = this.activeIcon === type ? null : type;
|
|
},
|
|
filterEnd(data) {
|
|
this.activeIcon = null;
|
|
// this.filterData = data;
|
|
this.$parent.$refs.RoadAndEventsRef?.setFilterData?.(data);
|
|
},
|
|
goStrategy(item){
|
|
this.$router.push(`/control/device/strategy?id=${item.id}`);
|
|
},
|
|
async handleSwitcherChange(value, item) {
|
|
request({
|
|
url: `/business/dcBatchFunctionsJobGroup`,
|
|
method: "PUT",
|
|
data: {
|
|
id:item.id,
|
|
status:value
|
|
},
|
|
})
|
|
.then((result) => {
|
|
item.status = result.data.status;
|
|
if (result.code != 200) return;
|
|
Message.success(`操作成功!`);
|
|
})
|
|
},
|
|
bindTimeing(){
|
|
request({
|
|
url: `/business/dcBatchFunctionsJobGroup/list`,
|
|
method: "get",
|
|
params: {},
|
|
})
|
|
.then((result) => {
|
|
if (result.code != 200) return;
|
|
this.tableTotal = result.total;
|
|
this.data2 = result.rows;
|
|
})
|
|
.finally(() => {
|
|
});
|
|
},
|
|
bindRecord(){
|
|
request({
|
|
url: `/business/dcOperLog/list`,
|
|
method: "get",
|
|
params: {
|
|
...this.searchData,
|
|
operType:this.dataRecord.operType,
|
|
startTime:this.dataRecord.operTime[0],
|
|
endTime:this.dataRecord.operTime[1]}
|
|
})
|
|
.then((result) => {
|
|
if (result.code != 200) return;
|
|
result.rows.forEach(e => {
|
|
e.operTime = moment(e.operTime).format('YYYY-MM-DD HH:mm:ss')
|
|
e.operType = _.find(this.Enum_ControlType,{key:e.operType}).label
|
|
});
|
|
this.tableData = result.rows;
|
|
this.tableTotal = result.total;
|
|
})
|
|
.finally(() => {
|
|
});
|
|
},
|
|
onSizeChange(pageSize) {
|
|
this.tableData = [];
|
|
this.searchData.pageSize = pageSize;
|
|
this.searchData.pageNum = 1;
|
|
this.bindRecord();
|
|
},
|
|
showResult(res){
|
|
this.digResultVisible = true
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
div.el-popper.global-input-search-popover {
|
|
background: rgba(6, 66, 88, 0.8);
|
|
border: 1px solid rgba(42, 217, 253, 0.6);
|
|
position: relative;
|
|
padding-top: 36px;
|
|
transform: translateY(24px);
|
|
// margin-top: 6vh;
|
|
|
|
.body {
|
|
.title {
|
|
background: linear-gradient(90deg,
|
|
#237e9b 0%,
|
|
rgba(23, 145, 184, 0) 100%);
|
|
padding: 3px 9px;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
}
|
|
|
|
.close {
|
|
padding: 3px 9px;
|
|
cursor: pointer;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: fit-content;
|
|
}
|
|
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
.image {
|
|
width: 50vw;
|
|
height: 65vh;
|
|
}
|
|
|
|
.HomeFrameControl {
|
|
.btn {
|
|
padding: 9px;
|
|
background: linear-gradient(180deg, #152e3c 0%, #163a45 100%);
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
height: unset;
|
|
border: 1px solid rgba(40, 144, 167, 1);
|
|
}
|
|
|
|
.btn-active {
|
|
background: linear-gradient(180deg, #005c79 0%, #009bcc 100%);
|
|
}
|
|
}
|
|
.cardPanel{
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.cardBox {
|
|
flex-basis: percentage(1/4);
|
|
padding-right: 10px;
|
|
padding-bottom: 10px;
|
|
}
|
|
.remark {
|
|
font-size: 14px; line-height: 20px; height: 40px; overflow: hidden;
|
|
color: #00b3cc;
|
|
}
|
|
.btnResult{
|
|
background-color:#00b3cc;
|
|
color: white;
|
|
border: none;
|
|
padding: 5px 20px;
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
.Pagination {
|
|
// color: #fff;
|
|
|
|
::v-deep {
|
|
> button,
|
|
> ul li {
|
|
background: #064258;
|
|
border-radius: 2px 2px 2px 2px;
|
|
opacity: 1;
|
|
color: #fff;
|
|
}
|
|
|
|
> button {
|
|
padding: 0 3px;
|
|
border: 1px solid #00b3cc;
|
|
}
|
|
|
|
> ul li {
|
|
background: linear-gradient(180deg, #004960 0%, #004b62 100%);
|
|
margin: 0 1.5px;
|
|
|
|
&.active {
|
|
background: linear-gradient(180deg, #005c79 0%, #009bcc 100%);
|
|
}
|
|
}
|
|
|
|
.el-pagination__total {
|
|
color: #fff;
|
|
}
|
|
|
|
.el-pagination__sizes {
|
|
.el-select {
|
|
.el-input {
|
|
width: 81px;
|
|
|
|
.el-input__inner {
|
|
font-size: 12px;
|
|
height: 23px;
|
|
background-color: #064258 !important;
|
|
}
|
|
}
|
|
|
|
.el-input__suffix {
|
|
.el-input__icon {
|
|
line-height: 23px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.el-pagination__jump {
|
|
margin-left: 10px;
|
|
color: #fff;
|
|
font-size: 12px;
|
|
|
|
.el-input {
|
|
width: 27px;
|
|
margin: 0 3px;
|
|
|
|
.el-input__inner {
|
|
font-size: 12px;
|
|
background-color: #064258 !important;
|
|
border-radius: 2px 2px 2px 2px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.btn-next {
|
|
margin-left: 6px;
|
|
}
|
|
|
|
.btn-prev {
|
|
margin-right: 6px;
|
|
}
|
|
}
|
|
::v-deep .el-pagination__total {
|
|
margin-left: 10px;
|
|
}
|
|
}
|
|
</style>
|