Merge remote-tracking branch 'origin/master'

# Conflicts:
#	dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/controller/UserLoginController.java
#	dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/service/UserLoginService.java
#	dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/service/impl/UserLoginServiceImpl.java
#	dq-financial-hrms/src/main/java/com/daqing/financial/hrms/controller/EmployeeController.java
master
shijie 4 years ago
commit e306d6eb3a
  1. 58
      dq-financial-api/src/main/java/com/daqing/financial/crms/CustomerWorkbenchControllerApi.java
  2. 4
      dq-financial-api/src/main/java/com/daqing/financial/hrms/UserControllerApi.java
  3. 126
      dq-financial-crms/src/main/java/com/daqing/financial/crms/controller/CustomerWorkbenchController.java
  4. 2
      dq-financial-crms/src/main/java/com/daqing/financial/crms/dao/CustomerWorkbenchDao.java
  5. 4
      dq-financial-crms/src/main/java/com/daqing/financial/crms/feign/HrmsFeignService.java
  6. 26
      dq-financial-crms/src/main/java/com/daqing/financial/crms/service/CustomerWorkbenchService.java
  7. 5
      dq-financial-crms/src/main/java/com/daqing/financial/crms/service/impl/CustomerServiceImpl.java
  8. 137
      dq-financial-crms/src/main/java/com/daqing/financial/crms/service/impl/CustomerWorkbenchServiceImpl.java
  9. 4
      dq-financial-crms/src/main/resources/mapper/crms/CustomerWorkbenchDao.xml
  10. 6
      dq-financial-hrms-auth/pom.xml
  11. 14
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/config/WeChatConfig.java
  12. 12
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/controller/UserLoginController.java
  13. 8
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/feign/HrmsFeignService.java
  14. 3
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/service/UserLoginService.java
  15. 2
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/service/UserService.java
  16. 16
      dq-financial-hrms-auth/src/main/java/com/daqing/financial/hrauth/service/impl/UserLoginServiceImpl.java
  17. 2
      dq-financial-hrms-auth/src/main/resources/mapper/hrauth/RolePermissionMapper.xml
  18. 10
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/controller/DeptController.java
  19. 1
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/controller/EmployeeController.java
  20. 16
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/controller/UserController.java
  21. 2
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/dao/DeptDao.java
  22. 2
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/dao/UserDao.java
  23. 6
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/feign/HrmsAuthFeignService.java
  24. 4
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/service/DeptService.java
  25. 3
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/service/UserService.java
  26. 14
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/service/impl/DeptServiceImpl.java
  27. 81
      dq-financial-hrms/src/main/java/com/daqing/financial/hrms/service/impl/UserServiceImpl.java
  28. 78
      dq-financial-hrms/src/main/resources/bootstrap.properties
  29. 18
      dq-financial-hrms/src/main/resources/mapper/hrms/DeptDao.xml
  30. 4
      dq-financial-hrms/src/main/resources/mapper/hrms/UserDao.xml
  31. 107
      dq-framework-common/src/main/java/com/daqing/framework/util/HttpUtils.java
  32. 2
      dq-framework-model/src/main/java/com/daqing/framework/domain/crms/response/CustomerWorkbenchListVO.java
  33. 1
      dq-govern-gateway/src/main/resources/jwt.properties
  34. 2
      pom.xml

@ -1,5 +1,9 @@
package com.daqing.financial.crms;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOI;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOU;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOI;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOU;
import com.daqing.framework.domain.crms.request.CustomerWorkbenchRequest;
import com.daqing.framework.domain.crms.response.CustomerWorkbenchListVO;
import com.daqing.framework.model.response.ResponseResult;
@ -20,4 +24,58 @@ public interface CustomerWorkbenchControllerApi {
*/
@ApiOperation(value = "客户信息列表展示", notes = "客户信息列表展示",response = CustomerWorkbenchListVO.class)
ResponseResult List(Integer page, Integer size, CustomerWorkbenchRequest customerWorkbenchRequest);
/**
* 详情
*/
@ApiOperation(value = "详情",notes = "详情")
ResponseResult info(Long id);
/**
* 删除
*/
@ApiOperation(value = "删除",notes = "删除")
ResponseResult delete(Long[] ids);
/**
* 新增个人
*/
@ApiOperation(value = "新增个人类型客户信息", notes = "新增个人类型客户信息")
ResponseResult savePersonal(CustomerPersonalTOI customerPersonalTOI);
/**
* 新增企业
*/
@ApiOperation(value = "新增企业类型客户信息", notes = "新增企业类型客户信息")
ResponseResult saveCompany(CustomerCompanyTOI customerCompanyTOI);
/**
* 更新个人类型客户信息
*/
@ApiOperation(value = "更新个人类型客户信息", notes = "更新个人类型客户信息")
ResponseResult updatePersonal(CustomerPersonalTOU customerPersonalTOU);
/**
* 更新企业类型客户信息
*/
@ApiOperation(value = "更新企业类型客户信息", notes = "更新企业类型客户信息")
ResponseResult updateCompany(CustomerCompanyTOU customerCompanyTOU);
/**
* 通过审核
*/
@ApiOperation(value = "通过审核", notes = "通过审核")
ResponseResult pass(Long id,Long manager);
/**
* 不通过
*/
@ApiOperation(value = "不通过",notes = "不通过")
ResponseResult noPass(Long id,String cause);
/**
* 获取当前客户部门经理的部门下所有客户经理
*/
@ApiOperation(value = "获取当前客户部门经理的部门下所有客户经理",notes = "获取当前客户部门经理的部门下所有客户经理")
ResponseResult getCustomerManager();
}

