ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/OaApprovalApplicationAssetController.java
@@ -163,6 +163,13 @@ IPage<OaApprovalApplicationAssetPageVO> page = oaApprovalApplicationAssetService.getReturnNotifyPageList(pageQuery); return R.ok(page); } @ApiOperation("获取资产归还详情") @GetMapping("/detail/return/{id}") public R<OaApprovalApplicationAssetDetailVO> getReturnDetail(@ApiParam(name = "id", value = "审批单ID", required = true) @PathVariable Integer id) { OaApprovalApplicationAssetDetailVO detail = oaApprovalApplicationAssetService.getReturnDetail(id); return R.ok(detail); } @ApiOperation("删除/领用/借用/归还申请") @DeleteMapping("/{id}") public R<?> delete(@ApiParam(name = "id",value = "审批记录ID",required = true) @PathVariable Integer id){ ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/OaApprovalApplicationDisposeController.java
@@ -1,20 +1,91 @@ package com.ruoyi.web.controller.api; import com.baomidou.mybatisplus.core.metadata.IPage; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.system.dto.dispose.OaApprovalApplicationDisposeDTO; import com.ruoyi.system.query.OaApprovalApplicationDisposePageQuery; import com.ruoyi.system.service.OaApprovalApplicationDisposeService; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.vo.dispose.OaApprovalApplicationDisposePageVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Lazy; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; 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; import javax.validation.Valid; /** * <p> * 资产领用单明细表 前端控制器 * 资产处置单明细表 前端控制器 * </p> * * @author WuGuanFengYue * @since 2025-09-15 */ @Validated @RestController @Api(tags = {"OA审批-资产处置相关接口"}) @RequiredArgsConstructor(onConstructor_ = {@Lazy}) @RequestMapping("/oa-approval-application-dispose") public class OaApprovalApplicationDisposeController { private final OaApprovalApplicationDisposeService oaApprovalApplicationDisposeService; private final ISysUserService sysUserService; @ApiOperation("提交资产处置申请") @PostMapping("/submit-dispose") @Log(title = "资产处置申请-提交", businessType = BusinessType.INSERT) public R<Void> submitDispose(@Valid @RequestBody OaApprovalApplicationDisposeDTO dto) { oaApprovalApplicationDisposeService.submitDispose(dto); return R.ok(); } @ApiOperation("获取资产处置申请分页列表") @PostMapping("/page-list") public R<IPage<OaApprovalApplicationDisposePageVO>> getDisposePageList(@RequestBody OaApprovalApplicationDisposePageQuery pageQuery) { // 数据权限:超级管理员/资产管理部查看所有数据,其他部门查看当前及下级部门的数据 Long userId = SecurityUtils.getUserId(); boolean isAdmin = SecurityUtils.isAdmin(userId); if (!isAdmin) { try { // 获取当前用户的部门名称 String deptName = sysUserService.selectUserById(userId).getDept().getDeptName(); // 非超级管理员且非资产管理部,设置部门权限 if (!"资产管理部".equals(deptName)) { pageQuery.setDeptId(Integer.valueOf(SecurityUtils.getLoginUser().getDeptId())); } } catch (Exception e) { // 如果获取部门信息失败,默认设置部门权限 try { pageQuery.setDeptId(Integer.valueOf(SecurityUtils.getLoginUser().getDeptId())); } catch (Exception ex) { // ignore parse, leave null if cannot parse } } } IPage<OaApprovalApplicationDisposePageVO> page = oaApprovalApplicationDisposeService.getDisposePageList(pageQuery); return R.ok(page); } @ApiOperation("删除处置申请") @DeleteMapping("/{id}") public R<?> deleteByApplicationId(@ApiParam(name = "id", value = "申请单ID", required = true) @PathVariable Integer id) { oaApprovalApplicationDisposeService.deleteByApplicationId(id); return R.ok(); } } ruoyi-system/src/main/java/com/ruoyi/system/dto/dispose/OaApprovalApplicationDisposeDTO.java
New file @@ -0,0 +1,69 @@ package com.ruoyi.system.dto.dispose; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; /** * 资产处置申请 DTO */ @Data @ApiModel("资产处置申请DTO") public class OaApprovalApplicationDisposeDTO implements Serializable { private static final long serialVersionUID = 2025092801L; @ApiModelProperty("事项标题") @NotNull(message = "事项标题不能为空") private String title; @ApiModelProperty("处置资产类型ID") @NotNull(message = "处置资产类型不能为空") private Integer assetTypeId; @ApiModelProperty("处置日期") @NotNull(message = "处置日期不能为空") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate disposeTime; @ApiModelProperty("处置方式 0-报废,1-报损,2-捐赠") @NotNull(message = "处置方式不能为空") private Integer disposeType; @ApiModelProperty("申请部门ID") @NotNull(message = "申请部门不能为空") private Integer deptId; @ApiModelProperty("申请部门名称") @NotNull(message = "申请部门名称不能为空") private String deptName; @ApiModelProperty("申请人用户ID") @NotNull(message = "申请人不能为空") private Integer applicantUserId; @ApiModelProperty("申请人名称") @NotNull(message = "申请人名称不能为空") private String applicantName; @ApiModelProperty("处置总金额(元)") @NotNull(message = "处置总金额不能为空") private BigDecimal disposeTotalAmount; @ApiModelProperty("处置备注") private String applicationReason; @ApiModelProperty("附件URL,多个使用英文逗号拼接") private String attachmentUrl; @ApiModelProperty("资产列表") @NotEmpty(message = "资产列表不能为空") private List<Integer> assetMainIds; } ruoyi-system/src/main/java/com/ruoyi/system/mapper/OaApprovalApplicationDisposeMapper.java
@@ -1,11 +1,16 @@ package com.ruoyi.system.mapper; import com.ruoyi.system.model.OaApprovalApplicationDispose; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.system.model.OaApprovalApplicationDispose; import com.ruoyi.system.query.OaApprovalApplicationDisposePageQuery; import com.ruoyi.system.vo.dispose.OaApprovalApplicationDisposePageVO; import org.apache.ibatis.annotations.Param; /** * <p> * 资产领用单明细表 Mapper 接口 * 资产处置单明细表 Mapper 接口 * </p> * * @author WuGuanFengYue @@ -13,4 +18,11 @@ */ public interface OaApprovalApplicationDisposeMapper extends BaseMapper<OaApprovalApplicationDispose> { /** * 分页查询资产处置申请列表 * @param page 分页参数 * @param pageQuery 查询条件 * @return 分页结果 */ IPage<OaApprovalApplicationDisposePageVO> getDisposePageList(Page<OaApprovalApplicationDisposePageVO> page, @Param("query") OaApprovalApplicationDisposePageQuery pageQuery); } ruoyi-system/src/main/java/com/ruoyi/system/query/OaApprovalApplicationDisposePageQuery.java
New file @@ -0,0 +1,24 @@ package com.ruoyi.system.query; import com.ruoyi.common.core.domain.BasePage; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; /** * 资产处置申请分页查询参数 */ @Data @EqualsAndHashCode(callSuper = true) @ApiModel(value = "资产处置申请分页查询参数") public class OaApprovalApplicationDisposePageQuery extends BasePage { private static final long serialVersionUID = 5275799518107306564L; @ApiModelProperty(value = "标题/单号") private String keyword; @ApiModelProperty(value = "部门ID") private Integer deptId; } ruoyi-system/src/main/java/com/ruoyi/system/service/OaApprovalApplicationAssetService.java
@@ -87,6 +87,13 @@ IPage<OaApprovalApplicationAssetPageVO> getReturnNotifyPageList(OaApprovalApplicationAssetPageQuery pageQuery); /** * 获取归还单详情 * @param id * @return */ OaApprovalApplicationAssetDetailVO getReturnDetail(Integer id); /** * 删除审批单相关的资产领用/借用/归还记录 * @param applicationId */ ruoyi-system/src/main/java/com/ruoyi/system/service/OaApprovalApplicationDisposeService.java
@@ -1,11 +1,15 @@ package com.ruoyi.system.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.system.dto.dispose.OaApprovalApplicationDisposeDTO; import com.ruoyi.system.model.OaApprovalApplicationDispose; import com.ruoyi.system.query.OaApprovalApplicationDisposePageQuery; import com.ruoyi.system.vo.dispose.OaApprovalApplicationDisposePageVO; /** * <p> * 资产领用单明细表 服务类 * 资产处置单明细表 服务类 * </p> * * @author WuGuanFengYue @@ -13,4 +17,22 @@ */ public interface OaApprovalApplicationDisposeService extends IService<OaApprovalApplicationDispose> { /** * 获取资产处置申请分页列表 * @param pageQuery 查询参数 * @return 分页结果 */ IPage<OaApprovalApplicationDisposePageVO> getDisposePageList(OaApprovalApplicationDisposePageQuery pageQuery); /** * 提交处置申请 * @param dto 处置申请数据 */ void submitDispose(OaApprovalApplicationDisposeDTO dto); /** * 删除审批单 * @param applicationId */ void deleteByApplicationId(Integer applicationId); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OaApprovalApplicationAssetServiceImpl.java
@@ -133,7 +133,7 @@ private OaApprovalApplicationAsset buildOaApprovalApplicationAsset(OaApprovalApplicationAssetReceiveDTO dto, Integer applicationId) { OaApprovalApplicationAsset asset = BeanUtil.copyProperties(dto, OaApprovalApplicationAsset.class); asset.setApprovalApplicationId(applicationId); asset.setType(AssetOperateTypeEnum.RECEIVE.getCode()); asset.setType(dto.getType()); return asset; } @@ -227,6 +227,7 @@ vo.setTitle(detail.getTitle()); vo.setAssetTypeId(detail.getAssetTypeId()); vo.setOperateTime(detail.getOperateTime()); vo.setExpectReturnDate(detail.getExpectReturnDate()); vo.setItems(assetMainVOS); return vo; } @@ -277,8 +278,12 @@ // 4. 保存归还明细 OaApprovalApplicationAsset detail = BeanUtil.copyProperties(dto, OaApprovalApplicationAsset.class); detail.setApprovalApplicationId(applications.getId()); detail.setBorrowApplicationId(dto.getApprovalApplicationId()); detail.setType(AssetOperateTypeEnum.RETURN.getCode()); OaApprovalApplicationAsset asset = lambdaQuery().eq(OaApprovalApplicationAsset::getApprovalApplicationId, dto.getApprovalApplicationId()).one(); if (Objects.nonNull(asset)) { detail.setAssetTypeId(asset.getAssetTypeId()); } this.save(detail); // 5. 保存关联的资产项 @@ -311,10 +316,36 @@ }); return pageByType; } @Override public OaApprovalApplicationAssetDetailVO getReturnDetail(Integer id) { OaApprovalApplications app = oaApprovalApplicationsService.getById(id); if (app == null) { throw new ServiceException("审批主记录不存在"); } OaApprovalApplicationAsset detail = this.lambdaQuery().eq(OaApprovalApplicationAsset::getApprovalApplicationId, app.getId()).one(); if (detail == null) { throw new ServiceException("记录不存在"); } oaApprovalApplicationsService.assembleApplicationDetail(app); List<Integer> assetMainIds = oaApprovalApplicationAssetItemService.lambdaQuery() .eq(OaApprovalApplicationAssetItem::getApprovalApplicationId, app.getId()) .list().stream().map(OaApprovalApplicationAssetItem::getAssetMainId) .distinct().collect(Collectors.toList()); List<AssetMainVO> assetMainVOS = assetMainIds.isEmpty() ? Collections.emptyList() : assetMainService.getListByIds(assetMainIds); OaApprovalApplicationAssetDetailVO vo = BeanUtil.copyProperties(app, OaApprovalApplicationAssetDetailVO.class); vo.setTitle(detail.getTitle()); vo.setAssetTypeId(detail.getAssetTypeId()); vo.setOperateTime(detail.getOperateTime()); vo.setItems(assetMainVOS); return vo; } @Transactional(rollbackFor = Exception.class) @Override public void deleteByApplicationId(Integer applicationId) { this.lambdaUpdate().eq(OaApprovalApplicationAsset::getApprovalApplicationId, applicationId).remove(); oaApprovalApplicationAssetItemService.lambdaUpdate().eq(OaApprovalApplicationAssetItem::getApprovalApplicationId, applicationId).remove(); oaApprovalApplicationsService.removeById(applicationId); } } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OaApprovalApplicationDisposeServiceImpl.java
@@ -1,20 +1,136 @@ package com.ruoyi.system.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.system.dto.dispose.OaApprovalApplicationDisposeDTO; import com.ruoyi.system.emums.ApprovalStatusEnum; import com.ruoyi.system.emums.ApprovalTypeEnum; import com.ruoyi.system.mapper.OaApprovalApplicationDisposeMapper; import com.ruoyi.system.model.OaApprovalApplicationAssetItem; import com.ruoyi.system.model.OaApprovalApplicationDispose; import com.ruoyi.system.model.OaApprovalApplications; import com.ruoyi.system.model.OaApprovalFlowNode; import com.ruoyi.system.query.OaApprovalApplicationDisposePageQuery; import com.ruoyi.system.service.OaApprovalApplicationAssetItemService; import com.ruoyi.system.service.OaApprovalApplicationDisposeService; import com.ruoyi.system.service.OaApprovalApplicationsService; import com.ruoyi.system.service.OaApprovalFlowNodeService; import com.ruoyi.system.service.OaApprovalTodoService; import com.ruoyi.system.vo.dispose.OaApprovalApplicationDisposePageVO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.stream.Collectors; /** * <p> * 资产领用单明细表 服务实现类 * 资产处置单明细表 服务实现类 * </p> * * @author WuGuanFengYue * @since 2025-09-15 */ @Service @RequiredArgsConstructor public class OaApprovalApplicationDisposeServiceImpl extends ServiceImpl<OaApprovalApplicationDisposeMapper, OaApprovalApplicationDispose> implements OaApprovalApplicationDisposeService { private final OaApprovalApplicationsService oaApprovalApplicationsService; private final OaApprovalFlowNodeService oaApprovalFlowNodeService; private final OaApprovalTodoService oaApprovalTodoService; private final OaApprovalApplicationAssetItemService oaApprovalApplicationAssetItemService; @Override public IPage<OaApprovalApplicationDisposePageVO> getDisposePageList(OaApprovalApplicationDisposePageQuery pageQuery) { Page<OaApprovalApplicationDisposePageVO> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()); return this.baseMapper.getDisposePageList(page, pageQuery); } @Override @Transactional(rollbackFor = Exception.class) public void submitDispose(OaApprovalApplicationDisposeDTO dto) { if (CollUtil.isEmpty(dto.getAssetMainIds())) { throw new ServiceException("资产ID列表不能为空"); } // 1. 构建并保存审批主表 OaApprovalApplications applications = buildOaApprovalApplications(dto); // 2. 获取流程首节点,设置当前节点,并保存 OaApprovalFlowNode firstFlowNode = getFirstFlowNode(ApprovalTypeEnum.ASSET_DISPOSE.getCode()); applications.setCurrentFlowNodeId(firstFlowNode.getId()); oaApprovalApplicationsService.save(applications); // 3. 创建待办 oaApprovalTodoService.createApprovalTodos(applications.getId(), applications.getApplicationCode(), firstFlowNode, dto.getDeptId()); // 4. 保存处置明细 OaApprovalApplicationDispose detail = buildOaApprovalApplicationDispose(dto, applications.getId()); this.save(detail); // 5. 保存关联的资产项 List<OaApprovalApplicationAssetItem> items = dto.getAssetMainIds().stream() .map(i -> { OaApprovalApplicationAssetItem item = new OaApprovalApplicationAssetItem(); item.setApprovalApplicationId(applications.getId()); item.setAssetMainId(i); return item; }) .collect(Collectors.toList()); oaApprovalApplicationAssetItemService.saveBatch(items); } private OaApprovalApplications buildOaApprovalApplications(OaApprovalApplicationDisposeDTO dto) { OaApprovalApplications applications = BeanUtil.copyProperties(dto, OaApprovalApplications.class); applications.setApplicationCode(generateApplicationCode("CZ")); applications.setApprovalId(ApprovalTypeEnum.ASSET_DISPOSE.getCode()); applications.setApplicationDate(LocalDate.now()); applications.setApprovalStatus(ApprovalStatusEnum.PENDING.getCode()); return applications; } private OaApprovalApplicationDispose buildOaApprovalApplicationDispose(OaApprovalApplicationDisposeDTO dto, Integer applicationId) { OaApprovalApplicationDispose dispose = BeanUtil.copyProperties(dto, OaApprovalApplicationDispose.class); dispose.setApprovalApplicationId(applicationId); return dispose; } private OaApprovalFlowNode getFirstFlowNode(Integer approvalId) { List<OaApprovalFlowNode> flowNodes = oaApprovalFlowNodeService.lambdaQuery() .eq(OaApprovalFlowNode::getApprovalId, approvalId) .eq(OaApprovalFlowNode::getStatus, 1) .orderByAsc(OaApprovalFlowNode::getSortOrder) .list(); if (CollectionUtils.isEmpty(flowNodes)) { throw new ServiceException("未找到有效的审批流程配置"); } return flowNodes.get(0); } /** * 生成申请单号:CZ + yyyyMMdd + 3位序号 */ private String generateApplicationCode(String prefix) { String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); prefix = prefix + dateStr; Long count = oaApprovalApplicationsService.lambdaQuery() .like(OaApprovalApplications::getApplicationCode, prefix) .count(); return prefix + String.format("%03d", count + 1); } @Override public void deleteByApplicationId(Integer applicationId) { this.lambdaUpdate().eq(OaApprovalApplicationDispose::getApprovalApplicationId, applicationId).remove(); oaApprovalApplicationAssetItemService.lambdaUpdate().eq(OaApprovalApplicationAssetItem::getApprovalApplicationId, applicationId).remove(); oaApprovalApplicationsService.removeById(applicationId); } } ruoyi-system/src/main/java/com/ruoyi/system/vo/dispose/OaApprovalApplicationDisposePageVO.java
New file @@ -0,0 +1,57 @@ package com.ruoyi.system.vo.dispose; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; /** * 资产处置申请分页列表VO */ @Data @ApiModel(value = "资产处置申请分页列表VO") public class OaApprovalApplicationDisposePageVO implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "审批申请ID") private Integer id; @ApiModelProperty(value = "单据号") private String applicationCode; @ApiModelProperty(value = "标题") private String title; @ApiModelProperty(value = "申请人") private String applicantName; @ApiModelProperty(value = "处置日期") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private LocalDate disposeTime; @ApiModelProperty(value = "处置方式 0-报废,1-报损,2-捐赠") private Integer disposeType; @ApiModelProperty(value = "处置方式名称") private String disposeTypeName; @ApiModelProperty(value = "处置金额") private BigDecimal disposeTotalAmount; @ApiModelProperty(value = "处置原因") private String applicationReason; @ApiModelProperty(value = "资产明细") private String assetTypeDetail; @ApiModelProperty(value = "审核状态 0-待审核,1-审核中,2-已通过,3-已拒绝") private Integer approvalStatus; @ApiModelProperty(value = "审核状态名称") private String approvalStatusName; } ruoyi-system/src/main/resources/mapper/system/OaApprovalApplicationAssetMapper.xml
@@ -72,9 +72,9 @@ LEFT JOIN oa_approval_applications oaa ON oaaai.approval_application_id = oaa.id <where> oaaa.type = 2 AND oaaa.borrow_application_id = #{applicationId} <if test="assetIds != null and assetIds.size() > 0"> <if test="assetMainIds != null and assetMainIds.size() > 0"> AND oaaai.asset_main_id IN <foreach collection="assetIds" item="id" open="(" separator="," close=")"> <foreach collection="assetMainIds" item="id" open="(" separator="," close=")"> #{id} </foreach> </if> ruoyi-system/src/main/resources/mapper/system/OaApprovalApplicationDisposeMapper.xml
@@ -18,4 +18,51 @@ id, approval_application_id, title, asset_type_id, dispose_time, dispose_type, dispose_total_amount </sql> <!-- 分页查询资产处置申请列表 --> <select id="getDisposePageList" resultType="com.ruoyi.system.vo.dispose.OaApprovalApplicationDisposePageVO"> SELECT app.id, app.application_code AS applicationCode, dispose.title, u.nick_name AS applicantName, dispose.dispose_time AS disposeTime, dispose.dispose_type AS disposeType, CASE dispose.dispose_type WHEN 0 THEN '报废' WHEN 1 THEN '报损' WHEN 2 THEN '捐赠' ELSE '未知' END AS disposeTypeName, dispose.dispose_total_amount AS disposeTotalAmount, app.application_reason AS applicationReason, CONCAT( IFNULL(pt.type_name, ''), CASE WHEN pt.type_name IS NOT NULL AND ct.type_name IS NOT NULL THEN '-' ELSE '' END, IFNULL(ct.type_name, '') ) AS assetTypeDetail, app.approval_status AS approvalStatus, CASE app.approval_status WHEN 0 THEN '待审核' WHEN 1 THEN '审核中' WHEN 2 THEN '已通过' WHEN 3 THEN '已拒绝' ELSE '未知' END AS approvalStatusName FROM oa_approval_applications app INNER JOIN oa_approval_application_dispose dispose ON app.id = dispose.approval_application_id LEFT JOIN sys_user u ON app.applicant_user_id = u.user_id LEFT JOIN asset_type ct ON dispose.asset_type_id = ct.id LEFT JOIN asset_type pt ON ct.parent_id = pt.id LEFT JOIN t_dept d ON app.dept_id = d.id WHERE app.disabled = 0 <if test="query.keyword != null and query.keyword != ''"> AND (dispose.title LIKE CONCAT('%', #{query.keyword}, '%') OR app.application_code LIKE CONCAT('%', #{query.keyword}, '%')) </if> <if test="query.deptId != null"> AND (d.id = #{query.deptId} OR FIND_IN_SET(#{query.deptId}, d.ancestors)) </if> ORDER BY app.create_time DESC </select> </mapper>