预案树显示

This commit is contained in:
fangxiang 2021-08-25 17:30:02 +08:00
parent 5a9cf78ba1
commit 187d2fda0b
21 changed files with 1574 additions and 110 deletions

View File

@ -252,6 +252,66 @@ export default class ClientConnection {
}
}
public async addSignalSourceGroup(parent_uuid: string, name: string) {
try {
return await this.doRpc<Protocol.AddSignalSourceGroupResponseEntity>(
new Protocol.AddSignalSourceGroupRequestEntity(0, parent_uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async editSignalSourceGroup(uuid: string, name: string) {
try {
return await this.doRpc<Protocol.EditSignalSourceGroupResponseEntity>(
new Protocol.EditSignalSourceGroupRequestEntity(0, uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async deleteSignalSourceGroup(uuid: string) {
try {
return await this.doRpc<Protocol.DeleteSignalSourceGroupResponseEntity>(
new Protocol.DeleteSignalSourceGroupRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public async addSignalSource(item: SignalSourceEntity) {
try {
return await this.doRpc<Protocol.AddSignalSourceResponseEntity>(
new Protocol.AddSignalSourceRequestEntity(0, item)
);
} catch (e) {
console.error(e);
}
}
public async editSignalSource(item: SignalSourceEntity) {
try {
return await this.doRpc<Protocol.EditSignalSourceResponseEntity>(
new Protocol.EditSignalSourceRequestEntity(0, item)
);
} catch (e) {
console.error(e);
}
}
public async deleteSignalSource(uuid: string) {
try {
return await this.doRpc<Protocol.DeleteSignalSourceResponseEntity>(
new Protocol.DeleteSignalSourceRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public async getModes() {
try {
return await this.doRpc<Protocol.GetModesResponseEntity>(
@ -262,6 +322,90 @@ export default class ClientConnection {
}
}
public async addPlanGroup(group_uuid: string, name: string) {
try {
return await this.doRpc<Protocol.AddPlanGroupResponseEntity>(
new Protocol.AddPlanGroupRequestEntity(0, group_uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async editPlanGroup(uuid: string, name: string) {
try {
return await this.doRpc<Protocol.EditPlanGroupResponseEntity>(
new Protocol.EditPlanGroupRequestEntity(0, uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async deletePlanGroup(uuid: string) {
try {
return await this.doRpc<Protocol.DeletePlanGroupResponseEntity>(
new Protocol.DeletePlanGroupRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public async addPlan(group_uuid?: string, name?: string) {
try {
return await this.doRpc<Protocol.AddPlanResponseEntity>(
new Protocol.AddPlanRequestEntity(0, name, group_uuid)
);
} catch (e) {
console.error(e);
}
}
public async editPlan(uuid?: string, name?: string) {
try {
return await this.doRpc<Protocol.EditPlanResponseEntity>(
new Protocol.EditPlanRequestEntity(0, name, uuid)
);
} catch (e) {
console.error(e);
}
}
public async deletePlan(uuid: string) {
try {
return await this.doRpc<Protocol.DeletePlanResponseEntity>(
new Protocol.DeletePlanRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public async getCurrentRunningPlan() {
try {
return await this.doRpc<Protocol.GetCurrentRunningPlanResponseEntity>(
new Protocol.GetCurrentRunningPlanRequestEntity(0)
);
} catch (e) {
console.error(e);
}
}
public runPlan(uuid: string) {
this.ws?.send(JSON.stringify(new Protocol.RunPlanRequestEntity(uuid)));
}
public async getPlans() {
try {
return await this.doRpc<Protocol.GetPlansResponseEntity>(
new Protocol.GetPlansRequestEntity()
);
} catch (e) {
console.error(e);
}
}
public async addModeGroup(group_uuid: string, name: string) {
try {
return await this.doRpc<Protocol.AddModeGroupResponseEntity>(
@ -381,66 +525,6 @@ export default class ClientConnection {
);
}
public async addSignalSourceGroup(parent_uuid: string, name: string) {
try {
return await this.doRpc<Protocol.AddSignalSourceGroupResponseEntity>(
new Protocol.AddSignalSourceGroupRequestEntity(0, parent_uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async editSignalSourceGroup(uuid: string, name: string) {
try {
return await this.doRpc<Protocol.EditSignalSourceGroupResponseEntity>(
new Protocol.EditSignalSourceGroupRequestEntity(0, uuid, name)
);
} catch (e) {
console.error(e);
}
}
public async deleteSignalSourceGroup(uuid: string) {
try {
return await this.doRpc<Protocol.DeleteSignalSourceGroupResponseEntity>(
new Protocol.DeleteSignalSourceGroupRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public async addSignalSource(item: SignalSourceEntity) {
try {
return await this.doRpc<Protocol.AddSignalSourceResponseEntity>(
new Protocol.AddSignalSourceRequestEntity(0, item)
);
} catch (e) {
console.error(e);
}
}
public async editSignalSource(item: SignalSourceEntity) {
try {
return await this.doRpc<Protocol.EditSignalSourceResponseEntity>(
new Protocol.EditSignalSourceRequestEntity(0, item)
);
} catch (e) {
console.error(e);
}
}
public async deleteSignalSource(uuid: string) {
try {
return await this.doRpc<Protocol.DeleteSignalSourceResponseEntity>(
new Protocol.DeleteSignalSourceRequestEntity(0, uuid)
);
} catch (e) {
console.error(e);
}
}
public setApplicationConfig(wall_row: number, wall_col: number) {
this.ws?.send(
JSON.stringify(
@ -473,3 +557,8 @@ export default class ClientConnection {
this.ws = null;
}
}
export interface NotifyMessage {
packet: Protocol.PacketEntity;
data: string;
}

View File

@ -2,6 +2,7 @@ import { SessionStorage } from "quasar";
import ApplicationConfigEntity from "src/entities/ApplicationConfigEntity";
import { HttpProtocol } from "src/entities/HttpProtocol";
import { ModeEntity } from "src/entities/ModeEntity";
import { PlanEntity } from "src/entities/PlanEntity";
import { SignalSourceEntity } from "src/entities/SignalSourceEntity";
import ClientConnection from "./ClientConnection";
import EventBus, { EventNamesDefine } from "./EventBus";
@ -65,6 +66,16 @@ export default class GlobalData {
this._modes = modes;
}
_plans: PlanEntity[] = [];
public get plans() {
return this._plans;
}
public set plans(plans: PlanEntity[]) {
this._plans = plans;
}
constructor() {
const url: string | null = SessionStorage.getItem("url");
let name: string | null = SessionStorage.getItem("name");

View File

@ -10,9 +10,7 @@
? $t("add mode")
: type == 2
? $t("edit mode")
: type == 3
? $t("delete mode")
: "add"
: $t("add mode")
}}
</div>
<q-space />

View File

@ -10,9 +10,7 @@
? $t("add group")
: type == 2
? $t("edit group")
: type == 3
? $t("delete group")
: "add"
: $t("add group")
}}
</div>
<q-space />

View File

@ -124,6 +124,7 @@ import { useI18n } from "vue-i18n";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { Protocol } from "src/entities/WSProtocol";
import { ModeEntity } from "src/entities/ModeEntity";
import { NotifyMessage } from "src/common/ClientConnection";
export default defineComponent({
name: "PageModeTree",
@ -149,13 +150,9 @@ export default defineComponent({
tree.value?.setExpanded("", true);
});
interface _ResponseMessage {
packet: Protocol.PacketEntity;
data: string;
}
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(response: _ResponseMessage) => {
(response: NotifyMessage) => {
if (response) {
switch (response.packet.command) {
case Protocol.Commands.kRpcAddMode:

View File

@ -0,0 +1,383 @@
<template>
<q-dialog persistent v-model="show_dialog" @before-hide="resetData">
<q-card class="overflow-hidden" style="overflow-y: scroll; max-width: 45vw">
<q-form @submit="onSubmit">
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
<div class="col-auto text-h6">
{{
type == 1
? $t("add plan")
: type == 2
? $t("edit plan")
: $t("add plan")
}}
</div>
<q-space />
<div>
<q-btn
:loading="loading"
flat
round
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: 50vh; width: 45vw" class="scroll">
<q-list>
<q-item>
<q-item-label>{{ $t("parent group") }}:</q-item-label>
</q-item>
<q-item class="q-pa-none q-ma-none">
<q-item-section style="padding-right: 10px">
<q-tree
ref="tree"
class="scroll"
:class="loading ? 'disable_tree' : ''"
v-model:selected="selected"
:nodes="tree_nodes"
default-expand-all
node-key="uuid"
labelKey="name"
filter="group filter"
:filter-method="treeNodesFilter"
>
<template v-slot:default-header="prop">
<q-item
class="full-width"
:class="
prop.tree.selected == prop.key ? 'item-selected-bg' : ''
"
>
<q-item-section avatar>
<q-icon
:name="'img:source_icon/group.png'"
color="orange"
size="28px"
class="q-mr-sm"
/>
</q-item-section>
<q-item-section>
<div class="text-weight-bold text-primary">
{{ prop.node.name }}
</div>
</q-item-section>
</q-item>
</template>
</q-tree>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input
autofocus
:loading="loading"
:disable="loading"
filled
v-model="name"
:label="$t('plan name')"
:hint="$t('please input plan name')"
lazy-rules
:rules="[
(val) =>
(val && val.length > 0) || $t('Please type something'),
]"
@keydown="
(evt) => {
if (evt.keyCode == 13) {
$refs?.accept?.click();
}
}
"
>
<template v-if="name" v-slot:append>
<q-icon
name="cancel"
@click.stop="name = null"
class="cursor-pointer"
/>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-table
style="height: 50vh"
:rows="datas"
:columns="columns"
virtual-scroll
:title="$t('plan data') + ':'"
hide-bottom
color="primary"
row-key="name"
:loading="loading"
:rows-per-page-options="[0]"
:virtual-scroll-sticky-size-start="48"
@row-contextmenu="onContextMenu"
>
<template v-slot:loading>
<q-inner-loading showing color="primary" />
</template>
<template v-slot:body-cell="props">
<q-td :props="props">
<div v-if="props.col.name == 'value'">
<div v-if="props.pageIndex % 2">
{{ props.value }}{{ $t("s") }}
</div>
<div v-else>
<!-- <q-select></q-select> -->
{{ props.value }}
</div>
</div>
<div v-else>
{{ props.value }}
</div>
</q-td>
</template>
</q-table>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
<q-separator />
<q-card-actions align="left">
<q-btn
:loading="loading"
flat
:label="$t('add row')"
color="primary"
@click="addRow"
/>
<q-space />
<q-btn
:loading="loading"
flat
:label="$t('Cancel')"
color="primary"
v-close-popup
/>
<q-btn
ref="accept"
flat
:label="$t('Accept')"
:loading="loading"
type="submit"
color="primary"
/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<div>
<q-menu :target="target_dom" v-model="show_context_menu">
<q-list>
<q-item clickable v-close-popup @click="(evt) => deleteRow()">
<q-item-section avatar
><q-icon name="delete" color="red"
/></q-item-section>
<q-item-section>{{ $t("delete row") }}</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="(evt) => addRow()">
<q-item-section avatar><q-icon name="add" /></q-item-section>
<q-item-section>{{ $t("add row") }}</q-item-section>
</q-item>
</q-list>
</q-menu>
</div>
</template>
<style scoped>
.disable_tree {
background: #9e9e9e;
cursor: wait;
pointer-events: none;
}
</style>
<script lang="ts">
import { defineComponent, ref, Ref, watch, computed } from "vue";
import { useStore } from "src/store";
import GlobalData from "src/common/GlobalData";
import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import { StringKeyValueEntity } from "src/entities/StringKeyValueEntity";
export default defineComponent({
name: "ComponentPlanDialog",
setup() {
let $store = useStore();
let $q = useQuasar();
let $t = useI18n();
let show_dialog = ref(false);
let type = ref(1);
let name = ref(null);
let uuid = ref("");
const selected: any = ref(null);
let loading = ref(false);
let datas: Ref<StringKeyValueEntity[]> = ref([]);
const columns = [
{
align: "left",
name: "key",
required: true,
label: $t.t("operator"),
field: "key",
sortable: true,
},
{
align: "left",
name: "value",
label: $t.t("operator value"),
field: "value",
sortable: true,
},
];
let show_context_menu = ref(false);
let target_dom: any = ref(document.body.children[0]);
let current_index = 0;
const tree_nodes = computed({
get: () => $store.state.plan_tree,
set: (val) => {},
});
watch(
() => selected.value,
(newValue, oldValue) => {
if (newValue == null) {
selected.value = "";
}
}
);
const requestAddPlan = async () => {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.addPlan(selected.value, name.value ?? "");
if (response) {
$q.notify({
color: response.success ? "positive" : "negative",
icon: response.success ? "done" : "warning",
message:
$t.t("add plan") +
(response.success ? $t.t("success") : $t.t("fail")) +
"!",
position: "top",
timeout: 1000,
});
}
};
const requestEditPlan = async () => {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.editPlan(uuid.value, name.value ?? "");
if (response) {
$q.notify({
color: response.success ? "positive" : "negative",
icon: response.success ? "done" : "warning",
message:
$t.t("edit plan") +
(response.success ? $t.t("success") : $t.t("fail")) +
"!",
position: "top",
timeout: 1000,
});
}
};
return {
show_dialog,
type,
name,
uuid,
selected,
loading,
datas,
columns,
show_context_menu,
target_dom,
tree_nodes,
showDialog(options: any) {
if (options) {
console.log(options);
type.value = options.type ?? 1;
if (type.value == 2) {
name.value = options.data?.name ?? null;
selected.value = options.data?.item_data?.group_uuid ?? null;
uuid.value = options.data?.item_data?.uuid ?? null;
} else {
selected.value = options.data?.uuid ?? null;
uuid.value = options.data?.uuid ?? null;
}
}
show_dialog.value = true;
},
resetData() {
loading.value = false;
(selected.value = null), (name.value = null);
type.value = 1;
},
treeNodesFilter(node: any, filter: any) {
return node.is_group;
},
addRow() {
datas.value.push({
key: $t.t("call mode"),
value: "222",
});
datas.value.push({
key: $t.t("delay") + "(" + $t.t("s") + ")",
value: "444",
});
},
onContextMenu(
evt: PointerEvent,
row: StringKeyValueEntity,
index: number
) {
evt.preventDefault();
evt.stopPropagation();
target_dom.value = evt.srcElement;
if (row) {
current_index = index;
show_context_menu.value = true;
}
},
deleteRow() {
if (datas.value.length > current_index) {
const start = Math.floor(current_index / 2);
if (!isNaN(start)) {
datas.value.splice(start, 2);
}
}
},
async onSubmit() {
loading.value = true;
try {
await (type.value == 2 ? requestEditPlan() : requestAddPlan());
show_dialog.value = false;
} catch {}
loading.value = false;
},
};
},
});
</script>

View File

@ -0,0 +1,261 @@
<template>
<q-dialog persistent v-model="show_dialog" @before-hide="resetData">
<q-card class="overflow-hidden" style="overflow-y: scroll; max-width: 45vw">
<q-form @submit="onSubmit">
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
<div class="col-auto text-h6">
{{
type == 1
? $t("add group")
: type == 2
? $t("edit group")
: $t("add group")
}}
</div>
<q-space />
<div>
<q-btn
:loading="loading"
flat
round
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: 50vh; width: 45vw" class="scroll">
<q-list>
<q-item v-if="type != 2">
<q-item-label>{{ $t("parent group") }}:</q-item-label>
</q-item>
<q-item v-if="type != 2" class="q-pa-none q-ma-none">
<q-item-section style="padding-right: 10px">
<q-tree
ref="tree"
class="scroll"
:class="loading ? 'disable_tree' : ''"
v-model:selected="selected"
:nodes="tree_nodes"
default-expand-all
node-key="uuid"
labelKey="name"
filter="group filter"
:filter-method="treeNodesFilter"
>
<template v-slot:default-header="prop">
<q-item
class="full-width"
:class="
prop.tree.selected == prop.key ? 'item-selected-bg' : ''
"
>
<q-item-section avatar>
<q-icon
:name="'img:source_icon/group.png'"
color="orange"
size="28px"
class="q-mr-sm"
/>
</q-item-section>
<q-item-section>
<div class="text-weight-bold text-primary">
{{ prop.node.name }}
</div>
</q-item-section>
</q-item>
</template>
</q-tree>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input
autofocus
:loading="loading"
:disable="loading"
filled
v-model="name"
:label="$t('group name')"
:hint="$t('please input group name')"
lazy-rules
:rules="[
(val) =>
(val && val.length > 0) || $t('Please type something'),
]"
@keydown="
(evt) => {
if (evt.keyCode == 13) {
$refs?.accept?.click();
}
}
"
>
<template v-if="name" v-slot:append>
<q-icon
name="cancel"
@click.stop="name = null"
class="cursor-pointer"
/>
</template>
</q-input>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
:loading="loading"
flat
:label="$t('Cancel')"
color="primary"
v-close-popup
/>
<q-btn
ref="accept"
flat
:label="$t('Accept')"
:loading="loading"
type="submit"
color="primary"
/>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped>
.disable_tree {
background: #9e9e9e;
cursor: wait;
pointer-events: none;
}
</style>
<script lang="ts">
import { defineComponent, ref, watch, computed } from "vue";
import { useStore } from "src/store";
import GlobalData from "src/common/GlobalData";
import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
export default defineComponent({
name: "ComponentPlanGroupDialog",
setup() {
let $store = useStore();
let $q = useQuasar();
let $t = useI18n();
let show_dialog = ref(false);
let type = ref(1);
let name = ref(null);
let uuid = ref("");
const selected: any = ref(null);
let loading = ref(false);
const tree_nodes = computed({
get: () => $store.state.plan_tree,
set: (val) => {},
});
watch(
() => selected.value,
(newValue, oldValue) => {
if (newValue == null) {
selected.value = "";
}
}
);
const requestAddPlanGroup = async () => {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.addPlanGroup(selected.value, name.value ?? "");
if (response) {
$q.notify({
color: response.success ? "positive" : "negative",
icon: response.success ? "done" : "warning",
message:
$t.t("add group") +
(response.success ? $t.t("success") : $t.t("fail")) +
"!",
position: "top",
timeout: 1000,
});
}
};
const requestEditPlanGroup = async () => {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.editPlanGroup(uuid.value, name.value ?? "");
if (response) {
$q.notify({
color: response.success ? "positive" : "negative",
icon: response.success ? "done" : "warning",
message:
$t.t("edit group") +
(response.success ? $t.t("success") : $t.t("fail")) +
"!",
position: "top",
timeout: 1000,
});
}
};
return {
show_dialog,
type,
name,
uuid,
selected,
loading,
tree_nodes,
showDialog(options: any) {
if (options) {
type.value = options.type ?? 1;
if (type.value == 2) {
name.value = options.data?.name ?? null;
}
selected.value = options.data?.uuid ?? null;
uuid.value = options.data?.uuid ?? null;
}
show_dialog.value = true;
},
resetData() {
loading.value = false;
(selected.value = null), (name.value = null);
type.value = 1;
},
treeNodesFilter(node: any, filter: any) {
return node.is_group;
},
async onSubmit() {
loading.value = true;
try {
await (type.value == 2
? requestEditPlanGroup()
: requestAddPlanGroup());
show_dialog.value = false;
} catch {}
loading.value = false;
},
};
},
});
</script>

294
src/components/PlanTree.vue Normal file
View File

@ -0,0 +1,294 @@
<template>
<div>
<q-tree ref="tree" :nodes="tree_nodes" node-key="uuid" labelKey="name">
<template v-slot:default-header="prop">
<q-item
class="full-width"
clickable
@dblclick="
(evt) => !prop.node.is_group && runPlan(prop.node.item_data)
"
>
<q-item-section avatar>
<q-icon
:name="
prop.node.is_group
? 'img:source_icon/group.png'
: 'img:source_icon/hdmi.png'
"
color="orange"
size="28px"
class="q-mr-sm"
/>
</q-item-section>
<q-item-section>
<div class="text-weight-bold text-primary">
{{ prop.node.name }}
</div>
</q-item-section>
<q-popup-proxy context-menu>
<q-popup-proxy context-menu />
<q-list>
<q-item
v-if="
prop.node.name == $t('root') ||
(prop.node.is_group && prop.node.item_data)
"
clickable
v-close-popup
v-ripple
@click="
$refs.plan_dialog.showDialog({
type: 1,
data: { uuid: prop.node.uuid },
})
"
>
<q-item-section avatar><q-icon name="add" /></q-item-section>
<q-item-section>{{ $t("add plan item") }}</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
v-if="
prop.node.name == $t('root') ||
(prop.node.is_group && prop.node.item_data)
"
v-ripple
@click="
() =>
$refs.group_dialog.showDialog({
type: 1,
data: prop.node,
})
"
>
<q-item-section avatar
><q-icon name="create_new_folder"
/></q-item-section>
<q-item-section>{{ $t("add group") }}</q-item-section>
</q-item>
<q-item
clickable
v-ripple
v-close-popup
v-if="prop.node.item_data"
@click="
() =>
(prop.node.is_group
? $refs.group_dialog
: $refs.plan_dialog
).showDialog({
type: 2,
data: prop.node,
})
"
>
<q-item-section avatar><q-icon name="edit" /></q-item-section>
<q-item-section>{{ $t("edit") }}</q-item-section>
</q-item>
<q-item
clickable
v-ripple
v-close-popup
v-if="prop.node.item_data"
@click="
(evt) => deleteItem(evt, prop.node.is_group, prop.node.uuid)
"
>
<q-item-section avatar
><q-icon color="red" name="delete"
/></q-item-section>
<q-item-section>{{ $t("delete") }} &nbsp;</q-item-section>
</q-item>
</q-list>
</q-popup-proxy>
</q-item>
</template>
</q-tree>
</div>
<plan-group-dialog ref="group_dialog" />
<plan-dialog ref="plan_dialog" />
</template>
<script lang="ts">
import { defineComponent, computed, onMounted, ref, nextTick } from "vue";
import { useStore } from "src/store";
import PlanGroupDialog from "src/components/PlanGroupDialog.vue";
import PlanDialog from "src/components/PlanDialog.vue";
import { Common } from "src/common/Common";
import GlobalData from "src/common/GlobalData";
import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { Protocol } from "src/entities/WSProtocol";
import { PlanEntity } from "src/entities/PlanEntity";
import { NotifyMessage } from "src/common/ClientConnection";
export default defineComponent({
name: "PagePlanTree",
components: { PlanGroupDialog, PlanDialog },
setup() {
const $store = useStore();
const $q = useQuasar();
const $t = useI18n();
const tree_nodes = computed({
get: () => $store.state.plan_tree,
set: (val) => {},
});
const tree: any | null = ref(null);
onMounted(async () => {
while (!tree.value.nodes.length) {
await Common.waitFor(100);
}
tree.value?.setExpanded("", true);
});
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(response: NotifyMessage) => {
if (response) {
switch (response.packet.command) {
case Protocol.Commands.kRpcAddPlan:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanAddNotifyEntity;
if (temp) {
GlobalData.getInstance().plans.push(temp.plan);
$store.commit("addPlanTreeItem", {
parent: temp.plan.group_uuid,
is_group: false,
item_data: temp.plan,
});
}
}
break;
case Protocol.Commands.kRpcDeletePlan:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanDeleteNotifyEntity;
if (temp) {
$store.commit("deletePlanTreeItem", {
is_group: false,
uuid: temp.uuid,
});
}
}
break;
case Protocol.Commands.kRpcEditPlan:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanEditNotifyEntity;
if (temp) {
$store.commit("setPlanTreeItem", {
is_group: false,
item_data: temp.plan,
});
}
}
break;
case Protocol.Commands.kRpcAddPlanGroup:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanGroupAddNotifyEntity;
if (temp) {
$store.commit("addPlanTreeItem", {
parent: temp.plan_group.parent_uuid,
is_group: true,
item_data: temp.plan_group,
});
}
}
break;
case Protocol.Commands.kRpcDeletePlanGroup:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanGroupDeleteNotifyEntity;
if (temp) {
$store.commit("deletePlanTreeItem", {
is_group: true,
uuid: temp.uuid,
});
}
}
break;
case Protocol.Commands.kRpcEditPlanGroup:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanGroupEditNotifyEntity;
if (temp) {
$store.commit("setPlanTreeItem", {
is_group: true,
item_data: temp.plan_group,
});
}
}
break;
}
}
}
);
return {
tree,
tree_nodes,
loga(a: any) {
console.log(a);
},
async deleteItem(
evt: PointerEvent | null,
is_group: boolean,
uuid: string
) {
let success = false;
if (is_group) {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.deletePlanGroup(uuid);
if (response) {
success = response.success;
}
} else {
let response = await GlobalData.getInstance()
.getCurrentClient()
?.deletePlan(uuid);
if (response) {
success = response.success;
}
}
$q.notify({
color: success ? "positive" : "negative",
icon: success ? "done" : "warning",
message:
$t.t("delete") + (success ? $t.t("success") : $t.t("fail")) + "!",
position: "top",
timeout: 1000,
});
},
runPlan(item: PlanEntity) {
GlobalData.getInstance().getCurrentClient()?.runPlan(item.uuid);
$q.notify({
color: "positive",
icon: "done",
message: $t.t("run plan directives send") + $t.t("success") + "!",
position: "top",
timeout: 1000,
});
},
};
},
});
</script>

View File

@ -10,9 +10,7 @@
? $t("add signal source")
: type == 2
? $t("edit signal source")
: type == 3
? $t("delete signal source")
: "add"
: $t("add signal source")
}}
</div>
<q-space />

View File

@ -10,9 +10,7 @@
? $t("add group")
: type == 2
? $t("edit group")
: type == 3
? $t("delete group")
: "add"
: $t("add group")
}}
</div>
<q-space />

View File

@ -133,6 +133,7 @@ import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { Protocol } from "src/entities/WSProtocol";
import { NotifyMessage } from "src/common/ClientConnection";
export default defineComponent({
name: "PageSignalSourceTree",
@ -158,13 +159,9 @@ export default defineComponent({
tree.value?.setExpanded("", true);
});
interface _ResponseMessage {
packet: Protocol.PacketEntity;
data: string;
}
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(response: _ResponseMessage) => {
(response: NotifyMessage) => {
if (response) {
switch (response.packet.command) {
case Protocol.Commands.kRpcAddSignalSource:

View File

@ -0,0 +1,45 @@
import BaseEntity from "./BaseEntity";
import { StringKeyValueEntity } from "./StringKeyValueEntity";
export class PlanEntity extends BaseEntity {
group_uuid: string = "";
name: string = "";
datas: StringKeyValueEntity[] = [];
public static copy(dest: PlanEntity, src?: PlanEntity) {
if (!src) {
src = new PlanEntity();
}
dest.uuid = src.uuid;
dest.base_note = src.base_note;
dest.name = src.name;
dest.group_uuid = src.group_uuid;
dest.datas = src.datas;
}
}
export class PlanTreeItemEntity {
uuid = "";
parent = "";
name = "";
is_group = false;
children: PlanTreeItemEntity[] = [];
item_data: PlanEntity | null = null;
constructor(
uuid?: string,
parent?: string,
name?: string,
is_group?: boolean,
item_data?: any,
children?: PlanTreeItemEntity[]
) {
this.uuid = uuid ?? "";
this.parent = parent ?? "";
this.name = name ?? "";
this.is_group = is_group ?? false;
this.children = children ?? (Array.isArray(children) ? children : []);
this.item_data = item_data;
}
}

View File

@ -0,0 +1,9 @@
export class StringKeyValueEntity {
public key: string;
public value: string;
constructor(key?: string, value?: string) {
this.key = key ?? "";
this.value = value ?? "";
}
}

View File

@ -2,6 +2,7 @@ import { SignalSourceEntity } from "./SignalSourceEntity";
import ApplicationConfigEntity from "./ApplicationConfigEntity";
import { WindowOpenNotifyEntity } from "./MultimediaWindowEntity";
import { ModeEntity } from "./ModeEntity";
import { PlanEntity } from "./PlanEntity";
export namespace Protocol {
export class Commands {
@ -42,6 +43,10 @@ export namespace Protocol {
return Commands.PROTOCOL_PREFIX + "RpcGetModes";
}
public static get kRpcGetPlans() {
return Commands.PROTOCOL_PREFIX + "RpcGetPlans";
}
public static get kRpcGetApplicationConfig() {
return Commands.PROTOCOL_PREFIX + "RpcGetApplicationConfig";
}
@ -114,12 +119,48 @@ export namespace Protocol {
return Commands.PROTOCOL_PREFIX + "RpcDeleteMode";
}
public static get kRpcEditMode() {
return Commands.PROTOCOL_PREFIX + "RpcEditMode";
}
public static get kCallMode() {
return Commands.PROTOCOL_PREFIX + "CallMode";
}
public static get kRpcEditMode() {
return Commands.PROTOCOL_PREFIX + "RpcEditMode";
public static get kRpcAddPlanGroup() {
return Commands.PROTOCOL_PREFIX + "RpcAddPlanGroup";
}
public static get kRpcDeletePlanGroup() {
return Commands.PROTOCOL_PREFIX + "RpcDeletePlanGroup";
}
public static get kRpcEditPlanGroup() {
return Commands.PROTOCOL_PREFIX + "RpcEditPlanGroup";
}
public static get kRpcAddPlan() {
return Commands.PROTOCOL_PREFIX + "RpcAddPlan";
}
public static get kRpcDeletePlan() {
return Commands.PROTOCOL_PREFIX + "RpcDeletePlan";
}
public static get kRpcEditPlan() {
return Commands.PROTOCOL_PREFIX + "RpcEditPlan";
}
public static get kRunPlan() {
return Commands.PROTOCOL_PREFIX + "RunPlan";
}
public static get kRpcGetCurrentRunningPlan() {
return Commands.PROTOCOL_PREFIX + "RpcGetCurrentRunningPlan";
}
public static get kPlanRunningStateChanged() {
return Commands.PROTOCOL_PREFIX + "PlanRunningStateChanged";
}
public static get kSetApplicationConfig() {
@ -141,6 +182,7 @@ export namespace Protocol {
Commands.kRpcGetWindows,
Commands.kRpcGetSignalSources,
Commands.kRpcGetModes,
Commands.kRpcGetPlans,
Commands.kRpcGetApplicationConfig,
Commands.kMoveWindow,
Commands.kResizeWindow,
@ -159,6 +201,14 @@ export namespace Protocol {
Commands.kRpcAddMode,
Commands.kRpcDeleteMode,
Commands.kRpcEditMode,
Commands.kRpcGetCurrentRunningPlan,
Commands.kPlanRunningStateChanged,
Commands.kRpcAddPlanGroup,
Commands.kRpcDeletePlanGroup,
Commands.kRpcEditPlanGroup,
Commands.kRpcAddPlan,
Commands.kRpcDeletePlan,
Commands.kRpcEditPlan,
Commands.kSetApplicationConfig,
]);
@ -250,6 +300,26 @@ export namespace Protocol {
}
}
export class GetPlansRequestEntity extends PacketEntity {
timestamp = new Date().getMilliseconds();
constructor(rpcid?: number) {
super();
this.rpc_id = rpcid ?? 0;
this.command = Commands.kRpcGetPlans;
}
}
export class GetPlansResponseEntity extends PacketEntity {
plans: PlanEntity[] = [];
plan_groups: [] = [];
constructor() {
super();
this.command = Commands.kRpcGetPlans;
}
}
export class GetApplicationConfigRequestEntity extends PacketEntity {
timestamp: number = new Date().getMilliseconds();
@ -712,6 +782,194 @@ export namespace Protocol {
mode_group: ModeGroupEntity = new ModeGroupEntity();
}
export class AddPlanGroupRequestEntity extends Protocol.PacketEntity {
parent_uuid = "";
name = "";
constructor(rcp_id?: number, parent_uuid?: string, name?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcAddPlanGroup;
this.parent_uuid = parent_uuid ?? "";
this.name = name ?? "";
}
}
export class AddPlanGroupResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcAddPlanGroup;
}
}
export class EditPlanGroupRequestEntity extends Protocol.PacketEntity {
uuid = "";
name = "";
constructor(rcp_id?: number, uuid?: string, name?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcEditPlanGroup;
this.uuid = uuid ?? "";
this.name = name ?? "";
}
}
export class EditPlanGroupResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcEditPlanGroup;
}
}
export class DeletePlanGroupRequestEntity extends Protocol.PacketEntity {
uuid = "";
constructor(rcp_id?: number, uuid?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcDeletePlanGroup;
this.uuid = uuid ?? "";
}
}
export class DeletePlanGroupResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcDeletePlan;
}
}
export class AddPlanRequestEntity extends Protocol.PacketEntity {
name: string;
group_uuid: string;
constructor(rcp_id?: number, name?: string, group_uuid?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcAddPlan;
this.name = name ?? "";
this.group_uuid = group_uuid ?? "";
}
}
export class AddPlanResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcAddPlan;
}
}
export class EditPlanRequestEntity extends Protocol.PacketEntity {
name: string;
uuid: string;
constructor(rcp_id?: number, name?: string, uuid?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcEditPlan;
this.name = name ?? "";
this.uuid = uuid ?? "";
}
}
export class EditPlanResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcEditPlan;
}
}
export class DeletePlanRequestEntity extends Protocol.PacketEntity {
uuid: string = "";
constructor(rcp_id?: number, uuid?: string) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcDeletePlan;
this.uuid = uuid ?? "";
}
}
export class DeletePlanResponseEntity extends Protocol.PacketEntity {
success = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcDeletePlan;
}
}
export class GetCurrentRunningPlanRequestEntity extends Protocol.PacketEntity {
timestamp: number = new Date().getMilliseconds();
constructor(rcp_id?: number) {
super();
this.rpc_id = rcp_id ?? 0;
this.command = Protocol.Commands.kRpcGetCurrentRunningPlan;
}
}
export class GetCurrentRunningPlanResponseEntity extends Protocol.PacketEntity {
plan = PlanEntity;
running = false;
constructor() {
super();
this.command = Protocol.Commands.kRpcGetCurrentRunningPlan;
}
}
export class PlanGroupEntity extends Protocol.PacketEntity {
parent_uuid: string = "";
name: string = "";
}
export class RunPlanRequestEntity extends Protocol.PacketEntity {
uuid: string;
constructor(uuid: string) {
super();
this.command = Protocol.Commands.kRunPlan;
this.flag = Protocol.PacketEntity.FLAG_REQUEST;
this.uuid = uuid;
}
}
export class PlanAddNotifyEntity extends Protocol.PacketEntity {
plan: PlanEntity = new PlanEntity();
}
export class PlanDeleteNotifyEntity extends Protocol.PacketEntity {
uuid: string = "";
}
export class PlanEditNotifyEntity extends Protocol.PacketEntity {
plan: PlanEntity = new PlanEntity();
}
export class PlanGroupAddNotifyEntity extends Protocol.PacketEntity {
plan_group: PlanGroupEntity = new PlanGroupEntity();
}
export class PlanGroupDeleteNotifyEntity extends Protocol.PacketEntity {
uuid: string = "";
}
export class PlanGroupEditNotifyEntity extends Protocol.PacketEntity {
plan_group: PlanGroupEntity = new PlanGroupEntity();
}
export class PlanRunningStateChangeNotifyEntity extends Protocol.PacketEntity {
plan: PlanEntity = new PlanEntity();
running = false;
}
export class SetApplicationConfigRequestEntity extends Protocol.PacketEntity {
key: string = "";
value: string = "";

View File

@ -128,4 +128,22 @@ export default {
"add mode": "添加模式",
"mode name": "模式名称",
"edit mode": "修改模式",
spa: "网页版",
pwa: "PWA版",
"add plan item": "添加预案",
"run plan directives send": "执行预案发送",
"is running": "正在运行",
"is stopping": "已经停止",
"add plan": "添加预案",
"edit plan": "修改预案",
"delete plan": "删除预案",
"plan name": "预案名称",
"please input plan name": "请输入预案名称",
"add row": "添加行",
"delete row": "删除行",
"operator value": "值",
delay: "延迟",
s: "秒",
"call mode": "模式调用",
"plan data": "预案数据",
};

View File

@ -10,6 +10,8 @@ import WallPage from "src/pages/WallPage.vue";
import EventBus, { EventNamesDefine } from "src/common/EventBus";
import { useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import { NotifyMessage } from "src/common/ClientConnection";
import { Protocol } from "src/entities/WSProtocol";
export default defineComponent({
name: "PageIndex",
@ -28,6 +30,37 @@ export default defineComponent({
EventBus.getInstance().on(EventNamesDefine.CurrentConnectConnected, () => {
$q.loading.hide();
});
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(response: NotifyMessage) => {
try {
switch (response.packet.command) {
case Protocol.Commands.kPlanRunningStateChanged:
{
const temp = JSON.parse(
response.data
) as Protocol.PlanRunningStateChangeNotifyEntity;
if (temp && temp.plan) {
$q.notify({
color: "positive",
icon: "done",
message:
$t.t("plan") +
" '" +
temp.plan.name +
" '" +
(temp.running ? $t.t("is running") : $t.t("is stopping")),
position: "top",
timeout: 1500,
});
}
}
break;
}
} catch {}
}
);
return {};
},
});

View File

@ -182,6 +182,10 @@ export default defineComponent({
const $route = useRouter();
const data = reactive(new _Data());
let web_socket: ClientConnection | null = null;
let is_pwa = ["fullscreen", "standalone", "minimal-ui"].some(
(displayMode) =>
window.matchMedia("(display-mode: " + displayMode + ")").matches
);
const landspace = ref(window.innerHeight < window.innerWidth);
@ -192,6 +196,7 @@ export default defineComponent({
return {
data,
landspace,
is_pwa,
loga(a: any) {
console.log(a);
},

View File

@ -20,8 +20,7 @@
</q-tab-panel>
<q-tab-panel name="plan">
<div class="text-h6">Alarms</div>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
<plan-tree />
</q-tab-panel>
</q-tab-panels>
</div>
@ -30,14 +29,15 @@
<script lang="ts">
import { defineComponent, ref } from "vue";
import ModeTree from "src/components/ModeTree.vue";
import PlanTree from "src/components/PlanTree.vue";
export default defineComponent({
name: "PageRightToolBar",
components: { ModeTree },
components: { ModeTree, PlanTree },
setup() {
let tab_value = ref("mode");
let tab_value = ref("plan");
return { tab_value };
},
});

View File

@ -110,6 +110,7 @@ import { api } from "boot/axios";
import { HttpProtocol } from "src/entities/HttpProtocol";
import { openURL, useQuasar } from "quasar";
import { useI18n } from "vue-i18n";
import { NotifyMessage } from "src/common/ClientConnection";
export default defineComponent({
name: "PageTopToolBar",
@ -127,15 +128,11 @@ export default defineComponent({
let $q = useQuasar();
let $t = useI18n();
let show_advanced_menu = ref(true);
let show_advanced_menu = ref(false);
interface _ResponseMessage {
packet: Protocol.PacketEntity;
data: string;
}
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(notify: _ResponseMessage) => {
(notify: NotifyMessage) => {
if (notify) {
switch (notify.packet.command) {
case Protocol.Commands.kSetApplicationConfig:

View File

@ -109,6 +109,7 @@ import {
} from "src/entities/MultimediaWindowEntity";
import WindowOtherStateChangeNotifyEntity from "src/entities/WindowOtherStateChangeNotifyEntity";
import { useQuasar } from "quasar";
import { NotifyMessage } from "src/common/ClientConnection";
interface _OptionsType {
$t: any;
@ -129,6 +130,13 @@ const _getModes = async () => {
?.getModes()) as Protocol.GetModesResponseEntity;
};
const _getPlans = async () => {
const global_data = GlobalData.getInstance();
return (await global_data
.getCurrentClient()
?.getPlans()) as Protocol.GetPlansResponseEntity;
};
const _initSignalSourceTree = async (options: _OptionsType) => {
const $store = options?.$store;
if ($store) {
@ -159,6 +167,21 @@ const _initModeTree = async (options: _OptionsType) => {
}
};
const _initPlanTree = async (options: _OptionsType) => {
const $store = options?.$store;
if ($store) {
try {
let response = await _getPlans();
if (response) {
$store.commit("buildPlanTree", { options, response });
GlobalData.getInstance().plans = response.plans;
}
} catch (e) {
console.error(e);
}
}
};
const _getApplicationConfig = async (options: _OptionsType) => {
const global_data = GlobalData.getInstance();
global_data.applicationConfig = (
@ -199,8 +222,9 @@ const _initialize = async (options: _OptionsType) => {
await _getApplicationConfig(options);
await _initSignalSourceTree(options);
await _initModeTree(options);
/* await */ _initSignalSourceTree(options);
/* await */ _initModeTree(options);
/* await */ _initPlanTree(options);
_getWindows(options);
}
};
@ -264,13 +288,9 @@ export default defineComponent({
}
};
interface _ResponseMessage {
packet: Protocol.PacketEntity;
data: string;
}
EventBus.getInstance().on(
EventNamesDefine.NotifyMessage,
(response: _ResponseMessage) => {
(response: NotifyMessage) => {
try {
switch (response.packet.command) {
case Protocol.Commands.kCloseWindow:

View File

@ -1,6 +1,7 @@
import { store } from "quasar/wrappers";
import { ModeEntity, ModeTreeItemEntity } from "src/entities/ModeEntity";
import { WindowOpenNotifyEntity } from "src/entities/MultimediaWindowEntity";
import { PlanEntity, PlanTreeItemEntity } from "src/entities/PlanEntity";
import {
SignalSourceEntity,
SignalSourceTreeItemEntity,
@ -31,6 +32,7 @@ export interface StateInterface {
initialized: boolean;
signal_source_tree: SignalSourceTreeItemEntity[];
mode_tree: ModeTreeItemEntity[];
plan_tree: PlanTreeItemEntity[];
wall_row: number;
wall_col: number;
device_screen_width: number;
@ -254,6 +256,7 @@ export default store(function (/* { ssrContext } */) {
initialized: false,
signal_source_tree: [],
mode_tree: [],
plan_tree: [],
wall_col: 1,
wall_row: 1,
device_screen_width: 1920,
@ -504,10 +507,7 @@ export default store(function (/* { ssrContext } */) {
}
},
//mode tree
setModeTree(
state: StateInterface,
playload?: SignalSourceTreeItemEntity[]
) {
setModeTree(state: StateInterface, playload?: ModeTreeItemEntity[]) {
if (playload) {
state.mode_tree = playload;
}
@ -515,10 +515,7 @@ export default store(function (/* { ssrContext } */) {
clearModeTree(state: StateInterface, playload?: any) {
state.mode_tree = [];
},
pushModeTreeItem(
state: StateInterface,
playload?: SignalSourceTreeItemEntity
) {
pushModeTreeItem(state: StateInterface, playload?: ModeTreeItemEntity) {
if (playload) {
state.mode_tree.push(playload);
}
@ -554,7 +551,7 @@ export default store(function (/* { ssrContext } */) {
name?: string,
is_group?: boolean,
item_data?: any,
children?: SignalSourceTreeItemEntity[]
children?: ModeTreeItemEntity[]
) =>
new ModeTreeItemEntity(
uuid,
@ -567,6 +564,64 @@ export default store(function (/* { ssrContext } */) {
playload
);
},
// plan tree
setPlanTree(state: StateInterface, playload?: PlanTreeItemEntity[]) {
if (playload) {
state.plan_tree = playload;
}
},
clearPlanTree(state: StateInterface, playload?: any) {
state.plan_tree = [];
},
pushPlanTreeItem(state: StateInterface, playload?: PlanTreeItemEntity) {
if (playload) {
state.plan_tree.push(playload);
}
},
addPlanTreeItem(state: StateInterface, playload?: any) {
_TreeHelper.addTreeItem(
state.plan_tree,
() => new PlanEntity(),
(uuid: string, parent: string, name: string, is_group: boolean) =>
new PlanTreeItemEntity(uuid, parent, name, is_group),
playload
);
},
setPlanTreeItem(state: StateInterface, playload?: any) {
_TreeHelper.setTreeItem(
state.plan_tree,
() => new PlanEntity(),
(left: any, right: any) => PlanEntity.copy(left, right),
playload
);
},
deletePlanTreeItem(state: StateInterface, playload?: any) {
_TreeHelper.deleteTreeItem(state.plan_tree, playload);
},
buildPlanTree(state: StateInterface, playload?: any) {
_TreeHelper.buildTree(
state.plan_tree,
"plan_groups",
"plans",
(
uuid?: string,
parent?: string,
name?: string,
is_group?: boolean,
item_data?: any,
children?: PlanTreeItemEntity[]
) =>
new PlanTreeItemEntity(
uuid,
parent,
name,
is_group,
item_data,
children
),
playload
);
},
},
// enable strict mode (adds overhead!)