@ -4,6 +4,9 @@ import com.daqing.framework.domain.hrms.ext.EmployeeAndUserVO;
import com.daqing.framework.model.response.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.http.HttpResponse;
import javax.servlet.http.HttpServletResponse;
/**
* @auther River
@ -26,4 +29,5 @@ public interface UserControllerApi {
@ApiOperation(value = "绑定手机号",notes = "绑定手机号")
ResponseResult binding(Long id,String phone,String code);
}

@ -2,14 +2,21 @@ package com.daqing.financial.crms.controller;
import com.daqing.financial.crms.CustomerWorkbenchControllerApi;
import com.daqing.financial.crms.service.CustomerWorkbenchService;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOI;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOU;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOI;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOU;
import com.daqing.framework.domain.crms.request.CustomerWorkbenchRequest;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.model.response.CommonCode;
import com.daqing.framework.model.response.PromptSuccess;
import com.daqing.framework.model.response.ResponseResult;
import com.daqing.framework.utils.PageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
/**
* 工作台客户资源系统
@ -35,4 +42,115 @@ public class CustomerWorkbenchController implements CustomerWorkbenchControllerA
return new ResponseResult<PageUtils>().SUCCESS(list);
}
/**
* 详情
*/
@GetMapping("/info")
@Override
public ResponseResult info(@RequestParam("id") Long id) {
return customerWorkbenchService.info(id);
}
/**
* 删除
*/
@Override
@PostMapping("/delete")
public ResponseResult delete(@RequestBody Long[] ids) {
List<String> list = customerWorkbenchService.delete(ids);
if (list == null){
return new ResponseResult(CommonCode.INVALID_PARAM);
}else if (Objects.equals(list.get(0), PromptSuccess.DELETE_SUCCESS)){
return ResponseResult.SUCCESS();
}else if (Objects.equals(list.get(0),PromptSuccess.DELETE_FAIL)){
return new ResponseResult(CommonCode.DELETE_FAIL);
}
else {
return new ResponseResult<List<String>>().SUCCESS_DATA(list);
}
}
/**
* 新增个人
*/
@PostMapping("/savePersonal")
@Override
public ResponseResult savePersonal(@RequestBody CustomerPersonalTOI customerPersonalTOI) {
boolean result = customerWorkbenchService.savePersonal(customerPersonalTOI);
return result ? ResponseResult.SUCCESS() : new ResponseResult(CommonCode.SAVE_FAIL);
}
/**
* 新增企业
*/
@PostMapping("/saveCompany")
@Override
public ResponseResult saveCompany(@RequestBody CustomerCompanyTOI customerCompanyTOI) {
boolean result = customerWorkbenchService.saveCompany(customerCompanyTOI);
return result ? ResponseResult.SUCCESS() : new ResponseResult(CommonCode.SAVE_FAIL);
}
/**
* 修改个人
*/
@PostMapping("/updatePersonal")
@Override
public ResponseResult updatePersonal(@RequestBody CustomerPersonalTOU customerPersonalTOU) {
Boolean result = customerWorkbenchService.updatePersonal(customerPersonalTOU);
return result ? ResponseResult.SUCCESS() : new ResponseResult(CommonCode.UPDATE_FAIL);
}
/**
* 修改企业
*/
@PostMapping("/updateCompany")
@Override
public ResponseResult updateCompany(@RequestBody CustomerCompanyTOU customerCompanyTOU) {
Boolean result = customerWorkbenchService.updateCompany(customerCompanyTOU);
return result ? ResponseResult.SUCCESS() : new ResponseResult(CommonCode.UPDATE_FAIL);
}
/**
* 通过审核
*/
@GetMapping("/pass")
@Override
public ResponseResult pass(@RequestParam("id") Long id, @RequestParam("manager") Long manager) {
Boolean result = customerWorkbenchService.pass(id, manager);
return result ? ResponseResult.SUCCESS() : ResponseResult.FAIL();
}
/**
* 不通过审核
*/
@GetMapping("/noPass")
@Override
public ResponseResult noPass(@RequestParam("id") Long id, @RequestParam("cause") String cause) {
Boolean result = customerWorkbenchService.noPass(id, cause);
return result ? ResponseResult.SUCCESS() : ResponseResult.FAIL();
}
/**
* 获取当前客户部门经理的部门下所有客户经理
*/
@GetMapping("/manager")
@Override
public ResponseResult getCustomerManager() {
return new ResponseResult<List<EmployeeEntity>>().SUCCESS(customerWorkbenchService.getCustomerManager());
}
}

@ -16,4 +16,6 @@ import org.apache.ibatis.annotations.Param;
public interface CustomerWorkbenchDao extends BaseMapper<CustomerEntity> {
IPage<CustomerEntity> queryList(Page page, @Param("cr")CustomerWorkbenchRequest customerWorkbenchRequest);
Boolean passById(@Param("id")Long id,@Param("manager")Long manager);
}

