添加窗口显示。宫格行啊是

This commit is contained in:
fangxiang 2021-08-05 17:26:27 +08:00
parent ff030f8b6b
commit be4f57530e
9 changed files with 262 additions and 162 deletions

View File

@ -6,7 +6,7 @@
// Configuration for your app
// https://v2.quasar.dev/quasar-cli/quasar-conf-js
const { configure } = require('quasar/wrappers');
const { configure } = require("quasar/wrappers");
module.exports = configure(function (ctx) {
return {
@ -19,15 +19,10 @@ module.exports = configure(function (ctx) {
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli/boot-files
boot: [
'i18n',
'axios',
],
boot: ["i18n", "axios"],
// https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
css: [
'app.scss'
],
css: ["app.scss"],
// https://github.com/quasarframework/quasar/tree/dev/extras
extras: [
@ -39,13 +34,13 @@ module.exports = configure(function (ctx) {
// 'line-awesome',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
'roboto-font', // optional, you are not bound to it
'material-icons', // optional, you are not bound to it
"roboto-font", // optional, you are not bound to it
"material-icons", // optional, you are not bound to it
],
// Full list of options: https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
build: {
vueRouterMode: 'hash', // available values: 'hash', 'history'
vueRouterMode: "hash", // available values: 'hash', 'history'
// transpile: false,
@ -74,7 +69,7 @@ module.exports = configure(function (ctx) {
devServer: {
https: false,
port: 8080,
open: true // opens browser window automatically
open: true, // opens browser window automatically
},
// https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
@ -92,7 +87,7 @@ module.exports = configure(function (ctx) {
// directives: [],
// Quasar plugins
plugins: []
plugins: ["Notify", "Dialog", "Loading", "AppFullscreen"],
},
// animations: 'all', // --- includes all animations
@ -117,14 +112,14 @@ module.exports = configure(function (ctx) {
},
middlewares: [
ctx.prod ? 'compression' : '',
'render' // keep this as last one
]
ctx.prod ? "compression" : "",
"render", // keep this as last one
],
},
// https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
pwa: {
workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
workboxPluginMode: "GenerateSW", // 'GenerateSW' or 'InjectManifest'
workboxOptions: {}, // only for GenerateSW
// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
@ -137,38 +132,38 @@ module.exports = configure(function (ctx) {
name: `Quasar App`,
short_name: `Quasar App`,
description: `A Quasar Framework app`,
display: 'standalone',
orientation: 'portrait',
background_color: '#ffffff',
theme_color: '#027be3',
display: "standalone",
orientation: "portrait",
background_color: "#ffffff",
theme_color: "#027be3",
icons: [
{
src: 'icons/icon-128x128.png',
sizes: '128x128',
type: 'image/png'
src: "icons/icon-128x128.png",
sizes: "128x128",
type: "image/png",
},
{
src: 'icons/icon-192x192.png',
sizes: '192x192',
type: 'image/png'
src: "icons/icon-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: 'icons/icon-256x256.png',
sizes: '256x256',
type: 'image/png'
src: "icons/icon-256x256.png",
sizes: "256x256",
type: "image/png",
},
{
src: 'icons/icon-384x384.png',
sizes: '384x384',
type: 'image/png'
src: "icons/icon-384x384.png",
sizes: "384x384",
type: "image/png",
},
{
src: 'icons/icon-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
}
src: "icons/icon-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
@ -178,22 +173,20 @@ module.exports = configure(function (ctx) {
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
capacitor: {
hideSplashscreen: true
hideSplashscreen: true,
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
electron: {
bundler: 'packager', // 'packager' or 'builder'
bundler: "packager", // 'packager' or 'builder'
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
@ -201,7 +194,7 @@ module.exports = configure(function (ctx) {
builder: {
// https://www.electron.build/configuration/configuration
appId: 'media_player_web'
appId: "media_player_web",
},
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
@ -215,6 +208,6 @@ module.exports = configure(function (ctx) {
// do something with the Electron main process Webpack cfg
// extendWebpackPreload also available besides this chainWebpackPreload
},
}
}
},
};
});

View File

@ -3,15 +3,19 @@
<router-view />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
import { defineComponent } from "vue";
import { useI18n } from "vue-i18n";
import EventBus from "src/common/EventBus";
export default defineComponent({
name: 'App',
name: "App",
setup() {
const $t = useI18n();
document.title = $t.t('title');
document.title = $t.t("title");
window.onresize = (evt: any) =>
EventBus.getInstance().emit("windowResize", evt);
return {};
},
});

View File

@ -144,11 +144,10 @@ export default class ClientConnection {
}
}
public async doRpc(reuqest: any | Protocol.PacketEntity) {
public async doRpc<_RequestType extends Protocol.PacketEntity, _ResponseType>(
RequestType: new () => _RequestType
): Promise<_ResponseType | null> {
return new Promise((resolve, reject) => {
if (!reuqest) {
reject();
}
const rpc_id = ++this._rpc_id_counter;
if (this.rpc_map.has(rpc_id)) {
const f = this.rpc_map.get(rpc_id);
@ -157,8 +156,9 @@ export default class ClientConnection {
this.rpc_map.delete(rpc_id);
}
}
reuqest.rpc_id = rpc_id;
this.ws?.send(JSON.stringify(reuqest));
let request: _RequestType = new RequestType();
request.rpc_id = rpc_id;
this.ws?.send(JSON.stringify(request));
this.rpc_map.set(
rpc_id,
(is_fail: boolean, packet: Protocol.Commands, data: string) => {
@ -166,9 +166,7 @@ export default class ClientConnection {
reject();
} else {
try {
const response = JSON.parse(
data
) as Protocol.GetApplicationConfigResponseEntity;
const response = JSON.parse(data) as _ResponseType;
if (response) {
resolve(response);
} else {
@ -186,49 +184,33 @@ export default class ClientConnection {
}
public async getSignalSources() {
return new Promise((resolve, reject) => {
const rpc_id = ++this._rpc_id_counter;
if (this.rpc_map.has(rpc_id)) {
const f = this.rpc_map.get(rpc_id);
if (f && typeof f == "function") {
f(true, new Protocol.Commands(), "");
this.rpc_map.delete(rpc_id);
}
}
this.ws?.send(
JSON.stringify(new Protocol.GetSignalSourcesRequest(rpc_id))
);
this.rpc_map.set(
rpc_id,
(is_fail: boolean, packet: Protocol.Commands, data: string) => {
if (is_fail) {
reject();
} else {
try {
const response = JSON.parse(
data
) as Protocol.GetSignalSourcesResponse;
if (response) {
resolve(response);
} else {
reject();
console.log("reject");
return await this.doRpc<
Protocol.GetSignalSourcesRequest,
Protocol.GetSignalSourcesResponse
>(Protocol.GetSignalSourcesRequest);
} catch (e) {
console.error(e);
}
} catch {
reject();
console.log("reject");
}
}
}
);
});
}
public async getApplicationSettins() {
try {
return (await this.doRpc(
new Protocol.GetApplicationConfigRequestEntity()
)) as Protocol.GetApplicationConfigResponseEntity;
return await this.doRpc<
Protocol.GetApplicationConfigRequestEntity,
Protocol.GetApplicationConfigResponseEntity
>(Protocol.GetApplicationConfigRequestEntity);
} catch (e) {
console.error(e);
}
}
public async getWindows() {
try {
return await this.doRpc<
Protocol.GetWindowsRequestEntity,
Protocol.GetWindowsResponseEntity
>(Protocol.GetWindowsRequestEntity);
} catch (e) {
console.error(e);
}

12
src/common/EventBus.ts Normal file
View File

@ -0,0 +1,12 @@
import EventEmitter from "events";
export default class EventBus extends EventEmitter {
private static _instance: EventBus | null = null;
public static getInstance() {
if (!EventBus._instance) {
EventBus._instance = new EventBus();
}
return EventBus._instance;
}
}

View File

@ -1,5 +1,6 @@
import { SignalSourceEntity } from "./SignalSourceEntity";
import ApplicationConfigEntity from "./ApplicationConfigEntity";
import MultimediaWindowEntity from "./MultimediaWindowEntity";
export namespace Protocol {
export class Commands {
@ -139,4 +140,23 @@ export namespace Protocol {
this.command = Commands.kRpcGetApplicationConfig;
}
}
export class GetWindowsRequestEntity extends PacketEntity {
timestamp: number = new Date().getMilliseconds();
constructor(rpcid?: number) {
super();
this.rpc_id = rpcid ?? 0;
this.command = Commands.kRpcGetWindows;
}
}
export class GetWindowsResponseEntity extends PacketEntity {
windows: MultimediaWindowEntity[] = [];
constructor() {
super();
this.command = Commands.kRpcGetWindows;
}
}
}

View File

@ -2,21 +2,25 @@
// so you can safely delete all default props below
export default {
title: 'MediaPlayerWebAPP',
failed: '失败',
success: '成功',
login: '登录',
'user name': '用户名',
password: '密码',
'please input user name': '请输入用户',
'please input password': '请输入密码',
'login fail!': '登陆失败',
'Please type something': '请输入内容',
title: "MediaPlayerWebAPP",
failed: "失败",
success: "成功",
login: "登录",
"user name": "用户名",
password: "密码",
"please input user name": "请输入用户",
"please input password": "请输入密码",
"login fail!": "登陆失败",
"Please type something": "请输入内容",
'grid setting': '宫格设置',
'background image': '底图设置',
'data import': '数据导入',
'data export': '数据导出',
"grid setting": "宫格设置",
"background image": "底图设置",
"data import": "数据导入",
"data export": "数据导出",
root: '根节点',
root: "根节点",
"close all windwos": "关闭所有窗口",
"close this window": "关闭当前窗口",
"close other windows": "关闭其它窗口",
};

View File

@ -7,6 +7,7 @@
icon="img:icons/favicon-32x32.png"
label="电视机拼接盒"
class="q-mr-sm"
@click="test"
/>
<q-separator vertical inset />
<q-btn
@ -60,15 +61,22 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent } from "vue";
import { useStore } from "src/store";
export default defineComponent({
name: 'PageTopToolBar',
name: "PageTopToolBar",
components: {},
setup() {
return {};
let $store = useStore();
return {
test() {
$store.commit("setWallCol", 2);
},
};
},
});
</script>

View File

@ -18,6 +18,24 @@
</q-item>
</q-list>
</q-popup-proxy>
<div id="windows" style="position: absolute">
<div
:ref="'window_' + index"
v-for="(item, index) in windows"
:key="index"
class="window"
:style="{
top: item.y / wall_height_scaler + 'px',
left: item.x / wall_width_scaler + 'px',
width: item.width / wall_width_scaler + 'px',
height: item.height / wall_height_scaler + 'px',
}"
>
{{ wall_height_scaler }}
{{ wall_width_scaler }}
</div>
</div>
<div ref="wall_grids">
<div
v-for="row in wall_rows"
:key="row"
@ -35,6 +53,7 @@
width: item_witdh + 'px',
height: item_height + 'px',
}"
@resize="(evt) => loga(evt)"
>
<q-popup-proxy context-menu no-parent-event>
<q-popup-proxy context-menu />
@ -49,7 +68,9 @@
<q-item-section avatar>
<q-icon name="close" color="red" />
</q-item-section>
<q-item-section> {{ $t("close other windwos") }} </q-item-section>
<q-item-section>
{{ $t("close other windwos") }}
</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section avatar>
@ -62,6 +83,7 @@
</div>
</div>
</div>
</div>
</template>
<style scoped>
@ -72,16 +94,22 @@
.wall_item {
border: 1px solid black;
}
.window {
border: 1px solid rebeccapurple;
position: absolute;
}
</style>
<script lang="ts">
import GlobalData from "src/common/GlobalData";
import { defineComponent, ref, Ref, computed } from "vue";
import { defineComponent, ref, Ref, computed, watch, onMounted } from "vue";
import { Common } from "src/common/Common";
import { Protocol } from "src/entities/WSProtocol";
import { useI18n } from "vue-i18n";
import { useStore } from "src/store";
import EventBus from "src/common/EventBus";
interface _OptionsType {
$t: any;
@ -131,6 +159,15 @@ const _getApplicationConfig = async (options: _OptionsType) => {
}
};
const _getWindows = async (options: _OptionsType) => {
const global_data = GlobalData.getInstance();
let windows = (await global_data.getCurrentClient()?.getWindows())?.windows;
let $store = options.$store;
if (windows && $store) {
$store.commit("setWindows", windows);
}
};
const _initialize = async (options: _OptionsType) => {
const global_data = GlobalData.getInstance();
let client = global_data.getCurrentClient();
@ -139,7 +176,9 @@ const _initialize = async (options: _OptionsType) => {
await Common.waitFor(100);
}
_initSignalSourceTree(options);
_initSignalSourceTree(options).then(() => {
_getWindows(options);
});
_getApplicationConfig(options);
}
};
@ -157,6 +196,11 @@ export default defineComponent({
$store,
});
const windows = computed({
get: () => $store.state.windows,
set: (val) => $store.commit("setWindows", val),
});
const wall_rows = computed({
get: () => $store.state.wall_row,
set: (val) => $store.commit("setWallRow", val),
@ -195,13 +239,40 @@ export default defineComponent({
set: (val) => $store.commit("setWallCol", val),
});
const wall_width_scaler = ref(0);
const wall_height_scaler = ref(0);
const calcWallVWScaler = () => {
if (wall.value && wall.value.parentElement) {
wall_height_scaler.value =
$store.state.device_screen_height /
(item_height.value * wall_rows.value);
wall_width_scaler.value =
$store.state.device_screen_width /
wall.value.parentElement.offsetWidth;
wall_height_scaler.value += 0.1;
wall_width_scaler.value += 0.05;
}
};
EventBus.getInstance().on("windowResize", () => {
calcWallVWScaler();
});
onMounted(() => {
calcWallVWScaler();
});
return {
windows,
wall,
wall_rows,
wall_cols,
item_witdh,
item_height,
wall_width_scaler,
wall_height_scaler,
loga(a: any) {
console.log(a);
},

View File

@ -62,6 +62,12 @@ export default store(function (/* { ssrContext } */) {
},
mutations: {
setWindows(state: StateInterface, playload?: any) {
let windows = playload as MultimediaWindowEntity[];
if (windows) {
state.windows = windows;
}
},
clearWindows(state: StateInterface, playload?: any) {
state.windows = [];
},