package cn.iocoder.yudao.module.finance.controller.admin.subject; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.finance.controller.admin.subject.vo.FinAccountSubjectPageReqVO; import cn.iocoder.yudao.module.finance.controller.admin.subject.vo.FinAccountSubjectRespVO; import cn.iocoder.yudao.module.finance.controller.admin.subject.vo.FinAccountSubjectSaveReqVO; import cn.iocoder.yudao.module.finance.dal.dataobject.subject.FinAccountSubjectDO; import cn.iocoder.yudao.module.finance.service.subject.FinAccountSubjectService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @Tag(name = "管理后台 - 财务会计科目") @RestController @RequestMapping("/finance/account-subject") @Validated public class FinAccountSubjectController { @Resource private FinAccountSubjectService accountSubjectService; @PostMapping("/create") @Operation(summary = "创建会计科目") @PreAuthorize("@ss.hasPermission('finance:account-subject:create')") public CommonResult createAccountSubject(@Valid @RequestBody FinAccountSubjectSaveReqVO createReqVO) { return success(accountSubjectService.createAccountSubject(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新会计科目") @PreAuthorize("@ss.hasPermission('finance:account-subject:update')") public CommonResult updateAccountSubject(@Valid @RequestBody FinAccountSubjectSaveReqVO updateReqVO) { accountSubjectService.updateAccountSubject(updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除会计科目", description = "存在下级科目或被凭证分录引用时不允许删除") @Parameter(name = "ids", description = "科目编号数组", required = true, example = "1,2,3") @PreAuthorize("@ss.hasPermission('finance:account-subject:delete')") public CommonResult deleteAccountSubject(@RequestParam("ids") List ids) { accountSubjectService.deleteAccountSubjectList(ids); return success(true); } @GetMapping("/get") @Operation(summary = "获得会计科目") @Parameter(name = "id", description = "科目编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('finance:account-subject:query')") public CommonResult getAccountSubject(@RequestParam("id") Long id) { FinAccountSubjectDO subject = accountSubjectService.getAccountSubject(id); return success(BeanUtils.toBean(subject, FinAccountSubjectRespVO.class)); } /** * 会计科目树形列表页的取数方式:一次拉全量命中的科目,再在前端内存里组树,分页对树没有意义, * 所以前端传 pageSize = -1(即框架的 PageParam.PAGE_SIZE_NONE,语义是「查询全部」)。 * * 但 PageParam 上挂着 @Min(1) @Max(200),请求里的 -1 会被参数校验直接拦成 * 400「每页条数最小值为 1」。PAGE_SIZE_NONE 在框架里一直是服务端导出方法内部 set 的 * (见下方 export-excel),从没走 HTTP 参数校验,所以这里必须去掉 @Valid, * 改为在方法内把 pageSize < 1 显式归一为 PAGE_SIZE_NONE,让「查询全部」这条路走得通。 */ @GetMapping("/page") @Operation(summary = "获得会计科目分页", description = "pageSize 传 -1 表示查询全部(树形列表页组树用)") @PreAuthorize("@ss.hasPermission('finance:account-subject:query')") public CommonResult> getAccountSubjectPage(FinAccountSubjectPageReqVO pageReqVO) { if (pageReqVO.getPageSize() == null || pageReqVO.getPageSize() < 1) { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); } PageResult pageResult = accountSubjectService.getAccountSubjectPage(pageReqVO); return success(BeanUtils.toBean(pageResult, FinAccountSubjectRespVO.class)); } @GetMapping("/list") @Operation(summary = "获得会计科目树列表", description = "返回全量科目,按父子层级组装 children") @PreAuthorize("@ss.hasPermission('finance:account-subject:query')") public CommonResult> getAccountSubjectList() { return success(buildTree(accountSubjectService.getAccountSubjectList())); } @GetMapping("/simple-list") @Operation(summary = "获得会计科目精简列表", description = "用于凭证分录的科目下拉/树选择") public CommonResult> getAccountSubjectSimpleList() { List list = accountSubjectService.getAccountSubjectList(); return success(convertList(list, subject -> new FinAccountSubjectRespVO() .setId(subject.getId()).setParentId(subject.getParentId()) .setSubjectCode(subject.getSubjectCode()).setSubjectName(subject.getSubjectName()) .setSubjectType(subject.getSubjectType()).setBalanceDirection(subject.getBalanceDirection()) .setStatus(subject.getStatus()))); } @GetMapping("/export-excel") @Operation(summary = "导出会计科目 Excel") @PreAuthorize("@ss.hasPermission('finance:account-subject:export')") @ApiAccessLog(operateType = EXPORT) public void exportAccountSubjectExcel(@Valid FinAccountSubjectPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = accountSubjectService.getAccountSubjectPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "会计科目.xls", "数据", FinAccountSubjectRespVO.class, BeanUtils.toBean(list, FinAccountSubjectRespVO.class)); } /** * 将扁平科目列表组装为树:上级科目不存在(已被删除)时,按根节点处理,避免节点丢失 */ private List buildTree(List list) { List voList = BeanUtils.toBean(list, FinAccountSubjectRespVO.class); Map idMap = convertMap(voList, FinAccountSubjectRespVO::getId); List roots = new ArrayList<>(); voList.forEach(vo -> { FinAccountSubjectRespVO parent = vo.getParentId() == null ? null : idMap.get(vo.getParentId()); if (parent == null) { roots.add(vo); } else { if (parent.getChildren() == null) { parent.setChildren(new ArrayList<>()); } parent.getChildren().add(vo); } }); return roots; } }