@ -5,7 +5,6 @@ import com.daqing.framework.domain.hrms.ext.EmployeeTO;
import com.daqing.framework.domain.hrms.ext.EmployeeVO;
import com.daqing.framework.model.response.ResponseResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -28,4 +27,7 @@ public interface HrmsFeignService {
@GetMapping("/hrms/employee/listEmployeeName")
ResponseResult<List<EmployeeVO>> listEmployeeName();
@GetMapping("/hrms/dept/listEmployeeById")
ResponseResult<List<EmployeeEntity>> listEmployeeById(@RequestParam("id") Long id);
}

@ -2,9 +2,17 @@ package com.daqing.financial.crms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.daqing.framework.domain.crms.CustomerEntity;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOI;
import com.daqing.framework.domain.crms.ext.CustomerCompanyTOU;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOI;
import com.daqing.framework.domain.crms.ext.CustomerPersonalTOU;
import com.daqing.framework.domain.crms.request.CustomerWorkbenchRequest;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.model.response.ResponseResult;
import com.daqing.framework.utils.PageUtils;
import java.util.List;
/**
* @auther River
@ -13,4 +21,22 @@ import com.daqing.framework.utils.PageUtils;
public interface CustomerWorkbenchService extends IService<CustomerEntity> {
PageUtils list(Integer page, Integer size, CustomerWorkbenchRequest customerWorkbenchRequest);
ResponseResult info(Long id);
List<String> delete(Long[] ids);
Boolean savePersonal(CustomerPersonalTOI customerPersonalTOI);
Boolean saveCompany(CustomerCompanyTOI customerCompanyTOI);
Boolean updatePersonal(CustomerPersonalTOU customerPersonalTOU);
Boolean updateCompany(CustomerCompanyTOU customerCompanyTOU);
Boolean pass(Long id,Long manager);
Boolean noPass(Long id,String cause);
List<EmployeeEntity> getCustomerManager();
}

@ -177,7 +177,7 @@ public class CustomerServiceImpl extends ServiceImpl<CustomerDao, CustomerEntity
}
//TODO 远程调用审批模块判断所选客户是否在审批,返回正在审批的客户的id集合Long[] idArray
List<Long> idArray = new ArrayList<>();// 假设为返回的正在审批的客户id集合
if (idArray.size() == 0 || idArray == null) {
if (idArray == null || idArray.size() == 0) {
boolean customer = customerDao.updateCustomerById(Arrays.asList(ids));
List<String> success = new ArrayList<>();
success.add(PromptSuccess.DELETE_SUCCESS);
@ -206,6 +206,8 @@ public class CustomerServiceImpl extends ServiceImpl<CustomerDao, CustomerEntity
customerEntity.setType(CrmsConstant.CustomerType.PERSONAL_CUSTOMER.getType());
boolean customer = customerDao.saveCustomer(customerEntity);
personalCustomerEntity.setCustomerId(customerEntity.getId());
// 将自增的客户id返回给工作台
customerPersonalTOI.setManager(customerEntity.getId());
boolean personal = personalCustomerDao.savePersonalCustomer(personalCustomerEntity);
return customer && personal;
}
@ -227,6 +229,7 @@ public class CustomerServiceImpl extends ServiceImpl<CustomerDao, CustomerEntity
customerEntity.setType(CrmsConstant.CustomerType.COMPANY_CUSTOMER.getType());
boolean customer = customerDao.saveCustomer(customerEntity);
companyCustomerEntity.setCustomerId(customerEntity.getId());
customerCompanyTOI.setManager(customerEntity.getId());
boolean company = companyCustomerDao.saveCompanyCustomer(companyCustomerEntity);
return customer && company;
}

@ -5,17 +5,23 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.daqing.financial.crms.dao.CustomerWorkbenchDao;
import com.daqing.financial.crms.feign.HrmsFeignService;
import com.daqing.financial.crms.service.CustomerService;
import com.daqing.financial.crms.service.CustomerWorkbenchService;
import com.daqing.framework.domain.crms.CustomerEntity;
import com.daqing.framework.domain.crms.ext.CustomerTO;
import com.daqing.framework.domain.crms.ext.*;
import com.daqing.framework.domain.crms.request.CustomerWorkbenchRequest;
import com.daqing.framework.domain.crms.response.CustomerWorkbenchListVO;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.domain.hrms.ext.EmployeeTO;
import com.daqing.framework.exception.ExceptionCast;
import com.daqing.framework.exception.ExceptionCatch;
import com.daqing.framework.model.response.CommonCode;
import com.daqing.framework.model.response.ResponseResult;
import com.daqing.framework.utils.PageUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.util.*;
@ -28,15 +34,24 @@ import java.util.*;
public class CustomerWorkbenchServiceImpl extends ServiceImpl<CustomerWorkbenchDao, CustomerEntity>
implements CustomerWorkbenchService {
//TODO 从redis获取当前登录用户信息
/*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
String userId = RedisUtil.get("dq:token:"+token);*/
Long userId = Long.parseLong("1");
@Autowired
private HrmsFeignService hrmsFeignService;
@Autowired
private CustomerService customerService;
/**
* 列表
*/
@Override
public PageUtils list(Integer page, Integer size, CustomerWorkbenchRequest cwr) {
// 分页参数
if (page == null || size == null){
page = 1;
size = 10;
@ -65,7 +80,12 @@ public class CustomerWorkbenchServiceImpl extends ServiceImpl<CustomerWorkbenchD
for (CustomerWorkbenchListVO customerWorkbenchListVO : customerWorkbenchListVOS) {
customerWorkbenchListVO.setStatus(2);
}
if (cwr.getStatus() != null && (cwr.getStatus() == 0 || cwr.getStatus() == 1 || cwr.getStatus() == 2)){
// 筛选状态
customerWorkbenchListVOS.removeIf(customerWorkbenchListVO -> !Objects.equals(customerWorkbenchListVO.getStatus(),cwr.getStatus()));
}
}
// 属性拷贝,将泛型为CustomerEntity类型的IPage的属性拷贝给泛型为CustomerTO类型的IPage,才能赋值给PageUtils
IPage<CustomerWorkbenchListVO> iPage = new Page<>();
BeanUtils.copyProperties(customerEntityIPage,iPage);
@ -74,6 +94,119 @@ public class CustomerWorkbenchServiceImpl extends ServiceImpl<CustomerWorkbenchD
return new PageUtils(iPage);
}
/**
* 详情
*/
@Override
public ResponseResult info(Long id) {
return customerService.queryCustomerById(id);
}
/**
* 删除
*/
@Transactional
@Override
public List<String> delete(Long[] ids) {
return customerService.updateCustomerById(ids);
}
/**
* 新增个人
*/
@Transactional
@Override
public Boolean savePersonal(CustomerPersonalTOI customerPersonalTOI) {
customerPersonalTOI.setManager(userId); // 从redis当前登录用户
boolean result = customerService.saveCustomerPersonal(customerPersonalTOI);
// TODO 将当前客户状态和自增的客户id新增到担保表中
// customerId = customerPersonalTOI.getManager();
// status = 2;
// Boolean result = save(customerId,status);
return result;
}
/**
* 新增企业
*/
@Transactional
@Override
public Boolean saveCompany(CustomerCompanyTOI customerCompanyTOI) {
customerCompanyTOI.setManager(userId); // 从redis获取当前登录用户
boolean result = customerService.saveCustomerCompany(customerCompanyTOI);
// TODO 将当前客户状态和自增的客户id新增到担保表中
// customerId = customerPersonalTOI.getManager();
// status = 2;
// Boolean result = save(customerId,status);
return result;
}
/**
* 修改个人
*/
@Transactional
@Override
public Boolean updatePersonal(CustomerPersonalTOU customerPersonalTOU) {
customerPersonalTOU.setManager(userId);
return customerService.updateCustomerPersonal(customerPersonalTOU);
}
/**
* 修改企业
*/
@Transactional
@Override
public Boolean updateCompany(CustomerCompanyTOU customerCompanyTOU) {
customerCompanyTOU.setManager(userId);
return customerService.updateCustomerCompany(customerCompanyTOU);
}
/**
* 通过审核
* @param id 当前客户id
* @param manager 客户经理id
* @return
*/
@Override
public Boolean pass(Long id, Long manager) {
if (id == null || manager == null){
ExceptionCast.cast(CommonCode.INVALID_PARAM);
}
return this.getBaseMapper().passById(id,manager);
}
/**
* 不通过审核
* @param id 当前客户id
* @param cause 原因
* @return
*/
@Override
public Boolean noPass(Long id, String cause) {
// TODO 将当前客户id、不通过原因、客户状态status = 1(不通过)更新到担保业务的表中
return null;
}
/**
* 获取当前客户部门经理的部门下所有客户经理
*/
@Override
public List<EmployeeEntity> getCustomerManager() {
ResponseResult<List<EmployeeEntity>> employees = hrmsFeignService.listEmployeeById(userId);
return employees.getData();
}
/**
* 选择某段时间内客户信息的时间参数校验
*/

