rsf-admin/src/page/orders/wave/WaveList.jsx
@@ -28,7 +28,8 @@ import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE, DEFAULT_WAVE_AUTO_EXCE } from '@/config/setting'; import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline'; import { Box, Typography, Card, Stack } from '@mui/material'; import StopCircleOutlinedIcon from '@mui/icons-material/StopCircleOutlined'; import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material'; import ConfirmButton from "../../components/ConfirmButton"; import PageDrawer from "../../components/PageDrawer"; import PublicIcon from '@mui/icons-material/Public'; @@ -36,7 +37,7 @@ import { styled } from '@mui/material/styles'; import request from '@/utils/request'; import WaveCreate from "./WaveCreate"; import WavePannel from "./WavePanel" const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -48,7 +49,7 @@ '& .column-name': { }, '& .opt': { width: 260 width: 200 }, })); @@ -102,12 +103,13 @@ const { data: { code, data, msg } } = await request.get('/config/flag/' + DEFAULT_WAVE_AUTO_EXCE); if (code === 200) { setAutoExce(JSON.parse(data?.val)) } } } return ( <Box display="flex"> <List queryOptions={{ refetchInterval: 5000 }} sx={{ flexGrow: 1, transition: (theme) => @@ -122,8 +124,8 @@ sort={{ field: "create_time", order: "desc" }} actions={( <TopToolbar> <BulkStartButton autoExce={autoExce} setAutoExce={setAutoExce} /> <BulkPauseButton autoExce={autoExce} setAutoExce={setAutoExce} /> <BulkAutoStartButton autoExce={autoExce} setAutoExce={setAutoExce} /> <BulkAutoPauseButton autoExce={autoExce} setAutoExce={setAutoExce} /> <FilterButton /> <SelectColumnsButton preferenceKey='wave' /> </TopToolbar> @@ -132,28 +134,34 @@ > <StyledDatagrid preferenceKey='wave' bulkActionButtons={false} bulkActionButtons={ <> <BulkStartButton /> </> } rowClick={(id, resource, record) => false} expand={false} expandSingle={false} expand={<WavePannel />} expandSingle={true} omit={['id', 'createTime', 'createBy', 'memo', 'createBy$']} > <NumberField source="id" /> <TextField source="code" label="table.field.wave.code" /> <TextField source="type$" label="table.field.wave.type" sortable={false} /> <TextField source="exceStatus$" label="table.field.wave.exceStatus" sortable={false} /> <NumberField source="anfme" label="table.field.wave.anfme" /> <NumberField source="groupQty" label="table.field.wave.groupQty" /> <NumberField source="qty" label="table.field.wave.qty" /> <NumberField source="workQty" label="table.field.wave.qty" /> <NumberField source="orderNum" label="table.field.wave.orderNum" /> <DateField source="createTime" label="common.field.createTime" showTime /> <TextField source="updateBy$" label="common.field.updateBy" /> <DateField source="updateTime" label="common.field.updateTime" showTime /> <TextField source="createBy$" label="common.field.createBy" /> <DateField source="createTime" label="common.field.createTime" showTime /> <BooleanField source="statusBool" label="common.field.status" sortable={false} /> <TextField source="memo" label="common.field.memo" sortable={false} /> <CustomProcess source="progress" /> <TextField source="exceStatus$" label="table.field.wave.exceStatus" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt"> <PublicTaskButton setSelectIds={setSelectIds} setDetailDialog={setDetailDialog} /> <PauseButton /> <ContinueButton /> <EditButton label="toolbar.detail" sx={{ padding: '1px', fontSize: '.75rem' }} /> </WrapperField> </StyledDatagrid> @@ -179,6 +187,36 @@ export default WaveList; const BulkStartButton = () => { const { data, selectedIds, onUnselectItems } = useListContext(); // const waveId = useGetRecordId(); const notify = useNotify(); const refresh = useRefresh() const startClick = async () => { onUnselectItems(); const { data: { code, data, msg } } = await request.post('/wave/selects/task', { ids: selectedIds }); if (code === 200) { notify(msg); setAutoExce(false) } else { notify(msg); } } return ( <Button label="toolbar.publicWorking" onClick={startClick} startIcon={<PlayArrowOutlinedIcon />} variant="outlined" /> ) } const CustomProcess = () => { const record = useRecordContext(); const progress = (record.workQty / record.anfme) * 100 return ( <> <LinearProgress variant="determinate" value={progress} /> </> ) } const PublicTaskButton = ({ setSelectIds, setDetailDialog }) => { const record = useRecordContext(); const notify = useNotify(); @@ -194,7 +232,7 @@ ); } const BulkStartButton = ({ autoExce, setAutoExce }) => { const BulkAutoStartButton = ({ autoExce, setAutoExce }) => { const { data, selectedIds, onUnselectItems } = useListContext(); const notify = useNotify(); const startClick = async () => { @@ -212,7 +250,7 @@ ) } const BulkPauseButton = ({ autoExce, setAutoExce }) => { const BulkAutoPauseButton = ({ autoExce, setAutoExce }) => { const notify = useNotify(); const { data, selectedIds, onUnselectItems } = useListContext(); @@ -229,4 +267,40 @@ return ( autoExce ? <Button label="toolbar.pause" onClick={pauseClick} startIcon={<PauseCircleOutlineIcon />} /> : <></> ) } const PauseButton = () => { const notify = useNotify() const refresh = useRefresh(); const record = useRecordContext(); const pauseClick = async () => { const { data: { code, data, msg } } = await request.post('/wave/pause/pub/' + record?.id); if (code === 200) { notify(msg); } else { notify(msg); } refresh() } return ( record?.exceStatus == 1 ? <Button label="toolbar.pause" onClick={pauseClick} startIcon={<StopCircleOutlinedIcon />} /> : <></> ) } const ContinueButton = () => { const notify = useNotify() const refresh = useRefresh(); const record = useRecordContext(); const continueClick = async () => { const { data: { code, data, msg } } = await request.post('/wave/continue/pub/' + record?.id); if (code === 200) { notify(msg); } else { notify(msg); } refresh() } return ( record?.exceStatus == 2 ? <Button label="toolbar.continuePub" onClick={continueClick} startIcon={<PauseCircleOutlineIcon />} /> : <></> ) } rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -193,7 +193,7 @@ if (null == wave){ throw new CoolException("未找到容器号对应波次"); } wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_DONE.val); wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); if (!waveService.updateById(wave)){ throw new CoolException("波次单更新状态失败"); } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveController.java
@@ -1,6 +1,7 @@ package com.vincent.rsf.server.manager.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.framework.common.Cools; @@ -15,6 +16,8 @@ import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.entity.Wave; import com.vincent.rsf.server.manager.entity.WaveItem; import com.vincent.rsf.server.manager.enums.WaveExceStatus; import com.vincent.rsf.server.manager.enums.WaveItemExceStatus; import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.WaveService; import com.vincent.rsf.server.system.controller.BaseController; @@ -134,7 +137,7 @@ @ApiOperation("选择明细下发任务") @PostMapping("/wave/selects/task") public R waveToTask(@RequestBody Map<String, Object> map) { if (Cools.isEmpty(map) || Cools.isEmpty(map.get("wave"))) { if (Cools.isEmpty(map) || Cools.isEmpty(map.get("ids"))) { throw new CoolException("参数不能为空!!"); } return waveService.waveToTask(map, getLoginUserId()); @@ -154,7 +157,25 @@ return R.ok().add(pageResult); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("暂停下发任务") @PostMapping("/wave/pause/pub/{id}") public R pausePublicTask(@PathVariable Long id) { waveService.update(new LambdaUpdateWrapper<Wave>() .eq(Wave::getId, id) .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_PAUSE.val)); return R.ok(); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("继续下发任务") @PostMapping("/wave/continue/pub/{id}") public R continuePublicTask(@PathVariable Long id) { waveService.update(new LambdaUpdateWrapper<Wave>() .eq(Wave::getId, id) .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val)); return R.ok(); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaveItemController.java
@@ -109,26 +109,4 @@ public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { ExcelUtil.build(ExcelUtil.create(waveItemService.list(), WaveItem.class), response); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("暂停下发任务") @PostMapping("/waveItem/pause/pub/{id}") public R pausePublicTask(@PathVariable Long id) { waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .eq(WaveItem::getId, id) .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_ITEM_EXCE_PAUSE.val)); return R.ok(); } @PreAuthorize("hasAuthority('manager:waveItem:update')") @ApiOperation("继续下发任务") @PostMapping("/waveItem/continue/pub/{id}") public R continuePublicTask(@PathVariable Long id) { waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .eq(WaveItem::getId, id) .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val)); return R.ok(); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/WaveExceStatus.java
@@ -10,12 +10,12 @@ public enum WaveExceStatus { //波次执行状态 WAVE_EXCE_STATUS_INIT("0", "初始化"), WAVE_EXCE_STATUS_EXCING("1", "执行中"), WAVE_EXCE_STATUS_TASK("2", "生成任务"), WAVE_EXCE_STATUS_DONE("3", "任务完成"), ; WAVE_EXCE_STATUS_INIT("0", "等待执行"), WAVE_EXCE_STATUS_EXCING("1", "正在执行"), WAVE_EXCE_STATUS_PAUSE("2", "暂停执行"), WAVE_EXCE_STATUS_TASK("3", "执行完成"), ; WaveExceStatus(String val, String desc) { this.val = Short.parseShort(val); this.desc = desc; rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/WaveItemExceStatus.java
@@ -18,6 +18,7 @@ WAVE_EXCE_STATUS_DONE("4", "任务完成"), ; // 终止, 等待执行, 正在执行,执行完成 WaveItemExceStatus(String val, String desc) { this.val = Short.parseShort(val); this.desc = desc; rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/WaveSchedules.java
@@ -25,12 +25,12 @@ import java.util.stream.Collectors; /** * @author Ryan * @description 波次定时任务 * @param * @return * @time 2025/6/23 13:49 */ * @param * @author Ryan * @description 波次定时任务 * @return * @time 2025/6/23 13:49 */ @Component public class WaveSchedules { @@ -48,12 +48,12 @@ /** * @author Ryan * @description 自动下发波次任务 * @param * @return * @time 2025/6/23 13:52 */ * @param * @return * @author Ryan * @description 自动下发波次任务 * @time 2025/6/23 13:52 */ @Scheduled(cron = "0/15 * * * * ?") // @Transactional(rollbackFor = Exception.class) public void autoGenerateTask() { @@ -61,36 +61,26 @@ if (Objects.isNull(config) || !Boolean.parseBoolean(config.getVal())) { return; } // List<Wave> list = waveService.list(new LambdaQueryWrapper<Wave>() // .select(Wave::getId) // .in(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_INIT.val // , WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val)); // if (list.isEmpty()) { // return; // } // List<Long> longs = list.stream().map(Wave::getId).collect(Collectors.toList()); List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>() .in(WaveItem::getExceStatus, Arrays.asList(WaveItemExceStatus.WAVE_ITEM_EXCE_STATUS_UN.val , WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val))); waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val) .apply("anfme > work_qty") ); if (waveItems.isEmpty()) { List<Wave> list = waveService.list(new LambdaQueryWrapper<Wave>() .select(Wave::getId) .in(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_INIT.val , WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val)); if (list.isEmpty()) { return; } List<Long> longs = list.stream().map(Wave::getId).collect(Collectors.toList()); waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .in(WaveItem::getWaveId, longs) .set(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) .apply("anfme > work_qty")); Long loginUserId = SystemAuthUtils.getLoginUserId(); Map<Long, List<WaveItem>> listMap = waveItems.stream().collect(Collectors.groupingBy(WaveItem::getWaveId)); listMap.keySet().forEach(waveId -> { List<Long> itemIds = listMap.get(waveId).stream().map(WaveItem::getId).collect(Collectors.toList()); Map<String, Object> params = new HashMap<>(); params.put("wave", waveId); params.put("waveItem", itemIds); waveService.waveToTask(params, loginUserId); }); Map<String, Object> params = new HashMap<>(); params.put("ids", longs); waveService.waveToTask(params, loginUserId); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java
@@ -110,7 +110,6 @@ return R.ok(); } /** * 选择波次明细下发任务 * @@ -121,99 +120,94 @@ @Override @Transactional(rollbackFor = Exception.class) public R waveToTask(Map<String, Object> map, Long loginUserId) { if (Objects.isNull(map.get("waveItem"))) { if (Objects.isNull(map.get("ids"))) { throw new CoolException("参数不能为空!!"); } String waveId = map.get("wave").toString(); Wave waves = this.getById(Long.parseLong(waveId)); List<Long> WaveIds = JSONArray.parseArray(JSON.toJSONString(map.get("ids")), Long.class); List<Wave> waves = waveService.listByIds(WaveIds); if (Objects.isNull(waves)) { throw new CoolException("波次数据不存在!!"); throw new CoolException("数据错误: 波次不存在!!"); } List<Long> waveItems = JSONArray.parseArray(JSON.toJSONString(map.get("waveItem")), Long.class); if (waveItems.isEmpty()) { throw new CoolException("波次明细不能为空!!"); } List<WaveItem> items = waveItemService.listByIds(waveItems); if (items.isEmpty()) { throw new CoolException("波次明细不存在!!"); } if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val) .in(WaveItem::getId, waveItems))) { throw new CoolException("执行状态修改失败!!"); } WaveRule waveRule = waveRuleService.getOne(new LambdaQueryWrapper<WaveRule>() .eq(WaveRule::getType, WaveRuleType.First_In_First_Out.type)); if (Cools.isEmpty(waveRule)) { throw new CoolException("未找到当前策略"); } List<WaveToLocParams> params = new ArrayList<>(); for (WaveItem item : items) { WaveToLocParams locParams = new WaveToLocParams(); BeanUtils.copyProperties(item, locParams); locParams.setBatch(item.getSplrBatch()) .setItemId(item.getId()) .setWaveId(item.getWaveId()); params.add(locParams); } List<OrderOutItemDto> results = LocManageUtil.getOutOrderList(params, waveRule); if (results.isEmpty()) { Wave wave = waveService.getById(waveId); if (Objects.isNull(wave)) { throw new CoolException("<UNK>"); for (Wave wave : waves) { List<WaveItem> items = waveItemService.list(new LambdaQueryWrapper<WaveItem>().eq(WaveItem::getWaveId, wave.getId())); if (items.isEmpty()) { throw new CoolException("波次明细不存在!!"); } wave.setUpdateBy(loginUserId).setUpdateTime(new Date()); if (wave.getAnfme().compareTo(wave.getWorkQty()) == 0) { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); } else { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val); } waveService.updateById(wave); return R.ok(); } try { /**生成出库任务*/ generateOutTask(results, loginUserId, waves); } catch (Exception e) { log.error("UNK", e); throw new CoolException(e.getMessage()); } List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>() .in(TaskItem::getSource, waveItems)); if (Cools.isEmpty(taskItems)) { throw new CoolException("暂无合适库存信息!!"); } for (TaskItem item : taskItems) { WaveItem waveItem = waveItemService.getById(item.getSource()); Double workQty = Math.round((waveItem.getWorkQty() + item.getAnfme()) * 10000) / 10000.0; waveItem.setWorkQty(workQty); if (workQty.compareTo(waveItem.getAnfme()) < 0) { waveItem.setExceStatus(WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val); } else { waveItem.setExceStatus(WaveItemExceStatus.WAVE_EXCE_STATUS_PUBD.val); } List<Long> ids = items.stream().map(WaveItem::getId).collect(Collectors.toList()); if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_PUBD.val) .setSql("work_qty = work_qty + " + item.getAnfme()) .set(WaveItem::getUpdateBy, loginUserId) .set(WaveItem::getUpdateTime, new Date()) .eq(WaveItem::getId, item.getSource()))) { throw new CoolException("下发执行异常,请稍候重试!"); .set(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) .in(WaveItem::getId, ids))) { throw new CoolException("执行状态修改失败!!"); } WaveRule waveRule = waveRuleService.getOne(new LambdaQueryWrapper<WaveRule>() .eq(WaveRule::getType, WaveRuleType.First_In_First_Out.type)); if (Cools.isEmpty(waveRule)) { throw new CoolException("未找到当前策略"); } List<WaveToLocParams> params = new ArrayList<>(); for (WaveItem item : items) { WaveToLocParams locParams = new WaveToLocParams(); BeanUtils.copyProperties(item, locParams); locParams.setBatch(item.getSplrBatch()) .setItemId(item.getId()) .setWaveId(item.getWaveId()); params.add(locParams); } List<OrderOutItemDto> results = LocManageUtil.getOutOrderList(params, waveRule); if (results.isEmpty()) { wave.setUpdateBy(loginUserId).setUpdateTime(new Date()); if (wave.getAnfme().compareTo(wave.getWorkQty()) == 0) { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); } else { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val); } waveService.updateById(wave); return R.ok(); } try { /**生成出库任务*/ generateOutTask(results, loginUserId, wave); } catch (Exception e) { log.error("UNK", e); throw new CoolException(e.getMessage()); } List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>() .in(TaskItem::getSource, ids)); if (Cools.isEmpty(taskItems)) { throw new CoolException("暂无合适库存信息!!"); } for (TaskItem item : taskItems) { WaveItem waveItem = waveItemService.getById(item.getSource()); Double workQty = Math.round((waveItem.getWorkQty() + item.getAnfme()) * 10000) / 10000.0; waveItem.setWorkQty(workQty); if (workQty.compareTo(waveItem.getAnfme()) < 0) { waveItem.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val); } else { waveItem.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); } if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() .set(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .setSql("work_qty = work_qty + " + item.getAnfme()) .set(WaveItem::getUpdateBy, loginUserId) .set(WaveItem::getUpdateTime, new Date()) .eq(WaveItem::getId, item.getSource()))) { throw new CoolException("下发执行异常,请稍候重试!"); } } if (!waveService.update(new LambdaUpdateWrapper<Wave>() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .set(Wave::getWorkQty, taskItems.stream().mapToDouble(TaskItem::getAnfme).sum()) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, wave.getId()))) { throw new CoolException("波次状态修改失败!!"); } } if (!waveService.update(new LambdaUpdateWrapper<Wave>() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .set(Wave::getWorkQty, taskItems.stream().mapToDouble(TaskItem::getAnfme).sum()) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, waveId))) { throw new CoolException("波次状态修改失败!!"); } return R.ok(); }