| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- <template>
- <!-- 场景选择下拉框 -->
- <customHeader
- :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }"
- :options="options"
- :optionValue="optionValue"
- @change="changeSelectRow"
- >
- {{ mainTitle }}
- </customHeader>
- <!-- 默认插槽,一般用来放模型 -->
- <slot :monitor-data="monitorData"></slot>
- <div class="scene-box">
- <div class="center-container">
- <!-- 监测模块 -->
- <template v-if="activeKey == 'monitor'">
- <slot name="opration">
- <div class="button-wrapper">
- <template v-for="item in mainConfig.operations" :key="item.key">
- <template v-if="hasPermission(item.permission)">
- <div :class="{ 'button-box': true, 'button-box-disable': item.disabled }" @click="handleOperate(item)">{{ item.label }} </div>
- </template>
- </template>
- </div>
- </slot>
- <slot name="monitor">
- <ModuleCommon
- v-for="cfg in mainConfig.configs"
- :key="cfg.deviceType"
- :show-style="cfg.showStyle"
- :module-data="cfg.moduleData"
- :module-name="cfg.moduleName"
- :device-type="cfg.deviceType"
- :data="monitorData"
- :visible="true"
- />
- </slot>
- </template>
- <div v-else class="history-group">
- <!-- 场景下关联的设备有很多,在这里选择 -->
- <div v-if="showDeviceList && deviceList.length > 0" class="device-button-group">
- <div
- v-for="(device, index) in deviceList"
- :class="{ 'device-button': true, 'device-active': deviceActive == device.deviceType }"
- :key="index"
- @click="deviceChange(index)"
- >
- {{ device.deviceName }}
- </div>
- </div>
- <div class="history-container">
- <slot name="history" :device-type="deviceType" :device-id="optionValue">
- <HistoryTable
- v-if="activeKey == 'monitor_history'"
- class="vent-margin-t-20"
- :columns-type="deviceType"
- :device-type="deviceType"
- :sysId="optionValue"
- :scroll="{ y: 650 }"
- v-bind="monitorHistoryConfig"
- />
- </slot>
- <slot name="handler" :device-type="deviceType" :device-id="optionValue">
- <HandlerHistoryTable
- v-if="activeKey == 'handler_history'"
- class="vent-margin-t-20"
- columns-type="operator_history"
- :deviceType="deviceType"
- v-bind="handlerHistoryConfig"
- />
- </slot>
- <slot name="alarm" :device-type="deviceType" :device-id="optionValue">
- <AlarmHistoryTable
- v-if="activeKey == 'faultRecord'"
- columns-type="alarm"
- :device-type="deviceType"
- :sys-id="optionValue"
- v-bind="alarmHistoryConfig"
- />
- </slot>
- </div>
- </div>
- </div>
- <BottomMenu @change="changeActive" />
- </div>
- <PasswordModal
- :modal-is-show="passwordModalShown"
- :modal-title="operatingTarget?.label"
- @handle-ok="handlePasswordOK"
- @handle-cancel="passwordModalShown = false"
- />
- </template>
- <script setup lang="ts">
- import customHeader from '/@/components/vent/customHeader.vue';
- import { ref, onMounted, onUnmounted } from 'vue';
- import { getDevice, sysList } from '/@/views/vent/monitorManager/comment/comment.api';
- import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
- import ModuleCommon from '/@/views/vent/home/configurable/components/ModuleCommon.vue';
- import HistoryTable from '/@/views/vent/monitorManager/comment/HistoryTable.vue';
- import HandlerHistoryTable from '/@/views/vent/monitorManager/comment/HandlerHistoryTable.vue';
- import AlarmHistoryTable from '/@/views/vent/monitorManager/comment/AlarmHistoryTable.vue';
- import { useRouter } from 'vue-router';
- import { Config } from '/@/views/vent/deviceManager/configurationTable/types';
- import { message, Modal } from 'ant-design-vue';
- import _ from 'lodash';
- import PasswordModal from '/@/views/vent/monitorManager/comment/components/PasswordModal.vue';
- import { usePermission } from '/@/hooks/web/usePermission';
- import { deviceControlApi } from '/@/api/vent';
- type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
- type Operation = {
- label: string;
- key: string;
- value: string;
- disabled?: boolean;
- showPassword?: boolean;
- permission?: string;
- onOk?: (key: string, value: string, pwd?: string) => Promise<void>;
- };
- const props = withDefaults(
- defineProps<{
- mainTitle: string;
- /** 是否显示历史数据上方的设备类型选择器 */
- showDeviceList?: boolean;
- /** 请求场景数据传入的类型字符 */
- strtype: string;
- /** 请求场景数据传入的页面类型字符 */
- pagetype?: string;
- /** 获取各表格配置时依赖的设备类型 */
- // deviceType: string;
- /** 主要模块配置 */
- mainConfig: {
- operations: Operation[];
- configs: Config[];
- /** 获取该场景所含设备及其监测信息的API */
- monitorApi?: (params: { deviceType: string; deviceId: number | string }) => Promise<any>;
- /** 定时获取监测信息的配置,单位为毫秒,不传入即默认,传0即停用 */
- timer?: number;
- };
- /** 历史数据配置 */
- monitorHistoryConfig: {
- /** 请求历史数据时传入的类型字符 */
- columnsType?: string;
- /** 如果默认的设备类型不适用,可以传递固定的类型 */
- deviceType?: string;
- /** 仅展示已绑定设备,选择是则从系统中获取sysId下已绑定设备。仅能查询到已绑定设备的历史数据 */
- onlyBounedDevices?: boolean;
- /** 显示历史数据曲线图 */
- showHistoryCurve?: boolean;
- };
- /** 操作历史配置 */
- handlerHistoryConfig: {
- /** 请求操作历史时传入的类型字符 */
- columnsType?: string;
- /** 如果默认的设备类型不适用,可以传递固定的类型 */
- deviceType?: string;
- /** 获取操作历史的API,可以不提供以使用默认的请求 */
- deviceListApi?: (params: any) => Promise<any[]>;
- };
- /** 报警历史配置 */
- alarmHistoryConfig: {
- /** 请求报警历史时传入的类型字符 */
- columnsType?: string;
- /** 如果默认的设备类型不适用,可以传递固定的类型 */
- deviceType?: string;
- /** 获取报警历史的API,可以不提供以使用默认的请求 */
- list?: (params: any) => Promise<any[]>;
- /** 获取设备以供报警历史过滤的API,可以不提供以使用默认的请求 */
- deviceListApi?: (params: any) => Promise<any[]>;
- };
- }>(),
- {
- mainConfig: () => ({
- operations: [],
- configs: [],
- }),
- monitorHistoryConfig: () => ({}),
- handlerHistoryConfig: () => ({}),
- alarmHistoryConfig: () => ({}),
- pagetype: 'normal',
- showDeviceList: true,
- }
- );
- const { currentRoute } = useRouter();
- const { hasPermission } = usePermission();
- const activeKey = ref('monitor');
- function changeActive(activeValue) {
- activeKey.value = activeValue;
- }
- /** 场景选项 */
- const options = ref([]);
- /** 已选择了的场景的id */
- const optionValue = ref('');
- /** 获取左上角场景选择框数据的方法,如果此时初始场景未赋值则选择首项做初始化 */
- async function getSysDataSource() {
- const res = await sysList({ strtype: props.strtype, pagetype: props.pagetype }).catch(() => {
- message.error('获取场景数据时发生了错误');
- });
- // 初始时选择第一条数据
- options.value = res.records || [];
- if (!optionValue.value) {
- changeSelectRow(options.value[0]['id']);
- }
- }
- // 切换检测数据
- function changeSelectRow(deviceID) {
- optionValue.value = deviceID;
- getDeviceList();
- }
- /** 当前场景所关联设备 */
- const deviceList = ref<DeviceType[]>([]);
- const deviceActive = ref('');
- const deviceType = ref('');
- /** 选择设备 */
- function deviceChange(index) {
- deviceType.value = deviceList.value[index]?.deviceType || '';
- deviceActive.value = deviceList.value[index]?.deviceType || '';
- }
- /** 查询当前场景所关联设备列表 */
- async function getDeviceList() {
- const { msgTxt = [] } = await getDevice({ devicetype: 'sys', systemID: optionValue.value }).catch(() => {
- message.error('获取已绑定设备时发生了错误');
- });
- deviceList.value = msgTxt.reduce((arr, item) => {
- const data = item.datalist.map((data: any) => {
- return Object.assign(data, data.readData);
- });
- // sys代表场景本身,应该过滤掉去处理该场景下的关联设备
- if (item.type != 'sys') {
- arr.unshift({
- deviceType: item.type,
- deviceName: item.typeName || item.datalist[0].typeName,
- datalist: data,
- });
- }
- return arr;
- }, []);
- if (!deviceActive.value) {
- deviceChange(0);
- }
- }
- let timer: NodeJS.Timeout;
- /** 场景的监测数据 */
- const monitorData = ref<any>({});
- /** 获取本场景下所绑定的设备,将监测数据赋值 */
- async function getMonitor() {
- if (props.mainConfig.monitorApi) {
- monitorData.value = await props.mainConfig
- .monitorApi({
- deviceType: deviceType.value,
- deviceId: optionValue.value,
- })
- .catch(() => {
- message.error('获取已绑定设备时发生了错误');
- });
- } else if (optionValue.value) {
- const { msgTxt = [] } = await getDevice({ devicetype: 'sys', systemID: optionValue.value }).catch(() => {
- message.error('获取已绑定设备时发生了错误');
- });
- const temp = {};
- msgTxt.forEach((item) => {
- _.set(temp, item.type, item.datalist);
- });
- monitorData.value = temp;
- }
- }
- /** 密码提示框是否显示 */
- const passwordModalShown = ref(false);
- /** 下发操作时的目标配置 */
- const operatingTarget = ref<Operation>();
- /** 操作按钮点击后根据配置弹出确认框,初始化数据 */
- function handleOperate(item: Operation) {
- if (item.disabled) return;
- operatingTarget.value = item;
- if (item.showPassword) {
- passwordModalShown.value = true;
- } else {
- Modal.confirm({
- title: '操作确认',
- content: `确定要进行${operatingTarget.value.label}操作吗?`,
- iconType: 'info',
- onOk: () => handlePasswordOK(),
- });
- }
- }
- /** 密码输入后确认的回调 */
- function handlePasswordOK(pwd?: string) {
- if (!operatingTarget.value) return message.error('操作目标不存在');
- const { onOk = deviceControl, key, value } = operatingTarget.value;
- return onOk(key, value, pwd)
- .then(() => {
- passwordModalShown.value = false;
- })
- .finally(() => {
- operatingTarget.value = undefined;
- });
- }
- function deviceControl(key: string, value: string, pwd?: string) {
- return deviceControlApi({
- deviceid: optionValue.value,
- devicetype: deviceType.value,
- password: pwd,
- paramcode: key,
- value: value,
- })
- .then((r) => {
- if (!r.success) throw r.message || '操作失败';
- message.success('指令下发成功');
- })
- .catch((e) => {
- message.error(typeof e === 'string' ? e : '指令下发失败');
- });
- }
- onMounted(async () => {
- if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
- optionValue.value = currentRoute.value['query']['id'] as string;
- }
- await getSysDataSource();
- if (props.mainConfig.timer !== 0) {
- timer = setInterval(() => {
- getMonitor();
- }, props.mainConfig.timer || 5000);
- } else {
- getMonitor();
- }
- });
- onUnmounted(() => {
- clearInterval(timer);
- });
- </script>
- <style lang="less" scoped>
- @import '/@/design/vent/modal.less';
- @ventSpace: zxm;
- .scene-box {
- --image-tab-group-bg: url('/@/assets/images/vent/tab-group-bg.png');
- margin-top: 40px;
- pointer-events: none;
- .history-group {
- margin-top: 80px;
- padding: 0 10px;
- .history-container {
- pointer-events: auto;
- background: #6195af1a;
- // width: 100%;
- border: 1px solid #00fffd22;
- padding: 10px 0;
- box-shadow: 0 0 20px #44b4ff33 inset;
- }
- }
- .device-button-group {
- // margin: 0 20px;
- padding: 0 10px;
- display: flex;
- pointer-events: auto;
- position: relative;
- &::after {
- position: absolute;
- content: '';
- width: 100%;
- height: 2px;
- top: 30px;
- left: -1px;
- border-bottom: 1px solid #0efcff;
- }
- .device-button {
- padding: 4px 15px;
- position: relative;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 14px;
- color: #fff;
- cursor: pointer;
- margin: 0 3px;
- &::before {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- border: 1px solid #6176af;
- transform: skewX(-38deg);
- background-color: rgba(0, 77, 103, 85%);
- z-index: -1;
- }
- }
- .device-active {
- // color: #0efcff;
- &::before {
- border-color: #0efcff;
- box-shadow: 1px 1px 3px 1px #0efcff inset;
- }
- }
- }
- }
- .center-container {
- width: 100%;
- height: calc(100% - 150px);
- }
- .input-box {
- display: flex;
- align-items: center;
- padding-left: 10px;
- .input-title {
- color: #73e8fe;
- width: auto;
- }
- .@{ventSpace}-input-number {
- border-color: #ffffff88;
- }
- margin-right: 10px;
- }
- .button-wrapper {
- position: relative;
- top: 30px;
- left: 500px;
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 10px;
- width: 1165px !important;
- height: 75px;
- background: var(--image-tab-group-bg) no-repeat;
- background-image: 100% 100%;
- padding: 0 30px;
- z-index: 10;
- .button-box {
- margin: 0 10px;
- }
- }
- .button-box {
- position: relative;
- padding: 5px;
- border-radius: 5px;
- width: auto;
- height: 34px;
- border: 1px solid var(--vent-base-border);
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--vent-font-color);
- padding: 0 10px;
- cursor: pointer;
- pointer-events: all;
- &:hover {
- background: var(--vent-device-manager-control-btn-hover);
- }
- &::before {
- width: calc(100% - 6px);
- height: 26px;
- content: '';
- position: absolute;
- top: 3px;
- right: 0;
- left: 3px;
- bottom: 0;
- z-index: -1;
- border-radius: inherit;
- /*important*/
- background: var(--vent-device-manager-control-btn);
- }
- }
- .button-box-disable {
- cursor: not-allowed;
- border: 1px solid var(--vent-base-border);
- &:hover {
- background: none;
- }
- &:before {
- background: linear-gradient(#5897c299, #4a92a899);
- }
- }
- </style>
|