feat: load standard scene

This commit is contained in:
chndfang 2025-05-17 22:53:30 +08:00
parent e3edde1b16
commit 713cf8a022
3 changed files with 92 additions and 30 deletions

View File

@ -6,6 +6,7 @@ import type { GroupSceneDetail, SceneDetail, SceneInfo } from './type';
const enum API {
= '/scene/getById',
= '/scene/saveById',
= '/scene/pushById',
= '/scene/getByGroupId',
= '/scene/saveByGroupId',
@ -39,6 +40,20 @@ export async function saveSceneById(id: SceneInfo['id'], json: string): Promise<
}
}
export async function pushSceneById(id: SceneInfo['id']): Promise<boolean> {
if (!id) return false;
type B = { id: string };
type D = void;
try {
const body = { id };
await http.post<D, B>(API., body);
return true;
} catch (error) {
console.debug(error);
return false;
}
}
export async function getSceneByGroupId(
id: RobotGroup['id'],
sid: RobotGroup['sid'],

View File

@ -1,10 +1,12 @@
<script setup lang="ts">
import { getSceneById } from '@api/scene';
import { getSceneById, pushSceneById } from '@api/scene';
import { EditorService } from '@core/editor.service';
import { decodeTextFile, downloadFile, selectFile, textToBlob } from '@core/utils';
import { Modal } from 'ant-design-vue';
import { computed, watch } from 'vue';
import { ref } from 'vue';
import { onMounted, provide, shallowRef } from 'vue';
import { useI18n } from 'vue-i18n';
const EDITOR_KEY = Symbol('editor-key');
@ -13,12 +15,18 @@ type Props = {
};
const props = defineProps<Props>();
const { t } = useI18n();
//#region
const readScene = async () => {
const res = await getSceneById(props.id);
title.value = res?.label ?? '';
editor.value?.load(res?.json, editable.value);
};
const pushScene = async () => {
await pushSceneById(props.id);
};
//#endregion
const title = ref<string>('');
@ -38,6 +46,17 @@ onMounted(() => {
const editable = ref<boolean>(false);
watch(editable, (v) => editor.value?.setState(v));
const toPush = () =>
Modal.confirm({
class: 'confirm',
title: t('您确定要推送该场景文件至数据库吗?'),
content: t('请确保当前场景已经保存,否则可能导致推送的文件版本不正确。'),
centered: true,
cancelText: t('返回'),
okText: t('推送'),
onOk: () => pushScene(),
});
const importScene = async () => {
const file = await selectFile('.scene');
if (!file?.size) return;
@ -93,6 +112,7 @@ const selectRobot = (id: string) => {
<i class="icon edit size-18 mr-8" />
<span>{{ $t('启用编辑器') }}</span>
</a-button>
<a-button @click="toPush">{{ $t('同步') }}</a-button>
<a-button @click="importScene">{{ $t('导入') }}</a-button>
<a-button @click="exportScene">{{ $t('导出') }}</a-button>
</a-space>

View File

@ -35,13 +35,14 @@ export class EditorService extends Meta2d {
scene.robots = detail.robots;
}
const { robotGroups, robots, points, routes, areas } = scene;
this.open(undefined, false);
await this.#loadScenePoints(points);
const data = this.data();
data.robotGroups = robotGroups;
data.robots = robots;
this.open(data, true);
this.open();
this.setState(editable);
this.#loadRobots(robotGroups, robots);
await this.#loadScenePoints(points);
this.#loadSceneRoutes(routes);
await this.#loadSceneAreas(areas);
this.store.historyIndex = undefined;
this.store.histories = [];
}
public save(): string {
const scene: StandardScene = {
@ -55,6 +56,11 @@ export class EditorService extends Meta2d {
return JSON.stringify(scene);
}
#loadRobots(groups?: RobotGroup[], robots?: RobotInfo[]): void {
this.#robotMap.clear();
robots?.forEach((v) => this.#robotMap.set(v.id, v));
this.#robotGroups$$.next(groups ?? []);
}
async #loadScenePoints(points?: StandardScenePoint[]): Promise<void> {
if (!points?.length) return;
await Promise.all(
@ -68,6 +74,31 @@ export class EditorService extends Meta2d {
}),
);
}
#loadSceneRoutes(routes?: StandardSceneRoute[]): void {
if (!routes?.length) return;
routes.map((v) => {
const { id, desc, from, to, type, pass, c1, c2, properties } = v;
this.addRoute([from, to], <MapRouteType>type, id);
this.setValue(
{ id, desc, properties, route: { type, pass, c1, c2 } },
{ render: false, history: false, doEvent: false },
);
});
}
async #loadSceneAreas(areas?: StandardSceneArea[]): Promise<void> {
if (!areas?.length) return;
await Promise.all(
areas.map(async (v) => {
const { id, name, desc, x, y, w, h, type, points, routes, properties } = v;
await this.addArea({ x, y }, { x: x + w, y: y + h }, type, id);
this.setValue(
{ id, label: name, desc, properties, area: { type, points, routes } },
{ render: false, history: false, doEvent: false },
);
}),
);
}
#mapScenePoint(pen?: MapPen): StandardScenePoint | null {
if (!pen?.id || isEmpty(pen?.point)) return null;
const { id, label, desc, properties } = pen;
@ -433,23 +464,26 @@ export class EditorService extends Meta2d {
const w = Math.abs(p1.x - p2.x);
const h = Math.abs(p1.y - p2.y);
if (w * scale < 50 || h * scale < 60) return;
const selected = <MapPen[]>this.store.active;
id ||= s8();
const points = new Array<string>();
const routes = new Array<string>();
switch (type) {
case MapAreaType.:
selected?.filter(({ point }) => point?.type === MapPointType.).forEach(({ id }) => points.push(id!));
break;
case MapAreaType.:
selected?.filter(({ point }) => point?.type).forEach(({ id }) => points.push(id!));
selected?.filter(({ route }) => route?.type).forEach(({ id }) => routes.push(id!));
break;
case MapAreaType.:
selected?.filter(({ point }) => point?.type).forEach(({ id }) => points.push(id!));
break;
default:
break;
if (id) {
const selected = <MapPen[]>this.store.active;
switch (type) {
case MapAreaType.:
selected?.filter(({ point }) => point?.type === MapPointType.).forEach(({ id }) => points.push(id!));
break;
case MapAreaType.:
selected?.filter(({ point }) => point?.type).forEach(({ id }) => points.push(id!));
selected?.filter(({ route }) => route?.type).forEach(({ id }) => routes.push(id!));
break;
case MapAreaType.:
selected?.filter(({ point }) => point?.type).forEach(({ id }) => points.push(id!));
break;
default:
break;
}
} else {
id = s8();
}
const pen: MapPen = {
id,
@ -464,9 +498,8 @@ export class EditorService extends Meta2d {
area: { type, points, routes },
locked: LockState.DisableMoveScale,
};
const area = await this.addPen(pen, false, true, true);
const area = await this.addPen(pen, true, true, true);
this.bottom(area);
// this.pushHistory({ type: EditType.Add, pens: [cloneDeep(pen)] });
}
public updateArea(id: string, info: Partial<MapAreaInfo>): void {
@ -493,12 +526,6 @@ export class EditorService extends Meta2d {
#load(theme: string): void {
this.setTheme(theme);
const { robots, robotGroups } = this.data();
this.#robotMap.clear();
robots?.forEach((r) => this.#robotMap.set(r.id, r));
this.#robotGroups$$.next(robotGroups ?? []);
this.find('point').forEach((pen) => {
if (!pen.point?.type) return;
if (pen.point.type < 10) return;