Joe
10 months ago
15 changed files with 715 additions and 129 deletions
@ -0,0 +1,278 @@ |
|||
<template> |
|||
<Dialog v-model="modelVisible" title="设备操作"> |
|||
<div class='DeviceControlDialog'> |
|||
|
|||
<ElTabs v-model="activeName" class="tabs"> |
|||
<ElTabPane label="一般模式" name="first"> |
|||
<Form v-model="formData" class="form" ref="FormConfigRef" :formList="formList1" column="1" labelWidth="120px" /> |
|||
</ElTabPane> |
|||
<ElTabPane label="自定义模式" name="second"> |
|||
<Form class="form" ref="FormConfigRef" :formList="formList2" column="1" labelWidth="120px" /> |
|||
</ElTabPane> |
|||
</ElTabs> |
|||
</div> |
|||
|
|||
<template #footer> |
|||
<Button style="background-color: rgba(0, 179, 204, .3);" @click.native="modelVisible = false, submitting = false"> |
|||
取消 |
|||
</Button> |
|||
<Button @click.native="handleSubmit" :loading="submitting"> |
|||
确定 |
|||
</Button> |
|||
</template> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
import Dialog from "@screen/components/Dialog/index.vue"; |
|||
import Button from "@screen/components/Buttons/Button.vue" |
|||
import Form from '@screen/components/FormConfig'; |
|||
|
|||
import { delay } from "@screen/utils/common.js" |
|||
import request from "@/utils/request"; |
|||
|
|||
import { Message } from "element-ui"; |
|||
|
|||
|
|||
export default { |
|||
name: 'DeviceControlDialog', |
|||
components: { |
|||
Dialog, |
|||
Button, |
|||
Form |
|||
}, |
|||
model: { |
|||
prop: 'visible', |
|||
event: "update:value" |
|||
}, |
|||
props: { |
|||
visible: Boolean, |
|||
deviceId: String |
|||
}, |
|||
data() { |
|||
return { |
|||
submitting: false, |
|||
activeName: "first", |
|||
formData: {}, |
|||
formList1: [ |
|||
{ |
|||
label: "设备模式:", |
|||
key: "controlType", |
|||
type: "RadioGroup", |
|||
default: "00", |
|||
options: { |
|||
type: 'circle', |
|||
options: [ |
|||
{ |
|||
key: "00", |
|||
label: "常量", |
|||
}, |
|||
{ |
|||
key: "01", |
|||
label: "闪烁", |
|||
} |
|||
], |
|||
}, |
|||
}, |
|||
{ |
|||
label: "操作时长:", |
|||
key: "onWorkStatus", |
|||
required: true, |
|||
type: "select", |
|||
options: { |
|||
placeholder: "请选择", |
|||
} |
|||
}, |
|||
], |
|||
formList2: [ |
|||
{ |
|||
label: "设备模式:", |
|||
key: "controlType", |
|||
type: "RadioGroup", |
|||
default: "00", |
|||
options: { |
|||
type: 'circle', |
|||
options: [ |
|||
{ |
|||
key: "00", |
|||
label: "常量", |
|||
}, |
|||
{ |
|||
key: "01", |
|||
label: "闪烁", |
|||
} |
|||
], |
|||
}, |
|||
}, |
|||
{ |
|||
label: "线路选择:", |
|||
key: "onWorkStatus2", |
|||
required: true, |
|||
type: "select", |
|||
options: { |
|||
placeholder: "请选择", |
|||
} |
|||
}, |
|||
{ |
|||
label: "操作时长:", |
|||
key: "onWorkStatus", |
|||
required: true, |
|||
type: "select", |
|||
options: { |
|||
placeholder: "请选择", |
|||
} |
|||
}, |
|||
] |
|||
} |
|||
}, |
|||
computed: { |
|||
modelVisible: { |
|||
get() { |
|||
return this.visible |
|||
}, |
|||
set(val) { |
|||
this.$emit('update:value', val) |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
modelVisible: { |
|||
immediate: true, |
|||
handler(bool) { |
|||
if (!bool) return; |
|||
|
|||
this.reDisplay(); |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
requestURL(functionId, options = {}) { |
|||
return new Promise((resolve, reject) => { |
|||
request.post(`business/device/functions/${this.deviceId}/${functionId}`, options) |
|||
.then((result) => { |
|||
if (result.code != 200) return reject(); |
|||
|
|||
resolve(result.data[0]); |
|||
}) |
|||
.catch((err) => { |
|||
reject(); |
|||
}); |
|||
}); |
|||
}, |
|||
reDisplay() { |
|||
this.requestURL(52) |
|||
.then(async (data) => { |
|||
await delay(0); |
|||
|
|||
const formData = this.$refs.FormConfigRef?.formData; |
|||
|
|||
formData.controlType = data.mode; |
|||
|
|||
switch (data.mode) { |
|||
case "00": |
|||
formData.onWorkStatus = data.onWorkStatus; |
|||
formData.inWorkStatus = data.inWorkStatus; |
|||
break; |
|||
case "01": |
|||
case "02": |
|||
await this.requestURL("3C") |
|||
.then((data2) => { |
|||
formData.onWorkStatus = data2.onWorkStatus; |
|||
formData.inWorkStatus = data2.inWorkStatus; |
|||
|
|||
if (data.mode === '01') |
|||
formData.displayTime = [data.startDisplay, data.endDisplay]; |
|||
}) |
|||
.catch(() => { }); |
|||
break; |
|||
} |
|||
|
|||
this.oldFormData = { ...formData }; |
|||
|
|||
}) |
|||
}, |
|||
handleSubmit() { |
|||
const result = {}, formData = this.$refs.FormConfigRef?.formData; |
|||
|
|||
result.mode = formData.controlType; |
|||
|
|||
delete result.controlType; |
|||
|
|||
if (result.mode === '01') { |
|||
if (!formData.displayTime?.length) return Message.error(`时间不能为空!`); |
|||
} |
|||
|
|||
if (!formData.onWorkStatus || !formData.inWorkStatus) return Message.error(`工作状态不能为空!`); |
|||
|
|||
if (["01", "02"].includes(result.mode)) { |
|||
if (["04", "00"].includes(formData.onWorkStatus)) return Message.error(`上行工作状态不能选择当前类型!`); |
|||
if (["04", "00"].includes(formData.inWorkStatus)) return Message.error(`下行工作状态不能选择当前类型!`); |
|||
} |
|||
|
|||
result.onWorkStatus = formData.onWorkStatus; |
|||
result.inWorkStatus = formData.inWorkStatus; |
|||
|
|||
this.submitting = true; |
|||
|
|||
// this.submitting = false; |
|||
// return; |
|||
|
|||
/** |
|||
* 接口 地址 |
|||
* |
|||
* https://www.showdoc.com.cn/2450725213006196/10877717880262686 |
|||
*/ |
|||
let promise = []; |
|||
|
|||
switch (result.mode) { |
|||
case "00": |
|||
promise.push(this.requestURL("51", result)) |
|||
break; |
|||
case "01": |
|||
case "02": |
|||
|
|||
const options = { mode: result.mode }; |
|||
|
|||
if (result.mode === '01') { |
|||
options.startDisplayTime = formData.displayTime[0]; |
|||
options.endDisplayTime = formData.displayTime[1]; |
|||
} |
|||
|
|||
promise.push( |
|||
this.requestURL("30", { |
|||
onWorkStatus: result.onWorkStatus, |
|||
inWorkStatus: result.inWorkStatus, |
|||
}), |
|||
this.requestURL("51", options), |
|||
) |
|||
break; |
|||
} |
|||
Promise.all(promise) |
|||
.then(() => { |
|||
this.modelVisible = false; |
|||
}) |
|||
.catch((err) => { |
|||
console.log("%c [ err ]-110-「DeviceControlDialog.vue」", "font-size:15px; background:#547bf2; color:#98bfff;", err); |
|||
Message.error(`设备操作失败!`); |
|||
}) |
|||
.finally(() => { |
|||
this.submitting = false; |
|||
}) |
|||
} |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.DeviceControlDialog { |
|||
width: 450px; |
|||
height: 210px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15px; |
|||
|
|||
.tips { |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,139 @@ |
|||
<template> |
|||
<Dialog v-model="obverseVisible" title="疲劳唤醒弹窗"> |
|||
<div class="FatigueWakesUp"> |
|||
<Video class="video-stream" :pileNum="dialogData.stakeMark" /> |
|||
|
|||
<Descriptions labelWidth="72px" :list="list" :data="data" style="gap: 18px" /> |
|||
</div> |
|||
|
|||
<template #footer> |
|||
<Button @click.native="deviceControlVisible = true">设备操作</Button> |
|||
</template> |
|||
|
|||
<DeviceControlDialog v-model="deviceControlVisible" :deviceId="dialogData.iotDeviceId" /> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
import Dialog from "@screen/components/Dialog/index.vue"; |
|||
import Descriptions from '@screen/components/Descriptions.vue'; |
|||
import Button from "@screen/components/Buttons/Button.vue" |
|||
// import { getRoadInfoByStakeMark, getProduct } from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js" |
|||
import Video from "@screen/components/Video" |
|||
import DeviceControlDialog from "./components/DeviceControlDialog.vue" |
|||
|
|||
import request from "@/utils/request"; |
|||
import { dialogDelayVisible } from "./../mixin" |
|||
|
|||
// 疲劳唤醒弹窗 |
|||
export default { |
|||
name: 'FatigueWakesUp', |
|||
mixins: [dialogDelayVisible], |
|||
components: { |
|||
Dialog, |
|||
Descriptions, |
|||
Video, |
|||
DeviceControlDialog, |
|||
Button |
|||
}, |
|||
data() { |
|||
return { |
|||
deviceControlVisible: false, |
|||
data: { |
|||
deviceType: "行车诱导", |
|||
deviceStation: "k094+079", |
|||
roadName: "G35济泽高速", |
|||
direction: "1", |
|||
deviceState: "0", |
|||
deviceVendors: "XXX厂家", |
|||
}, |
|||
list: [ |
|||
{ |
|||
label: '设备名称', |
|||
key: "deviceName", |
|||
}, |
|||
{ |
|||
label: '设备桩号', |
|||
key: "stakeMark", |
|||
}, |
|||
{ |
|||
label: '道路名称', |
|||
key: "roadName", |
|||
}, |
|||
{ |
|||
label: '设备方向', |
|||
key: "direction", |
|||
enum: "CameraDirectionEnum" |
|||
}, |
|||
{ |
|||
label: '设备状态', |
|||
key: "deviceState", |
|||
enum: "DeviceTypeEnum" |
|||
}, |
|||
{ |
|||
label: '设备厂商', |
|||
key: "brand", |
|||
}, |
|||
] |
|||
} |
|||
}, |
|||
async created() { |
|||
this.data = { ...this.dialogData }; |
|||
|
|||
getProduct(this.dialogData.productId) |
|||
.then(data => { |
|||
this.dialogData.brand = data.brand; |
|||
}) |
|||
|
|||
const roadInfo = await getRoadInfoByStakeMark(this.dialogData.stakeMark); |
|||
|
|||
if (roadInfo) this.data.roadName = roadInfo.roadName; |
|||
}, |
|||
methods: { |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.FatigueWakesUp { |
|||
width: 420px; |
|||
color: #fff; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12px; |
|||
padding-bottom: 24px; |
|||
|
|||
.camera-video { |
|||
flex: 1.5; |
|||
} |
|||
|
|||
.tabs { |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
::v-deep { |
|||
.el-tabs__content { |
|||
flex: 1; |
|||
|
|||
.el-tab-pane { |
|||
height: 100%; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.bottom { |
|||
margin-top: 12px; |
|||
display: flex; |
|||
gap: 9px; |
|||
align-items: center; |
|||
justify-content: end; |
|||
|
|||
>div { |
|||
font-size: 16px; |
|||
padding: 6px 12px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,56 @@ |
|||
<template> |
|||
<Dialog v-model="modelVisible" title="设备操作"> |
|||
<div class='DeviceControlDialog'> |
|||
<DeviceParams :dialogData="dialogData" /> |
|||
|
|||
</div> |
|||
</Dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
import Dialog from "@screen/components/Dialog/index.vue"; |
|||
import DeviceParams from "./DeviceParams.vue" |
|||
|
|||
export default { |
|||
name: 'DeviceControlDialog', |
|||
components: { |
|||
Dialog, |
|||
DeviceParams |
|||
}, |
|||
model: { |
|||
prop: 'visible', |
|||
event: "update:value" |
|||
}, |
|||
props: { |
|||
visible: Boolean, |
|||
dialogData: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
}, |
|||
}, |
|||
computed: { |
|||
modelVisible: { |
|||
get() { |
|||
return this.visible |
|||
}, |
|||
set(val) { |
|||
this.$emit('update:value', val) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.DeviceControlDialog { |
|||
width: 510px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15px; |
|||
min-height: 360px; |
|||
|
|||
.tips { |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,174 @@ |
|||
<template> |
|||
<div class='DeviceParams'> |
|||
<div class="no-data" v-if="!devicesList.length" v-loading="secondLoading">暂无设备参数</div> |
|||
<Descriptions :list="devicesList" style="gap: 18px;" column="5"> |
|||
<template v-for="item in devicesList.slice(0, -1)" #[`content-${getSlotKey(item.key)}`]="{ data }"> |
|||
<span>{{ data.text }}</span> |
|||
<Switcher class="switcher" :disabled="disabled" :activeOption="activeOption" :value="data.state" |
|||
@change="(value) => handleSwitcherChange(value, data)" /> |
|||
</template> |
|||
</Descriptions> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import Descriptions from '@screen/components/Descriptions.vue'; |
|||
import Switcher from '@screen/pages/service/PublishingChannelManagement/components/Switcher.vue'; |
|||
|
|||
import request from "@/utils/request"; |
|||
import { Message } from 'element-ui'; |
|||
import { confirm } from "@screen/utils/common"; |
|||
|
|||
export default { |
|||
name: 'DeviceParams', |
|||
components: { |
|||
Descriptions, |
|||
Switcher |
|||
}, |
|||
props: { |
|||
dialogData: { |
|||
type: Object, |
|||
default: () => ({}) |
|||
}, |
|||
disabled: Boolean |
|||
}, |
|||
data() { |
|||
return { |
|||
secondLoading: true, |
|||
devicesList: [], |
|||
activeOption: { |
|||
active: { |
|||
text: "开" |
|||
}, |
|||
unActive: { |
|||
text: "关" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
// https://www.yuque.com/dayuanzhong-ovjwn/gkht0m/ww776d5kzs72ilzh?singleDoc= |
|||
// 获取设备参数 |
|||
request({ |
|||
url: `/business/device/properties/latest/${this.dialogData.iotDeviceId || '10.0.36.143-1883'}`, |
|||
method: "get", |
|||
params: {} |
|||
}) |
|||
.then(result => { |
|||
if (result.code != 200) return; |
|||
const [deviceInfo] = result.data; |
|||
|
|||
const typeMap = { |
|||
ac: '220v', |
|||
dc: '12v', |
|||
} |
|||
|
|||
for (const key in deviceInfo.formatValue) { |
|||
// electricity 电流 |
|||
// voltage 电压 |
|||
if (key.includes('electricity')) { |
|||
const args = key.match(/[a-z]+|[0-9]+$/g); |
|||
|
|||
const type = args[0], num = args.slice(-1)[0], prefix = args.slice(0, 2).join('_'); |
|||
this.devicesList.push( |
|||
{ |
|||
label: `支路${num} (${typeMap[type]}) 电压`, |
|||
key: `${prefix}_voltage_${num}`, |
|||
text: deviceInfo.formatValue[`${prefix}_voltage_${num}`], |
|||
gridColumn: 3 |
|||
}, |
|||
{ |
|||
label: '电流', |
|||
key: `${prefix}_electricity_${num}`, |
|||
text: deviceInfo.formatValue[key], |
|||
gridColumn: 2, |
|||
state: deviceInfo.value[key] > 0 |
|||
} |
|||
); |
|||
} |
|||
} |
|||
this.devicesList.push( |
|||
{ |
|||
label: '风扇', |
|||
key: `fan_status`, |
|||
text: { 0: '正常', 1: '开' }[deviceInfo.formatValue['fan_status']] || '-', |
|||
gridColumn: 1 |
|||
}, |
|||
{ |
|||
label: '箱门', |
|||
key: `door_status`, |
|||
text: { 0: '关闭', 1: '打开' }[deviceInfo.formatValue['door_status']] || '-', |
|||
gridColumn: 1 |
|||
}, |
|||
{ |
|||
label: '温度', |
|||
key: `temperature`, |
|||
text: deviceInfo.formatValue['temperature'] ? `${deviceInfo.formatValue['temperature']} °C` : '-', |
|||
gridColumn: 1 |
|||
}, |
|||
{ |
|||
label: '湿度', |
|||
key: `humidity`, |
|||
text: deviceInfo.formatValue['humidity'] || '-', |
|||
gridColumn: 1 |
|||
}, |
|||
{ |
|||
label: '市电掉电', |
|||
key: `power_status`, |
|||
text: { 0: '正常', 1: '掉电' }[deviceInfo.formatValue['power_status']] || '-', |
|||
gridColumn: 2 |
|||
}, |
|||
) |
|||
// this.data = result.rows; |
|||
// this.total = result.total; |
|||
}) |
|||
.finally(() => { |
|||
this.secondLoading = false |
|||
}) |
|||
}, |
|||
methods: { |
|||
async handleSwitcherChange(value, data) { |
|||
data.state = value; |
|||
|
|||
const isContinue = await confirm({ message: "是否要删除该辖段信息?" }) |
|||
.catch(() => { |
|||
data.state = !value; |
|||
}); |
|||
|
|||
if (!isContinue) return; |
|||
|
|||
// https://www.yuque.com/dayuanzhong-ovjwn/gkht0m/ww776d5kzs72ilzh?singleDoc= |
|||
request({ |
|||
url: `/business/device/functions/${this.dialogData.iotDeviceId}/${102}`, |
|||
method: "POST", |
|||
data: { |
|||
deviceName: data.key.match(/^[a-z]+_out|[0-9]+/g).join("_") + "_en", |
|||
// 开关:1=打开,0=关闭 |
|||
value: value ? 1 : 0 |
|||
} |
|||
}) |
|||
.then(result => { |
|||
if (result.code != 200) { |
|||
Message.error("操作失败"); |
|||
data.state = !value; |
|||
return; |
|||
}; |
|||
Message.success("操作成功"); |
|||
}) |
|||
.catch(() => { |
|||
data.state = !value; |
|||
Message.error("操作失败"); |
|||
}) |
|||
}, |
|||
getSlotKey(key) { |
|||
return key.includes('electricity') ? key : '' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.DeviceParams { |
|||
height: 100%; |
|||
} |
|||
</style> |
Loading…
Reference in new issue