package cn.iocoder.yudao.module.mes.controller.admin.pro.qrexport;
|
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.qrexport.vo.MesProQrExportCountRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.qrexport.vo.MesProQrExportTaskRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.qrexport.vo.MesProQrExportTaskSubmitReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.qrexport.MesProQrExportTaskDO;
|
import cn.iocoder.yudao.module.mes.enums.pro.MesProQrExportBizTypeEnum;
|
import cn.iocoder.yudao.module.mes.enums.pro.MesProQrExportTaskStatusEnum;
|
import cn.iocoder.yudao.module.mes.framework.qrexport.MesProQrExportProperties;
|
import cn.iocoder.yudao.module.mes.service.pro.qrexport.MesProQrExportTaskService;
|
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import jakarta.annotation.Resource;
|
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.validation.Valid;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.validation.annotation.Validated;
|
import org.springframework.web.bind.annotation.*;
|
|
import java.io.IOException;
|
|
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_EXPORT_PARAMS_INVALID;
|
|
/**
|
* 二维码大批量导出任务接口
|
* <p>
|
* 数量不超过分界线的导出不走这里(调用方直接调原下载接口,秒级返回、不排队);
|
* 超过分界线才提交任务、轮询进度、完成后下载。
|
* <p>
|
* 说明:下载与取消未额外限制「只能操作自己创建的任务」。能进入本接口的用户已持有对应模块的导出权限,
|
* 也就已经可以直接调用同步导出接口拿到同样的 ZIP 内容,再加一层创建人校验并不能提供实际保护。
|
*/
|
@Tag(name = "管理后台 - MES 二维码导出任务")
|
@RestController
|
@RequestMapping("/mes/pro/qr-export")
|
@Validated
|
public class MesProQrExportTaskController {
|
|
/**
|
* 任一模块的导出权限即可访问本接口;具体业务类型再逐项校验
|
*/
|
private static final String ANY_EXPORT_PERMISSION =
|
"@ss.hasAnyPermissions('mes:pro-bag-code:export','mes:pro-pallet:export','mes:pro-batch:export')";
|
|
@Resource
|
private MesProQrExportTaskService taskService;
|
@Resource
|
private MesProQrExportProperties properties;
|
@Resource
|
private SecurityFrameworkService securityFrameworkService;
|
|
@GetMapping("/count")
|
@Operation(summary = "统计二维码导出张数并给出导出方式(SYNC 直接下载 / ASYNC 后台任务)")
|
@PreAuthorize(ANY_EXPORT_PERMISSION)
|
public CommonResult<MesProQrExportCountRespVO> count(@RequestParam("bizType") String bizType,
|
@RequestParam(value = "uuid", required = false) String uuid,
|
@RequestParam(value = "batchId", required = false) Long batchId) {
|
MesProQrExportBizTypeEnum bizTypeEnum = resolveBizType(bizType);
|
assertBizPermission(bizTypeEnum);
|
long total = taskService.countLabels(bizTypeEnum, uuid, batchId);
|
MesProQrExportCountRespVO respVO = new MesProQrExportCountRespVO();
|
respVO.setTotalCount(total);
|
respVO.setSyncThreshold(properties.getSyncThreshold());
|
respVO.setMode(total > properties.getSyncThreshold()
|
? MesProQrExportCountRespVO.MODE_ASYNC : MesProQrExportCountRespVO.MODE_SYNC);
|
return success(respVO);
|
}
|
|
@PostMapping("/task")
|
@Operation(summary = "提交二维码后台导出任务(大批量)")
|
@PreAuthorize(ANY_EXPORT_PERMISSION)
|
public CommonResult<MesProQrExportTaskRespVO> submit(@Valid @RequestBody MesProQrExportTaskSubmitReqVO reqVO) {
|
MesProQrExportBizTypeEnum bizTypeEnum = resolveBizType(reqVO.getBizType());
|
assertBizPermission(bizTypeEnum);
|
MesProQrExportTaskDO task = taskService.submit(bizTypeEnum, reqVO.getUuid(), reqVO.getBatchId());
|
return success(convert(task));
|
}
|
|
@GetMapping("/task/get")
|
@Operation(summary = "获得二维码导出任务(用于轮询进度)")
|
@Parameter(name = "id", description = "任务编号", required = true, example = "1024")
|
@PreAuthorize(ANY_EXPORT_PERMISSION)
|
public CommonResult<MesProQrExportTaskRespVO> get(@RequestParam("id") Long id) {
|
return success(convert(taskService.getTask(id)));
|
}
|
|
@PostMapping("/task/cancel")
|
@Operation(summary = "取消二维码导出任务")
|
@Parameter(name = "id", description = "任务编号", required = true, example = "1024")
|
@PreAuthorize(ANY_EXPORT_PERMISSION)
|
public CommonResult<Boolean> cancel(@RequestParam("id") Long id) {
|
taskService.cancel(id);
|
return success(true);
|
}
|
|
@GetMapping("/task/download")
|
@Operation(summary = "下载二维码导出产物(下载完成后系统立即删除临时文件)")
|
@Parameter(name = "id", description = "任务编号", required = true, example = "1024")
|
@PreAuthorize(ANY_EXPORT_PERMISSION)
|
public void download(@RequestParam("id") Long id, HttpServletResponse response) throws IOException {
|
taskService.download(id, response);
|
}
|
|
// ==================== 私有方法 ====================
|
|
private MesProQrExportBizTypeEnum resolveBizType(String bizType) {
|
for (MesProQrExportBizTypeEnum value : MesProQrExportBizTypeEnum.values()) {
|
if (value.getType().equals(bizType)) {
|
return value;
|
}
|
}
|
throw exception(PRO_QR_EXPORT_PARAMS_INVALID);
|
}
|
|
/**
|
* 校验业务类型对应的模块导出权限
|
* <p>
|
* 单靠「任一导出权限」会让只有托盘导出权限的用户也能导出袋码,故按类型再校验一次。
|
*/
|
private void assertBizPermission(MesProQrExportBizTypeEnum bizType) {
|
String permission = switch (bizType) {
|
case BAG_LABEL, BAG_BUSINESS -> "mes:pro-bag-code:export";
|
case PALLET_LABEL, PALLET_BUSINESS -> "mes:pro-pallet:export";
|
case BATCH_LABEL, BATCH_BUSINESS -> "mes:pro-batch:export";
|
};
|
if (!securityFrameworkService.hasAnyPermissions(permission)) {
|
throw exception(FORBIDDEN);
|
}
|
}
|
|
private MesProQrExportTaskRespVO convert(MesProQrExportTaskDO task) {
|
MesProQrExportTaskRespVO respVO = new MesProQrExportTaskRespVO();
|
respVO.setId(task.getId());
|
respVO.setBizType(task.getBizType());
|
respVO.setTaskName(task.getTaskName());
|
respVO.setStatus(task.getStatus());
|
MesProQrExportTaskStatusEnum statusEnum = parseStatus(task.getStatus());
|
respVO.setStatusName(statusEnum == null ? null : statusEnum.getName());
|
respVO.setTotalCount(task.getTotalCount());
|
respVO.setFinishedCount(task.getFinishedCount());
|
respVO.setProgress(calcProgress(task));
|
respVO.setFileSize(task.getFileSize());
|
respVO.setErrorMsg(task.getErrorMsg());
|
respVO.setDownloadable(MesProQrExportTaskStatusEnum.FINISHED.getStatus().equals(task.getStatus())
|
&& task.getFilePath() != null && !task.getFilePath().isBlank());
|
respVO.setCreateTime(task.getCreateTime());
|
respVO.setFinishTime(task.getFinishTime());
|
return respVO;
|
}
|
|
private Integer calcProgress(MesProQrExportTaskDO task) {
|
Integer total = task.getTotalCount();
|
if (total == null || total <= 0) {
|
return 0;
|
}
|
int finished = task.getFinishedCount() == null ? 0 : task.getFinishedCount();
|
return (int) Math.min(100L, (long) finished * 100 / total);
|
}
|
|
private MesProQrExportTaskStatusEnum parseStatus(Integer status) {
|
if (status == null) {
|
return null;
|
}
|
for (MesProQrExportTaskStatusEnum value : MesProQrExportTaskStatusEnum.values()) {
|
if (value.getStatus().equals(status)) {
|
return value;
|
}
|
}
|
return null;
|
}
|
|
}
|