123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- <!-- eslint-disable vue/multi-word-component-names -->
- <template>
- <!-- Header部分 -->
- <div v-if="headerConfig.show" class="w-100% flex content__header">
- <!-- 选择下拉框,自动填充剩余空间,这种实现是因为 Select 不支持 suffix -->
- <Dropdown
- v-if="headerConfig.showSelector"
- class="flex-grow-1 content__header_left"
- :trigger="['click']"
- :bordered="false"
- @open-change="headerVisible = $event"
- >
- <div class="w-100% flex flex-items-center" @click.prevent>
- <SwapOutlined class="w-30px" />
- <div class="flex-grow-1">
- {{ selectedDeviceLabel }}
- </div>
- <CaretUpOutlined class="w-30px" v-if="headerVisible" />
- <CaretDownOutlined class="w-30px" v-else />
- </div>
- <template #overlay>
- <Menu :selected-keys="[selectedDeviceID]" @click="headerSelectHandler">
- <MenuItem v-for="item in options" :key="item.value" :title="item.label">
- {{ item.label }}
- </MenuItem>
- </Menu>
- </template>
- </Dropdown>
- <template v-if="headerConfig.showSlot">
- <div class="flex flex-items-center flex-grow-1 content__header_right">
- <SwapOutlined class="w-30px" />
- <div class="flex-grow-1">
- {{ selectedDeviceSlot }}
- </div>
- </div>
- </template>
- </div>
- <!-- 主体内容部分 -->
- <div class="content" :class="{ content_without_header: !headerConfig.show }">
- <!-- 背景 -->
- <img v-if="background.show && background.type === 'image'" class="content__background" :src="background.link" />
- <video
- v-if="background.show && background.type === 'video'"
- class="content__background content__background_video"
- width="100%"
- autoplay
- loop
- muted
- >
- <source :src="background.link" />
- Not Supportted Link Or Browser
- </video>
- <template v-for="config in layoutConfig" :key="config.key">
- <!-- 告示板部分 -->
- <div v-if="config.key === 'board'" class="flex flex-justify-around pt-10px pb-10px">
- <MiniBoard
- v-for="item in config.items"
- :key="item.prop"
- :label="item.label"
- :value="item.value"
- :type="config.type"
- :layout="config.layout"
- />
- </div>
- <!-- 图表部分,这部分通常需要填充,有告示板、Header等内容需要填充父级 -->
- <template v-if="config.key === 'chart'">
- <CustomChart :chart-config="config.config" :chart-data="config.data" class="flex-grow" />
- </template>
- <!-- 通常列表部分 -->
- <template v-if="config.key === 'list'">
- <template v-if="config.type === 'timeline'">
- <TimelineList :list-config="config.items" />
- </template>
- <template v-else>
- <CustomList :type="config.type" :list-config="config.items" />
- </template>
- </template>
- <!-- 表格部分,这部分通常是占一整个模块的 -->
- <template v-if="config.key === 'table'">
- <CommonTable
- v-if="config.type === 'A'"
- :columns="config.columns"
- :data="tableData"
- class="mt-20px mb-10px text-center flex-grow overflow-auto"
- />
- <CustomTable
- v-else
- :type="config.type"
- :columns="config.columns"
- :data="tableData"
- class="mt-20px mb-10px text-center flex-grow overflow-auto"
- />
- </template>
- <template v-if="config.key === 'blast_delta'">
- <BlastDelta class="mt-10px mb-10px" :pos-monitor="blastDeltaData" :canvas-size="{ width: 250, height: 147 }" />
- </template>
- <template v-if="config.key === 'fire_control'">
- <FIreControl class="mt-10px mb-10px" />
- </template>
- <template v-if="config.key === 'fire_warn'">
- <FIreWarn class="mt-10px mb-10px" />
- </template>
- </template>
- </div>
- </template>
- <script lang="ts" setup>
- import { computed, onMounted, ref } from 'vue';
- import {
- Config,
- // ModuleDataBoard,
- // ModuleDataChart,
- // ModuleDataList,
- // ModuleDataPreset,
- // ModuleDataTable,
- } from '../../../deviceManager/configurationTable/types';
- import { useInitDevices } from '../hooks/useInit';
- import { MenuItem, Menu, Dropdown } from 'ant-design-vue';
- import { SwapOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons-vue';
- import MiniBoard from './MiniBoard.vue';
- import TimelineList from './TimelineList.vue';
- import CustomList from './CustomList.vue';
- import CustomTable from './CustomTable.vue';
- import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
- import CustomChart from './CustomChart.vue';
- import { get, clone } from 'lodash-es';
- import CommonTable from '../../billboard/components/CommonTable.vue';
- import BlastDelta from '../../../monitorManager/deviceMonitor/components/device/modal/blastDelta.vue';
- import FIreWarn from './FIreWarn.vue';
- import FIreControl from './FIreControl.vue';
- import { posMonitorData } from '../configurable.data';
- const props = defineProps<{
- deviceType: Config['deviceType'];
- moduleData: Config['moduleData'];
- showStyle: Config['showStyle'];
- }>();
- const { header: headerConfig, background, layout } = props.moduleData;
- /** 根据配置里的layout将配置格式化为带 key 的具体配置,例如:[{ key: 'list', value: any, ...ModuleDataList }] */
- const layoutConfig = computed(() => {
- const data = selectedDevice.value;
- const board = clone(props.moduleData.board);
- const list = clone(props.moduleData.list);
- const chart = clone(props.moduleData.chart);
- const table = clone(props.moduleData.table);
- const preset = clone(props.moduleData.preset);
- return layout.reduce((arr: any[], key) => {
- switch (key) {
- case 'board': {
- const cfg = board[0];
- if (!cfg) break;
- arr.push({
- ...cfg,
- key,
- items: cfg.items.map((i) => {
- return {
- ...i,
- value: getFormattedText(data, i.prop, i.formatter),
- };
- }),
- });
- break;
- }
- case 'list': {
- const cfg = list.shift();
- if (!cfg) break;
- arr.push({
- ...cfg,
- key,
- items: cfg.items.map((i) => {
- return {
- ...i,
- value: getFormattedText(data, i.prop, i.formatter),
- };
- }),
- });
- break;
- }
- case 'chart': {
- const cfg = chart.shift();
- if (!cfg) break;
- arr.push({
- key,
- config: cfg,
- data: get(data, cfg.readFrom, []),
- });
- break;
- }
- case 'table': {
- const cfg = table.shift();
- if (!cfg) break;
- arr.push({
- ...cfg,
- key,
- columns: (cfg.columns || []).map((e) => {
- return {
- name: e.label,
- prop: e.prop,
- };
- }),
- data: get(data, cfg.readFrom, []),
- });
- break;
- }
- default: {
- const cfg = preset.shift();
- if (!cfg) break;
- arr.push({
- key,
- config: cfg,
- });
- break;
- }
- }
- return arr;
- }, []);
- });
- // 额外的 header 相关的变量
- const headerVisible = ref(false);
- function headerSelectHandler({ key }) {
- selectedDeviceID.value = key;
- }
- // 额外的告示牌相关的变量
- // const boardConfig = computed(() => {
- // const data = selectedDevice.value;
- // return (board || []).map((b) => {
- // return {
- // ...b.items,
- // value: getFormattedText(data, b.prop, b.formatter),
- // };
- // });
- // });
- // 额外的时间线列表相关的变量
- // const listConfig = computed(() => {
- // const data = selectedDevice.value;
- // return (list || []).map((b) => {
- // return {
- // ...b,
- // value: getFormattedText(data, b.prop, b.formatter),
- // };
- // });
- // });
- // const listType = computed(() => {
- // return list[0]?.type || 'A';
- // });
- // const chartConfig = computed(() => {
- // return chart[0];
- // });
- // const chartData = computed(() => {
- // const data = selectedDevice.value;
- // return get(data, chart[0]?.readFrom, []);
- // });
- // const tableConfig = computed(() => {
- // return {
- // columns: (table[0]?.columns || []).map((e) => {
- // return {
- // name: e.label,
- // prop: e.prop,
- // };
- // }),
- // };
- // });
- const tableData = computed(() => {
- // const data = selectedDevice.value;
- return [
- {
- index: '1',
- time: '2024/07/22 07:00',
- warn: '未知',
- cate: 'xxx综采工作面',
- temp: '26',
- wspd: '2',
- spst: 'ON',
- },
- {
- index: '2',
- time: '2024/07/22 08:00',
- warn: '未知',
- cate: 'xxx综采工作面',
- temp: '26',
- wspd: '2',
- spst: 'ON',
- },
- {
- index: '3',
- time: '2024/07/22 09:00',
- warn: '未知',
- cate: 'xxx综采工作面',
- temp: '26',
- wspd: '2',
- spst: 'ON',
- },
- {
- index: '4',
- time: '2024/07/22 10:00',
- warn: '未知',
- cate: 'xxx综采工作面',
- temp: '26',
- wspd: '2',
- spst: 'ON',
- },
- ];
- // return get(data, table[0]?.readFrom, []);
- });
- const blastDeltaData = ref();
- const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
- props.deviceType,
- headerConfig
- );
- onMounted(() => {
- blastDeltaData.value = posMonitorData;
- fetchDevices();
- });
- </script>
- <style lang="less" scoped>
- @import '@/design/vent/color.less';
- /* Header 相关的样式 */
- .content__header {
- height: 30px;
- background-image: linear-gradient(90deg, #3df6ff44, transparent 20%, transparent 80%, #3df6ff44);
- }
- .content__header_left {
- border-left: 3px solid;
- border-right: 3px solid;
- border-image-source: linear-gradient(to top, #185f7188, #3df6ff, #185f7188);
- border-image-slice: 1;
- }
- .content__header_right {
- border-left: 3px solid;
- border-right: 3px solid;
- border-image-source: linear-gradient(to top, #185f7188, #3df6ff, #185f7188);
- border-image-slice: 1;
- min-width: 160px;
- }
- .content {
- height: calc(100% - 30px);
- position: relative;
- // z-index: -2;
- display: flex;
- flex-direction: column;
- }
- .content_without_header {
- height: 100%;
- }
- .content__background {
- width: 100%;
- height: 100%;
- position: absolute;
- top: 0;
- left: 0;
- z-index: -1;
- object-fit: fill;
- }
- ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
- /* background-color: transparent; */
- color: #fff;
- }
- ::v-deep .zxm-select-arrow {
- color: #fff;
- }
- ::v-deep .zxm-select-selection-item {
- color: #fff !important;
- }
- ::v-deep .zxm-select-selection-placeholder {
- color: #fff !important;
- }
- </style>
|