@ -40,4 +40,8 @@
ORDER BY create_time DESC
</select>
<update id="passById">
UPDATE hrms_customer SET manager = #{manager} WHERE id = #{id}
</update>
</mapper>

@ -66,6 +66,12 @@
<artifactId>dq-financial-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>

@ -1,17 +1,23 @@
package com.daqing.financial.hrauth.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import java.io.Serializable;
/**
* 微信配置类
*/
@Configuration
@Data
public class WeChatConfig {
@NoArgsConstructor
@AllArgsConstructor
public class WeChatConfig implements Serializable {
/**
* 开放平台appid
@ -31,6 +37,12 @@ public class WeChatConfig {
@Value("${wxopen.redirect_url}")
private String openRedirectUrl;
/**
* 绑定微信回调url
*/
@Value("${wxopen.wechat_binding_redirect_url}")
private String weChatBindingRedirectUrl;
/**
* 微信开放平台二维码连接
*/

@ -34,6 +34,7 @@ public class UserLoginController implements UserLoginControllerApi {
@Autowired
private UserLoginService userLoginService;
@Autowired
private WeChatConfig weChatConfig;
@Autowired
@ -132,7 +133,7 @@ public class UserLoginController implements UserLoginControllerApi {
}
}
/**
/**
* 绑定手机号和openId
* @param bindOpenIdRequest
* @return
@ -154,6 +155,15 @@ public class UserLoginController implements UserLoginControllerApi {
return result ? ResponseResult.SUCCESS("短信发送成功") : ResponseResult.FAIL(55001,"短信发送失败");
}
/**
* 获取WeChatConfig配置类值的接口
*/
@GetMapping("/getWeChatConfig")
public ResponseResult getWeChatConfig(){
return new ResponseResult<WeChatConfig>().SUCCESS(userLoginService.getWeChatConfig());
}
/**
* 判断手机号是否存在
* @param mobile

@ -0,0 +1,8 @@
package com.daqing.financial.hrauth.feign;
/**
* @auther River
* @date 2020/10/22 14:04
*/
public class HrmsFeignService {
}

@ -1,6 +1,7 @@
package com.daqing.financial.hrauth.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.daqing.financial.hrauth.config.WeChatConfig;
import com.daqing.framework.domain.hrms.UserEntity;
import com.daqing.framework.domain.hrms.request.*;
import com.daqing.framework.model.response.ResponseResult;
@ -20,5 +21,7 @@ public interface UserLoginService extends IService<UserEntity> {
boolean bindPhoneAndOpenId(BindOpenIdRequest bindOpenIdRequest);
WeChatConfig getWeChatConfig();
int isPhoneExist(String mobile);
}

@ -10,5 +10,7 @@ import javax.servlet.http.HttpServletResponse;
* @date 2020/9/22 15:00
*/
public interface UserService extends IService<UserEntity> {
UserEntity saveWeChatUser(String code, HttpServletResponse response);
}

@ -2,6 +2,7 @@ package com.daqing.financial.hrauth.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.daqing.financial.hrauth.config.WeChatConfig;
import com.daqing.financial.hrauth.dao.UserLoginDao;
import com.daqing.financial.hrauth.service.LoginLogService;
import com.daqing.financial.hrauth.service.TokenService;
@ -44,6 +45,9 @@ public class UserLoginServiceImpl extends ServiceImpl<UserLoginDao, UserEntity>
@Autowired
private LoginLogService loginLogService;
@Resource
private WeChatConfig weChatConfig;
/* @Autowired
private OdcProperties properties;*/
@ -229,6 +233,18 @@ public class UserLoginServiceImpl extends ServiceImpl<UserLoginDao, UserEntity>
return count>0;
}
/**
* 获取WeChatConfig
*/
@Override
public WeChatConfig getWeChatConfig() {
WeChatConfig weChatConfigResponse = new WeChatConfig();
weChatConfigResponse.setOpenAppid(weChatConfig.getOpenAppid());
weChatConfigResponse.setOpenAppsecret(weChatConfig.getOpenAppsecret());
weChatConfigResponse.setOpenRedirectUrl(weChatConfig.getWeChatBindingRedirectUrl());
return weChatConfigResponse;
}
@Override
public int isPhoneExist(String mobile) {
return userLoginDao.selectCount(mobile);

@ -9,7 +9,7 @@
<result property="permissionId" column="permission_id"/>
</resultMap>
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.daqing.framework.domain.hrms.PermissionEntity" id="permissionMap">
<resultMap type="com.daqing.framework.domain.hrms.PermissionEntity" id="permissionRoleMap">
<result property="id" column="id"/>
<result property="code" column="code"/>
<result property="name" column="name"/>

@ -4,6 +4,7 @@ import com.daqing.financial.hrms.DeptControllerApi;
import com.daqing.financial.hrms.service.DeptService;
import com.daqing.framework.domain.hrms.DepartmentVO;
import com.daqing.framework.domain.hrms.DeptEntity;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.domain.hrms.request.DeptAddRequest;
import com.daqing.framework.model.response.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
@ -114,4 +115,13 @@ public class DeptController implements DeptControllerApi {
public ResponseResult children(Long id){
return new ResponseResult<DepartmentVO>().SUCCESS(deptService.getDepartmentAndEmployee(id));
}
/**
* 根据员工id获取对应部门下所有的客户经理
*/
@GetMapping("/listEmployeeById")
public ResponseResult listEmployeeById(@RequestParam("id") Long id){
return new ResponseResult<List<EmployeeEntity>>().SUCCESS(deptService.listEmployeeById(id));
}
}

@ -1,5 +1,6 @@
package com.daqing.financial.hrms.controller;
import com.daqing.financial.hrms.EmployeeControllerApi;
import com.daqing.financial.hrms.service.EmployeeService;
import com.daqing.framework.domain.crms.request.EmployeeDisableRequest;

@ -7,10 +7,13 @@ import com.daqing.framework.domain.hrms.ext.EmployeeAndUserVO;
import com.daqing.framework.model.response.CommonCode;
import com.daqing.framework.model.response.ResponseResult;
import com.daqing.framework.utils.PageUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
@ -22,6 +25,7 @@ import java.util.Map;
* @email gongsj@gmail.com
* @date 2020-09-07 16:26:04
*/
@Slf4j
@RestController
@RequestMapping("hrms/user")
public class UserController implements UserControllerApi {
@ -80,6 +84,7 @@ public class UserController implements UserControllerApi {
/**
* 绑定手机号
*/
@GetMapping("/binding")
@Override
public ResponseResult binding(@RequestParam("id") Long id, String phone, String code) {
@ -88,6 +93,17 @@ public class UserController implements UserControllerApi {
return result ? ResponseResult.SUCCESS() : ResponseResult.FAIL();
}
/**
* 微信绑定回调
*/
@GetMapping("/weChatCallback")
public ResponseResult weChatCallback(@RequestParam("code") String code, HttpServletResponse response) throws IOException {
userService.weChatCallback(code,response);
return null;
}
/**
* 只有当访问用户具有 ROLE_ADMIN 权限时才能访问否则返回 401 未授权
* 通过 Authentication 参数或者 SecurityContextHolder.getContext().getAuthentication() 可以拿到授权信息进行查看

@ -3,6 +3,7 @@ package com.daqing.financial.hrms.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.daqing.framework.domain.hrms.DepartmentVO;
import com.daqing.framework.domain.hrms.DeptEntity;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -29,4 +30,5 @@ public interface DeptDao extends BaseMapper<DeptEntity> {
List<DepartmentVO> listDepartmentIdAndName();
List<EmployeeEntity> listEmployeeById(Long id);
}

@ -24,4 +24,6 @@ public interface UserDao extends BaseMapper<UserEntity> {
String getPhoneAccount(Long id);
Boolean updatePhoneAccount(@Param("id")Long id,@Param("phoneAccount") String phoneAccount);
Boolean updateWeChat(@Param("id") Long id, @Param("weChatId") String weChatId);
}

@ -1,14 +1,18 @@
package com.daqing.financial.hrms.feign;
import com.alibaba.fastjson.JSONObject;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 声明这是一个远程调用
* @auther River
* @date 2020/10/12 17:58
*/
@FeignClient("dq-financial-hrms-auht")
@FeignClient("dq-financial-hrms-auth")
public interface HrmsAuthFeignService {
@GetMapping("/hrms/auth/userlogin/getWeChatConfig")
JSONObject getWeChatConfig();
}

@ -3,6 +3,7 @@ package com.daqing.financial.hrms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.daqing.framework.domain.hrms.DepartmentVO;
import com.daqing.framework.domain.hrms.DeptEntity;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.domain.hrms.request.DeptAddRequest;
import java.util.List;
@ -27,5 +28,8 @@ public interface DeptService extends IService<DeptEntity> {
/*List<DepartmentVO> listDepartmentAndEmployeeTree();*/
DepartmentVO getDepartmentAndEmployee(Long id);
List<EmployeeEntity> listEmployeeById(Long id);
}

@ -5,6 +5,7 @@ import com.daqing.framework.domain.hrms.ext.EmployeeAndUserVO;
import com.daqing.framework.utils.PageUtils;
import com.daqing.framework.domain.hrms.UserEntity;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@ -26,5 +27,7 @@ public interface UserService extends IService<UserEntity> {
Boolean getVerificationCode(String phone);
Boolean bindingPhoneAccount(Long id,String phone,String code);
Boolean weChatCallback(String code, HttpServletResponse response) throws IOException;
}

@ -7,6 +7,7 @@ import com.daqing.financial.hrms.dao.EmployeeDao;
import com.daqing.financial.hrms.service.DeptService;
import com.daqing.framework.domain.hrms.DepartmentVO;
import com.daqing.framework.domain.hrms.DeptEntity;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.domain.hrms.ext.EmployeeVO;
import com.daqing.framework.domain.hrms.request.DeptAddRequest;
import com.daqing.framework.domain.hrms.response.HrmsCode;
@ -192,4 +193,17 @@ public class DeptServiceImpl extends ServiceImpl<DeptDao, DeptEntity> implements
return departmentVO;
}
}
/**
*
* 根据员工id获取对应部门下所有的客户经理
*
* @param id 员工id
* @return
*/
@Override
public List<EmployeeEntity> listEmployeeById(Long id) {
return this.getBaseMapper().listEmployeeById(id);
}
}

@ -1,12 +1,19 @@
package com.daqing.financial.hrms.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.daqing.financial.hrms.dao.EmployeeDao;
import com.daqing.financial.hrms.dao.UserDao;
import com.daqing.financial.hrms.feign.HrmsAuthFeignService;
import com.daqing.financial.hrms.service.UserService;
import com.daqing.framework.domain.hrms.EmployeeEntity;
import com.daqing.framework.domain.hrms.UserEntity;
import com.daqing.framework.domain.hrms.ext.EmployeeAndUserVO;
import com.daqing.framework.domain.hrms.response.HrmsCode;
import com.daqing.framework.exception.ExceptionCast;
import com.daqing.framework.model.response.CommonCode;
import com.daqing.framework.model.response.PromptSuccess;
import com.daqing.framework.util.HttpUtils;
import com.daqing.framework.util.Md5Util;
import com.daqing.framework.util.RedisUtil;
import com.daqing.framework.util.SendSMS;
@ -14,34 +21,26 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Map;
import java.util.Objects;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.daqing.framework.utils.PageUtils;
import com.daqing.framework.utils.Query;
import com.daqing.financial.hrms.dao.UserDao;
import com.daqing.framework.domain.hrms.UserEntity;
import com.daqing.financial.hrms.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
@Slf4j
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
@Resource
@Autowired
private EmployeeDao employeeDao;
@Autowired
private HrmsAuthFeignService hrmsAuthFeignService;
/**
* 当前登录的用户信息
*/
@ -52,7 +51,20 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements
String userId = RedisUtil.get("dq:token:"+token);*/
//TODO:测试环境模拟从redis中拿取用户id
String userId = "1";
return employeeDao.getEmployeeByUserId(Long.parseLong(userId));
EmployeeAndUserVO employeeAndUser = employeeDao.getEmployeeByUserId(Long.parseLong(userId));
if (employeeAndUser.getWechatId() == null || employeeAndUser.getWechatId().length() == 0){
JSONObject responseResult = hrmsAuthFeignService.getWeChatConfig();
JSONObject weChatConfig = responseResult.getJSONObject("data");
if (weChatConfig == null){
employeeAndUser.setWechatId("二维码获取失败,请稍后重试");
}else {
employeeAndUser.setWechatId(String.format(weChatConfig.get("OPEN_QRCODE_URL").toString(),weChatConfig.get("openAppid"),
weChatConfig.get("openRedirectUrl"),weChatConfig.get("openAppsecret")));
}
}else {
employeeAndUser.setWechatId("已绑定,微信扫码即可登录");
}
return employeeAndUser;
}
/**
@ -229,4 +241,41 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements
RedisUtil.del(phone);
return this.getBaseMapper().updatePhoneAccount(id, phone);
}
/**
* 绑定微信回调接收接口
* @param code 微信端返回的code,用于申请openid
* @return
*/
@Override
public Boolean weChatCallback(String code, HttpServletResponse response) {
log.info("微信回调成功---------------------------------------");
JSONObject responseResult = hrmsAuthFeignService.getWeChatConfig();
JSONObject weChatConfig = responseResult.getJSONObject("data");
String accessTokenUrl = String.format(weChatConfig.get("OPEN_ACCESS_TOKEN_URL").toString(), weChatConfig.get("openAppid"), weChatConfig.get("openAppsecret"), code);
//获取access_token
Map<String ,Object> baseMap = HttpUtils.doGet(accessTokenUrl);
if(baseMap == null || baseMap.isEmpty()){ return false; }
String openId = (String) baseMap.get("openid");
/*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
String userId = RedisUtil.get("dq:token:"+token);*/
//TODO:测试环境模拟从redis中拿取用户id
String userId = "1";
Boolean result = this.getBaseMapper().updateWeChat(Long.parseLong(userId), openId);
log.info("绑定成功---------------------------------------");
if (result){
try {
log.info("转发成功---------------------------------------");
response.sendRedirect("https://www.baidu.com?openId="+openId);
}catch (IOException e){
e.printStackTrace();
}
}
return false;
}
}

