窗口选中,拖动功能

This commit is contained in:
fangxiang 2021-08-06 10:54:03 +08:00
parent be4f57530e
commit 9e05658b3b
11 changed files with 243 additions and 62 deletions

View File

@ -1,11 +1,13 @@
<template> <template>
<q-ajax-bar position="top" color="accent" size="5px" skip-hijack /> <div class="fit">
<router-view /> <q-ajax-bar position="top" color="accent" size="5px" skip-hijack />
<router-view />
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import EventBus from "src/common/EventBus"; import EventBus, { EventNamesDefine } from "src/common/EventBus";
export default defineComponent({ export default defineComponent({
name: "App", name: "App",
@ -15,7 +17,7 @@ export default defineComponent({
document.title = $t.t("title"); document.title = $t.t("title");
window.onresize = (evt: any) => window.onresize = (evt: any) =>
EventBus.getInstance().emit("windowResize", evt); EventBus.getInstance().emit(EventNamesDefine.WindowResize, evt);
return {}; return {};
}, },
}); });

View File

@ -1,9 +1,30 @@
export namespace Common { export namespace Common {
export const waitFor = async (ms: number) => { export const waitFor = async (ms: number) => {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
resolve(null); resolve(null);
}, ms); }, ms);
}); });
}; };
export const getSignalSourceIcon = (item_type: string) => {
let icon_map = new Map([
["EwindowType::Normal", "img:source_icon/hdmi.png"],
["EwindowType::Multimedia", "img:source_icon/media.png"],
["EwindowType::Web", "img:source_icon/web.png"],
["EwindowType::Image", "img:source_icon/image.png"],
["EwindowType::Pdf", "img:source_icon/pdf.png"],
["EwindowType::Ppt", "img:source_icon/ppt.png"],
["EwindowType::Rtsp", "img:source_icon/rtsp.png"],
["EwindowType::Subtitles", "img:source_icon/subtitles.png"],
["EwindowType::Weather", "img:source_icon/weather.png"],
["EwindowType::HdmiIn", "img:source_icon/hdmi.png"],
]);
if (icon_map.has(item_type)) {
return icon_map.get(item_type);
} else {
return "img:source_icon/hdmi.png";
}
};
} }

View File

@ -10,3 +10,8 @@ export default class EventBus extends EventEmitter {
return EventBus._instance; return EventBus._instance;
} }
} }
export namespace EventNamesDefine {
export const UnSelectAllWindows = "unselect_all_windows";
export const WindowResize = "windowResize";
}

View File

