This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package com.yunhai.svchall.controller.api;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.ApplySubmitRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.ApplyVo;
|
||||
import com.yunhai.svchall.service.impl.ServiceApplyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户面办件(/api/apply/**,CAS 登录):发起/重试/我的办件/详情。
|
||||
* 审批动作(撤回/催办/轨迹)由前端直调流程中心 /api/flow/*(同主域 CAS cookie),
|
||||
* 本控制器只管办事大厅侧的申请记录。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/apply")
|
||||
@RequiredArgsConstructor
|
||||
public class ApplyUserController {
|
||||
|
||||
private final ServiceApplyService applyService;
|
||||
|
||||
/** 发起(表单数据强校验 → 快照落库 → 代发起;流程中心未接入时落待提交态) */
|
||||
@PostMapping
|
||||
public ApplyVo submit(BoaUser authUserWithDept, @Valid @RequestBody ApplySubmitRequest request) {
|
||||
return applyService.submit(authUserWithDept, request);
|
||||
}
|
||||
|
||||
/** 重试(仅待提交态;复用同一 bizId,流程中心 uk 幂等) */
|
||||
@PostMapping("/{id}/retry")
|
||||
public ApplyVo retry(BoaUser authUserWithDept, @PathVariable("id") Integer id) {
|
||||
return applyService.retry(authUserWithDept, id);
|
||||
}
|
||||
|
||||
/** 一键重提(仅驳回/撤回态;复用同一 bizId,flow-center R4 重启推进,轨迹跨轮连续) */
|
||||
@PostMapping("/{id}/resubmit")
|
||||
public ApplyVo resubmit(BoaUser authUserWithDept, @PathVariable("id") Integer id) {
|
||||
return applyService.resubmit(authUserWithDept, id);
|
||||
}
|
||||
|
||||
/** 我的办件 */
|
||||
@GetMapping("/my")
|
||||
public Map<String, Object> my(BoaUser authUserWithDept,
|
||||
@RequestParam(value = "flowStatus", required = false) Integer flowStatus,
|
||||
@RequestParam(value = "page", required = false) Integer page,
|
||||
@RequestParam(value = "pageSize", required = false) Integer pageSize) {
|
||||
return applyService.myApplies(authUserWithDept, flowStatus, page, pageSize);
|
||||
}
|
||||
|
||||
/** 详情(提交人本人或站点管理面) */
|
||||
@GetMapping("/{id}")
|
||||
public ApplyVo detail(BoaUser authUserWithDept,
|
||||
@PathVariable("id") Integer id,
|
||||
@RequestParam(value = "siteCode", required = false) String siteCode) {
|
||||
return applyService.detail(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起页数据(CAS,本校用户):事项发布态要点 + 绑定表单的已发布 schema(前端渲染动态表单)。
|
||||
* 未发布/不存在报业务错;未绑流程报"未开通在线办理"。
|
||||
*/
|
||||
@GetMapping("/item")
|
||||
public java.util.Map<String, Object> applyItem(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("itemCode") String itemCode) {
|
||||
return applyService.applyItem(authUserWithDept, siteCode, itemCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.yunhai.svchall.controller.api;
|
||||
|
||||
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
|
||||
import com.yunhai.platform.utils.model.BoaModule;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 平台代理域接口(Notice/CMS BaseApiController 同款契约):GetUserInfo / GetUserMod。
|
||||
* GetUserInfo 直接返回 CAS 会话注入的 BoaUser;GetUserMod 经 Tier1 SDK 取当前用户在
|
||||
* 本应用(appKey 按 yh.open 身份)下已授权模块并组树,是前端左侧菜单与页头用户信息的数据源。
|
||||
* 返回裸对象,由统一响应包装为 {code, msg, data}。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/base")
|
||||
public class BaseApiController {
|
||||
|
||||
/** 当前登录用户信息(页头用户名/头像) */
|
||||
@GetMapping("GetUserInfo")
|
||||
public BoaUser getUserInfo(BoaUser authUserWithDept) {
|
||||
return authUserWithDept;
|
||||
}
|
||||
|
||||
/** 当前用户已授权模块列表(左侧菜单树) */
|
||||
@GetMapping("GetUserMod")
|
||||
public List<Map<String, Object>> getUserMod(BoaUser authUserWithDept) {
|
||||
Integer schId = authUserWithDept.getCurrentRole() != null
|
||||
? authUserWithDept.getCurrentRole().getSchId() : null;
|
||||
List<BoaModule> modules = YschBaseOpenApi.getUserModule(authUserWithDept.getId(), schId);
|
||||
if (modules == null || modules.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return buildModuleTree(modules);
|
||||
}
|
||||
|
||||
/** 扁平模块列表组树(Notice UserCenterService.buildModuleTree 同构:modId/page/children) */
|
||||
private static List<Map<String, Object>> buildModuleTree(List<BoaModule> modules) {
|
||||
Map<Integer, BoaModule> moduleMap = new LinkedHashMap<>();
|
||||
for (BoaModule m : modules) {
|
||||
moduleMap.put(m.getId(), m);
|
||||
}
|
||||
Map<Integer, Map<String, Object>> nodeMap = new LinkedHashMap<>();
|
||||
for (BoaModule m : modules) {
|
||||
Map<String, Object> node = new LinkedHashMap<>();
|
||||
node.put("id", m.getId());
|
||||
node.put("modId", m.getId());
|
||||
node.put("name", m.getName());
|
||||
node.put("parentId", m.getParentId() != null ? m.getParentId() : 0);
|
||||
node.put("page", m.getPath() != null ? m.getPath() : "");
|
||||
node.put("level", m.getLevel() != null ? m.getLevel() : 0);
|
||||
node.put("icon", m.getIcon() != null ? m.getIcon() : "");
|
||||
node.put("orderNumber", m.getSortNo() != null ? m.getSortNo() : 0);
|
||||
node.put("usable", true);
|
||||
node.put("children", new ArrayList<>());
|
||||
nodeMap.put(m.getId(), node);
|
||||
}
|
||||
List<Map<String, Object>> roots = new ArrayList<>();
|
||||
for (BoaModule m : modules) {
|
||||
Map<String, Object> node = nodeMap.get(m.getId());
|
||||
int parentId = m.getParentId() != null ? m.getParentId() : 0;
|
||||
if (parentId == 0 || !moduleMap.containsKey(parentId)) {
|
||||
roots.add(node);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> children =
|
||||
(List<Map<String, Object>>) nodeMap.get(parentId).get("children");
|
||||
children.add(node);
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.yunhai.svchall.controller.api;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.entity.ServiceAttachment;
|
||||
import com.yunhai.svchall.service.impl.AttachmentService;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件上传(/api/file/upload,Notice 上传通道契约):完整 URL 直接返回(直连访问),
|
||||
* DB 存相对段;业务绑定(指南附件/办件材料)由保存与提交动作完成。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/file")
|
||||
@RequiredArgsConstructor
|
||||
public class FileController {
|
||||
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
@PostMapping("/upload")
|
||||
public UploadVo upload(BoaUser authUserWithDept,
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "type", defaultValue = "file") String type,
|
||||
@RequestParam(value = "siteCode", required = false) String siteCode) {
|
||||
ServiceAttachment attachment = attachmentService.upload(authUserWithDept, siteCode, file, type);
|
||||
UploadVo vo = new UploadVo();
|
||||
vo.setId(attachment.getId());
|
||||
vo.setFileName(attachment.getFileName());
|
||||
vo.setFileUrl(com.yunhai.svchall.utils.FileUtil.buildUrl(attachment.getFileUrl()));
|
||||
vo.setFileSize(attachment.getFileSize());
|
||||
vo.setMimeType(attachment.getMimeType());
|
||||
return vo;
|
||||
}
|
||||
|
||||
/** 上传返回体(fileUrl 为完整可达地址) */
|
||||
@Data
|
||||
public static class UploadVo {
|
||||
private Integer id;
|
||||
private String fileName;
|
||||
private String fileUrl;
|
||||
private Long fileSize;
|
||||
private String mimeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.yunhai.svchall.controller.api;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.service.SiteDirectory;
|
||||
import com.yunhai.svchall.service.SiteDirectory.SiteInfo;
|
||||
import com.yunhai.svchall.service.SiteGuard;
|
||||
import com.yunhai.svchall.service.impl.ServiceFormService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 站点选项(/api/svc/site/options):管理端站点选择器数据源,代理 CMS 站点目录
|
||||
* (/oapi/site/list,本地缓存 5 分钟)。当前用户角色学校口径;超管同样按其角色学校下发
|
||||
* (跨校站点管理走超管在该校的角色,与 CMS requireManageable 的使用方式一致)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/svc/site")
|
||||
@RequiredArgsConstructor
|
||||
public class SiteOptionsController {
|
||||
|
||||
private final SiteDirectory siteDirectory;
|
||||
private final SiteGuard siteGuard;
|
||||
private final ServiceFormService formService;
|
||||
|
||||
@GetMapping("/options")
|
||||
public List<com.yunhai.svchall.model.svc.SvcModels.SiteOptionVo> options(BoaUser authUserWithDept) {
|
||||
if (authUserWithDept == null || authUserWithDept.getCurrentRole() == null
|
||||
|| authUserWithDept.getCurrentRole().getSchId() == null) {
|
||||
throw new com.yunhai.platform.apistd.BizException(
|
||||
com.yunhai.platform.utils.exception.ErrorCode.PARAM_ERROR, "当前用户无学校归属");
|
||||
}
|
||||
Long schId = authUserWithDept.getCurrentRole().getSchId().longValue();
|
||||
return siteDirectory.listSites(schId);
|
||||
}
|
||||
|
||||
/** 站点解析校验(编辑页初始化时前端可调,确保站点可达且有权) */
|
||||
@GetMapping("/check")
|
||||
public SiteInfo check(BoaUser authUserWithDept, @RequestParam("siteCode") String siteCode) {
|
||||
return siteGuard.requireSiteManager(authUserWithDept, siteCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.svchall.controller.api.svc;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.ApplyPageQuery;
|
||||
import com.yunhai.svchall.service.impl.ServiceApplyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** 办件记录管理面(/api/svc/apply/**):本校在途与历史办件分页。 */
|
||||
@RestController
|
||||
@RequestMapping("/api/svc/apply")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcApplyAdminController {
|
||||
|
||||
private final ServiceApplyService applyService;
|
||||
|
||||
@GetMapping("/page")
|
||||
public Map<String, Object> page(BoaUser authUserWithDept, ApplyPageQuery query) {
|
||||
return applyService.adminPage(authUserWithDept, query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.yunhai.svchall.controller.api.svc;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.DeleteRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcDeptVo;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcDictSaveRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcDictVo;
|
||||
import com.yunhai.svchall.service.impl.ServiceDictService;
|
||||
import com.yunhai.svchall.service.impl.ServiceItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 事项字典 + 服务部门选项(/api/svc/dict/**、/api/svc/dept/tree,迁移自 CMS SvcDictController)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/svc")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcDictController {
|
||||
|
||||
private final ServiceDictService dictService;
|
||||
private final ServiceItemService itemService;
|
||||
|
||||
@GetMapping("/dict/list")
|
||||
public List<SvcDictVo> list(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam(value = "dictType", required = false) String dictType) {
|
||||
return dictService.list(authUserWithDept, siteCode, dictType);
|
||||
}
|
||||
|
||||
@PostMapping("/dict/save")
|
||||
public Integer save(BoaUser authUserWithDept, @Valid @RequestBody SvcDictSaveRequest request) {
|
||||
return dictService.save(authUserWithDept, request);
|
||||
}
|
||||
|
||||
@PostMapping("/dict/delete")
|
||||
public void delete(BoaUser authUserWithDept, @Valid @RequestBody DeleteRequest request) {
|
||||
dictService.delete(authUserWithDept, request);
|
||||
}
|
||||
|
||||
/** 服务部门选项(UserBase 组树代理;平台不可达降级空列表) */
|
||||
@GetMapping("/dept/tree")
|
||||
public List<SvcDeptVo> deptTree(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
return itemService.deptTree(authUserWithDept, siteCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.yunhai.svchall.controller.api.svc;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.FlowSummaryVo;
|
||||
import com.yunhai.svchall.service.FlowClient;
|
||||
import com.yunhai.svchall.service.SiteDirectory;
|
||||
import com.yunhai.svchall.service.SiteGuard;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程选择器(/api/svc/flow/**):事项编辑页"办理流程"数据源,代理流程中心
|
||||
* /oapi/flow/list。流程中心未接入(svchall.flow.enabled=false)时抛业务异常,
|
||||
* 前端据此降级提示(事项只能配为线下/纯指南)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/svc/flow")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcFlowController {
|
||||
|
||||
private final FlowClient flowClient;
|
||||
private final SiteGuard siteGuard;
|
||||
private final SiteDirectory siteDirectory;
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<FlowSummaryVo> list(BoaUser authUserWithDept, @RequestParam("siteCode") String siteCode) {
|
||||
siteGuard.requireSiteManager(authUserWithDept, siteCode);
|
||||
SiteDirectory.SiteInfo site = siteDirectory.requireSite(siteCode);
|
||||
return flowClient.listFlows(site.getSchId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.yunhai.svchall.controller.api.svc;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcFormSaveRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcFormVo;
|
||||
import com.yunhai.svchall.service.impl.ServiceFormService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义表单管理(/api/svc/form/**,V2.0 Part B.3):列表/版本轨迹/保存(发布版自动升版)/
|
||||
* 发布(静态校验)/删除(被绑定即拦)。表单为 sch 级,端点仍以 siteCode 定位做权限收口。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/svc/form")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcFormController {
|
||||
|
||||
private final ServiceFormService formService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<SvcFormVo> list(BoaUser authUserWithDept, @RequestParam("siteCode") String siteCode) {
|
||||
return formService.list(authUserWithDept, siteCode);
|
||||
}
|
||||
|
||||
@GetMapping("/versions")
|
||||
public List<SvcFormVo> versions(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("code") String code) {
|
||||
return formService.versions(authUserWithDept, siteCode, code);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
public SvcFormVo get(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("id") Integer id) {
|
||||
return formService.get(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public Integer save(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@Valid @RequestBody SvcFormSaveRequest request) {
|
||||
return formService.save(authUserWithDept, siteCode, request);
|
||||
}
|
||||
|
||||
@PostMapping("/publish/{id}")
|
||||
public void publish(BoaUser authUserWithDept,
|
||||
@PathVariable("id") Integer id,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
formService.publish(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("code") String code) {
|
||||
formService.delete(authUserWithDept, siteCode, code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.yunhai.svchall.controller.api.svc;
|
||||
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.DeleteRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.IdSortItem;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemAttachmentVo;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemEditVo;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemPageItem;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemPageQuery;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemSaveRequest;
|
||||
import com.yunhai.svchall.model.svc.SvcModels.SvcItemSimpleVo;
|
||||
import com.yunhai.svchall.service.impl.ServiceItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 事项管理(/api/svc/item/**,迁移自 CMS SvcItemController;siteId → siteCode)。
|
||||
* 权限:站点管理面(SiteGuard:超管或本校角色,站点经 CMS 目录解析 fail-closed)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/svc/item")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcItemController {
|
||||
|
||||
private final ServiceItemService itemService;
|
||||
|
||||
@GetMapping("/page")
|
||||
public Map<String, Object> page(BoaUser authUserWithDept, SvcItemPageQuery query) {
|
||||
return itemService.adminPage(authUserWithDept, query);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
public SvcItemEditVo get(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("id") Integer id) {
|
||||
return itemService.adminGet(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
/** 保存(新建草稿/编辑;富文本 jsoup 清洗;flowGuid 绑定校验:onlineFlag=1 ⇒ 必绑流程) */
|
||||
@PostMapping("/save")
|
||||
public Integer save(BoaUser authUserWithDept, @Valid @RequestBody SvcItemSaveRequest request) {
|
||||
return itemService.adminSave(authUserWithDept, request);
|
||||
}
|
||||
|
||||
@PostMapping("/publish/{id}")
|
||||
public void publish(BoaUser authUserWithDept,
|
||||
@PathVariable("id") Integer id,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
itemService.adminPublish(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
@PostMapping("/offline/{id}")
|
||||
public void offline(BoaUser authUserWithDept,
|
||||
@PathVariable("id") Integer id,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
itemService.adminOffline(authUserWithDept, siteCode, id);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(BoaUser authUserWithDept, @Valid @RequestBody DeleteRequest request) {
|
||||
itemService.adminDelete(authUserWithDept, request);
|
||||
}
|
||||
|
||||
@PostMapping("/sort")
|
||||
public void sort(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestBody List<IdSortItem> items) {
|
||||
itemService.adminSort(authUserWithDept, siteCode, items);
|
||||
}
|
||||
|
||||
/** 同步部门名快照(UserBase 组树改名后刷新 dept_name) */
|
||||
@PostMapping("/syncDeptName")
|
||||
public Map<String, Object> syncDeptName(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
return itemService.syncDeptName(authUserWithDept, siteCode);
|
||||
}
|
||||
|
||||
@GetMapping("/selList")
|
||||
public List<SvcItemSimpleVo> selList(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode) {
|
||||
return itemService.adminSelList(authUserWithDept, siteCode);
|
||||
}
|
||||
|
||||
/** 指南附件回显(编辑页列表) */
|
||||
@GetMapping("/attList")
|
||||
public List<SvcItemAttachmentVo> attList(BoaUser authUserWithDept,
|
||||
@RequestParam("siteCode") String siteCode,
|
||||
@RequestParam("id") Integer id) {
|
||||
return itemService.itemAttachments(authUserWithDept, siteCode, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.yunhai.svchall.controller.callback;
|
||||
|
||||
import com.yunhai.svchall.service.impl.FlowCallbackService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
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 java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 流程中心回调接收端点(/callback/flow;不在 CAS pattern(/api/*)内、也不在 /oapi/*
|
||||
* (appKey 签名)内——独立走 FlowCallbackVerifyFilter 的 X-Flw-* 四头验签后才到达这里)。
|
||||
* <p>
|
||||
* <b>返回语义(契约冻结 D2,免对账前提)</b>:状态推进成功 / 重复投递(去重命中)/
|
||||
* 协议毒消息 / 乱序丢弃 / 办件不属本应用 → <b>200</b>(毒消息回 200 防无限重放);
|
||||
* 瞬时失败(DB 异常/锁冲突,{@link FlowCallbackService.TransientCallbackException})/
|
||||
* 意外 RuntimeException → <b>5xx</b>——flow-center 持续重试直至送达,消费方恢复自动追平
|
||||
* (替代旧"恒 200 + 每日对账"架构,验收报告 §五遗留批次)。
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/callback")
|
||||
@RequiredArgsConstructor
|
||||
public class FlowCallbackController {
|
||||
|
||||
private final FlowCallbackService callbackService;
|
||||
|
||||
@PostMapping("/flow")
|
||||
public ResponseEntity<String> flow(@RequestBody byte[] body) {
|
||||
try {
|
||||
callbackService.process(new String(body, StandardCharsets.UTF_8));
|
||||
return ResponseEntity.ok("{\"ok\":true}");
|
||||
} catch (FlowCallbackService.TransientCallbackException e) {
|
||||
log.error("[svc-hall] 回调瞬时失败(回 5xx 触发流程中心重试): {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"ok\":false}");
|
||||
} catch (Exception e) {
|
||||
// 意外异常同样按瞬时失败处理(宁可多重试一次,不可丢事件)
|
||||
log.error("[svc-hall] 回调意外异常(回 5xx 触发流程中心重试)", e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"ok\":false}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.yunhai.svchall.controller.oapi.svc;
|
||||
|
||||
import com.yunhai.platform.apistd.BizException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import com.yunhai.svchall.model.oapi.OapiModels;
|
||||
import com.yunhai.svchall.service.SiteDirectory;
|
||||
import com.yunhai.svchall.service.impl.ServiceItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 门户供数开放接口(/oapi/svc/**,appKey 签名访问,消费方=CMS;V2.0 Part C.2 契约冻结件)。
|
||||
* 错误纪律:未签名 401(RequireAppSignFilter);缺参/站点或事项不存在/未发布 →
|
||||
* HTTP 200 + 信封 code=2(BizException);detail 支持 itemId/itemCode 双键。
|
||||
* 站点解析 fail-closed:站点目录不可达按"站点不存在"报 code=2,不降级全局查询。
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/oapi/svc")
|
||||
@RequiredArgsConstructor
|
||||
public class SvcOapiController {
|
||||
|
||||
private final ServiceItemService itemService;
|
||||
private final SiteDirectory siteDirectory;
|
||||
|
||||
/** 服务中心列表(分页 + 三维筛选 + 关键词;URL 由 CMS 生成,接口不返回 url) */
|
||||
@GetMapping("/items")
|
||||
public OapiModels.ListData items(@RequestParam(value = "siteCode", required = false) String siteCode,
|
||||
@RequestParam(value = "objectKey", required = false) String objectKey,
|
||||
@RequestParam(value = "categoryKey", required = false) String categoryKey,
|
||||
@RequestParam(value = "deptGroupId", required = false) Integer deptGroupId,
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
@RequestParam(value = "page", required = false) Integer page,
|
||||
@RequestParam(value = "pageSize", required = false) Integer pageSize) {
|
||||
SiteDirectory.SiteInfo site = requireSite(siteCode);
|
||||
return itemService.oapiItems(site.getSchId(), site.getSiteCode(), emptyToNull(objectKey),
|
||||
emptyToNull(categoryKey), deptGroupId, emptyToNull(keyword), page, pageSize);
|
||||
}
|
||||
|
||||
/** 三组筛选项 + 计数(已发布口径) */
|
||||
@GetMapping("/filters")
|
||||
public OapiModels.Filters filters(@RequestParam(value = "siteCode", required = false) String siteCode) {
|
||||
SiteDirectory.SiteInfo site = requireSite(siteCode);
|
||||
return itemService.oapiFilters(site.getSchId(), site.getSiteCode());
|
||||
}
|
||||
|
||||
/** 指南页详情(itemId 或 itemCode 二选一;三段 HTML/封面/附件已绝对化;含关联事项与 applyUrl) */
|
||||
@GetMapping("/item/detail")
|
||||
public OapiModels.Detail detail(@RequestParam(value = "siteCode", required = false) String siteCode,
|
||||
@RequestParam(value = "itemId", required = false) Integer itemId,
|
||||
@RequestParam(value = "itemCode", required = false) String itemCode) {
|
||||
SiteDirectory.SiteInfo site = requireSite(siteCode);
|
||||
if (itemId == null && !StringUtils.hasText(itemCode)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "itemId/itemCode 不得同时为空");
|
||||
}
|
||||
OapiModels.Detail detail = itemService.oapiDetail(site.getSchId(), site.getSiteCode(),
|
||||
itemId, emptyToNull(itemCode));
|
||||
if (detail == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "事项不存在或未发布");
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
|
||||
/** 浏览量累加(CMS fire-and-forget;支持 itemId 直取;找不到事项静默忽略,保持信封 code=0) */
|
||||
@PostMapping("/item/view")
|
||||
public void view(@RequestParam(value = "siteCode", required = false) String siteCode,
|
||||
@RequestParam(value = "itemCode", required = false) String itemCode,
|
||||
@RequestParam(value = "itemId", required = false) Integer itemId) {
|
||||
if (itemId != null) {
|
||||
itemService.countViewByItemId(itemId);
|
||||
return;
|
||||
}
|
||||
SiteDirectory.SiteInfo site = requireSite(siteCode);
|
||||
if (!StringUtils.hasText(itemCode)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "itemCode/itemId 不得同时为空");
|
||||
}
|
||||
itemService.countView(site.getSchId(), site.getSiteCode(), itemCode.trim());
|
||||
}
|
||||
|
||||
/** 指南附件(按 itemId 直取;fileUrl 已绝对化) */
|
||||
@GetMapping("/item/attachments")
|
||||
public java.util.List<OapiModels.AttachmentRow> attachments(
|
||||
@RequestParam(value = "itemId", required = false) Integer itemId) {
|
||||
if (itemId == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "itemId 不得为空");
|
||||
}
|
||||
return itemService.attachmentsByItemId(itemId);
|
||||
}
|
||||
|
||||
/** 关联事项(按 itemId 直取:同类别已发布 Top N,排除自身) */
|
||||
@GetMapping("/item/related")
|
||||
public java.util.List<OapiModels.RelatedItemRow> related(
|
||||
@RequestParam(value = "itemId", required = false) Integer itemId,
|
||||
@RequestParam(value = "limit", required = false) Integer limit) {
|
||||
if (itemId == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "itemId 不得为空");
|
||||
}
|
||||
return itemService.relatedByItemId(itemId, limit);
|
||||
}
|
||||
|
||||
/** 跨服务要点快照(docs/17 §1.1 契约平移;原消费方流程中心已取消,保留为对外标准口) */
|
||||
@GetMapping("/item/snapshot")
|
||||
public OapiModels.Snapshot snapshot(@RequestParam(value = "siteCode", required = false) String siteCode,
|
||||
@RequestParam(value = "itemCode", required = false) String itemCode) {
|
||||
if (!StringUtils.hasText(siteCode) || !StringUtils.hasText(itemCode)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "siteCode/itemCode 不得为空");
|
||||
}
|
||||
OapiModels.Snapshot vo = itemService.oapiSnapshot(siteCode.trim(), itemCode.trim());
|
||||
if (vo == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "事项不存在或未发布");
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/** 站点解析 fail-closed:不可达或不存在一律 code=2(门户侧不应渲染未知站点) */
|
||||
private SiteDirectory.SiteInfo requireSite(String siteCode) {
|
||||
if (!StringUtils.hasText(siteCode)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "siteCode 不得为空");
|
||||
}
|
||||
SiteDirectory.SiteInfo site = siteDirectory.resolveSite(siteCode.trim());
|
||||
if (site == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "站点不存在或站点服务不可达:" + siteCode);
|
||||
}
|
||||
return site;
|
||||
}
|
||||
|
||||
private static String emptyToNull(String value) {
|
||||
return StringUtils.hasText(value) ? value.trim() : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user