@ -1,61 +1,61 @@
##服务名称
#spring.application.name=dq-financial-hrms
##配置中心地址
#spring.cloud.nacos.config.server-addr=192.168.31.142:8848
#spring.cloud.nacos.config.namespace=4c56c2f9-b6a3-4e7b-88b8-b1001e86dfd6
##spring.cloud.nacos.config.group=prod
#
#spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
#spring.cloud.nacos.config.ext-config[0].group=dev
#spring.cloud.nacos.config.ext-config[0].refresh=true
#
#spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
#spring.cloud.nacos.config.ext-config[1].group=dev
#spring.cloud.nacos.config.ext-config[1].refresh=true
#
#spring.cloud.nacos.config.ext-config[2].data-id=other.yml
#spring.cloud.nacos.config.ext-config[2].group=dev
#spring.cloud.nacos.config.ext-config[2].refresh=true
#
#spring.redis.host=127.0.0.1
#spring.redis.port=6379
#spring.redis.password=123456
#spring.redis.database=0
#spring.redis.timeout=30000
#spring.redis.jedis.pool.max-active=8
#spring.redis.jedis.pool.max-wait=-1
#spring.redis.jedis.pool.max-idle=8
#spring.redis.jedis.pool.min-idle=0
#
#spring.servlet.multipart.max-file-size=10MB
#spring.servlet.multipart.max-request-size=10MB
# 正式环境(prod)
#服务名称
spring.application.name=dq-financial-hrms
#配置中心地址
spring.cloud.nacos.config.server-addr=192.168.31.142:8848
spring.cloud.nacos.config.namespace=4c56c2f9-b6a3-4e7b-88b8-b1001e86dfd6
spring.cloud.nacos.config.server-addr=120.78.127.12:8848
spring.cloud.nacos.config.namespace=69614b55-1521-421c-ac58-dbe4a5b01b43
#spring.cloud.nacos.config.group=prod
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].group=prod
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].group=prod
spring.cloud.nacos.config.ext-config[1].refresh=true
spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].group=prod
spring.cloud.nacos.config.ext-config[2].refresh=true
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.password=dq123456
spring.redis.database=0
spring.redis.timeout=30000
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
# 正式环境(prod)
#服务名称
#spring.application.name=dq-financial-hrms
##配置中心地址
#spring.cloud.nacos.config.server-addr=120.78.127.12:8848
#spring.cloud.nacos.config.namespace=69614b55-1521-421c-ac58-dbe4a5b01b43
##spring.cloud.nacos.config.group=prod
#
#spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
#spring.cloud.nacos.config.ext-config[0].group=prod
#spring.cloud.nacos.config.ext-config[0].refresh=true
#
#spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
#spring.cloud.nacos.config.ext-config[1].group=prod
#spring.cloud.nacos.config.ext-config[1].refresh=true
#
#spring.cloud.nacos.config.ext-config[2].data-id=other.yml
#spring.cloud.nacos.config.ext-config[2].group=prod
#spring.cloud.nacos.config.ext-config[2].refresh=true
#spring.redis.host=127.0.0.1
#spring.redis.port=6379
#spring.redis.password=dq123456
#spring.redis.database=0
#spring.redis.timeout=30000
#spring.redis.jedis.pool.max-active=8
#spring.redis.jedis.pool.max-wait=-1
#spring.redis.jedis.pool.max-idle=8
#spring.redis.jedis.pool.min-idle=0

