添加魔墙对话框

This commit is contained in:
miao 2022-12-13 14:42:25 +08:00
parent 4aa7784ec5
commit a43188c3a1
4 changed files with 603 additions and 0 deletions

View File

@ -0,0 +1,565 @@
<template>
<q-dialog persistent v-model="show_dialog" @before-hide="resetData" @keydown="
(evt) => {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}
">
<q-card class="overflow-hidden" style="overflow-y: scroll; max-width: 60vw">
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
<div class="col-auto text-h6">
{{ $t("magic wall") }}
</div>
<q-space />
<div>
<q-btn :loading="loading" flat round :disable="loading" icon="close" color="red" v-close-popup>
<q-tooltip>
{{ $t("close") }}
</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-section style="max-height: 80vh; width: 55vw" class="scroll">
<q-card class="my-card" flat bordered>
<q-card-section horizontal>
<q-card-section class="col-3" style="">
<div class="text-h5">{{ $t("angle") }}</div>
<q-separator />
<br />
<div class="row no-wrap items-center">
<q-item>
<q-item-section avatar>
<span class="q-mb-md" style="font-size:1rem"> angle:</span>
</q-item-section>
<q-item-section>
<q-input v-if="(current_index > -1)" type="number" min="0"
v-model="(test_monitor_wall[current_index].angle)"
oninput="if(value<0)value=0;if(value>360)value=360;" hint="">
<template v-slot:append>
<span class="input_append">°</span>
</template>
</q-input>
<q-input v-else type="number" min="0" :model-value="0" :disable="true" hint="">
<template v-slot:append>
<span class="input_append">°</span>
</template>
</q-input>
</q-item-section>
</q-item>
</div>
<br />
<div class="text-h5">{{ $t("physical central location") }}</div>
<q-separator />
<br />
<div class="row no-wrap items-center">
<q-item>
<q-item-section avatar>
<span class="q-mb-md">X:</span>
</q-item-section>
<q-item-section>
<q-input v-if="(current_index > -1)" type="number" min="0"
v-model="test_monitor_wall[current_index].currentx" :rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 0 ||
$t('the number must be greater than 0'),
]" lazy-rules hint="">
<template v-slot:append>
<span class="input_append text-h6">px</span>
</template>
</q-input>
<q-input v-else type="number" min="0" :model-value="0" :disable="true" hint="">
<template v-slot:append>
<span class="input_append text-h6">px</span>
</template>
</q-input>
</q-item-section>
</q-item>
</div>
<br />
<div class="row ">
<q-item>
<q-item-section avatar>
<span class="q-mb-md">Y:</span>
</q-item-section>
<q-item-section>
<q-input v-if="(current_index > -1)" :hint="''" type="number" min="0"
v-model="test_monitor_wall[current_index].currenty" :rules="[
(val) =>
(val != null &&
val != undefined &&
val.toString().length > 0) ||
$t('Please type something'),
(val) =>
parseInt(val) >= 0 ||
$t('the number must be greater than 0'),
]" lazy-rules>
<template v-slot:append>
<span class="input_append text-h6">px</span>
</template>
</q-input>
<q-input v-else type="number" min="0" :model-value="0" :disable="true" hint="">
<template v-slot:append>
<span class="input_append text-h6">px</span>
</template>
</q-input>
</q-item-section>
</q-item>
</div>
</q-card-section>
<q-separator vertical></q-separator>
<q-card-section @dragenter="onDragEnter" @dragleave="onDragLeave" @dragover="onDragOver" @drop="onDrop"
style="max-height: 80vh; width: 55vw ; position: relative;">
<div class="text-h6">{{ $t("topology diagram") }}</div>
<div style="position: absolute; height: 85%; width: 95%; text-align: center;"
:class="$store.state.power_state ? 'wall' : ''">
<div class="row" v-for="i in (64 / 8)" :key="i" style="height:12.5%;align-items: center;"
:class="(i % 2) == 0 ? 'wall_row' : ''">
<div class="col" v-for="j in 8" :key="j">
{{ (i * j) }}
</div>
</div>
</div>
<div id="monitors" ref="wall" v-if="$store.state.power_state"
style="position: absolute; height: 85%; width: 95%; overflow: hidden;">
<div v-for=" (item, index) of test_monitor_wall">
<vue3-resize-drag v-if="((item.id < 4) && item.uuid != '')" :w="($refs.wall?.offsetWidth * 0.5)"
:h="($refs.wall?.offsetHeight * 0.5)"
:x="((item.currentx) > $refs.wall?.offsetWidth - item.w ? item.currenty - item.w : item.currentx)"
:y="((item.currenty) > $refs.wall?.offsetHeight - item.h ? item.currenty - item.h : item.currenty)"
:resizeIconSize="8" :isActive="item.active" :isGuide="(true && item.angle == 0)" :rotate="item.angle"
style="background-color: grey; opacity: 0.8; text-align: center;position: absolute; "
@moveHandler="moveingMonitor(item, $event)" @moveEndHandler="moveMonitor(item, $event)"
@mousedown="activeMouseDown(item, index)" @rotateHandler="rotateMonitor(item, $event)"
:z-index="item.active ? 99 : 0">
<div class="full-height full-width" :class="item.active ? 'monitor_selected' : ''"
style="text-align:center;" :style="{ lineHeight: show_box_line_height($refs.wall?.offsetHeight) }">
<q-popup-proxy context-menu>
<q-list>
<q-item clickable v-close-popup>
<q-item-section @click="closeWindow(item, index)"> {{ $t("close this window") }}
</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section @click="closeOtherWindows(item, index)">
{{ $t("close other windows") }}
</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section @click="closeAllWindows()"> {{ $t("close all windows") }} </q-item-section>
</q-item>
</q-list>
</q-popup-proxy>
{{ item.uuid }}
</div>
</vue3-resize-drag>
<vue3-resize-drag v-else-if="(item.id < 8 && item.uuid != '')" :w="($refs.wall?.offsetWidth * 0.6)"
:h="($refs.wall?.offsetHeight * 0.6)"
:x="((item.currentx) > $refs.wall?.offsetWidth - item.w ? item.currenty - item.w : item.currentx)"
:y="((item.currenty) > $refs.wall?.offsetHeight - item.h ? item.currenty - item.h : item.currenty)"
:resizeIconSize="8" :isActive="item.active" :isGuide="(true && item.angle == 0)" :rotate="item.angle"
style="background-color: grey; opacity: 0.8; text-align: center;position: absolute;"
@moveHandler="moveingMonitor(item, $event)" @moveEndHandler="moveMonitor(item, $event)"
@mousedown="activeMouseDown(item, index)" @rotateHandler="rotateMonitor(item, $event)"
:z-index="item.active ? 99 : 0">
<div class="full-height full-width" :class="item.active ? 'monitor_selected' : ''"
style="text-align:center;" :style="{ lineHeight: show_box_line_height($refs.wall?.offsetHeight) }">
<q-popup-proxy context-menu>
<q-list>
<q-item clickable v-close-popup>
<q-item-section @click="closeWindow(item, index)"> {{ $t("close this window") }}
</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section @click="closeOtherWindows(item, index)">
{{ $t("close other windows") }}
</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section @click="closeAllWindows()"> {{ $t("close all windows") }} </q-item-section>
</q-item>
</q-list>
</q-popup-proxy>
{{ item.uuid }}
</div>
</vue3-resize-drag>
</div>
</div>
</q-card-section>
</q-card-section>
</q-card>
<br />
<q-card class="my-card" flat bordered>
<q-item>
<q-item-section>
<q-item-label class="text-h6">{{ $t("monitors list") }}</q-item-label>
</q-item-section>
</q-item>
<q-separator></q-separator>
<q-card-section horizontal>
<q-list key="uuid" class=" full-width">
<div v-for="item in (Math.ceil(test_monitor_list.length / 4))">
<div v-for="(j) in 4" style="display:inline-block"
v-if="(item < test_monitor_list.length / 4 || (test_monitor_list.length % 4 == 0))"
:style="{ lineHeight: box_height(item, j) }">
<div v-if="test_monitor_list[(item - 1) * 4 + (j - 1)] == ''">
</div>
<div v-else style="background-color: grey; opacity: 0.5; border: 1px solid black;text-align: center;"
:style="{ width: box_width(item, j), height: box_height(item, j) }" :draggable="$store.state.power_state"
@dragstart="(evt) => onDragStart(evt, (test_monitor_list[(item - 1) * 4 + (j - 1)]))"
@dragend="(evt) => onDragend(evt, item, j)">
{{ (test_monitor_list[(item - 1) * 4 + (j - 1)].uuid) }}
</div>
</div>
<div v-else v-for="j in (test_monitor_list.length) % 4" style="display:inline-block;text-align: center;"
:style="{ lineHeight: box_height(item, j) }">
<div v-if="test_monitor_list[(item - 1) * 4 + (j - 1)] == ''">
</div>
<div v-else style="background-color: grey; opacity: 0.5; border: 1px solid black;"
:style="{ width: box_width(item, j), height: box_height(item, j) }" :draggable="$store.state.power_state"
@dragstart="(evt) => onDragStart(evt, (test_monitor_list[(item - 1) * 4 + (j - 1)]))"
@dragend="(evt) => onDragend(evt, item, j)">
{{ (test_monitor_list[(item - 1) * 4 + (j - 1)].uuid) }}
</div>
</div>
</div>
</q-list>
</q-card-section>
</q-card>
<q-separator />
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn :loading="loading" flat :label="$t('Cancel')" no-caps color="primary" v-close-popup />
<q-btn ref="accept" flat :label="$t('Accept')" no-caps :loading="loading" type="submit" color="primary" />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<style scoped>
.monitor_selected {
outline-style: dashed;
outline-color: #166fab;
background-color: dimgrey;
}
.wall {
border: 1px solid black;
}
.wall_row {
background-color: #166fab;
}
.drag-enter {
outline-style: dashed;
}
</style>
<script lang="ts">
import { defineComponent, ref, watch, computed, Ref, reactive } from "vue";
import { useStore } from "src/store";
import { useQuasar, extend } from "quasar";
import { useI18n } from "vue-i18n";
import GlobalData from "src/common/GlobalData";
import { HttpProtocol } from "src/entities/HttpProtocol";
import vue3ResizeDrag from "../third_lib/vue3-resize-drag/components/vue3-resize-drag/index.vue";
import itemDrag from "src/third_lib/vue3-resize-drag/components/vue3-resize-drag/func/drag";
class test_monitor {
uuid = "";
active = false;
start_x = 0;
start_y = 0;
w = 0;
h = 0;
currentx = 0;
currenty = 0;
angle = 0;
id = 0;
reset() {
this.uuid = "";
this.active = false;
this.start_x = 0;
this.start_y = 0;
this.w = 0;
this.h = 0;
this.currentx = 0;
this.currenty = 0;
this.angle = 0;
this.id = 0;
}
}
export default defineComponent({
name: "ComponentControlPanelDialog",
components: { vue3ResizeDrag },
setup() {
let $store = useStore();
let $q = useQuasar();
let $t = useI18n();
let show_dialog = ref(false);
let loading = ref(false);
let upload_url = ref("");
let file_count = ref(0);
let show_windows_flag = ref(true); // window
let wall: Ref<HTMLElement | null> = ref(null);
let current_index = ref(-1);
let window_rect = reactive({
x: 0,
y: 0,
width: 0,
height: 0,
angle: 0,
});
const aw = 128; const ah = 72;
const bw = 160; const bh = 90;
let test_monitor_list: Ref<Object[]> = ref([
{ id: 0, uuid: "01", active: false, start_x: 0, start_y: 0, w: aw, h: ah },
{ id: 1, uuid: "02", active: false, start_x: 0, start_y: 0, w: aw, h: ah },
{ id: 2, uuid: "03", active: false, start_x: 0, start_y: 0, w: aw, h: ah },
{ id: 3, uuid: "04", active: false, start_x: 0, start_y: 0, w: aw, h: ah },
{ id: 4, uuid: "05", active: false, start_x: 0, start_y: 0, w: bw, h: bh },
{ id: 5, uuid: "06", active: false, start_x: 0, start_y: 0, w: bw, h: bh },
{ id: 6, uuid: "07", active: false, start_x: 0, start_y: 0, w: bw, h: bh },
{ id: 7, uuid: "08", active: false, start_x: 0, start_y: 0, w: bw, h: bh },
]);
const delete_monitor_list: Ref<test_monitor[]> = ref([]);
interface show__Rect {
width: number;
height: number;
x: number;
y: number;
left: number;
top: number;
angle: number;
};
let showMonitor = reactive({
x: 0,
y: 0,
width: 0,
height: 0,
active: false
})
let test_monitor_wall: Ref<test_monitor[]> = ref([]);
const moveingMonitor = (item: test_monitor, rect: show__Rect) => {
if (item.active) {
test_monitor_wall.value.forEach(element => {
element.active = false
});
}
item.active = true;
if (rect.left > 0) {
item.currentx = rect.left;
}
if (rect.top > 0) {
item.currenty = rect.top;
}
};
const rotateMonitor = (item: test_monitor, rect: show__Rect) => {
item.angle = rect.angle;
};
const moveMonitor = (item: test_monitor, rect: show__Rect) => {
let test = JSON.stringify(rect)
//
//
if (rect.left < 0) {
if (item.currentx == 0) {
item.currentx = 0.1
} else {
item.currentx = 0
}
} else {
item.currentx = rect.left
}
if (rect.top < 0) {
if (item.currenty == 0) {
item.currenty = 0.1
} else {
item.currenty = 0
}
} else {
item.currenty = rect.top
}
};
let test_delete_flag = false;
return {
show_dialog,
loading,
upload_url,
delete_monitor_list,
file_count,
window_rect,
current_index,
test_monitor_list,
test_monitor_wall,
moveMonitor,
moveingMonitor,
rotateMonitor,
loga(a: any) {
console.log(a);
},
aaa(x: any) {
console.log(x)
},
showDialog() {
show_dialog.value = true;
let client = GlobalData.getInstance().getCurrentClient();
if (client) {
let url = new URL(client.url);
url.port =
GlobalData.getInstance().applicationConfig?.httpserver_port ??
HttpProtocol.DefaultHttpPort.toString();
url.pathname = HttpProtocol.RequestUploadFile;
url.protocol = "http:";
url.searchParams.append(
"type",
HttpProtocol.UploadTypeBackgroundImage
);
upload_url.value = url.toString();
}
},
resetData() {
loading.value = false;
upload_url.value = "";
file_count.value = 0;
},
activeMouseDown(item: test_monitor, index: number) {
current_index.value = index;
if (item.active) {
test_monitor_wall.value.forEach(element => {
element.active = false
});
}
item.active = true;
},
onDragStart(e: DragEvent, item: test_monitor) {
item.start_x = e.offsetX;
item.start_y = e.offsetY;
item.active = false;
test_delete_flag = false;
e.dataTransfer?.setData("item", JSON.stringify(item));
},
onDragOver(e: DragEvent) {
e.preventDefault();
},
onDrop(e: DragEvent) {
if (e.dataTransfer?.getData("item") != "") {
let item = JSON.parse(e.dataTransfer?.getData("item") + "");
item.currentx = e.offsetX - item.start_x;
item.currenty = e.offsetY - item.start_y;
item.active = true;
item.angle = 0;
if (item.active) {
test_monitor_wall.value.forEach(element => {
element.active = false
});
}
if (item.currentx < 0) {
item.currentx = 0.1
window_rect.x = 0
} else {
window_rect.x = item.currentx
}
if (item.currenty < 0) {
item.currenty = 0.1
window_rect.y = 0
} else {
window_rect.y = item.currenty
}
test_delete_flag = false;
if (test_monitor_wall.value.indexOf(item) == -1) {
test_monitor_wall.value.push(item);
test_delete_flag = true;
}
}
},
onDragEnter(e: DragEvent, index: string) {
e.stopPropagation();
let target: HTMLElement | null = e.target as HTMLElement;
if (target && target.draggable !== true) {
while (
target &&
!target.classList.contains("window_flag") &&
!target.classList.contains("wall_item_flag")
) {
target = target.parentElement;
}
target?.classList.add("drag-enter");
}
},
onDragend(e: DragEvent, row: number, col: number) {
let num = (row - 1) * 4 + (col - 1);
if (test_delete_flag) {
test_monitor_list.value[num] = ""
}
},
onDragLeave(e: DragEvent) {
let target: HTMLElement = e.target as HTMLElement;
target?.classList.remove("drag-enter");
},
closeWindow(item: test_monitor, index: number) {
current_index.value = -1;
test_monitor_list.value[item.id] = item;
test_monitor_wall.value[index] = new test_monitor;
},
closeOtherWindows(item: test_monitor, index: number) {
current_index.value = 0;
let tep = JSON.parse(JSON.stringify(item));
delete_monitor_list.value = test_monitor_wall.value;
delete_monitor_list.value.forEach(element => {
test_monitor_list.value[element.id] = element
})
test_monitor_list.value[item.id] = []
test_monitor_wall.value = [tep,];
},
closeAllWindows() {
current_index.value = -1;
delete_monitor_list.value = test_monitor_wall.value;
delete_monitor_list.value.forEach(element => {
test_monitor_list.value[element.id] = element
})
test_monitor_wall.value = [];
},
box_width(row: number, col: number) {
let tep = JSON.parse(JSON.stringify(test_monitor_list.value[(row - 1) * 4 + (col - 1)]))
return tep.w + "px"
},
box_height(row: number, col: number) {
let tep = JSON.parse(JSON.stringify(test_monitor_list.value[(row - 1) * 4 + (col - 1)]))
return tep.h + "px"
},
show_box_line_height(height: number) {
return height * 0.5 + "px"
}
};
},
});
</script>