@ -4,6 +4,10 @@ import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
import ClientConnection from "./ClientConnection"; import ClientConnection from "./ClientConnection";
export default class GlobalData { export default class GlobalData {
getSignalSource(uuid: string) {
return this.signal_source.find((item) => item && item.uuid == uuid);
throw new Error("Method not implemented.");
}
private static _instance: GlobalData | null = null; private static _instance: GlobalData | null = null;
public static get kWebsocketResource() { public static get kWebsocketResource() {

124
src/components/Window.vue Normal file
View File

@ -0,0 +1,124 @@
<template>
<div
:class="selected ? 'window_selected' : 'window_normal'"
@click="onClick"
@mousedown="onMouseDown"
@mousemove="onMouseMove"
@mouseleave="onMouseLeave"
@mouseup="onMouseLeave"
>
<div class="title_bar full-width">
<q-icon :name="getItemIcon(signal_source.window_type)" />
<span>{{ signal_source.name }}</span>
</div>
</div>
</template>
<style scoped>
.window_selected {
outline-style: dashed;
outline-color: #166fab;
}
.window_normal {
border: 1px solid #166fab;
}
.title_bar {
border: 1px solid black;
}
</style>
<script lang="ts">
import { Common } from "src/common/Common";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import GlobalData from "src/common/GlobalData";
import { defineComponent, ref } from "vue";
import { useStore } from "src/store";
export default defineComponent({
name: "ComponentWindow",
components: {},
props: {
signal_source_table_uuid: {
type: String,
required: true,
},
window: {
type: Object,
required: true,
},
},
emits: ["move_window"],
setup(props, { emit }) {
const $store = useStore();
const signal_source = ref(
GlobalData.getInstance().getSignalSource(props.signal_source_table_uuid)
);
let selected = ref(false);
EventBus.getInstance().on(EventNamesDefine.UnSelectAllWindows, () => {
selected.value = false;
});
let mouse_down_flag = false;
let mouse_last_pos_x = 0;
let mouse_last_pos_y = 0;
let can_move = true;
let can_resize = true;
const cleanMouseDownFlag = () => {
mouse_down_flag = false;
mouse_last_pos_x = 0;
mouse_last_pos_y = 0;
};
return {
signal_source,
selected,
onClick(evt: PointerEvent) {
EventBus.getInstance().emit(EventNamesDefine.UnSelectAllWindows);
selected.value = true;
},
onMouseDown(evt: MouseEvent) {
if (evt.button == 0) {
mouse_down_flag = true;
mouse_last_pos_x = evt.x;
mouse_last_pos_y = evt.y;
}
},
onMouseMove(evt: MouseEvent) {
if (mouse_down_flag && selected.value) {
emit(
"move_window",
$store,
props.window,
evt.x - mouse_last_pos_x,
evt.y - mouse_last_pos_y
);
mouse_last_pos_x = evt.x;
mouse_last_pos_y = evt.y;
}
},
cleanMouseDownFlag,
onMouseLeave(evt: MouseEvent) {
cleanMouseDownFlag();
},
onMouseUp(evt: MouseEvent) {
cleanMouseDownFlag();
},
getItemIcon(item_type: string) {
return Common.getSignalSourceIcon(item_type);
},
};
},
});
</script>

View File

@ -14,7 +14,6 @@ strong {
-webkit-backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
backdrop-filter: blur(7px); backdrop-filter: blur(7px);
background-color: #0000001a; background-color: #0000001a;
height: 50px;
} }
body { body {

View File

@ -13,6 +13,8 @@
<meta name="HandheldFriendly" content="true" /> <meta name="HandheldFriendly" content="true" />
<meta name="full-screen" content="yes" /> <meta name="full-screen" content="yes" />
<meta name="x5-fullscreen" content="true" /> <meta name="x5-fullscreen" content="true" />
<meta name="screen-orientation" content="landscape" />
<meta name="x5-orientation" content="landscape" />
<script> <script>
/*@cc_on window.location.href="http://support.dmeng.net/upgrade-your-browser.html?referrer="+encodeURIComponent(window.location.href); @*/ /*@cc_on window.location.href="http://support.dmeng.net/upgrade-your-browser.html?referrer="+encodeURIComponent(window.location.href); @*/
</script> </script>

View File

@ -3,25 +3,11 @@
<q-header elevated class="header text-black"> <q-header elevated class="header text-black">
<top-tool-bar /> <top-tool-bar />
</q-header> </q-header>
<q-drawer <q-drawer v-model="data.show_left_drawer" side="left" bordered>
no-swipe-open
no-swipe-close
no-swipe-backdrop
v-model="data.show_left_drawer"
side="left"
bordered
>
<left-tool-bar /> <left-tool-bar />
</q-drawer> </q-drawer>
<q-drawer <q-drawer v-model="data.show_right_drawer" side="right" bordered>
no-swipe-open
no-swipe-close
no-swipe-backdrop
v-model="data.show_right_drawer"
side="right"
bordered
>
<!-- drawer content --> <!-- drawer content -->
<right-tool-bar /> <right-tool-bar />
</q-drawer> </q-drawer>
@ -35,11 +21,11 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive } from 'vue'; import { defineComponent, reactive } from "vue";
import LeftToolBar from 'src/pages/LeftToolBar.vue'; import LeftToolBar from "src/pages/LeftToolBar.vue";
import RightToolBar from 'src/pages/RightToolBar.vue'; import RightToolBar from "src/pages/RightToolBar.vue";
import TopToolBar from 'src/pages/TopToolBar.vue'; import TopToolBar from "src/pages/TopToolBar.vue";
class _Data { class _Data {
show_left_drawer = true; show_left_drawer = true;
@ -47,7 +33,7 @@ class _Data {
} }
export default defineComponent({ export default defineComponent({
name: 'MainLayout', name: "MainLayout",
components: { LeftToolBar, RightToolBar, TopToolBar }, components: { LeftToolBar, RightToolBar, TopToolBar },

View File

@ -75,6 +75,7 @@
import { defineComponent, computed } from "vue"; import { defineComponent, computed } from "vue";
import { useStore } from "src/store"; import { useStore } from "src/store";
import { SignalSourceTreeItemEntity } from "src/entities/SignalSourceEntity"; import { SignalSourceTreeItemEntity } from "src/entities/SignalSourceEntity";
import { Common } from "src/common/Common";
export default defineComponent({ export default defineComponent({
name: "PageLeftToolBar", name: "PageLeftToolBar",
@ -102,24 +103,7 @@ export default defineComponent({
} }
}, },
getItemIcon(item_type: string) { getItemIcon(item_type: string) {
let icon_map = new Map([ return Common.getSignalSourceIcon(item_type);
["EwindowType::Normal", "img:source_icon/hdmi.png"],
["EwindowType::Multimedia", "img:source_icon/media.png"],
["EwindowType::Web", "img:source_icon/web.png"],
["EwindowType::Image", "img:source_icon/image.png"],
["EwindowType::Pdf", "img:source_icon/pdf.png"],
["EwindowType::Ppt", "img:source_icon/ppt.png"],
["EwindowType::Rtsp", "img:source_icon/rtsp.png"],
["EwindowType::Subtitles", "img:source_icon/subtitles.png"],
["EwindowType::Weather", "img:source_icon/weather.png"],
["EwindowType::HdmiIn", "img:source_icon/hdmi.png"],
]);
if (icon_map.has(item_type)) {
return icon_map.get(item_type);
} else {
return "img:source_icon/hdmi.png";
}
}, },
}; };
}, },

View File

@ -19,11 +19,14 @@
</q-list> </q-list>
</q-popup-proxy> </q-popup-proxy>
<div id="windows" style="position: absolute"> <div id="windows" style="position: absolute">
<div <window
@move_window="move_window"
:ref="'window_' + index" :ref="'window_' + index"
v-for="(item, index) in windows" v-for="(item, index) in windows"
:key="index" :key="index"
class="window" class="window"
:signal_source_table_uuid="item.signal_source_table_uuid"
:window="item"
:style="{ :style="{
top: item.y / wall_height_scaler + 'px', top: item.y / wall_height_scaler + 'px',
left: item.x / wall_width_scaler + 'px', left: item.x / wall_width_scaler + 'px',
@ -33,9 +36,9 @@
> >
{{ wall_height_scaler }} {{ wall_height_scaler }}
{{ wall_width_scaler }} {{ wall_width_scaler }}
</div> </window>
</div> </div>
<div ref="wall_grids"> <div ref="wall_grids" @click="onWallGridsClick">
<div <div
v-for="row in wall_rows" v-for="row in wall_rows"
:key="row" :key="row"
@ -92,24 +95,33 @@
} }
.wall_item { .wall_item {
border: 1px solid black; border: 1px solid gray;
} }
.window { .window {
border: 1px solid rebeccapurple;
position: absolute; position: absolute;
} }
</style> </style>
<script lang="ts"> <script lang="ts">
import GlobalData from "src/common/GlobalData"; import GlobalData from "src/common/GlobalData";
import { defineComponent, ref, Ref, computed, watch, onMounted } from "vue"; import {
defineComponent,
ref,
Ref,
computed,
watch,
onMounted,
getCurrentInstance,
} from "vue";
import { Common } from "src/common/Common"; import { Common } from "src/common/Common";
import { Protocol } from "src/entities/WSProtocol"; import { Protocol } from "src/entities/WSProtocol";
import Window from "src/components/Window.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useStore } from "src/store"; import { useStore } from "src/store";
import EventBus from "src/common/EventBus"; import EventBus, { EventNamesDefine } from "src/common/EventBus";
import MultimediaWindowEntity from "src/entities/MultimediaWindowEntity";
interface _OptionsType { interface _OptionsType {
$t: any; $t: any;
@ -186,8 +198,7 @@ const _initialize = async (options: _OptionsType) => {
export default defineComponent({ export default defineComponent({
name: "PageWall", name: "PageWall",
components: {}, components: { Window },
setup() { setup() {
const $store = useStore(); const $store = useStore();
const $t = useI18n(); const $t = useI18n();
@ -256,7 +267,7 @@ export default defineComponent({
} }
}; };
EventBus.getInstance().on("windowResize", () => { EventBus.getInstance().on(EventNamesDefine.WindowResize, () => {
calcWallVWScaler(); calcWallVWScaler();
}); });
@ -313,6 +324,29 @@ export default defineComponent({
onDragOver(e: DragEvent) { onDragOver(e: DragEvent) {
e.preventDefault(); e.preventDefault();
}, },
onWallGridsClick(e: MouseEvent) {
EventBus.getInstance().emit(EventNamesDefine.UnSelectAllWindows);
},
move_window: (
$store: ReturnType<typeof useStore>,
window: any,
offset_x: number,
offset_y: number
) => {
$store.commit("setWindowPropertys", [
{
window,
property_name: "x",
value: window.x + offset_x * wall_width_scaler.value,
},
{
window,
property_name: "y",
value: window.y + offset_y * wall_height_scaler.value,
},
]);
},
}; };
}, },
}); });

View File

@ -62,6 +62,26 @@ export default store(function (/* { ssrContext } */) {
}, },
mutations: { mutations: {
setWindowPropertys(state: StateInterface, playload?: any[]) {
if (playload && Array.isArray(playload)) {
for (let item of playload) {
const window = item.window;
const property_name = item.property_name;
const value = item.value;
if (window && property_name) {
window[property_name] = value;
}
}
}
},
setWindowProperty(state: StateInterface, playload?: any) {
const window = playload.window;
const property_name = playload.property_name;
const value = playload.value;
if (window && property_name) {
window[property_name] = value;
}
},
setWindows(state: StateInterface, playload?: any) { setWindows(state: StateInterface, playload?: any) {
let windows = playload as MultimediaWindowEntity[]; let windows = playload as MultimediaWindowEntity[];
if (windows) { if (windows) {