From 3d2b51ea4520533de5e78f88dddf5b5c7dce4247 Mon Sep 17 00:00:00 2001 From: mitao <2763622819@qq.com> Date: 星期四, 06 六月 2024 15:56:18 +0800 Subject: [PATCH] 管理后台添加营销员导入功能 --- meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java | 8 meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java | 1 meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html | 8 meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java | 116 ++++++++ meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java | 64 ++++ meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java | 15 + meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java | 1 meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java | 193 ++++++++++++++ meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java | 89 ++++++ meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java | 5 meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js | 54 ++++ meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java | 22 + meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml | 3 meiya-admin/pom.xml | 7 meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html | 7 meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java | 2 meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java | 165 ++++++++++++ meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java | 2 18 files changed, 757 insertions(+), 5 deletions(-) diff --git a/meiya-admin/pom.xml b/meiya-admin/pom.xml index df6f742..d350cbb 100644 --- a/meiya-admin/pom.xml +++ b/meiya-admin/pom.xml @@ -157,6 +157,13 @@ <artifactId>esdk-obs-java-bundle</artifactId> <version>[3.21.11,)</version> </dependency> + + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.4</version> + </dependency> + </dependencies> <build> diff --git a/meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java b/meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java index b5f00c9..cbd98c9 100644 --- a/meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java +++ b/meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java @@ -3,6 +3,7 @@ import cn.hutool.core.util.StrUtil; import com.obs.services.ObsClient; import com.sinata.core.config.HuaWeiConfig; +import java.io.ByteArrayInputStream; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -46,4 +47,25 @@ } return objectName; } + public static String obsUploadInputStream(InputStream is, String dir,String fileName) throws IOException { + // 文件目录 + dir = StrUtil.isBlank(dir) ? "excel/" : dir + "/"; + + String objectName = ""; + // 创建ObsClient实例 + ObsClient obsClient = new ObsClient(HuaWeiConfig.AK, HuaWeiConfig.SK, https + endPoint); + + //获得指定文件的输入流 + objectName = dir + fileName; + + // 上传对象至OBS + obsClient.putObject(bucketName, objectName, is); + + if (objectName != null && !"".equals(objectName)) { + objectName = obsDomain + objectName; + } + // 关闭obsClient,全局使用一个ObsClient客户端的情况下,不建议主动关闭ObsClient客户端 + obsClient.close(); + return objectName; + } } diff --git a/meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java b/meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java new file mode 100644 index 0000000..f9822c4 --- /dev/null +++ b/meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java @@ -0,0 +1,15 @@ +package com.sinata.core.util.juhe; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "juhe") +class JuHeProperties{ + + private String openid; + + private String appkey; +} \ No newline at end of file diff --git a/meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java b/meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java new file mode 100644 index 0000000..df3f6a5 --- /dev/null +++ b/meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java @@ -0,0 +1,89 @@ +package com.sinata.core.util.juhe; + + + +import static com.sinata.core.util.juhe.TelecomUtil.MD5; + +import java.io.UnsupportedEncodingException; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.binary.Base64; + +public class SecurityAESTool { + + /** + * AES加密 + * + * @param str + * 明文 + * @param key + * 秘钥 + * @return + */ + public static String encrypt(String str, String key) { + byte[] crypted = null; + try { + + SecretKeySpec skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, skey); + + String enStr = str; + crypted = cipher.doFinal(enStr.getBytes("UTF-8")); + } catch (Exception e) { + System.out.println(e.toString()); + } + + String body = new String(Base64.encodeBase64(crypted)); + return body; + } + + /** + * AES解密 + * + * @param input + * @param key + * @return + */ + public static String decrypt(String input, String key) { + byte[] output = null; + String body = null; + if (input == null || key == null) { + return null; + } + try { + SecretKeySpec skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, skey); + byte[] b = Base64.decodeBase64(input); + // 解密 + output = cipher.doFinal(b); + body = new String(output, "UTF-8"); + } catch (Exception e) { + System.out.println(e.toString()); + } + return body; + } + + public static void main(String[] args) throws UnsupportedEncodingException { + String openid = "JH1ad5c53745350580f7c24ca4b09717de"; + String key = MD5(openid).substring(0, 16);//取前16位作为加密密钥 + //String key = MD5Util.encrypt(appId).toLowerCase(Locale.ROOT).substring(0,16);//秘钥 + System.out.println(key); + //取lowerCase前16位 + String realname = "米涛"; // 明文 + String idcard = "510603199912053256"; // 明文 + + realname = SecurityAESTool.encrypt(realname, key); + System.out.println("realname:"+realname); + System.out.println("realname:"+SecurityAESTool.decrypt(realname, key)); + idcard = SecurityAESTool.encrypt(idcard, key); + System.out.println("idcard:"+idcard); + System.out.println("idcard:"+SecurityAESTool.decrypt(idcard, key)); + String mobile = "18283820718"; + mobile = SecurityAESTool.encrypt(mobile, key); + System.out.println("mobile:"+mobile); + System.out.println("mobile:"+SecurityAESTool.decrypt(mobile, key)); + + } +} \ No newline at end of file diff --git a/meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java b/meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java new file mode 100644 index 0000000..2d19edc --- /dev/null +++ b/meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java @@ -0,0 +1,165 @@ +package com.sinata.core.util.juhe; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.internal.util.file.IOUtils; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +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.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.stereotype.Component; + +/**三网手机实名认证 + * @author mitao + * @date 2024/4/1 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class TelecomUtil { + private final JuHeProperties juHeProperties; + //设置超时时间为5秒 + public static RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build(); + //明文查询地址 + public static String query_url = "https://v.juhe.cn/telecom/query?key="; + //加密查询地址 + public static String queryEncry_url = "https://v.juhe.cn/telecom/queryEncry?key="; + + public boolean verify(String realname, String idcard, String mobile) { + // ----------------------三网手机实名制认证----------------------------------------------------------------------- + // int queryType = 1;// 1:普通查询 2:加密查询 + // String realname = "";// 姓名 + // String idcard = "";// 身份证 + //String mobile="" // 手机号 + // int type = 1;// 是否显示手机运营商 1:显示 0:不显示(默认) + //int showid = 1 //是否显示聚合订单账号 1:显示 0:不显示(默认) + //int province = 1 //是否显示号码归属地 1:显示 0:不显示(默认) + //int detail = 1 //是否买显示匹配详情码 1:显示 0:不显示(默认) + // Map<String, Object> params = new HashMap<>(); + // params.put("realname", realname); + // params.put("idcard", idcard); + // params.put("mobile", mobile); + + // ----------------------调用三网手机实名认证(加密版)----------------------------------------------------------------------- + String key = MD5(juHeProperties.getOpenid()).substring(0, 16);//取前16位作为加密密钥 + int queryType = 2;// 加密版本 + realname = SecurityAESTool.encrypt(realname, key);//加密姓名 + idcard = SecurityAESTool.encrypt(idcard, key);//加密身份证 + mobile = SecurityAESTool.encrypt(mobile, key);// + Map<String, Object> params = new HashMap<>();//组合参数 + params.put("realname", realname); + params.put("idcard", idcard); + params.put("mobile", mobile); + //请求接口 + JSONObject result = null; + try { + result = JSONObject.parseObject(queryResult(params, queryType)); + } catch (Exception e) { + log.error("调用三网手机实名认证失败", e); + } + //打印结果 + System.out.println(result); + JSONObject innerResult = result.getJSONObject("result"); + if (result != null && innerResult != null && innerResult.getInteger("res") == 1) { + return true; + } + return false; + } + + /** + * 请求接口查询数据 + * + * @param params 参数 + * @param queryType 类型,1明文查询(默认),2加密版 + * @return 结果 + * @throws Exception + */ + + private String queryResult(Map<String, Object> params, int queryType) throws Exception { + + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String result = null; + String url = query_url; + switch (queryType) { + case 2: + url = queryEncry_url + juHeProperties.getAppkey(); + break; + } + try { + url = new StringBuffer(url).append("&").append(urlencode(params)).toString(); + HttpGet httpget = new HttpGet(url); + httpget.setConfig(config); + response = httpClient.execute(httpget); + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + result = IOUtils.toString(resEntity.getContent(), "UTF-8"); + } + EntityUtils.consume(resEntity); + } catch (Exception e) { + e.printStackTrace(); + } finally { + response.close(); + httpClient.close(); + } + return result; + } + + + // 将map型转为请求参数型 + public static String urlencode(Map<String, ?> data) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry<String, ?> i : data.entrySet()) { + try { + sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue() + "", "UTF-8")).append("&"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + String result = sb.toString(); + result = result.substring(0, result.lastIndexOf("&")); + return result; + } + + + /** + * md5加密 + * + * @param data + * @return 加密结果 + */ + public static String MD5(String data) { + StringBuffer md5str = new StringBuffer(); + byte[] input = data.getBytes(); + try { + // 创建一个提供信息摘要算法的对象,初始化为md5算法对象 + MessageDigest md = MessageDigest.getInstance("MD5"); + // 计算后获得字节数组 + byte[] buff = md.digest(input); + // 把数组每一字节换成16进制连成md5字符串 + int digital; + for (int i = 0; i < buff.length; i++) { + digital = buff[i]; + if (digital < 0) { + digital += 256; + } + if (digital < 16) { + md5str.append("0"); + } + md5str.append(Integer.toHexString(digital)); + } + } catch (Exception e) { + e.printStackTrace(); + } + return md5str.toString(); + } +} diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java b/meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java index 6de9a9d..fe11369 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java +++ b/meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java @@ -3,6 +3,8 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.excel.ExcelReader; +import cn.hutool.poi.excel.ExcelUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.enums.SqlLike; import com.baomidou.mybatisplus.mapper.EntityWrapper; @@ -17,10 +19,13 @@ import com.sinata.core.common.annotion.BussinessLog; import com.sinata.core.common.annotion.Permission; import com.sinata.core.common.constant.factory.PageFactory; +import com.sinata.core.common.exception.BizExceptionEnum; +import com.sinata.core.exception.GunsException; import com.sinata.core.shiro.ShiroKit; import com.sinata.core.shiro.ShiroUser; import com.sinata.core.util.Convert; import com.sinata.core.util.ExcelExportUtil; +import com.sinata.core.util.ExcelImportUtil; import com.sinata.core.util.SqlUtil; import com.sinata.modular.mall.model.MallOrder; import com.sinata.modular.mall.service.IMallOrderService; @@ -34,19 +39,25 @@ import com.sinata.modular.system.service.IRoleService; import com.sinata.modular.system.service.ISystemNoticeService; import com.sinata.modular.system.service.ITCityRegionService; +import java.io.IOException; +import java.net.URLEncoder; +import javax.servlet.ServletOutputStream; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; +import org.springframework.web.multipart.MultipartFile; /** * 会员用户信息控制器 @@ -489,6 +500,7 @@ + ", agent_province_code = " + SqlUtil.addSingleQuotes(province) + ", agent_city_code = " + SqlUtil.addSingleQuotes(city) + ", agent_county_code = " + SqlUtil.addSingleQuotes(county); + log.info("用户:{}修改了营销员城市地址",memUser.getRealName()); } } @@ -798,7 +810,7 @@ + ", agent_province_code = " + SqlUtil.addSingleQuotes(province) + ", agent_city_code = " + SqlUtil.addSingleQuotes(city) + ", agent_county_code = " + SqlUtil.addSingleQuotes(county); - + log.info("用户:{}修改了营销员城市地址",userIdList.toString()); boolean flag = memUserService.updateForSet(whereSql, new EntityWrapper<MemUser>().in("id", userIdList)); return returnByFlag(flag, null); } @@ -828,5 +840,55 @@ return new ErrorTip(500, StrUtil.isNotBlank(msg) ? msg : "操作失败!"); } } + @Permission + @ResponseBody + @BussinessLog(value = "营销人员管理-下载导入模板") + @RequestMapping(value = "/downloadTemplate",method = RequestMethod.POST) + public Object downloadTemplate(HttpServletResponse response) { + // // 表格数据【封装】 + // List<List<Object>> dataList = new ArrayList<>(); + // // 头部列【封装】 + // List<Object> shellList = new ArrayList<>(); + // shellList.add("姓名"); + // shellList.add("手机号"); + // shellList.add("性别"); + // shellList.add("生日 例:2024-06-06"); + // shellList.add("证件类型 0身份证 1护照"); + // shellList.add("身份证号"); + // shellList.add("银行名称"); + // shellList.add("银行卡号"); + // shellList.add("推荐人手机号"); + // dataList.add(shellList); + // try { + // ExcelExportUtil.easySheet(URLEncoder.encode("营销人员导入模板", "UTF-8"),"sheet1",dataList,response); + // } catch (IOException e) { + // throw new RuntimeException(e); + // } + String url = "https://meitianmeiya.obs.cn-southwest-2.myhuaweicloud.com/excel/%E8%90%A5%E9%94%80%E4%BA%BA%E5%91%98%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xls"; + return new SuccessTip(200, url); + } + @Permission + @ResponseBody + @BussinessLog(value = "营销人员管理-导入") + @RequestMapping(value = "/importSalesUser",method = RequestMethod.POST) + public Object importUsers(MultipartFile file, HttpServletResponse response) { + String s = file.getOriginalFilename(); + if (s == null || !("xls".equals(s.substring(s.lastIndexOf(".") + 1)) || "xlsx".equals(s.substring(s.lastIndexOf(".") + 1)))) { + return new ErrorTip(500,"只能上传.xls或.xlsx格式的文件!"); + } + List<Map<String, String>> mapList = null; + try { + mapList = ExcelImportUtil.getMapList(file, + new String[]{"姓名", "手机号", "性别","生日 例:2024-06-06","证件类型 0身份证 1护照", "身份证号","银行名称","银行卡号","推荐人手机号","职级 3黄金营销员 4城市合伙人 5市场总监"}); + } catch (IOException e) { + throw new RuntimeException(e); + } + String str = memUserService.importSalesUser(mapList, response); + if (str == null) { + return SUCCESS_TIP; + } else { + return new SuccessTip(201, str); + } + } } diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java b/meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java index 52137d8..76145a0 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java +++ b/meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java @@ -26,4 +26,6 @@ List<Map<String, Object>> getMapListAuth(@Param("ew") Wrapper wrapper); List<Map<String, Object>> getMapListAuth(Page<Map<String, Object>> page, @Param("ew")Wrapper wrapper); + + MemUser selectLast(); } diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml b/meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml index 23aaad0..ab1eb16 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml +++ b/meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml @@ -76,5 +76,8 @@ LEFT JOIN t_city_region county ON county.`code` = o.agent_county_code WHERE 1 = 1 ${ew.sqlSegment} </select> + <select id="selectLast" resultMap="BaseResultMap"> + SELECT * from mem_user where create_time = (select max(create_time) from mem_user) + </select> </mapper> diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java b/meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java index 58e2a06..a9b16f9 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java +++ b/meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java @@ -2,12 +2,15 @@ import com.baomidou.mybatisplus.activerecord.Model; import com.baomidou.mybatisplus.annotations.TableField; +import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; +import com.baomidou.mybatisplus.enums.IdType; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import java.io.Serializable; @@ -22,6 +25,7 @@ * @since 2023-03-23 */ @Data +@EqualsAndHashCode(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor @@ -35,6 +39,7 @@ * 会员ID */ @ApiModelProperty(value = "会员ID") + @TableId(value = "id", type = IdType.INPUT) private Integer id; /** * 邀请码 diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java b/meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java index aa0f942..a1e8312 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java +++ b/meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletResponse; /** * <p> @@ -49,4 +50,5 @@ */ void subIntegralCancelOrder(String orderNo); + String importSalesUser(List<Map<String, String>> mapList, HttpServletResponse response); } diff --git a/meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java b/meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java index b1ec92d..ed49865 100644 --- a/meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java +++ b/meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java @@ -1,17 +1,38 @@ package com.sinata.modular.member.service.impl; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.baomidou.mybatisplus.plugins.Page; import com.baomidou.mybatisplus.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.sinata.common.enums.EnumMemberGrade; import com.sinata.common.enums.EnumUserBankDetailDoneType; import com.sinata.common.enums.EnumUserBankDetailType; import com.sinata.core.shiro.ShiroKit; +import com.sinata.core.util.Convert; +import com.sinata.core.util.ExcelExportUtil; +import com.sinata.core.util.MD5Util; +import com.sinata.core.util.SqlUtil; +import com.sinata.core.util.ToolUtil; +import com.sinata.core.util.huawei.obs.ObsUploadUtil; +import com.sinata.core.util.juhe.TelecomUtil; import com.sinata.modular.member.dao.MemUserMapper; import com.sinata.modular.member.model.MemUser; import com.sinata.modular.member.model.MemUserBankDetail; +import com.sinata.modular.member.model.MemUserRelation; import com.sinata.modular.member.service.IMemUserBankDetailService; +import com.sinata.modular.member.service.IMemUserRelationService; import com.sinata.modular.member.service.IMemUserService; +import java.io.InputStream; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -32,11 +53,15 @@ * @since 2023-03-23 */ @Service +@Slf4j public class MemUserServiceImpl extends ServiceImpl<MemUserMapper, MemUser> implements IMemUserService { @Resource private IMemUserBankDetailService memoryUserBankDetailService; - + @Resource + private IMemUserRelationService memUserRelationService; + @Resource + private TelecomUtil telecomUtil; @Override public List<Map<String, Object>> getMapList(Wrapper wrapper) { boolean admin = ShiroKit.isAdmin(); @@ -149,5 +174,171 @@ } } } + @Override + @Transactional(rollbackFor = Exception.class) + public String importSalesUser(List<Map<String, String>> mapList, HttpServletResponse response) { + // 表格数据【封装】 + List<List<Object>> dataList = new ArrayList<>(); + // 头部列【封装】 + List<Object> shellList = new ArrayList<>(); + shellList.add("姓名"); + shellList.add("手机号"); + shellList.add("性别"); + shellList.add("生日"); + shellList.add("证件类型 0身份证 1护照"); + shellList.add("身份证号"); + shellList.add("银行名称"); + shellList.add("银行卡号"); + shellList.add("推荐人手机号"); + shellList.add("职级 3黄金营销员 4城市合伙人 5市场总监"); + shellList.add("备注"); + dataList.add(shellList); + List<String> cardTypeList = Lists.newArrayList("0", "1"); + List<String> gradeIdList = Lists.newArrayList("3", "4", "5"); + List<String> sexList = Lists.newArrayList("男", "女"); + for (Map<String, String> stringStringMap : mapList) { + MemUser memUser = new MemUser(); + String realName = stringStringMap.get("姓名"); + String sex = stringStringMap.get("性别"); + String birthday = stringStringMap.get("生日 例:2024-06-06"); + String idCard = stringStringMap.get("身份证号"); + String cardType = stringStringMap.get("证件类型 0身份证 1护照"); + String inviteUserPhone = stringStringMap.get("推荐人手机号"); + String phone = stringStringMap.get("手机号"); + String bankName = stringStringMap.get("银行名称"); + String bankNumber = stringStringMap.get("银行卡号"); + String memberGradeId = stringStringMap.get("职级 3黄金营销员 4城市合伙人 5市场总监"); + List<Object> list = new ArrayList<>(); + list.add(realName); + list.add(phone); + list.add(sex); + list.add(birthday); + list.add(cardType); + list.add(idCard); + list.add(bankName); + list.add(bankNumber); + list.add(inviteUserPhone); + list.add(memberGradeId); + if (ToolUtil.isAllEmpty(realName, phone, sex,birthday,idCard, cardType, inviteUserPhone, bankName, bankNumber)) { + continue; + } + //判断导入的生日格式是否正确2024-06-06 + if (ToolUtil.isNotEmpty(birthday)) { + try { + DateUtil.parse(birthday, "yyyy-MM-dd"); + } catch (Exception e) { + list.add("生日格式错误"); + dataList.add(list); + continue; + } + } + if (!gradeIdList.contains(memberGradeId)) { + list.add("职级填写错误"); + dataList.add(list); + continue; + } + if (!sexList.contains(sex)) { + list.add("性别填写错误"); + dataList.add(list); + continue; + } + if (ToolUtil.isOneEmpty(realName, phone, sex,birthday,idCard, cardType, inviteUserPhone, bankName, bankNumber)) { + list.add("信息填写不完整"); + dataList.add(list); + continue; + } + memUser.setRealName(realName); + memUser.setPhone(phone); + memUser.setSex(sex); + memUser.setBirthday(birthday); + memUser.setCardType(cardTypeList.contains(cardType) ? cardType : "0"); + memUser.setIdCard(idCard); + memUser.setBankName(bankName); + memUser.setBankNumber(bankNumber); + memUser.setNickName("用户" + ToolUtil.getRandomString(4)); + memUser.setPassword(MD5Util.encrypt(phone)); + memUser.setMemberGradeId(Integer.valueOf(memberGradeId)); + memUser.setMemberGradeTime(new Date()); + memUser.setShowId("0"); + memUser.setIsLeaveOffice(0); + memUser.setAuditTime(new Date()); + memUser.setAuditState(1); + memUser.setCreateTime(new Date()); + memUser.setCreditScore(BigDecimal.valueOf(100L)); + // 获取最新工号 + Object showId = this.selectObj( + new EntityWrapper<MemUser>() + .setSqlSelect("MAX(CAST(show_id AS UNSIGNED)) AS max_show_id") + .ne("show_id", "0") + ); + if (showId == null) { + showId = "1000" + "100000"; + } + String showIdStr = String.valueOf(Convert.toInt(showId) + 1); + memUser.setShowId(showIdStr); + EntityWrapper<MemUser> wrapper = new EntityWrapper<>(); + wrapper.eq("phone", memUser.getPhone()); + if (this.selectOne(wrapper) != null) { + list.add("该手机号已被注册"); + dataList.add(list); + continue; + } + EntityWrapper<MemUser> wrapper2 = new EntityWrapper<>(); + wrapper2.eq("phone", inviteUserPhone); + MemUser inviteUser = this.selectOne(wrapper2); + if (inviteUser == null) { + list.add("邀请人不存在"); + dataList.add(list); + continue; + } else { + if (inviteUser.getMemberGradeId() < EnumMemberGrade.G_3.index) { + list.add("邀请人等级不足"); + dataList.add(list); + continue; + } + } + boolean verify = telecomUtil.verify(memUser.getRealName(), memUser.getIdCard(), + memUser.getPhone()); + if (!verify) { + list.add("实名认证失败"); + dataList.add(list); + continue; + } + String agentCountyCode = inviteUser.getAgentCountyCode(); + String agentCityCode = inviteUser.getAgentCityCode(); + String agentProvinceCode = inviteUser.getAgentProvinceCode(); + memUser.setAgentProvinceCode(agentProvinceCode); + memUser.setAgentCityCode(agentCityCode); + memUser.setAgentCountyCode(agentCountyCode); + memUser.setCityCode(agentCityCode); + this.insert(memUser); + MemUserRelation shareUserRelation = memUserRelationService.selectById(inviteUser.getId()); + //添加关系 + MemUserRelation build = MemUserRelation.builder() + .id(memUser.getId()) + .parentId(shareUserRelation.getId()) + .relationPath( + shareUserRelation.getRelationPath() + "/" + memUser.getId()) + .build(); + memUserRelationService.insertOrUpdate(build); + } + + if (dataList.size() > 1) { + try { + InputStream inputStream = ExcelExportUtil.easySheet2( + URLEncoder.encode("导入失败数据", "UTF-8"), "sheet1", dataList, response); + if (inputStream != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String fileName = "导入失败数据" + "-"+sdf.format(new Date())+".xls"; + String url = ObsUploadUtil.obsUploadInputStream(inputStream, "excel", fileName); + log.info("导入失败数据:{}", url); + return url; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return null; + } } diff --git a/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html b/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html index 60a3d1d..ab15883 100644 --- a/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html +++ b/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html @@ -93,6 +93,12 @@ @if(shiro.hasPermission("/memUserSales/updateState")){ <input id='updateStateAuth' type="hidden" value='true'> @} + @if(shiro.hasPermission("/memUserSales/downloadTemplate")){ + <button type="button" class="btn btn-primary" onclick="MemUserSales.downloadTemplate()"><i class="fa fa-external-link"></i> 下载导入模板</button> + @} + @if(shiro.hasPermission("/memUserSales/importSalesUser")){ + <#button name="导入" icon="fa-plus" clickFun="MemUserSales.import()" space="false"/> + @} </div> <table id="MemUserTable" class="table_list_box" data-mobile-responsive="true" data-click-to-select="true"> <thead> @@ -107,5 +113,6 @@ </div> </div> </div> +<input type="file" id="file" style="display: none;"> <script src="${ctxPath}/static/modular/member/memUserSales/memUserSales.js"></script> @} diff --git a/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html b/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html index 6ecdee0..e7fd995 100644 --- a/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html +++ b/meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html @@ -29,7 +29,7 @@ </div> <div class="form-group"> <label class="col-sm-2 control-label">权益转让</label> - <div class="col-sm-2 form-control-static">${item.equityUser.id!=item.id?"是":"否"}</div> + <div class="col-sm-2 form-control-static">${item.equityUser.id! != item.id! ?"是":"否"}</div> <label class="col-sm-2 control-label">权益受让人</label> <div class="col-sm-2 form-control-static">${item.realName!}</div> @@ -81,7 +81,11 @@ <label class="col-sm-2 control-label">证件类型</label> <div class="col-sm-2 form-control-static">${item.cardType=="0"?"身份证":"护照"}</div> - <label class="col-sm-2 control-label">${item.cardType=="0"?"身份证图片(正面)":"护照个人资料页"}</label> + <label class="col-sm-2 control-label"> + @if(isNotEmpty(item.cardType)){ + ${item.cardType=="0"?"身份证图片(正面)":"护照个人资料页"} + @} + </label> <div class="col-sm-2 form-control-static"> @if(isNotEmpty(item.idCardFrontImage)){ <img height="150px" src="${item.idCardBackImage}" onclick="Feng.lookBigImg('${item.idCardBackImage}')" /> diff --git a/meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js b/meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js index ea4d5c6..6c7332c 100644 --- a/meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js +++ b/meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js @@ -273,7 +273,22 @@ "&memberGradeId=" + memberGradeId + "&phone=" + phone; }; +/** + * 导出记录 + */ +MemUserSales.downloadTemplate = function () { + var ajax = new $ax(Feng.ctxPath + "/memUserSales/downloadTemplate", function (data) { + if(data.code == 200){ + window.location.href = data.message; + } else { + Feng.error("操作失败!" + data.message); + } + }, function () { + Feng.error("操作失败!"); + }); + ajax.start(); +}; /** * 查询销售人员信息列表 */ @@ -303,6 +318,12 @@ $("#memberGradeId").val("-1"); MemUserSales.search(); }; +/** + * 导入 + */ +MemUserSales.import = function(){ + $('#file').click(); +} $(function () { var defaultColunms = MemUserSales.initColumn(); var table = new BSTable(MemUserSales.id, "/memUserSales/list", defaultColunms); @@ -328,5 +349,38 @@ laydate.render({ elem: '#endTime' }); + + $('#file').on('change', function () { + let formData = new FormData() //创建一个forData + formData.append('file', $('#file')[0].files[0]) //把file添加进去 name命名为img + layer.load(); //上传loading + $.ajax({ + url: Feng.ctxPath + '/memUserSales/importSalesUser', + data: formData, + type: "POST", + async: true, + cache: false, + contentType: false, + processData: false, + success: function(res) { + console.log(res) + layer.closeAll('loading'); //关闭loading + $('#file').val(''); + MemUserSales.search(); + if (res.code == 200) { + Feng.info("操作成功!") + } + if (res.code == 201) { + window.open(res.message); + } + }, + error: function(res) { + console.log("res", res) + layer.closeAll('loading'); //关闭loading + $('#file').val(''); + Feng.error(res.message); + } + }) + }) }); diff --git a/meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java b/meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java index c8ae99a..cd74242 100644 --- a/meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java +++ b/meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java @@ -1,8 +1,14 @@ package com.sinata.core.util; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFDataFormat; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; @@ -17,6 +23,8 @@ import java.io.OutputStream; import java.net.URLEncoder; import java.util.List; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; /** * Excel报表导出工具类 @@ -34,7 +42,7 @@ */ public static void easySheet(String fileName, String sheetName, List<List<Object>> dataList, HttpServletResponse response) throws IOException { //设置响应头,输出文件 - setResponseHeader(response, fileName); + setResponseHeader2(response, fileName); HSSFWorkbook workbook = new HSSFWorkbook(); Sheet sheet = null; @@ -70,6 +78,10 @@ sheet.setDefaultColumnWidth(15);//setColumnWidth设置cell的宽度 sheet.setDefaultRowHeightInPoints(20); + // 设置单元格类型为文本类型 + HSSFDataFormat dataFormat = workbook.createDataFormat(); + style.setDataFormat(dataFormat.getFormat("@")); + //填充报表数据 for (int y = 0; y < dataList.size(); y++) { List<Object> cellList = dataList.get(y); @@ -88,6 +100,92 @@ outStream.flush(); outStream.close(); } + /** + * 简单模板excel导出功能 + * + * @param fileName 报表文件名 + * @param sheetName 报表表名 + * @param dataList 报表数据(包含行头和列内容) + * @param response + * @throws IOException + */ + public static InputStream easySheet2(String fileName, String sheetName, List<List<Object>> dataList, HttpServletResponse response) throws IOException { + //设置响应头,输出文件 + setResponseHeader2(response, fileName); + + HSSFWorkbook workbook = new HSSFWorkbook(); + Sheet sheet = null; + + HSSFCellStyle style = workbook.createCellStyle(); + // 创建字体对象 + Font ztFont = workbook.createFont(); + ztFont.setItalic(true); // 设置字体为斜体字 + ztFont.setColor(Font.COLOR_RED); // 将字体设置为“红色” + ztFont.setFontHeightInPoints((short) 22); // 将字体大小设置为18px + ztFont.setFontName("华文行楷"); // 将“华文行楷”字体应用到当前单元格上 + ztFont.setUnderline(Font.U_DOUBLE); // 添加(Font.U_SINGLE单条下划线/Font.U_DOUBLE双条下划线) + style.setFont(ztFont); // 将字体应用到样式上面 + + // 设置单元格边框样式 + style.setBorderBottom(CellStyle.BORDER_THICK); + style.setBorderTop(CellStyle.BORDER_DASHED); + style.setBorderLeft(CellStyle.BORDER_DOUBLE); + style.setBorderRight(CellStyle.BORDER_THIN); + + // 设置单元格边框颜色 + style.setBottomBorderColor(HSSFColor.ORANGE.index); + style.setTopBorderColor(HSSFColor.ORANGE.index); + style.setLeftBorderColor(HSSFColor.ORANGE.index); + + style.setFillForegroundColor(HSSFColor.SKY_BLUE.index); + style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); + style.setAlignment(HSSFCellStyle.ALIGN_CENTER); + + // 设置单元格内容垂直对其方式 + style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); + sheet = workbook.createSheet(sheetName);//设置表明 + sheet.setDefaultColumnWidth(15);//setColumnWidth设置cell的宽度 + sheet.setDefaultRowHeightInPoints(20); + + //填充报表数据 + for (int y = 0; y < dataList.size(); y++) { + List<Object> cellList = dataList.get(y); + Row row = sheet.createRow(y); + for (int x = 0; x < cellList.size(); x++) { + row.createCell(x).setCellValue(ToolUtil.toStr(cellList.get(x))); + } + } + ByteArrayOutputStream bos = null; + try { + bos = new ByteArrayOutputStream(); + workbook.write(bos); + byte[] byteArray = bos.toByteArray(); + return new ByteArrayInputStream(byteArray); + } catch (Exception e) { + e.printStackTrace(); + }finally { + if (bos != null) { + bos.flush(); + bos.close(); + } + } + /* + try { + File file = new File("F:\\DeskTop"); + if (!file.exists()) { + file.mkdirs();// 创建文件根目录 + } + String savePath = file.getPath() +"/导入失败数据.xls"; + OutputStream os = new FileOutputStream(savePath); + workbook.write(os); + os.flush(); + os.close(); + } catch (Exception e) { + e.printStackTrace(); + }*/ + return null; + } + /** * 复杂杂模板excel导出(合并单元格、设置表格样式等) @@ -270,4 +368,20 @@ e.printStackTrace(); } } + /** + * 设置响应头 + * + * @param response + */ + public static void setResponseHeader2(HttpServletResponse response, String excelName) { + response.setCharacterEncoding("utf-8"); + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-Control", "no-cache"); + try { + response.setHeader("Content-Disposition", "attachment;filename=" + excelName + URLEncoder.encode(".xls", "UTF-8")); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java b/meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java index b74fe63..bec632a 100644 --- a/meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java +++ b/meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java @@ -9,6 +9,8 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.sinata.common.enums.EnumMemberGrade; import com.sinata.common.enums.EnumPayType; import com.sinata.common.enums.EnumUserBankDetailDoneType; @@ -147,6 +149,12 @@ @Override public Object createOrder(List<BodyMallOrder> list) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + log.info("createOrder:{}", objectMapper.writeValueAsString(list)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } // 持久化数据组 List<MallOrder> orderList = new ArrayList<>(); List<MallOrderDetail> orderDetailList = new ArrayList<>(); diff --git a/meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java b/meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java index 0c53358..49bd24e 100644 --- a/meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java +++ b/meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java @@ -282,6 +282,7 @@ user.setAgentProvinceCode(province); user.setAgentCityCode(city); user.setAgentCountyCode(county); + log.info("用户:{}修改了营销员城市地址",user.getRealName()); } // user.setSignature(info.signature); // user.setAddress(info.address); diff --git a/meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java b/meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java index 13e6db8..c1fde58 100644 --- a/meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java +++ b/meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java @@ -449,6 +449,7 @@ user.setAgentCityCode(city); user.setAgentCountyCode(county); user.updateById(); + log.info("用户:{}修改了营销员城市地址",user.getRealName()); } // if (mallOrder.getUseUserId() != null && !mallOrder.getUseUserId().equals(mallOrder.getUserId())) { -- Gitblit v1.7.1