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;
|
||||
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 {
|
||||
padding: 16px;
|
||||
}
|
||||
@ -103,8 +113,8 @@
|
||||
.ant-checkbox-wrapper {
|
||||
align-items: center;
|
||||
font: 400 14px/22px Roboto;
|
||||
color: get-color(text2);
|
||||
vertical-align: top;
|
||||
color: get-color(text2);
|
||||
}
|
||||
|
||||
.ant-collapse.ant-collapse-ghost {
|
||||
@ -261,13 +271,13 @@
|
||||
box-shadow: none !important;
|
||||
|
||||
&.ant-input-status-error {
|
||||
border-color: get-color(error) !important;
|
||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||
border-color: get-color(error) !important;
|
||||
}
|
||||
|
||||
&:not(:disabled):focus {
|
||||
border-color: get-color(primary);
|
||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||
border-color: get-color(primary);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@ -281,13 +291,13 @@
|
||||
box-shadow: none !important;
|
||||
|
||||
&.ant-input-affix-wrapper-status-error {
|
||||
border-color: get-color(error) !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 {
|
||||
border-color: get-color(primary);
|
||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||
border-color: get-color(primary);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@ -296,8 +306,8 @@
|
||||
}
|
||||
|
||||
& > .ant-input {
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
& > .ant-input-suffix {
|
||||
@ -322,13 +332,13 @@
|
||||
box-shadow: none !important;
|
||||
|
||||
&.ant-input-number-status-error {
|
||||
border-color: get-color(error) !important;
|
||||
outline-color: rgba($color: get-color(error), $alpha: 20%) !important;
|
||||
border-color: get-color(error) !important;
|
||||
}
|
||||
|
||||
&:not(:disabled).ant-input-number-focused {
|
||||
border-color: get-color(primary);
|
||||
outline: 2px solid rgba($color: get-color(primary), $alpha: 20%);
|
||||
border-color: get-color(primary);
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@ -455,6 +465,8 @@
|
||||
}
|
||||
|
||||
.ant-select:not(.ant-select-borderless) {
|
||||
width: 100%;
|
||||
|
||||
& > .ant-select-selector {
|
||||
color: get-color(text1);
|
||||
background-color: get-color(neutral1);
|
||||
@ -477,8 +489,8 @@
|
||||
}
|
||||
|
||||
&.ant-select-status-error > .ant-select-selector {
|
||||
border-color: get-color(error) !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 {
|
||||
@ -486,8 +498,8 @@
|
||||
}
|
||||
|
||||
&: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%);
|
||||
border-color: get-color(primary);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@ -578,6 +590,10 @@
|
||||
margin: 0;
|
||||
background-color: get-color(fill1);
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& > .ant-tabs-nav-wrap > .ant-tabs-nav-list {
|
||||
& > .ant-tabs-tab {
|
||||
padding: 14px 32px;
|
||||
@ -604,6 +620,10 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
& > .ant-tabs-nav-operations {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
& > .ant-tabs-content-holder > .ant-tabs-content {
|
||||
@ -620,8 +640,8 @@
|
||||
padding: 3px 5px;
|
||||
margin: 0;
|
||||
font: 500 14px/22px Roboto;
|
||||
color: get-color(text1);
|
||||
vertical-align: top;
|
||||
color: get-color(text1);
|
||||
background-color: transparent;
|
||||
border-color: get-color(border1);
|
||||
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 = {
|
||||
token: InjectionKey<ShallowRef<EditorService>>;
|
||||
editable?: boolean;
|
||||
current?: string;
|
||||
id: string;
|
||||
};
|
||||
const props = defineProps<Props>();
|
||||
const editor = inject(props.token)!;
|
||||
@ -54,13 +54,18 @@ watch(editor.value.mouseBrush, (v) => {
|
||||
<a-button class="icon-btn tool-btn" size="large">
|
||||
<i class="mask save" />
|
||||
</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" />
|
||||
</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" />
|
||||
</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" />
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { getSceneById } from '@api/scene';
|
||||
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 { ref } from 'vue';
|
||||
import { onMounted, provide, shallowRef } from 'vue';
|
||||
@ -38,6 +38,22 @@ onMounted(() => {
|
||||
const editable = ref<boolean>(false);
|
||||
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 current = ref<{ type: 'robot' | 'point' | 'line' | 'area'; id: string }>();
|
||||
watch(
|
||||
@ -78,8 +94,8 @@ const selectRobot = (id: string) => {
|
||||
<span>{{ $t('启用编辑器') }}</span>
|
||||
</a-button>
|
||||
<a-button>{{ $t('推送') }}</a-button>
|
||||
<a-button>{{ $t('导入') }}</a-button>
|
||||
<a-button @click="editor?.export()">{{ $t('导出') }}</a-button>
|
||||
<a-button @click="importScene">{{ $t('导入') }}</a-button>
|
||||
<a-button @click="exportScene">{{ $t('导出') }}</a-button>
|
||||
</a-space>
|
||||
</a-flex>
|
||||
</a-layout-header>
|
||||
@ -111,7 +127,7 @@ const selectRobot = (id: string) => {
|
||||
</a-layout>
|
||||
|
||||
<div v-if="editable" class="toolbar-container">
|
||||
<EditorToolbar v-if="editor" :token="EDITOR_KEY" />
|
||||
<EditorToolbar v-if="editor" :token="EDITOR_KEY" :id="id" />
|
||||
</div>
|
||||
|
||||
<template v-if="current?.id">
|
||||
@ -122,7 +138,7 @@ const selectRobot = (id: string) => {
|
||||
<RobotDetailCard v-if="isRobot" :token="EDITOR_KEY" :current="current.id" />
|
||||
|
||||
<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" />
|
||||
</template>
|
||||
<template v-if="isRoute">
|
||||
@ -146,14 +162,14 @@ const selectRobot = (id: string) => {
|
||||
right: 50%;
|
||||
bottom: 40px;
|
||||
left: 50%;
|
||||
z-index: 8888;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
right: 64px;
|
||||
z-index: 8888;
|
||||
z-index: 100;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
|
@ -15,26 +15,11 @@ export class EditorService extends Meta2d {
|
||||
const data = map ? JSON.parse(map) : undefined;
|
||||
this.open(data);
|
||||
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 {
|
||||
const data = this.data();
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
public export(): void {
|
||||
const json = this.save();
|
||||
console.log(json);
|
||||
}
|
||||
|
||||
public setState(editable?: boolean): void {
|
||||
this.lock(editable ? LockState.None : LockState.DisableMoveScale);
|
||||
@ -137,6 +122,12 @@ export class EditorService extends Meta2d {
|
||||
//#endregion
|
||||
|
||||
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[]>(
|
||||
this.#change$$.pipe(
|
||||
filter((v) => !v),
|
||||
@ -171,6 +162,10 @@ export class EditorService extends Meta2d {
|
||||
this.render();
|
||||
}
|
||||
|
||||
public updatePen(id: string, pen: Partial<MapPen>, record = true): void {
|
||||
this.setValue({ ...pen, id }, { render: record, history: record, doEvent: true });
|
||||
}
|
||||
|
||||
//#region 点位
|
||||
public readonly points = useObservable<MapPen[], MapPen[]>(
|
||||
this.#change$$.pipe(
|
||||
@ -189,7 +184,7 @@ export class EditorService extends Meta2d {
|
||||
...this.#mapPointImage(type),
|
||||
id,
|
||||
name: 'point',
|
||||
tags: ['point', `point-${type}`],
|
||||
tags: ['point'],
|
||||
label: `P${id}`,
|
||||
point: { type },
|
||||
};
|
||||
@ -200,6 +195,13 @@ export class EditorService extends Meta2d {
|
||||
// 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'>> {
|
||||
const width = type < 10 ? 24 : 48;
|
||||
const height = type < 10 ? 24 : 60;
|
||||
|
Loading…
x
Reference in New Issue
Block a user