This commit is contained in:
aikai 2024-07-04 19:08:55 +08:00
commit 8078d05095
26 changed files with 460 additions and 60 deletions

View File

@ -16,7 +16,8 @@ public enum BpmMessageEnum {
PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时发送给申请人 PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时发送给申请人
TASK_ASSIGNED("bpm_task_assigned"), // 任务被分配时发送给审批人 TASK_ASSIGNED("bpm_task_assigned"), // 任务被分配时发送给审批人
BPM_WORK_TASK("bpm_work_task"), //任务分配发起任务 BPM_WORK_TASK("bpm_work_task"), //任务分配发起任务
BPM_WORK_TASK_COMPLETE("bpm_work_task_complete"); //任务分配任务完成 BPM_WORK_TASK_COMPLETE("bpm_work_task_complete"), //任务分配任务完成
BPM_OA_ENTRY_MESSAGE("bpm_oa_entry_message"); // 入职申请消息通知
/** /**
* 短信模板的标识 * 短信模板的标识

View File

@ -1,11 +1,15 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa; package cn.iocoder.yudao.module.bpm.controller.admin.oa;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryRespVO;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService;
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi; import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
@ -19,6 +23,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.annotation.security.PermitAll; import javax.annotation.security.PermitAll;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -42,6 +47,9 @@ public class BpmOAEntryController {
@Resource @Resource
private PostApi postApi; private PostApi postApi;
@Resource
private BpmTaskService bpmTaskService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建请求申请") @Operation(summary = "创建请求申请")
@PermitAll @PermitAll
@ -66,13 +74,24 @@ public class BpmOAEntryController {
@PermitAll @PermitAll
public CommonResult<BpmOAEntryRespVO> getEntryByOpenId(@RequestParam("openId") String openId) { public CommonResult<BpmOAEntryRespVO> getEntryByOpenId(@RequestParam("openId") String openId) {
BpmOAEntryDO entry = entryService.getEntryByOpenId(openId); // 查询当前openId 是否存在
List<BpmOAEntryDO> entryList = entryService.getEntryByOpenId(openId);
if (entry == null) { if (CollectionUtil.isEmpty(entryList)) {
return success(null); return success(null);
} }
BpmOAEntryDO entry = entryList.get(0);
BpmOAEntryRespVO respVO = BpmOAEntryConvert.INSTANCE.convert(entry); BpmOAEntryRespVO respVO = BpmOAEntryConvert.INSTANCE.convert(entry);
if (entry.getResult().equals(BpmProcessInstanceResultEnum.REJECT.getResult())) {
// 获得取消流程的 task
BpmTaskExtDO taskExtDO = bpmTaskService.getTaskByProcessInstanceIdAndResult(entry.getProcessInstanceId(),
BpmProcessInstanceResultEnum.REJECT.getResult());
respVO.setRemark(taskExtDO.getReason());
}
// 设备部门名称 // 设备部门名称
respVO.setEntryDeptName(getDept(entry.getEntryDeptId()).getName()); respVO.setEntryDeptName(getDept(entry.getEntryDeptId()).getName());
// 设备岗位名称 // 设备岗位名称
@ -97,7 +116,7 @@ public class BpmOAEntryController {
/** /**
* 获得岗位信息 * 获得岗位信息
* @param postId 岗位ID * @param postId 岗位ID
* @return * @return 岗位信息
*/ */
public PostRespVO getPost(Long postId) { public PostRespVO getPost(Long postId) {

View File

@ -62,4 +62,7 @@ public class BpmOAEntryRespVO extends BpmOABaseRespVO {
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
private List<UploadUserFile> fileItems; private List<UploadUserFile> fileItems;
@Schema(description = "备注")
private String remark;
} }

View File

@ -5,9 +5,8 @@ import lombok.Data;
/** /**
* 功能描述 用于给oa流程附件同用的上传文件对象 * 功能描述 用于给oa流程附件同用的上传文件对象
* * author: yj
* @author: yj * date: 2024年02月07日 22:37
* @date: 2024年02月07日 22:37
*/ */
@Data @Data
public class UploadUserFile { public class UploadUserFile {

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi; import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
@ -15,7 +16,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {FileApi.class,RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, @EnableFeignClients(clients = {FileApi.class,RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class,
SubscribeMessageSendApi.class, SocialClientApi.class SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class
}) })
public class RpcConfiguration { public class RpcConfiguration {
} }

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreate
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
public interface BpmOAEntryService { public interface BpmOAEntryService {
@ -21,7 +22,7 @@ public interface BpmOAEntryService {
* @param id 编号 * @param id 编号
* @param result 结果 * @param result 结果
*/ */
void updateEntryResult(Long id, Integer result); void updateEntryResult(String processInstanceId, Long id, Integer result);
/** /**
* 获得入职申请 * 获得入职申请
@ -36,5 +37,5 @@ public interface BpmOAEntryService {
* @param openId openId * @param openId openId
* @return 入职申请信息 * @return 入职申请信息
*/ */
BpmOAEntryDO getEntryByOpenId(String openId); List<BpmOAEntryDO> getEntryByOpenId(String openId);
} }

View File

@ -1,21 +1,41 @@
package cn.iocoder.yudao.module.bpm.service.oa; package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.upload.UploadUserFile;
import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAEntryMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAEntryMapper;
import cn.iocoder.yudao.module.bpm.enums.message.BpmMessageEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.infra.api.file.dto.UserFileUpdateReqDTO;
import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_ENTRY_NOT_EXISTS; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_ENTRY_NOT_EXISTS;
/** /**
@ -38,7 +58,27 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{
@Resource @Resource
private BpmProcessInstanceApi processInstanceApi; private BpmProcessInstanceApi processInstanceApi;
@Resource
@Lazy
private BpmProcessInstanceService bpmProcessInstanceService;
@Resource
private AdminUserApi userApi;
@Resource
private FileApi fileApi;
@Resource
private UsersExtApi usersExtApi;
@Resource
private WebProperties webProperties;
@Resource
private NotifyMessageSendApi notifyMessageSendApi;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Long createEntry(BpmOAEntryCreateReqVO createReqVO) { public Long createEntry(BpmOAEntryCreateReqVO createReqVO) {
//插入OA 入职申请 //插入OA 入职申请
@ -59,16 +99,75 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{
} }
@Override @Override
public void updateEntryResult(Long id, Integer result) { @Transactional(rollbackFor = Exception.class)
public void updateEntryResult(String processInstanceId, Long id, Integer result) {
validateLeaveExists(id); BpmOAEntryDO entry = validateLeaveExists(id);
entryMapper.updateById(new BpmOAEntryDO().setId(id).setResult(result));
BpmOAEntryDO updateVO = new BpmOAEntryDO().setId(id).setResult(result);
//审核通过 最后节点
if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
if (instance.isEnded()) {
// 新增入职申请中的用户信息
UserSaveRespDTO saveRespDTO = BeanUtils.toBean(entry, UserSaveRespDTO.class);
saveRespDTO.setId(null);
saveRespDTO.setDeptId(entry.getEntryDeptId());
saveRespDTO.setPostIds(Collections.singleton(entry.getEntryPostId()));
saveRespDTO.setPassword("123456");
// 解析身份证号码
IdCardDO idCardDO = StrUtils.IdCardAnalysis(saveRespDTO.getIdcard());
// 设置性别年龄生日
saveRespDTO.setSex(idCardDO.getSex());
saveRespDTO.setAge(idCardDO.getAge());
saveRespDTO.setBirthdayDay(idCardDO.getDate());
// 插入用户 获得用户编号
Long userId = userApi.createUser(saveRespDTO).getCheckedData();
updateVO.setEntryUserId(userId);
// 同步修改用户文件数据
List<UploadUserFile> uploadUserFiles = BeanUtils.toBean(entry.getFileItems(), UploadUserFile.class);
UserFileUpdateReqDTO updateReqDTO = new UserFileUpdateReqDTO()
.setUrls(convertList(uploadUserFiles, UploadUserFile::getUrl))
.setUserId(userId);
fileApi.updateUserFileUserId(updateReqDTO);
// 同步修改business_file文件 更新用户编号
fileApi.updateBusinessFileFormEntry(entry.getFaceImg(), String.valueOf(userId));
try {
// 同步插入用户拓展表
usersExtApi.createUsersExt(userId, entry.getNickname(), entry.getEntryDeptId(), entry.getFaceImg());
} catch (Exception e) {
Map<String, Object> templateParams = new HashMap<>();
templateParams.put("userName", entry.getNickname());
templateParams.put("detailUrl", webProperties.getAdminUi().getUrl() + "/attendance/user?userName=" + entry.getNickname());
// 发送站内信 通知流程发起人 新员工人脸图片上传失败
notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1(
entry.getUserId(), BpmMessageEnum.BPM_OA_ENTRY_MESSAGE.getSmsTemplateCode(), templateParams));
}
}
} }
private void validateLeaveExists(Long id) { // 更新入职申请状态
if (entryMapper.selectById(id) == null) { entryMapper.updateById(updateVO);
}
private BpmOAEntryDO validateLeaveExists(Long id) {
BpmOAEntryDO entry = entryMapper.selectById(id);
if (entry == null) {
throw exception(OA_ENTRY_NOT_EXISTS); throw exception(OA_ENTRY_NOT_EXISTS);
} }
return entry;
} }
@Override @Override
@ -78,10 +177,10 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{
} }
@Override @Override
public BpmOAEntryDO getEntryByOpenId(String openId) { public List<BpmOAEntryDO> getEntryByOpenId(String openId) {
return entryMapper.selectOne(new LambdaQueryWrapperX<BpmOAEntryDO>() return entryMapper.selectList(new LambdaQueryWrapperX<BpmOAEntryDO>()
.eq(BpmOAEntryDO::getOpenId, openId) .eq(BpmOAEntryDO::getOpenId, openId)
.eq(BpmOAEntryDO::getResult, BpmProcessInstanceResultEnum.REJECT.getResult())); .orderByDesc(BpmOAEntryDO::getCreateTime));
} }
} }

View File

@ -28,6 +28,6 @@ public class BpmOAEntryResultListener extends BpmProcessInstanceResultEventListe
@Override @Override
protected void onEvent(BpmProcessInstanceResultEvent event) { protected void onEvent(BpmProcessInstanceResultEvent event) {
entryService.updateEntryResult(Long.parseLong(event.getBusinessKey()), event.getResult()); entryService.updateEntryResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult());
} }
} }

View File

@ -205,5 +205,19 @@ public interface BpmTaskService {
*/ */
String getCurrentTaskIdByProcessInstanceId(String processInstanceId) ; String getCurrentTaskIdByProcessInstanceId(String processInstanceId) ;
/**
* 获得指定的task记录
* @param processInstanceId 流程实例id集合
* @param result 结果
* @return task
*/
List<BpmTaskExtDO> getTaskByProcessInstanceIdAndResult(List<String> processInstanceId, Integer result); List<BpmTaskExtDO> getTaskByProcessInstanceIdAndResult(List<String> processInstanceId, Integer result);
/**
* 获得指定的task记录
* @param processInstanceId 流程实例id
* @param result 结果
* @return task
*/
BpmTaskExtDO getTaskByProcessInstanceIdAndResult(String processInstanceId, Integer result);
} }

View File

@ -1235,4 +1235,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return taskExtMapper.selectTask(processInstanceId, result); return taskExtMapper.selectTask(processInstanceId, result);
} }
@Override
public BpmTaskExtDO getTaskByProcessInstanceIdAndResult(String processInstanceId, Integer result) {
return taskExtMapper.selectOne(new LambdaQueryWrapperX<BpmTaskExtDO>()
.eq(BpmTaskExtDO::getProcessInstanceId, processInstanceId)
.eq(BpmTaskExtDO::getResult, result));
}
} }

