窗口选中,拖动功能
This commit is contained in:
parent
be4f57530e
commit
9e05658b3b
10
src/App.vue
10
src/App.vue
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<q-ajax-bar position="top" color="accent" size="5px" skip-hijack />
|
||||
<router-view />
|
||||
<div class="fit">
|
||||
<q-ajax-bar position="top" color="accent" size="5px" skip-hijack />
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import EventBus from "src/common/EventBus";
|
||||
import EventBus, { EventNamesDefine } from "src/common/EventBus";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App",
|
||||
|
@ -15,7 +17,7 @@ export default defineComponent({
|
|||
document.title = $t.t("title");
|
||||
|
||||
window.onresize = (evt: any) =>
|
||||
EventBus.getInstance().emit("windowResize", evt);
|
||||
EventBus.getInstance().emit(EventNamesDefine.WindowResize, evt);
|
||||
return {};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,9 +1,30 @@
|
|||
export namespace Common {
|
||||
export const waitFor = async (ms: number) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(null);
|
||||
}, ms);
|
||||
});
|
||||
};
|
||||
export const waitFor = async (ms: number) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(null);
|
||||
}, 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";
|
||||
}
|
||||
};
|
||||
}
|
|
@ -10,3 +10,8 @@ export default class EventBus extends EventEmitter {
|
|||
return EventBus._instance;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace EventNamesDefine {
|
||||
export const UnSelectAllWindows = "unselect_all_windows";
|
||||
export const WindowResize = "windowResize";
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@ import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
|
|||
import ClientConnection from "./ClientConnection";
|
||||
|
||||
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;
|
||||
|
||||
public static get kWebsocketResource() {
|
||||
|
|
|
@ -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>
|
|
@ -14,7 +14,6 @@ strong {
|
|||
-webkit-backdrop-filter: blur(7px);
|
||||
backdrop-filter: blur(7px);
|
||||
background-color: #0000001a;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
<meta name="HandheldFriendly" content="true" />
|
||||
<meta name="full-screen" content="yes" />
|
||||
<meta name="x5-fullscreen" content="true" />
|
||||
<meta name="screen-orientation" content="landscape" />
|
||||
<meta name="x5-orientation" content="landscape" />
|
||||
<script>
|
||||
/*@cc_on window.location.href="http://support.dmeng.net/upgrade-your-browser.html?referrer="+encodeURIComponent(window.location.href); @*/
|
||||
</script>
|
||||
|
|
|
@ -3,25 +3,11 @@
|
|||
<q-header elevated class="header text-black">
|
||||
<top-tool-bar />
|
||||
</q-header>
|
||||
<q-drawer
|
||||
no-swipe-open
|
||||
no-swipe-close
|
||||
no-swipe-backdrop
|
||||
v-model="data.show_left_drawer"
|
||||
side="left"
|
||||
bordered
|
||||
>
|
||||
<q-drawer v-model="data.show_left_drawer" side="left" bordered>
|
||||
<left-tool-bar />
|
||||
</q-drawer>
|
||||
|
||||
<q-drawer
|
||||
no-swipe-open
|
||||
no-swipe-close
|
||||
no-swipe-backdrop
|
||||
v-model="data.show_right_drawer"
|
||||
side="right"
|
||||
bordered
|
||||
>
|
||||
<q-drawer v-model="data.show_right_drawer" side="right" bordered>
|
||||
<!-- drawer content -->
|
||||
<right-tool-bar />
|
||||
</q-drawer>
|
||||
|
@ -35,11 +21,11 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive } from 'vue';
|
||||
import { defineComponent, reactive } from "vue";
|
||||
|
||||
import LeftToolBar from 'src/pages/LeftToolBar.vue';
|
||||
import RightToolBar from 'src/pages/RightToolBar.vue';
|
||||
import TopToolBar from 'src/pages/TopToolBar.vue';
|
||||
import LeftToolBar from "src/pages/LeftToolBar.vue";
|
||||
import RightToolBar from "src/pages/RightToolBar.vue";
|
||||
import TopToolBar from "src/pages/TopToolBar.vue";
|
||||
|
||||
class _Data {
|
||||
show_left_drawer = true;
|
||||
|
@ -47,7 +33,7 @@ class _Data {
|
|||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
name: "MainLayout",
|
||||
|
||||
components: { LeftToolBar, RightToolBar, TopToolBar },
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
import { defineComponent, computed } from "vue";
|
||||
import { useStore } from "src/store";
|
||||
import { SignalSourceTreeItemEntity } from "src/entities/SignalSourceEntity";
|
||||
import { Common } from "src/common/Common";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PageLeftToolBar",
|
||||
|
@ -102,24 +103,7 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
getItemIcon(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";
|
||||
}
|
||||
return Common.getSignalSourceIcon(item_type);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -19,11 +19,14 @@
|
|||
</q-list>
|
||||
</q-popup-proxy>
|
||||
<div id="windows" style="position: absolute">
|
||||
<div
|
||||
<window
|
||||
@move_window="move_window"
|
||||
:ref="'window_' + index"
|
||||
v-for="(item, index) in windows"
|
||||
:key="index"
|
||||
class="window"
|
||||
:signal_source_table_uuid="item.signal_source_table_uuid"
|
||||
:window="item"
|
||||
:style="{
|
||||
top: item.y / wall_height_scaler + 'px',
|
||||
left: item.x / wall_width_scaler + 'px',
|
||||
|
@ -33,9 +36,9 @@
|
|||
>
|
||||
{{ wall_height_scaler }}
|
||||
{{ wall_width_scaler }}
|
||||
</div>
|
||||
</window>
|
||||
</div>
|
||||
<div ref="wall_grids">
|
||||
<div ref="wall_grids" @click="onWallGridsClick">
|
||||
<div
|
||||
v-for="row in wall_rows"
|
||||
:key="row"
|
||||
|
@ -92,24 +95,33 @@
|
|||
}
|
||||
|
||||
.wall_item {
|
||||
border: 1px solid black;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
.window {
|
||||
border: 1px solid rebeccapurple;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
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 { Protocol } from "src/entities/WSProtocol";
|
||||
import Window from "src/components/Window.vue";
|
||||
|
||||
import { useI18n } from "vue-i18n";
|
||||
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 {
|
||||
$t: any;
|
||||
|
@ -186,8 +198,7 @@ const _initialize = async (options: _OptionsType) => {
|
|||
export default defineComponent({
|
||||
name: "PageWall",
|
||||
|
||||
components: {},
|
||||
|
||||
components: { Window },
|
||||
setup() {
|
||||
const $store = useStore();
|
||||
const $t = useI18n();
|
||||
|
@ -256,7 +267,7 @@ export default defineComponent({
|
|||
}
|
||||
};
|
||||
|
||||
EventBus.getInstance().on("windowResize", () => {
|
||||
EventBus.getInstance().on(EventNamesDefine.WindowResize, () => {
|
||||
calcWallVWScaler();
|
||||
});
|
||||
|
||||
|
@ -313,6 +324,29 @@ export default defineComponent({
|
|||
onDragOver(e: DragEvent) {
|
||||
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,
|
||||
},
|
||||
]);
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -62,6 +62,26 @@ export default store(function (/* { ssrContext } */) {
|
|||
},
|
||||
|
||||
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) {
|
||||
let windows = playload as MultimediaWindowEntity[];
|
||||
if (windows) {
|
||||
|
|
Loading…
Reference in New Issue