@ -45,4 +45,22 @@
SELECT id,name FROM hrms_dept
</select>
<select id="listEmployeeById" parameterType="long" resultType="com.daqing.framework.domain.hrms.EmployeeEntity">
SELECT DISTINCT e.id id,e.name name
FROM hrms_employee e
LEFT JOIN hrms_employee_dept ed
ON e.id = ed.employee_id
LEFT JOIN hrms_dept d
ON d.id = ed.dept_id
WHERE d.id IN
( SELECT d.id
FROM hrms_dept d
LEFT JOIN hrms_employee_dept ed
ON d.id = ed.dept_id
LEFT JOIN hrms_employee e
ON e.id = ed.employee_id
WHERE e.id = #{id}
)
</select>
</mapper>

@ -41,4 +41,8 @@
UPDATE hrms_user SET phone_account = #{phoneAccount} WHERE id = #{id}
</update>
<update id="updateWeChat">
UPDATE hrms_user SET wechat_id = #{weChatId} WHERE id = #{id}
</update>
</mapper>

@ -0,0 +1,107 @@
package com.daqing.framework.util;
import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 封装http get post
*/
public class HttpUtils {
private static final Gson gson = new Gson();
/**
* get方法
* @param url
* @return
*/
public static Map<String,Object> doGet(String url){
Map<String,Object> map = new HashMap<>();
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000) //连接超时
.setConnectionRequestTimeout(5000)//请求超时
.setSocketTimeout(5000)
.setRedirectsEnabled(true) //允许自动重定向
.build();
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(requestConfig);
try{
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() == 200){
String jsonResult = EntityUtils.toString( httpResponse.getEntity());
map = gson.fromJson(jsonResult,map.getClass());
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
httpClient.close();
}catch (Exception e){
e.printStackTrace();
}
}
return map;
}
/**
* 封装post
* @return
*/
public static String doPost(String url, String data,int timeout){
CloseableHttpClient httpClient = HttpClients.createDefault();
//超时设置
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout) //连接超时
.setConnectionRequestTimeout(timeout)//请求超时
.setSocketTimeout(timeout)
.setRedirectsEnabled(true) //允许自动重定向
.build();
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
httpPost.addHeader("Content-Type","text/html; chartset=UTF-8");
if(data != null && data instanceof String){ //使用字符串传参
StringEntity stringEntity = new StringEntity(data,"UTF-8");
httpPost.setEntity(stringEntity);
}
try{
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpResponse.getStatusLine().getStatusCode() == 200){
String result = EntityUtils.toString(httpEntity);
return result;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{
httpClient.close();
}catch (Exception e){
e.printStackTrace();
}
}
return null;
}
}

