调整Oam通讯录,调整角色绑定

This commit is contained in:
DB 2023-10-16 17:19:54 +08:00
parent 59282a7ae1
commit 8e1b539669
29 changed files with 782 additions and 118 deletions

View File

@ -77,7 +77,7 @@ CREATE TABLE `cp_sys_user` (
`nick_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`phone_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
`sex` tinyint(1) NULL DEFAULT NULL COMMENT '性别(0:男;1:女)',
`sex` tinyint(1) NULL DEFAULT '0' COMMENT '性别(0:男;1:女)',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像',
`salt` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '',
`status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0:停用;1:启用)',

View File

@ -34,6 +34,9 @@ public class SecurityUtils {
**/
public LoginUser getLoginUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return null;
}
if (null != authentication.getPrincipal()) {
return (LoginUser) authentication.getPrincipal();
} else {

View File

@ -78,9 +78,3 @@ knife4j:
api-rule: package
api-rule-resources:
- com.cpop.oam
#jambox
jambox:
group-name: Jambox
api-rule: package
api-rule-resources:
- com.cpop.jambox

View File

@ -4,7 +4,7 @@ cpop:
profile: /root/jambox-union/jambox-oam/uploadPath/upload
jwt:
#白名单
whiteList: /login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*
whiteList: /login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*
#拦截
gateway:
rsa-keypair:

View File

@ -4,7 +4,7 @@ cpop:
profile: /root/jambox-union/jambox-oam/uploadPath/upload
jwt:
#白名单
whiteList: /login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*
whiteList: /login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*
#拦截
gateway:
rsa-keypair:
@ -79,9 +79,3 @@ knife4j:
api-rule: package
api-rule-resources:
- com.cpop.oam
#jambox
jambox:
group-name: Jambox
api-rule: package
api-rule-resources:
- com.cpop.jambox

View File

@ -1,7 +1,14 @@
package com.cpop.oam.web;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author DB
* @createTime 2023/09/15 17:44
@ -10,14 +17,15 @@ import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class CpopApiTests {
/*@Autowired
@Autowired
private WebHookSendHandler webHookSendHandler;
*//**
/**
* @descriptions 机器人发送测试
* @author DB
* @date 2023/09/15 17:46
*//*
* @date 2023/10/12 15:19
* @return: void
*/
@Test
public void webHookSendTest(){
List<String> list = new ArrayList<>();
@ -27,5 +35,5 @@ public class CpopApiTests {
} catch (IOException e) {
throw new RuntimeException(e);
}
}*/
}
}

View File

@ -0,0 +1,377 @@
package com.cpop.oam.web;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysUser;
import com.cpop.core.mapper.CoreMapper;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.uuid.IdUtils;
import com.cpop.oam.business.entity.Dept;
import com.cpop.oam.business.entity.Staff;
import com.cpop.oam.business.entity.StaffMidDept;
import com.cpop.oam.business.service.DeptService;
import com.cpop.oam.business.service.StaffMidDeptService;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.framework.config.wxCp.WxCpConfiguration;
import com.mybatisflex.core.row.Db;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.export.WxCpExportRequest;
import me.chanjar.weixin.cp.bean.export.WxCpExportResult;
import me.chanjar.weixin.cp.bean.user.WxCpDeptUserResult;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* @author DB
* @createTime 2023/10/12 15:19
* @description 企业微信Api测试
*/
@SpringBootTest
@Slf4j
public class CpopWxCpTests {
/**
* @descriptions 获取成员ID列表
* @author DB
* @date 2023/10/12 15:33
* @return: void
*/
@Test
public void userListId() {
try {
WxCpDeptUserResult userListId = WxCpConfiguration.getCpService(1000024).getUserService().getUserListId("", 100);
System.out.println(userListId);
} catch (WxErrorException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 根据手机号获取用户id
*/
@Test
public void getUserId() {
try {
String userId = WxCpConfiguration.getCpService(1000024).getUserService().getUserId("17728500831");
System.out.println(userId);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
/**
* 根据用户id获取用户
*/
@Test
public void getUser() {
try {
WxCpUser user = WxCpConfiguration.getCpService(1000024).getUserService().getById("XiaoKanTianSeMuKanYun");
System.out.println(user);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
/**
* 获取部门列表
*/
@Test
public void getDepartmentList() {
try {
List<WxCpDepart> wxCpDeparts = WxCpConfiguration.getCpService(1000000).getDepartmentService().simpleList(1L);
System.out.println(wxCpDeparts);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
@Test
public void getDeptById() {
try {
WxCpDepart wxCpDepart = WxCpConfiguration.getCpService(1000024).getDepartmentService().get(1L);
System.out.println(wxCpDepart);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
/**
* 导出部门
*/
@Test
public void exportDept() {
try {
WxCpExportRequest request = new WxCpExportRequest();
request.setEncodingAesKey("DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt");
String jabId = WxCpConfiguration.getCpService(1000024).getExportService().department(request);
System.out.println(jabId);
} catch (WxErrorException e) {
throw new RuntimeException(e);
}
}
/**
* @descriptions 获取导出结果
* @author DB
* @date 2023/10/13 16:18
* @return: void
*/
@Test
public void getExportResult() throws WxErrorException {
//jobid_dFssU8d6nirNJjOHwoxoPV23OzWH6edwrb__ilftwyA
WxCpExportResult result = WxCpConfiguration.getCpService(1000024).getExportService().getResult("jobid__qH9HAsRGgeErUVEaJA1UnOFpjuL7CQddh11dYtDE6s");
System.out.println(result);
}
/**
* @descriptions 解密导出数据
* @author DB
* @date 2023/10/13 16:49
* @return: void
*/
@Test
public void decryptExportData(){
String result = getDecryptExportData("DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt", "https://szfront.wxwork.qq.com:443/downloadobject?fileid=080112043133303122093131343535363239362a0131322463396566396533662d626332392d346666622d623033652d623034626633343633656539388004421453e8114eb1942bcda5dfca7c8457534c237ab95448015802600768b8177207333030303030308a010b6170706c69636174696f6e90018ffba3a9069a0100a001d5b703&weixinnum=2519320458&authkey=7008001005186022606b8b2cec47b7d5c6a502d671c77f8b35bfb4908f7cc912258e5c54554a0485f9b61c484bb3f5c56fc823c2b3aefed8b319fd113a0220b6297a7879c4a3d50313c6bc91b004c50efd6d2849165eb511f52b8027d3f34de5e970d95291af935be7&filename=data_0.json");
if (result != null) {
System.out.println(result.substring(0, result.lastIndexOf("}") + 1));
}
}
public final String getDecryptExportData(String aesKey, String url) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(url, byte[].class);
if (responseEntity.getBody() == null) {
return null;
}
byte[] key = Base64.decodeBase64(aesKey + "=");
byte[] original = null;
try {
// 设置解密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(key, 0, 16));
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
original = cipher.doFinal(responseEntity.getBody());
} catch (Exception e) {
log.error("", e);
}
assert original != null;
return new String(original);
}
/**
* @descriptions 导入部门
* @author DB
* @date 2023/10/13 16:54
* @return: void
*/
@Test
public void importDept() {
//将导出数据转换
String result = getDecryptExportData("DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt", "https://szfront.wxwork.qq.com:443/downloadobject?fileid=080112043133303122093131343535363239362a0131322463396566396533662d626332392d346666622d623033652d623034626633343633656539388004421453e8114eb1942bcda5dfca7c8457534c237ab95448015802600768b8177207333030303030308a010b6170706c69636174696f6e90018ffba3a9069a0100a001d5b703&weixinnum=2519320458&authkey=7008001005186022606b8b2cec47b7d5c6a502d671c77f8b35bfb4908f7cc912258e5c54554a0485f9b61c484bb3f5c56fc823c2b3aefed8b319fd113a0220b6297a7879c4a3d50313c6bc91b004c50efd6d2849165eb511f52b8027d3f34de5e970d95291af935be7&filename=data_0.json");
//导出集合
List<ExportDept> exportDeptList = JSONObject.parseObject(result).getJSONArray("department").toJavaList(ExportDept.class);
//转换部门
List<Dept> list = new ArrayList<>();
exportDeptList.forEach(item -> {
Dept dept = new Dept();
dept.setWxCpId(item.getId())
.setWxCpParentId(item.getParentId())
.setOrderNo(item.getOrder())
.setName(item.getName());
list.add(dept);
});
//批量导入数据
DeptService deptService = SpringUtils.getBean(DeptService.class);
deptService.saveBatch(list);
//同步父id
Map<Long, Dept> deptMap = list.stream().collect(Collectors.toMap(Dept::getWxCpId, item -> item));
list.forEach(item->{
if (null != deptMap.get(item.getWxCpParentId())){
item.setParentId(deptMap.get(item.getWxCpParentId()).getId());
}
});
//批量更新
deptService.updateBatch(list);
}
/**
* 导出部门数据
*/
@Data
public class ExportDept {
/**
* 部门id
*/
private Long id;
/**
* 部门名
*/
private String name;
/**
* 父部门id
*/
@JSONField(name = "parentid")
private Long parentId;
/**
* 排序
*/
private Integer order;
}
@Test
public void getUserList() throws WxErrorException {
WxCpExportRequest request = new WxCpExportRequest();
request.setEncodingAesKey("DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt");
String jobId = WxCpConfiguration.getCpService(1000024).getExportService().user(request);
System.out.println(jobId);
}
/**
* @descriptions 导出员工
* @author DB
* @date 2023/10/16 9:20
* @return: void
*/
@Test
public void importStaffList() throws WxErrorException {
//https://szfront.wxwork.qq.com:443/downloadobject?fileid=080112043133303122093131343535363239362a0131322464333430383931612d386139312d346262652d616231302d62353464653065383035316138a03b42149c55bf3c6169f900ae391370dd348245dd7308a548015802600768b8177207333030303030308a010b6170706c69636174696f6e900197a4b2a9069a0100a0019cdf03&weixinnum=2909765272&authkey=700800100918602260b996bf284cb359495885b1480d4065832650ca9911785379ca2fe340691640e9e97f18aa5e0df436f97b866f7364f9ea4b81497eca584fedd26dca5fb1afdbcf42508abe97ef4529ec213ade2dac789a350500807294c0c941157438264a30c7&filename=data_0.json
String result = getDecryptExportData("DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt", "https://szfront.wxwork.qq.com:443/downloadobject?fileid=080112043133303122093131343535363239362a0131322464333430383931612d386139312d346262652d616231302d62353464653065383035316138a03b42149c55bf3c6169f900ae391370dd348245dd7308a548015802600768b8177207333030303030308a010b6170706c69636174696f6e900197a4b2a9069a0100a0019cdf03&weixinnum=2909765272&authkey=700800100918602260b996bf284cb359495885b1480d4065832650ca9911785379ca2fe340691640e9e97f18aa5e0df436f97b866f7364f9ea4b81497eca584fedd26dca5fb1afdbcf42508abe97ef4529ec213ade2dac789a350500807294c0c941157438264a30c7&filename=data_0.json");
JSONArray department = JSONObject.parseObject(result).getJSONArray("userlist");
//转换员工用户
List<Staff> staffList = new ArrayList<>();
List<SysUser> sysUserList = new ArrayList<>();
List<ExportUser> exportUsers = department.toJavaList(ExportUser.class);
//获取当前创建人员信息
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
Map<Integer, Staff> userMapStaff = new HashMap<>();
AtomicReference<Integer> flag = new AtomicReference<>(0);
exportUsers.forEach(item -> {
//创建用户
SysUser sysUser = new SysUser();
//TODO:获取初始化密码
sysUser.setId(IdUtils.fastSimpleUUID());
sysUser.setPassword("$2a$10$6CA0M3iyO8u8zSVtmufYGO3KfLvjaE5fxdHCqTQ2NpxYH/Dxi/fBu")
.setNickName(item.getAlias())
.setStatus(item.getStatus())
.setUserType(UserType.OAM_USER);
sysUser.setCreateUserId(loginUser == null ? "1" : loginUser.getUserId());
sysUser.setUpdateUserId(loginUser == null ? "1" : loginUser.getUserId());
sysUserList.add(sysUser);
//转换员工
Staff staff = BeanUtils.mapToClass(item, Staff.class);
staff.setName(item.getName())
//默认售后人员由管理人员修改
.setStaffType(1)
//设置角色信息
//.setRoleId()
.setWxCpUserId(item.getWxCpUserId());
//放入一个map集合中
userMapStaff.put(flag.get(), staff);
flag.getAndSet(flag.get() + 1);
});
Db.executeBatch(sysUserList, CoreMapper.class, CoreMapper::insertSysUser);
for (int i = 0; i < sysUserList.size(); i++) {
SysUser sysUser = sysUserList.get(i);
Staff staff = userMapStaff.get(i);
staff.setUserId(sysUser.getId());
staffList.add(staff);
}
SpringUtils.getBean(StaffService.class).saveBatch(staffList);
//导入用户信息分组
Map<String, ExportUser> exportUserMap = exportUsers.stream().collect(Collectors.toMap(ExportUser::getWxCpUserId, item -> item));
//获取所有部门信息
Map<Long, Dept> deptMap = SpringUtils.getBean(DeptService.class).list().stream().collect(Collectors.toMap(Dept::getWxCpId, item -> item));
List<StaffMidDept> staffMidDeptList = new ArrayList<>();
//设置中间部门表信息
staffList.forEach(item->{
ExportUser exportUser = exportUserMap.get(item.getWxCpUserId());
exportUser.getDepartment().forEach(innerItem->{
StaffMidDept staffMidDept = new StaffMidDept();
staffMidDept.setDeptId(deptMap.get(innerItem).getId());
staffMidDept.setStaffId(item.getId());
staffMidDeptList.add(staffMidDept);
});
});
SpringUtils.getBean(StaffMidDeptService.class).getMapper().insertBatch(staffMidDeptList);
}
/**
* 导入用户
*/
@Data
public class ExportUser {
/**
* 成员名称
*/
private String name;
/**
* 别名
*/
private String alias;
/**
* 座机
*/
private String telephone;
/**
* 职位名称
*/
private String position;
/**
* 成员所属部门id列表
*/
private List<Long> department;
/**
* 表示在所在的部门内是否为部门负责人
*/
@JSONField(name = "is_leader_in_dept")
private List<Long> isLeaderInDept;
/**
* 企业微信用户id
*/
@JSONField(name = "userid")
private String wxCpUserId;
/**
* 是否启用
*/
private Boolean status;
/**
* 部门排序
*/
private List<Long> order;
}
}

View File

@ -35,13 +35,13 @@ public class DeptBo implements Serializable {
/**
* 部门名称
*/
@ApiModelProperty("部门名称")
@ApiModelProperty(value = "部门名称",required = true)
private String name;
/**
* 排序
*/
@ApiModelProperty("排序")
@ApiModelProperty(value = "排序",required = true)
private Integer orderNo;
/**
@ -65,7 +65,7 @@ public class DeptBo implements Serializable {
/**
* 部门状态:1正常,0停用
*/
@ApiModelProperty("部门状态:1正常,0停用")
@ApiModelProperty(value = "部门状态:1正常,0停用",required = true)
private Boolean status;
/**

View File

@ -1,5 +1,6 @@
package com.cpop.oam.business.bo;
import com.cpop.core.annontation.StringArrayConvert;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -38,6 +39,7 @@ public class StaffBo implements Serializable {
/**
* 部门id
*/
@StringArrayConvert
@NotBlank(message = "部门不能为空")
@ApiModelProperty(value = "部门id",required = true)
private String deptId;

View File

@ -3,6 +3,7 @@ package com.cpop.oam.business.controller;
import com.cpop.core.annontation.OperationLog;
import com.cpop.core.base.R;
import com.cpop.core.base.enums.OperationLogEnum;
import com.cpop.oam.business.bo.MenuListBo;
import com.cpop.oam.business.bo.RoleBo;
import com.cpop.oam.business.bo.RolePageBo;
import com.cpop.oam.business.bo.RoleStatusBo;
@ -77,7 +78,7 @@ public class RoleController {
@ApiOperation("获取菜单树列表")
@GetMapping("/getFilterAuthMenuTreeList")
public R<List<MenuVo>> getFilterAuthMenuTreeList() {
List<MenuVo> list = menuService.getFilterAuthMenuTreeList();
List<MenuVo> list = menuService.getOamMenuTreeList(new MenuListBo());
//过滤掉没有权限的数据
return R.ok(list);
}

View File

@ -0,0 +1,78 @@
package com.cpop.oam.business.controller;
import com.cpop.common.utils.StringUtils;
import com.cpop.oam.framework.config.wxCp.WxCpConfiguration;
import com.cpop.sdk.framework.utils.JsonUtils;
import io.swagger.annotations.Api;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
/**
* @author DB
* @createTime 2023/10/12 15:17
* @description 企业微信认证回调接口
*/
@Api(tags = "企业微信消息接收controller")
@RestController
@RequestMapping("/wxCp/portal/{agentId}")
public class WxCpPortalController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@PathVariable Integer agentId,
@RequestParam(name = "msg_signature", required = false) String signature,
@RequestParam(name = "timestamp", required = false) String timestamp,
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr) {
this.logger.info("\n接收到来自微信服务器的认证消息signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]",
signature, timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
if (wxCpService == null) {
throw new IllegalArgumentException(String.format("未找到对应agentId=[%d]的配置,请核实!", agentId));
}
if (wxCpService.checkSignature(signature, timestamp, nonce, echostr)) {
return new WxCpCryptUtil(wxCpService.getWxCpConfigStorage()).decrypt(echostr);
}
return "非法请求";
}
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@PathVariable Integer agentId,
@RequestBody String requestBody,
@RequestParam("msg_signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce) {
this.logger.info("\n接收微信请求[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
signature, timestamp, nonce, requestBody);
final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
timestamp, nonce, signature);
this.logger.debug("\n消息解密后内容为\n{} ", JsonUtils.toJson(inMessage));
WxCpXmlOutMessage outMessage = this.route(agentId, inMessage);
if (outMessage == null) {
return "";
}
String out = outMessage.toEncryptedXml(wxCpService.getWxCpConfigStorage());
this.logger.debug("\n组装回复信息{}", out);
return out;
}
private WxCpXmlOutMessage route(Integer agentId, WxCpXmlMessage message) {
try {
return WxCpConfiguration.getRouters().get(agentId).route(message);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}
return null;
}
}

View File

@ -37,6 +37,16 @@ public class Dept extends BaseEntity implements Serializable {
*/
private String parentId;
/**
* 企微id
*/
private Long wxCpId;
/**
* 企微父id
*/
private Long wxCpParentId;
/**
* 部门名称
*/

View File

@ -37,11 +37,6 @@ public class Staff extends BaseEntity implements Serializable {
*/
private String name;
/**
* 部门id
*/
private String deptId;
/**
* 用户id
*/
@ -57,6 +52,11 @@ public class Staff extends BaseEntity implements Serializable {
*/
private String roleId;
/**
* 企微用户id
*/
private String wxCpUserId;
/**
* 逻辑删除(0否1是)
*/

View File

@ -0,0 +1,37 @@
package com.cpop.oam.business.entity;
import com.cpop.core.base.entity.BaseEntity;
import com.cpop.core.base.entity.BaseInsertListener;
import com.cpop.core.base.entity.BaseUpdateListener;
import com.mybatisflex.annotation.Table;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* Oam-员工-用户中间表 实体类
*
* @author DB
* @since 2023-10-13
*/
@Data
@EqualsAndHashCode(callSuper=false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_oam_staff_mid_dept", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class StaffMidDept extends BaseEntity implements Serializable {
/**
* 员工id
*/
private String staffId;
/**
* 部门id
*/
private String deptId;
}

View File

@ -0,0 +1,14 @@
package com.cpop.oam.business.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cpop.oam.business.entity.StaffMidDept;
/**
* Oam-员工-用户中间表 映射层
*
* @author DB
* @since 2023-10-13
*/
public interface StaffMidDeptMapper extends BaseMapper<StaffMidDept> {
}

View File

@ -67,12 +67,4 @@ public interface MenuService extends IService<Menu> {
*/
List<MenuRouteVo> getOamMenuList();
/**
* @Description: 获取菜单树列表
* @param
* @return List<MenuVo>
* @Author DB
* @Date: 2023/10/11 19:47
*/
List<MenuVo> getFilterAuthMenuTreeList();
}

View File

@ -0,0 +1,14 @@
package com.cpop.oam.business.service;
import com.mybatisflex.core.service.IService;
import com.cpop.oam.business.entity.StaffMidDept;
/**
* Oam-员工-用户中间表 服务层
*
* @author DB
* @since 2023-10-13
*/
public interface StaffMidDeptService extends IService<StaffMidDept> {
}

View File

@ -11,6 +11,8 @@ import com.cpop.oam.business.vo.StaffInfoVo;
import com.cpop.oam.business.vo.StaffPageVo;
import com.cpop.oam.business.vo.StaffVo;
import com.cpop.oam.business.vo.SysOperationLogVo;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import java.util.List;
@ -108,4 +110,13 @@ public interface StaffService extends IService<Staff> {
* @Date: 2023/5/11 17:50
**/
List<StaffVo> getTechnologyStaffList();
/**
* @descriptions 创建企业微信用户
* @author DB
* @date 2023/10/13 14:31
* @param wxMessage 企业微信用户信息
* @return: void
*/
void createWxCpUser(WxCpXmlMessage wxMessage, WxCpService cpService);
}

View File

@ -232,13 +232,6 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements Me
}
}
@Override
public List<MenuVo> getFilterAuthMenuTreeList() {
return buildMenuTree(this.listAs(QueryWrapper.create()
.and(MENU.TYPE.eq(0).or(MENU.TYPE.ne(0).and(MENU.PERMISSION.isNotNull().or(MENU.PERMISSION.eq("")))))
.orderBy(MENU.ORDER_NO.asc()), MenuVo.class));
}
/**
* @Description: 构建菜单路由树
* @param menus 菜单集合

View File

@ -0,0 +1,18 @@
package com.cpop.oam.business.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.cpop.oam.business.entity.StaffMidDept;
import com.cpop.oam.business.mapper.StaffMidDeptMapper;
import com.cpop.oam.business.service.StaffMidDeptService;
import org.springframework.stereotype.Service;
/**
* Oam-员工-用户中间表 服务层实现
*
* @author DB
* @since 2023-10-13
*/
@Service("staffMidDeptService")
public class StaffMidDeptServiceImpl extends ServiceImpl<StaffMidDeptMapper, StaffMidDept> implements StaffMidDeptService {
}

View File

@ -1,11 +1,6 @@
package com.cpop.oam.business.service.impl;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
@ -31,6 +26,15 @@ import com.cpop.oam.business.vo.StaffInfoVo;
import com.cpop.oam.business.vo.StaffPageVo;
import com.cpop.oam.business.vo.StaffVo;
import com.cpop.oam.business.vo.SysOperationLogVo;
import com.cpop.oam.framework.utils.OamUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -42,7 +46,10 @@ import java.util.List;
import static com.cpop.core.base.table.table.SysOperationLogTableDef.SYS_OPERATION_LOG;
import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
import static com.cpop.oam.business.entity.table.RoleTableDef.ROLE;
import static com.cpop.oam.business.entity.table.StaffMidDeptTableDef.STAFF_MID_DEPT;
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;
import static com.mybatisflex.core.query.QueryMethods.distinct;
import static com.mybatisflex.core.query.QueryMethods.groupConcat;
/**
* 员工表 服务层实现
@ -65,18 +72,25 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
return this.mapper.paginateAs(pageDomain.getPageNum(), pageDomain.getPageSize()
, QueryWrapper.create()
.select(STAFF.ALL_COLUMNS)
.select(SYS_USER.ALL_COLUMNS,SYS_USER.ID.as("user_id"))
.select(ROLE.ROLE_NAME,ROLE.ID.as("roleId"))
//去重
.select(distinct(STAFF.ALL_COLUMNS))
.select(SYS_USER.USER_NAME,SYS_USER.NICK_NAME, SYS_USER.EMAIL, SYS_USER.PHONE_NUMBER, SYS_USER.SEX, SYS_USER.AVATAR, SYS_USER.STATUS, SYS_USER.PASSWORD)
.select(ROLE.ROLE_NAME)
//将部门id分组
.select(groupConcat(STAFF_MID_DEPT.DEPT_ID).as(StaffPageVo::getDeptId))
.from(STAFF)
.leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
.leftJoin(ROLE).on(ROLE.ID.eq(STAFF.ROLE_ID))
//左联中间表
.leftJoin(STAFF_MID_DEPT).on(STAFF_MID_DEPT.STAFF_ID.eq(STAFF.ID))
//姓名
.and(STAFF.NAME.like(bo.getName()))
//员工类型
.and(STAFF.STAFF_TYPE.eq(bo.getStaffType()))
//部门id
.and(STAFF.DEPT_ID.eq(bo.getDeptId()))
.and(SYS_USER.USER_NAME.ne(Constants.SUPER_ADMIN))
.and(STAFF_MID_DEPT.DEPT_ID.eq(bo.getDeptId()))
.and(SYS_USER.USER_NAME.ne(Constants.SUPER_ADMIN).or(SYS_USER.USER_NAME.isNull()))
.groupBy(STAFF.ID)
, StaffPageVo.class);
}
@ -174,8 +188,9 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
this.updateById(sysStaff);
//获取缓存信息
RedisService redisService = SpringUtils.getBean(RedisService.class);
LoginUser loginUser = redisService.getCacheObject(UserType.OAM_USER.getKey() + bo.getUserName());
if (null != loginUser) {
JSONObject jsonObject = redisService.getCacheObject(UserType.OAM_USER.getKey() + bo.getUserName());
if (jsonObject != null) {
LoginUser loginUser = jsonObject.getObject("user", LoginUser.class);
OamStaffLoginInfo staffLoginInfo = BeanUtils.mapToClass(bo, OamStaffLoginInfo.class);
loginUser.setUser(staffLoginInfo);
redisService.setCacheObject(UserType.OAM_USER.getKey() + loginUser.getUsername(), loginUser);
@ -264,7 +279,7 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
.and(SYS_OPERATION_LOG.CREATE_TIME.le(LocalDateTime.parse(split[1], df)));
}
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
Page<Row> page = Db.paginate("pp_sys_operation_log", pageDomain.getPageNum(), pageDomain.getPageSize(), queryWrapper);
Page<Row> page = Db.paginate("cp_sys_operation_log", pageDomain.getPageNum(), pageDomain.getPageSize(), queryWrapper);
return page.map(row -> row.toEntity(SysOperationLogVo.class));
}
@ -277,13 +292,19 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
**/
@Override
public void modifyUserPassword(ModifyUserPasswordBo bo) {
//先用rsa解密
RsaUtils rsaUtils = SpringUtils.getBean(RsaUtils.class);
String oldPassword = rsaUtils.decrypt(bo.getOldPassword());
//只允许超级管理员或自己修改面膜
OamStaffLoginInfo loginStaffInfo = SpringUtils.getBean(OamUtils.class).getLoginStaffInfo();
String userName = loginStaffInfo.getUserName();
//同数据库密码进行比较
SysUser user = DbChain.table(SYS_USER)
.where(SYS_USER.ID.eq(bo.getUserId()))
.oneAs(SysUser.class);
if (!StringUtils.equals(userName, Constants.SUPER_ADMIN) || !StringUtils.equals(userName, user.getUserName())) {
throw new ServiceException("非超级管理员不允许修改他人密码");
}
//先用rsa解密
RsaUtils rsaUtils = SpringUtils.getBean(RsaUtils.class);
String oldPassword = rsaUtils.decrypt(bo.getOldPassword());
if (BCrypt.checkpw(oldPassword, user.getPassword())) {
//存入系统
DbChain.table(SYS_USER)
@ -304,7 +325,7 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
@Override
public List<StaffVo> getServiceStaffList() {
return SpringUtils.getBean(StaffService.class).listAs(QueryWrapper.create()
.select(STAFF.ID, STAFF.NAME, STAFF.DEPT_ID, STAFF.USER_ID, STAFF.STAFF_TYPE)
.select(STAFF.ID, STAFF.NAME, STAFF.USER_ID, STAFF.STAFF_TYPE)
.from(STAFF)
.leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
.where(STAFF.STAFF_TYPE.eq(1))
@ -322,7 +343,7 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
@Override
public List<StaffVo> getTechnologyStaffList() {
return this.listAs(QueryWrapper.create()
.select(STAFF.ID, STAFF.NAME, STAFF.DEPT_ID, STAFF.USER_ID, STAFF.STAFF_TYPE)
.select(STAFF.ID, STAFF.NAME, STAFF.USER_ID, STAFF.STAFF_TYPE)
.from(STAFF)
.leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
.where(STAFF.STAFF_TYPE.eq(0))
@ -330,4 +351,17 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
.and(SYS_USER.STATUS.eq(true)),
StaffVo.class);
}
/**
* @descriptions 创建企业微信用户
* @author DB
* @date 2023/10/13 14:31
* @param wxMessage 企业微信用户信息
* @return: void
*/
@Override
public void createWxCpUser(WxCpXmlMessage wxMessage, WxCpService cpService) {
//TODO:先改造部门
//insertStaff(wxCpUserToStaff(wxMessage, cpService));
}
}

View File

@ -1,5 +1,6 @@
package com.cpop.oam.business.vo;
import com.cpop.core.annontation.StringArrayConvert;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -43,6 +44,7 @@ public class StaffPageVo implements Serializable {
/**
* 部门id
*/
@StringArrayConvert
@ApiModelProperty("部门id")
private String deptId;

View File

@ -1,6 +1,8 @@
package com.cpop.sdk.framework.config.wxCp;
package com.cpop.oam.framework.config.wxCp;
import com.cpop.sdk.framework.config.wxCp.WxCpProperties;
import com.cpop.sdk.framework.handler.wxCp.*;
import com.cpop.oam.framework.handler.wxCp.ContactChangeHandler;
import com.google.common.collect.Maps;
import lombok.val;
import me.chanjar.weixin.common.api.WxConsts;
@ -26,16 +28,16 @@ import java.util.stream.Collectors;
@EnableConfigurationProperties(WxCpProperties.class)
public class WxCpConfiguration {
private LogHandler logHandler;
private NullHandler nullHandler;
private LocationHandler locationHandler;
private MenuHandler menuHandler;
private MsgHandler msgHandler;
private UnsubscribeHandler unsubscribeHandler;
private SubscribeHandler subscribeHandler;
private WxCpProperties properties;
private final LogHandler logHandler;
private final NullHandler nullHandler;
private final LocationHandler locationHandler;
private final MenuHandler menuHandler;
private final MsgHandler msgHandler;
private final UnsubscribeHandler unsubscribeHandler;
private final SubscribeHandler subscribeHandler;
private final WxCpProperties properties;
private static Map<Integer, WxCpMessageRouter> routers = Maps.newHashMap();
private static final Map<Integer, WxCpMessageRouter> routers = Maps.newHashMap();
private static Map<Integer, WxCpService> cpServices = Maps.newHashMap();
@Autowired
@ -61,6 +63,12 @@ public class WxCpConfiguration {
return cpServices.get(agentId);
}
/**
* @descriptions 初始化服务
* @author DB
* @date 2023/10/13 14:08
* @return: void
*/
@PostConstruct
public void initServices() {
cpServices = this.properties.getAppConfigs().stream().map(a -> {
@ -83,7 +91,11 @@ public class WxCpConfiguration {
// 记录所有事件的日志异步执行
newRouter.rule().handler(this.logHandler).next();
// 自定义菜单事件
//通讯录变更
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxCpConsts.EventType.CHANGE_CONTACT).handler(new ContactChangeHandler()).end();
/*// 自定义菜单事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.MenuButtonType.CLICK).handler(this.menuHandler).end();
@ -114,11 +126,9 @@ public class WxCpConfiguration {
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.EventType.SCAN).handler(this.nullHandler).end();
//进入应用
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxCpConsts.EventType.CHANGE_CONTACT).handler(new ContactChangeHandler()).end();
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxCpConsts.EventType.ENTER_AGENT).handler(new EnterAgentHandler()).end();
.event(WxCpConsts.EventType.ENTER_AGENT).handler(new EnterAgentHandler()).end();*/
// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();

View File

@ -0,0 +1,38 @@
package com.cpop.oam.framework.constant;
/**
* 企业微信通知类型实体类
* @author DB
*/
public interface WxCpNoticeType {
/**
* 创建用户
*/
String CREATE_USER = "create_user";
/**
* 更新用户
*/
String UPDATE_USER = "update_user";
/**
* 删除用户
*/
String DELETE_USER = "delete_user";
/**
* 创建部门
*/
String CREATE_DEPT = "create_party";
/**
* 更新部门
*/
String UPDATE_DEPT = "update_party";
/**
* 删除部门
*/
String DELETE_DEPT = "delete_party";
}

View File

@ -0,0 +1,52 @@
package com.cpop.oam.framework.handler.wxCp;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.framework.constant.WxCpNoticeType;
import com.cpop.sdk.framework.builder.wxCp.TextBuilder;
import com.cpop.sdk.framework.handler.wxCp.AbstractHandler;
import com.cpop.sdk.framework.utils.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 通讯录变更事件处理器.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Component
public class ContactChangeHandler extends AbstractHandler {
@Autowired
private StaffService staffService;
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService, WxSessionManager sessionManager) {
String content = "收到通讯录变更事件,内容:" + JsonUtils.toJson(wxMessage);
this.logger.info(content);
//通知处理
switch (wxMessage.getChangeType()){
case WxCpNoticeType.CREATE_USER:
staffService.createWxCpUser(wxMessage, cpService);
break;
case WxCpNoticeType.UPDATE_USER:
break;
case WxCpNoticeType.DELETE_USER:
break;
case WxCpNoticeType.CREATE_DEPT:
break;
case WxCpNoticeType.UPDATE_DEPT:
break;
case WxCpNoticeType.DELETE_DEPT:
break;
default:
}
return new TextBuilder().build(content, wxMessage, cpService);
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cpop.oam.business.mapper.StaffMidDeptMapper">
</mapper>

View File

@ -1,30 +0,0 @@
package com.cpop.sdk.framework.handler.wxCp;
import com.cpop.sdk.framework.builder.wxCp.TextBuilder;
import com.cpop.sdk.framework.utils.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 通讯录变更事件处理器.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Component
public class ContactChangeHandler extends AbstractHandler {
@Override
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
WxSessionManager sessionManager) {
String content = "收到通讯录变更事件,内容:" + JsonUtils.toJson(wxMessage);
this.logger.info(content);
return new TextBuilder().build(content, wxMessage, cpService);
}
}

View File

@ -32,8 +32,13 @@ wx:
cp:
corpId: ww9b83a363662f219f
appConfigs:
#通讯录
- agentId: 1000001
secret:
token:
aesKey:
#通讯录同步
- agentId: 1000000
secret: YAvZS9i2Ccc3_arbH-qi3zTEDJfmEt_2L-k2LG_TTEw
token: xKOLVqjOUklbQ
aesKey: A71T8zPqzb5B2uPesyfRyuTEFpDjhinIRdHg65NuUFj
#Oam-企业微信互通应用
- agentId: 1000024
secret: VJFNBvZgK6oNEKpfrb5B9KQcm7yB0CacpWS2BfTln5Q
token: 1i2dz2yxD0Np2xvMYTD
aesKey: DLSzfHVUZN3O9WhtL07RBXUoooqC2bjEJYwep8k8ojt