Compare commits
75 Commits
0aaa01f4bf
...
test.X
| Author | SHA1 | Date | |
|---|---|---|---|
| 75a2623d8b | |||
| 5d046be15b | |||
|
|
fef2f132d0 | ||
|
|
1038b17a66 | ||
|
|
bd5e0ac5e9 | ||
| 896c6b89ca | |||
| a8e94ac34d | |||
|
|
f389576c92 | ||
|
|
a2b90f3b72 | ||
|
|
693edbb543 | ||
| 194c481e12 | |||
| 0050af7677 | |||
|
|
d3da84f65e | ||
|
|
c532d7f753 | ||
| 7736ac3311 | |||
| b660ddcc3e | |||
| e6c588af63 | |||
| 7a78ad3eb7 | |||
| db379748f2 | |||
|
|
44013170f5 | ||
| e5acc06e1c | |||
| 71159a496b | |||
| 141d0a1c4e | |||
| e5147564ce | |||
|
|
273d7c44b7 | ||
|
|
4fdddac389 | ||
|
|
3afac814c4 | ||
|
|
cbfea329f0 | ||
| 5b0e35ce03 | |||
|
|
e3727abebf | ||
|
|
a024be0858 | ||
| bc99d985f5 | |||
| 1f6b3a9ace | |||
| 7bb102a17f | |||
| 78a7bb4123 | |||
| 0edeb429c6 | |||
| f9c192a5b4 | |||
| 88741bc062 | |||
| 17e6f793c7 | |||
|
|
f6c60226ba | ||
| b257afdb6b | |||
|
|
9e24368d4c | ||
| 428e94d4f9 | |||
| 4a11ae2079 | |||
| e8b40d2fa3 | |||
| f30fd06dc4 | |||
| 86812a655b | |||
| 0e6357253a | |||
| 612fd8bf12 | |||
| 625ef6330b | |||
|
|
3e343f5a07 | ||
|
|
15e59c10da | ||
| 04de7e267c | |||
| ffc42d110a | |||
| dfd2ba15d9 | |||
| 28839275d2 | |||
| 0b5fe00d94 | |||
| 5c6a3c4981 | |||
|
|
8659847e96 | ||
|
|
721c48d6a4 | ||
|
|
d601dc8320 | ||
|
|
ee05f031a4 | ||
| 2bfecfbbb2 | |||
| f6681b73af | |||
|
|
03bf7f7398 | ||
|
|
341606c051 | ||
| 8b47e91598 | |||
|
|
f26960e4c7 | ||
| 8d9613a350 | |||
| 181f0726d8 | |||
|
|
9ed926e4ce | ||
|
|
261f55dded | ||
|
|
a4b77f9654 | ||
| 66bb295acb | |||
| 8a540096f5 |
@@ -119,6 +119,10 @@
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-reader</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-aps</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
25
klp-aps/pom.xml
Normal file
25
klp-aps/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-oa</artifactId>
|
||||
<version>0.8.3</version>
|
||||
</parent>
|
||||
<artifactId>klp-aps</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.klp</groupId>
|
||||
<artifactId>klp-wms</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.aps.domain.bo.ApsCalendarBo;
|
||||
import com.klp.aps.domain.vo.ApsCalendarVo;
|
||||
import com.klp.aps.service.ApsCalendarService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工厂日历Controller
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/calendar")
|
||||
public class ApsCalendarController extends BaseController {
|
||||
|
||||
private final ApsCalendarService apsCalendarService;
|
||||
|
||||
/**
|
||||
* 查询工厂日历列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ApsCalendarVo> list(ApsCalendarBo bo, PageQuery pageQuery) {
|
||||
return apsCalendarService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出工厂日历列表
|
||||
*/
|
||||
@Log(title = "工厂日历", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ApsCalendarBo bo, HttpServletResponse response) {
|
||||
List<ApsCalendarVo> list = apsCalendarService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "工厂日历", ApsCalendarVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工厂日历详细信息
|
||||
*/
|
||||
@GetMapping("/{calendarId}")
|
||||
public R<ApsCalendarVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long calendarId) {
|
||||
return R.ok(apsCalendarService.queryById(calendarId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增工厂日历
|
||||
*/
|
||||
@Log(title = "工厂日历", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsCalendarBo bo) {
|
||||
return toAjax(apsCalendarService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改工厂日历
|
||||
*/
|
||||
@Log(title = "工厂日历", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsCalendarBo bo) {
|
||||
return toAjax(apsCalendarService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除工厂日历
|
||||
*/
|
||||
@Log(title = "工厂日历", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{calendarIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] calendarIds) {
|
||||
return toAjax(apsCalendarService.deleteWithValidByIds(Arrays.asList(calendarIds), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.aps.domain.bo.ApsCalendarShiftBo;
|
||||
import com.klp.aps.domain.vo.ApsCalendarShiftVo;
|
||||
import com.klp.aps.service.ApsCalendarShiftService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 日历班次配置Controller
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/calendar-shift")
|
||||
public class ApsCalendarShiftController extends BaseController {
|
||||
|
||||
private final ApsCalendarShiftService apsCalendarShiftService;
|
||||
|
||||
/**
|
||||
* 查询日历班次配置列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ApsCalendarShiftVo> list(ApsCalendarShiftBo bo, PageQuery pageQuery) {
|
||||
return apsCalendarShiftService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出日历班次配置列表
|
||||
*/
|
||||
@Log(title = "日历班次配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ApsCalendarShiftBo bo, HttpServletResponse response) {
|
||||
List<ApsCalendarShiftVo> list = apsCalendarShiftService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "日历班次配置", ApsCalendarShiftVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日历班次配置详细信息
|
||||
*/
|
||||
@GetMapping("/{configId}")
|
||||
public R<ApsCalendarShiftVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long configId) {
|
||||
return R.ok(apsCalendarShiftService.queryById(configId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增日历班次配置
|
||||
*/
|
||||
@Log(title = "日历班次配置", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsCalendarShiftBo bo) {
|
||||
return toAjax(apsCalendarShiftService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改日历班次配置
|
||||
*/
|
||||
@Log(title = "日历班次配置", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsCalendarShiftBo bo) {
|
||||
return toAjax(apsCalendarShiftService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除日历班次配置
|
||||
*/
|
||||
@Log(title = "日历班次配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{configIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] configIds) {
|
||||
return toAjax(apsCalendarShiftService.deleteWithValidByIds(Arrays.asList(configIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 一键生成全年工作日日历
|
||||
*/
|
||||
@Log(title = "日历班次配置", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/generate-workday-year/{year}")
|
||||
public R<Integer> generateWorkdayYear(@PathVariable Integer year,
|
||||
@RequestParam(value = "overwriteExisting", required = false, defaultValue = "false") Boolean overwriteExisting) {
|
||||
return R.ok(apsCalendarShiftService.generateWorkdayForYear(year, overwriteExisting));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsGanttQueryReq;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarRespVo;
|
||||
import com.klp.aps.domain.vo.ApsGanttItemVo;
|
||||
import com.klp.aps.service.ApsGanttService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* APS 甘特图查询(MVP)
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps")
|
||||
public class ApsGanttController extends BaseController {
|
||||
|
||||
private final ApsGanttService apsGanttService;
|
||||
|
||||
/**
|
||||
* GET /aps/gantt
|
||||
* 参数:lineId/queryStart/queryEnd/planId/orderId
|
||||
*/
|
||||
@GetMapping("/gantt")
|
||||
public R<List<ApsGanttItemVo>> gantt(@Validated ApsGanttQueryReq req) {
|
||||
return R.ok(apsGanttService.selectGanttItems(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 工厂日历聚合接口(减轻前端计算压力)
|
||||
*/
|
||||
@GetMapping("/factory-calendar")
|
||||
public R<ApsFactoryCalendarRespVo> factoryCalendar(@Validated ApsGanttQueryReq req) {
|
||||
return R.ok(apsGanttService.queryFactoryCalendar(req));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.aps.domain.bo.ApsLineCapabilityBo;
|
||||
import com.klp.aps.domain.vo.ApsLineCapabilityVo;
|
||||
import com.klp.aps.service.ApsLineCapabilityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 产线能力Controller
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/line-capability")
|
||||
public class ApsLineCapabilityController extends BaseController {
|
||||
|
||||
private final ApsLineCapabilityService apsLineCapabilityService;
|
||||
|
||||
/**
|
||||
* 查询产线能力列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ApsLineCapabilityVo> list(ApsLineCapabilityBo bo, PageQuery pageQuery) {
|
||||
return apsLineCapabilityService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出产线能力列表
|
||||
*/
|
||||
@Log(title = "产线能力", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ApsLineCapabilityBo bo, HttpServletResponse response) {
|
||||
List<ApsLineCapabilityVo> list = apsLineCapabilityService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "产线能力", ApsLineCapabilityVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产线能力详细信息
|
||||
*/
|
||||
@GetMapping("/{capabilityId}")
|
||||
public R<ApsLineCapabilityVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long capabilityId) {
|
||||
return R.ok(apsLineCapabilityService.queryById(capabilityId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增产线能力
|
||||
*/
|
||||
@Log(title = "产线能力", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsLineCapabilityBo bo) {
|
||||
return toAjax(apsLineCapabilityService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改产线能力
|
||||
*/
|
||||
@Log(title = "产线能力", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsLineCapabilityBo bo) {
|
||||
return toAjax(apsLineCapabilityService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除产线能力
|
||||
*/
|
||||
@Log(title = "产线能力", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{capabilityIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] capabilityIds) {
|
||||
return toAjax(apsLineCapabilityService.deleteWithValidByIds(Arrays.asList(capabilityIds), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsLockReq;
|
||||
import com.klp.aps.service.ApsLockService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
/**
|
||||
* APS 锁定/解锁
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps")
|
||||
public class ApsLockController extends BaseController {
|
||||
|
||||
private final ApsLockService apsLockService;
|
||||
|
||||
/**
|
||||
* POST /aps/lock
|
||||
*/
|
||||
@PostMapping("/lock")
|
||||
public R<Long> lock(@Validated @RequestBody ApsLockReq req) {
|
||||
Long lockId = apsLockService.createLock(req, getUsername());
|
||||
return R.ok(lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /aps/lock/release/{lockId}
|
||||
*/
|
||||
@PostMapping("/lock/release/{lockId}")
|
||||
public R<Void> release(@PathVariable Long lockId) {
|
||||
apsLockService.releaseLock(lockId, getUsername());
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsRescheduleReq;
|
||||
import com.klp.aps.service.ApsOperationService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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;
|
||||
|
||||
/**
|
||||
* APS 工序级操作(重排等)
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/operation")
|
||||
public class ApsOperationController extends BaseController {
|
||||
|
||||
private final ApsOperationService apsOperationService;
|
||||
|
||||
/**
|
||||
* POST /aps/operation/reschedule
|
||||
*/
|
||||
@PostMapping("/reschedule")
|
||||
public R<Void> reschedule(@Validated @RequestBody ApsRescheduleReq req) {
|
||||
apsOperationService.reschedule(req, getUsername());
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsConvertFromCrmReq;
|
||||
import com.klp.aps.domain.dto.ApsConvertFromCrmResp;
|
||||
import com.klp.aps.domain.dto.ApsConvertFromProductReq;
|
||||
import com.klp.aps.domain.dto.ApsConvertFromProductsReq;
|
||||
import com.klp.aps.service.ApsPlanService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/order")
|
||||
public class ApsOrderController extends BaseController {
|
||||
|
||||
private final ApsPlanService apsPlanService;
|
||||
|
||||
@PostMapping("/convert-from-crm")
|
||||
public R<ApsConvertFromCrmResp> convertFromCrm(@Validated @RequestBody ApsConvertFromCrmReq req) {
|
||||
Long wmsOrderId = apsPlanService.convertFromCrmOrderWithItems(req.getCrmOrderId(), req.getCrmItemIds(), getUsername());
|
||||
return R.ok(new ApsConvertFromCrmResp(wmsOrderId, null));
|
||||
}
|
||||
|
||||
@PostMapping("/convert-from-product")
|
||||
public R<ApsConvertFromCrmResp> convertFromProduct(@Validated @RequestBody ApsConvertFromProductReq req) {
|
||||
Long wmsOrderId = apsPlanService.convertFromProduct(
|
||||
req.getProductId(),
|
||||
req.getQuantity(),
|
||||
req.getProductName(),
|
||||
req.getRemark(),
|
||||
getUsername()
|
||||
);
|
||||
return R.ok(new ApsConvertFromCrmResp(wmsOrderId, null));
|
||||
}
|
||||
|
||||
@PostMapping("/convert-from-products")
|
||||
public R<ApsConvertFromCrmResp> convertFromProducts(@Validated @RequestBody ApsConvertFromProductsReq req) {
|
||||
Long wmsOrderId = apsPlanService.convertFromProducts(req.getItems(), req.getRemark(), getUsername());
|
||||
return R.ok(new ApsConvertFromCrmResp(wmsOrderId, null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsAutoScheduleReq;
|
||||
import com.klp.aps.domain.dto.ApsPlanCreateReq;
|
||||
import com.klp.aps.service.ApsAutoScheduleService;
|
||||
import com.klp.aps.service.ApsPlanService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* APS 计划(MVP)
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/plan")
|
||||
public class ApsPlanController extends BaseController {
|
||||
|
||||
private final ApsPlanService apsPlanService;
|
||||
private final ApsAutoScheduleService apsAutoScheduleService;
|
||||
|
||||
/**
|
||||
* POST /aps/plan/create
|
||||
* 创建计划头与明细,返回 planId
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public R<Long> create(@Validated @RequestBody ApsPlanCreateReq req) {
|
||||
Long planId = apsPlanService.createPlan(req, getUsername());
|
||||
return R.ok(planId);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /aps/plan/auto-schedule
|
||||
* 自动排程生成 operation + change_log,并更新 plan 状态
|
||||
*/
|
||||
@PostMapping("/auto-schedule")
|
||||
public R<Void> autoSchedule(@Validated @RequestBody ApsAutoScheduleReq req) {
|
||||
apsAutoScheduleService.autoSchedule(req, getUsername());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /aps/plan/publish/{planId}
|
||||
* 仅允许已排产(plan.status=1) 的计划发布,状态流转为 2(已发布/生产中)
|
||||
*/
|
||||
@PostMapping("/publish/{planId}")
|
||||
public R<Void> publish(@PathVariable Long planId) {
|
||||
apsPlanService.publishPlan(planId, getUsername());
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetQueryReq;
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetSupplementSaveReq;
|
||||
import com.klp.aps.domain.vo.ApsScheduleSheetResp;
|
||||
import com.klp.aps.service.ApsScheduleSheetService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 统一排产表(查询 + 导出)
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps")
|
||||
public class ApsScheduleSheetController extends BaseController {
|
||||
|
||||
private final ApsScheduleSheetService apsScheduleSheetService;
|
||||
|
||||
/**
|
||||
* GET /aps/schedule-sheet
|
||||
*/
|
||||
@GetMapping("/schedule-sheet")
|
||||
public R<ApsScheduleSheetResp> query(@Validated ApsScheduleSheetQueryReq req) {
|
||||
return R.ok(apsScheduleSheetService.query(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /aps/schedule-sheet/export
|
||||
*/
|
||||
@GetMapping("/schedule-sheet/export")
|
||||
public void export(@Validated ApsScheduleSheetQueryReq req, HttpServletResponse response) {
|
||||
apsScheduleSheetService.exportExcel(req, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /aps/schedule-sheet/supplement/save
|
||||
*/
|
||||
@PostMapping("/schedule-sheet/supplement/save")
|
||||
public R<Void> saveSupplement(@Validated @RequestBody ApsScheduleSheetSupplementSaveReq req) {
|
||||
apsScheduleSheetService.saveSupplement(req, getUsername());
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.klp.aps.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.aps.domain.bo.ApsShiftTemplateBo;
|
||||
import com.klp.aps.domain.vo.ApsShiftTemplateVo;
|
||||
import com.klp.aps.service.ApsShiftTemplateService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 班次模板Controller
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/aps/shift-template")
|
||||
public class ApsShiftTemplateController extends BaseController {
|
||||
|
||||
private final ApsShiftTemplateService apsShiftTemplateService;
|
||||
|
||||
/**
|
||||
* 查询班次模板列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ApsShiftTemplateVo> list(ApsShiftTemplateBo bo, PageQuery pageQuery) {
|
||||
return apsShiftTemplateService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出班次模板列表
|
||||
*/
|
||||
@Log(title = "班次模板", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ApsShiftTemplateBo bo, HttpServletResponse response) {
|
||||
List<ApsShiftTemplateVo> list = apsShiftTemplateService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "班次模板", ApsShiftTemplateVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班次模板详细信息
|
||||
*/
|
||||
@GetMapping("/{shiftId}")
|
||||
public R<ApsShiftTemplateVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long shiftId) {
|
||||
return R.ok(apsShiftTemplateService.queryById(shiftId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增班次模板
|
||||
*/
|
||||
@Log(title = "班次模板", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsShiftTemplateBo bo) {
|
||||
return toAjax(apsShiftTemplateService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改班次模板
|
||||
*/
|
||||
@Log(title = "班次模板", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsShiftTemplateBo bo) {
|
||||
return toAjax(apsShiftTemplateService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除班次模板
|
||||
*/
|
||||
@Log(title = "班次模板", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{shiftIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] shiftIds) {
|
||||
return toAjax(apsShiftTemplateService.deleteWithValidByIds(Arrays.asList(shiftIds), true));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.klp.aps.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 工厂日历业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApsCalendarBo extends BaseEntity {
|
||||
|
||||
private Long calendarId;
|
||||
|
||||
@NotNull(message = "日期不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private LocalDate calendarDate;
|
||||
|
||||
@NotNull(message = "日历类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Integer calendarType;
|
||||
|
||||
private String factoryCode;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.klp.aps.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 日历班次配置业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApsCalendarShiftBo extends BaseEntity {
|
||||
|
||||
private Long configId;
|
||||
|
||||
@NotNull(message = "日期不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate calendarDate;
|
||||
|
||||
@NotNull(message = "产线ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long lineId;
|
||||
|
||||
@NotNull(message = "班次ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long shiftId;
|
||||
|
||||
private BigDecimal plannedHours;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.klp.aps.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 产线能力业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApsLineCapabilityBo extends BaseEntity {
|
||||
|
||||
private Long capabilityId;
|
||||
|
||||
@NotNull(message = "产线ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long lineId;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private Long processId;
|
||||
|
||||
@NotNull(message = "每小时产能不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private BigDecimal capacityPerHour;
|
||||
|
||||
private Integer setupMinutes;
|
||||
|
||||
private Integer priority;
|
||||
|
||||
private Integer isEnabled;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.klp.aps.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 班次模板业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApsShiftTemplateBo extends BaseEntity {
|
||||
|
||||
private Long shiftId;
|
||||
|
||||
@NotBlank(message = "班次编码不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String shiftCode;
|
||||
|
||||
@NotBlank(message = "班次名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String shiftName;
|
||||
|
||||
@NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private LocalTime startTime;
|
||||
|
||||
@NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private LocalTime endTime;
|
||||
|
||||
private Integer crossDay;
|
||||
|
||||
private BigDecimal efficiencyRate;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 自动排程请求
|
||||
*/
|
||||
@Data
|
||||
public class ApsAutoScheduleReq {
|
||||
/** 必填:计划ID */
|
||||
@NotNull(message = "planId 不能为空")
|
||||
private Long planId;
|
||||
|
||||
/** 是否清理旧排程(默认 true,仅删除未锁定记录) */
|
||||
private Boolean clearOld;
|
||||
|
||||
/** 备注/预留 */
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApsConvertFromCrmReq {
|
||||
|
||||
@NotBlank(message = "crmOrderId 不能为空")
|
||||
private String crmOrderId;
|
||||
|
||||
/**
|
||||
* 可选:指定转换的 CRM 明细 itemId 列表;为空则转换该订单全部明细
|
||||
*/
|
||||
private List<String> crmItemIds;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ApsConvertFromCrmResp {
|
||||
|
||||
private Long wmsOrderId;
|
||||
private String wmsOrderCode;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.DecimalMin;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ApsConvertFromProductReq {
|
||||
|
||||
@NotNull(message = "productId 不能为空")
|
||||
private Long productId;
|
||||
|
||||
@NotNull(message = "quantity 不能为空")
|
||||
@DecimalMin(value = "0.0001", message = "quantity 必须大于 0")
|
||||
private BigDecimal quantity;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApsConvertFromProductsReq {
|
||||
|
||||
@Valid
|
||||
@NotEmpty(message = "items 不能为空")
|
||||
private List<ApsConvertFromProductReq> items;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 甘特查询参数
|
||||
*/
|
||||
@Data
|
||||
public class ApsGanttQueryReq {
|
||||
/** 可空:不传则查全部产线 */
|
||||
private Long lineId;
|
||||
|
||||
/** 必填:查询开始时间 */
|
||||
@NotNull(message = "queryStart 不能为空")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime queryStart;
|
||||
|
||||
/** 必填:查询结束时间 */
|
||||
@NotNull(message = "queryEnd 不能为空")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime queryEnd;
|
||||
|
||||
/** 可空:按计划过滤 */
|
||||
private Long planId;
|
||||
|
||||
/** 可空:按订单过滤 */
|
||||
private Long orderId;
|
||||
}
|
||||
|
||||
30
klp-aps/src/main/java/com/klp/aps/domain/dto/ApsLockReq.java
Normal file
30
klp-aps/src/main/java/com/klp/aps/domain/dto/ApsLockReq.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 排产锁定请求
|
||||
*/
|
||||
@Data
|
||||
public class ApsLockReq {
|
||||
|
||||
/**
|
||||
* 锁定类型:1计划 2产线时间窗 3工序
|
||||
*/
|
||||
private Integer lockType;
|
||||
|
||||
private Long planId;
|
||||
|
||||
private Long lineId;
|
||||
|
||||
private Long operationId;
|
||||
|
||||
private LocalDateTime lockStartTime;
|
||||
|
||||
private LocalDateTime lockEndTime;
|
||||
|
||||
private String lockReason;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 创建计划请求
|
||||
*/
|
||||
@Data
|
||||
public class ApsPlanCreateReq {
|
||||
/** 必填:订单ID */
|
||||
@NotNull(message = "orderId 不能为空")
|
||||
private Long orderId;
|
||||
|
||||
/** 可空:排产计划编号,不传则后端生成 */
|
||||
private String planCode;
|
||||
|
||||
/** 可空:版本,不传默认 V1 */
|
||||
private String version;
|
||||
|
||||
/** 可空:优先级(0低 1中 2高 3VIP) */
|
||||
private Integer priority;
|
||||
|
||||
/** 可空:目标产线ID(不传则按默认产线) */
|
||||
private Long lineId;
|
||||
|
||||
/** 可空:计划开始时间 */
|
||||
private LocalDateTime startDate;
|
||||
|
||||
/** 可空:计划结束时间 */
|
||||
private LocalDateTime endDate;
|
||||
|
||||
/** 可空:备注 */
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 单工序重排请求
|
||||
*/
|
||||
@Data
|
||||
public class ApsRescheduleReq {
|
||||
|
||||
/** 必填:工序排程ID */
|
||||
@NotNull(message = "operationId 不能为空")
|
||||
private Long operationId;
|
||||
|
||||
/** 必填:目标产线ID */
|
||||
@NotNull(message = "targetLineId 不能为空")
|
||||
private Long targetLineId;
|
||||
|
||||
/** 必填:目标开始时间 */
|
||||
@NotNull(message = "targetStartTime 不能为空")
|
||||
private LocalDateTime targetStartTime;
|
||||
|
||||
/** 必填:目标结束时间 */
|
||||
@NotNull(message = "targetEndTime 不能为空")
|
||||
private LocalDateTime targetEndTime;
|
||||
|
||||
/** 必填:重排原因 */
|
||||
@NotNull(message = "reason 不能为空")
|
||||
private String reason;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 统一排产表查询参数(MVP)
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleSheetQueryReq {
|
||||
/** 可空:计划查询关键字(支持 planId 或 planCode) */
|
||||
private String planId;
|
||||
|
||||
/** 可空:订单查询关键字(支持 orderId 或 orderCode) */
|
||||
private String orderId;
|
||||
|
||||
/** 可空:产线ID(不传查全部产线) */
|
||||
private Long lineId;
|
||||
|
||||
/** 必填:查询开始时间 */
|
||||
@NotNull(message = "queryStart 不能为空")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime queryStart;
|
||||
|
||||
/** 必填:查询结束时间 */
|
||||
@NotNull(message = "queryEnd 不能为空")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime queryEnd;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApsScheduleSheetSupplementSaveReq {
|
||||
|
||||
@Valid
|
||||
@NotEmpty(message = "rows 不能为空")
|
||||
private List<Row> rows;
|
||||
|
||||
@Data
|
||||
public static class Row {
|
||||
@NotNull(message = "operationId 不能为空")
|
||||
private Long operationId;
|
||||
|
||||
private Long rawMaterialId;
|
||||
private String rawCoilNos;
|
||||
private BigDecimal rawNetWeight;
|
||||
private String rawPackaging;
|
||||
private String rawEdgeReq;
|
||||
private String rawCoatingType;
|
||||
private String rawLocation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ApsWmsOrderCreateReq {
|
||||
|
||||
private String orderCode;
|
||||
private Long customerId;
|
||||
private String customerName;
|
||||
private String salesManager;
|
||||
private Integer orderStatus;
|
||||
private String remark;
|
||||
private BigDecimal taxAmount;
|
||||
private BigDecimal noTaxAmount;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.klp.aps.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ApsWmsOrderDetailCreateReq {
|
||||
|
||||
private Long orderId;
|
||||
private Long productId;
|
||||
private BigDecimal quantity;
|
||||
private String unit;
|
||||
private String remark;
|
||||
private BigDecimal taxPrice;
|
||||
private BigDecimal noTaxPrice;
|
||||
private Long groupId;
|
||||
private Integer delFlag;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 工厂日历实体 wms_calendar
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wms_calendar")
|
||||
public class ApsCalendarEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "calendar_id", type = IdType.AUTO)
|
||||
private Long calendarId;
|
||||
|
||||
private LocalDate calendarDate;
|
||||
|
||||
private Integer calendarType;
|
||||
|
||||
private String factoryCode;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 日历班次配置实体 wms_calendar_shift
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wms_calendar_shift")
|
||||
public class ApsCalendarShiftEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "config_id", type = IdType.AUTO)
|
||||
private Long configId;
|
||||
|
||||
private LocalDate calendarDate;
|
||||
|
||||
private Long lineId;
|
||||
|
||||
private Long shiftId;
|
||||
|
||||
private BigDecimal plannedHours;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 产线能力实体 wms_line_capability
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wms_line_capability")
|
||||
public class ApsLineCapabilityEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "capability_id", type = IdType.AUTO)
|
||||
private Long capabilityId;
|
||||
|
||||
private Long lineId;
|
||||
|
||||
private Long productId;
|
||||
|
||||
private Long processId;
|
||||
|
||||
private BigDecimal capacityPerHour;
|
||||
|
||||
private Integer setupMinutes;
|
||||
|
||||
private Integer priority;
|
||||
|
||||
private Integer isEnabled;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* wms_schedule_change_log(APS 自动排程审计)
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleChangeLogEntity {
|
||||
private Long logId;
|
||||
private Long operationId;
|
||||
private String changeType;
|
||||
private String beforeValue;
|
||||
private String afterValue;
|
||||
private String changeReason;
|
||||
private String changeBy;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* wms_schedule_lock
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleLockEntity {
|
||||
private Long lockId;
|
||||
private Integer lockType;
|
||||
private Long planId;
|
||||
private Long lineId;
|
||||
private Long operationId;
|
||||
private LocalDateTime lockStartTime;
|
||||
private LocalDateTime lockEndTime;
|
||||
private String lockReason;
|
||||
private Integer status;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* wms_schedule_operation(APS 自动排程落库)
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleOperationEntity {
|
||||
private Long operationId;
|
||||
private Long planId;
|
||||
private Long detailId;
|
||||
private Long orderId;
|
||||
private Long orderDetailId;
|
||||
private Long productId;
|
||||
private Long processId;
|
||||
private Long lineId;
|
||||
private Integer sequenceNo;
|
||||
private BigDecimal planQty;
|
||||
private LocalDateTime startTime;
|
||||
private LocalDateTime endTime;
|
||||
private Integer setupMinutes;
|
||||
private Integer status;
|
||||
private Integer lockedFlag;
|
||||
private String remark;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* wms_schedule_plan_detail(仅用于 APS MVP 插入)
|
||||
*/
|
||||
@Data
|
||||
public class ApsSchedulePlanDetailEntity {
|
||||
private Long detailId;
|
||||
private Long planId;
|
||||
private Long lineId;
|
||||
private Long taskId;
|
||||
private Long productId;
|
||||
private BigDecimal quantity;
|
||||
private LocalDate startDate;
|
||||
private LocalDate endDate;
|
||||
private String remark;
|
||||
private Integer delFlag;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* wms_schedule_plan(仅用于 APS MVP 插入/回填主键)
|
||||
*/
|
||||
@Data
|
||||
public class ApsSchedulePlanEntity {
|
||||
private Long planId;
|
||||
private String planCode;
|
||||
private String version;
|
||||
private Long orderId;
|
||||
private Integer status;
|
||||
private String remark;
|
||||
private Integer delFlag;
|
||||
private String createBy;
|
||||
private String updateBy;
|
||||
private Integer priority;
|
||||
private LocalDateTime startDate;
|
||||
private LocalDateTime endDate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.klp.aps.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 班次模板实体 wms_shift_template
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("wms_shift_template")
|
||||
public class ApsShiftTemplateEntity extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "shift_id", type = IdType.AUTO)
|
||||
private Long shiftId;
|
||||
|
||||
private String shiftCode;
|
||||
|
||||
private String shiftName;
|
||||
|
||||
private LocalTime startTime;
|
||||
|
||||
private LocalTime endTime;
|
||||
|
||||
private Integer crossDay;
|
||||
|
||||
private BigDecimal efficiencyRate;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ApsCrmOrderItemRow {
|
||||
|
||||
private String itemId;
|
||||
private String orderId;
|
||||
private String productType;
|
||||
private Long productNum;
|
||||
private BigDecimal contractPrice;
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ApsCrmOrderRow {
|
||||
|
||||
private String orderId;
|
||||
private String orderCode;
|
||||
private String customerId;
|
||||
private String salesman;
|
||||
private BigDecimal orderAmount;
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 产线能力(wms_line_capability)最小行
|
||||
*/
|
||||
@Data
|
||||
public class ApsLineCapabilityRow {
|
||||
private Long lineId;
|
||||
private BigDecimal capacityPerHour;
|
||||
private Integer setupMinutes;
|
||||
private Integer priority;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApsLineMetaRow {
|
||||
private Long lineId;
|
||||
private String lineName;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* wms_order_detail 最小取数行
|
||||
*/
|
||||
@Data
|
||||
public class ApsOrderDetailRow {
|
||||
private Long detailId;
|
||||
private Long productId;
|
||||
private BigDecimal quantity;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 计划明细最小行(用于自动排程)
|
||||
*/
|
||||
@Data
|
||||
public class ApsPlanDetailRow {
|
||||
private Long detailId;
|
||||
private Long taskId;
|
||||
private Long lineId;
|
||||
private Long productId;
|
||||
private BigDecimal quantity;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApsProductMetaRow {
|
||||
private Long productId;
|
||||
private String productName;
|
||||
private String specification;
|
||||
private String material;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 产品工艺路线(wms_product_processe)最小行
|
||||
*/
|
||||
@Data
|
||||
public class ApsProductProcessRow {
|
||||
private Long processId;
|
||||
private Integer processSequence;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* wms_schedule_plan 最小行(用于自动排程)
|
||||
*/
|
||||
@Data
|
||||
public class ApsSchedulePlanRow {
|
||||
private Long planId;
|
||||
private String planCode;
|
||||
private String version;
|
||||
private Long orderId;
|
||||
private Integer status;
|
||||
private LocalDateTime startDate;
|
||||
private LocalDateTime endDate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 日历班次时段(wms_calendar_shift + wms_shift_template)
|
||||
*/
|
||||
@Data
|
||||
public class ApsShiftSlotRow {
|
||||
private LocalDate calendarDate;
|
||||
private Long lineId;
|
||||
private Long shiftId;
|
||||
private BigDecimal plannedHours;
|
||||
private LocalTime startTime;
|
||||
private LocalTime endTime;
|
||||
private Integer crossDay;
|
||||
private BigDecimal efficiencyRate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.klp.aps.domain.row;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApsWmsOrderRow {
|
||||
|
||||
private Long orderId;
|
||||
private String orderCode;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 日历班次配置视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApsCalendarShiftVo {
|
||||
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long configId;
|
||||
|
||||
@ExcelProperty(value = "日期")
|
||||
private LocalDate calendarDate;
|
||||
|
||||
@ExcelProperty(value = "产线ID")
|
||||
private Long lineId;
|
||||
|
||||
@ExcelProperty(value = "产线名称")
|
||||
private String lineName;
|
||||
|
||||
@ExcelProperty(value = "班次ID")
|
||||
private Long shiftId;
|
||||
|
||||
@ExcelProperty(value = "班次名称")
|
||||
private String shiftName;
|
||||
|
||||
@ExcelProperty(value = "计划工时")
|
||||
private BigDecimal plannedHours;
|
||||
|
||||
@ExcelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
@ExcelProperty(value = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 工厂日历视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApsCalendarVo {
|
||||
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long calendarId;
|
||||
|
||||
@ExcelProperty(value = "日期")
|
||||
private LocalDate calendarDate;
|
||||
|
||||
@ExcelProperty(value = "日历类型")
|
||||
private Integer calendarType;
|
||||
|
||||
@ExcelProperty(value = "日历类型名称")
|
||||
private String calendarTypeName;
|
||||
|
||||
@ExcelProperty(value = "工厂编码")
|
||||
private String factoryCode;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApsFactoryCalendarDayVo {
|
||||
private Integer taskCount = 0;
|
||||
private Integer shiftCount = 0;
|
||||
private Integer lineCount = 0;
|
||||
/** 1=工作日,0=休息日,null=未知 */
|
||||
private Integer dayStatus;
|
||||
private List<ApsFactoryCalendarTaskLiteVo> tasks = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApsFactoryCalendarOverviewVo {
|
||||
private Integer taskCount;
|
||||
private Integer activeLineCount;
|
||||
private Integer totalLineCount;
|
||||
private Integer shiftCount;
|
||||
private String totalHours;
|
||||
private String peakDayText;
|
||||
private String busiestLineText;
|
||||
private String busiestLineShiftText;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ApsFactoryCalendarRespVo {
|
||||
private ApsFactoryCalendarOverviewVo overview;
|
||||
private List<String> dateList;
|
||||
private Map<Long, String> lineNameMap;
|
||||
private Map<Long, String> shiftNameMap;
|
||||
private Map<String, ApsFactoryCalendarDayVo> lineDayMap;
|
||||
private Map<String, ApsFactoryCalendarDayVo> lineShiftDayMap;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApsFactoryCalendarTaskLiteVo {
|
||||
private String label;
|
||||
private String title;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 甘特图条目返回
|
||||
*/
|
||||
@Data
|
||||
public class ApsGanttItemVo {
|
||||
private Long operationId;
|
||||
private Long planId;
|
||||
private String planCode;
|
||||
private Long orderId;
|
||||
private Long orderDetailId;
|
||||
private Long productId;
|
||||
private String productName;
|
||||
private String material;
|
||||
private String specification;
|
||||
private Long processId;
|
||||
private String processName;
|
||||
private Long lineId;
|
||||
private String lineName;
|
||||
private Integer sequenceNo;
|
||||
private BigDecimal planQty;
|
||||
private LocalDateTime startTime;
|
||||
private LocalDateTime endTime;
|
||||
private Integer status;
|
||||
private Integer lockedFlag;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 产线能力视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApsLineCapabilityVo {
|
||||
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long capabilityId;
|
||||
|
||||
@ExcelProperty(value = "产线ID")
|
||||
private Long lineId;
|
||||
|
||||
@ExcelProperty(value = "产线名称")
|
||||
private String lineName;
|
||||
|
||||
@ExcelProperty(value = "产品ID")
|
||||
private Long productId;
|
||||
|
||||
@ExcelProperty(value = "产品名称")
|
||||
private String productName;
|
||||
|
||||
@ExcelProperty(value = "工序ID")
|
||||
private Long processId;
|
||||
|
||||
@ExcelProperty(value = "工序名称")
|
||||
private String processName;
|
||||
|
||||
@ExcelProperty(value = "每小时产能")
|
||||
private BigDecimal capacityPerHour;
|
||||
|
||||
@ExcelProperty(value = "换产时间(分钟)")
|
||||
private Integer setupMinutes;
|
||||
|
||||
@ExcelProperty(value = "优先级")
|
||||
private Integer priority;
|
||||
|
||||
@ExcelProperty(value = "是否启用")
|
||||
private Integer isEnabled;
|
||||
|
||||
@ExcelProperty(value = "是否启用名称")
|
||||
private String isEnabledName;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 统一排产表返回
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleSheetResp {
|
||||
/** 表头元信息(可扩展:计划号/日期/机组等) */
|
||||
private Map<String, Object> header;
|
||||
|
||||
/** 明细行 */
|
||||
private List<ApsScheduleSheetRowVo> rows;
|
||||
|
||||
/** 合计 */
|
||||
private Summary summary;
|
||||
|
||||
@Data
|
||||
public static class Summary {
|
||||
private Integer totalCount;
|
||||
private BigDecimal totalPlanQty;
|
||||
private BigDecimal totalRawNetWeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 统一排产表行(前端统一展示用)
|
||||
*
|
||||
* 说明:字段是“统一超集”,不同机组可只展示子集,但表头保持一致。
|
||||
*/
|
||||
@Data
|
||||
public class ApsScheduleSheetRowVo {
|
||||
/** 排程主键 */
|
||||
private Long operationId;
|
||||
|
||||
/** 产线 */
|
||||
private Long lineId;
|
||||
private String lineName;
|
||||
|
||||
/** 计划/订单 */
|
||||
private Long planId;
|
||||
private String planCode;
|
||||
private Long orderId;
|
||||
private String orderCode;
|
||||
|
||||
/** 销售信息 */
|
||||
private String salesman;
|
||||
private String customerName;
|
||||
|
||||
/** 产品/工序 */
|
||||
private Long productId;
|
||||
private String productName;
|
||||
private String material;
|
||||
private String specification;
|
||||
private Long processId;
|
||||
private String processName;
|
||||
|
||||
/** 排程数量/时间 */
|
||||
private BigDecimal planQty;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
|
||||
/** 原料钢卷(来自 wms_material_coil 的展示字段,MVP:按 productId 兜底关联) */
|
||||
private Long rawMaterialId; // 回填钢卷ID
|
||||
private String rawCoilNos; // current_coil_no 逗号分隔
|
||||
private String rawLocation; // 实际库位名称
|
||||
private BigDecimal rawNetWeight; // 合计净重(吨/或 kg,按库表单位展示)
|
||||
private String rawPackaging; // packaging_requirement
|
||||
private String rawEdgeReq; // trimming_requirement
|
||||
private String rawCoatingType; // coating_type
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.klp.aps.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 班次模板视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ApsShiftTemplateVo {
|
||||
|
||||
@ExcelProperty(value = "主键")
|
||||
private Long shiftId;
|
||||
|
||||
@ExcelProperty(value = "班次编码")
|
||||
private String shiftCode;
|
||||
|
||||
@ExcelProperty(value = "班次名称")
|
||||
private String shiftName;
|
||||
|
||||
@ExcelProperty(value = "开始时间")
|
||||
private LocalTime startTime;
|
||||
|
||||
@ExcelProperty(value = "结束时间")
|
||||
private LocalTime endTime;
|
||||
|
||||
@ExcelProperty(value = "跨天标识")
|
||||
private Integer crossDay;
|
||||
|
||||
@ExcelProperty(value = "跨天标识名称")
|
||||
private String crossDayName;
|
||||
|
||||
@ExcelProperty(value = "效率系数")
|
||||
private BigDecimal efficiencyRate;
|
||||
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.entity.ApsScheduleChangeLogEntity;
|
||||
import com.klp.aps.domain.entity.ApsScheduleOperationEntity;
|
||||
import com.klp.aps.domain.row.ApsLineCapabilityRow;
|
||||
import com.klp.aps.domain.row.ApsLineMetaRow;
|
||||
import com.klp.aps.domain.row.ApsOrderDetailRow;
|
||||
import com.klp.aps.domain.row.ApsPlanDetailRow;
|
||||
import com.klp.aps.domain.row.ApsProductMetaRow;
|
||||
import com.klp.aps.domain.row.ApsSchedulePlanRow;
|
||||
import com.klp.aps.domain.row.ApsShiftSlotRow;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface ApsAutoScheduleMapper {
|
||||
|
||||
ApsSchedulePlanRow selectPlanByIdForUpdate(@Param("planId") Long planId);
|
||||
|
||||
List<ApsOrderDetailRow> selectOrderDetailsByOrderId(@Param("orderId") Long orderId);
|
||||
|
||||
List<ApsPlanDetailRow> selectPlanDetailsByPlanId(@Param("planId") Long planId);
|
||||
|
||||
List<ApsLineCapabilityRow> selectLineCandidatesByProductAndLine(@Param("productId") Long productId,
|
||||
@Param("lineId") Long lineId);
|
||||
|
||||
ApsLineMetaRow selectLineMetaById(@Param("lineId") Long lineId);
|
||||
|
||||
ApsProductMetaRow selectProductMetaById(@Param("productId") Long productId);
|
||||
|
||||
List<ApsShiftSlotRow> selectAvailableShifts(@Param("lineId") Long lineId,
|
||||
@Param("startDate") LocalDate startDate,
|
||||
@Param("endDate") LocalDate endDate);
|
||||
|
||||
Long selectPlanDetailId(@Param("planId") Long planId, @Param("taskId") Long taskId);
|
||||
|
||||
int deleteUnlockedOperationsByPlanId(@Param("planId") Long planId);
|
||||
|
||||
/**
|
||||
* 返回冲突记录的 end_time(若无冲突返回 null)
|
||||
*/
|
||||
LocalDateTime selectFirstConflictEndTime(@Param("lineId") Long lineId,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("excludeOperationId") Long excludeOperationId);
|
||||
|
||||
/**
|
||||
* 返回命中锁定的 lock_end_time(若未命中返回 null)
|
||||
*/
|
||||
LocalDateTime selectFirstHitLockEndTime(@Param("lineId") Long lineId,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("planId") Long planId,
|
||||
@Param("excludeOperationId") Long excludeOperationId);
|
||||
|
||||
int insertOperation(ApsScheduleOperationEntity op);
|
||||
|
||||
int insertChangeLog(ApsScheduleChangeLogEntity log);
|
||||
|
||||
int updatePlanStatus(@Param("planId") Long planId, @Param("status") Integer status, @Param("updateBy") String updateBy);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.klp.aps.domain.entity.ApsCalendarEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工厂日历Mapper接口
|
||||
*/
|
||||
public interface ApsCalendarMapper extends BaseMapper<ApsCalendarEntity> {
|
||||
|
||||
/**
|
||||
* 查询工厂日历列表
|
||||
*/
|
||||
List<ApsCalendarEntity> selectCalendarList(@Param("calendarDate") LocalDate calendarDate,
|
||||
@Param("calendarType") Integer calendarType,
|
||||
@Param("factoryCode") String factoryCode);
|
||||
|
||||
/**
|
||||
* 根据日期和工厂编码查询
|
||||
*/
|
||||
ApsCalendarEntity selectByDateAndFactory(@Param("calendarDate") LocalDate calendarDate,
|
||||
@Param("factoryCode") String factoryCode);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.klp.aps.domain.entity.ApsCalendarShiftEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 日历班次配置Mapper接口
|
||||
*/
|
||||
public interface ApsCalendarShiftMapper extends BaseMapper<ApsCalendarShiftEntity> {
|
||||
|
||||
/**
|
||||
* 根据日期、产线和班次查询
|
||||
*/
|
||||
ApsCalendarShiftEntity selectByDateLineAndShift(@Param("calendarDate") LocalDate calendarDate,
|
||||
@Param("lineId") Long lineId,
|
||||
@Param("shiftId") Long shiftId);
|
||||
|
||||
List<Long> selectDistinctLineIds();
|
||||
}
|
||||
11
klp-aps/src/main/java/com/klp/aps/mapper/ApsGanttMapper.java
Normal file
11
klp-aps/src/main/java/com/klp/aps/mapper/ApsGanttMapper.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsGanttQueryReq;
|
||||
import com.klp.aps.domain.vo.ApsGanttItemVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApsGanttMapper {
|
||||
List<ApsGanttItemVo> selectGanttItems(ApsGanttQueryReq req);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.klp.aps.domain.entity.ApsLineCapabilityEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 产线能力Mapper接口
|
||||
*/
|
||||
public interface ApsLineCapabilityMapper extends BaseMapper<ApsLineCapabilityEntity> {
|
||||
|
||||
/**
|
||||
* 根据产线、产品、工序查询
|
||||
*/
|
||||
ApsLineCapabilityEntity selectByLineProductAndProcess(@Param("lineId") Long lineId,
|
||||
@Param("productId") Long productId,
|
||||
@Param("processId") Long processId);
|
||||
}
|
||||
14
klp-aps/src/main/java/com/klp/aps/mapper/ApsLockMapper.java
Normal file
14
klp-aps/src/main/java/com/klp/aps/mapper/ApsLockMapper.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.entity.ApsScheduleLockEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface ApsLockMapper {
|
||||
|
||||
int insertLock(ApsScheduleLockEntity lock);
|
||||
|
||||
int updateLockStatus(@Param("lockId") Long lockId,
|
||||
@Param("status") Integer status,
|
||||
@Param("updateBy") String updateBy);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.entity.ApsScheduleChangeLogEntity;
|
||||
import com.klp.aps.domain.entity.ApsScheduleOperationEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface ApsOperationMapper {
|
||||
|
||||
ApsScheduleOperationEntity selectByIdForUpdate(@Param("operationId") Long operationId);
|
||||
|
||||
int updateSlot(ApsScheduleOperationEntity op);
|
||||
|
||||
int insertChangeLog(ApsScheduleChangeLogEntity log);
|
||||
}
|
||||
|
||||
35
klp-aps/src/main/java/com/klp/aps/mapper/ApsPlanMapper.java
Normal file
35
klp-aps/src/main/java/com/klp/aps/mapper/ApsPlanMapper.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsWmsOrderCreateReq;
|
||||
import com.klp.aps.domain.dto.ApsWmsOrderDetailCreateReq;
|
||||
import com.klp.aps.domain.entity.ApsSchedulePlanDetailEntity;
|
||||
import com.klp.aps.domain.entity.ApsSchedulePlanEntity;
|
||||
import com.klp.aps.domain.row.ApsCrmOrderItemRow;
|
||||
import com.klp.aps.domain.row.ApsCrmOrderRow;
|
||||
import com.klp.aps.domain.row.ApsOrderDetailRow;
|
||||
import com.klp.aps.domain.row.ApsWmsOrderRow;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApsPlanMapper {
|
||||
|
||||
List<ApsOrderDetailRow> selectOrderDetailsByOrderId(@Param("orderId") Long orderId);
|
||||
|
||||
ApsCrmOrderRow selectCrmOrderById(@Param("crmOrderId") String crmOrderId);
|
||||
|
||||
List<ApsCrmOrderItemRow> selectCrmOrderItemsByOrderId(@Param("crmOrderId") String crmOrderId);
|
||||
|
||||
ApsWmsOrderRow selectWmsOrderByCode(@Param("orderCode") String orderCode);
|
||||
|
||||
int insertWmsOrder(ApsWmsOrderCreateReq req);
|
||||
|
||||
int insertWmsOrderDetail(ApsWmsOrderDetailCreateReq req);
|
||||
|
||||
Long selectAnyProductionLineId();
|
||||
|
||||
int insertSchedulePlan(ApsSchedulePlanEntity plan);
|
||||
|
||||
int insertSchedulePlanDetail(ApsSchedulePlanDetailEntity detail);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetQueryReq;
|
||||
import com.klp.aps.domain.vo.ApsScheduleSheetRowVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApsScheduleSheetMapper {
|
||||
List<ApsScheduleSheetRowVo> selectSheetRows(ApsScheduleSheetQueryReq req);
|
||||
|
||||
int deleteOperationCoils(@Param("operationId") Long operationId, @Param("updateBy") String updateBy);
|
||||
|
||||
int insertOperationCoil(@Param("operationId") Long operationId, @Param("coilId") Long coilId, @Param("createBy") String createBy);
|
||||
|
||||
int updateOperationSupplement(@Param("operationId") Long operationId, @Param("remarkJson") String remarkJson, @Param("updateBy") String updateBy);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.klp.aps.domain.entity.ApsShiftTemplateEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 班次模板Mapper接口
|
||||
*/
|
||||
public interface ApsShiftTemplateMapper extends BaseMapper<ApsShiftTemplateEntity> {
|
||||
|
||||
/**
|
||||
* 根据班次编码查询
|
||||
*/
|
||||
ApsShiftTemplateEntity selectByShiftCode(@Param("shiftCode") String shiftCode);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsAutoScheduleReq;
|
||||
|
||||
public interface ApsAutoScheduleService {
|
||||
void autoSchedule(ApsAutoScheduleReq req, String operator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.aps.domain.bo.ApsCalendarBo;
|
||||
import com.klp.aps.domain.vo.ApsCalendarVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工厂日历Service接口
|
||||
*/
|
||||
public interface ApsCalendarService {
|
||||
|
||||
/**
|
||||
* 查询工厂日历
|
||||
*/
|
||||
ApsCalendarVo queryById(Long calendarId);
|
||||
|
||||
/**
|
||||
* 查询工厂日历列表
|
||||
*/
|
||||
TableDataInfo<ApsCalendarVo> queryPageList(ApsCalendarBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询工厂日历列表
|
||||
*/
|
||||
List<ApsCalendarVo> queryList(ApsCalendarBo bo);
|
||||
|
||||
/**
|
||||
* 新增工厂日历
|
||||
*/
|
||||
Boolean insertByBo(ApsCalendarBo bo);
|
||||
|
||||
/**
|
||||
* 修改工厂日历
|
||||
*/
|
||||
Boolean updateByBo(ApsCalendarBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除工厂日历
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.aps.domain.bo.ApsCalendarShiftBo;
|
||||
import com.klp.aps.domain.vo.ApsCalendarShiftVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 日历班次配置Service接口
|
||||
*/
|
||||
public interface ApsCalendarShiftService {
|
||||
|
||||
/**
|
||||
* 查询日历班次配置
|
||||
*/
|
||||
ApsCalendarShiftVo queryById(Long configId);
|
||||
|
||||
/**
|
||||
* 查询日历班次配置列表
|
||||
*/
|
||||
TableDataInfo<ApsCalendarShiftVo> queryPageList(ApsCalendarShiftBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询日历班次配置列表
|
||||
*/
|
||||
List<ApsCalendarShiftVo> queryList(ApsCalendarShiftBo bo);
|
||||
|
||||
/**
|
||||
* 新增日历班次配置
|
||||
*/
|
||||
Boolean insertByBo(ApsCalendarShiftBo bo);
|
||||
|
||||
/**
|
||||
* 修改日历班次配置
|
||||
*/
|
||||
Boolean updateByBo(ApsCalendarShiftBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除日历班次配置
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 一键生成指定年份的工作日日历(状态=启用)
|
||||
* @param overwriteExisting true=覆盖已有记录为工作日;false=仅补齐缺失记录
|
||||
*/
|
||||
Integer generateWorkdayForYear(Integer year, Boolean overwriteExisting);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsGanttQueryReq;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarRespVo;
|
||||
import com.klp.aps.domain.vo.ApsGanttItemVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApsGanttService {
|
||||
List<ApsGanttItemVo> selectGanttItems(ApsGanttQueryReq req);
|
||||
|
||||
ApsFactoryCalendarRespVo queryFactoryCalendar(ApsGanttQueryReq req);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.aps.domain.bo.ApsLineCapabilityBo;
|
||||
import com.klp.aps.domain.vo.ApsLineCapabilityVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 产线能力Service接口
|
||||
*/
|
||||
public interface ApsLineCapabilityService {
|
||||
|
||||
/**
|
||||
* 查询产线能力
|
||||
*/
|
||||
ApsLineCapabilityVo queryById(Long capabilityId);
|
||||
|
||||
/**
|
||||
* 查询产线能力列表
|
||||
*/
|
||||
TableDataInfo<ApsLineCapabilityVo> queryPageList(ApsLineCapabilityBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询产线能力列表
|
||||
*/
|
||||
List<ApsLineCapabilityVo> queryList(ApsLineCapabilityBo bo);
|
||||
|
||||
/**
|
||||
* 新增产线能力
|
||||
*/
|
||||
Boolean insertByBo(ApsLineCapabilityBo bo);
|
||||
|
||||
/**
|
||||
* 修改产线能力
|
||||
*/
|
||||
Boolean updateByBo(ApsLineCapabilityBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除产线能力
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsLockReq;
|
||||
|
||||
public interface ApsLockService {
|
||||
|
||||
Long createLock(ApsLockReq req, String operator);
|
||||
|
||||
void releaseLock(Long lockId, String operator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsRescheduleReq;
|
||||
|
||||
public interface ApsOperationService {
|
||||
void reschedule(ApsRescheduleReq req, String operator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsConvertFromProductReq;
|
||||
import com.klp.aps.domain.dto.ApsPlanCreateReq;
|
||||
|
||||
public interface ApsPlanService {
|
||||
Long createPlan(ApsPlanCreateReq req, String operator);
|
||||
|
||||
Long convertFromCrmOrder(String crmOrderId, String operator);
|
||||
|
||||
Long convertFromCrmOrderWithItems(String crmOrderId, java.util.List<String> crmItemIds, String operator);
|
||||
|
||||
Long convertFromProduct(Long productId, java.math.BigDecimal quantity, String productName, String remark, String operator);
|
||||
|
||||
Long convertFromProducts(java.util.List<ApsConvertFromProductReq> items, String remark, String operator);
|
||||
|
||||
void publishPlan(Long planId, String operator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetQueryReq;
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetSupplementSaveReq;
|
||||
import com.klp.aps.domain.vo.ApsScheduleSheetResp;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface ApsScheduleSheetService {
|
||||
ApsScheduleSheetResp query(ApsScheduleSheetQueryReq req);
|
||||
|
||||
void exportExcel(ApsScheduleSheetQueryReq req, HttpServletResponse response);
|
||||
|
||||
void saveSupplement(ApsScheduleSheetSupplementSaveReq req, String operator);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.aps.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.aps.domain.bo.ApsShiftTemplateBo;
|
||||
import com.klp.aps.domain.vo.ApsShiftTemplateVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 班次模板Service接口
|
||||
*/
|
||||
public interface ApsShiftTemplateService {
|
||||
|
||||
/**
|
||||
* 查询班次模板
|
||||
*/
|
||||
ApsShiftTemplateVo queryById(Long shiftId);
|
||||
|
||||
/**
|
||||
* 查询班次模板列表
|
||||
*/
|
||||
TableDataInfo<ApsShiftTemplateVo> queryPageList(ApsShiftTemplateBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询班次模板列表
|
||||
*/
|
||||
List<ApsShiftTemplateVo> queryList(ApsShiftTemplateBo bo);
|
||||
|
||||
/**
|
||||
* 新增班次模板
|
||||
*/
|
||||
Boolean insertByBo(ApsShiftTemplateBo bo);
|
||||
|
||||
/**
|
||||
* 修改班次模板
|
||||
*/
|
||||
Boolean updateByBo(ApsShiftTemplateBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除班次模板
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.klp.aps.domain.row.*;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.dto.ApsAutoScheduleReq;
|
||||
import com.klp.aps.domain.entity.ApsScheduleChangeLogEntity;
|
||||
import com.klp.aps.domain.entity.ApsScheduleOperationEntity;
|
||||
import com.klp.aps.domain.row.ApsLineCapabilityRow;
|
||||
import com.klp.aps.domain.row.ApsSchedulePlanRow;
|
||||
import com.klp.aps.mapper.ApsAutoScheduleMapper;
|
||||
import com.klp.aps.service.ApsAutoScheduleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsAutoScheduleServiceImpl implements ApsAutoScheduleService {
|
||||
|
||||
private final ApsAutoScheduleMapper apsAutoScheduleMapper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void autoSchedule(ApsAutoScheduleReq req, String operator) {
|
||||
boolean clearOld = req.getClearOld() == null || Boolean.TRUE.equals(req.getClearOld());
|
||||
|
||||
// 1) 锁定计划行,避免并发排程
|
||||
ApsSchedulePlanRow plan = apsAutoScheduleMapper.selectPlanByIdForUpdate(req.getPlanId());
|
||||
if (plan == null) {
|
||||
throw new ServiceException("排产计划不存在");
|
||||
}
|
||||
if (plan.getStatus() == null || plan.getStatus() != 0) {
|
||||
throw new ServiceException("仅新建状态计划可自动排程");
|
||||
}
|
||||
|
||||
// 2) 清理旧排程(仅未锁定)
|
||||
if (clearOld) {
|
||||
apsAutoScheduleMapper.deleteUnlockedOperationsByPlanId(plan.getPlanId());
|
||||
}
|
||||
|
||||
// 3) 读取订单明细(基础校验)
|
||||
List<ApsOrderDetailRow> details = apsAutoScheduleMapper.selectOrderDetailsByOrderId(plan.getOrderId());
|
||||
if (details == null || details.isEmpty()) {
|
||||
throw new ServiceException("订单明细为空,无法排程");
|
||||
}
|
||||
|
||||
// 4) 正排:按计划明细(仅到产线粒度,不依赖工艺路线)
|
||||
List<ApsPlanDetailRow> planDetails = apsAutoScheduleMapper.selectPlanDetailsByPlanId(plan.getPlanId());
|
||||
if (planDetails == null || planDetails.isEmpty()) {
|
||||
throw new ServiceException("计划明细为空,无法排程");
|
||||
}
|
||||
|
||||
int seqNo = 1;
|
||||
LocalDateTime cursor = plan.getStartDate() != null ? plan.getStartDate() : LocalDateTime.now();
|
||||
for (ApsPlanDetailRow pd : planDetails) {
|
||||
Long productId = pd.getProductId();
|
||||
Long lineId = pd.getLineId();
|
||||
BigDecimal qty = safeQty(pd.getQuantity());
|
||||
if (lineId == null) {
|
||||
throw new ServiceException("计划明细未指定产线: detailId=" + pd.getDetailId());
|
||||
}
|
||||
|
||||
List<ApsLineCapabilityRow> caps = apsAutoScheduleMapper.selectLineCandidatesByProductAndLine(productId, lineId);
|
||||
if (caps == null || caps.isEmpty()) {
|
||||
ApsLineMetaRow lineMeta = apsAutoScheduleMapper.selectLineMetaById(lineId);
|
||||
ApsProductMetaRow productMeta = apsAutoScheduleMapper.selectProductMetaById(productId);
|
||||
String lineName = lineMeta != null && lineMeta.getLineName() != null ? lineMeta.getLineName() : ("产线" + lineId);
|
||||
String productText = productMeta == null
|
||||
? ("产品" + productId)
|
||||
: (safe(productMeta.getProductName()) + "-" + safe(productMeta.getSpecification()) + "-" + safe(productMeta.getMaterial()));
|
||||
throw new ServiceException("产线【" + lineName + "】未配置产品产能:" + productText);
|
||||
}
|
||||
ApsLineCapabilityRow cap = caps.get(0);
|
||||
|
||||
long runMinutes = calcRunMinutes(qty, cap.getCapacityPerHour());
|
||||
int setupMinutes = cap.getSetupMinutes() == null ? 0 : Math.max(0, cap.getSetupMinutes());
|
||||
long totalMinutes = runMinutes + setupMinutes;
|
||||
|
||||
ScheduledSlot slot = findEarliestAvailableSlotWithShift(lineId, cursor, totalMinutes, plan.getPlanId());
|
||||
|
||||
ApsScheduleOperationEntity op = new ApsScheduleOperationEntity();
|
||||
op.setPlanId(plan.getPlanId());
|
||||
op.setDetailId(pd.getDetailId());
|
||||
op.setOrderId(plan.getOrderId());
|
||||
op.setOrderDetailId(pd.getTaskId());
|
||||
op.setProductId(productId);
|
||||
op.setProcessId(null);
|
||||
op.setLineId(lineId);
|
||||
op.setSequenceNo(seqNo++);
|
||||
op.setPlanQty(qty);
|
||||
op.setStartTime(slot.start);
|
||||
op.setEndTime(slot.end);
|
||||
op.setSetupMinutes(setupMinutes);
|
||||
op.setStatus(0);
|
||||
op.setLockedFlag(0);
|
||||
op.setCreateBy(operator);
|
||||
op.setUpdateBy(operator);
|
||||
apsAutoScheduleMapper.insertOperation(op);
|
||||
|
||||
if (op.getOperationId() == null) {
|
||||
throw new ServiceException("写入排程结果失败:未回填 operationId");
|
||||
}
|
||||
|
||||
ApsScheduleChangeLogEntity log = new ApsScheduleChangeLogEntity();
|
||||
log.setOperationId(op.getOperationId());
|
||||
log.setChangeType("CREATE");
|
||||
log.setBeforeValue(null);
|
||||
log.setAfterValue(JSON.toJSONString(op));
|
||||
log.setChangeReason("AUTO_SCHEDULE");
|
||||
log.setChangeBy(operator);
|
||||
apsAutoScheduleMapper.insertChangeLog(log);
|
||||
|
||||
cursor = slot.end;
|
||||
}
|
||||
|
||||
// 5) 更新计划状态 -> 已排产
|
||||
apsAutoScheduleMapper.updatePlanStatus(plan.getPlanId(), 1, operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在日历班次 + 冲突/锁定约束下寻找最早可用时间窗(当前实现:仅允许落在单个班次内,跨班次暂不支持)
|
||||
*/
|
||||
private ScheduledSlot findEarliestAvailableSlotWithShift(Long lineId, LocalDateTime earliest, long totalMinutes, Long planId) {
|
||||
if (lineId == null) {
|
||||
throw new ServiceException("排程失败:lineId 为空");
|
||||
}
|
||||
if (earliest == null) {
|
||||
earliest = LocalDateTime.now();
|
||||
}
|
||||
if (totalMinutes <= 0) {
|
||||
totalMinutes = 1;
|
||||
}
|
||||
|
||||
// 只在 earliest 所在日期起,向后若干天内查找可用班次
|
||||
LocalDate startDate = earliest.toLocalDate();
|
||||
LocalDate endDate = startDate.plusDays(30);
|
||||
|
||||
java.util.List<ApsShiftSlotRow> shifts =
|
||||
apsAutoScheduleMapper.selectAvailableShifts(lineId, startDate, endDate);
|
||||
if (shifts == null || shifts.isEmpty()) {
|
||||
throw new ServiceException("未配置可用班次或当前日期范围无班次:lineId=" + lineId);
|
||||
}
|
||||
|
||||
for (ApsShiftSlotRow shift : shifts) {
|
||||
LocalDate d = shift.getCalendarDate();
|
||||
LocalTime st = shift.getStartTime();
|
||||
LocalTime et = shift.getEndTime();
|
||||
if (d == null || st == null || et == null) {
|
||||
continue;
|
||||
}
|
||||
LocalDateTime slotStart = LocalDateTime.of(d, st);
|
||||
LocalDateTime slotEnd = shift.getCrossDay() != null && shift.getCrossDay() == 1
|
||||
? LocalDateTime.of(d.plusDays(1), et)
|
||||
: LocalDateTime.of(d, et);
|
||||
|
||||
// 跳过整班结束早于 earliest 的班次
|
||||
if (!slotEnd.isAfter(earliest)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在班次内,从 max(earliest, 班次开始) 起尝试
|
||||
LocalDateTime start = earliest.isAfter(slotStart) ? earliest : slotStart;
|
||||
// 防止在单个班次内死循环,最多推进 100 次
|
||||
for (int i = 0; i < 100; i++) {
|
||||
LocalDateTime end = start.plusMinutes(totalMinutes);
|
||||
if (!end.isBefore(slotEnd) && !end.equals(slotEnd)) {
|
||||
// 超出当前班次结束,换下一个班次
|
||||
break;
|
||||
}
|
||||
|
||||
LocalDateTime conflictEnd = apsAutoScheduleMapper.selectFirstConflictEndTime(lineId, start, end, null);
|
||||
if (conflictEnd != null && conflictEnd.isAfter(start) && conflictEnd.isBefore(slotEnd)) {
|
||||
start = conflictEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
LocalDateTime lockEnd = apsAutoScheduleMapper.selectFirstHitLockEndTime(lineId, start, end, planId, null);
|
||||
if (lockEnd != null && lockEnd.isAfter(start) && lockEnd.isBefore(slotEnd)) {
|
||||
start = lockEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
return new ScheduledSlot(start, end, lineId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ServiceException("排程失败:在可用班次内无法找到可用时间窗(lineId=" + lineId + ")");
|
||||
}
|
||||
|
||||
private static long calcRunMinutes(BigDecimal qty, BigDecimal capacityPerHour) {
|
||||
BigDecimal q = safeQty(qty);
|
||||
if (capacityPerHour == null || capacityPerHour.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("产线能力 capacityPerHour 不合法");
|
||||
}
|
||||
// minutes = ceil(qty / capPerHour * 60)
|
||||
BigDecimal minutes = q.multiply(BigDecimal.valueOf(60))
|
||||
.divide(capacityPerHour, 0, RoundingMode.CEILING);
|
||||
long m = minutes.longValue();
|
||||
return Math.max(1L, m);
|
||||
}
|
||||
|
||||
private static BigDecimal safeQty(BigDecimal qty) {
|
||||
BigDecimal q = qty == null ? BigDecimal.ZERO : qty;
|
||||
// wms_order_detail.quantity 是 decimal(18,0),这里统一按 4 位小数存 op.plan_qty
|
||||
return q.setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private static String safe(String s) {
|
||||
return s == null || s.trim().isEmpty() ? "-" : s.trim();
|
||||
}
|
||||
|
||||
private static class ScheduledSlot {
|
||||
private final LocalDateTime start;
|
||||
private final LocalDateTime end;
|
||||
private final Long lineId;
|
||||
private final int setupMinutes;
|
||||
|
||||
private ScheduledSlot(LocalDateTime start, LocalDateTime end, Long lineId, int setupMinutes) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.lineId = lineId;
|
||||
this.setupMinutes = setupMinutes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.aps.domain.bo.ApsCalendarBo;
|
||||
import com.klp.aps.domain.entity.ApsCalendarEntity;
|
||||
import com.klp.aps.domain.vo.ApsCalendarVo;
|
||||
import com.klp.aps.mapper.ApsCalendarMapper;
|
||||
import com.klp.aps.service.ApsCalendarService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 工厂日历Service业务层处理
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsCalendarServiceImpl implements ApsCalendarService {
|
||||
|
||||
private final ApsCalendarMapper baseMapper;
|
||||
|
||||
private static final Map<Integer, String> CALENDAR_TYPE_MAP = new HashMap<Integer, String>() {{
|
||||
put(1, "工作日");
|
||||
put(2, "周末");
|
||||
put(3, "法定假日");
|
||||
put(4, "停机日");
|
||||
}};
|
||||
|
||||
@Override
|
||||
public ApsCalendarVo queryById(Long calendarId) {
|
||||
ApsCalendarEntity entity = baseMapper.selectById(calendarId);
|
||||
ApsCalendarVo vo = BeanUtil.toBean(entity, ApsCalendarVo.class);
|
||||
if (vo != null && vo.getCalendarType() != null) {
|
||||
vo.setCalendarTypeName(CALENDAR_TYPE_MAP.getOrDefault(vo.getCalendarType(), "未知"));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ApsCalendarVo> queryPageList(ApsCalendarBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ApsCalendarEntity> lqw = buildQueryWrapper(bo);
|
||||
Page<ApsCalendarEntity> result = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
List<ApsCalendarVo> voList = result.getRecords().stream()
|
||||
.map(entity -> {
|
||||
ApsCalendarVo vo = BeanUtil.toBean(entity, ApsCalendarVo.class);
|
||||
if (vo.getCalendarType() != null) {
|
||||
vo.setCalendarTypeName(CALENDAR_TYPE_MAP.getOrDefault(vo.getCalendarType(), "未知"));
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
TableDataInfo<ApsCalendarVo> build = TableDataInfo.build(voList);
|
||||
build.setTotal(result.getTotal());
|
||||
return build;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ApsCalendarVo> queryList(ApsCalendarBo bo) {
|
||||
LambdaQueryWrapper<ApsCalendarEntity> lqw = buildQueryWrapper(bo);
|
||||
List<ApsCalendarEntity> list = baseMapper.selectList(lqw);
|
||||
return list.stream()
|
||||
.map(entity -> {
|
||||
ApsCalendarVo vo = BeanUtil.toBean(entity, ApsCalendarVo.class);
|
||||
if (vo.getCalendarType() != null) {
|
||||
vo.setCalendarTypeName(CALENDAR_TYPE_MAP.getOrDefault(vo.getCalendarType(), "未知"));
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ApsCalendarEntity> buildQueryWrapper(ApsCalendarBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<ApsCalendarEntity> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getCalendarDate() != null, ApsCalendarEntity::getCalendarDate, bo.getCalendarDate());
|
||||
lqw.eq(bo.getCalendarType() != null, ApsCalendarEntity::getCalendarType, bo.getCalendarType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getFactoryCode()), ApsCalendarEntity::getFactoryCode, bo.getFactoryCode());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ApsCalendarBo bo) {
|
||||
ApsCalendarEntity entity = BeanUtil.toBean(bo, ApsCalendarEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ApsCalendarBo bo) {
|
||||
ApsCalendarEntity entity = BeanUtil.toBean(bo, ApsCalendarEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ApsCalendarEntity entity) {
|
||||
if (entity.getFactoryCode() == null || entity.getFactoryCode().isEmpty()) {
|
||||
entity.setFactoryCode("DEFAULT");
|
||||
}
|
||||
ApsCalendarEntity exist = baseMapper.selectByDateAndFactory(entity.getCalendarDate(), entity.getFactoryCode());
|
||||
if (exist != null && !exist.getCalendarId().equals(entity.getCalendarId())) {
|
||||
throw new ServiceException("该日期和工厂编码的组合已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 可以添加业务校验,例如检查是否被排产计划使用
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.bo.ApsCalendarShiftBo;
|
||||
import com.klp.aps.domain.bo.ApsShiftTemplateBo;
|
||||
import com.klp.aps.domain.entity.ApsCalendarEntity;
|
||||
import com.klp.aps.domain.entity.ApsCalendarShiftEntity;
|
||||
import com.klp.aps.domain.vo.ApsCalendarShiftVo;
|
||||
import com.klp.aps.mapper.ApsCalendarMapper;
|
||||
import com.klp.aps.mapper.ApsCalendarShiftMapper;
|
||||
import com.klp.aps.service.ApsCalendarShiftService;
|
||||
import com.klp.service.IWmsProductionLineService;
|
||||
import com.klp.domain.vo.WmsProductionLineVo;
|
||||
import com.klp.aps.service.ApsShiftTemplateService;
|
||||
import com.klp.aps.domain.vo.ApsShiftTemplateVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 日历班次配置Service业务层处理
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsCalendarShiftServiceImpl implements ApsCalendarShiftService {
|
||||
|
||||
private final ApsCalendarShiftMapper baseMapper;
|
||||
private final ApsCalendarMapper calendarMapper;
|
||||
private final IWmsProductionLineService productionLineService;
|
||||
private final ApsShiftTemplateService shiftTemplateService;
|
||||
|
||||
private static final Map<Integer, String> STATUS_MAP = new HashMap<Integer, String>() {{
|
||||
put(0, "停用");
|
||||
put(1, "启用");
|
||||
}};
|
||||
|
||||
@Override
|
||||
public ApsCalendarShiftVo queryById(Long configId) {
|
||||
ApsCalendarShiftEntity entity = baseMapper.selectById(configId);
|
||||
ApsCalendarShiftVo vo = BeanUtil.toBean(entity, ApsCalendarShiftVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ApsCalendarShiftVo> queryPageList(ApsCalendarShiftBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ApsCalendarShiftEntity> lqw = buildQueryWrapper(bo);
|
||||
Page<ApsCalendarShiftEntity> result = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
List<ApsCalendarShiftVo> voList = result.getRecords().stream()
|
||||
.map(entity -> {
|
||||
ApsCalendarShiftVo vo = BeanUtil.toBean(entity, ApsCalendarShiftVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
TableDataInfo<ApsCalendarShiftVo> tableDataInfo = TableDataInfo.build(voList);
|
||||
tableDataInfo.setTotal(result.getTotal());
|
||||
return tableDataInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ApsCalendarShiftVo> queryList(ApsCalendarShiftBo bo) {
|
||||
LambdaQueryWrapper<ApsCalendarShiftEntity> lqw = buildQueryWrapper(bo);
|
||||
List<ApsCalendarShiftEntity> list = baseMapper.selectList(lqw);
|
||||
return list.stream()
|
||||
.map(entity -> {
|
||||
ApsCalendarShiftVo vo = BeanUtil.toBean(entity, ApsCalendarShiftVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void enrichVo(ApsCalendarShiftVo vo) {
|
||||
if (vo == null) return;
|
||||
if (vo.getStatus() != null) {
|
||||
vo.setStatusName(STATUS_MAP.getOrDefault(vo.getStatus(), "未知"));
|
||||
}
|
||||
if (vo.getLineId() != null) {
|
||||
try {
|
||||
WmsProductionLineVo line = productionLineService.queryById(vo.getLineId());
|
||||
if (line != null) {
|
||||
vo.setLineName(line.getLineName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,仅记录
|
||||
}
|
||||
}
|
||||
if (vo.getShiftId() != null) {
|
||||
try {
|
||||
ApsShiftTemplateVo shift = shiftTemplateService.queryById(vo.getShiftId());
|
||||
if (shift != null) {
|
||||
vo.setShiftName(shift.getShiftName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,仅记录
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ApsCalendarShiftEntity> buildQueryWrapper(ApsCalendarShiftBo bo) {
|
||||
LambdaQueryWrapper<ApsCalendarShiftEntity> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getCalendarDate() != null, ApsCalendarShiftEntity::getCalendarDate, bo.getCalendarDate());
|
||||
lqw.eq(bo.getLineId() != null, ApsCalendarShiftEntity::getLineId, bo.getLineId());
|
||||
lqw.eq(bo.getShiftId() != null, ApsCalendarShiftEntity::getShiftId, bo.getShiftId());
|
||||
lqw.eq(bo.getStatus() != null, ApsCalendarShiftEntity::getStatus, bo.getStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ApsCalendarShiftBo bo) {
|
||||
ApsCalendarShiftEntity entity = BeanUtil.toBean(bo, ApsCalendarShiftEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ApsCalendarShiftBo bo) {
|
||||
ApsCalendarShiftEntity entity = BeanUtil.toBean(bo, ApsCalendarShiftEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ApsCalendarShiftEntity entity) {
|
||||
ApsCalendarShiftEntity exist = baseMapper.selectByDateLineAndShift(
|
||||
entity.getCalendarDate(), entity.getLineId(), entity.getShiftId());
|
||||
if (exist != null && !exist.getConfigId().equals(entity.getConfigId())) {
|
||||
throw new ServiceException("该日期、产线和班次的组合已存在");
|
||||
}
|
||||
if (entity.getStatus() == null) {
|
||||
entity.setStatus(1);
|
||||
}
|
||||
if (entity.getPlannedHours() == null) {
|
||||
entity.setPlannedHours(java.math.BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 预留业务校验扩展点
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer generateWorkdayForYear(Integer year, Boolean overwriteExisting) {
|
||||
if (year == null || year < 2000 || year > 2100) {
|
||||
throw new ServiceException("年份范围不合法,请输入 2000-2100");
|
||||
}
|
||||
|
||||
List<Long> lineIds = baseMapper.selectDistinctLineIds();
|
||||
if (lineIds == null || lineIds.isEmpty()) {
|
||||
throw new ServiceException("暂无可用产线,请先维护至少一条日历班次或产线数据");
|
||||
}
|
||||
|
||||
List<ApsShiftTemplateVo> shifts = shiftTemplateService.queryList(new ApsShiftTemplateBo());
|
||||
if (shifts == null || shifts.isEmpty()) {
|
||||
throw new ServiceException("暂无班次模板,请先配置班次模板");
|
||||
}
|
||||
|
||||
LocalDate start = LocalDate.of(year, 1, 1);
|
||||
LocalDate end = LocalDate.of(year, 12, 31);
|
||||
|
||||
int affected = 0;
|
||||
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
|
||||
ApsCalendarEntity cal = calendarMapper.selectByDateAndFactory(d, "DEFAULT");
|
||||
if (cal == null) {
|
||||
ApsCalendarEntity c = new ApsCalendarEntity();
|
||||
c.setCalendarDate(d);
|
||||
c.setCalendarType(1);
|
||||
c.setFactoryCode("DEFAULT");
|
||||
c.setRemark("系统批量生成工作日");
|
||||
affected += calendarMapper.insert(c);
|
||||
} else if (Boolean.TRUE.equals(overwriteExisting) && (cal.getCalendarType() == null || cal.getCalendarType() != 1)) {
|
||||
cal.setCalendarType(1);
|
||||
affected += calendarMapper.updateById(cal);
|
||||
}
|
||||
}
|
||||
|
||||
for (Long lineId : lineIds) {
|
||||
for (ApsShiftTemplateVo shift : shifts) {
|
||||
if (shift == null || shift.getShiftId() == null) continue;
|
||||
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
|
||||
ApsCalendarShiftEntity exist = baseMapper.selectByDateLineAndShift(d, lineId, shift.getShiftId());
|
||||
if (exist == null) {
|
||||
ApsCalendarShiftEntity entity = new ApsCalendarShiftEntity();
|
||||
entity.setCalendarDate(d);
|
||||
entity.setLineId(lineId);
|
||||
entity.setShiftId(shift.getShiftId());
|
||||
entity.setStatus(1);
|
||||
entity.setPlannedHours(BigDecimal.valueOf(8));
|
||||
entity.setRemark("系统批量生成");
|
||||
affected += baseMapper.insert(entity);
|
||||
} else {
|
||||
boolean changed = false;
|
||||
if (Boolean.TRUE.equals(overwriteExisting)) {
|
||||
if (exist.getStatus() == null || exist.getStatus() != 1) {
|
||||
exist.setStatus(1);
|
||||
changed = true;
|
||||
}
|
||||
if (exist.getPlannedHours() == null || exist.getPlannedHours().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
exist.setPlannedHours(BigDecimal.valueOf(8));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
affected += baseMapper.updateById(exist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.klp.aps.domain.bo.ApsShiftTemplateBo;
|
||||
import com.klp.aps.domain.dto.ApsGanttQueryReq;
|
||||
import com.klp.aps.domain.entity.ApsCalendarShiftEntity;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarDayVo;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarOverviewVo;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarRespVo;
|
||||
import com.klp.aps.domain.vo.ApsFactoryCalendarTaskLiteVo;
|
||||
import com.klp.aps.domain.vo.ApsGanttItemVo;
|
||||
import com.klp.aps.domain.vo.ApsShiftTemplateVo;
|
||||
import com.klp.aps.mapper.ApsCalendarShiftMapper;
|
||||
import com.klp.aps.mapper.ApsGanttMapper;
|
||||
import com.klp.aps.service.ApsGanttService;
|
||||
import com.klp.aps.service.ApsShiftTemplateService;
|
||||
import com.klp.domain.bo.WmsProductionLineBo;
|
||||
import com.klp.domain.vo.WmsProductionLineVo;
|
||||
import com.klp.service.IWmsProductionLineService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsGanttServiceImpl implements ApsGanttService {
|
||||
|
||||
private final ApsGanttMapper apsGanttMapper;
|
||||
private final ApsCalendarShiftMapper calendarShiftMapper;
|
||||
private final IWmsProductionLineService productionLineService;
|
||||
private final ApsShiftTemplateService shiftTemplateService;
|
||||
|
||||
@Override
|
||||
public List<ApsGanttItemVo> selectGanttItems(ApsGanttQueryReq req) {
|
||||
return apsGanttMapper.selectGanttItems(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApsFactoryCalendarRespVo queryFactoryCalendar(ApsGanttQueryReq req) {
|
||||
if (req.getQueryStart() == null || req.getQueryEnd() == null) {
|
||||
ApsFactoryCalendarRespVo empty = new ApsFactoryCalendarRespVo();
|
||||
empty.setOverview(new ApsFactoryCalendarOverviewVo());
|
||||
empty.setDateList(new ArrayList<>());
|
||||
empty.setLineNameMap(new HashMap<>());
|
||||
empty.setShiftNameMap(new HashMap<>());
|
||||
empty.setLineDayMap(new HashMap<>());
|
||||
empty.setLineShiftDayMap(new HashMap<>());
|
||||
return empty;
|
||||
}
|
||||
|
||||
List<ApsGanttItemVo> tasks = apsGanttMapper.selectGanttItems(req);
|
||||
List<WmsProductionLineVo> lineVos = productionLineService.queryList(new WmsProductionLineBo());
|
||||
List<ApsShiftTemplateVo> shiftVos = shiftTemplateService.queryList(new ApsShiftTemplateBo());
|
||||
|
||||
Map<Long, String> lineNameMap = new HashMap<>();
|
||||
for (WmsProductionLineVo l : lineVos) {
|
||||
if (l != null && l.getLineId() != null) {
|
||||
lineNameMap.put(l.getLineId(), l.getLineName() != null ? l.getLineName() : l.getLineCode());
|
||||
}
|
||||
}
|
||||
|
||||
Map<Long, String> shiftNameMap = new HashMap<>();
|
||||
for (ApsShiftTemplateVo s : shiftVos) {
|
||||
if (s != null && s.getShiftId() != null) {
|
||||
shiftNameMap.put(s.getShiftId(), s.getShiftName());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, ApsFactoryCalendarDayVo> lineDayMap = new HashMap<>();
|
||||
Map<String, ApsFactoryCalendarDayVo> lineShiftDayMap = new HashMap<>();
|
||||
Map<String, Set<Long>> lineDayShiftSetMap = new HashMap<>();
|
||||
Map<String, Set<Long>> lineShiftLineSetMap = new HashMap<>();
|
||||
|
||||
List<ApsCalendarShiftEntity> calendarShiftList = calendarShiftMapper.selectList(
|
||||
Wrappers.<ApsCalendarShiftEntity>lambdaQuery()
|
||||
.between(ApsCalendarShiftEntity::getCalendarDate, req.getQueryStart().toLocalDate(), req.getQueryEnd().toLocalDate())
|
||||
);
|
||||
Map<String, Integer> lineStatusAgg = new HashMap<>();
|
||||
for (ApsCalendarShiftEntity cs : calendarShiftList) {
|
||||
if (cs == null || cs.getLineId() == null || cs.getShiftId() == null || cs.getCalendarDate() == null || cs.getStatus() == null) continue;
|
||||
String d = cs.getCalendarDate().format(DateTimeFormatter.ISO_DATE);
|
||||
String lineShiftKey = cs.getLineId() + "|" + cs.getShiftId() + "|" + d;
|
||||
lineShiftDayMap.computeIfAbsent(lineShiftKey, k -> new ApsFactoryCalendarDayVo()).setDayStatus(cs.getStatus());
|
||||
|
||||
String lineKey = cs.getLineId() + "|" + d;
|
||||
Integer old = lineStatusAgg.get(lineKey);
|
||||
int cur = cs.getStatus();
|
||||
if (old == null) {
|
||||
lineStatusAgg.put(lineKey, cur);
|
||||
} else if (old == 1 || cur == 1) {
|
||||
lineStatusAgg.put(lineKey, 1);
|
||||
} else {
|
||||
lineStatusAgg.put(lineKey, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Integer> dayCountMap = new HashMap<>();
|
||||
Map<Long, Integer> lineCountMap = new HashMap<>();
|
||||
Map<String, Integer> lineShiftCountMap = new HashMap<>();
|
||||
|
||||
Set<Long> activeLineSet = new HashSet<>();
|
||||
BigDecimal totalHours = BigDecimal.ZERO;
|
||||
int validTaskCount = 0;
|
||||
|
||||
for (ApsGanttItemVo t : tasks) {
|
||||
if (t == null || t.getStartTime() == null || t.getLineId() == null) continue;
|
||||
validTaskCount++;
|
||||
LocalDateTime st = t.getStartTime();
|
||||
String dateText = st.toLocalDate().format(DateTimeFormatter.ISO_DATE);
|
||||
Long lineId = t.getLineId();
|
||||
|
||||
activeLineSet.add(lineId);
|
||||
dayCountMap.put(dateText, dayCountMap.getOrDefault(dateText, 0) + 1);
|
||||
lineCountMap.put(lineId, lineCountMap.getOrDefault(lineId, 0) + 1);
|
||||
|
||||
if (t.getEndTime() != null && t.getEndTime().isAfter(st)) {
|
||||
totalHours = totalHours.add(BigDecimal.valueOf(Duration.between(st, t.getEndTime()).toMinutes())
|
||||
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP));
|
||||
}
|
||||
|
||||
Long shiftId = matchShiftId(shiftVos, st.toLocalTime());
|
||||
|
||||
String lineDayKey = lineId + "|" + dateText;
|
||||
ApsFactoryCalendarDayVo lineDayVo = lineDayMap.computeIfAbsent(lineDayKey, k -> new ApsFactoryCalendarDayVo());
|
||||
lineDayVo.setTaskCount(lineDayVo.getTaskCount() + 1);
|
||||
if (shiftId != null) {
|
||||
Set<Long> shiftSet = lineDayShiftSetMap.computeIfAbsent(lineDayKey, k -> new HashSet<>());
|
||||
shiftSet.add(shiftId);
|
||||
lineDayVo.setShiftCount(shiftSet.size());
|
||||
}
|
||||
pushTaskLite(lineDayVo, t, shiftId, shiftNameMap, true);
|
||||
|
||||
if (shiftId != null) {
|
||||
String lsDayKey = lineId + "|" + shiftId + "|" + dateText;
|
||||
ApsFactoryCalendarDayVo lsDayVo = lineShiftDayMap.computeIfAbsent(lsDayKey, k -> new ApsFactoryCalendarDayVo());
|
||||
lsDayVo.setTaskCount(lsDayVo.getTaskCount() + 1);
|
||||
Set<Long> lineSet = lineShiftLineSetMap.computeIfAbsent(lsDayKey, k -> new HashSet<>());
|
||||
lineSet.add(lineId);
|
||||
lsDayVo.setLineCount(lineSet.size());
|
||||
pushTaskLite(lsDayVo, t, shiftId, shiftNameMap, false);
|
||||
|
||||
String aggKey = lineId + "|" + shiftId;
|
||||
lineShiftCountMap.put(aggKey, lineShiftCountMap.getOrDefault(aggKey, 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Integer> e : lineStatusAgg.entrySet()) {
|
||||
lineDayMap.computeIfAbsent(e.getKey(), k -> new ApsFactoryCalendarDayVo()).setDayStatus(e.getValue());
|
||||
}
|
||||
|
||||
ApsFactoryCalendarOverviewVo overview = new ApsFactoryCalendarOverviewVo();
|
||||
overview.setTaskCount(validTaskCount);
|
||||
overview.setActiveLineCount(activeLineSet.size());
|
||||
overview.setTotalLineCount(lineNameMap.size());
|
||||
overview.setShiftCount(shiftNameMap.size());
|
||||
overview.setTotalHours(totalHours.setScale(1, RoundingMode.HALF_UP).toPlainString());
|
||||
|
||||
String peakDay = maxKey(dayCountMap);
|
||||
overview.setPeakDayText(peakDay == null ? "-" : peakDay + " (" + dayCountMap.get(peakDay) + "单)");
|
||||
|
||||
Long busiestLineId = maxKeyLong(lineCountMap);
|
||||
overview.setBusiestLineText(busiestLineId == null ? "-" : lineNameMap.getOrDefault(busiestLineId, "产线" + busiestLineId) + " (" + lineCountMap.get(busiestLineId) + "单)");
|
||||
|
||||
String busiestLs = maxKey(lineShiftCountMap);
|
||||
if (busiestLs == null) {
|
||||
overview.setBusiestLineShiftText("-");
|
||||
} else {
|
||||
String[] arr = busiestLs.split("\\|");
|
||||
Long lId = Long.valueOf(arr[0]);
|
||||
Long sId = Long.valueOf(arr[1]);
|
||||
overview.setBusiestLineShiftText(lineNameMap.getOrDefault(lId, "产线" + lId)
|
||||
+ " · " + shiftNameMap.getOrDefault(sId, "班次" + sId)
|
||||
+ " (" + lineShiftCountMap.get(busiestLs) + "单)");
|
||||
}
|
||||
|
||||
ApsFactoryCalendarRespVo resp = new ApsFactoryCalendarRespVo();
|
||||
resp.setOverview(overview);
|
||||
resp.setDateList(buildDateList(req.getQueryStart(), req.getQueryEnd()));
|
||||
resp.setLineNameMap(lineNameMap);
|
||||
resp.setShiftNameMap(shiftNameMap);
|
||||
resp.setLineDayMap(lineDayMap);
|
||||
resp.setLineShiftDayMap(lineShiftDayMap);
|
||||
return resp;
|
||||
}
|
||||
|
||||
private List<String> buildDateList(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
List<String> arr = new ArrayList<>();
|
||||
if (startTime == null || endTime == null) return arr;
|
||||
LocalDate start = startTime.toLocalDate();
|
||||
LocalDate end = endTime.toLocalDate();
|
||||
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
|
||||
arr.add(d.format(DateTimeFormatter.ISO_DATE));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
private Long matchShiftId(List<ApsShiftTemplateVo> shifts, LocalTime time) {
|
||||
if (shifts == null || time == null) return null;
|
||||
for (ApsShiftTemplateVo s : shifts) {
|
||||
if (s == null || s.getShiftId() == null || s.getStartTime() == null || s.getEndTime() == null) continue;
|
||||
boolean cross = s.getCrossDay() != null && s.getCrossDay() == 1;
|
||||
if (!cross) {
|
||||
if (!time.isBefore(s.getStartTime()) && !time.isAfter(s.getEndTime())) return s.getShiftId();
|
||||
} else {
|
||||
if (!time.isBefore(s.getStartTime()) || !time.isAfter(s.getEndTime())) return s.getShiftId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void pushTaskLite(ApsFactoryCalendarDayVo vo,
|
||||
ApsGanttItemVo task,
|
||||
Long shiftId,
|
||||
Map<Long, String> shiftNameMap,
|
||||
boolean withShift) {
|
||||
if (vo.getTasks().size() >= 3) return;
|
||||
ApsFactoryCalendarTaskLiteVo lite = new ApsFactoryCalendarTaskLiteVo();
|
||||
String st = task.getStartTime() == null ? "--:--" : task.getStartTime().toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||
String et = task.getEndTime() == null ? "--:--" : task.getEndTime().toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||
String p = task.getProductName() == null ? "产品" : task.getProductName();
|
||||
String sp = task.getSpecification() == null ? "-" : task.getSpecification();
|
||||
String m = task.getMaterial() == null ? "-" : task.getMaterial();
|
||||
String shiftText = (withShift && shiftId != null) ? " [" + shiftNameMap.getOrDefault(shiftId, "班次" + shiftId) + "]" : "";
|
||||
lite.setLabel(st + " " + p + "-" + sp + "-" + m + shiftText);
|
||||
lite.setTitle(st + "-" + et + " " + p + "-" + sp + "-" + m);
|
||||
vo.getTasks().add(lite);
|
||||
}
|
||||
|
||||
private String maxKey(Map<String, Integer> map) {
|
||||
String key = null;
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (Map.Entry<String, Integer> e : map.entrySet()) {
|
||||
if (e.getValue() != null && e.getValue() > max) {
|
||||
key = e.getKey();
|
||||
max = e.getValue();
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private Long maxKeyLong(Map<Long, Integer> map) {
|
||||
Long key = null;
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (Map.Entry<Long, Integer> e : map.entrySet()) {
|
||||
if (e.getValue() != null && e.getValue() > max) {
|
||||
key = e.getKey();
|
||||
max = e.getValue();
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.bo.ApsLineCapabilityBo;
|
||||
import com.klp.aps.domain.entity.ApsLineCapabilityEntity;
|
||||
import com.klp.aps.domain.vo.ApsLineCapabilityVo;
|
||||
import com.klp.aps.mapper.ApsLineCapabilityMapper;
|
||||
import com.klp.aps.service.ApsLineCapabilityService;
|
||||
import com.klp.domain.vo.WmsProductionLineVo;
|
||||
import com.klp.service.IWmsProductionLineService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 产线能力Service业务层处理
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsLineCapabilityServiceImpl implements ApsLineCapabilityService {
|
||||
|
||||
private final ApsLineCapabilityMapper baseMapper;
|
||||
private final IWmsProductionLineService productionLineService;
|
||||
|
||||
private static final Map<Integer, String> ENABLED_MAP =new HashMap<Integer, String>(){{
|
||||
put(0, "停用");
|
||||
put(1, "启用");
|
||||
|
||||
|
||||
}};
|
||||
|
||||
@Override
|
||||
public ApsLineCapabilityVo queryById(Long capabilityId) {
|
||||
ApsLineCapabilityEntity entity = baseMapper.selectById(capabilityId);
|
||||
ApsLineCapabilityVo vo = BeanUtil.toBean(entity, ApsLineCapabilityVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ApsLineCapabilityVo> queryPageList(ApsLineCapabilityBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ApsLineCapabilityEntity> lqw = buildQueryWrapper(bo);
|
||||
Page<ApsLineCapabilityEntity> result = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
List<ApsLineCapabilityVo> voList = result.getRecords().stream()
|
||||
.map(entity -> {
|
||||
ApsLineCapabilityVo vo = BeanUtil.toBean(entity, ApsLineCapabilityVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
TableDataInfo<ApsLineCapabilityVo> build = TableDataInfo.build(voList);
|
||||
build.setTotal(result.getTotal());
|
||||
return build;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ApsLineCapabilityVo> queryList(ApsLineCapabilityBo bo) {
|
||||
LambdaQueryWrapper<ApsLineCapabilityEntity> lqw = buildQueryWrapper(bo);
|
||||
List<ApsLineCapabilityEntity> list = baseMapper.selectList(lqw);
|
||||
return list.stream()
|
||||
.map(entity -> {
|
||||
ApsLineCapabilityVo vo = BeanUtil.toBean(entity, ApsLineCapabilityVo.class);
|
||||
enrichVo(vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void enrichVo(ApsLineCapabilityVo vo) {
|
||||
if (vo == null) return;
|
||||
if (vo.getIsEnabled() != null) {
|
||||
vo.setIsEnabledName(ENABLED_MAP.getOrDefault(vo.getIsEnabled(), "未知"));
|
||||
}
|
||||
if (vo.getLineId() != null) {
|
||||
try {
|
||||
WmsProductionLineVo line = productionLineService.queryById(vo.getLineId());
|
||||
if (line != null) {
|
||||
vo.setLineName(line.getLineName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 忽略异常,仅记录
|
||||
}
|
||||
}
|
||||
// TODO: 如果产品ID和工序ID有对应的服务,可以在这里补充产品名称和工序名称
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ApsLineCapabilityEntity> buildQueryWrapper(ApsLineCapabilityBo bo) {
|
||||
LambdaQueryWrapper<ApsLineCapabilityEntity> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getLineId() != null, ApsLineCapabilityEntity::getLineId, bo.getLineId());
|
||||
lqw.eq(bo.getProductId() != null, ApsLineCapabilityEntity::getProductId, bo.getProductId());
|
||||
lqw.eq(bo.getProcessId() != null, ApsLineCapabilityEntity::getProcessId, bo.getProcessId());
|
||||
lqw.eq(bo.getIsEnabled() != null, ApsLineCapabilityEntity::getIsEnabled, bo.getIsEnabled());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ApsLineCapabilityBo bo) {
|
||||
ApsLineCapabilityEntity entity = BeanUtil.toBean(bo, ApsLineCapabilityEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ApsLineCapabilityBo bo) {
|
||||
ApsLineCapabilityEntity entity = BeanUtil.toBean(bo, ApsLineCapabilityEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ApsLineCapabilityEntity entity) {
|
||||
// 如果产品ID和工序ID都为空,表示通用能力,允许重复
|
||||
// 如果产品ID或工序ID不为空,检查是否已存在
|
||||
if (entity.getProductId() != null || entity.getProcessId() != null) {
|
||||
ApsLineCapabilityEntity exist = baseMapper.selectByLineProductAndProcess(
|
||||
entity.getLineId(), entity.getProductId(), entity.getProcessId());
|
||||
if (exist != null && !exist.getCapabilityId().equals(entity.getCapabilityId())) {
|
||||
throw new ServiceException("该产线、产品和工序的组合已存在");
|
||||
}
|
||||
}
|
||||
if (entity.getIsEnabled() == null) {
|
||||
entity.setIsEnabled(1);
|
||||
}
|
||||
if (entity.getPriority() == null) {
|
||||
entity.setPriority(999);
|
||||
}
|
||||
if (entity.getSetupMinutes() == null) {
|
||||
entity.setSetupMinutes(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 可以添加业务校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.dto.ApsLockReq;
|
||||
import com.klp.aps.domain.entity.ApsScheduleLockEntity;
|
||||
import com.klp.aps.mapper.ApsLockMapper;
|
||||
import com.klp.aps.service.ApsLockService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsLockServiceImpl implements ApsLockService {
|
||||
|
||||
private final ApsLockMapper apsLockMapper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long createLock(ApsLockReq req, String operator) {
|
||||
if (req.getLockType() == null) {
|
||||
throw new ServiceException("lockType 不能为空");
|
||||
}
|
||||
if (req.getLockType() == 2 && (req.getLineId() == null || req.getLockStartTime() == null || req.getLockEndTime() == null)) {
|
||||
throw new ServiceException("产线时间窗锁定必须指定 lineId / lockStartTime / lockEndTime");
|
||||
}
|
||||
if (req.getLockType() == 3 && req.getOperationId() == null) {
|
||||
throw new ServiceException("工序锁定必须指定 operationId");
|
||||
}
|
||||
if (req.getLockStartTime() != null && req.getLockEndTime() != null
|
||||
&& !req.getLockStartTime().isBefore(req.getLockEndTime())) {
|
||||
throw new ServiceException("lockStartTime 必须早于 lockEndTime");
|
||||
}
|
||||
|
||||
ApsScheduleLockEntity lock = new ApsScheduleLockEntity();
|
||||
lock.setLockType(req.getLockType());
|
||||
lock.setPlanId(req.getPlanId());
|
||||
lock.setLineId(req.getLineId());
|
||||
lock.setOperationId(req.getOperationId());
|
||||
lock.setLockStartTime(req.getLockStartTime());
|
||||
lock.setLockEndTime(req.getLockEndTime());
|
||||
lock.setLockReason(req.getLockReason());
|
||||
lock.setStatus(1);
|
||||
lock.setCreateBy(operator);
|
||||
lock.setUpdateBy(operator);
|
||||
|
||||
apsLockMapper.insertLock(lock);
|
||||
if (lock.getLockId() == null) {
|
||||
throw new ServiceException("创建锁定记录失败:未回填 lockId");
|
||||
}
|
||||
return lock.getLockId();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void releaseLock(Long lockId, String operator) {
|
||||
int rows = apsLockMapper.updateLockStatus(lockId, 0, operator);
|
||||
if (rows == 0) {
|
||||
throw new ServiceException("锁定记录不存在或已失效");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.dto.ApsRescheduleReq;
|
||||
import com.klp.aps.domain.entity.ApsScheduleChangeLogEntity;
|
||||
import com.klp.aps.domain.entity.ApsScheduleOperationEntity;
|
||||
import com.klp.aps.mapper.ApsAutoScheduleMapper;
|
||||
import com.klp.aps.mapper.ApsOperationMapper;
|
||||
import com.klp.aps.service.ApsOperationService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsOperationServiceImpl implements ApsOperationService {
|
||||
|
||||
private final ApsOperationMapper apsOperationMapper;
|
||||
private final ApsAutoScheduleMapper apsAutoScheduleMapper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void reschedule(ApsRescheduleReq req, String operator) {
|
||||
ApsScheduleOperationEntity origin = apsOperationMapper.selectByIdForUpdate(req.getOperationId());
|
||||
if (origin == null) {
|
||||
throw new ServiceException("工序排程不存在");
|
||||
}
|
||||
if (origin.getLockedFlag() != null && origin.getLockedFlag() == 1) {
|
||||
throw new ServiceException("工序已锁定,禁止重排");
|
||||
}
|
||||
|
||||
LocalDateTime start = req.getTargetStartTime();
|
||||
LocalDateTime end = req.getTargetEndTime();
|
||||
if (start.isAfter(end) || start.equals(end)) {
|
||||
throw new ServiceException("目标开始时间必须早于结束时间");
|
||||
}
|
||||
|
||||
// 冲突 & 锁定校验(排除自身)
|
||||
Long lineId = req.getTargetLineId();
|
||||
Long excludeId = origin.getOperationId();
|
||||
|
||||
LocalDateTime conflictEnd = apsAutoScheduleMapper.selectFirstConflictEndTime(lineId, start, end, excludeId);
|
||||
if (conflictEnd != null) {
|
||||
throw new ServiceException("目标时间窗存在产线冲突,无法重排");
|
||||
}
|
||||
LocalDateTime lockEnd = apsAutoScheduleMapper.selectFirstHitLockEndTime(lineId, start, end, origin.getPlanId(), excludeId);
|
||||
if (lockEnd != null) {
|
||||
throw new ServiceException("目标时间窗命中锁定区间,无法重排");
|
||||
}
|
||||
|
||||
// 备份 before
|
||||
String beforeJson = com.alibaba.fastjson2.JSON.toJSONString(origin);
|
||||
|
||||
origin.setLineId(lineId);
|
||||
origin.setStartTime(start);
|
||||
origin.setEndTime(end);
|
||||
origin.setUpdateBy(operator);
|
||||
apsOperationMapper.updateSlot(origin);
|
||||
|
||||
// after
|
||||
String afterJson = com.alibaba.fastjson2.JSON.toJSONString(origin);
|
||||
|
||||
ApsScheduleChangeLogEntity log = new ApsScheduleChangeLogEntity();
|
||||
log.setOperationId(origin.getOperationId());
|
||||
log.setChangeType("RESCHEDULE");
|
||||
log.setBeforeValue(beforeJson);
|
||||
log.setAfterValue(afterJson);
|
||||
log.setChangeReason(req.getReason());
|
||||
log.setChangeBy(operator);
|
||||
apsOperationMapper.insertChangeLog(log);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.klp.aps.domain.dto.ApsConvertFromProductReq;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.aps.domain.dto.ApsPlanCreateReq;
|
||||
import com.klp.aps.domain.dto.ApsWmsOrderCreateReq;
|
||||
import com.klp.aps.domain.dto.ApsWmsOrderDetailCreateReq;
|
||||
import com.klp.aps.domain.entity.ApsSchedulePlanDetailEntity;
|
||||
import com.klp.aps.domain.entity.ApsSchedulePlanEntity;
|
||||
import com.klp.aps.domain.row.ApsCrmOrderItemRow;
|
||||
import com.klp.aps.domain.row.ApsCrmOrderRow;
|
||||
import com.klp.aps.domain.row.ApsOrderDetailRow;
|
||||
import com.klp.aps.domain.row.ApsSchedulePlanRow;
|
||||
import com.klp.aps.domain.row.ApsWmsOrderRow;
|
||||
import com.klp.aps.mapper.ApsAutoScheduleMapper;
|
||||
import com.klp.aps.mapper.ApsPlanMapper;
|
||||
import com.klp.aps.service.ApsPlanService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsPlanServiceImpl implements ApsPlanService {
|
||||
|
||||
private final ApsPlanMapper apsPlanMapper;
|
||||
private final ApsAutoScheduleMapper apsAutoScheduleMapper;
|
||||
|
||||
private static final DateTimeFormatter PLAN_CODE_TIME = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long convertFromCrmOrder(String crmOrderId, String operator) {
|
||||
return convertFromCrmOrderWithItems(crmOrderId, null, operator);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long convertFromCrmOrderWithItems(String crmOrderId, List<String> crmItemIds, String operator) {
|
||||
ApsCrmOrderRow crmOrder = apsPlanMapper.selectCrmOrderById(crmOrderId);
|
||||
if (crmOrder == null) {
|
||||
throw new ServiceException("CRM 订单不存在");
|
||||
}
|
||||
List<ApsCrmOrderItemRow> items = apsPlanMapper.selectCrmOrderItemsByOrderId(crmOrderId);
|
||||
if (items == null || items.isEmpty()) {
|
||||
throw new ServiceException("CRM 订单明细为空,无法转换");
|
||||
}
|
||||
if (crmItemIds != null && !crmItemIds.isEmpty()) {
|
||||
items = items.stream().filter(i -> crmItemIds.contains(i.getItemId())).collect(java.util.stream.Collectors.toList());
|
||||
if (items.isEmpty()) {
|
||||
throw new ServiceException("所选 CRM 明细为空,无法转换");
|
||||
}
|
||||
}
|
||||
|
||||
String wmsOrderCode = "CRM-" + crmOrder.getOrderCode();
|
||||
ApsWmsOrderRow existed = apsPlanMapper.selectWmsOrderByCode(wmsOrderCode);
|
||||
if (existed != null && existed.getOrderId() != null) {
|
||||
return existed.getOrderId();
|
||||
}
|
||||
|
||||
Long customerId = null;
|
||||
try {
|
||||
if (StringUtils.isNotBlank(crmOrder.getCustomerId())) {
|
||||
customerId = Long.valueOf(crmOrder.getCustomerId());
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
ApsWmsOrderCreateReq orderCreateReq = new ApsWmsOrderCreateReq();
|
||||
orderCreateReq.setOrderCode(wmsOrderCode);
|
||||
orderCreateReq.setCustomerId(customerId);
|
||||
orderCreateReq.setCustomerName(crmOrder.getCustomerId());
|
||||
orderCreateReq.setSalesManager(crmOrder.getSalesman());
|
||||
orderCreateReq.setOrderStatus(0);
|
||||
orderCreateReq.setRemark("由 CRM 订单 " + crmOrder.getOrderCode() + " 转换");
|
||||
orderCreateReq.setTaxAmount(crmOrder.getOrderAmount());
|
||||
orderCreateReq.setNoTaxAmount(crmOrder.getOrderAmount());
|
||||
orderCreateReq.setCreateBy(operator);
|
||||
orderCreateReq.setUpdateBy(operator);
|
||||
apsPlanMapper.insertWmsOrder(orderCreateReq);
|
||||
|
||||
ApsWmsOrderRow created = apsPlanMapper.selectWmsOrderByCode(wmsOrderCode);
|
||||
if (created == null || created.getOrderId() == null) {
|
||||
throw new ServiceException("转换失败:WMS 订单未生成");
|
||||
}
|
||||
|
||||
for (ApsCrmOrderItemRow item : items) {
|
||||
Long productId = parseLong(item.getProductType());
|
||||
if (productId == null) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal qty = BigDecimal.valueOf(item.getProductNum() == null ? 0 : item.getProductNum());
|
||||
BigDecimal taxPrice = item.getContractPrice() == null ? BigDecimal.ZERO : item.getContractPrice();
|
||||
ApsWmsOrderDetailCreateReq detailCreateReq = new ApsWmsOrderDetailCreateReq();
|
||||
detailCreateReq.setOrderId(created.getOrderId());
|
||||
detailCreateReq.setProductId(productId);
|
||||
detailCreateReq.setQuantity(qty);
|
||||
detailCreateReq.setUnit("件");
|
||||
detailCreateReq.setRemark(item.getRemark());
|
||||
detailCreateReq.setTaxPrice(taxPrice);
|
||||
detailCreateReq.setNoTaxPrice(taxPrice);
|
||||
detailCreateReq.setGroupId(null);
|
||||
detailCreateReq.setDelFlag(0);
|
||||
detailCreateReq.setCreateBy(operator);
|
||||
detailCreateReq.setUpdateBy(operator);
|
||||
apsPlanMapper.insertWmsOrderDetail(detailCreateReq);
|
||||
}
|
||||
|
||||
return created.getOrderId();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long createPlan(ApsPlanCreateReq req, String operator) {
|
||||
List<ApsOrderDetailRow> orderDetails = apsPlanMapper.selectOrderDetailsByOrderId(req.getOrderId());
|
||||
if (orderDetails == null || orderDetails.isEmpty()) {
|
||||
throw new ServiceException("订单明细为空,无法创建排产计划(orderId=" + req.getOrderId() + ")");
|
||||
}
|
||||
|
||||
Long selectedLineId = req.getLineId();
|
||||
if (selectedLineId == null) {
|
||||
selectedLineId = apsPlanMapper.selectAnyProductionLineId();
|
||||
}
|
||||
if (selectedLineId == null) {
|
||||
throw new ServiceException("未找到可用产线(wms_production_line 为空),无法创建排产明细");
|
||||
}
|
||||
|
||||
String planCode = req.getPlanCode();
|
||||
if (StringUtils.isBlank(planCode)) {
|
||||
planCode = genPlanCode();
|
||||
}
|
||||
String version = StringUtils.isBlank(req.getVersion()) ? "V1" : req.getVersion().trim();
|
||||
|
||||
ApsSchedulePlanEntity plan = new ApsSchedulePlanEntity();
|
||||
plan.setPlanCode(planCode);
|
||||
plan.setVersion(version);
|
||||
plan.setOrderId(req.getOrderId());
|
||||
plan.setStatus(0);
|
||||
plan.setRemark(req.getRemark());
|
||||
plan.setDelFlag(0);
|
||||
plan.setPriority(req.getPriority());
|
||||
plan.setStartDate(req.getStartDate());
|
||||
plan.setEndDate(req.getEndDate());
|
||||
plan.setCreateBy(operator);
|
||||
plan.setUpdateBy(operator);
|
||||
|
||||
apsPlanMapper.insertSchedulePlan(plan);
|
||||
if (plan.getPlanId() == null) {
|
||||
throw new ServiceException("创建排产计划失败:未回填 planId");
|
||||
}
|
||||
|
||||
LocalDate detailStart = resolveDetailStart(req.getStartDate());
|
||||
LocalDate detailEnd = resolveDetailEnd(req.getEndDate(), detailStart);
|
||||
|
||||
for (ApsOrderDetailRow od : orderDetails) {
|
||||
ApsSchedulePlanDetailEntity detail = new ApsSchedulePlanDetailEntity();
|
||||
detail.setPlanId(plan.getPlanId());
|
||||
detail.setLineId(selectedLineId);
|
||||
|
||||
// wms_schedule_plan_detail.task_id 当前无外键约束,MVP 先用订单明细ID占位,后续接入生产任务时再替换
|
||||
detail.setTaskId(od.getDetailId());
|
||||
detail.setProductId(od.getProductId());
|
||||
detail.setQuantity(scale4(od.getQuantity()));
|
||||
detail.setStartDate(detailStart);
|
||||
detail.setEndDate(detailEnd);
|
||||
detail.setRemark(req.getRemark());
|
||||
detail.setDelFlag(0);
|
||||
detail.setCreateBy(operator);
|
||||
detail.setUpdateBy(operator);
|
||||
|
||||
apsPlanMapper.insertSchedulePlanDetail(detail);
|
||||
}
|
||||
|
||||
return plan.getPlanId();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long convertFromProduct(Long productId, BigDecimal quantity, String productName, String remark, String operator) {
|
||||
ApsConvertFromProductReq one = new ApsConvertFromProductReq();
|
||||
one.setProductId(productId);
|
||||
one.setQuantity(quantity);
|
||||
one.setProductName(productName);
|
||||
one.setRemark(remark);
|
||||
return convertFromProducts(java.util.Collections.singletonList(one), remark, operator);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public Long convertFromProducts(List<ApsConvertFromProductReq> items, String remark, String operator) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
throw new ServiceException("items 不能为空");
|
||||
}
|
||||
|
||||
String code = "PRD-" + LocalDateTime.now().format(PLAN_CODE_TIME) + ThreadLocalRandom.current().nextInt(100, 999);
|
||||
ApsWmsOrderCreateReq orderCreateReq = new ApsWmsOrderCreateReq();
|
||||
orderCreateReq.setOrderCode(code);
|
||||
orderCreateReq.setCustomerId(null);
|
||||
orderCreateReq.setCustomerName("产品直排");
|
||||
orderCreateReq.setSalesManager(operator);
|
||||
orderCreateReq.setOrderStatus(0);
|
||||
orderCreateReq.setRemark(StringUtils.isBlank(remark) ? "APS_PRODUCT_DIRECT_BATCH" : remark);
|
||||
orderCreateReq.setTaxAmount(BigDecimal.ZERO);
|
||||
orderCreateReq.setNoTaxAmount(BigDecimal.ZERO);
|
||||
orderCreateReq.setCreateBy(operator);
|
||||
orderCreateReq.setUpdateBy(operator);
|
||||
apsPlanMapper.insertWmsOrder(orderCreateReq);
|
||||
|
||||
ApsWmsOrderRow created = apsPlanMapper.selectWmsOrderByCode(code);
|
||||
if (created == null || created.getOrderId() == null) {
|
||||
throw new ServiceException("创建库存订单失败");
|
||||
}
|
||||
|
||||
for (ApsConvertFromProductReq item : items) {
|
||||
if (item == null || item.getProductId() == null) {
|
||||
continue;
|
||||
}
|
||||
if (item.getQuantity() == null || item.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
ApsWmsOrderDetailCreateReq detailCreateReq = new ApsWmsOrderDetailCreateReq();
|
||||
detailCreateReq.setOrderId(created.getOrderId());
|
||||
detailCreateReq.setProductId(item.getProductId());
|
||||
detailCreateReq.setQuantity(scale4(item.getQuantity()));
|
||||
detailCreateReq.setUnit("件");
|
||||
detailCreateReq.setRemark(StringUtils.isBlank(item.getProductName()) ? "产品直排" : ("产品直排:" + item.getProductName()));
|
||||
detailCreateReq.setTaxPrice(BigDecimal.ZERO);
|
||||
detailCreateReq.setNoTaxPrice(BigDecimal.ZERO);
|
||||
detailCreateReq.setGroupId(null);
|
||||
detailCreateReq.setDelFlag(0);
|
||||
detailCreateReq.setCreateBy(operator);
|
||||
detailCreateReq.setUpdateBy(operator);
|
||||
apsPlanMapper.insertWmsOrderDetail(detailCreateReq);
|
||||
}
|
||||
|
||||
return created.getOrderId();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void publishPlan(Long planId, String operator) {
|
||||
ApsSchedulePlanRow plan = apsAutoScheduleMapper.selectPlanByIdForUpdate(planId);
|
||||
if (plan == null) {
|
||||
throw new ServiceException("排产计划不存在");
|
||||
}
|
||||
Integer status = plan.getStatus();
|
||||
if (status == null || status != 1) {
|
||||
throw new ServiceException("仅已排产状态的计划可发布");
|
||||
}
|
||||
// 约定:0=新建 1=已排产 2=已发布/生产中
|
||||
apsAutoScheduleMapper.updatePlanStatus(planId, 2, operator);
|
||||
}
|
||||
|
||||
private static String genPlanCode() {
|
||||
int rnd = ThreadLocalRandom.current().nextInt(1000, 10000);
|
||||
return "APS" + LocalDateTime.now().format(PLAN_CODE_TIME) + rnd;
|
||||
}
|
||||
|
||||
private static LocalDate resolveDetailStart(LocalDateTime planStart) {
|
||||
return planStart != null ? planStart.toLocalDate() : LocalDate.now();
|
||||
}
|
||||
|
||||
private static LocalDate resolveDetailEnd(LocalDateTime planEnd, LocalDate fallbackStart) {
|
||||
LocalDate d = planEnd != null ? planEnd.toLocalDate() : null;
|
||||
return d != null ? d : fallbackStart;
|
||||
}
|
||||
|
||||
private static BigDecimal scale4(BigDecimal v) {
|
||||
if (v == null) {
|
||||
return BigDecimal.ZERO.setScale(4);
|
||||
}
|
||||
try {
|
||||
return v.setScale(4, RoundingMode.HALF_UP);
|
||||
} catch (Exception e) {
|
||||
return new BigDecimal(v.toPlainString()).setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
}
|
||||
|
||||
private static Long parseLong(String text) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.valueOf(text.trim());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetQueryReq;
|
||||
import com.klp.aps.domain.dto.ApsScheduleSheetSupplementSaveReq;
|
||||
import com.klp.aps.domain.vo.ApsScheduleSheetResp;
|
||||
import com.klp.aps.domain.vo.ApsScheduleSheetRowVo;
|
||||
import com.klp.aps.mapper.ApsScheduleSheetMapper;
|
||||
import com.klp.aps.service.ApsScheduleSheetService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsScheduleSheetServiceImpl implements ApsScheduleSheetService {
|
||||
|
||||
private final ApsScheduleSheetMapper apsScheduleSheetMapper;
|
||||
|
||||
@Override
|
||||
public ApsScheduleSheetResp query(ApsScheduleSheetQueryReq req) {
|
||||
List<ApsScheduleSheetRowVo> rows = apsScheduleSheetMapper.selectSheetRows(req);
|
||||
|
||||
ApsScheduleSheetResp resp = new ApsScheduleSheetResp();
|
||||
Map<String, Object> header = new HashMap<>();
|
||||
header.put("planId", req.getPlanId());
|
||||
header.put("orderId", req.getOrderId());
|
||||
header.put("lineId", req.getLineId());
|
||||
header.put("queryStart", req.getQueryStart());
|
||||
header.put("queryEnd", req.getQueryEnd());
|
||||
resp.setHeader(header);
|
||||
resp.setRows(rows);
|
||||
|
||||
ApsScheduleSheetResp.Summary s = new ApsScheduleSheetResp.Summary();
|
||||
s.setTotalCount(rows == null ? 0 : rows.size());
|
||||
s.setTotalPlanQty(sumPlanQty(rows));
|
||||
s.setTotalRawNetWeight(sumRawWeight(rows));
|
||||
resp.setSummary(s);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
|
||||
public void saveSupplement(ApsScheduleSheetSupplementSaveReq req, String operator) {
|
||||
if (req == null || req.getRows() == null || req.getRows().isEmpty()) {
|
||||
throw new ServiceException("保存数据不能为空");
|
||||
}
|
||||
for (ApsScheduleSheetSupplementSaveReq.Row row : req.getRows()) {
|
||||
if (row == null || row.getOperationId() == null) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Object> remarkMap = new LinkedHashMap<>();
|
||||
remarkMap.put("rawMaterialId", row.getRawMaterialId());
|
||||
remarkMap.put("rawCoilNos", row.getRawCoilNos());
|
||||
remarkMap.put("rawNetWeight", row.getRawNetWeight());
|
||||
remarkMap.put("rawPackaging", row.getRawPackaging());
|
||||
remarkMap.put("rawEdgeReq", row.getRawEdgeReq());
|
||||
remarkMap.put("rawCoatingType", row.getRawCoatingType());
|
||||
remarkMap.put("rawLocation", row.getRawLocation());
|
||||
String remarkJson = com.alibaba.fastjson2.JSON.toJSONString(remarkMap);
|
||||
|
||||
apsScheduleSheetMapper.updateOperationSupplement(row.getOperationId(), remarkJson, operator);
|
||||
apsScheduleSheetMapper.deleteOperationCoils(row.getOperationId(), operator);
|
||||
if (row.getRawMaterialId() != null) {
|
||||
apsScheduleSheetMapper.insertOperationCoil(row.getOperationId(), row.getRawMaterialId(), operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportExcel(ApsScheduleSheetQueryReq req, HttpServletResponse response) {
|
||||
ApsScheduleSheetResp data = query(req);
|
||||
List<ApsScheduleSheetRowVo> rows = data.getRows();
|
||||
|
||||
try (Workbook wb = new XSSFWorkbook()) {
|
||||
Sheet sheet = wb.createSheet("APS排产表");
|
||||
|
||||
int r = 0;
|
||||
// 标题行(合并 0~14 列,高度加倍,字体加大加粗居中)
|
||||
Row title = sheet.createRow(r++);
|
||||
title.setHeightInPoints(40f);
|
||||
Cell t0 = title.createCell(0);
|
||||
t0.setCellValue("统一排产表(冷轧/酸轧等机组通用)");
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 14));
|
||||
|
||||
CellStyle titleStyle = wb.createCellStyle();
|
||||
titleStyle.setAlignment(HorizontalAlignment.CENTER);
|
||||
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
XSSFFont titleFont = ((XSSFWorkbook) wb).createFont();
|
||||
titleFont.setBold(true);
|
||||
titleFont.setFontHeightInPoints((short) 16);
|
||||
titleStyle.setFont(titleFont);
|
||||
t0.setCellStyle(titleStyle);
|
||||
|
||||
// 查询条件行
|
||||
Row info = sheet.createRow(r++);
|
||||
info.createCell(0).setCellValue("时间范围:");
|
||||
info.createCell(1).setCellValue(fmt(req.getQueryStart()) + " ~ " + fmt(req.getQueryEnd()));
|
||||
if (req.getLineId() != null) {
|
||||
info.createCell(3).setCellValue("产线ID:");
|
||||
info.createCell(4).setCellValue(String.valueOf(req.getLineId()));
|
||||
}
|
||||
if (req.getPlanId() != null) {
|
||||
info.createCell(6).setCellValue("计划ID:");
|
||||
info.createCell(7).setCellValue(String.valueOf(req.getPlanId()));
|
||||
}
|
||||
|
||||
// 表头
|
||||
Row head = sheet.createRow(r++);
|
||||
int c = 0;
|
||||
head.createCell(c++).setCellValue("产线");
|
||||
head.createCell(c++).setCellValue("计划号");
|
||||
head.createCell(c++).setCellValue("订单号");
|
||||
head.createCell(c++).setCellValue("客户");
|
||||
head.createCell(c++).setCellValue("业务员");
|
||||
head.createCell(c++).setCellValue("产品");
|
||||
head.createCell(c++).setCellValue("计划数量");
|
||||
head.createCell(c++).setCellValue("开始时间");
|
||||
head.createCell(c++).setCellValue("结束时间");
|
||||
head.createCell(c++).setCellValue("原料卷号");
|
||||
head.createCell(c++).setCellValue("钢卷位置");
|
||||
head.createCell(c++).setCellValue("原料净重");
|
||||
head.createCell(c++).setCellValue("包装要求");
|
||||
head.createCell(c++).setCellValue("切边要求");
|
||||
head.createCell(c++).setCellValue("镀层种类");
|
||||
|
||||
if (rows != null) {
|
||||
for (ApsScheduleSheetRowVo row : rows) {
|
||||
Row rr = sheet.createRow(r++);
|
||||
int cc = 0;
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getLineName(), row.getLineId()));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getPlanCode(), row.getPlanId()));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getOrderCode(), row.getOrderId()));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getCustomerName(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getSalesman(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getProductName(), ""));
|
||||
rr.createCell(cc++).setCellValue(row.getPlanQty() == null ? "" : row.getPlanQty().toPlainString());
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getStartTime(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getEndTime(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getRawCoilNos(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getRawLocation(), ""));
|
||||
rr.createCell(cc++).setCellValue(row.getRawNetWeight() == null ? "" : row.getRawNetWeight().toPlainString());
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getRawPackaging(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getRawEdgeReq(), ""));
|
||||
rr.createCell(cc++).setCellValue(nvl(row.getRawCoatingType(), ""));
|
||||
}
|
||||
}
|
||||
|
||||
// 合计行
|
||||
ApsScheduleSheetResp.Summary s = data.getSummary();
|
||||
Row sum = sheet.createRow(r++);
|
||||
sum.createCell(0).setCellValue("合计");
|
||||
sum.createCell(6).setCellValue(s.getTotalPlanQty() == null ? "" : s.getTotalPlanQty().toPlainString());
|
||||
sum.createCell(10).setCellValue(s.getTotalRawNetWeight() == null ? "" : s.getTotalRawNetWeight().toPlainString());
|
||||
|
||||
// 自动列宽(前 14 列)
|
||||
for (int i = 0; i < 14; i++) {
|
||||
sheet.autoSizeColumn(i, true);
|
||||
int w = sheet.getColumnWidth(i);
|
||||
sheet.setColumnWidth(i, Math.min(Math.max(w, 3000), 12000));
|
||||
}
|
||||
|
||||
String filename = "aps_schedule_sheet_" + System.currentTimeMillis() + ".xlsx";
|
||||
String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8.name());
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encoded);
|
||||
|
||||
try (ServletOutputStream os = response.getOutputStream()) {
|
||||
wb.write(os);
|
||||
os.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("导出失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static BigDecimal sumPlanQty(List<ApsScheduleSheetRowVo> rows) {
|
||||
BigDecimal sum = BigDecimal.ZERO;
|
||||
if (rows == null) return sum;
|
||||
for (ApsScheduleSheetRowVo r : rows) {
|
||||
if (r.getPlanQty() != null) {
|
||||
sum = sum.add(r.getPlanQty());
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static BigDecimal sumRawWeight(List<ApsScheduleSheetRowVo> rows) {
|
||||
BigDecimal sum = BigDecimal.ZERO;
|
||||
if (rows == null) return sum;
|
||||
for (ApsScheduleSheetRowVo r : rows) {
|
||||
if (r.getRawNetWeight() != null) {
|
||||
sum = sum.add(r.getRawNetWeight());
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static final DateTimeFormatter DT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private static String fmt(java.time.LocalDateTime t) {
|
||||
return t == null ? "" : t.format(DT);
|
||||
}
|
||||
|
||||
private static String nvl(String s, Object fallback) {
|
||||
if (s != null && !s.isEmpty()) return s;
|
||||
return fallback == null ? "" : String.valueOf(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.klp.aps.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.aps.domain.bo.ApsShiftTemplateBo;
|
||||
import com.klp.aps.domain.entity.ApsShiftTemplateEntity;
|
||||
import com.klp.aps.domain.vo.ApsShiftTemplateVo;
|
||||
import com.klp.aps.mapper.ApsShiftTemplateMapper;
|
||||
import com.klp.aps.service.ApsShiftTemplateService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 班次模板Service业务层处理
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ApsShiftTemplateServiceImpl implements ApsShiftTemplateService {
|
||||
|
||||
private final ApsShiftTemplateMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public ApsShiftTemplateVo queryById(Long shiftId) {
|
||||
ApsShiftTemplateEntity entity = baseMapper.selectById(shiftId);
|
||||
ApsShiftTemplateVo vo = BeanUtil.toBean(entity, ApsShiftTemplateVo.class);
|
||||
if (vo != null && vo.getCrossDay() != null) {
|
||||
vo.setCrossDayName(vo.getCrossDay() == 1 ? "跨天" : "不跨天");
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ApsShiftTemplateVo> queryPageList(ApsShiftTemplateBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ApsShiftTemplateEntity> lqw = buildQueryWrapper(bo);
|
||||
Page<ApsShiftTemplateEntity> result = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
List<ApsShiftTemplateVo> voList = result.getRecords().stream()
|
||||
.map(entity -> {
|
||||
ApsShiftTemplateVo vo = BeanUtil.toBean(entity, ApsShiftTemplateVo.class);
|
||||
if (vo.getCrossDay() != null) {
|
||||
vo.setCrossDayName(vo.getCrossDay() == 1 ? "跨天" : "不跨天");
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
TableDataInfo<ApsShiftTemplateVo> build = TableDataInfo.build(voList);
|
||||
build.setTotal(result.getTotal());
|
||||
return build;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ApsShiftTemplateVo> queryList(ApsShiftTemplateBo bo) {
|
||||
LambdaQueryWrapper<ApsShiftTemplateEntity> lqw = buildQueryWrapper(bo);
|
||||
List<ApsShiftTemplateEntity> list = baseMapper.selectList(lqw);
|
||||
return list.stream()
|
||||
.map(entity -> {
|
||||
ApsShiftTemplateVo vo = BeanUtil.toBean(entity, ApsShiftTemplateVo.class);
|
||||
if (vo.getCrossDay() != null) {
|
||||
vo.setCrossDayName(vo.getCrossDay() == 1 ? "跨天" : "不跨天");
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ApsShiftTemplateEntity> buildQueryWrapper(ApsShiftTemplateBo bo) {
|
||||
LambdaQueryWrapper<ApsShiftTemplateEntity> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getShiftCode()), ApsShiftTemplateEntity::getShiftCode, bo.getShiftCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getShiftName()), ApsShiftTemplateEntity::getShiftName, bo.getShiftName());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ApsShiftTemplateBo bo) {
|
||||
ApsShiftTemplateEntity entity = BeanUtil.toBean(bo, ApsShiftTemplateEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ApsShiftTemplateBo bo) {
|
||||
ApsShiftTemplateEntity entity = BeanUtil.toBean(bo, ApsShiftTemplateEntity.class);
|
||||
validEntityBeforeSave(entity);
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ApsShiftTemplateEntity entity) {
|
||||
ApsShiftTemplateEntity exist = baseMapper.selectByShiftCode(entity.getShiftCode());
|
||||
if (exist != null && !exist.getShiftId().equals(entity.getShiftId())) {
|
||||
throw new ServiceException("班次编码已存在");
|
||||
}
|
||||
if (entity.getCrossDay() == null) {
|
||||
entity.setCrossDay(0);
|
||||
}
|
||||
if (entity.getEfficiencyRate() == null) {
|
||||
entity.setEfficiencyRate(java.math.BigDecimal.ONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 可以添加业务校验,例如检查是否被日历班次配置使用
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
0
klp-aps/src/main/resources/mapper/1.txt
Normal file
0
klp-aps/src/main/resources/mapper/1.txt
Normal file
@@ -0,0 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsAutoScheduleMapper">
|
||||
|
||||
<select id="selectPlanByIdForUpdate"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsSchedulePlanRow">
|
||||
SELECT
|
||||
plan_id AS planId,
|
||||
plan_code AS planCode,
|
||||
version AS version,
|
||||
order_id AS orderId,
|
||||
status AS status,
|
||||
start_date AS startDate,
|
||||
end_date AS endDate
|
||||
FROM wms_schedule_plan
|
||||
WHERE plan_id = #{planId}
|
||||
AND del_flag = 0
|
||||
FOR UPDATE
|
||||
</select>
|
||||
|
||||
<select id="selectOrderDetailsByOrderId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsOrderDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
product_id AS productId,
|
||||
quantity AS quantity
|
||||
FROM wms_order_detail
|
||||
WHERE order_id = #{orderId}
|
||||
AND del_flag = 0
|
||||
ORDER BY detail_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectPlanDetailsByPlanId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsPlanDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
task_id AS taskId,
|
||||
line_id AS lineId,
|
||||
product_id AS productId,
|
||||
quantity AS quantity
|
||||
FROM wms_schedule_plan_detail
|
||||
WHERE plan_id = #{planId}
|
||||
AND del_flag = 0
|
||||
ORDER BY detail_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectLineCandidatesByProductAndLine"
|
||||
resultType="com.klp.aps.domain.row.ApsLineCapabilityRow">
|
||||
SELECT
|
||||
line_id AS lineId,
|
||||
capacity_per_hour AS capacityPerHour,
|
||||
setup_minutes AS setupMinutes,
|
||||
priority AS priority
|
||||
FROM wms_line_capability
|
||||
WHERE is_enabled = 1
|
||||
AND line_id = #{lineId}
|
||||
AND (product_id = #{productId} OR product_id IS NULL)
|
||||
ORDER BY CASE WHEN product_id = #{productId} THEN 0 ELSE 1 END, priority ASC, capability_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectLineMetaById" resultType="com.klp.aps.domain.row.ApsLineMetaRow">
|
||||
SELECT line_id AS lineId, line_name AS lineName
|
||||
FROM wms_production_line
|
||||
WHERE line_id = #{lineId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectProductMetaById" resultType="com.klp.aps.domain.row.ApsProductMetaRow">
|
||||
SELECT product_id AS productId, product_name AS productName, specification AS specification, material AS material
|
||||
FROM wms_product
|
||||
WHERE product_id = #{productId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectAvailableShifts"
|
||||
resultType="com.klp.aps.domain.row.ApsShiftSlotRow">
|
||||
SELECT
|
||||
cs.calendar_date AS calendarDate,
|
||||
cs.line_id AS lineId,
|
||||
cs.shift_id AS shiftId,
|
||||
cs.planned_hours AS plannedHours,
|
||||
st.start_time AS startTime,
|
||||
st.end_time AS endTime,
|
||||
st.cross_day AS crossDay,
|
||||
st.efficiency_rate AS efficiencyRate
|
||||
FROM wms_calendar_shift cs
|
||||
JOIN wms_shift_template st ON st.shift_id = cs.shift_id
|
||||
JOIN wms_calendar c ON c.calendar_date = cs.calendar_date
|
||||
WHERE cs.line_id = #{lineId}
|
||||
AND cs.status = 1
|
||||
AND c.calendar_type = 1
|
||||
AND cs.calendar_date BETWEEN #{startDate} AND #{endDate}
|
||||
ORDER BY cs.calendar_date, st.start_time
|
||||
</select>
|
||||
|
||||
<select id="selectPlanDetailId" resultType="long">
|
||||
SELECT detail_id
|
||||
FROM wms_schedule_plan_detail
|
||||
WHERE plan_id = #{planId}
|
||||
AND task_id = #{taskId}
|
||||
AND del_flag = 0
|
||||
ORDER BY detail_id ASC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<delete id="deleteUnlockedOperationsByPlanId">
|
||||
DELETE FROM wms_schedule_operation
|
||||
WHERE plan_id = #{planId}
|
||||
AND locked_flag = 0
|
||||
</delete>
|
||||
|
||||
<select id="selectFirstConflictEndTime" resultType="java.time.LocalDateTime">
|
||||
SELECT end_time
|
||||
FROM wms_schedule_operation
|
||||
WHERE line_id = #{lineId}
|
||||
AND status IN (0, 1, 3)
|
||||
<if test="excludeOperationId != null">
|
||||
AND operation_id <![CDATA[<>]]> #{excludeOperationId}
|
||||
</if>
|
||||
AND NOT (end_time <![CDATA[<=]]> #{startTime} OR start_time <![CDATA[>=]]> #{endTime})
|
||||
ORDER BY end_time ASC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectFirstHitLockEndTime" resultType="java.time.LocalDateTime">
|
||||
SELECT l.lock_end_time
|
||||
FROM wms_schedule_lock l
|
||||
WHERE l.status = 1
|
||||
<if test="planId != null">
|
||||
AND (l.plan_id = #{planId} OR l.plan_id IS NULL)
|
||||
</if>
|
||||
AND (l.line_id = #{lineId} OR l.line_id IS NULL)
|
||||
<if test="excludeOperationId != null">
|
||||
AND (l.operation_id IS NULL OR l.operation_id <![CDATA[<>]]> #{excludeOperationId})
|
||||
</if>
|
||||
AND l.lock_start_time IS NOT NULL
|
||||
AND l.lock_end_time IS NOT NULL
|
||||
AND NOT (l.lock_end_time <![CDATA[<=]]> #{startTime} OR l.lock_start_time <![CDATA[>=]]> #{endTime})
|
||||
ORDER BY l.lock_end_time ASC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertOperation"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleOperationEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="operationId"
|
||||
keyColumn="operation_id">
|
||||
INSERT INTO wms_schedule_operation
|
||||
(
|
||||
plan_id,
|
||||
detail_id,
|
||||
order_id,
|
||||
order_detail_id,
|
||||
product_id,
|
||||
process_id,
|
||||
line_id,
|
||||
sequence_no,
|
||||
plan_qty,
|
||||
start_time,
|
||||
end_time,
|
||||
setup_minutes,
|
||||
status,
|
||||
locked_flag,
|
||||
remark,
|
||||
create_by,
|
||||
update_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{planId},
|
||||
#{detailId},
|
||||
#{orderId},
|
||||
#{orderDetailId},
|
||||
#{productId},
|
||||
#{processId},
|
||||
#{lineId},
|
||||
#{sequenceNo},
|
||||
#{planQty},
|
||||
#{startTime},
|
||||
#{endTime},
|
||||
#{setupMinutes},
|
||||
#{status},
|
||||
#{lockedFlag},
|
||||
#{remark},
|
||||
#{createBy},
|
||||
#{updateBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertChangeLog"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="logId"
|
||||
keyColumn="log_id">
|
||||
INSERT INTO wms_schedule_change_log
|
||||
(
|
||||
operation_id,
|
||||
change_type,
|
||||
before_value,
|
||||
after_value,
|
||||
change_reason,
|
||||
change_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{operationId},
|
||||
#{changeType},
|
||||
#{beforeValue},
|
||||
#{afterValue},
|
||||
#{changeReason},
|
||||
#{changeBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updatePlanStatus">
|
||||
UPDATE wms_schedule_plan
|
||||
SET status = #{status},
|
||||
update_by = #{updateBy},
|
||||
update_time = CURRENT_TIMESTAMP
|
||||
WHERE plan_id = #{planId}
|
||||
AND del_flag = 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsCalendarMapper">
|
||||
|
||||
<resultMap type="com.klp.aps.domain.entity.ApsCalendarEntity" id="ApsCalendarResult">
|
||||
<result property="calendarId" column="calendar_id"/>
|
||||
<result property="calendarDate" column="calendar_date"/>
|
||||
<result property="calendarType" column="calendar_type"/>
|
||||
<result property="factoryCode" column="factory_code"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCalendarVo">
|
||||
SELECT calendar_id, calendar_date, calendar_type, factory_code, remark,
|
||||
create_by, create_time, update_by, update_time
|
||||
FROM wms_calendar
|
||||
</sql>
|
||||
|
||||
<select id="selectCalendarList" parameterType="com.klp.aps.domain.entity.ApsCalendarEntity" resultMap="ApsCalendarResult">
|
||||
<include refid="selectCalendarVo"/>
|
||||
<where>
|
||||
<if test="calendarDate != null">
|
||||
AND calendar_date = #{calendarDate}
|
||||
</if>
|
||||
<if test="calendarType != null">
|
||||
AND calendar_type = #{calendarType}
|
||||
</if>
|
||||
<if test="factoryCode != null and factoryCode != ''">
|
||||
AND factory_code = #{factoryCode}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY calendar_date DESC
|
||||
</select>
|
||||
|
||||
<select id="selectByDateAndFactory" resultMap="ApsCalendarResult">
|
||||
<include refid="selectCalendarVo"/>
|
||||
WHERE calendar_date = #{calendarDate}
|
||||
AND factory_code = #{factoryCode}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsCalendarShiftMapper">
|
||||
|
||||
<select id="selectByDateLineAndShift" resultType="com.klp.aps.domain.entity.ApsCalendarShiftEntity">
|
||||
SELECT *
|
||||
FROM wms_calendar_shift
|
||||
WHERE calendar_date = #{calendarDate}
|
||||
AND line_id = #{lineId}
|
||||
AND shift_id = #{shiftId}
|
||||
AND del_flag = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectDistinctLineIds" resultType="java.lang.Long">
|
||||
SELECT DISTINCT line_id
|
||||
FROM wms_production_line
|
||||
WHERE del_flag = 0
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
50
klp-da/src/main/resources/mapper/da/aps/ApsGanttMapper.xml
Normal file
50
klp-da/src/main/resources/mapper/da/aps/ApsGanttMapper.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsGanttMapper">
|
||||
|
||||
<select id="selectGanttItems"
|
||||
parameterType="com.klp.aps.domain.dto.ApsGanttQueryReq"
|
||||
resultType="com.klp.aps.domain.vo.ApsGanttItemVo">
|
||||
SELECT
|
||||
o.operation_id AS operationId,
|
||||
o.plan_id AS planId,
|
||||
p.plan_code AS planCode,
|
||||
o.order_id AS orderId,
|
||||
o.order_detail_id AS orderDetailId,
|
||||
o.product_id AS productId,
|
||||
pr.product_name AS productName,
|
||||
pr.material AS material,
|
||||
pr.specification AS specification,
|
||||
o.process_id AS processId,
|
||||
ps.process_name AS processName,
|
||||
o.line_id AS lineId,
|
||||
l.line_name AS lineName,
|
||||
o.sequence_no AS sequenceNo,
|
||||
o.plan_qty AS planQty,
|
||||
o.start_time AS startTime,
|
||||
o.end_time AS endTime,
|
||||
o.status AS status,
|
||||
o.locked_flag AS lockedFlag
|
||||
FROM wms_schedule_operation o
|
||||
LEFT JOIN wms_schedule_plan p ON p.plan_id = o.plan_id
|
||||
LEFT JOIN wms_product pr ON pr.product_id = o.product_id
|
||||
LEFT JOIN wms_processe ps ON ps.process_id = o.process_id
|
||||
LEFT JOIN wms_production_line l ON l.line_id = o.line_id
|
||||
WHERE o.end_time <![CDATA[>=]]> #{queryStart}
|
||||
AND o.start_time <![CDATA[<=]]> #{queryEnd}
|
||||
<if test="lineId != null">
|
||||
AND o.line_id = #{lineId}
|
||||
</if>
|
||||
<if test="planId != null">
|
||||
AND o.plan_id = #{planId}
|
||||
</if>
|
||||
<if test="orderId != null">
|
||||
AND o.order_id = #{orderId}
|
||||
</if>
|
||||
ORDER BY o.line_id, o.start_time
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsLineCapabilityMapper">
|
||||
|
||||
<select id="selectByLineProductAndProcess" resultType="com.klp.aps.domain.entity.ApsLineCapabilityEntity">
|
||||
SELECT *
|
||||
FROM wms_line_capability
|
||||
WHERE line_id = #{lineId}
|
||||
AND (product_id = #{productId} OR (product_id IS NULL AND #{productId} IS NULL))
|
||||
AND (process_id = #{processId} OR (process_id IS NULL AND #{processId} IS NULL))
|
||||
AND del_flag = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
49
klp-da/src/main/resources/mapper/da/aps/ApsLockMapper.xml
Normal file
49
klp-da/src/main/resources/mapper/da/aps/ApsLockMapper.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsLockMapper">
|
||||
|
||||
<insert id="insertLock"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleLockEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="lockId"
|
||||
keyColumn="lock_id">
|
||||
INSERT INTO wms_schedule_lock
|
||||
(
|
||||
lock_type,
|
||||
plan_id,
|
||||
line_id,
|
||||
operation_id,
|
||||
lock_start_time,
|
||||
lock_end_time,
|
||||
lock_reason,
|
||||
status,
|
||||
create_by,
|
||||
update_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{lockType},
|
||||
#{planId},
|
||||
#{lineId},
|
||||
#{operationId},
|
||||
#{lockStartTime},
|
||||
#{lockEndTime},
|
||||
#{lockReason},
|
||||
#{status},
|
||||
#{createBy},
|
||||
#{updateBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateLockStatus">
|
||||
UPDATE wms_schedule_lock
|
||||
SET status = #{status},
|
||||
update_by = #{updateBy},
|
||||
update_time = CURRENT_TIMESTAMP
|
||||
WHERE lock_id = #{lockId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsOperationMapper">
|
||||
|
||||
<resultMap id="ApsScheduleOperationMap"
|
||||
type="com.klp.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
<id property="operationId" column="operation_id"/>
|
||||
<result property="planId" column="plan_id"/>
|
||||
<result property="detailId" column="detail_id"/>
|
||||
<result property="orderId" column="order_id"/>
|
||||
<result property="orderDetailId" column="order_detail_id"/>
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="processId" column="process_id"/>
|
||||
<result property="lineId" column="line_id"/>
|
||||
<result property="sequenceNo" column="sequence_no"/>
|
||||
<result property="planQty" column="plan_qty"/>
|
||||
<result property="startTime" column="start_time"/>
|
||||
<result property="endTime" column="end_time"/>
|
||||
<result property="setupMinutes" column="setup_minutes"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="lockedFlag" column="locked_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectByIdForUpdate"
|
||||
parameterType="long"
|
||||
resultMap="ApsScheduleOperationMap">
|
||||
SELECT
|
||||
operation_id,
|
||||
plan_id,
|
||||
detail_id,
|
||||
order_id,
|
||||
order_detail_id,
|
||||
product_id,
|
||||
process_id,
|
||||
line_id,
|
||||
sequence_no,
|
||||
plan_qty,
|
||||
start_time,
|
||||
end_time,
|
||||
setup_minutes,
|
||||
status,
|
||||
locked_flag,
|
||||
remark,
|
||||
create_by,
|
||||
update_by
|
||||
FROM wms_schedule_operation
|
||||
WHERE operation_id = #{operationId}
|
||||
FOR UPDATE
|
||||
</select>
|
||||
|
||||
<update id="updateSlot"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleOperationEntity">
|
||||
UPDATE wms_schedule_operation
|
||||
SET line_id = #{lineId},
|
||||
start_time = #{startTime},
|
||||
end_time = #{endTime},
|
||||
update_by = #{updateBy},
|
||||
update_time = CURRENT_TIMESTAMP
|
||||
WHERE operation_id = #{operationId}
|
||||
</update>
|
||||
|
||||
<insert id="insertChangeLog"
|
||||
parameterType="com.klp.aps.domain.entity.ApsScheduleChangeLogEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="logId"
|
||||
keyColumn="log_id">
|
||||
INSERT INTO wms_schedule_change_log
|
||||
(
|
||||
operation_id,
|
||||
change_type,
|
||||
before_value,
|
||||
after_value,
|
||||
change_reason,
|
||||
change_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{operationId},
|
||||
#{changeType},
|
||||
#{beforeValue},
|
||||
#{afterValue},
|
||||
#{changeReason},
|
||||
#{changeBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
|
||||
197
klp-da/src/main/resources/mapper/da/aps/ApsPlanMapper.xml
Normal file
197
klp-da/src/main/resources/mapper/da/aps/ApsPlanMapper.xml
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsPlanMapper">
|
||||
|
||||
<select id="selectOrderDetailsByOrderId"
|
||||
parameterType="long"
|
||||
resultType="com.klp.aps.domain.row.ApsOrderDetailRow">
|
||||
SELECT
|
||||
detail_id AS detailId,
|
||||
product_id AS productId,
|
||||
quantity AS quantity
|
||||
FROM wms_order_detail
|
||||
WHERE order_id = #{orderId}
|
||||
AND (del_flag = 0 OR del_flag IS NULL)
|
||||
ORDER BY detail_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectCrmOrderById" resultType="com.klp.aps.domain.row.ApsCrmOrderRow">
|
||||
SELECT
|
||||
order_id AS orderId,
|
||||
order_code AS orderCode,
|
||||
customer_id AS customerId,
|
||||
salesman AS salesman,
|
||||
order_amount AS orderAmount,
|
||||
remark AS remark
|
||||
FROM crm_order
|
||||
WHERE order_id = #{crmOrderId}
|
||||
AND del_flag = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectCrmOrderItemsByOrderId" resultType="com.klp.aps.domain.row.ApsCrmOrderItemRow">
|
||||
SELECT
|
||||
item_id AS itemId,
|
||||
order_id AS orderId,
|
||||
product_type AS productType,
|
||||
product_num AS productNum,
|
||||
contract_price AS contractPrice,
|
||||
remark AS remark
|
||||
FROM crm_order_item
|
||||
WHERE order_id = #{crmOrderId}
|
||||
AND del_flag = 0
|
||||
ORDER BY item_id ASC
|
||||
</select>
|
||||
|
||||
<select id="selectWmsOrderByCode" resultType="com.klp.aps.domain.row.ApsWmsOrderRow">
|
||||
SELECT order_id AS orderId, order_code AS orderCode
|
||||
FROM wms_order
|
||||
WHERE order_code = #{orderCode}
|
||||
AND del_flag = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertWmsOrder" parameterType="com.klp.aps.domain.dto.ApsWmsOrderCreateReq">
|
||||
INSERT INTO wms_order
|
||||
(
|
||||
order_code,
|
||||
customer_id,
|
||||
customer_name,
|
||||
sales_manager,
|
||||
order_status,
|
||||
remark,
|
||||
tax_amount,
|
||||
no_tax_amount,
|
||||
del_flag,
|
||||
create_by,
|
||||
update_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{orderCode},
|
||||
#{customerId},
|
||||
#{customerName},
|
||||
#{salesManager},
|
||||
#{orderStatus},
|
||||
#{remark},
|
||||
#{taxAmount},
|
||||
#{noTaxAmount},
|
||||
0,
|
||||
#{createBy},
|
||||
#{updateBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertWmsOrderDetail" parameterType="com.klp.aps.domain.dto.ApsWmsOrderDetailCreateReq">
|
||||
INSERT INTO wms_order_detail
|
||||
(
|
||||
order_id,
|
||||
product_id,
|
||||
quantity,
|
||||
unit,
|
||||
remark,
|
||||
tax_price,
|
||||
no_tax_price,
|
||||
group_id,
|
||||
del_flag,
|
||||
create_by,
|
||||
update_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{orderId},
|
||||
#{productId},
|
||||
#{quantity},
|
||||
#{unit},
|
||||
#{remark},
|
||||
#{taxPrice},
|
||||
#{noTaxPrice},
|
||||
#{groupId},
|
||||
IFNULL(#{delFlag}, 0),
|
||||
#{createBy},
|
||||
#{updateBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<select id="selectAnyProductionLineId" resultType="long">
|
||||
SELECT line_id
|
||||
FROM wms_production_line
|
||||
WHERE del_flag = 0
|
||||
ORDER BY line_id ASC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertSchedulePlan"
|
||||
parameterType="com.klp.aps.domain.entity.ApsSchedulePlanEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="planId"
|
||||
keyColumn="plan_id">
|
||||
INSERT INTO wms_schedule_plan
|
||||
(
|
||||
plan_code,
|
||||
version,
|
||||
order_id,
|
||||
status,
|
||||
remark,
|
||||
del_flag,
|
||||
create_by,
|
||||
update_by,
|
||||
priority,
|
||||
start_date,
|
||||
end_date
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{planCode},
|
||||
#{version},
|
||||
#{orderId},
|
||||
#{status},
|
||||
#{remark},
|
||||
#{delFlag},
|
||||
#{createBy},
|
||||
#{updateBy},
|
||||
#{priority},
|
||||
#{startDate},
|
||||
#{endDate}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertSchedulePlanDetail"
|
||||
parameterType="com.klp.aps.domain.entity.ApsSchedulePlanDetailEntity"
|
||||
useGeneratedKeys="true"
|
||||
keyProperty="detailId"
|
||||
keyColumn="detail_id">
|
||||
INSERT INTO wms_schedule_plan_detail
|
||||
(
|
||||
plan_id,
|
||||
line_id,
|
||||
task_id,
|
||||
product_id,
|
||||
quantity,
|
||||
start_date,
|
||||
end_date,
|
||||
remark,
|
||||
del_flag,
|
||||
create_by,
|
||||
update_by
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{planId},
|
||||
#{lineId},
|
||||
#{taskId},
|
||||
#{productId},
|
||||
#{quantity},
|
||||
#{startDate},
|
||||
#{endDate},
|
||||
#{remark},
|
||||
#{delFlag},
|
||||
#{createBy},
|
||||
#{updateBy}
|
||||
)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.aps.mapper.ApsScheduleSheetMapper">
|
||||
|
||||
<select id="selectSheetRows"
|
||||
parameterType="com.klp.aps.domain.dto.ApsScheduleSheetQueryReq"
|
||||
resultType="com.klp.aps.domain.vo.ApsScheduleSheetRowVo">
|
||||
SELECT
|
||||
o.operation_id AS operationId,
|
||||
o.line_id AS lineId,
|
||||
l.line_name AS lineName,
|
||||
o.plan_id AS planId,
|
||||
p.plan_code AS planCode,
|
||||
o.order_id AS orderId,
|
||||
ord.order_code AS orderCode,
|
||||
ord.sales_manager AS salesman,
|
||||
ord.customer_name AS customerName,
|
||||
o.product_id AS productId,
|
||||
pr.product_name AS productName,
|
||||
pr.material AS material,
|
||||
pr.specification AS specification,
|
||||
o.process_id AS processId,
|
||||
ps.process_name AS processName,
|
||||
o.plan_qty AS planQty,
|
||||
DATE_FORMAT(o.start_time, '%Y-%m-%d %H:%i:%s') AS startTime,
|
||||
DATE_FORMAT(o.end_time, '%Y-%m-%d %H:%i:%s') AS endTime,
|
||||
|
||||
-- 原料钢卷信息:优先来自 wms_schedule_operation_coil + wms_material_coil
|
||||
COALESCE(
|
||||
CAST(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawMaterialId')) AS UNSIGNED),
|
||||
MAX(soc.coil_id)
|
||||
) AS rawMaterialId,
|
||||
COALESCE(
|
||||
NULLIF(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawCoilNos')), ''),
|
||||
GROUP_CONCAT(DISTINCT COALESCE(mc.current_coil_no, mc.enter_coil_no) ORDER BY COALESCE(mc.current_coil_no, mc.enter_coil_no) SEPARATOR ',')
|
||||
) AS rawCoilNos,
|
||||
COALESCE(
|
||||
NULLIF(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawLocation')), ''),
|
||||
GROUP_CONCAT(DISTINCT aw.actual_warehouse_name ORDER BY aw.actual_warehouse_name SEPARATOR ',')
|
||||
) AS rawLocation,
|
||||
COALESCE(
|
||||
CAST(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawNetWeight')) AS DECIMAL(18,4)),
|
||||
COALESCE(SUM(mc.net_weight), 0)
|
||||
) AS rawNetWeight,
|
||||
COALESCE(
|
||||
NULLIF(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawPackaging')), ''),
|
||||
MAX(mc.packaging_requirement)
|
||||
) AS rawPackaging,
|
||||
COALESCE(
|
||||
NULLIF(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawEdgeReq')), ''),
|
||||
MAX(mc.trimming_requirement)
|
||||
) AS rawEdgeReq,
|
||||
COALESCE(
|
||||
NULLIF(JSON_UNQUOTE(JSON_EXTRACT(MAX(CASE WHEN JSON_VALID(o.remark) THEN o.remark ELSE NULL END), '$.rawCoatingType')), ''),
|
||||
MAX(mc.coating_type)
|
||||
) AS rawCoatingType
|
||||
|
||||
FROM wms_schedule_operation o
|
||||
LEFT JOIN wms_schedule_plan p ON p.plan_id = o.plan_id
|
||||
LEFT JOIN wms_order ord ON ord.order_id = o.order_id
|
||||
LEFT JOIN wms_product pr ON pr.product_id = o.product_id
|
||||
LEFT JOIN wms_processe ps ON ps.process_id = o.process_id
|
||||
LEFT JOIN wms_production_line l ON l.line_id = o.line_id
|
||||
LEFT JOIN wms_schedule_operation_coil soc ON soc.operation_id = o.operation_id AND soc.del_flag = 0
|
||||
LEFT JOIN wms_material_coil mc ON mc.coil_id = soc.coil_id AND mc.del_flag = 0
|
||||
LEFT JOIN wms_actual_warehouse aw ON aw.actual_warehouse_id = mc.actual_warehouse_id AND aw.del_flag = 0
|
||||
WHERE o.end_time <![CDATA[>=]]> #{queryStart}
|
||||
AND o.start_time <![CDATA[<=]]> #{queryEnd}
|
||||
<if test="lineId != null">
|
||||
AND o.line_id = #{lineId}
|
||||
</if>
|
||||
<if test="planId != null and planId != ''">
|
||||
AND (
|
||||
p.plan_code = #{planId}
|
||||
OR (#{planId} REGEXP '^[0-9]+$' AND o.plan_id = CAST(#{planId} AS UNSIGNED))
|
||||
)
|
||||
</if>
|
||||
<if test="orderId != null and orderId != ''">
|
||||
AND (
|
||||
ord.order_code = #{orderId}
|
||||
OR (#{orderId} REGEXP '^[0-9]+$' AND o.order_id = CAST(#{orderId} AS UNSIGNED))
|
||||
)
|
||||
</if>
|
||||
GROUP BY
|
||||
o.operation_id,
|
||||
o.line_id,
|
||||
l.line_name,
|
||||
o.plan_id,
|
||||
p.plan_code,
|
||||
o.order_id,
|
||||
ord.order_code,
|
||||
ord.sales_manager,
|
||||
ord.customer_name,
|
||||
o.product_id,
|
||||
pr.product_name,
|
||||
o.process_id,
|
||||
ps.process_name,
|
||||
o.plan_qty,
|
||||
o.start_time,
|
||||
o.end_time
|
||||
ORDER BY o.line_id, o.start_time
|
||||
</select>
|
||||
|
||||
<update id="deleteOperationCoils">
|
||||
UPDATE wms_schedule_operation_coil
|
||||
SET del_flag = 1,
|
||||
update_by = #{updateBy},
|
||||
update_time = CURRENT_TIMESTAMP
|
||||
WHERE operation_id = #{operationId}
|
||||
AND del_flag = 0
|
||||
</update>
|
||||
|
||||
<insert id="insertOperationCoil">
|
||||
INSERT INTO wms_schedule_operation_coil
|
||||
(
|
||||
operation_id,
|
||||
coil_id,
|
||||
create_by,
|
||||
update_by,
|
||||
del_flag
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{operationId},
|
||||
#{coilId},
|
||||
#{createBy},
|
||||
#{createBy},
|
||||
0
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateOperationSupplement">
|
||||
UPDATE wms_schedule_operation
|
||||
SET remark = #{remarkJson},
|
||||
update_by = #{updateBy},
|
||||
update_time = CURRENT_TIMESTAMP
|
||||
WHERE operation_id = #{operationId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user