From ec2e79e0d510568d51714a7121e4a32c026e6d44 Mon Sep 17 00:00:00 2001
From: Junjie <xjj@123>
Date: 星期二, 19 三月 2024 14:02:52 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/entity/MapItem.java | 28 +
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/service/MapService.java | 37 +
zy-asrs-flow/package.json | 2
zy-asrs-flow/src/pages/map/index.css | 23
zy-asrs-flow/src/locales/en-US/map.ts | 30 +
zy-asrs-flow/src/components/RightContent/AvatarDropdown.jsx | 5
zy-asrs-flow/src/pages/map/header/search.jsx | 164 ++++++
zy-asrs-flow/public/img/map/point.svg | 3
zy-asrs-flow/public/favicon.jpg | 0
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/param/MapDataParam.java | 16
zy-asrs-flow/src/pages/map/drawer/shelf/index.jsx | 60 ++
zy-asrs-flow/src/pages/map/index.jsx | 200 +++++--
zy-asrs-flow/src/config/setting.ts | 2
zy-asrs-flow/src/pages/map/drawer/agv/index.jsx | 60 ++
zy-asrs-flow/config/config.ts | 6
zy-asrs-flow/src/pages/map/components/settings.jsx | 2
zy-asrs-flow/src/pages/map/components/configSettings.jsx | 128 ++++
zy-asrs-flow/src/pages/map/components/mapSettings.jsx | 40 +
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/MapController.java | 38 +
zy-asrs-flow/src/App.jsx | 4
zy-asrs-flow/src/pages/map/drawer/index.jsx | 52 +
zy-asrs-flow/src/pages/map/drawer/point/index.jsx | 60 ++
zy-asrs-flow/src/locales/en-US.ts | 5
zy-asrs-flow/src/pages/map/player.js | 91 ++
zy-asrs-flow/src/pages/map/components/mapCopySettings.jsx | 166 +++++
zy-asrs-flow/src/pages/map/components/device.jsx | 94 ++-
zy-asrs-flow/src/pages/map/drawer/showJson.jsx | 56 ++
zy-asrs-flow/src/pages/map/utils.js | 204 +++++++
28 files changed, 1,407 insertions(+), 169 deletions(-)
diff --git a/zy-asrs-flow/config/config.ts b/zy-asrs-flow/config/config.ts
index 7decf08..fd287f1 100644
--- a/zy-asrs-flow/config/config.ts
+++ b/zy-asrs-flow/config/config.ts
@@ -76,7 +76,7 @@
* @name layout 鎻掍欢
* @doc https://umijs.org/docs/max/layout-menu
*/
- title: 'Ant Design Pro',
+ title: 'zy-asrs-wcs',
layout: {
locale: true,
...defaultSettings,
@@ -153,4 +153,8 @@
},
esbuildMinifyIIFE: true,
requestRecord: {},
+ // title logo
+ favicons: [
+ '/favicon.jpg'
+ ]
});
diff --git a/zy-asrs-flow/package.json b/zy-asrs-flow/package.json
index f8dba02..708a4ae 100644
--- a/zy-asrs-flow/package.json
+++ b/zy-asrs-flow/package.json
@@ -1,5 +1,5 @@
{
- "name": "ant-design-pro",
+ "name": "zy-asrs-wcs",
"version": "6.0.0",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
diff --git a/zy-asrs-flow/public/favicon.jpg b/zy-asrs-flow/public/favicon.jpg
new file mode 100644
index 0000000..403da8f
--- /dev/null
+++ b/zy-asrs-flow/public/favicon.jpg
Binary files differ
diff --git a/zy-asrs-flow/public/img/map/point.svg b/zy-asrs-flow/public/img/map/point.svg
new file mode 100644
index 0000000..e042908
--- /dev/null
+++ b/zy-asrs-flow/public/img/map/point.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15" height="15" viewBox="0 0 15 15">
+ <image id="鍥惧眰_1" data-name="鍥惧眰 1" width="15" height="15" xlink:href="data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAA4ElEQVQokZ3TvUoDQRgF0OMiiqA2NmJlG0xjIWKR1spSES20SpNXMo02Kr6B4BOIAf9rO8FSJdrJJzOwSiDJ3G7hHtjduTPRvXpRyxR2sYMm5vGOB1zgHN+5PlmDKzjChr9ZwDK20EEb99GoUq2BywHwf9ZTr5nxNI6xNATmLOIEM4G3sTYizFmNfxN4f0yYs1fl9y9II/BcIZ6t0jmW5DPwYyF+CnxaiM8Cx+x6Y8LbjL9wiNcR4RsO0M/zjOFv4noIvEm9u3ioX4wYeyuNJm5V7D2O8QPP6fPi//R/2/gBn1UmkhfMfDoAAAAASUVORK5CYII="/>
+</svg>
diff --git a/zy-asrs-flow/src/App.jsx b/zy-asrs-flow/src/App.jsx
index 9283200..84866e2 100644
--- a/zy-asrs-flow/src/App.jsx
+++ b/zy-asrs-flow/src/App.jsx
@@ -8,7 +8,7 @@
import { getRemoteMenu, getRoutersInfo, getUserInfo, setRemoteMenu, patchRouteWithRemoteMenus } from './services/route';
import { getToken, setToken } from '@/utils/token-util'
import { TOKEN_HEADER_NAME, TOKEN_STORE_NAME } from '@/config/setting';
-import { API_BASE_URL } from '@/config/setting'
+import { API_BASE_URL, API_TIMEOUT } from '@/config/setting'
import { message } from 'antd';
import logo from '../public/img/logo.png'
@@ -231,7 +231,7 @@
export const request = {
baseURL: API_BASE_URL,
...errorConfig,
- timeout: 60000,
+ timeout: API_TIMEOUT * 1000,
// 鍓嶇疆瀹堝崼
requestInterceptors: [
(url, options) => {
diff --git a/zy-asrs-flow/src/components/RightContent/AvatarDropdown.jsx b/zy-asrs-flow/src/components/RightContent/AvatarDropdown.jsx
index 9f1889b..fef5588 100644
--- a/zy-asrs-flow/src/components/RightContent/AvatarDropdown.jsx
+++ b/zy-asrs-flow/src/components/RightContent/AvatarDropdown.jsx
@@ -1,6 +1,6 @@
import { outLogin } from '@/services/ant-design-pro/api';
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
-import { history, useModel } from '@umijs/max';
+import { history, useModel, FormattedMessage, useIntl } from '@umijs/max';
import { Spin } from 'antd';
import { createStyles } from 'antd-style';
import { stringify } from 'querystring';
@@ -35,6 +35,7 @@
};
export const AvatarDropdown = ({ menu, children }) => {
+ const intl = useIntl();
const { styles } = useStyles();
const { initialState, setInitialState } = useModel('@@initialState');
@@ -116,7 +117,7 @@
{
key: 'logout',
icon: <LogoutOutlined />,
- label: '閫�鍑虹櫥褰�',
+ label: intl.formatMessage({ id: 'common.account.logout', defaultMessage: '閫�鍑虹櫥褰�' }),
},
];
diff --git a/zy-asrs-flow/src/config/setting.ts b/zy-asrs-flow/src/config/setting.ts
index 32a86f4..0d5a234 100644
--- a/zy-asrs-flow/src/config/setting.ts
+++ b/zy-asrs-flow/src/config/setting.ts
@@ -1,6 +1,8 @@
// 鎺ュ彛鍦板潃
export const API_BASE_URL: string = 'http://127.0.0.1:9090/wcs';
+export const API_TIMEOUT: number = 60;
+
// 椤圭洰鍚嶇О
export const PROJECT_NAME: string = 'admin';
diff --git a/zy-asrs-flow/src/locales/en-US.ts b/zy-asrs-flow/src/locales/en-US.ts
index 7e1627b..61f4e4e 100644
--- a/zy-asrs-flow/src/locales/en-US.ts
+++ b/zy-asrs-flow/src/locales/en-US.ts
@@ -19,6 +19,11 @@
'common.idcard':'ID Number',
'common.introduction':'Introduction',
'common.execute':'Execute',
+ 'common.success':'Success',
+ 'common.fail':'Fail',
+ 'common.account.logout': 'Logout',
+ 'common.search.placeholder': 'Please enter search content',
+ 'common.loading.api.message': 'Calling Server...',
'':'',
'':'',
'':'',
diff --git a/zy-asrs-flow/src/locales/en-US/map.ts b/zy-asrs-flow/src/locales/en-US/map.ts
index b14533a..4048b88 100644
--- a/zy-asrs-flow/src/locales/en-US/map.ts
+++ b/zy-asrs-flow/src/locales/en-US/map.ts
@@ -5,6 +5,20 @@
'map.device.oper': 'Device Settings',
'map.model.observer': 'Observer Pattern',
'map.model.editor': 'Editor Pattern',
+ 'map.save': 'Save Map',
+ 'map.load': 'Load Map',
+ 'map.clear': 'Clear Map',
+ '': '',
+ '': '',
+ '': '',
+ '': '',
+ 'map.sensor.type.shelf': 'Shelf',
+ 'map.sensor.type.agv': 'Agv',
+ 'map.sensor.type.point': 'Point',
+ '': '',
+ '': '',
+ '': '',
+ 'map.drawer.json': 'JSON',
'': '',
'': '',
'': '',
@@ -30,9 +44,16 @@
'map.settings.config.param': 'Config Parameters',
'': '',
'': '',
+ 'map.settings.no': 'No.',
'map.settings.shelf.no': 'Shelf No',
'map.settings.shelf.row': 'Row',
'map.settings.shelf.bay': 'Bay',
+ '': '',
+ '': '',
+ '': '',
+ '': '',
+ 'map.settings.point.horizontal': 'Horizontal',
+ 'map.settings.point.vertical': 'Vertical',
'': '',
'': '',
'': '',
@@ -45,6 +66,15 @@
'map.settings.sub.copy.count': 'Count',
'map.settings.sub.copy.gap': 'Gap',
'map.settings.sub.copy.id': 'ID',
+ 'map.settings.sub.copy.shelf.auto-increment': 'Auto Increment',
+ 'map.settings.sub.copy.shelf.increment-value': 'Increment Value',
+ 'map.settings.sub.copy.increment.mode': 'Increment Mode',
+ 'map.settings.sub.copy.ascend': 'Ascending',
+ 'map.settings.sub.copy.descend': 'Descending',
+ '': '',
+ '': '',
+ '': '',
+ 'map.settings.sub.copy.warn.config.shelf': 'Please set the shelf parameters first!',
'': '',
'': '',
'': '',
diff --git a/zy-asrs-flow/src/pages/map/components/configSettings.jsx b/zy-asrs-flow/src/pages/map/components/configSettings.jsx
index 7a6a67a..01697ee 100644
--- a/zy-asrs-flow/src/pages/map/components/configSettings.jsx
+++ b/zy-asrs-flow/src/pages/map/components/configSettings.jsx
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
-import { Col, Form, Input, Row, Checkbox, Slider, Select, Drawer, Space, Button, InputNumber, Card } from 'antd';
+import { message, Form, Input, Row, Checkbox, Slider, Select, Drawer, Space, Button, InputNumber, Card } from 'antd';
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
import { createStyles } from 'antd-style';
import * as Utils from '../utils'
@@ -15,7 +15,17 @@
const { curSprite, configForm: form } = props;
useEffect(() => {
- }, []);
+ form.resetFields();
+ if (curSprite) {
+ form.setFieldsValue({
+
+ // shelf
+ row: curSprite?.data?.row,
+ bay: curSprite?.data?.bay,
+ no: curSprite?.data?.no,
+ })
+ }
+ }, [props, form]);
const formValuesChange = (changeList) => {
if (curSprite && changeList && changeList.length > 0) {
@@ -27,11 +37,11 @@
const bay = form.getFieldValue('bay')
if (value && bay) {
form.setFieldsValue({
- shelfNo: Utils.pureNumStr(value) + '-' + Utils.pureNumStr(bay)
+ no: Utils.pureNumStr(value) + '-' + Utils.pureNumStr(bay)
});
} else {
form.setFieldsValue({
- shelfNo: ''
+ no: ''
});
}
break;
@@ -39,11 +49,35 @@
const row = form.getFieldValue('row')
if (value && row) {
form.setFieldsValue({
- shelfNo: Utils.pureNumStr(row) + '-' + Utils.pureNumStr(value)
+ no: Utils.pureNumStr(row) + '-' + Utils.pureNumStr(value)
});
} else {
form.setFieldsValue({
- shelfNo: ''
+ no: ''
+ });
+ }
+ break;
+ case 'vertical':
+ const horizontal = form.getFieldValue('horizontal')
+ if (value && horizontal) {
+ form.setFieldsValue({
+ no: Utils.pureNumStr(value) + '-' + Utils.pureNumStr(horizontal)
+ });
+ } else {
+ form.setFieldsValue({
+ no: ''
+ });
+ }
+ break;
+ case 'horizontal':
+ const vertical = form.getFieldValue('vertical')
+ if (value && vertical) {
+ form.setFieldsValue({
+ no: Utils.pureNumStr(vertical) + '-' + Utils.pureNumStr(value)
+ });
+ } else {
+ form.setFieldsValue({
+ no: ''
});
}
break;
@@ -60,8 +94,32 @@
const onFinishFailed = (errorInfo) => {
};
- const handleFinish = async (values) => {
- props.onSubmit({ ...values });
+ const handleFinish = (values) => {
+ // execute where the form was finished
+ const confirmSettings = () => {
+ if (curSprite && curSprite?.data?.type) {
+ switch (curSprite.data.type) {
+ case Utils.SENSOR_TYPE.SHELF:
+ curSprite.data.no = values.no; // *
+ curSprite.data.row = values.row;
+ curSprite.data.bay = values.bay;
+ break;
+ case Utils.SENSOR_TYPE.POINT:
+ curSprite.data.no = values.no; // *
+ curSprite.data.horizontal = values.horizontal;
+ curSprite.data.vertical = values.vertical;
+ break;
+ case Utils.SENSOR_TYPE.AGV:
+ curSprite.data.no = values.no; // *
+ break;
+ default:
+ break;
+ }
+ }
+ message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '鎿嶄綔鎴愬姛' }));
+ }
+
+ props.onSubmit({ ...values }, confirmSettings);
}
return (
@@ -90,14 +148,14 @@
}}
>
<br />
-
+
<Form.Item
label={intl.formatMessage({ id: 'map.settings.type', defaultMessage: '绫诲瀷' })}
>
<span>{curSprite?.data?.type}</span>
</Form.Item>
<Form.Item
- label={intl.formatMessage({ id: 'map.settings.uuid', defaultMessage: '缂栧彿' })}
+ label={intl.formatMessage({ id: 'map.settings.uuid', defaultMessage: '鍦板浘鍙�' })}
>
<span>{curSprite?.data?.uuid}</span>
</Form.Item>
@@ -115,7 +173,7 @@
label={intl.formatMessage({ id: 'map.settings.shelf.row', defaultMessage: '鎺�' })}
rules={[
{
- required: true,
+ required: false,
},
]}
>
@@ -130,7 +188,27 @@
label={intl.formatMessage({ id: 'map.settings.shelf.bay', defaultMessage: '鍒�' })}
rules={[
{
- required: true,
+ required: false,
+ },
+ ]}
+ >
+ <InputNumber
+ style={{
+ width: '50%',
+ }}
+ />
+ </Form.Item>
+ </>
+ )}
+
+ {curSprite?.data?.type === Utils.SENSOR_TYPE.POINT && (
+ <>
+ <Form.Item
+ name='vertical'
+ label={intl.formatMessage({ id: 'map.settings.point.vertical', defaultMessage: '绾靛悜' })}
+ rules={[
+ {
+ required: false,
},
]}
>
@@ -141,15 +219,15 @@
/>
</Form.Item>
<Form.Item
- name='shelfNo'
- label={intl.formatMessage({ id: 'map.settings.shelf.no', defaultMessage: '璐ф灦鍙�' })}
+ name='horizontal'
+ label={intl.formatMessage({ id: 'map.settings.point.horizontal', defaultMessage: '妯悜' })}
rules={[
{
- required: true,
+ required: false,
},
]}
>
- <Input
+ <InputNumber
style={{
width: '50%',
}}
@@ -159,11 +237,27 @@
)}
<Form.Item
+ name='no'
+ label={intl.formatMessage({ id: 'map.settings.no', defaultMessage: '缂栧彿' })}
+ rules={[
+ {
+ required: false,
+ },
+ ]}
+ >
+ <Input
+ style={{
+ width: '50%',
+ }}
+ />
+ </Form.Item>
+
+ <Form.Item
wrapperCol={{
offset: 4,
span: 16,
}}>
- <Button type="primary" onClick={handleFinish}>
+ <Button type="primary" htmlType="submit">
<FormattedMessage id='common.submit' defaultMessage='淇濆瓨' />
</Button>
</Form.Item>
diff --git a/zy-asrs-flow/src/pages/map/components/device.jsx b/zy-asrs-flow/src/pages/map/components/device.jsx
index 72a6818..18477fd 100644
--- a/zy-asrs-flow/src/pages/map/components/device.jsx
+++ b/zy-asrs-flow/src/pages/map/components/device.jsx
@@ -37,9 +37,10 @@
import agv from '/public/img/map/agv.svg'
import shelf from '/public/img/map/shelf.png'
-import { Util } from '@antv/g6';
+import point from '/public/img/map/point.svg'
const Device = (props) => {
+ const intl = useIntl();
const { styles } = useStyles();
const [dragging, setDragging] = useState(false);
const [dragSprite, setDragSprite] = useState(null);
@@ -75,6 +76,9 @@
rootStyle={{ position: "absolute" }}
mask={false}
width={378}
+ style={{
+ opacity: .8
+ }}
extra={
<Space>
<Button onClick={() => props.onCancel()}><FormattedMessage id='common.cancel' defaultMessage='鍙栨秷' /></Button>
@@ -90,7 +94,9 @@
draggable="true"
onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.AGV)}
/>
- <div className={styles.title}>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.agv' defaultMessage='鏃犱汉灏忚溅' />
+ </div>
</Col>
<Col className={styles.mapCol} span={8} >
<Image
@@ -100,17 +106,23 @@
draggable="true"
onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.SHELF)}
/>
- <div className={styles.title}>SHELF</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.shelf' defaultMessage='璐ф灦' />
+ </div>
</Col>
- <Col className={styles.mapCol} span={8} >
+ <Col className={styles.mapCol} span={8}>
<Image
- src={agv}
+ src={point}
+ style={{
+ }}
width='50px'
preview={false}
draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.POINT)}
/>
- <div>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.point' defaultMessage='瀹氫綅鐐�' />
+ </div>
</Col>
</Row>
<Row className={styles.mapRow}>
@@ -120,9 +132,23 @@
width='50px'
preview={false}
draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.AGV)}
/>
- <div>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.agv' defaultMessage='鏃犱汉灏忚溅' />
+ </div>
+ </Col>
+ <Col className={styles.mapCol} span={8} >
+ <Image
+ src={shelf}
+ width='35px'
+ preview={false}
+ draggable="true"
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.SHELF)}
+ />
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.shelf' defaultMessage='璐ф灦' />
+ </div>
</Col>
<Col className={styles.mapCol} span={8} >
<Image
@@ -130,19 +156,11 @@
width='50px'
preview={false}
draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.AGV)}
/>
- <div>AGV</div>
- </Col>
- <Col className={styles.mapCol} span={8} >
- <Image
- src={agv}
- width='50px'
- preview={false}
- draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
- />
- <div>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.agv' defaultMessage='鏃犱汉灏忚溅' />
+ </div>
</Col>
</Row>
<Row className={styles.mapRow}>
@@ -152,9 +170,23 @@
width='50px'
preview={false}
draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.AGV)}
/>
- <div>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.agv' defaultMessage='鏃犱汉灏忚溅' />
+ </div>
+ </Col>
+ <Col className={styles.mapCol} span={8} >
+ <Image
+ src={shelf}
+ width='35px'
+ preview={false}
+ draggable="true"
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.SHELF)}
+ />
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.shelf' defaultMessage='璐ф灦' />
+ </div>
</Col>
<Col className={styles.mapCol} span={8} >
<Image
@@ -162,19 +194,11 @@
width='50px'
preview={false}
draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
+ onDragStart={(e) => onDragStart(e, Utils.SENSOR_TYPE.AGV)}
/>
- <div>AGV</div>
- </Col>
- <Col className={styles.mapCol} span={8} >
- <Image
- src={agv}
- width='50px'
- preview={false}
- draggable="true"
- onDragStart={(e) => onDragStart(e, 'AGV')}
- />
- <div>AGV</div>
+ <div className={styles.title}>
+ <FormattedMessage id='map.sensor.type.agv' defaultMessage='鏃犱汉灏忚溅' />
+ </div>
</Col>
</Row>
</Drawer>
diff --git a/zy-asrs-flow/src/pages/map/components/mapCopySettings.jsx b/zy-asrs-flow/src/pages/map/components/mapCopySettings.jsx
index e2af697..1ebb8ac 100644
--- a/zy-asrs-flow/src/pages/map/components/mapCopySettings.jsx
+++ b/zy-asrs-flow/src/pages/map/components/mapCopySettings.jsx
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
-import { Col, Form, Input, Row, Checkbox, Slider, Select, Drawer, Space, Button, InputNumber, Switch } from 'antd';
+import { Col, Form, Input, Row, Switch, Slider, message, Drawer, Space, Button, InputNumber, Segmented } from 'antd';
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
import { createStyles } from 'antd-style';
import * as Utils from '../utils'
@@ -14,16 +14,36 @@
const { styles } = useStyles();
const { curSprite } = props;
const [form] = Form.useForm();
+ const [autoIncrement, setAutoIncrement] = useState(false);
+ const [autoIncrementError, setAutoIncrementError] = useState(null);
useEffect(() => {
+ setAutoIncrement(false);
form.resetFields();
if (curSprite && props) {
form.setFieldsValue({
...props.values,
- copyGap: 0
});
}
}, [form, props]);
+
+ useEffect(() => {
+ if (autoIncrement === true && curSprite) {
+ switch (curSprite.data?.type) {
+ case Utils.SENSOR_TYPE.SHELF:
+ if (!curSprite.data?.row || !curSprite.data?.bay) {
+ setAutoIncrementError(intl.formatMessage({ id: 'map.settings.sub.copy.warn.config.shelf', defaultMessage: '璇峰厛璁剧疆璐ф灦鍙傛暟锛�' }));
+ } else {
+ setAutoIncrementError(null);
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ setAutoIncrementError(null);
+ }
+ }, [autoIncrement])
const handleCancel = () => {
props.onClose();
@@ -34,11 +54,12 @@
}
const handleFinish = (values) => {
- props.submit({ ...values, ...props.values })
- }
-
- const formValuesChange = () => {
-
+ props.submit({
+ ...values
+ , ...props.values
+ , autoIncrement: autoIncrement
+ , type: curSprite?.data?.type
+ })
}
return (
@@ -64,8 +85,10 @@
>
<Form
form={form}
- onFieldsChange={formValuesChange}
initialValues={{
+ copyGap: 0,
+ autoIncrement: false,
+ incrementMode: 'ascending',
}}
onFinish={handleFinish}
autoComplete="off"
@@ -108,26 +131,121 @@
style={{
width: '60%',
}}
- // min={0}
+ // min={0}
/>
</Form.Item>
</Col>
- {curSprite?.data?.type === 'AGV' && (
- <Col span={24}>
- <Form.Item
- name='id'
- label={intl.formatMessage({ id: 'map.settings.sub.copy.id', defaultMessage: '搴忓彿' })}
- labelCol={{ span: 8 }}
- >
- <InputNumber
- style={{
- width: '60%',
- }}
- min={0}
- />
- </Form.Item>
- </Col>
+ {/* switch auto increment */}
+ <Col span={24}>
+ <Form.Item
+ label={intl.formatMessage({ id: 'map.settings.sub.copy.shelf.auto-increment', defaultMessage: '鑷闀�' })}
+ labelCol={{ span: 8 }}
+ help={autoIncrementError}
+ validateStatus={autoIncrementError ? "error" : null}
+ >
+ <Switch value={autoIncrement} onChange={setAutoIncrement} />
+ </Form.Item>
+ </Col>
+
+ {autoIncrement && curSprite?.data?.type === Utils.SENSOR_TYPE.AGV && (
+ <>
+ <Col span={24}>
+ <Form.Item
+ name='incrementValue'
+ label={intl.formatMessage({ id: 'map.settings.sub.copy.shelf.increment-value', defaultMessage: '鑷闀垮��' })}
+ labelCol={{ span: 8 }}
+ initialValue='no'
+ >
+ <Segmented
+ block
+ options={[
+ {
+ label: intl.formatMessage({ id: 'map.settings.no', defaultMessage: '缂栧彿' }),
+ value: 'no'
+ },
+ ]}
+ onChange={(value) => {
+ }}
+ />
+ </Form.Item>
+ </Col>
+ <Col span={24}>
+ <Form.Item
+ name='incrementMode'
+ label={intl.formatMessage({ id: 'map.settings.sub.copy.increment.mode', defaultMessage: '澧為暱鏂瑰紡' })}
+ labelCol={{ span: 8 }}
+ >
+ <Segmented
+ block
+ options={[
+ {
+ label: intl.formatMessage({ id: 'map.settings.sub.copy.ascend', defaultMessage: '鍗囧簭' }),
+ value: 'ascending'
+ },
+ {
+ label: intl.formatMessage({ id: 'map.settings.sub.copy.descend', defaultMessage: '闄嶅簭' }),
+ value: 'descending'
+ },
+ ]}
+ onChange={(value) => {
+ }}
+ />
+ </Form.Item>
+ </Col>
+ </>
+ )}
+
+ {autoIncrement && curSprite?.data?.type === Utils.SENSOR_TYPE.SHELF && (
+ <>
+ <Col span={24}>
+ <Form.Item
+ name='incrementValue'
+ label={intl.formatMessage({ id: 'map.settings.sub.copy.shelf.increment-value', defaultMessage: '鑷闀垮��' })}
+ labelCol={{ span: 8 }}
+ initialValue='row'
+ >
+ <Segmented
+ block
+ options={[
+ {
+ label: intl.formatMessage({ id: 'map.settings.shelf.row', defaultMessage: '鎺�' }),
+ value: 'row'
+ },
+ {
+ label: intl.formatMessage({ id: 'map.settings.shelf.bay', defaultMessage: '鍒�' }),
+ value: 'bay'
+ },
+ ]}
+ onChange={(value) => {
+ }}
+ />
+ </Form.Item>
+ </Col>
+ <Col span={24}>
+ <Form.Item
+ name='incrementMode'
+ label={intl.formatMessage({ id: 'map.settings.sub.copy.increment.mode', defaultMessage: '澧為暱鏂瑰紡' })}
+ labelCol={{ span: 8 }}
+ >
+ <Segmented
+ block
+ options={[
+ {
+ label: intl.formatMessage({ id: 'map.settings.sub.copy.ascend', defaultMessage: '鍗囧簭' }),
+ value: 'ascending'
+ },
+ {
+ label: intl.formatMessage({ id: 'map.settings.sub.copy.descend', defaultMessage: '闄嶅簭' }),
+ value: 'descending'
+ },
+ ]}
+ onChange={(value) => {
+ }}
+ />
+ </Form.Item>
+ </Col>
+ </>
)}
</Row>
diff --git a/zy-asrs-flow/src/pages/map/components/mapSettings.jsx b/zy-asrs-flow/src/pages/map/components/mapSettings.jsx
index ba5b05f..e01c7f2 100644
--- a/zy-asrs-flow/src/pages/map/components/mapSettings.jsx
+++ b/zy-asrs-flow/src/pages/map/components/mapSettings.jsx
@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
-import { Col, Form, Input, Row, Checkbox, Slider, Select, Drawer, Space, Button, InputNumber, Card } from 'antd';
+import { Col, Form, Input, Row, message, Slider, Select, Drawer, Space, Button, InputNumber, Card } from 'antd';
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
import { createStyles } from 'antd-style';
import * as Utils from '../utils'
@@ -99,6 +99,42 @@
setLastCopiedSprites([]);
for (let i = 0; i < values.copyCount; i++) {
const copiedSprite = Utils.copySprite(curSprite);
+ // auto-increment-value
+ if (values.autoIncrement && values.type) {
+ switch (values.type) {
+ case Utils.SENSOR_TYPE.SHELF:
+ if (values.incrementValue === 'row') {
+ if (values.incrementMode === 'descending') {
+ copiedSprite.data.row = curSprite.data.row - i - 1;
+ } else {
+ copiedSprite.data.row = curSprite.data.row + i + 1;
+ }
+ }
+ if (values.incrementValue === 'bay') {
+ if (values.incrementMode === 'descending') {
+ copiedSprite.data.bay = curSprite.data.bay - i - 1;
+ } else {
+ copiedSprite.data.bay = curSprite.data.bay + i + 1;
+ }
+ }
+ if (copiedSprite.data.row && copiedSprite.data.bay) {
+ copiedSprite.data.no = Utils.pureNumStr(copiedSprite.data.row) + '-' + Utils.pureNumStr(copiedSprite.data.bay);
+ }
+ break;
+ case Utils.SENSOR_TYPE.AGV:
+ if (values.incrementValue === 'no') {
+ if (values.incrementMode === 'descending') {
+ copiedSprite.data.no = Number(curSprite.data.no) - i - 1;
+ } else {
+ copiedSprite.data.no = Number(curSprite.data.no) + i + 1;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // graph copy
switch (values.copyDire) {
case 'left':
copiedSprite.position.x -= (i + 1) * (values.copyGap + copiedSprite.width);
@@ -339,7 +375,7 @@
</Form.Item>
<Form.Item>
<Button
- type="dashed"
+ type="link"
onClick={() => {
if (lastCopiedSprites) {
lastCopiedSprites.forEach(copiedSprite => {
diff --git a/zy-asrs-flow/src/pages/map/components/settings.jsx b/zy-asrs-flow/src/pages/map/components/settings.jsx
index 2bb2233..0a82de3 100644
--- a/zy-asrs-flow/src/pages/map/components/settings.jsx
+++ b/zy-asrs-flow/src/pages/map/components/settings.jsx
@@ -73,7 +73,7 @@
<Button onClick={handleCancel}>
<FormattedMessage id='common.cancel' defaultMessage='鍙栨秷' />
</Button>
- <Button hidden={activeTabKey === 'map'} onClick={handleOk} type="primary">
+ <Button hidden={activeTabKey === 'map' || activeTabKey === 'config'} onClick={handleOk} type="primary">
<FormattedMessage id='common.submit' defaultMessage='淇濆瓨' />
</Button>
</Space>
diff --git a/zy-asrs-flow/src/pages/map/drawer/agv/index.jsx b/zy-asrs-flow/src/pages/map/drawer/agv/index.jsx
new file mode 100644
index 0000000..6899ae9
--- /dev/null
+++ b/zy-asrs-flow/src/pages/map/drawer/agv/index.jsx
@@ -0,0 +1,60 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { Card, Form, Button } from 'antd';
+import { FormattedMessage, useIntl, useModel } from '@umijs/max';
+import { createStyles } from 'antd-style';
+import * as Utils from '../../utils'
+import Http from '@/utils/http';
+import ShowJson from '../showJson';
+
+const useStyles = createStyles(({ token, css }) => {
+
+})
+
+const AgvDrawer = (props) => {
+ const intl = useIntl();
+ const { styles } = useStyles();
+ const [activeTabKey, setActiveTabKey] = useState('json');
+
+ const contentList = {
+ json: (
+ <ShowJson
+ curSprite={props.curSprite}
+ />
+ ),
+ };
+
+ return (
+ <>
+ <Card
+ className='drawer-card'
+ hoverable
+ bordered={false}
+ type='inner'
+ tabList={[
+ {
+ key: 'json',
+ tab: intl.formatMessage({ id: 'map.drawer.json', defaultMessage: 'JSON' }),
+ },
+ ]}
+ activeTabKey={activeTabKey}
+ onTabChange={(key) => {
+ setActiveTabKey(key)
+ }}
+ tabProps={{
+ centered: true,
+ size: 'large',
+ type: "card",
+ style: {
+ }
+ }}
+ style={{
+ height: '100%'
+ }}
+ >
+ {contentList[activeTabKey]}
+ </Card>
+ </>
+ )
+}
+
+export default AgvDrawer;
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/drawer/index.jsx b/zy-asrs-flow/src/pages/map/drawer/index.jsx
index 1394379..0662017 100644
--- a/zy-asrs-flow/src/pages/map/drawer/index.jsx
+++ b/zy-asrs-flow/src/pages/map/drawer/index.jsx
@@ -1,9 +1,11 @@
import React, { useState, useRef, useEffect } from 'react';
-import { Drawer } from 'antd';
+import { Drawer, Space, Button } from 'antd';
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
import { createStyles } from 'antd-style';
import * as Utils from '../utils'
-import Http from '@/utils/http';
+import ShelfDrawer from './shelf';
+import AgvDrawer from './agv';
+import PointDrawer from './point'
const useStyles = createStyles(({ token, css }) => {
@@ -12,12 +14,54 @@
const MapDrawer = (props) => {
const intl = useIntl();
const { styles } = useStyles();
+ const { curSprite } = props;
+
+ const handleCancel = () => {
+ props.onCancel();
+ };
return (
<>
<Drawer
-
- />
+ open={props.open}
+ onClose={handleCancel}
+ getContainer={props.refCurr}
+ rootStyle={{ position: "absolute" }}
+ mask={false}
+ width={600}
+ style={{
+ opacity: .8
+ }}
+ extra={
+ <Space>
+ <Button onClick={handleCancel}>
+ <FormattedMessage id='common.cancel' defaultMessage='鍙栨秷' />
+ </Button>
+ </Space>
+ }
+ >
+ {props.curSprite?.data?.type === Utils.SENSOR_TYPE.SHELF && (
+ <>
+ <ShelfDrawer
+ curSprite={curSprite}
+ />
+ </>
+ )}
+ {props.curSprite?.data?.type === Utils.SENSOR_TYPE.POINT && (
+ <>
+ <PointDrawer
+ curSprite={curSprite}
+ />
+ </>
+ )}
+ {props.curSprite?.data?.type === Utils.SENSOR_TYPE.AGV && (
+ <>
+ <AgvDrawer
+ curSprite={curSprite}
+ />
+ </>
+ )}
+ </Drawer>
</>
)
}
diff --git a/zy-asrs-flow/src/pages/map/drawer/point/index.jsx b/zy-asrs-flow/src/pages/map/drawer/point/index.jsx
new file mode 100644
index 0000000..5fd6e94
--- /dev/null
+++ b/zy-asrs-flow/src/pages/map/drawer/point/index.jsx
@@ -0,0 +1,60 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { Card, Form, Button } from 'antd';
+import { FormattedMessage, useIntl, useModel } from '@umijs/max';
+import { createStyles } from 'antd-style';
+import * as Utils from '../../utils'
+import Http from '@/utils/http';
+import ShowJson from '../showJson';
+
+const useStyles = createStyles(({ token, css }) => {
+
+})
+
+const PointDrawer = (props) => {
+ const intl = useIntl();
+ const { styles } = useStyles();
+ const [activeTabKey, setActiveTabKey] = useState('json');
+
+ const contentList = {
+ json: (
+ <ShowJson
+ curSprite={props.curSprite}
+ />
+ ),
+ };
+
+ return (
+ <>
+ <Card
+ className='drawer-card'
+ hoverable
+ bordered={false}
+ type='inner'
+ tabList={[
+ {
+ key: 'json',
+ tab: intl.formatMessage({ id: 'map.drawer.json', defaultMessage: 'JSON' }),
+ },
+ ]}
+ activeTabKey={activeTabKey}
+ onTabChange={(key) => {
+ setActiveTabKey(key)
+ }}
+ tabProps={{
+ centered: true,
+ size: 'large',
+ type: "card",
+ style: {
+ }
+ }}
+ style={{
+ height: '100%'
+ }}
+ >
+ {contentList[activeTabKey]}
+ </Card>
+ </>
+ )
+}
+
+export default PointDrawer;
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/drawer/shelf/index.jsx b/zy-asrs-flow/src/pages/map/drawer/shelf/index.jsx
new file mode 100644
index 0000000..faef89f
--- /dev/null
+++ b/zy-asrs-flow/src/pages/map/drawer/shelf/index.jsx
@@ -0,0 +1,60 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { Card, Form, Button } from 'antd';
+import { FormattedMessage, useIntl, useModel } from '@umijs/max';
+import { createStyles } from 'antd-style';
+import * as Utils from '../../utils'
+import Http from '@/utils/http';
+import ShowJson from '../showJson';
+
+const useStyles = createStyles(({ token, css }) => {
+
+})
+
+const ShelfDrawer = (props) => {
+ const intl = useIntl();
+ const { styles } = useStyles();
+ const [activeTabKey, setActiveTabKey] = useState('json');
+
+ const contentList = {
+ json: (
+ <ShowJson
+ curSprite={props.curSprite}
+ />
+ ),
+ };
+
+ return (
+ <>
+ <Card
+ className='drawer-card'
+ hoverable
+ bordered={false}
+ type='inner'
+ tabList={[
+ {
+ key: 'json',
+ tab: intl.formatMessage({ id: 'map.drawer.json', defaultMessage: 'JSON' }),
+ },
+ ]}
+ activeTabKey={activeTabKey}
+ onTabChange={(key) => {
+ setActiveTabKey(key)
+ }}
+ tabProps={{
+ centered: true,
+ size: 'large',
+ type: "card",
+ style: {
+ }
+ }}
+ style={{
+ height: '100%'
+ }}
+ >
+ {contentList[activeTabKey]}
+ </Card>
+ </>
+ )
+}
+
+export default ShelfDrawer;
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/drawer/showJson.jsx b/zy-asrs-flow/src/pages/map/drawer/showJson.jsx
new file mode 100644
index 0000000..c545c33
--- /dev/null
+++ b/zy-asrs-flow/src/pages/map/drawer/showJson.jsx
@@ -0,0 +1,56 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { Card, Space, Button } from 'antd';
+import { FormattedMessage, useIntl, useModel } from '@umijs/max';
+import { createStyles } from 'antd-style';
+import * as Utils from '../utils'
+import Http from '@/utils/http';
+
+const useStyles = createStyles(({ token, css }) => {
+ let dark = token.colorBgBase === '#000';
+ return {
+ jsonBox: {
+ height: '100%',
+ border: dark ? '2px solid #747d8c' : '2px solid #535c68',
+ borderRadius: '5px',
+ padding: '5px',
+ cursor: 'text'
+ },
+ jsonContent: {
+ height: '100%',
+ overflowY: 'auto',
+ width: '100%',
+ border: 'none',
+ backgroundColor: 'transparent',
+ resize: 'none',
+ fontFamily: '"Courier New", monospace',
+ fontWeight: 'bold',
+ fontSize: '1em',
+ lineHeight: '1.5',
+ color: dark ? '#eee' : '#333',
+ '&:focus': {
+ outline: 'none'
+ }
+ }
+ }
+})
+
+const ShowJSON = (props) => {
+ const { styles } = useStyles();
+ const { curSprite } = props;
+
+ const formattedJSON = JSON.stringify(curSprite.data, null, 2);
+
+ return (
+ <>
+ <div className={styles.jsonBox}>
+ <textarea
+ readOnly
+ className={styles.jsonContent}
+ value={formattedJSON}
+ />
+ </div>
+ </>
+ )
+}
+
+export default ShowJSON;
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/header/search.jsx b/zy-asrs-flow/src/pages/map/header/search.jsx
new file mode 100644
index 0000000..5c70fe6
--- /dev/null
+++ b/zy-asrs-flow/src/pages/map/header/search.jsx
@@ -0,0 +1,164 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { Select, AutoComplete } from 'antd';
+import { FormattedMessage, useIntl } from '@umijs/max';
+import { CloseOutlined } from '@ant-design/icons';
+import * as Utils from '../utils'
+
+const renderTitle = (title, uuid) => (
+ <>
+ <span style={{ fontWeight: 'bold' }} >{title}</span>
+ <span style={{ float: 'right', opacity: .3 }} >{uuid}</span>
+ </>
+);
+
+const sensorTypeSelectOptionsFn = (intl) => {
+ let options = [];
+ Object.entries(Utils.SENSOR_TYPE).forEach(([key, value]) => {
+ switch (key) {
+ case Utils.SENSOR_TYPE.SHELF:
+ options.push({
+ value: value,
+ label:
+ (
+ <>
+ <span style={{ fontWeight: 'bold' }} >{intl.formatMessage({ id: 'map.sensor.type.shelf', defaultMessage: '璐ф灦' })}</span>
+ </>
+ )
+ })
+ break;
+ case Utils.SENSOR_TYPE.AGV:
+ options.push({
+ value: value,
+ label:
+ (
+ <>
+ <span style={{ fontWeight: 'bold' }} >{intl.formatMessage({ id: 'map.sensor.type.agv', defaultMessage: '鏃犱汉灏忚溅' })}</span>
+ </>
+ )
+ })
+ break;
+ case Utils.SENSOR_TYPE.POINT:
+ options.push({
+ value: value,
+ label:
+ (
+ <>
+ <span style={{ fontWeight: 'bold' }} >{intl.formatMessage({ id: 'map.sensor.type.point', defaultMessage: '瀹氫綅鐐�' })}</span>
+ </>
+ )
+ })
+ break;
+ default:
+ break;
+ }
+
+ })
+ return options;
+}
+
+function getAllSensorList(curSensorType) {
+ let sensorListAll = [];
+ Utils.getMapContainer().children.forEach(child => {
+ if (child?.data?.type === curSensorType && child?.data?.no) {
+ sensorListAll.push({
+ value: child.data.no,
+ label: renderTitle(child.data.no, child.data.uuid)
+ })
+ }
+ });
+ return sensorListAll;
+}
+
+const MapSearch = (props) => {
+ const intl = useIntl();
+ const {
+ curSprite: curSensor,
+ setCurSPrite: setCurSensor,
+ setSpriteBySettings,
+ model,
+ setModel,
+ ModelEnum,
+ } = props;
+
+ const sensorTypeSelectOptions = sensorTypeSelectOptionsFn(intl);
+ const [curSensorType, setCurSensorType] = React.useState(sensorTypeSelectOptions?.[0]?.value);
+
+ const [sensorList, setSensorList] = React.useState([]);
+ const [filterSensorList, setFilterSensorList] = React.useState([]);
+ const [curSensorLabel, setCurSensorLabel] = React.useState(null);
+
+ // first select
+ React.useEffect(() => {
+ if (!Utils.getMapContainer()) { return; }
+ let sensorListAll = getAllSensorList(curSensorType);
+ setSensorList(sensorListAll);
+ setFilterSensorList(sensorListAll);
+ setCurSensorLabel(null);
+ }, [curSensorType])
+
+ // second select
+ React.useEffect(() => {
+ if (!Utils.getMapContainer()) { return; }
+ if ((curSensorLabel !== null || curSensorLabel != undefined)
+ && sensorList && sensorList.length > 0) {
+ setFilterSensorList(sensorList.filter(item => item.value.includes(curSensorLabel)));
+ }
+ }, [curSensorLabel])
+
+ const onSecondSelect = (value, option) => {
+ const uuid = option.label?.props?.children?.[1].props.children;
+ const selectSensor = Utils.findSpriteByUuid(uuid);
+ if (selectSensor) {
+ Utils.beCenter(selectSensor);
+ }
+ switch (model) {
+ case ModelEnum.OBSERVER_MODEL:
+ setCurSensor(selectSensor);
+ break;
+ case ModelEnum.MOVABLE_MODEL:
+ setModel(ModelEnum.SETTINGS_MODEL);
+ setSpriteBySettings(selectSensor);
+ break;
+ case ModelEnum.SETTINGS_MODEL:
+ setSpriteBySettings(selectSensor);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (
+ <>
+ <Select
+ className='map-header-select'
+ variant='filled'
+ style={{
+ width: 160,
+ }}
+ size={'large'}
+ options={sensorTypeSelectOptions}
+ value={curSensorType}
+ onChange={setCurSensorType}
+ />
+ <AutoComplete
+ className='map-header-select'
+ variant='filled'
+ style={{
+ width: 360,
+ }}
+ size={'large'}
+ placeholder={intl.formatMessage({ id: 'common.search.placeholder', defaultMessage: '璇疯緭鍏ユ悳绱㈠唴瀹�' })}
+ allowClear={{
+ clearIcon: <CloseOutlined />
+ }}
+ popupMatchSelectWidth={500}
+ options={filterSensorList}
+ value={curSensorLabel}
+ onSelect={onSecondSelect}
+ onChange={setCurSensorLabel}
+ />
+ </>
+ )
+}
+
+export default MapSearch;
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/index.css b/zy-asrs-flow/src/pages/map/index.css
index 6c27554..a60f254 100644
--- a/zy-asrs-flow/src/pages/map/index.css
+++ b/zy-asrs-flow/src/pages/map/index.css
@@ -18,3 +18,26 @@
* {
box-sizing: border-box;
}
+
+
+.map-header-select .ant-select-selector {
+ border-radius: 0px !important;
+}
+
+.map-header-button {
+ border-radius: 0px !important;
+ font-weight: bolder !important;
+}
+
+.map-header-select.ant-select .ant-select-selector .ant-select-selection-item {
+ font-weight: bolder !important;
+}
+
+.map-header-select .ant-select-selector .ant-select-selection-search .ant-select-selection-search-input {
+ font-weight: bolder !important;
+}
+
+.drawer-card .ant-card-body {
+ height: 95%;
+ padding: 12px;
+}
\ No newline at end of file
diff --git a/zy-asrs-flow/src/pages/map/index.jsx b/zy-asrs-flow/src/pages/map/index.jsx
index 9e56171..0d84c56 100644
--- a/zy-asrs-flow/src/pages/map/index.jsx
+++ b/zy-asrs-flow/src/pages/map/index.jsx
@@ -1,13 +1,14 @@
import * as React from 'react'
import * as PIXI from 'pixi.js';
import { FormattedMessage, useIntl, useModel } from '@umijs/max';
-import { Layout, Button, Flex, Row, Col, FloatButton, Select, Spin } from 'antd';
+import { Layout, Button, Flex, Row, Col, FloatButton, Select, Spin, AutoComplete } from 'antd';
const { Header, Content } = Layout;
import {
AppstoreAddOutlined,
FileAddOutlined,
CompressOutlined,
SettingOutlined,
+ CloseOutlined
} from '@ant-design/icons';
import './index.css'
import { createStyles } from 'antd-style';
@@ -15,6 +16,7 @@
import Settings from './components/settings'
import * as Utils from './utils'
import Player from './player';
+import MapSearch from './header/search';
import MapDrawer from './drawer';
const useStyles = createStyles(({ token }) => {
@@ -42,6 +44,9 @@
select: {
color: 'red',
fontWeight: 'bold',
+ },
+ headerCol: {
+ paddingLeft: '50px'
}
};
});
@@ -61,7 +66,7 @@
const mapRef = React.useRef();
const contentRef = React.useRef();
- const [model, setModel] = React.useState(() => MapModel.OBSERVER_MODEL);
+ const [model, setModel] = React.useState(null);
const [deviceVisible, setDeviceVisible] = React.useState(false);
const [settingsVisible, setSettingsVisible] = React.useState(false);
const [windowSize, setWindowSize] = React.useState({
@@ -73,22 +78,35 @@
const [didClickSprite, setDidClickSprite] = React.useState(false);
const [spriteBySettings, setSpriteBySettings] = React.useState(null);
const prevSpriteBySettingsRef = React.useRef();
+ const [drawerVisible, setDrawerVisible] = React.useState(false);
+ const [dataFetched, setDataFetched] = React.useState(false);
+ const [curSprite, setCurSPrite] = React.useState(null);
+ const prevCurSpriteRef = React.useRef();
// init func
React.useEffect(() => {
- player = new Player(mapRef.current, styles.dark, didClickSprite);
- setApp(player.app);
- setMapContainer(player.mapContainer);
- Utils.syncApp(player.app);
- Utils.syncMapContainer(player.mapContainer);
+ const initialize = async () => {
+ player = new Player(mapRef.current, styles.dark, didClickSprite);
+ setApp(player.app);
+ setMapContainer(player.mapContainer);
+ Utils.syncApp(player.app);
+ Utils.syncMapContainer(player.mapContainer);
- const handleResize = () => {
- setWindowSize({
- width: window.innerWidth,
- height: window.innerHeight,
- });
- };
- window.addEventListener('resize', handleResize);
+ const handleResize = () => {
+ setWindowSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ };
+ window.addEventListener('resize', handleResize);
+ await Utils.fetchMapData(intl);
+ setDataFetched(true);
+ setModel(MapModel.OBSERVER_MODEL)
+ setTimeout(() => {
+ player.adaptScreen();
+ }, 200)
+ }
+ initialize();
}, []);
// resize
@@ -100,14 +118,13 @@
const height = contentRef.current.offsetHeight;
app.renderer.resize(width, height);
if (model !== MapModel.OBSERVER_MODEL) {
- player.hideGridlines();
player.showGridlines();
}
}, [app, mapContainer, windowSize])
// model
React.useEffect(() => {
- if (!mapContainer) {
+ if (!mapContainer && !dataFetched) {
return;
}
switch (model) {
@@ -119,14 +136,12 @@
player.activateMapEvent(null);
Utils.removeSelectedEffect();
+ setCurSPrite(null);
setDeviceVisible(false);
setSettingsVisible(false);
mapContainer.children.forEach(child => {
- child.off('pointerup');
- child.off('pointermove');
- child.off('pointerdown');
- child.off('click');
+ Utils.viewFeature(child, setCurSPrite);
})
break
case MapModel.MOVABLE_MODEL:
@@ -139,6 +154,7 @@
Utils.removeSelectedEffect();
setSpriteBySettings(null);
setSettingsVisible(false);
+ setDrawerVisible(false);
mapContainer.children.forEach(child => {
Utils.beMovable(child, setDidClickSprite);
@@ -152,6 +168,7 @@
player.activateMapEvent(null);
setDeviceVisible(false);
+ setDrawerVisible(false);
mapContainer.children.forEach(child => {
Utils.beSettings(child, setSpriteBySettings, setDidClickSprite);
@@ -172,6 +189,26 @@
mapContainer.addChild(sprite);
Utils.beMovable(sprite, setDidClickSprite);
};
+
+ // watch curSprite
+ React.useEffect(() => {
+ if (!mapContainer) {
+ return;
+ }
+ prevCurSpriteRef.current = curSprite;
+ if (curSprite && prevCurSprite !== curSprite) {
+ Utils.removeSelectedEffect();
+ }
+ if (curSprite) {
+ if (model === MapModel.OBSERVER_MODEL) {
+ Utils.showSelectedEffect(curSprite)
+ setDrawerVisible(true)
+ }
+ } else {
+ Utils.removeSelectedEffect();
+ }
+ }, [curSprite]);
+ const prevCurSprite = prevCurSpriteRef.current;
// didClickSprite, stop triggers both sprite click and play's selection boxs
React.useEffect(() => {
@@ -196,9 +233,10 @@
}, [spriteBySettings])
const prevSpriteBySettings = prevSpriteBySettingsRef.current;
- const settingsFinish = () => {
- setSettingsVisible(false);
- setSpriteBySettings(null);
+ const settingsFinish = (values, fn) => {
+ fn();
+ // setSettingsVisible(false);
+ // setSpriteBySettings(null);
}
return (
@@ -206,42 +244,76 @@
<Layout className={styles.layout}>
<Header className={styles.header}>
<Row style={{ height: '100%' }}>
- <Col span={8} style={{ backgroundColor: '#dcdde1' }}>
-
-
- <Select
- defaultValue="agv"
- style={{
- width: 120,
- }}
- size={'large'}
- onChange={(value, option) => {
- console.log(value, option);
- }}
- options={[
- {
- value: 'agv',
- label: 'agv',
- },
- {
- value: 'crn',
- label: 'crn',
- },
- ]}
- />
-
- <Select
-
- // notFoundContent={loading ? <Spin size="small" /> : null}
-
- />
-
-
+ <Col className={styles.headerCol} span={12} style={{}}>
+ {dataFetched && (
+ <MapSearch
+ model={model}
+ setModel={setModel}
+ ModelEnum={MapModel}
+ curSprite={curSprite}
+ setCurSPrite={setCurSPrite}
+ setSpriteBySettings={setSpriteBySettings}
+ />
+ )}
</Col>
- <Col span={16} style={{ backgroundColor: '#3C40C6' }}>
+ <Col span={12} style={{ backgroundColor: styles.dark ? '#2C3A47' : '#4a69bd' }}>
<Flex className={styles.flex} gap={'large'} justify={'flex-end'} align={'center'}>
+
+ {model === MapModel.OBSERVER_MODEL && (
+ <>
+ <Button
+ className='map-header-button'
+ size={'large'}
+ onClick={async () => {
+ await Utils.fetchMapData(intl);
+
+ player.hideGridlines();
+ player.hideStarryBackground();
+
+ player.activateMapEvent(null);
+
+ Utils.removeSelectedEffect();
+ setCurSPrite(null);
+ setDeviceVisible(false);
+ setSettingsVisible(false);
+ setDrawerVisible(false);
+
+ mapContainer.children.forEach(child => {
+ Utils.viewFeature(child, setCurSPrite);
+ })
+
+ }}
+ >
+ <FormattedMessage id='map.load' defaultMessage='鍔犺浇鍦板浘' />
+ </Button>
+ </>
+ )}
+
+ {model !== MapModel.OBSERVER_MODEL && (
+ <>
+ <Button
+ className='map-header-button'
+ size={'large'}
+ onClick={() => {
+ Utils.clearMapData(intl);
+ }}
+ >
+ <FormattedMessage id='map.clear' defaultMessage='娓呴櫎鍦板浘' />
+ </Button>
+ <Button
+ className='map-header-button'
+ size={'large'}
+ onClick={() => {
+ Utils.saveMapData(intl);
+ }}
+ >
+ <FormattedMessage id='map.save' defaultMessage='淇濆瓨鍦板浘' />
+ </Button>
+ </>
+ )}
+
<Select
- className={styles.select}
+ className='map-header-select'
size={'large'}
defaultValue={MapModel.OBSERVER_MODEL}
style={{
@@ -274,8 +346,10 @@
>
<FloatButton
icon={<CompressOutlined />}
+ onClick={() => {
+ player.adaptScreen();
+ }}
/>
- <FloatButton.BackTop visibilityHeight={0} />
</FloatButton.Group>
<FloatButton.Group
@@ -312,7 +386,17 @@
</FloatButton.Group>
</div>
</Content>
- </Layout>
+ </Layout >
+
+ <MapDrawer
+ open={drawerVisible}
+ curSprite={curSprite}
+ refCurr={mapRef.current}
+ onCancel={() => {
+ setCurSPrite(null);
+ setDrawerVisible(false);
+ }}
+ />
<Edit
open={deviceVisible}
diff --git a/zy-asrs-flow/src/pages/map/player.js b/zy-asrs-flow/src/pages/map/player.js
index 35edc66..772f874 100644
--- a/zy-asrs-flow/src/pages/map/player.js
+++ b/zy-asrs-flow/src/pages/map/player.js
@@ -22,7 +22,7 @@
this.activateMapScale();
this.activateMapPan();
this.showCoordinates();
- this.appTicker();
+ this.getStartedTicker();
}
activateMapEvent = (leftEvent, rightEvent) => {
@@ -146,20 +146,34 @@
}
activateMapScale = () => {
- this.scale = 1; // 缂╂斁
+ this.scale = 1;
this.app.view.addEventListener('wheel', (event) => {
event.preventDefault();
+ if (this.scale !== this.mapContainer.scale.x) {
+ this.scale = this.mapContainer.scale.x;
+ }
+
const delta = Math.sign(event.deltaY);
- if (delta === 1) {
- this.scale *= 0.9;
- } else if (delta === -1) {
- this.scale *= 1.1;
- }
+ const mousePosition = new PIXI.Point();
+ this.app.renderer.plugins.interaction.mapPositionToPoint(mousePosition, event.clientX, event.clientY);
+
+ const diffPositionX = mousePosition.x - this.mapContainer.x;
+ const diffPositionY = mousePosition.y - this.mapContainer.y;
+
+ const newScale = this.scale * (delta === 1 ? 0.9 : 1.1);
+ const scaleFactor = newScale / this.scale;
+
+ this.mapContainer.x = mousePosition.x - diffPositionX * scaleFactor;
+ this.mapContainer.y = mousePosition.y - diffPositionY * scaleFactor;
+
+ this.scale = newScale;
+
this.mapContainer.scale.set(this.scale);
+
this.mapContainer.children.forEach(child => {
// child.scale.set(1 / this.scale); // 闃叉鍥炬爣鍙樺皬
- })
+ });
});
}
@@ -183,17 +197,18 @@
}
showGridlines = () => {
+ this.hideGridlines();
if (!this.gridLineContainer) {
this.gridLineContainer = generatePixiContainer('gridLineContainer');
this.app.stage.addChild(this.gridLineContainer);
}
const inte = 30;
- const lineDefaultAlpha = .5;;
+ const lineDefaultAlpha = .1;;
const lineDefaultColor = 0x000000;
for (let i = 0; i < this.app.view.width / inte; i++) {
const graphics = new PIXI.Graphics();
- graphics.lineStyle(.3, lineDefaultColor, lineDefaultAlpha);
+ graphics.lineStyle(1, lineDefaultColor, lineDefaultAlpha);
graphics.beginFill(lineDefaultColor);
graphics.moveTo(i * inte, 0);
graphics.lineTo(i * inte, this.app.view.height);
@@ -203,7 +218,7 @@
for (let i = 0; i < this.app.view.height / inte; i++) {
const graphics = new PIXI.Graphics();
- graphics.lineStyle(.3, lineDefaultColor, lineDefaultAlpha);
+ graphics.lineStyle(1, lineDefaultColor, lineDefaultAlpha);
graphics.beginFill(lineDefaultColor);
graphics.moveTo(0, i * inte);
graphics.lineTo(this.app.view.width, i * inte);
@@ -258,7 +273,6 @@
warpSpeed = warpSpeed > 0 ? 0 : 1;
}, 5000);
-
this.starryTicker = (delta) => {
speed += (warpSpeed - speed) / 20;
cameraZ += delta * 10 * (speed + baseSpeed);
@@ -294,7 +308,7 @@
}
hideStarryBackground = () => {
- if(this.starryTicker) {
+ if (this.starryTicker) {
this.app.ticker.remove(this.starryTicker);
this.starryTicker = null;
}
@@ -311,12 +325,59 @@
}
}
+ adaptScreen = () => {
+ if (!this.mapContainer || !this.app) {
+ return;
+ }
+
+ this.mapContainer.scale.set(1);
+ this.mapContainer.position.set(0, 0);
+ if (this.mapContainer.children.length === 0) {
+ return;
+ }
+
+ let minX, maxX, minY, maxY;
+ for (let sprite of this.mapContainer.children) {
+ if (sprite?.data?.uuid) {
+ let bounds = sprite.getBounds();
+ minX = minX !== undefined ? Math.min(minX, bounds.x) : bounds.x;
+ minY = minY !== undefined ? Math.min(minY, bounds.y) : bounds.y;
+ maxX = maxX !== undefined ? Math.max(maxX, bounds.x + bounds.width) : bounds.x + bounds.width;
+ maxY = maxY !== undefined ? Math.max(maxY, bounds.y + bounds.height) : bounds.y + bounds.height;
+ }
+ }
+
+ this.scale = Math.min(
+ this.app.renderer.width / (maxX - minX) * 0.8,
+ this.app.renderer.height / (maxY - minY) * 0.8
+ );
+
+ let centerPoint = {
+ x: (minX + maxX) / 2 * this.mapContainer.scale.x,
+ y: (minY + maxY) / 2 * this.mapContainer.scale.y
+ };
+
+ new TWEEDLE.Tween(this.mapContainer.scale).easing(TWEEDLE.Easing.Quadratic.Out)
+ .to({
+ x: this.scale,
+ y: this.scale
+ }, 200).start();
+
+ new TWEEDLE.Tween(this.mapContainer.position).easing(TWEEDLE.Easing.Quadratic.Out)
+ .to({
+ x: this.app.renderer.width / 2 - centerPoint.x * this.scale,
+ y: this.app.renderer.height / 2 - centerPoint.y * this.scale
+ }, 200).start();
+ }
+
updateDidClickSprite = (value) => {
this.didClickSprite = value;
}
- appTicker = () => {
- TWEEDLE.Group.shared.update();
+ getStartedTicker = () => {
+ this.app.ticker.add((delta) => {
+ TWEEDLE.Group.shared.update();
+ });
}
}
diff --git a/zy-asrs-flow/src/pages/map/utils.js b/zy-asrs-flow/src/pages/map/utils.js
index a1ca052..d00398a 100644
--- a/zy-asrs-flow/src/pages/map/utils.js
+++ b/zy-asrs-flow/src/pages/map/utils.js
@@ -1,4 +1,11 @@
import * as PIXI from 'pixi.js';
+import * as TWEEDLE from 'tweedle.js';
+import Http from '@/utils/http';
+import { message } from 'antd';
+import { API_TIMEOUT } from '@/config/setting'
+import agv from '/public/img/map/agv.svg'
+import shelf from '/public/img/map/shelf.png'
+import point from '/public/img/map/point.svg'
let app = null;
let mapContainer = null;
@@ -21,8 +28,9 @@
})
export const SENSOR_TYPE = Object.freeze({
- AGV: "AGV",
SHELF: "SHELF",
+ POINT: "POINT",
+ AGV: "AGV",
})
export const getRealPosition = (x, y, mapContainer) => {
@@ -43,6 +51,21 @@
};
}
+// show sprite feature from sprite click event
+export const viewFeature = (sprite, setCurSPrite) => {
+ sprite.off('pointerup');
+ sprite.off('pointermove');
+ sprite.off('pointerdown');
+ sprite.off('click');
+
+ sprite.on("click", onClick);
+
+ function onClick(event) {
+ setCurSPrite(sprite);
+ }
+
+}
+
// sprite be movable from sprite click event
export const beMovable = (sprite, setDidClickSprite) => {
sprite.off('pointerup');
@@ -54,13 +77,15 @@
let dragTarget;
function onDragStart(event) {
- setDidClickSprite(true);
- dragTarget = event.currentTarget;
- mapContainer.parent.off('pointermove');
- mapContainer.parent.on('pointermove', onDragMove, dragTarget);
+ if (event.button === 0) {
+ setDidClickSprite(true);
+ dragTarget = event.currentTarget;
+ mapContainer.parent.off('pointermove');
+ mapContainer.parent.on('pointermove', onDragMove, dragTarget);
- mapContainer.parent.off('pointerup');
- mapContainer.parent.on('pointerup', onDragEnd.bind(mapContainer));
+ mapContainer.parent.off('pointerup');
+ mapContainer.parent.on('pointerup', onDragEnd.bind(mapContainer));
+ }
}
function onDragMove(event) {
@@ -248,4 +273,169 @@
} else {
return '';
}
+}
+
+export const rotationToNum = (rotation) => {
+ let res = rotation * 180 / Math.PI;
+ if (res < 0) {
+ res += 360;
+ } else if (res > 360) {
+ res -= 360;
+ }
+ return res;
+}
+
+export const rotationParseNum = (num) => {
+ return num * Math.PI / 180;
+}
+
+export const findSpriteByUuid = (uuid) => {
+ return mapContainer?.children?.find(child => child?.data?.uuid === uuid);
+}
+
+export const sensorTypeSelectOptions = (intl) => {
+ let options = [];
+ Object.entries(SENSOR_TYPE).forEach(([key, value]) => {
+ switch (key) {
+ case SENSOR_TYPE.SHELF:
+ options.push({
+ value: value,
+ label: intl.formatMessage({ id: 'map.sensor.type.shelf', defaultMessage: '璐ф灦' })
+ })
+ break;
+ case SENSOR_TYPE.AGV:
+ options.push({
+ value: value,
+ label: intl.formatMessage({ id: 'map.sensor.type.agv', defaultMessage: '鏃犱汉灏忚溅' })
+ })
+ break;
+ case SENSOR_TYPE.POINT:
+ options.push({
+ value: value,
+ label: intl.formatMessage({ id: 'map.sensor.type.point', defaultMessage: '瀹氫綅鐐�' })
+ })
+ break;
+ default:
+ break;
+ }
+
+ })
+ return options;
+}
+
+export const fetchMapData = async (intl) => {
+ clearMapData();
+ await Http.doPostPromise('api/map/list', {}, (res) => {
+ const mapItemList = res.data.itemList;
+ mapItemList.forEach(item => {
+ let sprite;
+ switch (item.type) {
+ case SENSOR_TYPE.SHELF:
+ sprite = PIXI.Sprite.from(shelf);
+ break;
+ case SENSOR_TYPE.AGV:
+ sprite = PIXI.Sprite.from(agv);
+ break;
+ case SENSOR_TYPE.POINT:
+ sprite = PIXI.Sprite.from(point);
+ break;
+ default:
+ break;
+ }
+ if (sprite) {
+ initSprite(sprite, item.type);
+ // data
+ sprite.data.uuid = item.uuid;
+ sprite.data.no = item.no;
+
+ // graph
+ sprite.position.set(item.positionX, item.positionY);
+ sprite.scale.set(item.scaleX, item.scaleY);
+ sprite.rotation = rotationParseNum(item.rotation);
+ mapContainer.addChild(sprite);
+ }
+ })
+
+ }).catch((error) => {
+ console.error(error);
+ })
+
+}
+
+export const saveMapData = async (intl) => {
+ if (!mapContainer) {
+ return;
+ }
+
+ let mapItemList = [];
+ mapContainer?.children.forEach(child => {
+ if (child.data?.uuid) {
+ mapItemList.push({
+ // data
+ type: child.data.type,
+ uuid: child.data.uuid,
+ no: child.data.no,
+
+ // graph
+ positionX: child.position.x,
+ positionY: child.position.y,
+ scaleX: child.scale.x,
+ scaleY: child.scale.y,
+ rotation: rotationToNum(child.rotation)
+ })
+ }
+ })
+
+ const closeLoading = message.loading({ content: intl.formatMessage({ id: 'common.loading.api.message', defaultMessage: '绛夊緟鏈嶅姟鍣�......' }), duration: API_TIMEOUT });
+ await Http.doPostPromise('api/map/save', { itemList: mapItemList }, (res) => {
+ closeLoading();
+ }).catch((error) => {
+ closeLoading();
+ console.error(error);
+ })
+}
+
+export const clearMapData = (intl) => {
+ if (!mapContainer) {
+ return;
+ }
+ let childList = [];
+ mapContainer.children.forEach(child => {
+ if (child.data?.uuid) {
+ childList.push(child);
+ }
+ })
+ if (childList.length > 0) {
+ childList.forEach(child => {
+ mapContainer.removeChild(child);
+ child.destroy({ children: true, texture: false, baseTexture: false });
+ })
+ childList.forEach((child, index) => {
+ childList[index] = null;
+ });
+ childList = [];
+ }
+}
+
+export const beCenter = (sprite) => {
+ if (!sprite || !app || !mapContainer) {
+ return;
+ }
+
+ mapContainer.scale.set(1);
+ mapContainer.position.set(0, 0);
+
+ let bounds = sprite.getBounds();
+ let centerPoint = {
+ x: bounds.x + bounds.width / 2,
+ y: bounds.y + bounds.height / 2
+ };
+
+ let targetPos = {
+ x: app.renderer.width / 3 - centerPoint.x * mapContainer.scale.x,
+ y: app.renderer.height / 3 - centerPoint.y * mapContainer.scale.y
+ };
+
+ new TWEEDLE.Tween(mapContainer.position).easing(TWEEDLE.Easing.Quadratic.Out)
+ .to(targetPos, 500).start();
}
\ No newline at end of file
diff --git a/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/MapController.java b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/MapController.java
new file mode 100644
index 0000000..38a6053
--- /dev/null
+++ b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/MapController.java
@@ -0,0 +1,38 @@
+package com.zy.asrs.wcs.core.map.controller;
+
+import com.zy.asrs.framework.common.R;
+import com.zy.asrs.wcs.core.map.controller.param.MapDataParam;
+import com.zy.asrs.wcs.core.map.service.MapService;
+import com.zy.asrs.wcs.system.controller.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by vincent on 3/15/2024
+ */
+@RestController
+@RequestMapping("/api/map")
+public class MapController extends BaseController {
+
+ @Autowired
+ private MapService mapService;
+
+ // @PreAuthorize("hasAuthority('core:map:list')")
+ @PostMapping("/list")
+ public R mapList() {
+ return R.ok().add(mapService.getMapData(getLoginUserId()));
+ }
+
+// @PreAuthorize("hasAuthority('core:map:save')")
+ @PostMapping("/save")
+ @Transactional
+ public R mapSave(@RequestBody MapDataParam param) {
+ mapService.saveMapData(param, getLoginUserId());
+ return R.ok();
+ }
+
+}
diff --git a/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/param/MapDataParam.java b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/param/MapDataParam.java
new file mode 100644
index 0000000..1a3f4ff
--- /dev/null
+++ b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/controller/param/MapDataParam.java
@@ -0,0 +1,16 @@
+package com.zy.asrs.wcs.core.map.controller.param;
+
+import com.zy.asrs.wcs.core.map.entity.MapItem;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created by vincent on 3/15/2024
+ */
+@Data
+public class MapDataParam {
+
+ public List<MapItem> itemList;
+
+}
diff --git a/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/entity/MapItem.java b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/entity/MapItem.java
new file mode 100644
index 0000000..009a761
--- /dev/null
+++ b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/entity/MapItem.java
@@ -0,0 +1,28 @@
+package com.zy.asrs.wcs.core.map.entity;
+
+import lombok.Data;
+
+/**
+ * Created by vincent on 3/15/2024
+ */
+@Data
+public class MapItem {
+
+ private String type;
+
+ private String uuid;
+
+ private String no;
+
+
+ private Double positionX;
+
+ private Double positionY;
+
+ private Double scaleX;
+
+ private Double scaleY;
+
+ private Double rotation;
+
+}
diff --git a/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/service/MapService.java b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/service/MapService.java
new file mode 100644
index 0000000..4ec28c1
--- /dev/null
+++ b/zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/map/service/MapService.java
@@ -0,0 +1,37 @@
+package com.zy.asrs.wcs.core.map.service;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.asrs.framework.common.Cools;
+import com.zy.asrs.framework.exception.CoolException;
+import com.zy.asrs.wcs.core.map.controller.param.MapDataParam;
+import com.zy.asrs.wcs.system.entity.User;
+import com.zy.asrs.wcs.system.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Created by vincent on 3/15/2024
+ */
+@Service
+public class MapService {
+
+ @Autowired
+ private UserService userService;
+
+ public MapDataParam getMapData(Long userId) {
+ User user = userService.getById(userId);
+ if (Cools.isEmpty(user.getMemo())) {
+ return new MapDataParam();
+ }
+ return JSON.parseObject(user.getMemo(), MapDataParam.class);
+ }
+
+ public void saveMapData(MapDataParam param, Long userId) {
+ User user = userService.getById(userId);
+ user.setMemo(JSON.toJSONString(param));
+ if (!userService.updateById(user)) {
+ throw new CoolException("鏈嶅姟鍣ㄥ唴閮ㄩ敊璇�");
+ }
+ }
+
+}
--
Gitblit v1.9.1