@ -38,6 +38,6 @@ public class CustomerWorkbenchListVO implements Serializable {
@ApiModelProperty(value = "所属部门")
private List<String> departments;
@ApiModelProperty(value = "审批状态(0:,1:,2:)")
@ApiModelProperty(value = "审批状态(0:通过,1:未通过,2:带审核)")
private Integer status;
}

@ -3,6 +3,7 @@ jwt.ignoreUrlList=/apiHrmsAuth/hrms/auth/userlogin/getBackPwd,\
/apiHrmsAuth/hrms/auth/userlogin/verifyMobile,\
/apiHrmsAuth/hrms/auth/userlogin/wxLoginUrl,\
/apiHrmsAuth/hrms/auth/userlogin/user/callback,\
/api-hrms/hrms/user/weChatCallback,\
/apiHrmsAuth/hrms/auth/userlogin/wxLoginUrl,\
/api-crms/sweagger-ui.html,\
/api-crms/crms/customer/excelTemplate,\

@ -17,7 +17,7 @@
<module>dq-financial-hrms</module>
<module>dq-financial-hrms-auth</module>
<module>dq-financial-crms</module>
<module>dq-financial-crms-auth</module>
<module>dq-govern-gateway</module>
<!-- <module>dq-financial-workflow</module>
<module>dq-financial-guarantee</module>-->
</modules>

Loading…
Cancel
Save