| | |
| | | setCurSprite(null); |
| | | const started = Tool.startAreaDrawing({ |
| | | promptText: translate('page.map.prompt.areaName'), |
| | | onComplete: ({ name, start, end, color }) => { |
| | | onComplete: ({ name, start, end, color, graphics }) => { |
| | | if (name) { |
| | | Http.saveAreaData(curZone, { name, start, end, color }); |
| | | notify.success(translate('page.map.msg.areaCreated', { name })); |
| | | Http.saveAreaData(curZone, { name, start, end, color }).then((savedArea) => { |
| | | if (savedArea?.id && graphics?.data) { |
| | | graphics.data.id = savedArea.id; |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | onFinish: () => { |
| | |
| | | import React from 'react'; |
| | | import { Stack, TextField, Button, Typography, Box } from '@mui/material'; |
| | | import { |
| | | Stack, |
| | | TextField, |
| | | Button, |
| | | Typography, |
| | | Box, |
| | | Autocomplete, |
| | | Checkbox, |
| | | } from '@mui/material'; |
| | | import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; |
| | | import CheckBoxIcon from '@mui/icons-material/CheckBox'; |
| | | import { useTranslate } from 'react-admin'; |
| | | |
| | | const AreaBasicTab = ({ |
| | | areaName, |
| | | setAreaName, |
| | | agvList, |
| | | setAgvList, |
| | | agvOptions, |
| | | selectedAgvs, |
| | | setSelectedAgvs, |
| | | barcodeList, |
| | | setBarcodeList, |
| | | onSave, |
| | | }) => { |
| | | const translate = useTranslate(); |
| | | const icon = <CheckBoxOutlineBlankIcon fontSize="small" />; |
| | | const checkedIcon = <CheckBoxIcon fontSize="small" />; |
| | | |
| | | const getOptionLabel = (option) => { |
| | | if (typeof option === 'string') { |
| | | return option; |
| | | } |
| | | return option?.label ?? option?.name ?? option?.agvNo ?? option?.value ?? option?.id ?? ''; |
| | | }; |
| | | |
| | | const getOptionId = (option) => { |
| | | if (typeof option === 'string') { |
| | | return option; |
| | | } |
| | | return option?.value ?? option?.id ?? option?.agvNo ?? option?.code ?? option?.name ?? ''; |
| | | }; |
| | | |
| | | return ( |
| | | <Stack spacing={2}> |
| | |
| | | <Typography variant="subtitle2" gutterBottom> |
| | | {translate('page.map.area.agv', { _: '添加AGV小车' })} |
| | | </Typography> |
| | | <TextField |
| | | placeholder={translate('page.map.area.agv.placeholder', { _: '用逗号分隔:agv01, agv02' })} |
| | | fullWidth |
| | | multiline |
| | | minRows={3} |
| | | value={agvList} |
| | | onChange={(e) => setAgvList(e.target.value)} |
| | | <Autocomplete |
| | | multiple |
| | | disableCloseOnSelect |
| | | options={agvOptions || []} |
| | | value={selectedAgvs || []} |
| | | getOptionLabel={getOptionLabel} |
| | | isOptionEqualToValue={(option, value) => getOptionId(option) === getOptionId(value)} |
| | | onChange={(event, newValue) => { |
| | | setSelectedAgvs(newValue); |
| | | }} |
| | | renderOption={(props, option, { selected }) => ( |
| | | <li {...props}> |
| | | <Checkbox |
| | | icon={icon} |
| | | checkedIcon={checkedIcon} |
| | | style={{ marginRight: 8 }} |
| | | checked={selected} |
| | | /> |
| | | {getOptionLabel(option)} |
| | | </li> |
| | | )} |
| | | renderInput={(params) => ( |
| | | <TextField |
| | | {...params} |
| | | placeholder={translate('page.map.area.agv.placeholder', { _: '选择AGV' })} |
| | | /> |
| | | )} |
| | | ListboxProps={{ sx: { maxHeight: 280 } }} |
| | | /> |
| | | </Box> |
| | | |
| | |
| | | minRows={6} |
| | | maxRows={10} |
| | | value={barcodeList} |
| | | onChange={(e) => setBarcodeList(e.target.value)} |
| | | InputProps={{ readOnly: true }} |
| | | /> |
| | | </Box> |
| | | </Stack> |
| | |
| | | import React, { useState, useEffect } from 'react'; |
| | | import React, { useState, useEffect, useMemo } from 'react'; |
| | | import { useTranslate } from "react-admin"; |
| | | import { |
| | | Drawer, |
| | |
| | | import AreaAdvancedTab from './AreaAdvancedTab'; |
| | | import { getAreaInfo } from '../http'; |
| | | |
| | | const getAgvOptionId = (option) => { |
| | | if (typeof option === 'string') { |
| | | return option; |
| | | } |
| | | return option?.value ?? option?.id ?? option?.agvNo ?? option?.code ?? option?.name ?? ''; |
| | | }; |
| | | |
| | | const AreaSettings = (props) => { |
| | | const { open, onCancel, sprite, width = PAGE_DRAWER_WIDTH } = props; |
| | | const theme = useTheme(); |
| | |
| | | |
| | | const [activeTab, setActiveTab] = useState(0); |
| | | const [areaName, setAreaName] = useState(''); |
| | | const [agvList, setAgvList] = useState(''); |
| | | const [selectedAgvs, setSelectedAgvs] = useState([]); |
| | | const [barcodeList, setBarcodeList] = useState(''); |
| | | const [areaCode, setAreaCode] = useState(''); |
| | | const [maxQty, setMaxQty] = useState(''); |
| | |
| | | } |
| | | |
| | | useEffect(() => { |
| | | if (sprite?.data) { |
| | | console.log(sprite.data); |
| | | if (sprite?.data?.id) { |
| | | fetchAreaInfo(sprite.data.id); |
| | | |
| | | setAreaName(sprite.data.name || ''); |
| | | setAreaCode(sprite.data.code || ''); |
| | | setMaxQty(sprite.data.maxQty || ''); |
| | | setSpeedLimit(sprite.data.speedLimit || ''); |
| | | setShapeData(sprite.data.shape || ''); |
| | | setPriority(sprite.data.priority || ''); |
| | | setAgvList((sprite.data.agvs || []).join(', ')); |
| | | setBarcodeList((sprite.data.barcodes || []).join('\n')); |
| | | } else { |
| | | setCurAreaInfo(null); |
| | | setAreaName(''); |
| | | setAreaCode(''); |
| | | setMaxQty(''); |
| | | setSpeedLimit(''); |
| | | setShapeData(''); |
| | | setPriority(''); |
| | | setAgvList(''); |
| | | setSelectedAgvs([]); |
| | | setBarcodeList(''); |
| | | } |
| | | }, [sprite]); |
| | | |
| | | const agvOptions = useMemo(() => { |
| | | if (!curAreaInfo) { |
| | | return []; |
| | | } |
| | | return curAreaInfo.agvOptions || curAreaInfo.agvCandidates || curAreaInfo.agvList || []; |
| | | }, [curAreaInfo]); |
| | | |
| | | useEffect(() => { |
| | | if (curAreaInfo) { |
| | | setAreaName(curAreaInfo.name || ''); |
| | | setAreaCode(curAreaInfo.code || ''); |
| | | setMaxQty(curAreaInfo.maxQty || ''); |
| | | setSpeedLimit(curAreaInfo.speedLimit || ''); |
| | | setShapeData(curAreaInfo.shape || ''); |
| | | setPriority(curAreaInfo.priority || ''); |
| | | |
| | | const selected = curAreaInfo.selectedAgvs || curAreaInfo.agvs || []; |
| | | if (Array.isArray(selected) && Array.isArray(agvOptions) && agvOptions.length > 0) { |
| | | const optionMap = new Map(agvOptions.map(option => [getAgvOptionId(option), option])); |
| | | setSelectedAgvs(selected.map(item => optionMap.get(getAgvOptionId(item)) || item)); |
| | | } else { |
| | | setSelectedAgvs(selected); |
| | | } |
| | | |
| | | const barcodes = curAreaInfo.barcodes || curAreaInfo.barcodeList || []; |
| | | setBarcodeList(Array.isArray(barcodes) ? barcodes.join('\n') : (barcodes || '')); |
| | | } |
| | | }, [curAreaInfo, agvOptions]); |
| | | |
| | | const handleTabChange = (event, newValue) => { |
| | | setActiveTab(newValue); |
| | |
| | | <AreaBasicTab |
| | | areaName={areaName} |
| | | setAreaName={setAreaName} |
| | | agvList={agvList} |
| | | setAgvList={setAgvList} |
| | | agvOptions={agvOptions} |
| | | selectedAgvs={selectedAgvs} |
| | | setSelectedAgvs={setSelectedAgvs} |
| | | barcodeList={barcodeList} |
| | | setBarcodeList={setBarcodeList} |
| | | onSave={handleSaveBasic} |
| | | /> |
| | | )} |
| | |
| | | zoneId: zoneId, |
| | | ...areaData, |
| | | }); |
| | | const { code, msg } = res.data; |
| | | const { code, msg, data } = res.data; |
| | | if (code !== 200) { |
| | | notify.error(msg); |
| | | return null; |
| | | } |
| | | return data; |
| | | } catch (error) { |
| | | notify.error(error.message); |
| | | console.error(error.message); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | |
| | | @PostMapping("/area/save") |
| | | @Transactional |
| | | public R save(@RequestBody MapAreaParam param) { |
| | | areaService.saveMapArea(param, getLoginUserId()); |
| | | return R.ok(); |
| | | return R.ok().add(areaService.saveMapArea(param, getLoginUserId())); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | public interface AreaService extends IService<Area> { |
| | | |
| | | void saveMapArea(MapAreaParam param, Long loginUserId); |
| | | Area saveMapArea(MapAreaParam param, Long loginUserId); |
| | | |
| | | } |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void saveMapArea(MapAreaParam param, Long loginUserId) { |
| | | public Area saveMapArea(MapAreaParam param, Long loginUserId) { |
| | | Date now = new Date(); |
| | | |
| | | Area area = new Area(); |
| | |
| | | if (!this.save(area)) { |
| | | log.error("failed to save area"); |
| | | } |
| | | |
| | | return area; |
| | | } |
| | | |
| | | } |