diff --git a/mocks/robot/seizeByIds b/mocks/robot/seizeByIds
index 8ecc2d2..3e6737a 100644
--- a/mocks/robot/seizeByIds
+++ b/mocks/robot/seizeByIds
@@ -1,5 +1,9 @@
{
"code": 200,
- "success": false,
+ "success": true,
+ "data": [
+ "mock-robot-1",
+ "mock-robot-2"
+ ],
"message": "模拟提示"
}
diff --git a/mocks/scene/getById b/mocks/scene/getById
index f716eb6..176003e 100644
--- a/mocks/scene/getById
+++ b/mocks/scene/getById
@@ -4,7 +4,7 @@
"data": {
"id": "mock-scene-1",
"label": "模拟场景A",
- "json": "{\"x\":0,\"y\":0,\"scale\":1,\"pens\":[],\"origin\":{\"x\":0,\"y\":0},\"center\":{\"x\":0,\"y\":0},\"paths\":{},\"template\":\"4c2a10f\",\"locked\":10,\"version\":\"1.0.78\",\"dataPoints\":[],\"robotGroups\":[{\"id\":\"mock-robot-group-1\",\"label\":\"模拟机器人组A\",\"robots\":[\"mock-robot-1\",\"mock-robot-2\",\"mock-robot-3\"]},{\"sid\":\"mock-scene-1\",\"id\":\"mock-robot-group-2\",\"label\":\"模拟机器人组B\",\"robots\":[\"mock-robot-4\"]}],\"robots\":[{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-1\",\"label\":\"模拟机器人A\",\"brand\":\"模拟品牌A\",\"type\":1},{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-2\",\"label\":\"模拟机器人B\",\"brand\":\"模拟品牌A\",\"type\":2},{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-3\",\"label\":\"模拟机器人C\",\"brand\":\"模拟品牌A\",\"type\":3},{\"gid\":\"mock-robot-group-2\",\"id\":\"mock-robot-4\",\"label\":\"模拟机器人D\",\"brand\":\"模拟品牌B\",\"type\":1}]}"
+ "json": "{\"x\":0,\"y\":0,\"scale\":1,\"pens\":[],\"origin\":{\"x\":0,\"y\":0},\"center\":{\"x\":0,\"y\":0},\"paths\":{},\"template\":\"4c2a10f\",\"locked\":10,\"version\":\"1.0.78\",\"dataPoints\":[],\"robotGroups\":[{\"id\":\"mock-robot-group-1\",\"label\":\"模拟机器人组A\",\"robots\":[\"mock-robot-1\",\"mock-robot-2\",\"mock-robot-3\"]},{\"sid\":\"mock-scene-1\",\"id\":\"mock-robot-group-2\",\"label\":\"模拟机器人组B\",\"robots\":[\"mock-robot-4\"]}],\"robots\":[{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-1\",\"label\":\"模拟机器人A\",\"brand\":\"模拟品牌A\",\"type\":1,\"ip\":\"127.0.1.1\"},{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-2\",\"label\":\"模拟机器人B\",\"brand\":\"模拟品牌A\",\"type\":2,\"ip\":\"127.0.1.2\"},{\"gid\":\"mock-robot-group-1\",\"id\":\"mock-robot-3\",\"label\":\"模拟机器人C\",\"brand\":\"模拟品牌A\",\"type\":3,\"ip\":\"127.0.1.3\"},{\"gid\":\"mock-robot-group-2\",\"id\":\"mock-robot-4\",\"label\":\"模拟机器人D\",\"brand\":\"模拟品牌B\",\"type\":1,\"ip\":\"127.0.2.1\"}]}"
},
"message": "模拟提示"
}
diff --git a/public/point/16-dark.png b/public/point/16-dark.png
new file mode 100644
index 0000000..d9d2cb0
Binary files /dev/null and b/public/point/16-dark.png differ
diff --git a/src/App.vue b/src/App.vue
index eeef236..0ac80ee 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,9 +1,6 @@
@@ -16,7 +13,7 @@ const empty = computed(() => new URL(`./assets/images/empty-${sTheme.the
>
-
+
{{ $t('暂无数据') }}
diff --git a/src/_ant.scss b/src/_ant.scss
index 5756e62..31347ab 100644
--- a/src/_ant.scss
+++ b/src/_ant.scss
@@ -55,6 +55,21 @@
&.ant-btn-sm {
padding: 0;
}
+
+ &.ant-btn-lg {
+ padding: 8px;
+ border-radius: 8px;
+ }
+ }
+ }
+
+ .ant-card {
+ background-color: get-color(sider_bg2);
+ border-radius: 8px;
+ box-shadow: 0 2px 8px 0 get-color(shadow1);
+
+ & > .ant-card-body {
+ padding: 16px;
}
}
@@ -89,6 +104,7 @@
align-items: center;
font: 400 14px/22px Roboto;
color: get-color(text2);
+ vertical-align: top;
}
.ant-collapse.ant-collapse-ghost {
@@ -136,6 +152,14 @@
}
}
+ .ant-divider {
+ border-color: get-color(border1);
+
+ &.ant-divider-vertical {
+ height: 1em;
+ }
+ }
+
.ant-dropdown-menu-root {
padding: 0;
overflow: hidden;
@@ -155,12 +179,57 @@
}
}
+ .ant-empty {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ margin: 0;
+
+ & > .ant-empty-image {
+ height: 40px;
+ margin: 0;
+ }
+
+ & > .ant-empty-description {
+ margin: 0;
+ font: 400 14px/22px Roboto;
+ color: get-color(text4);
+ }
+ }
+
.ant-flex {
& > * {
flex: none;
}
}
+ .ant-float-btn {
+ height: fit-content;
+ overflow: hidden;
+ background-color: transparent;
+ box-shadow: none !important;
+
+ &.ant-float-btn-square > .ant-badge > .ant-float-btn-body {
+ background-color: get-color(sider_bg2);
+ border-radius: 4px;
+ box-shadow: 0 1px 2px 0 get-color(shadow1);
+
+ & > .ant-float-btn-content {
+ padding: 0;
+
+ & > .ant-float-btn-icon {
+ width: auto;
+ height: auto;
+ margin: 0;
+ }
+ }
+ }
+
+ &:hover > .ant-badge > .ant-float-btn-body {
+ background-color: get-color(fill1);
+ }
+ }
+
.ant-form {
& > .ant-form-item {
margin-block-end: 8px;
@@ -297,6 +366,17 @@
}
}
+ .ant-list.block .ant-list-item {
+ padding: 12px;
+ background-color: get-color(fill4);
+ border: none;
+ border-radius: 4px;
+
+ &:not(:first-child) {
+ margin-block-start: 8px;
+ }
+ }
+
.ant-modal.ant-modal-confirm .ant-modal-content {
padding: 32px 32px 24px;
background-color: get-color(popover);
@@ -490,6 +570,8 @@
}
.ant-tabs {
+ height: 100%;
+ overflow: hidden;
border-radius: 8px;
& > .ant-tabs-nav {
@@ -531,17 +613,61 @@
}
}
+ .ant-tag {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 3px 5px;
+ margin: 0;
+ font: 500 14px/22px Roboto;
+ color: get-color(text1);
+ vertical-align: top;
+ background-color: transparent;
+ border-color: get-color(border1);
+ border-radius: 4px;
+ box-shadow: none !important;
+
+ &.ant-tag-borderless {
+ padding: 4px 8px;
+ font: 400 14px/16px Roboto;
+ color: get-color(text2);
+ background-color: get-color(fill3);
+ border: none;
+ }
+ }
+
.ant-typography {
- font: 400 14px/22px Roboto;
- color: get-color(text2);
+ font: 500 16px/22px Roboto;
+ color: get-color(text1);
+
+ &.ant-typography-secondary {
+ font: 400 14px/22px Roboto;
+ color: get-color(text2);
+ }
&.ant-typography-disabled {
+ font: 400 14px/22px Roboto;
color: get-color(text4);
}
& > strong {
- font: 500 16px/22px SourceHanSansSC;
- color: get-color(text1);
+ font: 500 16px/22px Roboto;
+ }
+
+ & > code {
+ padding: 0;
+ margin: 0;
+ font: 400 14px/22px Roboto;
+ color: get-color(text3);
+ background-color: transparent;
+ border: none;
}
}
+
+ .toolbar {
+ padding: 8px;
+ background-color: get-color(sider_bg);
+ border-radius: 8px;
+ box-shadow: 0 2px 8px 0 get-color(shadow2);
+ }
}
diff --git a/src/_icon.scss b/src/_icon.scss
index 1d46a9f..8147d16 100644
--- a/src/_icon.scss
+++ b/src/_icon.scss
@@ -4,10 +4,26 @@
@include themed {
.icon-btn {
&.panel-btn {
- color: get-color(ffffffd9);
+ color: get-color(icon);
&:disabled {
- color: get-color(ffffff2e);
+ color: get-color(icon-disabled);
+ }
+ }
+
+ &.tool-btn {
+ color: get-color(icon);
+
+ &:disabled {
+ color: get-color(icon-disabled);
+ }
+
+ &.active {
+ background-color: get-color(primary) !important;
+ }
+
+ &:not(:disabled):hover {
+ background-color: get-color(bg_layout);
}
}
}
diff --git a/src/apis/map/constant.ts b/src/apis/map/constant.ts
index f957a67..aefe14b 100644
--- a/src/apis/map/constant.ts
+++ b/src/apis/map/constant.ts
@@ -12,6 +12,7 @@ export enum MapPointType {
充电点,
停靠点,
动作点,
+ 禁行点,
障碍点 = 99,
}
diff --git a/src/apis/robot/api.ts b/src/apis/robot/api.ts
index 229b5b8..33df5f0 100644
--- a/src/apis/robot/api.ts
+++ b/src/apis/robot/api.ts
@@ -12,28 +12,38 @@ const enum API {
export async function getAllRobots(): Promise> {
type D = RobotInfo[];
- const data = await http.post(API.获取所有机器人);
- return data ?? [];
+ try {
+ const data = await http.post(API.获取所有机器人);
+ return data ?? [];
+ } catch (error) {
+ console.debug(error);
+ return [];
+ }
}
export async function registerRobot(robot: Omit): Promise {
type B = Omit;
type D = RobotInfo;
- const body = robot;
- const data = await http.post(API.注册机器人, body);
- return data ?? null;
-}
-
-export async function seizeRobotByIds(ids: Array): Promise {
- if (!ids.length) return false;
- type B = { ids: string[] };
- type D = void;
try {
- const body = { ids };
- await http.post(API.批量抢占控制权, body);
- return true;
+ const body = robot;
+ const data = await http.post(API.注册机器人, body);
+ return data ?? null;
} catch (error) {
console.debug(error);
- return false;
+ return null;
+ }
+}
+
+export async function seizeRobotByIds(ids: Array): Promise> {
+ if (!ids.length) return [];
+ type B = { ids: string[] };
+ type D = string[];
+ try {
+ const body = { ids };
+ const data = await http.post(API.批量抢占控制权, body);
+ return data ?? [];
+ } catch (error) {
+ console.debug(error);
+ return [];
}
}
diff --git a/src/apis/robot/constant.ts b/src/apis/robot/constant.ts
index 19ed990..da29310 100644
--- a/src/apis/robot/constant.ts
+++ b/src/apis/robot/constant.ts
@@ -15,8 +15,8 @@ export enum RobotType {
export const ROBOT_TYPE_OPTIONS = >Object.entries(RobotType).filter(([, v]) => isNumber(v));
export enum RobotState {
- '任务执行中' = 1,
- '充电中',
- '停靠中',
- '故障中',
+ 任务执行中 = 1,
+ 充电中,
+ 停靠中,
+ 空闲中,
}
diff --git a/src/assets/icons/_icon.scss b/src/assets/icons/_icon.scss
index 51a6034..6c12269 100644
--- a/src/assets/icons/_icon.scss
+++ b/src/assets/icons/_icon.scss
@@ -1 +1,28 @@
-$icons: (control, dot, dropdown, edit, exit, pen, plus, register, trash_fill, trash);
+$icons: (
+ area1-active,
+ area1,
+ area2-active,
+ area2,
+ area3-active,
+ area3,
+ battery_charge,
+ battery,
+ connect_off,
+ connect_on,
+ control,
+ detail,
+ dot,
+ dropdown,
+ edit,
+ exit,
+ pen,
+ plus,
+ redo,
+ register,
+ robot,
+ save,
+ search,
+ trash_fill,
+ trash,
+ undo
+);
diff --git a/src/assets/icons/dark/area1-active.png b/src/assets/icons/dark/area1-active.png
new file mode 100644
index 0000000..c6dbdfd
Binary files /dev/null and b/src/assets/icons/dark/area1-active.png differ
diff --git a/src/assets/icons/dark/area1.png b/src/assets/icons/dark/area1.png
new file mode 100644
index 0000000..7e28911
Binary files /dev/null and b/src/assets/icons/dark/area1.png differ
diff --git a/src/assets/icons/dark/area2-active.png b/src/assets/icons/dark/area2-active.png
new file mode 100644
index 0000000..f502758
Binary files /dev/null and b/src/assets/icons/dark/area2-active.png differ
diff --git a/src/assets/icons/dark/area2.png b/src/assets/icons/dark/area2.png
new file mode 100644
index 0000000..550c758
Binary files /dev/null and b/src/assets/icons/dark/area2.png differ
diff --git a/src/assets/icons/dark/area3-active.png b/src/assets/icons/dark/area3-active.png
new file mode 100644
index 0000000..dab86ea
Binary files /dev/null and b/src/assets/icons/dark/area3-active.png differ
diff --git a/src/assets/icons/dark/area3.png b/src/assets/icons/dark/area3.png
new file mode 100644
index 0000000..bfdd994
Binary files /dev/null and b/src/assets/icons/dark/area3.png differ
diff --git a/src/assets/icons/dark/battery.png b/src/assets/icons/dark/battery.png
new file mode 100644
index 0000000..09f0fe3
Binary files /dev/null and b/src/assets/icons/dark/battery.png differ
diff --git a/src/assets/icons/dark/battery_charge.png b/src/assets/icons/dark/battery_charge.png
new file mode 100644
index 0000000..91a9314
Binary files /dev/null and b/src/assets/icons/dark/battery_charge.png differ
diff --git a/src/assets/icons/dark/connect_off.png b/src/assets/icons/dark/connect_off.png
new file mode 100644
index 0000000..6d3c6b5
Binary files /dev/null and b/src/assets/icons/dark/connect_off.png differ
diff --git a/src/assets/icons/dark/connect_on.png b/src/assets/icons/dark/connect_on.png
new file mode 100644
index 0000000..b38e26d
Binary files /dev/null and b/src/assets/icons/dark/connect_on.png differ
diff --git a/src/assets/icons/dark/detail.png b/src/assets/icons/dark/detail.png
new file mode 100644
index 0000000..f196c87
Binary files /dev/null and b/src/assets/icons/dark/detail.png differ
diff --git a/src/assets/icons/dark/redo.png b/src/assets/icons/dark/redo.png
new file mode 100644
index 0000000..9eef61b
Binary files /dev/null and b/src/assets/icons/dark/redo.png differ
diff --git a/src/assets/icons/dark/robot.png b/src/assets/icons/dark/robot.png
new file mode 100644
index 0000000..1c3a37c
Binary files /dev/null and b/src/assets/icons/dark/robot.png differ
diff --git a/src/assets/icons/dark/save.png b/src/assets/icons/dark/save.png
new file mode 100644
index 0000000..5878ca9
Binary files /dev/null and b/src/assets/icons/dark/save.png differ
diff --git a/src/assets/icons/dark/search.png b/src/assets/icons/dark/search.png
new file mode 100644
index 0000000..65bc629
Binary files /dev/null and b/src/assets/icons/dark/search.png differ
diff --git a/src/assets/icons/dark/undo.png b/src/assets/icons/dark/undo.png
new file mode 100644
index 0000000..bf41809
Binary files /dev/null and b/src/assets/icons/dark/undo.png differ
diff --git a/src/components/card/robot-detail-card.vue b/src/components/card/robot-detail-card.vue
new file mode 100644
index 0000000..24fec2a
--- /dev/null
+++ b/src/components/card/robot-detail-card.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t(RobotType[robot.type]) }}
+
+
+
+
+ {{ robot.ip }}
+
+
+
+
+
+
+ {{ $t('已连接') }}
+
+
+
+ {{ $t('未连接') }}
+
+
+
+
+ {{ robot.battery ?? 0 }}%
+
+
+
+
+ {{ $t(RobotState[robot.state]) }}
+
+
+
+
+
+
+
+ {{ $t('接单状态') }}
+ {{ $t(robot.canOrder ? '接单' : '不可接单') }}
+
+
+ {{ $t('急停状态') }}
+ {{ $t(robot.canStop ? '是' : '否') }}
+
+
+ {{ $t('控制权') }}
+ {{ $t(robot.canControl ? '已抢占' : '当前无控制权') }}
+
+
+
+
+
+
+
+
diff --git a/src/components/editor-toolbar.vue b/src/components/editor-toolbar.vue
new file mode 100644
index 0000000..cd21161
--- /dev/null
+++ b/src/components/editor-toolbar.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/modal/robot-add-modal.vue b/src/components/modal/robot-add-modal.vue
index 6a8a33a..ec7892d 100644
--- a/src/components/modal/robot-add-modal.vue
+++ b/src/components/modal/robot-add-modal.vue
@@ -56,7 +56,9 @@ const submit = () => {
-
+
+
+
+import { type MapPen, MapPointType } from '@api/map';
+import type { EditorService } from '@core/editor.service';
+import { computed, inject, type InjectionKey, ref, type ShallowRef } from 'vue';
+
+type Props = {
+ token: InjectionKey>;
+ current?: string;
+};
+const props = defineProps();
+const editor = inject(props.token)!;
+
+const keyword = ref('');
+
+//#region 点位列表
+const points = computed(() =>
+ editor.value.points.value.filter(({ label }) => label?.includes(keyword.value)),
+);
+//#endregion
+
+//#region 线路列表
+//#endregion
+
+//#region 区域列表
+//#endregion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
diff --git a/src/components/robot-groups.vue b/src/components/robot-groups.vue
index e15c3de..2113510 100644
--- a/src/components/robot-groups.vue
+++ b/src/components/robot-groups.vue
@@ -1,11 +1,12 @@
@@ -69,16 +112,30 @@ const toDeleteGroup = (id: RobotGroup['id']) =>
-
+
+
+
{{ $t('全选') }}
-
+
-
+
@@ -88,10 +145,11 @@ const toDeleteGroup = (id: RobotGroup['id']) =>
-
+
+
-
+
@@ -124,7 +182,20 @@ const toDeleteGroup = (id: RobotGroup['id']) =>
-
+
+
+
+
+ {{ label }}
+
+
+
+
style="height: 36px"
@click="emit('change', item.id)"
>
-
- {{ item.label }}
+
+
+ {{ item.label }}
+
@@ -146,9 +224,3 @@ const toDeleteGroup = (id: RobotGroup['id']) =>
-
-
diff --git a/src/components/test-2.vue b/src/components/test-2.vue
new file mode 100644
index 0000000..c5f0eae
--- /dev/null
+++ b/src/components/test-2.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/scene-editor.vue b/src/pages/scene-editor.vue
index 234cc65..81f42bb 100644
--- a/src/pages/scene-editor.vue
+++ b/src/pages/scene-editor.vue
@@ -1,7 +1,7 @@
- {{ title }}
+ {{ title }}
@@ -56,25 +80,27 @@ const current = ref();
{{ $t('推送') }}
{{ $t('导入') }}
- {{ $t('导出') }}
+ {{ $t('导出') }}
-
+
Content of Tab Pane 2
- Content of Tab Pane 3
+
+
+
@@ -82,10 +108,45 @@ const current = ref();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/services/editor.service.ts b/src/services/editor.service.ts
index e25fd3f..66b65de 100644
--- a/src/services/editor.service.ts
+++ b/src/services/editor.service.ts
@@ -2,28 +2,35 @@ import { EDITOR_CONFIG, MapAreaType, type MapPen, MapPointType } from '@api/map'
import type { RobotGroup, RobotInfo } from '@api/robot';
import type { SceneData } from '@api/scene';
import sTheme from '@core/theme.service';
-import { CanvasLayer, EditType, LockState, Meta2d, s8 } from '@meta2d/core';
+import { CanvasLayer, EditType, LockState, Meta2d, type Pen, s8 } from '@meta2d/core';
import { useObservable } from '@vueuse/rxjs';
-import { clone, cloneDeep, get, isNil, pick, remove, some } from 'lodash-es';
+import { clone, cloneDeep, get, isNil, isString, pick, remove, some } from 'lodash-es';
import { BehaviorSubject, debounceTime, filter, map, Subject, switchMap } from 'rxjs';
-import { watch } from 'vue';
+import { reactive, watch } from 'vue';
export type Point = Record<'x' | 'y', number>;
export class EditorService extends Meta2d {
- public load(map?: string, readonly = false): void {
+ public async load(map?: string, editable = false): Promise {
const data = map ? JSON.parse(map) : undefined;
this.open(data);
- this.setState(readonly);
+ this.setState(editable);
}
public save(): string {
const data = this.data();
- const map = JSON.stringify(data);
- return map;
+ return JSON.stringify(data);
}
- public export(): string {
- const png = this.toPng(10);
- return png;
+ public export(): void {
+ const json = this.save();
+ console.log(json);
+ }
+
+ public setState(editable?: boolean): void {
+ this.lock(editable ? LockState.None : LockState.Disable);
+ }
+
+ public override data(): SceneData {
+ return super.data();
}
readonly #mouse$$ = new Subject<{ type: 'click' | 'mousedown' | 'mouseup'; value: Point }>();
@@ -46,19 +53,8 @@ export class EditorService extends Meta2d {
),
);
- public override data(): SceneData {
- return super.data();
- }
- public override find(target: string): MapPen[] {
- return super.find(target);
- }
-
- public setState(readonly?: boolean): void {
- this.lock(readonly ? LockState.Disable : LockState.None);
- }
-
//#region 机器人
- readonly #robotMap = new Map();
+ readonly #robotMap = reactive