temp
This commit is contained in:
parent
fe1ba733ef
commit
f8b88edcad
File diff suppressed because one or more lines are too long
@ -68,6 +68,16 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 8px 0 get-color(shadow1);
|
box-shadow: 0 2px 8px 0 get-color(shadow1);
|
||||||
|
|
||||||
|
& > .ant-card-head {
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
margin: 0;
|
||||||
|
font: 500 16px/20px Roboto;
|
||||||
|
color: get-color(text1);
|
||||||
|
background-color: get-color(fill1);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
& > .ant-card-body {
|
& > .ant-card-body {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
@ -103,8 +113,8 @@
|
|||||||
.ant-checkbox-wrapper {
|
.ant-checkbox-wrapper {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font: 400 14px/22px Roboto;
|
font: 400 14px/22px Roboto;
|
||||||
color: get-color(text2);
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
color: get-color(text2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-collapse.ant-collapse-ghost {
|
.ant-collapse.ant-collapse-ghost {
|
||||||
@ -261,13 +271,13 @@
|
|||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
|
||||||
&.ant-input-status-error {
|
&.ant-input-status-error {
|
||||||
border-color: get-color(error) !important;
|
|
||||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||||
|
border-color: get-color(error) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:disabled):focus {
|
&:not(:disabled):focus {
|
||||||
border-color: get-color(primary);
|
|
||||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||||
|
border-color: get-color(primary);
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,13 +291,13 @@
|
|||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
|
||||||
&.ant-input-affix-wrapper-status-error {
|
&.ant-input-affix-wrapper-status-error {
|
||||||
border-color: get-color(error) !important;
|
|
||||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||||
|
border-color: get-color(error) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.ant-input-affix-wrapper-disabled).ant-input-affix-wrapper-focused {
|
&:not(.ant-input-affix-wrapper-disabled).ant-input-affix-wrapper-focused {
|
||||||
border-color: get-color(primary);
|
|
||||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||||
|
border-color: get-color(primary);
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,8 +306,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
& > .ant-input {
|
& > .ant-input {
|
||||||
background-color: transparent;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > .ant-input-suffix {
|
& > .ant-input-suffix {
|
||||||
@ -322,13 +332,13 @@
|
|||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
|
||||||
&.ant-input-number-status-error {
|
&.ant-input-number-status-error {
|
||||||
border-color: get-color(error) !important;
|
|
||||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||||
|
border-color: get-color(error) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:disabled).ant-input-number-focused {
|
&:not(:disabled).ant-input-number-focused {
|
||||||
border-color: get-color(primary);
|
|
||||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||||
|
border-color: get-color(primary);
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,6 +465,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-select:not(.ant-select-borderless) {
|
.ant-select:not(.ant-select-borderless) {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
& > .ant-select-selector {
|
& > .ant-select-selector {
|
||||||
color: get-color(text1);
|
color: get-color(text1);
|
||||||
background-color: get-color(neutral1);
|
background-color: get-color(neutral1);
|
||||||
@ -477,8 +489,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.ant-select-status-error > .ant-select-selector {
|
&.ant-select-status-error > .ant-select-selector {
|
||||||
border-color: get-color(error) !important;
|
|
||||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||||
|
border-color: get-color(error) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.ant-select-disabled):hover > .ant-select-selector {
|
&:not(.ant-select-disabled):hover > .ant-select-selector {
|
||||||
@ -486,8 +498,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(.ant-select-disabled).ant-select-focused > .ant-select-selector {
|
&:not(.ant-select-disabled).ant-select-focused > .ant-select-selector {
|
||||||
border-color: get-color(primary);
|
|
||||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||||
|
border-color: get-color(primary);
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,6 +590,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: get-color(fill1);
|
background-color: get-color(fill1);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
& > .ant-tabs-nav-wrap > .ant-tabs-nav-list {
|
& > .ant-tabs-nav-wrap > .ant-tabs-nav-list {
|
||||||
& > .ant-tabs-tab {
|
& > .ant-tabs-tab {
|
||||||
padding: 14px 32px;
|
padding: 14px 32px;
|
||||||
@ -604,6 +620,10 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > .ant-tabs-nav-operations {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > .ant-tabs-content-holder > .ant-tabs-content {
|
& > .ant-tabs-content-holder > .ant-tabs-content {
|
||||||
@ -620,8 +640,8 @@
|
|||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font: 500 14px/22px Roboto;
|
font: 500 14px/22px Roboto;
|
||||||
color: get-color(text1);
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
color: get-color(text1);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-color: get-color(border1);
|
border-color: get-color(border1);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
43
src/components/card/point-edit-card.vue
Normal file
43
src/components/card/point-edit-card.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { MAP_POINT_TYPES, type MapPen, type MapPointInfo } from '@api/map';
|
||||||
|
import type { EditorService } from '@core/editor.service';
|
||||||
|
import sTheme from '@core/theme.service';
|
||||||
|
import { computed, inject, type InjectionKey, type ShallowRef } from 'vue';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
token: InjectionKey<ShallowRef<EditorService>>;
|
||||||
|
};
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const editor = inject(props.token)!;
|
||||||
|
|
||||||
|
const pen = computed<MapPen | undefined>(() => editor.value.current.value);
|
||||||
|
const point = computed<MapPointInfo | null>(() => {
|
||||||
|
const point = pen.value?.point;
|
||||||
|
if (!point?.type) return null;
|
||||||
|
return point;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-card :title="$t('属性')" :bordered="false">
|
||||||
|
<template v-if="pen && point">
|
||||||
|
<a-row :gutter="8">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-select :value="point.type" @change="editor.changePointType(pen.id!, <number>$event)">
|
||||||
|
<a-select-option v-for="[l, v] in MAP_POINT_TYPES" :key="v">{{ $t(l) }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-input
|
||||||
|
:maxlength="10"
|
||||||
|
:value="pen.label"
|
||||||
|
@change="editor.updatePen(pen.id!, { label: $event.target.value }, false)"
|
||||||
|
>
|
||||||
|
<template #suffix><EditOutlined /></template>
|
||||||
|
</a-input>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
<a-empty v-else :image="sTheme.empty" />
|
||||||
|
</a-card>
|
||||||
|
</template>
|
@ -7,7 +7,7 @@ import { inject, type InjectionKey, ref, type ShallowRef, watch } from 'vue';
|
|||||||
type Props = {
|
type Props = {
|
||||||
token: InjectionKey<ShallowRef<EditorService>>;
|
token: InjectionKey<ShallowRef<EditorService>>;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
current?: string;
|
id: string;
|
||||||
};
|
};
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
const editor = inject(props.token)!;
|
const editor = inject(props.token)!;
|
||||||
@ -54,13 +54,18 @@ watch(editor.value.mouseBrush, (v) => {
|
|||||||
<a-button class="icon-btn tool-btn" size="large">
|
<a-button class="icon-btn tool-btn" size="large">
|
||||||
<i class="mask save" />
|
<i class="mask save" />
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button class="icon-btn tool-btn ml-12" size="large">
|
<a-button class="icon-btn tool-btn ml-12" size="large" @click="editor.undo()">
|
||||||
<i class="mask undo" />
|
<i class="mask undo" />
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button class="icon-btn tool-btn ml-12" size="large">
|
<a-button class="icon-btn tool-btn ml-12" size="large" @click="editor.redo()">
|
||||||
<i class="mask redo" />
|
<i class="mask redo" />
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button class="icon-btn tool-btn ml-12" size="large" :disabled="!editor.selected.value.length">
|
<a-button
|
||||||
|
class="icon-btn tool-btn ml-12"
|
||||||
|
size="large"
|
||||||
|
@click="editor.delete(undefined, true)"
|
||||||
|
:disabled="!editor.selected.value.length"
|
||||||
|
>
|
||||||
<i class="mask trash" />
|
<i class="mask trash" />
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getSceneById } from '@api/scene';
|
import { getSceneById } from '@api/scene';
|
||||||
import { EditorService } from '@core/editor.service';
|
import { EditorService } from '@core/editor.service';
|
||||||
import { isNil } from 'lodash-es';
|
import { decodeTextFile, downloadFile, selectFile, textToBlob } from '@core/utils';
|
||||||
import { computed, watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { onMounted, provide, shallowRef } from 'vue';
|
import { onMounted, provide, shallowRef } from 'vue';
|
||||||
@ -38,6 +38,22 @@ onMounted(() => {
|
|||||||
const editable = ref<boolean>(false);
|
const editable = ref<boolean>(false);
|
||||||
watch(editable, (v) => editor.value?.setState(v));
|
watch(editable, (v) => editor.value?.setState(v));
|
||||||
|
|
||||||
|
const importScene = async () => {
|
||||||
|
const file = await selectFile('.scene');
|
||||||
|
if (!file?.size) return;
|
||||||
|
const json = await decodeTextFile(file);
|
||||||
|
editor.value?.load(json, editable.value);
|
||||||
|
};
|
||||||
|
const exportScene = () => {
|
||||||
|
const json = editor.value?.save();
|
||||||
|
if (!json) return;
|
||||||
|
const blob = textToBlob(json);
|
||||||
|
if (!blob?.size) return;
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
downloadFile(url, `${title.value || 'unknown'}.scene`);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
const show = ref<boolean>(true);
|
const show = ref<boolean>(true);
|
||||||
const current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
const current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
||||||
watch(
|
watch(
|
||||||
@ -78,8 +94,8 @@ const selectRobot = (id: string) => {
|
|||||||
<span>{{ $t('启用编辑器') }}</span>
|
<span>{{ $t('启用编辑器') }}</span>
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button>{{ $t('推送') }}</a-button>
|
<a-button>{{ $t('推送') }}</a-button>
|
||||||
<a-button>{{ $t('导入') }}</a-button>
|
<a-button @click="importScene">{{ $t('导入') }}</a-button>
|
||||||
<a-button @click="editor?.export()">{{ $t('导出') }}</a-button>
|
<a-button @click="exportScene">{{ $t('导出') }}</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-flex>
|
</a-flex>
|
||||||
</a-layout-header>
|
</a-layout-header>
|
||||||
@ -111,7 +127,7 @@ const selectRobot = (id: string) => {
|
|||||||
</a-layout>
|
</a-layout>
|
||||||
|
|
||||||
<div v-if="editable" class="toolbar-container">
|
<div v-if="editable" class="toolbar-container">
|
||||||
<EditorToolbar v-if="editor" :token="EDITOR_KEY" />
|
<EditorToolbar v-if="editor" :token="EDITOR_KEY" :id="id" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="current?.id">
|
<template v-if="current?.id">
|
||||||
@ -122,7 +138,7 @@ const selectRobot = (id: string) => {
|
|||||||
<RobotDetailCard v-if="isRobot" :token="EDITOR_KEY" :current="current.id" />
|
<RobotDetailCard v-if="isRobot" :token="EDITOR_KEY" :current="current.id" />
|
||||||
|
|
||||||
<template v-if="isPoint">
|
<template v-if="isPoint">
|
||||||
<div v-if="editable"></div>
|
<PointEditCard v-if="editable" :token="EDITOR_KEY" :current="current.id" />
|
||||||
<PointDetailCard v-else :token="EDITOR_KEY" :current="current.id" />
|
<PointDetailCard v-else :token="EDITOR_KEY" :current="current.id" />
|
||||||
</template>
|
</template>
|
||||||
<template v-if="isRoute">
|
<template v-if="isRoute">
|
||||||
@ -146,14 +162,14 @@ const selectRobot = (id: string) => {
|
|||||||
right: 50%;
|
right: 50%;
|
||||||
bottom: 40px;
|
bottom: 40px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
z-index: 8888;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-container {
|
.card-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 80px;
|
top: 80px;
|
||||||
right: 64px;
|
right: 64px;
|
||||||
z-index: 8888;
|
z-index: 100;
|
||||||
width: 320px;
|
width: 320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,26 +15,11 @@ export class EditorService extends Meta2d {
|
|||||||
const data = map ? JSON.parse(map) : undefined;
|
const data = map ? JSON.parse(map) : undefined;
|
||||||
this.open(data);
|
this.open(data);
|
||||||
this.setState(editable);
|
this.setState(editable);
|
||||||
this.addPoint({ x: 100, y: 100 }, 1);
|
|
||||||
this.addPoint({ x: 200, y: 100 }, 2);
|
|
||||||
this.addPoint({ x: 300, y: 100 }, 3);
|
|
||||||
this.addPoint({ x: 400, y: 100 }, 4);
|
|
||||||
|
|
||||||
this.addPoint({ x: 100, y: 200 }, 11);
|
|
||||||
this.addPoint({ x: 200, y: 200 }, 12);
|
|
||||||
this.addPoint({ x: 300, y: 200 }, 13);
|
|
||||||
this.addPoint({ x: 400, y: 200 }, 14);
|
|
||||||
this.addPoint({ x: 500, y: 200 }, 15);
|
|
||||||
this.addPoint({ x: 600, y: 200 }, 16);
|
|
||||||
}
|
}
|
||||||
public save(): string {
|
public save(): string {
|
||||||
const data = this.data();
|
const data = this.data();
|
||||||
return JSON.stringify(data);
|
return JSON.stringify(data);
|
||||||
}
|
}
|
||||||
public export(): void {
|
|
||||||
const json = this.save();
|
|
||||||
console.log(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setState(editable?: boolean): void {
|
public setState(editable?: boolean): void {
|
||||||
this.lock(editable ? LockState.None : LockState.DisableMoveScale);
|
this.lock(editable ? LockState.None : LockState.DisableMoveScale);
|
||||||
@ -137,6 +122,12 @@ export class EditorService extends Meta2d {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
readonly #change$$ = new Subject<boolean>();
|
readonly #change$$ = new Subject<boolean>();
|
||||||
|
public readonly current = useObservable<MapPen>(
|
||||||
|
this.#change$$.pipe(
|
||||||
|
debounceTime(100),
|
||||||
|
map(() => <MapPen>clone(this.store.active?.[0])),
|
||||||
|
),
|
||||||
|
);
|
||||||
public readonly selected = useObservable<string[], string[]>(
|
public readonly selected = useObservable<string[], string[]>(
|
||||||
this.#change$$.pipe(
|
this.#change$$.pipe(
|
||||||
filter((v) => !v),
|
filter((v) => !v),
|
||||||
@ -171,6 +162,10 @@ export class EditorService extends Meta2d {
|
|||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updatePen(id: string, pen: Partial<MapPen>, record = true): void {
|
||||||
|
this.setValue({ ...pen, id }, { render: record, history: record, doEvent: true });
|
||||||
|
}
|
||||||
|
|
||||||
//#region 点位
|
//#region 点位
|
||||||
public readonly points = useObservable<MapPen[], MapPen[]>(
|
public readonly points = useObservable<MapPen[], MapPen[]>(
|
||||||
this.#change$$.pipe(
|
this.#change$$.pipe(
|
||||||
@ -189,7 +184,7 @@ export class EditorService extends Meta2d {
|
|||||||
...this.#mapPointImage(type),
|
...this.#mapPointImage(type),
|
||||||
id,
|
id,
|
||||||
name: 'point',
|
name: 'point',
|
||||||
tags: ['point', `point-${type}`],
|
tags: ['point'],
|
||||||
label: `P${id}`,
|
label: `P${id}`,
|
||||||
point: { type },
|
point: { type },
|
||||||
};
|
};
|
||||||
@ -200,6 +195,13 @@ export class EditorService extends Meta2d {
|
|||||||
// this.pushHistory({ type: EditType.Add, pens: [cloneDeep(pen)] });
|
// this.pushHistory({ type: EditType.Add, pens: [cloneDeep(pen)] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public changePointType(id: string, type: MapPointType): void {
|
||||||
|
this.setValue(
|
||||||
|
{ id, ...this.#mapPoint(type), ...this.#mapPointImage(type), point: { type } },
|
||||||
|
{ render: true, history: true, doEvent: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#mapPoint(type: MapPointType): Required<Pick<MapPen, 'width' | 'height' | 'lineWidth' | 'iconSize'>> {
|
#mapPoint(type: MapPointType): Required<Pick<MapPen, 'width' | 'height' | 'lineWidth' | 'iconSize'>> {
|
||||||
const width = type < 10 ? 24 : 48;
|
const width = type < 10 ? 24 : 48;
|
||||||
const height = type < 10 ? 24 : 60;
|
const height = type < 10 ? 24 : 60;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user