package jnpf.tmsController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jnpf.annotation.HandleLog;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.constant.MsgCode;
import jnpf.tmsEntity.task.TmsFromPlanResult;
import jnpf.tmsEntity.task.TmsTaskForm;
import jnpf.tmsEntity.task.TmsTaskQuery;
import jnpf.tmsService.TmsTaskService;
import jnpf.util.JsonUtil;
import lombok.RequiredArgsConstructor;
import jnpf.util.StringUtil;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 培训任务管理。网关 {@code /api/tms/task/**}(StripPrefix=2)→ {@code /task/**}。
*
*
关键能力:
*
* - CRUD / 发布 / 取消 / 恢复草稿
* - 年计划、岗计划审批结束事件:{@code from-annual}、{@code from-post} 生成草稿任务
* - 送审流程结束事件:{@code POST /publish}(Body/Query 传 id)自动发布
*
* 路径版与 Body 版成对出现:路径给前端;Body 版给流程「数据接口」(只发 POST)。
*/
@Tag(name = "TMS培训任务", description = "Task")
@RestController
@RequestMapping("/task")
@RequiredArgsConstructor
public class TmsTaskController {
private final TmsTaskService taskService;
@Operation(summary = "培训任务分页列表")
@GetMapping("/list")
public ActionResult> list(TmsTaskQuery query) {
List list = taskService.getList(query);
PageListVO vo = new PageListVO<>();
vo.setList(list);
vo.setPagination(JsonUtil.getJsonToBean(query, PaginationVO.class));
return ActionResult.success(vo);
}
@Operation(summary = "培训任务详情")
@GetMapping("/{id}")
public ActionResult info(@PathVariable("id") String id) {
return ActionResult.success(taskService.getInfo(id));
}
@HandleLog(moduleName = "培训任务", requestMethod = "新增")
@Operation(summary = "新增培训任务")
@PostMapping
public ActionResult create(@RequestBody TmsTaskForm form) {
// 必须用 (msg, data):单参 success(String) 会把 id 写进 msg、data 为空
return ActionResult.success(MsgCode.SU001.get(), taskService.create(form));
}
@HandleLog(moduleName = "培训任务", requestMethod = "修改")
@Operation(summary = "更新培训任务")
@PutMapping("/{id}")
public ActionResult update(@PathVariable("id") String id, @RequestBody TmsTaskForm form) {
taskService.update(id, form);
return ActionResult.success("更新成功");
}
@HandleLog(moduleName = "培训任务", requestMethod = "删除")
@Operation(summary = "删除培训任务(仅草稿)")
@DeleteMapping("/{id}")
public ActionResult delete(@PathVariable("id") String id) {
taskService.delete(id);
return ActionResult.success("删除成功");
}
/**
* 前端「发布」按钮:路径传任务主键。
* 兼 POST:与数据接口行为一致,避免仅 PUT 时流程回调 405。
*/
@HandleLog(moduleName = "培训任务", requestMethod = "发布")
@Operation(summary = "发布培训任务")
@RequestMapping(value = "/{id}/publish", method = {RequestMethod.PUT, RequestMethod.POST})
public ActionResult publish(@PathVariable("id") String id) {
taskService.publish(id);
return ActionResult.success("发布成功");
}
/**
* 流程结束事件数据接口专用:{@code POST /api/tms/task/publish},
* Body/Query 的 {@code id}/{@code f_id} 为任务主键(送审流程中与 workflow_task.id 相同)。
*/
@HandleLog(moduleName = "培训任务", requestMethod = "发布")
@Operation(summary = "发布培训任务(数据接口)")
@PostMapping("/publish")
public ActionResult publishBody(
@RequestBody(required = false) Map body,
@RequestParam(value = "id", required = false) String id,
@RequestParam(value = "f_id", required = false) String fId) {
Map merged = new LinkedHashMap<>();
if (body != null) {
merged.putAll(body);
}
putIfAbsent(merged, "id", id);
putIfAbsent(merged, "f_id", fId);
String taskId = pickPlanId(merged);
if (StringUtil.isEmpty(taskId)) {
return ActionResult.fail("缺少任务主键 id");
}
taskService.publish(taskId);
return ActionResult.success("发布成功");
}
@HandleLog(moduleName = "培训任务", requestMethod = "取消")
@Operation(summary = "取消/终止培训任务")
@PutMapping("/{id}/cancel")
public ActionResult cancel(@PathVariable("id") String id) {
taskService.cancel(id);
return ActionResult.success("取消成功");
}
@HandleLog(moduleName = "培训任务", requestMethod = "取消")
@Operation(summary = "批量取消培训任务")
@PutMapping("/cancelBatch")
public ActionResult cancelBatch(@RequestBody Map> body) {
taskService.cancelBatch(body == null ? null : body.get("ids"));
return ActionResult.success("取消成功");
}
@HandleLog(moduleName = "培训任务", requestMethod = "恢复")
@Operation(summary = "恢复为草稿")
@PutMapping("/{id}/restore")
public ActionResult restore(@PathVariable("id") String id) {
taskService.restore(id);
return ActionResult.success("已恢复为草稿");
}
@HandleLog(moduleName = "培训任务", requestMethod = "新增")
@Operation(summary = "年计划审批通过:按子表生成未发布培训任务")
@PostMapping("/from-annual/{planId}")
public ActionResult fromAnnual(@PathVariable("planId") String planId) {
return ActionResult.success(taskService.createFromAnnual(planId));
}
@HandleLog(moduleName = "培训任务", requestMethod = "新增")
@Operation(summary = "年计划审批通过")
@PostMapping("/from-annual")
public ActionResult fromAnnualBody(
@RequestBody(required = false) Map body,
@RequestParam(value = "id", required = false) String id,
@RequestParam(value = "planId", required = false) String planIdParam,
@RequestParam(value = "f_id", required = false) String fId) {
Map merged = new LinkedHashMap<>();
if (body != null) {
merged.putAll(body);
}
// 数据接口预览常把「接口参数」放 query,不进 JSON Body
putIfAbsent(merged, "id", id);
putIfAbsent(merged, "planId", planIdParam);
putIfAbsent(merged, "f_id", fId);
return ActionResult.success(taskService.createFromAnnual(pickPlanId(merged)));
}
@HandleLog(moduleName = "培训任务", requestMethod = "新增")
@Operation(summary = "岗位培训计划审批通过:按子表生成未发布培训任务")
@PostMapping("/from-post/{planId}")
public ActionResult fromPost(@PathVariable("planId") String planId) {
return ActionResult.success(taskService.createFromPost(planId));
}
@HandleLog(moduleName = "培训任务", requestMethod = "新增")
@Operation(summary = "岗位培训计划审批通过")
@PostMapping("/from-post")
public ActionResult fromPostBody(
@RequestBody(required = false) Map body,
@RequestParam(value = "id", required = false) String id,
@RequestParam(value = "planId", required = false) String planIdParam,
@RequestParam(value = "f_id", required = false) String fId) {
Map merged = new LinkedHashMap<>();
if (body != null) {
merged.putAll(body);
}
putIfAbsent(merged, "id", id);
putIfAbsent(merged, "planId", planIdParam);
putIfAbsent(merged, "f_id", fId);
return ActionResult.success(taskService.createFromPost(pickPlanId(merged)));
}
private static void putIfAbsent(Map map, String key, String value) {
if (StringUtil.isEmpty(value)) {
return;
}
Object existed = map.get(key);
if (existed == null || StringUtil.isEmpty(String.valueOf(existed))
|| "null".equalsIgnoreCase(String.valueOf(existed))
|| "value".equalsIgnoreCase(String.valueOf(existed).trim())) {
map.put(key, value.trim());
}
}
/**
* 从 Body/Query 合并 Map 中解析业务主键。
* 兼容流程数据接口多种占位名:id / planId / f_id / formId;忽略字面量 null、value。
*/
private static String pickPlanId(Map body) {
if (body == null || body.isEmpty()) {
return null;
}
for (String key : new String[]{"id", "planId", "f_id", "F_Id", "formId"}) {
Object v = body.get(key);
if (v == null) {
continue;
}
String text = String.valueOf(v).trim();
if (StringUtil.isEmpty(text) || "null".equalsIgnoreCase(text) || "value".equalsIgnoreCase(text)) {
continue;
}
return text;
}
return null;
}
}