View File

@ -398,4 +398,9 @@ export default {
"server commit hash": "Server Commit Hash", "server commit hash": "Server Commit Hash",
"edit user or password": "Edit User Or Password", "edit user or password": "Edit User Or Password",
"old password error": "Old Password Error", "old password error": "Old Password Error",
"magic wall":"Magic Wall",
"angle":"Angle",
"topology diagram":"Topology Diagram",
"physical central location":"Central Location",
"monitors list":"Monitors List",
}; };

View File

@ -668,4 +668,9 @@ export default {
"new password": "新密码", "new password": "新密码",
"edit user or password": "修改用户名和密码", "edit user or password": "修改用户名和密码",
"old password error": "旧密码不匹配", "old password error": "旧密码不匹配",
"magic wall":"魔墙",
"angle":"角度",
"topology diagram":"拓扑图",
"physical central location":"物理中心位置",
"monitors list":"显示器",
}; };

View File

@ -310,6 +310,27 @@
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item
clickable
:disable="!$store.state.power_state"
v-close-popup
@click="$refs.control_panel_dialog.showDialog()"
>
<q-item-section avatar>
<!-- <q-icon name="image" /> -->
<q-icon name="img:new_icon/file_manager.png" />
</q-item-section>
<q-item-section>
{{ $t("magic wall") }}
</q-item-section>
</q-item>
<q-item <q-item
clickable clickable
:disable="!$store.state.power_state" :disable="!$store.state.power_state"
@ -457,6 +478,7 @@
v-if="$store.state.isSpecialVideo()" v-if="$store.state.isSpecialVideo()"
ref="special_video_grid_setting_dialog" ref="special_video_grid_setting_dialog"
/> />
<control-panel-dialog ref="control_panel_dialog" />
<background-image-dialog ref="background_image_dialog" /> <background-image-dialog ref="background_image_dialog" />
<subtitle-dialog ref="subtitle_dialog" /> <subtitle-dialog ref="subtitle_dialog" />
<recovery-database-dialog ref="recovery_database_dialog" /> <recovery-database-dialog ref="recovery_database_dialog" />
@ -496,6 +518,9 @@ import { useStore } from "src/store";
import GridSettingDialog from "src/components/GridSettingDialog.vue"; import GridSettingDialog from "src/components/GridSettingDialog.vue";
import SpecialVideoGridSettingDialog from "src/components/SpecialVideoGridSettingDialog.vue"; import SpecialVideoGridSettingDialog from "src/components/SpecialVideoGridSettingDialog.vue";
import ControlPanelDialog from "src/components/ControlPanelDialog.vue";
import BackgroundImageDialog from "src/components/BackgroundImageDialog.vue"; import BackgroundImageDialog from "src/components/BackgroundImageDialog.vue";
import RecoveryDatabaseDialog from "src/components/RecoveryDatabaseDialog.vue"; import RecoveryDatabaseDialog from "src/components/RecoveryDatabaseDialog.vue";
import UpgradeDialog from "src/components/UpgradeDialog.vue"; import UpgradeDialog from "src/components/UpgradeDialog.vue";
@ -527,6 +552,9 @@ export default defineComponent({
components: { components: {
GridSettingDialog, GridSettingDialog,
SpecialVideoGridSettingDialog, SpecialVideoGridSettingDialog,
ControlPanelDialog,
BackgroundImageDialog, BackgroundImageDialog,
RecoveryDatabaseDialog, RecoveryDatabaseDialog,
UpgradeDialog, UpgradeDialog,