rsf-admin/src/i18n/en.js
@@ -783,6 +783,9 @@ siteInit: 'site init', batch: 'batch', confirm: 'confirm', cancel: "cancel", top: "top", resort: "sort", subzone: 'subzone', bindmatnr: 'bind matnr', bindloc: 'bind loc', rsf-admin/src/i18n/zh.js
@@ -795,6 +795,9 @@ siteInit: '站点初始化', batch: '批量操作', confirm: '确认', cancel: "取消", top: "置顶", resort: "排序", subzone: '绑定分区', bindmatnr: '绑定物料', bindloc: '绑定库位', rsf-admin/src/page/task/TaskList.jsx
@@ -31,6 +31,7 @@ ReferenceArrayInput, AutocompleteInput, DeleteButton, Button, } from 'react-admin'; import { Box, Typography, Card, Stack } from '@mui/material'; import { styled } from '@mui/material/styles'; @@ -39,6 +40,10 @@ import EmptyData from "../components/EmptyData"; import MyCreateButton from "../components/MyCreateButton"; import MyExportButton from '../components/MyExportButton'; import SwapVertIcon from '@mui/icons-material/SwapVert'; import AlignVerticalTopIcon from '@mui/icons-material/AlignVerticalTop'; import TaskAltIcon from '@mui/icons-material/TaskAlt'; import CancelIcon from '@mui/icons-material/Cancel'; import PageDrawer from "../components/PageDrawer"; import MyField from "../components/MyField"; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; @@ -62,7 +67,6 @@ <SearchInput source="condition" alwaysOn />, <DateInput label='common.time.after' source="timeStart" alwaysOn />, <DateInput label='common.time.before' source="timeEnd" alwaysOn />, <TextInput source="taskCode" label="table.field.task.taskCode" />, <NumberInput source="taskStatus" label="table.field.task.taskStatus" />, <NumberInput source="taskType" label="table.field.task.taskType" />, @@ -92,7 +96,6 @@ const TaskList = () => { const translate = useTranslate(); const [createDialog, setCreateDialog] = useState(false); const [drawerVal, setDrawerVal] = useState(false); @@ -108,26 +111,33 @@ marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} title={"menu.task"} empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} // empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} filters={filters} sort={{ field: "create_time", order: "desc" }} actions={( <TopToolbar> <FilterButton /> <MyCreateButton onClick={() => { setCreateDialog(true) }} /> {/* <MyCreateButton onClick={() => { setCreateDialog(true) }} /> */} <SelectColumnsButton preferenceKey='task' /> <MyExportButton /> {/* <MyExportButton /> */} </TopToolbar> )} perPage={DEFAULT_PAGE_SIZE} > <StyledDatagrid preferenceKey='task' bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} // bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} bulkActionButtons={ <> <BulkResortButton /> <BulkCancelButton /> <BulkDeleteButton mutationMode={OPERATE_MODE} /> </> } rowClick={(id, resource, record) => false} expand={() => <TaskPanel />} expandSingle={true} omit={['id', 'createTime', 'createBy', 'memo']} // expand={() => <TaskPanel />} // expandSingle={true} omit={['id', 'createTime', 'createBy', 'memo', 'robotCode', 'exceStatus', 'expDesc', 'expCode', 'sort']} > <NumberField source="id" /> <TextField source="taskCode" label="table.field.task.taskCode" /> @@ -154,15 +164,17 @@ <BooleanField source="statusBool" label="common.field.status" sortable={false} /> <TextField source="memo" label="common.field.memo" sortable={false} /> <WrapperField cellClassName="opt" label="common.field.opt"> <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> {/* <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> */} <DoneButton sx={{ padding: '1px', fontSize: '.75rem' }} ></DoneButton> <CancelButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> <SetTopButton sx={{ padding: '1px', fontSize: '.75rem' }} ></SetTopButton> </WrapperField> </StyledDatagrid> </List> <TaskCreate {/* <TaskCreate open={createDialog} setOpen={setCreateDialog} /> /> */} <PageDrawer title='Task Detail' drawerVal={drawerVal} @@ -174,3 +186,102 @@ } export default TaskList; /** * 完成操作 * @returns */ const DoneButton = () => { const record = useRecordContext(); const clickComplete = () => { completeTask([record]) }; //完成任务 const completeTask = async (row) => { } return ( <Button onClick={clickComplete} label="toolbar.complete"> <TaskAltIcon /> </Button> ) } /** * 取消按钮 * @returns */ const CancelButton = () => { const record = useRecordContext(); const clickCancel = () => { cancleTask([record]) }; //取消任务 const cancleTask = async (row) => {} return ( <Button onClick={clickCancel} label="toolbar.cancel"> <CancelIcon /> </Button> ) } /** * 置顶操作 * @returns */ const SetTopButton = () => { const record = useRecordContext(); const clickTop = () => { topTask([record]) }; //置顶任务 const topTask = async (row) => { } return ( <Button onClick={clickTop} label="toolbar.top"> <AlignVerticalTopIcon /> </Button> ) } /** * 批量取消 * @returns */ const BulkCancelButton = () => { const record = useRecordContext(); const clickCancel = () => { cancleTask([record]) }; //取消任务 const cancleTask = async (row) => {} return ( <Button onClick={clickCancel} label="toolbar.cancel"> <CancelIcon /> </Button> ) } /** * 批量排序 * @returns */ const BulkResortButton = () => { const record = useRecordContext(); const bulkResort = () => { resortTask([record]) }; //批量排序 const resortTask = async (row) => { } return ( <Button onClick={bulkResort} label="toolbar.resort"> <SwapVertIcon /> </Button> ) } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/MobileController.java
@@ -89,7 +89,6 @@ return mobileService.receiptToWarehouse(params); } @PreAuthorize("hasAuthority('manager:asnOrder:list')") @PostMapping("/orders/other") @ApiOperation("其它扫码收货") @@ -186,6 +185,7 @@ return mobileService.confirmIspt(id); } @ApiOperation("快速质检信息") @PreAuthorize("hasAuthority('manager:qlyInspect:list')") @PostMapping("/inspect/query") public R checkObjs(@RequestBody CheckObjParams params) { @@ -196,6 +196,7 @@ } @ApiOperation("快带质检") @PreAuthorize("hasAuthority('manager:qlyInspect:update')") @PostMapping("/inspect/check/update") public R checkUpdate(@RequestBody QlyIsptItem params) { rsf-server/src/main/java/com/vincent/rsf/server/api/entity/dto/CheckObjDto.java
@@ -28,12 +28,16 @@ private String splrBatch; @ApiModelProperty("收货数量") private Double rcptQty; @ApiModelProperty("送货数量") private Double dlyQty; @ApiModelProperty("合格数量") private Double safeQty; @ApiModelProperty("不合格数量") private Double disQty; @ApiModelProperty("图片路径") private String picPath; @ApiModelProperty("质检结果") private String isptResult; @ApiModelProperty("备注") private String memo; } rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/MobileServiceImpl.java
@@ -525,7 +525,9 @@ .setMatnrCode(isptItem.getMatnrCode()) .setMaktx(isptItem.getMaktx()) .setDisQty(isptItem.getDisQty()) .setDlyQty(isptItem.getDlyQty()) .setRcptQty(isptItem.getRcptQty()) .setIsptResult(isptItem.getIsptResult()) .setSplrBatch(isptItem.getSplrBatch()) .setSplrName(isptItem.getSplrName()) .setPicPath(isptItem.getPicPath()) rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.utils.ExcelUtil; import com.vincent.rsf.server.common.annotation.OperationLog; import com.vincent.rsf.server.common.domain.BaseParam; @@ -14,6 +15,7 @@ import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.TaskService; import com.vincent.rsf.server.system.controller.BaseController; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -121,4 +123,15 @@ ExcelUtil.build(ExcelUtil.create(taskService.list(), Task.class), response); } @PreAuthorize("hasAuthority('manager:task:update')") @ApiOperation("完成任务") @GetMapping("/task/complete/{id}") public R completeTask(@PathVariable String id) { if (Objects.isNull(id)) { throw new CoolException("参数不能为空!!"); } return taskService.completeTask(id); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinController.java
@@ -11,8 +11,10 @@ import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.server.manager.controller.params.WaitPakinParam; import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.entity.WaitPakin; import com.vincent.rsf.server.manager.entity.WaitPakinItem; import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.TaskService; import com.vincent.rsf.server.manager.service.WaitPakinItemService; import com.vincent.rsf.server.manager.service.WaitPakinService; @@ -22,10 +24,12 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.*; import java.util.stream.Collectors; @Api(tags = "组拖通知档") @RestController @@ -39,6 +43,8 @@ @Autowired private TaskService taskService; @Autowired private TaskItemService taskItemService; @PreAuthorize("hasAuthority('manager:waitPakin:list')") @PostMapping("/waitPakin/page") @@ -100,15 +106,23 @@ @PreAuthorize("hasAuthority('manager:waitPakin:remove')") @OperationLog("Delete 组拖档") @PostMapping("/waitPakin/remove/{ids}") @Transactional(rollbackFor = Exception.class) public R remove(@PathVariable Long[] ids) { List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>() .in(WaitPakinItem::getPakinId, ids)); if (!pakinItems.isEmpty()) { return R.error("组拖档有明细任务"); List<Long> list = pakinItems.stream().map(WaitPakinItem::getId).collect(Collectors.toList()); List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getSource, list)); if (!taskItems.isEmpty()) { return R.error("组拖档有明细任务"); } } if (!waitPakinService.removeByIds(Arrays.asList(ids))) { return R.error("Delete Fail"); } if (!waitPakinItemService.removeByIds(pakinItems)) { throw new CoolException("明细删除失败!!"); } return R.ok("Delete Success").add(ids); } rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WaitPakinItemController.java
@@ -4,12 +4,15 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.utils.ExcelUtil; import com.vincent.rsf.server.common.annotation.OperationLog; import com.vincent.rsf.server.common.domain.BaseParam; import com.vincent.rsf.server.common.domain.KeyValVo; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.entity.WaitPakinItem; import com.vincent.rsf.server.manager.service.TaskItemService; import com.vincent.rsf.server.manager.service.WaitPakinItemService; import com.vincent.rsf.server.system.controller.BaseController; import io.swagger.annotations.Api; @@ -26,6 +29,8 @@ @Autowired private WaitPakinItemService waitPakinItemService; @Autowired private TaskItemService taskItemService; @PreAuthorize("hasAuthority('manager:waitPakinItem:list')") @PostMapping("/waitPakinItem/page") @@ -83,6 +88,13 @@ @OperationLog("Delete 组拖档明细") @PostMapping("/waitPakinItem/remove/{ids}") public R remove(@PathVariable Long[] ids) { if (Objects.isNull(ids) || ids.length < 1) { return R.error("参数不能为空!!"); } List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().in(TaskItem::getSource, ids)); if (!taskItems.isEmpty()) { throw new CoolException("有任务明细未完成"); } if (!waitPakinItemService.removeByIds(Arrays.asList(ids))) { return R.error("Delete Fail"); } rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/StockItem.java
@@ -35,6 +35,12 @@ private Long id; /** * 任务明细ID */ @ApiModelProperty("任务明细ID") private Long taskItemId; /** * 库存外键标识 */ @ApiModelProperty(value= "库存外键标识") rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java
New file @@ -0,0 +1,58 @@ package com.vincent.rsf.server.manager.schedules; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.api.entity.enums.TaskStsType; import com.vincent.rsf.server.manager.entity.Task; import com.vincent.rsf.server.manager.entity.TaskItem; import com.vincent.rsf.server.manager.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; /** * @Author Ryan * 任务工作档 */ @Component public class TaskSchedules { @Autowired private TaskService taskService; @Autowired private TaskItemService taskItemService; @Autowired private StockItemService stockItemService; @Autowired private StockService stockService; @Autowired private LocService locService; /** * @author Ryan * @description 完成入库,更新库存 * @param * @return * @time 2025/4/2 12:37 */ @Scheduled(cron = "0 0/05 * * * ? ") @Transactional(rollbackFor = Exception.class) public void completeInStock() { List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id)); if (tasks.isEmpty()) { return; } List<Long> list = tasks.stream().map(Task::getId).collect(Collectors.toList()); List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, list)); if (taskItems.isEmpty()) { throw new CoolException("任务明细为空!!"); } taskItems.forEach(item -> { }); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java
@@ -10,4 +10,6 @@ public interface TaskService extends IService<Task> { R generateTasks(List<WaitPakin> waitPakin, Long loginUserId); R completeTask(String id); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -1,6 +1,7 @@ package com.vincent.rsf.server.manager.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.vincent.rsf.server.api.entity.enums.OrderType; import com.vincent.rsf.server.api.entity.enums.TaskStsType; import com.vincent.rsf.framework.common.R; @@ -12,11 +13,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.vincent.rsf.server.manager.utils.LocManageUtil; import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.enums.LocStsType; import com.vincent.rsf.server.system.utils.SerialRuleUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; @@ -32,6 +35,9 @@ private TaskItemService taskItemService; @Autowired private WaitPakinItemService waitPakinItemService; @Autowired private LocService locService; @@ -44,7 +50,8 @@ * @time 2025/3/29 15:59 */ @Override public R generateTasks(List<WaitPakin> waitPakin, Long loginUserId) { @Transactional(rollbackFor = Exception.class) public synchronized R generateTasks(List<WaitPakin> waitPakin, Long loginUserId) { if (Objects.isNull(waitPakin) || waitPakin.isEmpty()) { throw new CoolException("参数不能为空!!"); } @@ -73,6 +80,11 @@ if (!this.save(task)) { throw new CoolException("任务保存失败!!"); } if (!locService.update(new LambdaUpdateWrapper<Loc>().eq(Loc::getCode, pakin.getCode()) .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_S.type).set(Loc::getBarcode, pakin.getBarcode()))) { throw new CoolException("库位预约失败!!"); } /**获取组拖明细**/ List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, pakin.getId())); if (waitPakinItems.isEmpty()) { @@ -93,14 +105,23 @@ if (!taskItemService.saveBatch(taskItems)) { throw new CoolException("任务明细保存失败!!"); } }); //TODO 任务生成完成需修改任务ASN订单状态为执行中,组拖删除需判断是否有子任务在执行 return R.ok("任务生成完毕!"); } /** * @author Ryan * @description 完成任务 * @param * @return * @time 2025/4/2 11:15 */ @Override @Transactional(rollbackFor = Exception.class) public R completeTask(String id) { return null; } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaitPakinServiceImpl.java
@@ -5,20 +5,15 @@ import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.manager.controller.params.PakinItem; import com.vincent.rsf.server.manager.controller.params.WaitPakinParam; import com.vincent.rsf.server.manager.entity.AsnOrder; import com.vincent.rsf.server.manager.entity.AsnOrderItem; import com.vincent.rsf.server.manager.entity.WaitPakinItem; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.mapper.WaitPakinMapper; import com.vincent.rsf.server.manager.entity.WaitPakin; import com.vincent.rsf.server.manager.service.AsnOrderItemService; import com.vincent.rsf.server.manager.service.AsnOrderService; import com.vincent.rsf.server.manager.service.WaitPakinItemService; import com.vincent.rsf.server.manager.service.WaitPakinService; import com.vincent.rsf.server.manager.service.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.utils.SerialRuleUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -40,6 +35,8 @@ private WaitPakinService waitPakinService; @Autowired private WaitPakinItemService waitPakinItemService; @Autowired private LocService locService; /** * @author Ryan @@ -58,6 +55,20 @@ throw new CoolException("参数错误:托盘码为空!!"); } List<WaitPakin> list = waitPakinService.list(new LambdaQueryWrapper<WaitPakin>().eq(WaitPakin::getBarcode, waitPakin.getBarcode())); if (!list.isEmpty()) { List<String> stringList = list.stream().map(WaitPakin::getCode).collect(Collectors.toList()); String join = StringUtils.join(stringList, ","); throw new CoolException("拖盘码:" + waitPakin.getBarcode() + "已被组拖单:" + join + "使用!!"); } List<Loc> locs = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, waitPakin.getBarcode())); if (!locs.isEmpty()) { List<String> locCodes = locs.stream().map(Loc::getCode).collect(Collectors.toList()); String join = StringUtils.join(locCodes, ","); throw new CoolException("拖盘码:" + waitPakin.getBarcode() + "已被库位:" + join + "使用!!"); } double sum = waitPakin.getItems().stream().mapToDouble(PakinItem::getReceiptQty).sum(); WaitPakin pakin = new WaitPakin();