View File

@ -76,12 +76,18 @@ public interface FileApi {
@RequestParam("name") String name, @RequestParam("name") String name,
@RequestBody byte[] content); @RequestBody byte[] content);
@PostMapping(PREFIX + "/updateBusinessFile")
@Operation(summary = "修改BusinessFile文件中的 businessInstanceId | 入职申请用")
CommonResult<Boolean> updateBusinessFileFormEntry(@RequestParam("url") String url,
@RequestParam("businessInstanceId") String businessInstanceId);
@DeleteMapping(PREFIX + "/deleteBpmFile") @DeleteMapping(PREFIX + "/deleteBpmFile")
@Operation(summary = "删除工作流附件") @Operation(summary = "删除工作流附件")
@Parameter(name = "url", description = "附件URL地址", required = true) @Parameter(name = "url", description = "附件URL地址", required = true)
CommonResult<Boolean> deleteBpmFile(@RequestParam("url") String url) throws Exception; CommonResult<Boolean> deleteBpmFile(@RequestParam("url") String url) throws Exception;
@PutMapping(PREFIX + "/updateUserFile") @PostMapping(PREFIX + "/updateUserFile")
@Operation(summary = "修改用户文件绑定 用户编号") @Operation(summary = "修改用户文件绑定 用户编号")
CommonResult<Boolean> updateUserFileUserId(@RequestBody UserFileUpdateReqDTO updateReqVO); CommonResult<Boolean> updateUserFileUserId(@RequestBody UserFileUpdateReqDTO updateReqVO);
} }

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.infra.api.file.dto.UserFileUpdateReqDTO;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.BpmFileUploadReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.BpmFileUploadReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.UserFileUpdateReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.UserFileUpdateReqVO;
import cn.iocoder.yudao.module.infra.service.file.FileService; import cn.iocoder.yudao.module.infra.service.file.FileService;
import lombok.SneakyThrows;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -55,6 +56,14 @@ public class FileApiImpl implements FileApi {
return fileService.updateBusinessFileContent(url, businessType, name, content) ; return fileService.updateBusinessFileContent(url, businessType, name, content) ;
} }
@Override
@SneakyThrows
public CommonResult<Boolean> updateBusinessFileFormEntry(String url, String businessInstanceId) {
fileService.uploadBusinessFileFormEntry(url, businessInstanceId);
return success(true);
}
@Override @Override
public CommonResult<Boolean> deleteBpmFile(String url) throws Exception { public CommonResult<Boolean> deleteBpmFile(String url) throws Exception {

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.*; import cn.iocoder.yudao.module.infra.dal.dataobject.file.*;
import cn.iocoder.yudao.module.infra.service.file.FileService; import cn.iocoder.yudao.module.infra.service.file.FileService;
@ -35,6 +36,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
@ -61,6 +63,9 @@ public class FileController {
@Resource @Resource
private PostApi postApi; private PostApi postApi;
@Resource
private SecurityProperties securityProperties;
@PostMapping("/uploadBpmFileProcessInstanceId") @PostMapping("/uploadBpmFileProcessInstanceId")
@Operation(summary = "更新文件的流程实例ID") @Operation(summary = "更新文件的流程实例ID")
@OperateLog(logArgs = false) // 上传文件没有记录操作日志的必要 @OperateLog(logArgs = false) // 上传文件没有记录操作日志的必要
@ -188,45 +193,54 @@ public class FileController {
@RequestParam("deptId") Long deptId, @RequestParam("deptId") Long deptId,
@RequestParam(value = "postId", required = false) Long postId) { @RequestParam(value = "postId", required = false) Long postId) {
// 查询当前部门编号下 是否存在小程序码 // 查询当前部门编号下 是否存在小程序码
QRCodeDO qrCodeDO = fileService.getQRCode(deptId); QRCodeDO qrCodeDO = fileService.getQRCode(deptId, null);
JSONObject scene = new JSONObject();
scene.set("userId", userId);
scene.set("deptId", deptId);
scene.set("postId", postId);
// 小程序码不存在 生成新的小程序码 // 小程序码不存在 生成新的小程序码
if (qrCodeDO == null) { if (qrCodeDO == null) {
// 生成小程序码
File QRCode = socialClientApi.getQRCode("subPages/register/register", "deptId=" + deptId).getCheckedData();
JSONObject object = new JSONObject();
object.set("userId", userId);
object.set("deptId", deptId);
object.set("postId", postId);
try { try {
FileInputStream fis = new FileInputStream(QRCode); qrCodeDO = createQRCode(deptId, scene.toString());
byte[] content = IoUtil.readBytes(fis);
// 上传小程序码 获得url
qrCodeDO = fileService.createQRCodeFile(deptId, QRCode.getName(), content, object.toString());
} catch (IOException e) { } catch (IOException e) {
return error(OA_QRCODE_ERROR); return error(OA_QRCODE_ERROR);
} }
}else { // 存在的时候 则更新小程序码的生成时间 }else { // 存在的时候 判断是否已存在相同参数的小程序码
// 查询是否存在 参数一致的小程序码
qrCodeDO = fileService.getQRCode(deptId, scene.toString());
if (qrCodeDO == null) {
try {
qrCodeDO = createQRCode(deptId, scene.toString());
} catch (IOException e) {
return error(OA_QRCODE_ERROR);
}
}else {
fileService.updateQRCodeFile(qrCodeDO.getId()); fileService.updateQRCodeFile(qrCodeDO.getId());
} }
}
return success(qrCodeDO); return success(qrCodeDO);
} }
@GetMapping("getQRCode") @GetMapping("getQRCode")
@Operation(summary = "获得入职申请小程序码") @Operation(summary = "获得入职申请小程序码")
public CommonResult<QRCodeReqVO> getQRCode(@RequestParam("deptId") Long deptId) { @PermitAll
public CommonResult<QRCodeReqVO> getQRCode(@RequestParam("id") Long id) {
// 查询当前部门编号下 是否存在小程序码 // 查询当前部门编号下 是否存在小程序码
QRCodeDO qrCodeDO = fileService.getQRCode(deptId); QRCodeDO qrCodeDO = fileService.getQRCode(id);
if (qrCodeDO != null) { if (qrCodeDO != null) {
@ -239,6 +253,7 @@ public class FileController {
reqVO.setUserId(Long.valueOf(qrCodeDO.getUpdater())); reqVO.setUserId(Long.valueOf(qrCodeDO.getUpdater()));
// 获取部门信息 // 获取部门信息
Long deptId = Long.valueOf(scene.get("deptId").toString());
DeptRespDTO deptRespDTO = deptApi.getDept(deptId).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(deptId).getCheckedData();
reqVO.setDeptId(deptId); reqVO.setDeptId(deptId);
reqVO.setDeptName(deptRespDTO.getName()); reqVO.setDeptName(deptRespDTO.getName());
@ -267,4 +282,18 @@ public class FileController {
return success(true); return success(true);
} }
public QRCodeDO createQRCode(Long deptId, String scene) throws FileNotFoundException {
Long id = fileService.createQRCodeFile(deptId, scene.toString());
// 生成小程序码
File QRCode = socialClientApi.getQRCode("subPages/register/register", "id=" + id).getCheckedData();
FileInputStream fis = new FileInputStream(QRCode);
byte[] content = IoUtil.readBytes(fis);
// 上传小程序码 获得url
return fileService.updateQRCodeFile(id, deptId, QRCode.getName(), content);
}
} }

View File

@ -8,10 +8,11 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface QRCodeDOMapper extends BaseMapperX<QRCodeDO> { public interface QRCodeDOMapper extends BaseMapperX<QRCodeDO> {
default QRCodeDO selectByDeptId(Long deptId) { default QRCodeDO selectByDeptId(Long deptId, String scene) {
return selectOne(new LambdaQueryWrapperX<QRCodeDO>() return selectOne(new LambdaQueryWrapperX<QRCodeDO>()
.eq(QRCodeDO::getBusinessId, deptId) .eq(QRCodeDO::getBusinessId, deptId)
.eqIfPresent(QRCodeDO::getScene, scene)
.eq(QRCodeDO::getBusinessType, 1)); .eq(QRCodeDO::getBusinessType, 1));
} }
} }

View File

@ -102,6 +102,12 @@ public interface FileService {
*/ */
void uploadBusinessFileProcessInstanceId(BusinessFileUploadReqVO reqVO) throws Exception ; void uploadBusinessFileProcessInstanceId(BusinessFileUploadReqVO reqVO) throws Exception ;
/**
* 更新文件的流程实例ID | 入职申请用
* @param url 文件地址
*/
void uploadBusinessFileFormEntry(String url, String businessInstanceId);
/** /**
* 获取用户的签名图片地址 * 获取用户的签名图片地址
* *
@ -153,14 +159,22 @@ public interface FileService {
* @param content 字节流 * @param content 字节流
* @return url * @return url
*/ */
QRCodeDO createQRCodeFile(Long deptId, String name, byte[] content, String scene) ; QRCodeDO updateQRCodeFile(Long id, Long deptId, String name, byte[] content) ;
/**
* 获得小程序码信息
* @param id 编号
* @return 小程序码信息
*/
QRCodeDO getQRCode(Long id);
/** /**
* 获得小程序码信息 * 获得小程序码信息
* @param deptId 部门编号 * @param deptId 部门编号
* @param scene 参数
* @return 小程序码信息 * @return 小程序码信息
*/ */
QRCodeDO getQRCode(Long deptId); QRCodeDO getQRCode(Long deptId, String scene);
/** /**
* 更新 小程序码生成时间 * 更新 小程序码生成时间
@ -173,4 +187,11 @@ public interface FileService {
* @param url 文件链接 * @param url 文件链接
*/ */
void deleteQRCode(String url); void deleteQRCode(String url);
/**
* 创建小程序码文件
* @param deptId 部门编号
* @param scene 参数
*/
Long createQRCodeFile(Long deptId, String scene);
} }

View File

@ -319,7 +319,6 @@ public class FileServiceImpl implements FileService {
/** /**
* 更新文件的流程实例ID * 更新文件的流程实例ID
* @param reqVO * @param reqVO
* @throws Exception
*/ */
@Override @Override
@SneakyThrows @SneakyThrows
@ -333,6 +332,21 @@ public class FileServiceImpl implements FileService {
businessFileMapper.update(null, lambdaUpdateWrapper); businessFileMapper.update(null, lambdaUpdateWrapper);
} }
@Override
@SneakyThrows
public void uploadBusinessFileFormEntry(String url, String businessInstanceId) {
LambdaUpdateWrapper<BusinessFileDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(BusinessFileDO::getUrl, url);
lambdaUpdateWrapper.set(BusinessFileDO::getBusinessInstanceId, businessInstanceId); // 假设 bid 是要更新的 bid
lambdaUpdateWrapper.set(BusinessFileDO::getUploadUserId, businessInstanceId);
lambdaUpdateWrapper.set(BusinessFileDO::getCreator, businessInstanceId);
lambdaUpdateWrapper.set(BusinessFileDO::getUpdater, businessInstanceId);
// 调用 MyBatis Plus update 方法执行批量更新
businessFileMapper.update(null, lambdaUpdateWrapper);
}
@Override @Override
public String getUserSignImgPath(Long userId) { public String getUserSignImgPath(Long userId) {
BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId(2L, userId.toString()) ; BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId(2L, userId.toString()) ;
@ -472,7 +486,7 @@ public class FileServiceImpl implements FileService {
@Override @Override
@SneakyThrows @SneakyThrows
public QRCodeDO createQRCodeFile(Long deptId, String name, byte[] content, String scene) { public QRCodeDO updateQRCodeFile(Long id, Long deptId, String name, byte[] content) {
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
// 计算默认的 path // 计算默认的 path
@ -491,20 +505,25 @@ public class FileServiceImpl implements FileService {
// 插入 system_qr_code // 插入 system_qr_code
QRCodeDO fileDo = new QRCodeDO(); QRCodeDO fileDo = new QRCodeDO();
fileDo.setBusinessId(deptId.toString()); fileDo.setId(id);
fileDo.setBusinessType(1); fileDo.setBusinessType(1);
fileDo.setConfigId(client.getId()); fileDo.setConfigId(client.getId());
fileDo.setUrl(url); fileDo.setUrl(url);
fileDo.setScene(scene); qrCodeDOMapper.updateById(fileDo);
qrCodeDOMapper.insert(fileDo);
return fileDo; return fileDo;
} }
@Override @Override
public QRCodeDO getQRCode(Long deptId) { public QRCodeDO getQRCode(Long id) {
return qrCodeDOMapper.selectByDeptId(deptId); return qrCodeDOMapper.selectById(id);
}
@Override
public QRCodeDO getQRCode(Long deptId, String scene) {
return qrCodeDOMapper.selectByDeptId(deptId, scene);
} }
@Override @Override
@ -533,6 +552,17 @@ public class FileServiceImpl implements FileService {
qrCodeDOMapper.deleteById(qrCodeDO.getId()); qrCodeDOMapper.deleteById(qrCodeDO.getId());
} }
@Override
public Long createQRCodeFile(Long deptId, String scene) {
QRCodeDO createDO = new QRCodeDO()
.setBusinessId(String.valueOf(deptId))
.setScene(scene);
qrCodeDOMapper.insert(createDO);
return createDO.getId();
}
/** /**
* 从文件存储器删除 文件 * 从文件存储器删除 文件
*/ */

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.system.api.equipment;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 用户拓展")
public interface UsersExtApi {
String PREFIX = ApiConstants.PREFIX + "/attendance-machine";
@PostMapping(PREFIX + "/create")
@Operation(summary = "新增设备请求记录")
void createUsersExt(@RequestParam("userId") Long userId,
@RequestParam("userName") String userName,
@RequestParam("deptId") Long deptId,
@RequestParam("faceImg") String faceImg);
}

View File

@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.system.api.user;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants; import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping; 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.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection; import java.util.Collection;
@ -63,4 +66,8 @@ public interface AdminUserApi {
@Operation(summary = "获取同部门所有用户id") @Operation(summary = "获取同部门所有用户id")
@Parameter(name = "userId", description = "用户id", example = "1024", required = true) @Parameter(name = "userId", description = "用户id", example = "1024", required = true)
CommonResult<List<Long>> getUserIdsByUserIdGroupByDept(@RequestParam("userId") Long userId); CommonResult<List<Long>> getUserIdsByUserIdGroupByDept(@RequestParam("userId") Long userId);
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建用户")
CommonResult<Long> createUser(@RequestBody UserSaveRespDTO saveRespDTO);
} }

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.system.api.user.dto;
import cn.iocoder.yudao.framework.common.validation.IdCard;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.Size;
import java.time.LocalDate;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "RPC 服务 - Admin 用户创建 DTO")
@Data
public class UserSaveRespDTO {
@Schema(description = "用户 ID", example = "1024")
private Long id;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@Size(max = 30, message = "用户昵称长度不能超过30个字符")
private String nickname;
@Schema(description = "部门ID", example = "我是一个用户")
private Long deptId;
@Schema(description = "岗位编号数组", example = "1")
private Set<Long> postIds;
@Schema(description = "手机号码", example = "15601691300")
@Mobile
private String mobile;
@Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
private Integer sex;
@Schema(description = "身份证号码")
@IdCard
private String idcard;
@Schema(description = "年龄", example = "23")
private Integer age;
@Schema(description = "生日日期", example = "03-23")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate birthdayDay;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.system.api.equipment;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.websocket.AddUserVO;
import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO;
import cn.iocoder.yudao.module.system.service.equipment.AttendanceMachineService;
import cn.iocoder.yudao.module.system.service.equipment.UsersExtService;
import cn.iocoder.yudao.module.system.service.websocket.WebsocketService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
public class UsersExtApiImpl implements UsersExtApi{
@Resource
private UsersExtService usersExtService;
@Resource
private AttendanceMachineService attendanceMachineService;
@Resource
private WebsocketService websocketService;
@Override
public void createUsersExt(Long userId, String userName, Long deptId, String faceImg) {
// 查询当前部门下 是否存在考勤设备
List<AttendanceMachineDO> deviceList = attendanceMachineService.getListByDeptId(deptId);
List<String> deviceNos = new ArrayList<>();
try {
for (AttendanceMachineDO machineDO : deviceList) {
// 设置下发命令
AddUserVO addUserVO = new AddUserVO()
.setCmd("addUser")
.setUser_id(String.valueOf(userId))
.setName(userName)
.setFace_template(faceImg)
.setId_valid("");
// 发送指令至 考勤设备 下发员工
websocketService.sendSn(machineDO.getDeviceNo(), addUserVO, 1);
deviceNos.add(machineDO.getDeviceNo());
}
} finally {
UsersExtSaveReqVO saveReqVO = new UsersExtSaveReqVO()
.setUserId(userId)
.setDeptId(deptId)
.setFaceImg(faceImg)
.setAttendanceMachineNos(deviceNos);
// 插入用户拓展信息
usersExtService.createUsers(saveReqVO);
}
}
}

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -12,7 +14,6 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -62,4 +63,10 @@ public class AdminUserApiImpl implements AdminUserApi {
return success(userIds); return success(userIds);
} }
@Override
public CommonResult<Long> createUser(UserSaveRespDTO saveRespDTO) {
return success(userService.createUser(BeanUtils.toBean(saveRespDTO, UserSaveReqVO.class)));
}
} }

View File

@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.system.controller.admin.equipment.vo.attendancem
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 考勤设备新增/修改 Request VO") @Schema(description = "管理后台 - 考勤设备新增/修改 Request VO")
@Data @Data
public class AttendanceMachineSaveReqVO { public class AttendanceMachineSaveReqVO {
@ -28,4 +25,7 @@ public class AttendanceMachineSaveReqVO {
@Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String deviceName; private String deviceName;
@Schema(description = "是否分配资产")
private Boolean isAssets;
} }

View File

@ -91,7 +91,7 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService {
validateAttendanceMachineExists(updateReqVO.getId(), updateReqVO.getDeviceNo()); validateAttendanceMachineExists(updateReqVO.getId(), updateReqVO.getDeviceNo());
//如果分配机构的情况 则调用资产分配方法 //如果分配机构的情况 则调用资产分配方法
if (updateReqVO.getDeptId() != null) { if (updateReqVO.getIsAssets()) {
DeptAssetsInOutStockSaveReqVO vos = new DeptAssetsInOutStockSaveReqVO(); DeptAssetsInOutStockSaveReqVO vos = new DeptAssetsInOutStockSaveReqVO();
vos.setInDeptId(updateReqVO.getDeptId()); vos.setInDeptId(updateReqVO.getDeptId());

View File

@ -66,7 +66,7 @@ public class WebsocketServiceImpl implements WebsocketService{
if (StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(deviceNo))) { if (StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(deviceNo))) {
stringRedisTemplate.opsForValue().set(deviceNo, "true"); stringRedisTemplate.opsForValue().set(deviceNo, "true");
} }
// 发送修改密码命令给设备 // 发送命令给设备
webSocketSenderApi.sendSN(deviceNo, "attendance-message-send", JsonUtils.toJsonString(baseVO)); webSocketSenderApi.sendSN(deviceNo, "attendance-message-send", JsonUtils.toJsonString(baseVO));
Long startTime = System.currentTimeMillis(); Long startTime = System.currentTimeMillis();

View File

@ -116,6 +116,12 @@ spring:
# Spring Boot Admin Server 服务端的相关配置 # Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring context-path: /admin # 配置 Spring
# 日志文件配置
logging:
level:
# 配置自己写的 MyBatis Mapper 打印日志
cn.iocoder.yudao.module.system.dal.mysql: debug
--- #################### 微信公众号、小程序相关配置 #################### --- #################### 微信公众号、小程序相关配置 ####################
wx: wx:
mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档