mitao
2024-06-06 3d2b51ea4520533de5e78f88dddf5b5c7dce4247
管理后台添加营销员导入功能
15个文件已修改
3个文件已添加
762 ■■■■■ 已修改文件
meiya-admin/pom.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/core/util/huawei/obs/ObsUploadUtil.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/controller/MemUserSalesController.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/dao/MemUserMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/dao/mapping/MemUserMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/model/MemUserRelation.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/service/IMemUserService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/java/com/sinata/modular/member/service/impl/MemUserServiceImpl.java 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales.html 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/webapp/WEB-INF/view/member/memUserSales/memUserSales_detail.html 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-admin/src/main/webapp/static/modular/member/memUserSales/memUserSales.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-core/src/main/java/com/sinata/core/util/ExcelExportUtil.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-rest/src/main/java/com/sinata/rest/modular/mall/service/impl/MallOrderServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-rest/src/main/java/com/sinata/rest/modular/member/controller/UserController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
meiya-rest/src/main/java/com/sinata/rest/modular/member/service/impl/MemUserServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>
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;
    }
}
meiya-admin/src/main/java/com/sinata/core/util/juhe/JuHeProperties.java
New file
@@ -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;
}
meiya-admin/src/main/java/com/sinata/core/util/juhe/SecurityAESTool.java
New file
@@ -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));
    }
}
meiya-admin/src/main/java/com/sinata/core/util/juhe/TelecomUtil.java
New file
@@ -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();
    }
}
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);
            }
    }
}
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();
}
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>
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;
    /**
     * 邀请码
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);
}
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;
    }
}
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>&nbsp;下载导入模板</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>
@}
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}')" />
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);
            }
        })
    })
});
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();
        }
    }
}
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<>();
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);
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())) {