xiaoyong931011
2022-07-27 3280d1bd977e8fb5c9c60e615612fabb7b99c3e3
20220727  保存代码
66 files added
27 files modified
5887 ■■■■■ changed files
pom.xml 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/properties/XcxProperties.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/utils/AppContants.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/utils/HttpCurlUtil.java 138 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/utils/SpringContextHolder.java 66 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/AdminGroupController.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/AdminMallOrderController.java 57 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/AdminMallTeamLeaderController.java 60 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java 36 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ApiMallMemberController.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ApiMallTeamLeaderController.java 115 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ViewGroupController.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ViewMallTeamLeaderController.java 44 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/conversion/MallTeamLeaderConversion.java 26 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/AddOrderDto.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/AdminLeaderUpdateDto.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiApplayLeaderDto.java 53 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderListDto.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderOrderConfirmDto.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderOrderListDto.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderTitleDto.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxLoginDto.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxPhoneLoginDto.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxSaveInfoDto.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/MallOrderInfoDto.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/OrderListDto.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallGroup.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallGroupJoinMember.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallTeamLeader.java 49 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallGroupMapper.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallTeamLeaderMapper.java 30 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IAdminGroupService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IAdminMallTeamLeaderService.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallTeamLeaderService.java 27 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminGroupServiceImpl.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallOrderService.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallTeamLeaderServiceImpl.java 79 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java 172 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java 21 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java 165 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/AdminMallOrderInfoVo.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/AdminMallTeamLeaderVo.java 40 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/AdminSelectListLeaderVo.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/ApiLeaderInfoVo.java 39 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/ApiLeaderListVo.java 50 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/ApiMallleaderStateVo.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/MallMemberVo.java 5 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/OrderDetailVo.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/OrderListVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/controller/XcxPayController.java 131 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/BrandWCPayRequestData.java 117 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/JsApiPayBusiness.java 141 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/JsApiPayComReqData.java 179 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/JsApiPayComResData.java 207 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/JsApiPayReqData.java 298 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/JsApiPayResData.java 232 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/NotifyData.java 145 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/RefundReqData.java 192 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/RefundResData.java 168 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/ScanPayQueryReqData.java 125 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/model/ScanPayQueryResData.java 236 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/IServiceRequest.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/IXcxPayService.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/BaseService.java 47 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/JsApiPayComService.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/JsApiPayService.java 55 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/RefundService.java 33 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/ScanPayQueryService.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/service/impl/XcxPayServiceImpl.java 93 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/MD5.java 59 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/PayThreadPool.java 46 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/RandomStringGenerator.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/Signature.java 144 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/Util.java 119 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/WebUtil.java 298 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/WechatConfigure.java 53 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/WeixinServiceUtil.java 151 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/util/XMLParser.java 84 ●●●●● patch | view | raw | blame | history
src/main/resources/application-dev.yml 9 ●●●● patch | view | raw | blame | history
src/main/resources/application-prod.yml 9 ●●●● patch | view | raw | blame | history
src/main/resources/application-test.yml 11 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberMapper.xml 7 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallOrderInfoMapper.xml 56 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallTeamLeaderMapper.xml 169 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/leader/leaderList.html 185 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/leader/leaderUpdate.html 143 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/order/orderList.html 63 ●●●●● patch | view | raw | blame | history
pom.xml
@@ -39,6 +39,17 @@
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.11.1</version>
        </dependency>
        <!-- Spring系列 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java
@@ -24,5 +24,7 @@
        registration.excludePathPatterns("/api/pay/**");
        registration.excludePathPatterns("/api/news/**");
        registration.excludePathPatterns("/api/member/cashOutSetting");
        registration.excludePathPatterns("/api/leader/leaderList");
        registration.excludePathPatterns("/api/leader/leaderTitle");
    }
}
src/main/java/cc/mrbird/febs/common/properties/XcxProperties.java
New file
@@ -0,0 +1,22 @@
package cc.mrbird.febs.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "xcx")
public class XcxProperties {
    private String wecharLoginUrl;
    private String xcxAppid;
    private String xcxSecret;
    private String wecharPaynotifyUrl;
    //测试支付的开关,true:支付0.01元
    private Boolean debug;
}
src/main/java/cc/mrbird/febs/common/utils/AppContants.java
@@ -18,6 +18,9 @@
     */
    public static final String APP_LOGIN_PREFIX = "app_";
    public static final String XCX_LOGIN_PREFIX = "xcx_";
    public static final String XCX_LOGIN_PHONE_PREFIX = "xcx_p";
    public static final String PC_LOGIN_PREFIX = "pc_";
    /**
@@ -68,4 +71,6 @@
    public static final String AGENT_LEVEL = "AGENT_LEVEL";
    public static final String AGENT_LEVEL_REQUIRE = "AGENT_LEVEL_REQUIRE";
    public static final String SIGN_MD5 = "MD5";
}
src/main/java/cc/mrbird/febs/common/utils/HttpCurlUtil.java
New file
@@ -0,0 +1,138 @@
package cc.mrbird.febs.common.utils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class HttpCurlUtil {
    /**
     * 向指定URL发送POST方法的请求
     *
     * @param url  发送请求的URL
     * @param data 请求参数,请求参数应该是json格式。
     */
    public static String sendPostHttp(String url, String data) throws HttpException, IOException {
        HttpClient httpClient = new HttpClient();
        PostMethod post = new PostMethod(url);
        post.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        post.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36");
        post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        post.setRequestHeader("Connection", "keep-alive");
        RequestEntity entity = new StringRequestEntity(data, "text/html", "utf-8");
        post.setRequestEntity(entity);
        httpClient.executeMethod(post);
        return post.getResponseBodyAsString();
    }
    /**
     * 向指定URL发送get方法的请求
     *
     * @param url  发送请求的URL
     * @param data 请求参数,请求参数应该是json格式。
     */
    public static String sendGetHttp(String url, Map<String, String> params) throws HttpException, IOException {
        if (params != null) {
            StringBuffer param = new StringBuffer();
            int i = 0;
            for (String key : params.keySet()) {
                if (i == 0)
                    param.append("?");
                else
                    param.append("&");
                param.append(key).append("=").append((String) params.get(key));
                i++;
            }
            url = url + param;
        }
        HttpClient httpClient = new HttpClient();
        GetMethod method = new GetMethod(url);
        method.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        method.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36");
        method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        method.setRequestHeader("Connection", "keep-alive");
        httpClient.executeMethod(method);
        return method.getResponseBodyAsString();
    }
    /**
     * 向指定URL发送POST请求
     * @param url 请求路径
     * @param params 请求参数
     * @return
     */
    public static String sendPost(String url, Map<String, String> params) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // POST方法
            conn.setRequestMethod("POST");
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            // 发送请求参数
            if (params != null) {
                StringBuilder param = new StringBuilder();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    if (param.length() > 0) {
                        param.append("&");
                    }
                    param.append(entry.getKey());
                    param.append("=");
                    param.append(entry.getValue());
                }
                out.write(param.toString());
            }
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result.toString();
    }
}
src/main/java/cc/mrbird/febs/common/utils/SpringContextHolder.java
New file
@@ -0,0 +1,66 @@
package cc.mrbird.febs.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * @Author wzy
 * @Date 2020/5/11
 * @email wangdoubleone@gmail.com
 * @Version V1.0
 **/
@Slf4j
@Component
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
    private static ApplicationContext applicationContext = null;
    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        assertContextInjected();
        return (T) applicationContext.getBean(name);
    }
    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(Class<T> requiredType) {
        assertContextInjected();
        return applicationContext.getBean(requiredType);
    }
    private static void assertContextInjected() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
                    ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
        }
    }
    /**
     * 检查ApplicationContext不为空.
     */
    private static void clearHolder() {
        log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
        applicationContext = null;
    }
    @Override
    public void destroy() throws Exception {
        SpringContextHolder.clearHolder();
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextHolder.applicationContext != null) {
            log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
        }
        SpringContextHolder.applicationContext = applicationContext;
    }
}
src/main/java/cc/mrbird/febs/mall/controller/AdminGroupController.java
New file
@@ -0,0 +1,20 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.controller.BaseController;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/admin/group")
public class AdminGroupController extends BaseController {
}
src/main/java/cc/mrbird/febs/mall/controller/AdminMallOrderController.java
@@ -281,6 +281,63 @@
        return null;
    }
    @GetMapping("exportOrderListOne")
    @ControllerEndpoint(operation = "订单列表", exceptionMessage = "导出失败")
    public FebsResponse exportOrderListOne(MallOrderInfo mallOrderInfo, HttpServletResponse response) throws IOException {
        List<ExcelSheetPO> res = new ArrayList<>();
        ExcelSheetPO orderSheet = new ExcelSheetPO();
        String title = "订单列表";
        orderSheet.setSheetName(title);
        orderSheet.setTitle(title);
        String[] header = {"订单编号", "订单金额", "下单时间", "配送方式", "收货姓名", "收货电话", "商品名称", "团长名称", "团长手机号码", "自提点名称","详细地址"};
        orderSheet.setHeaders(header);
        QueryRequest request = new QueryRequest();
        request.setPageNum(1);
        request.setPageSize(9999);
        List<MallOrderInfo> dataList = adminMallOrderService.findOrderListInPage(mallOrderInfo, request).getRecords();
        List<List<Object>> list = new ArrayList<>();
        if (dataList.size() > 0) {
            for (MallOrderInfo item : dataList) {
                List<Object> temp = new ArrayList<>();
                temp.add(item.getOrderNo());
                temp.add(item.getAmount());
                temp.add(DateUtil.format(item.getOrderTime(), "yyyy-MM-dd HH:mm:ss"));
                temp.add("自提");
                temp.add(item.getName());
                temp.add(item.getPhone());
                if (CollUtil.isNotEmpty(item.getItems())) {
                    StringBuilder sb = new StringBuilder();
                    for (MallOrderItem itemItem : item.getItems()) {
                        if (StrUtil.isNotBlank(sb)) {
                            sb.append(";" + itemItem.getGoodsName() + "*" + itemItem.getCnt());
                        } else {
                            sb.append(itemItem.getGoodsName() + "*" + itemItem.getCnt());
                        }
                    }
                    temp.add(sb.toString());
                } else {
                    temp.add("");
                }
                temp.add(item.getLeaderName());
                temp.add(item.getLeaderPhone());
                temp.add(item.getAddressArea());
                temp.add(item.getProvince()+item.getCity()+item.getTownship()+item.getDetailAddress());
                list.add(temp);
            }
        }
        orderSheet.setDataList(list);
        res.add(orderSheet);
        response = ResponseHeadUtil.setExcelHead(response);
        response.setHeader("Content-Disposition",
                "attachment;filename=" + URLEncoder.encode(title + DateUtil.format(new Date(), "yyyyMMDDHHmmss") + ".xlsx".trim(), "UTF-8"));
        OutputStream os = response.getOutputStream();
        ExcelUtil.createWorkbookAtOutStream(ExcelVersion.V2007, res, os, true);
        return null;
    }
    @PostMapping(value = "/importDeliver")
    @ControllerEndpoint(operation = "导入发货", exceptionMessage = "导入失败")
    public FebsResponse importDeliver(@RequestBody MultipartFile file) throws IOException {
src/main/java/cc/mrbird/febs/mall/controller/AdminMallTeamLeaderController.java
New file
@@ -0,0 +1,60 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.annotation.ControllerEndpoint;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.mall.dto.AdminLeaderUpdateDto;
import cc.mrbird.febs.mall.entity.MallGoodsCategory;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.service.IAdminMallTeamLeaderService;
import cc.mrbird.febs.mall.vo.AdminSelectListLeaderVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/admin/leader")
public class AdminMallTeamLeaderController extends BaseController {
    private final IAdminMallTeamLeaderService iAdminMallTeamLeaderService;
    /**
     * 团长信息--列表
     */
    @GetMapping("leaderList")
    public FebsResponse getLeaderList(MallTeamLeader mallTeamLeader, QueryRequest request) {
        Map<String, Object> data = getDataTable(iAdminMallTeamLeaderService.getLeaderListInPage(mallTeamLeader, request));
        return new FebsResponse().success().data(data);
    }
    /**
     * 团长信息--审核
     */
    @PostMapping("leaderUpdate")
    @ControllerEndpoint(operation = "团长信息--审核", exceptionMessage = "审核失败")
    public FebsResponse leaderUpdate(@Valid AdminLeaderUpdateDto adminLeaderUpdateDto) {
        return iAdminMallTeamLeaderService.leaderUpdate(adminLeaderUpdateDto);
    }
    /**
     * 团长信息--下拉列表
     */
    @GetMapping("selectList")
    public List<AdminSelectListLeaderVo> selectList(MallTeamLeader mallTeamLeader) {
        return iAdminMallTeamLeaderService.selectList(mallTeamLeader);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/ApiLoginController.java
@@ -1,19 +1,19 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.mall.dto.ForgetPwdDto;
import cc.mrbird.febs.mall.dto.LoginDto;
import cc.mrbird.febs.mall.dto.RegisterAppealDto;
import cc.mrbird.febs.mall.dto.RegisterDto;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.service.IApiMallMemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Dictionary;
/**
 * @author wzy
@@ -55,4 +55,32 @@
        memberService.addRegisterAppeal(registerAppeal);
        return new FebsResponse().success().message("申请成功");
    }
    /**
     * 小程序登录
     */
    @ApiOperation(value = "小程序登录", notes = "小程序登录")
    @PostMapping(value = "/xcxLogin")
    public FebsResponse xcxLogin(@RequestBody ApiXcxLoginDto apiXcxLoginDto) throws IOException {
        return memberService.xcxLogin(apiXcxLoginDto);
    }
    /**
     * 小程序手机号登录
     */
    @ApiOperation(value = "小程序手机号登录", notes = "小程序手机号登录")
    @PostMapping(value = "/xcxPhoneLogin")
    public FebsResponse xcxPhoneLogin(@RequestBody ApiXcxPhoneLoginDto apiXcxPhoneLoginDto){
        return memberService.xcxPhoneLogin(apiXcxPhoneLoginDto);
    }
    /**
     * 小程序接收用户数据,更新用户信息
     */
    @ApiOperation(value = "小程序接收用户数据", notes = "小程序接收用户数据")
    @PostMapping(value = "/xcxSaveInfo")
    public FebsResponse xcxSaveInfo(@RequestBody ApiXcxSaveInfoDto apiXcxSaveInfoDto){
        return memberService.xcxSaveInfo(apiXcxSaveInfoDto);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/ApiMallMemberController.java
@@ -35,6 +35,15 @@
    private final IMallMemberWithdrawService mallMemberWithdrawService;
    private final IApiMallMemberWalletService walletService;
    /**
     * 小程序接收用户数据,更新用户信息
     */
    @ApiOperation(value = "小程序接收用户数据", notes = "小程序接收用户数据")
    @PostMapping(value = "/xcxSaveInfo")
    public FebsResponse xcxSaveInfo(@RequestBody ApiXcxSaveInfoDto apiXcxSaveInfoDto){
        return memberService.xcxSaveInfo(apiXcxSaveInfoDto);
    }
    @ApiOperation(value = "获取商城用户信息", notes = "获取商城用户信息")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = MallMemberVo.class)
src/main/java/cc/mrbird/febs/mall/controller/ApiMallTeamLeaderController.java
New file
@@ -0,0 +1,115 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.annotation.ControllerEndpoint;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.service.IApiMallTeamLeaderService;
import cc.mrbird.febs.mall.vo.ApiLeaderInfoVo;
import cc.mrbird.febs.mall.vo.ApiLeaderListVo;
import cc.mrbird.febs.mall.vo.ApiMallleaderStateVo;
import cc.mrbird.febs.mall.vo.OrderListVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/leader")
@Api(value = "ApiMallTeamLeaderController", tags = "团长接口类")
public class ApiMallTeamLeaderController {
    private final IApiMallTeamLeaderService iApiMallTeamLeaderService;
    /**
     * 申请团长
     */
    @ApiOperation(value = "申请团长", notes = "申请团长")
    @PostMapping(value = "/applyLeader")
    public FebsResponse applyLeader(@RequestBody @Valid ApiApplayLeaderDto apiApplayLeaderDto) {
        return iApiMallTeamLeaderService.applyLeader(apiApplayLeaderDto);
    }
    /**
     * 团长列表
     */
    @ApiOperation(value = "团长列表", notes = "团长列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiLeaderListVo.class)
    })
    @PostMapping(value = "/leaderList")
    public FebsResponse leaderList(@RequestBody @Valid ApiLeaderListDto apiLeaderListDto) {
        return new FebsResponse().success().data(iApiMallTeamLeaderService.findLeaderListInPage(apiLeaderListDto));
    }
    /**
     *是否允许申请团长
     */
    @ApiOperation(value = "是否允许申请团长", notes = "是否允许申请团长")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiMallleaderStateVo.class)
    })
    @GetMapping(value = "/leaderState")
    public FebsResponse leaderState() {
        return iApiMallTeamLeaderService.leaderState();
    }
    /**
     *选择团长
     */
    @ApiOperation(value = "选择团长", notes = "选择团长")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiLeaderInfoVo.class)
    })
    @GetMapping(value = "/leaderChoose/{id}")
    public FebsResponse leaderChoose(@PathVariable(value = "id") Long id) {
        return iApiMallTeamLeaderService.getApiLeaderInfoVoById(id);
    }
    /**
     * 团长查看自提点订单列表
     */
    @ApiOperation(value = "团长查看自提点订单列表", notes = "团长查看自提点订单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = OrderListVo.class)
    })
    @PostMapping(value = "/leaderOrderList")
    public FebsResponse leaderOrderList(@RequestBody ApiLeaderOrderListDto apiLeaderOrderListDto) {
        return new FebsResponse().success().data(iApiMallTeamLeaderService.findLeaderOrderListInPage(apiLeaderOrderListDto));
    }
    /**
     * 团长点击到货确认,订单从状态 2 变更到状态 3 ,即待提货
     */
    @ApiOperation(value = "团长点击到货确认,订单从状态 2 变更到状态 3 ,即待提货", notes = "团长点击到货确认,订单从状态 2 变更到状态 3 ,即待提货")
    @PostMapping("/leaderOrderConfirm")
    public FebsResponse leaderOrderConfirm(@Valid ApiLeaderOrderConfirmDto apiLeaderOrderConfirmDto) {
        return iApiMallTeamLeaderService.leaderOrderConfirm(apiLeaderOrderConfirmDto);
    }
    /**
     * 商品列表页的团长信息
     * 有团长特征码直接显示该团长,
     * 有经纬度,按照经纬度选择距离最近的
     * 没有选择团长列表的第一个
     */
    @ApiOperation(value = "商品列表页的团长信息", notes = "商品列表页的团长信息")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiLeaderInfoVo.class)
    })
    @PostMapping("/leaderTitle")
    public FebsResponse leaderTitle(@RequestBody ApiLeaderTitleDto apiLeaderTitleDto) {
        return iApiMallTeamLeaderService.leaderTitle(apiLeaderTitleDto);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/ViewGroupController.java
New file
@@ -0,0 +1,13 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsConstant;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller("groupView")
@RequestMapping(FebsConstant.VIEW_PREFIX + "modules/group")
@RequiredArgsConstructor
public class ViewGroupController extends BaseController {
}
src/main/java/cc/mrbird/febs/mall/controller/ViewMallTeamLeaderController.java
New file
@@ -0,0 +1,44 @@
package cc.mrbird.febs.mall.controller;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsConstant;
import cc.mrbird.febs.common.utils.FebsUtil;
import cc.mrbird.febs.mall.service.IAdminMallOrderService;
import cc.mrbird.febs.mall.service.IAdminMallTeamLeaderService;
import cc.mrbird.febs.mall.vo.AdminMallOrderVo;
import cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller("leaderView")
@RequestMapping(FebsConstant.VIEW_PREFIX + "modules/leader")
@RequiredArgsConstructor
public class ViewMallTeamLeaderController extends BaseController {
    private final IAdminMallTeamLeaderService iAdminMallTeamLeaderService;
    /**
     * 团长信息--列表
     */
    @GetMapping("leaderList")
    @RequiresPermissions("leaderList:view")
    public String leaderList() {
        return FebsUtil.view("modules/leader/leaderList");
    }
    /**
     * 团长信息-审核
     */
    @GetMapping("leaderUpdate/{id}")
    @RequiresPermissions("leaderUpdate:update")
    public String leaderUpdate(@PathVariable long id, Model model) {
        AdminMallTeamLeaderVo data = iAdminMallTeamLeaderService.getMallTeamLederInfoById(id);
        model.addAttribute("leaderInfo", data);
        return FebsUtil.view("modules/leader/leaderUpdate");
    }
}
src/main/java/cc/mrbird/febs/mall/conversion/MallTeamLeaderConversion.java
New file
@@ -0,0 +1,26 @@
package cc.mrbird.febs.mall.conversion;
import cc.mrbird.febs.mall.dto.ApiApplayLeaderDto;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo;
import cc.mrbird.febs.mall.vo.ApiLeaderInfoVo;
import cc.mrbird.febs.mall.vo.ApiLeaderListVo;
import cc.mrbird.febs.mall.vo.OrderDetailVo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public abstract class MallTeamLeaderConversion {
    public static final MallTeamLeaderConversion INSTANCE = Mappers.getMapper(MallTeamLeaderConversion.class);
    public abstract MallTeamLeader dtoToEntity(ApiApplayLeaderDto apiApplayLeaderDto);
    public abstract List<ApiLeaderListVo> entitysToVos(List<MallTeamLeader> mallTeamLeaders);
    public abstract AdminMallTeamLeaderVo entityToVo(MallTeamLeader mallTeamLeaders);
}
src/main/java/cc/mrbird/febs/mall/dto/AddOrderDto.java
@@ -19,6 +19,12 @@
    @ApiModelProperty(value = "地址ID", example = "1")
    private Long addressId;
    @ApiModelProperty(value = "提货团长特征码", example = "1")
    private String takeUniqueCode;
//    @ApiModelProperty(value = "配送方式 1:自提 2:快递(默认自提)", example = "1")
//    private Integer deliveryType;
    @ApiModelProperty(value = "订单提交类型", example = "1从购物车提交, 2从商品直接提交")
    private Integer type;
src/main/java/cc/mrbird/febs/mall/dto/AdminLeaderUpdateDto.java
New file
@@ -0,0 +1,16 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "AdminLeaderUpdateDto", description = "接收参数类")
public class AdminLeaderUpdateDto {
    @NotNull(message = "ID不能为空")
    private Long id;
    @NotNull(message = "审核结果不能为空")
    private int isOk;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiApplayLeaderDto.java
New file
@@ -0,0 +1,53 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel(value = "ApiApplayLeaderDto", description = "参数接收类")
public class ApiApplayLeaderDto {
    //团长姓名
    @NotBlank(message = "姓名不能为空")
    @ApiModelProperty(value = "团长姓名")
    private String name;
    //手机号码
    @NotBlank(message = "手机号码不能为空")
    @ApiModelProperty(value = "手机号码")
    private String phone;
    //自提点照片
    @NotBlank(message = "自提点照片不能为空")
    @ApiModelProperty(value = "自提点照片")
    private String addressPic;
    //省
    @NotBlank(message = "省不能为空")
    @ApiModelProperty(value = "省")
    private String province;
    //市
    @NotBlank(message = "市不能为空")
    @ApiModelProperty(value = "市")
    private String city;
    //区
    @NotBlank(message = "区不能为空")
    @ApiModelProperty(value = "区")
    private String township;
    //小区名称
    @NotBlank(message = "小区名称(自提点名称)不能为空")
    @ApiModelProperty(value = "小区名称(自提点名称)")
    private String addressArea;
    //详细地址
    @NotBlank(message = "详细地址不能为空")
    @ApiModelProperty(value = "详细地址")
    private String detailAddress;
    //经度
    @NotBlank(message = "经度不能为空")
    @ApiModelProperty(value = "经度")
    private Double longitude;
    //纬度
    @NotBlank(message = "纬度不能为空")
    @ApiModelProperty(value = "纬度")
    private Double latitude;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderListDto.java
New file
@@ -0,0 +1,31 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "ApiLeaderListDto", description = "参数接收类")
public class ApiLeaderListDto {
    @ApiModelProperty(value = "第几页", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "每页数量", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "团长姓名,电话,自提地址", example = "123")
    private String query;
    @ApiModelProperty(value = "经度", example = "123")
    @NotNull(message = "请选择您的地址")
    private Double longitude;
    @ApiModelProperty(value = "纬度", example = "123")
    @NotNull(message = "请选择您的地址")
    private Double latitude;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderOrderConfirmDto.java
New file
@@ -0,0 +1,15 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel(value = "ApiLeaderOrderConfirmDto", description = "参数接收类")
public class ApiLeaderOrderConfirmDto {
    @NotBlank(message = "订单编号不能为空")
    private String orderNo;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderOrderListDto.java
New file
@@ -0,0 +1,29 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ApiLeaderOrderListDto", description = "参数接收类")
public class ApiLeaderOrderListDto {
    @ApiModelProperty(value = "一页数量", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "第几页", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "搜索参数(姓名,电话,提货码)", example = "1")
    private String query;
    @ApiModelProperty(value = "订单状态", example = "0-全部 1-待付款 2-待发货(待确认) 3-待收货(待提货) 4-已完成 5-已取消")
    private Integer status;
    @ApiModelProperty(hidden = true)
    private Long memberId;
    @ApiModelProperty(value = "1-普通订单, 2-积分订单", example = "1")
    private Integer orderType;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiLeaderTitleDto.java
New file
@@ -0,0 +1,22 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "ApiLeaderTitleDto", description = "参数接收类")
public class ApiLeaderTitleDto {
    @ApiModelProperty(value = "团长特征码", example = "1")
    private String uniqueCode;
    @ApiModelProperty(value = "经度", example = "123")
    private Double longitude;
    @ApiModelProperty(value = "纬度", example = "123")
    private Double latitude;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxLoginDto.java
New file
@@ -0,0 +1,12 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel(value = "ApiXcxLoginDto", description = "小程序登录")
public class ApiXcxLoginDto {
    private String code;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxPhoneLoginDto.java
New file
@@ -0,0 +1,16 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ApiXcxPhoneLoginDto", description = "小程序登录")
public class ApiXcxPhoneLoginDto {
    @ApiModelProperty(value = "手机号" )
    private String phone;
    @ApiModelProperty(value = "验证码" )
    private String code;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxSaveInfoDto.java
New file
@@ -0,0 +1,23 @@
package cc.mrbird.febs.mall.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ApiXcxSaveInfoDto", description = "小程序接收用户数据")
public class ApiXcxSaveInfoDto {
    @ApiModelProperty(value = "手机号码" )
    private String phone;
    @ApiModelProperty(value = "昵称" )
    private String nickName;
    @ApiModelProperty(value = "头像" )
    private String avatarUrl;
    @ApiModelProperty(value = "性别" )
    private Integer gender;
}
src/main/java/cc/mrbird/febs/mall/dto/MallOrderInfoDto.java
@@ -24,4 +24,8 @@
    private String name;
    private Integer orderType;
    //配送方式 1:自提 2:快递
    private Integer deliveryType;
    private String uniqueCode;
}
src/main/java/cc/mrbird/febs/mall/dto/OrderListDto.java
@@ -18,10 +18,10 @@
    @ApiModelProperty(value = "第几页", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "搜索参数", example = "1")
    @ApiModelProperty(value = "搜索参数(姓名,电话,提货码)", example = "1")
    private String query;
    @ApiModelProperty(value = "订单状态", example = "0-全部 1-待付款 2-待发货 3-待收货 4-已完成 5-已取消")
    @ApiModelProperty(value = "订单状态", example = "0-全部 1-待付款 2-待发货(待确认) 3-待收货(待提货) 4-已完成 5-已取消")
    private Integer status;
    @ApiModelProperty(hidden = true)
src/main/java/cc/mrbird/febs/mall/entity/MallGroup.java
New file
@@ -0,0 +1,29 @@
package cc.mrbird.febs.mall.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("mall_group")
public class MallGroup extends BaseEntity {
    //商品Id
    private Long goodsId;
    //平团是否成功 1:进行中 2:平团成功 3:已取消
    private Integer groupState;
    //开团时间
    private Date beginTime;
    //最晚结束时间
    private Date endTime;
    //拼团价格
    private String groupPrice;
    //拼团成功要求人数
    private Integer groupTeamNum;
    //团长ID
    private Long headMemberId;
}
src/main/java/cc/mrbird/febs/mall/entity/MallGroupJoinMember.java
New file
@@ -0,0 +1,25 @@
package cc.mrbird.febs.mall.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("mall_group_join_member")
public class MallGroupJoinMember {
    //团购信息表ID
    private Long groupId;
    //订单ID
    private Long orderId;
    //是否已支付 1-是 2-否
    private Long isHasPay;
    //支付结束时间
    private Date payEndTime;
    //是否已取消 1-是 2-否
    private Long isHasCancel;
    //用户ID
    private Long memberId;
}
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -134,4 +134,14 @@
     */
    private Integer storeMaster;
    /**
     * 微信用户标识
     */
    private String openId;
    /**
     * 会话密钥
     */
    private String sessionKey;
}
src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java
@@ -3,6 +3,7 @@
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@@ -87,4 +88,37 @@
     */
    public static final Integer COMMENT_STATE_NO = 1;
    public static final Integer COMMENT_STATE_YES = 2;
    //提货团长特征码
    private String takeUniqueCode;
    //提货码
    private String takeCode;
    //配送方式 1:自提 2:快递
    private Integer deliveryType;
    /**
     * 自提点信息
     */
    @TableField(exist = false)
    private String leaderName;
    @TableField(exist = false)
    private String leaderPhone;
    @TableField(exist = false)
    private String addressPic;
    @TableField(exist = false)
    private String province;
    @TableField(exist = false)
    private String city;
    @TableField(exist = false)
    private String township;
    @TableField(exist = false)
    private String addressArea;
    @TableField(exist = false)
    private String detailAddress;
    /**
     * 微信订单编号
     */
    private String wxOrderNo;
}
src/main/java/cc/mrbird/febs/mall/entity/MallTeamLeader.java
New file
@@ -0,0 +1,49 @@
package cc.mrbird.febs.mall.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
//团长信息表
@Data
@TableName("mall_team_leader")
public class MallTeamLeader extends BaseEntity {
    //用户ID
    private Long memberId;
    //申请状态 1:审核通过 2:审核不通过 3:申请中
    private Integer state;
    public static final Integer STATE_YES = 1;
    public static final Integer STATE_NO = 2;
    public static final Integer STATE_ING = 3;
    //团长姓名
    private String name;
    //手机号码
    private String phone;
    //团长特征码
    private String uniqueCode;
    //自提点照片
    private String addressPic;
    //省
    private String province;
    //市
    private String city;
    //区
    private String township;
    //小区名称
    private String addressArea;
    //详细地址
    private String detailAddress;
    //经度
    private Double longitude;
    //纬度
    private Double latitude;
    @TableField(exist = false)
    private Double distance;
}
src/main/java/cc/mrbird/febs/mall/mapper/MallGroupMapper.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.mall.mapper;
import cc.mrbird.febs.mall.entity.MallGroup;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MallGroupMapper  extends BaseMapper<MallGroup> {
}
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
@@ -85,4 +85,6 @@
    List<MallMember> selectDirectorsOrStoreMaster(@Param("type") Integer type);
    List<MallMember> selectMemberWithLevel(String level);
    MallMember selectMemberByOpenId(@Param("openId")String openId);
}
src/main/java/cc/mrbird/febs/mall/mapper/MallTeamLeaderMapper.java
New file
@@ -0,0 +1,30 @@
package cc.mrbird.febs.mall.mapper;
import cc.mrbird.febs.mall.dto.ApiLeaderListDto;
import cc.mrbird.febs.mall.dto.ApiLeaderOrderListDto;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MallTeamLeaderMapper extends BaseMapper<MallTeamLeader> {
    IPage<AdminMallTeamLeaderVo> selectLeaderListInPage(Page<AdminMallTeamLeaderVo> page, @Param("record")MallTeamLeader mallTeamLeader);
    IPage<MallTeamLeader> selectApiLeaderListInPage(Page<MallTeamLeader> page, @Param("record")ApiLeaderListDto apiLeaderListDto);
    List<MallTeamLeader> selectListByMemberIdAndState(@Param("memberId")Long memberId, @Param("state")Integer stateIng);
    IPage<MallOrderInfo> selectApiLeaderOrderListInPage(IPage<MallOrderInfo> page, @Param("record")ApiLeaderOrderListDto apiLeaderOrderListDto);
    List<MallTeamLeader> getMallTeamLeaderList();
    MallTeamLeader selectLeaderByUniqueCode(@Param("uniqueCode")String uniqueCode);
    MallTeamLeader selectLeaderByLonAndLat(@Param("longitude")Double longitude, @Param("latitude")Double latitude);
}
src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java
@@ -2,6 +2,7 @@
import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
@@ -25,6 +26,9 @@
    @Autowired
    private MallOrderInfoMapper orderInfoMapper;
    @Autowired
    private MallMemberMapper mallMemberMapper;
    @Scheduled(cron = "0 0/5 * * * ? ")
    public void overtimeJob() {
        log.info("订单超时任务执行");
@@ -42,4 +46,11 @@
        }
    }
    @Scheduled(cron = "0/5 * * * * ? ")
    public void wakeup() {
        log.info("本地保持唤醒状态");
        Long id = 5L;
        mallMemberMapper.selectById(id);
    }
}
src/main/java/cc/mrbird/febs/mall/service/IAdminGroupService.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.mall.service;
import cc.mrbird.febs.mall.entity.MallGroup;
import com.baomidou.mybatisplus.extension.service.IService;
public interface IAdminGroupService extends IService<MallGroup> {
}
src/main/java/cc/mrbird/febs/mall/service/IAdminMallTeamLeaderService.java
New file
@@ -0,0 +1,23 @@
package cc.mrbird.febs.mall.service;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.mall.dto.AdminLeaderUpdateDto;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo;
import cc.mrbird.febs.mall.vo.AdminSelectListLeaderVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface IAdminMallTeamLeaderService extends IService<MallTeamLeader> {
    IPage<AdminMallTeamLeaderVo> getLeaderListInPage(MallTeamLeader mallTeamLeader, QueryRequest request);
    AdminMallTeamLeaderVo getMallTeamLederInfoById(long id);
    FebsResponse leaderUpdate(AdminLeaderUpdateDto adminLeaderUpdateDto);
    List<AdminSelectListLeaderVo> selectList(MallTeamLeader mallTeamLeader);
}
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java
@@ -11,6 +11,7 @@
import cc.mrbird.febs.mall.vo.ShopListVo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
@@ -64,4 +65,10 @@
    CashOutSettingVo cashOutSetting();
    List<ShopListVo> findShopListVo(ShopListDto shopListDto);
    FebsResponse xcxLogin(ApiXcxLoginDto apiXcxLoginDto) throws IOException;
    FebsResponse xcxSaveInfo(ApiXcxSaveInfoDto apiXcxSaveInfoDto);
    FebsResponse xcxPhoneLogin(ApiXcxPhoneLoginDto apiXcxPhoneLoginDto);
}
src/main/java/cc/mrbird/febs/mall/service/IApiMallTeamLeaderService.java
New file
@@ -0,0 +1,27 @@
package cc.mrbird.febs.mall.service;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.vo.ApiLeaderListVo;
import cc.mrbird.febs.mall.vo.OrderListVo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface IApiMallTeamLeaderService extends IService<MallTeamLeader> {
    FebsResponse applyLeader(ApiApplayLeaderDto apiApplayLeaderDto);
    List<ApiLeaderListVo> findLeaderListInPage(ApiLeaderListDto apiLeaderListDto);
    FebsResponse leaderState();
    FebsResponse getApiLeaderInfoVoById(Long id);
    List<OrderListVo> findLeaderOrderListInPage(ApiLeaderOrderListDto apiLeaderOrderListDto);
    FebsResponse leaderOrderConfirm(ApiLeaderOrderConfirmDto apiLeaderOrderConfirmDto);
    FebsResponse leaderTitle(ApiLeaderTitleDto apiLeaderTitleDto);
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminGroupServiceImpl.java
New file
@@ -0,0 +1,17 @@
package cc.mrbird.febs.mall.service.impl;
import cc.mrbird.febs.mall.entity.MallGroup;
import cc.mrbird.febs.mall.mapper.MallGroupMapper;
import cc.mrbird.febs.mall.service.IAdminGroupService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class AdminGroupServiceImpl extends ServiceImpl<MallGroupMapper, MallGroup> implements IAdminGroupService {
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallOrderService.java
@@ -83,6 +83,10 @@
        if(2 != status){
            return new FebsResponse().fail().message("订单不是待发货状态");
        }
        Integer deliveryType = mallOrderInfo.getDeliveryType();
        if(2 != deliveryType){
            return new FebsResponse().fail().message("订单的配送方式不是快递");
        }
        String expressNo = deliverGoodsDto.getExpressNo();
        if(StrUtil.isEmpty(expressNo)){
            return new FebsResponse().fail().message("请输入物流单号");
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallTeamLeaderServiceImpl.java
New file
@@ -0,0 +1,79 @@
package cc.mrbird.febs.mall.service.impl;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.mall.conversion.MallTeamLeaderConversion;
import cc.mrbird.febs.mall.dto.AdminLeaderUpdateDto;
import cc.mrbird.febs.mall.entity.MallGoodsCategory;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.mapper.MallTeamLeaderMapper;
import cc.mrbird.febs.mall.service.IAdminMallTeamLeaderService;
import cc.mrbird.febs.mall.vo.AdminMallActSetVo;
import cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo;
import cc.mrbird.febs.mall.vo.AdminSelectListLeaderVo;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class AdminMallTeamLeaderServiceImpl extends ServiceImpl<MallTeamLeaderMapper, MallTeamLeader> implements IAdminMallTeamLeaderService {
    @Override
    public IPage<AdminMallTeamLeaderVo> getLeaderListInPage(MallTeamLeader mallTeamLeader, QueryRequest request) {
        Page<AdminMallTeamLeaderVo> page = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<AdminMallTeamLeaderVo> adminMallActSetVos = this.baseMapper.selectLeaderListInPage(page, mallTeamLeader);
        return adminMallActSetVos;
    }
    @Override
    public AdminMallTeamLeaderVo getMallTeamLederInfoById(long id) {
        MallTeamLeader mallTeamLeader = this.baseMapper.selectById(id);
        AdminMallTeamLeaderVo adminMallTeamLeaderVo = MallTeamLeaderConversion.INSTANCE.entityToVo(mallTeamLeader);
        return adminMallTeamLeaderVo;
    }
    @Override
    public FebsResponse leaderUpdate(AdminLeaderUpdateDto adminLeaderUpdateDto) {
        Long id = adminLeaderUpdateDto.getId();
        MallTeamLeader mallTeamLeader = this.baseMapper.selectById(id);
        Integer state = mallTeamLeader.getState();
        if(MallTeamLeader.STATE_ING != state){
            return new FebsResponse().fail().message("只有【待审核】状态才能提交!");
        }
        int isOk = adminLeaderUpdateDto.getIsOk();
        if(MallTeamLeader.STATE_YES == isOk){
            mallTeamLeader.setState(MallTeamLeader.STATE_YES);
            this.baseMapper.updateById(mallTeamLeader);
        }
        if(MallTeamLeader.STATE_NO == isOk){
            mallTeamLeader.setState(MallTeamLeader.STATE_NO);
            this.baseMapper.updateById(mallTeamLeader);
        }
        return new FebsResponse().success().message("审核成功");
    }
    @Override
    public List<AdminSelectListLeaderVo> selectList(MallTeamLeader mallTeamLeader) {
        List<AdminSelectListLeaderVo> list = new ArrayList<>();
        List<MallTeamLeader> mallTeamLeaders = this.baseMapper.getMallTeamLeaderList();
        if(CollUtil.isNotEmpty(mallTeamLeaders)){
            for(MallTeamLeader teamLeader : mallTeamLeaders){
                AdminSelectListLeaderVo adminSelectListLeaderVo = new AdminSelectListLeaderVo();
                adminSelectListLeaderVo.setUniqueCode(teamLeader.getUniqueCode());
                adminSelectListLeaderVo.setName(teamLeader.getName());
                list.add(adminSelectListLeaderVo);
            }
        }
        return list;
    }
}
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -6,6 +6,7 @@
import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.properties.XcxProperties;
import cc.mrbird.febs.common.utils.*;
import cc.mrbird.febs.mall.conversion.MallMemberConversion;
import cc.mrbird.febs.mall.conversion.MallShopApplyConversion;
@@ -31,10 +32,12 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
@@ -58,6 +61,7 @@
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    private final MallShopApplyMapper mallShopApplyMapper;
    private final MallRegisterAppealMapper mallRegisterAppealMapper;
    private final MallTeamLeaderMapper mallTeamLeaderMapper;
    @Value("${spring.profiles.active}")
@@ -213,7 +217,8 @@
    @Override
    public FebsResponse logout() {
        Long id = LoginUserUtil.getLoginUser().getId();
        redisUtils.del(AppContants.APP_LOGIN_PREFIX + id);
        redisUtils.del(AppContants.XCX_LOGIN_PREFIX + id);
        redisUtils.del(AppContants.XCX_LOGIN_PHONE_PREFIX + id);
        return new FebsResponse().success().message("退出登录");
    }
@@ -238,15 +243,23 @@
            mallMemberVo.setHasPayment(1);
        }
        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.AGENT_LEVEL, mallMember.getLevel());
        if (dic != null) {
            mallMemberVo.setLevelName(dic.getDescription());
        }
//        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.AGENT_LEVEL, mallMember.getLevel());
//        if (dic != null) {
//            mallMemberVo.setLevelName(dic.getDescription());
//        }
        MallMemberWallet wallet = mallMemberWalletMapper.selectWalletByMemberId(mallMemberVo.getId());
        mallMemberVo.setBalance(wallet.getBalance());
        mallMemberVo.setScore(wallet.getScore());
        mallMemberVo.setPrizeScore(wallet.getPrizeScore());
        mallMemberVo.setTotalCost(mallOrderInfoMapper.selectTotalAmount(id));
        //用户是否是团长
        List<MallTeamLeader> mallTeamLeaders = mallTeamLeaderMapper.selectListByMemberIdAndState(mallMember.getId(), MallTeamLeader.STATE_YES);
        if(CollUtil.isNotEmpty(mallTeamLeaders)){
            mallMemberVo.setIsTeamLeader(1);
        }else{
            mallMemberVo.setIsTeamLeader(2);
        }
        return new FebsResponse().success().data(mallMemberVo);
    }
@@ -542,4 +555,153 @@
        }
        return MallShopApplyConversion.INSTANCE.entitiesToVOs(list);
    }
    private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class);
    @Override
    public FebsResponse xcxLogin(ApiXcxLoginDto apiXcxLoginDto) throws IOException {
        FebsResponse febsResponse = new FebsResponse();
        String code = apiXcxLoginDto.getCode();
        log.info("code:" + code);
        if (StrUtil.isNotBlank(code)) {
            String requrl = getXcxLoginUrl(code);
            String reslutData = HttpCurlUtil.sendGetHttp(requrl, null);
            net.sf.json.JSONObject json = net.sf.json.JSONObject.fromObject(reslutData);
            log.info("微信登录获取到登录信息={}", json);
            if (json.containsKey("errcode")) {
                log.info("微信登录获取到异常信息errcode");
                return febsResponse.fail().message("自动登录失败");
            }
            String openId = json.getString("openid");
            String sessionKey = json.getString("session_key");
            log.info("openId={},sessionKey={}", openId, sessionKey);
            // 查询用户是否存在
            MallMember mallMember = null;
            synchronized (this) {
                mallMember = this.baseMapper.selectMemberByOpenId(openId);
                if (ObjectUtil.isEmpty(mallMember)) {
                    // 新增用户
                    mallMember = new MallMember();
                    mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
                    mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
                    mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name());
                    mallMember.setOpenId(openId);
                    mallMember.setSessionKey(sessionKey);
                    this.baseMapper.insert(mallMember);
                    mallMember = this.baseMapper.selectMemberByOpenId(openId);
                    String inviteId = ShareCodeUtil.toSerialCode(mallMember.getId());
                    mallMember.setInviteId(inviteId);
                    this.baseMapper.updateById(mallMember);
                    MallMemberWallet wallet = new MallMemberWallet();
                    wallet.setBalance(BigDecimal.ZERO);
                    wallet.setMemberId(mallMember.getId());
                    mallMemberWalletMapper.insert(wallet);
                } else {
                    mallMember.setSessionKey(sessionKey);
                    this.baseMapper.updateById(mallMember);
                }
            }
            // 存放redis
            String redisKey = AppContants.XCX_LOGIN_PREFIX + mallMember.getId();
            String existToken = redisUtils.getString(redisKey);
            if (StrUtil.isNotBlank(existToken)) {
                Object o = redisUtils.get(existToken);
                if (ObjectUtil.isNotEmpty(o)) {
                    redisUtils.del(existToken);
                }
            }
            String token = IdUtil.simpleUUID();
            redisUtils.set(token, JSONObject.toJSONString(mallMember), 360000);
            redisUtils.set(redisKey, token, 360000);
            Map<String, Object> authInfo = new HashMap<>();
            authInfo.put("token", token);
            authInfo.put("appid", xcxProperties.getXcxAppid());
            authInfo.put("member", mallMember);
            authInfo.put("rasToken", generateAsaToken(token));
            febsResponse.success().data(authInfo);
        } else {
            return febsResponse.fail().message("自动登录失败");
        }
        return febsResponse;
    }
    @Override
    public FebsResponse xcxSaveInfo(ApiXcxSaveInfoDto apiXcxSaveInfoDto) {
        log.info("name={},phone={},avatar={},sex={}",
                apiXcxSaveInfoDto.getNickName(),apiXcxSaveInfoDto.getPhone(),apiXcxSaveInfoDto.getAvatarUrl(),apiXcxSaveInfoDto.getGender());
        Long memberId = LoginUserUtil.getLoginUser().getId();
        MallMember mallMember = this.baseMapper.selectById(memberId);
        String nickName = apiXcxSaveInfoDto.getNickName();
        if(StrUtil.isNotEmpty(nickName)){
            mallMember.setName(nickName);
        }
        String phone = apiXcxSaveInfoDto.getPhone();
        if(StrUtil.isNotEmpty(phone)){
            mallMember.setPhone(phone);
        }
        String avatarUrl = apiXcxSaveInfoDto.getAvatarUrl();
        if(StrUtil.isNotEmpty(avatarUrl)){
            mallMember.setAvatar(avatarUrl);
        }
        mallMember.setSex(apiXcxSaveInfoDto.getGender() == 1 ? "女" : "男");
        this.baseMapper.updateById(mallMember);
        return new FebsResponse().success();
    }
    @Override
    public FebsResponse xcxPhoneLogin(ApiXcxPhoneLoginDto apiXcxPhoneLoginDto) {
        String phone = apiXcxPhoneLoginDto.getPhone();
        boolean flag = commonService.verifyCode(phone, apiXcxPhoneLoginDto.getCode());
        if (flag) {
            // 查询用户是否存在
            MallMember mallMember = null;
            synchronized (this) {
                mallMember = this.baseMapper.selectInfoByAccount(apiXcxPhoneLoginDto.getPhone());
                if (ObjectUtil.isEmpty(mallMember)) {
                    // 新增用户
                    mallMember = new MallMember();
                    mallMember.setPhone(phone);
                    mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
                    mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
                    mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name());
                    this.baseMapper.insert(mallMember);
                    String inviteId = ShareCodeUtil.toSerialCode(mallMember.getId());
                    mallMember.setInviteId(inviteId);
                    this.baseMapper.updateById(mallMember);
                    MallMemberWallet wallet = new MallMemberWallet();
                    wallet.setBalance(BigDecimal.ZERO);
                    wallet.setMemberId(mallMember.getId());
                    mallMemberWalletMapper.insert(wallet);
                }
            }
            // 存放redis
            String redisKey = AppContants.XCX_LOGIN_PHONE_PREFIX + mallMember.getId();
            String existToken = redisUtils.getString(redisKey);
            if (StrUtil.isNotBlank(existToken)) {
                Object o = redisUtils.get(existToken);
                if (ObjectUtil.isNotEmpty(o)) {
                    redisUtils.del(existToken);
                }
            }
            String token = IdUtil.simpleUUID();
            redisUtils.set(token, JSONObject.toJSONString(mallMember), 360000);
            redisUtils.set(redisKey, token, 360000);
            Map<String, Object> authInfo = new HashMap<>();
            authInfo.put("token", token);
            authInfo.put("member", mallMember);
            authInfo.put("rasToken", generateAsaToken(token));
            return new FebsResponse().success().message("登陆成功");
        }
        return new FebsResponse().fail().message("验证码错误");
    }
    private  String getXcxLoginUrl(String code) {
        String wechatLoginUrl =xcxProperties.getWecharLoginUrl();
        return String.format(wechatLoginUrl, xcxProperties.getXcxAppid(), xcxProperties.getXcxSecret(), code);
    }
}
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
@@ -2,10 +2,7 @@
import cc.mrbird.febs.common.enumerates.*;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.AppContants;
import cc.mrbird.febs.common.utils.LoginUserUtil;
import cc.mrbird.febs.common.utils.MallUtils;
import cc.mrbird.febs.common.utils.RedisUtils;
import cc.mrbird.febs.common.utils.*;
import cc.mrbird.febs.mall.conversion.MallGoodsCommentConversion;
import cc.mrbird.febs.mall.conversion.MallOrderInfoConversion;
import cc.mrbird.febs.mall.conversion.MallOrderRefundConversion;
@@ -16,7 +13,9 @@
import cc.mrbird.febs.mall.vo.OrderDetailVo;
import cc.mrbird.febs.mall.vo.OrderListVo;
import cc.mrbird.febs.mall.vo.OrderRefundVo;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.service.IPayService;
import cc.mrbird.febs.pay.service.IXcxPayService;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
@@ -60,6 +59,7 @@
    private final AgentProducer agentProducer;
    private final IPayService payService;
    private final IXcxPayService iXcxPayService;
    private final IMallAchieveService mallAchieveService;
    @Override
@@ -85,6 +85,9 @@
        orderInfo.setLongitude(address.getLongitude());
        orderInfo.setRemark(addOrderDto.getRemark());
        orderInfo.setOrderType(addOrderDto.getOrderType());
        orderInfo.setTakeUniqueCode(addOrderDto.getTakeUniqueCode());
        orderInfo.setDeliveryType(1);
        if (CollUtil.isEmpty(addOrderDto.getItems())) {
            throw new FebsException("参数错误");
@@ -216,6 +219,13 @@
            case "1":
//                orderInfo.setPayOrderNo(payOrderDto.getPayOrderNo());
//                orderInfo.setPayImage(payOrderDto.getPayImage());
                BrandWCPayRequestData brandWCPayRequestData = null;
                try {
                    brandWCPayRequestData = iXcxPayService.startPayment(orderInfo);
                } catch (Exception e) {
                    throw new FebsException("支付失败");
                }
                payResultStr = brandWCPayRequestData.getPrepay_id();
                orderInfo.setPayMethod("微信支付");
                agentProducer.sendOrderReturn(orderInfo.getId());
                break;
@@ -294,6 +304,9 @@
            default:
        }
        //订单支付成功产生一个提货码
        String takeCode = ShareCodeUtil.toSerialCode(orderInfo.getId());
        orderInfo.setTakeCode(takeCode);
        this.baseMapper.updateById(orderInfo);
        Map<String, Object> map = new HashMap<>();
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java
New file
@@ -0,0 +1,165 @@
package cc.mrbird.febs.mall.service.impl;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
import cc.mrbird.febs.common.utils.LoginUserUtil;
import cc.mrbird.febs.common.utils.ShareCodeUtil;
import cc.mrbird.febs.mall.conversion.MallOrderInfoConversion;
import cc.mrbird.febs.mall.conversion.MallTeamLeaderConversion;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.entity.MallExpressInfo;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.entity.MallTeamLeader;
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
import cc.mrbird.febs.mall.mapper.MallTeamLeaderMapper;
import cc.mrbird.febs.mall.service.IApiMallTeamLeaderService;
import cc.mrbird.febs.mall.vo.ApiLeaderInfoVo;
import cc.mrbird.febs.mall.vo.ApiLeaderListVo;
import cc.mrbird.febs.mall.vo.ApiMallleaderStateVo;
import cc.mrbird.febs.mall.vo.OrderListVo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class ApiMallTeamLeaderServiceImpl extends ServiceImpl<MallTeamLeaderMapper, MallTeamLeader> implements IApiMallTeamLeaderService {
    @Override
    @Transactional
    public FebsResponse applyLeader(ApiApplayLeaderDto apiApplayLeaderDto) {
        MallMember member = LoginUserUtil.getLoginUser();
        Long memberId = member.getId();
        List<MallTeamLeader> mallTeamLeaders = this.baseMapper.selectListByMemberIdAndState(memberId, MallTeamLeader.STATE_ING);
        if(CollUtil.isNotEmpty(mallTeamLeaders)){
            return new FebsResponse().fail().message("正在申请中");
        }
        MallTeamLeader mallTeamLeader = MallTeamLeaderConversion.INSTANCE.dtoToEntity(apiApplayLeaderDto);
        mallTeamLeader.setMemberId(memberId);
        mallTeamLeader.setState(MallTeamLeader.STATE_ING);
        mallTeamLeader.setUniqueCode(member.getInviteId());
        this.baseMapper.insert(mallTeamLeader);
        return new FebsResponse().success().message("申请成功");
    }
    @Override
    public List<ApiLeaderListVo> findLeaderListInPage(ApiLeaderListDto apiLeaderListDto) {
        Page<MallTeamLeader> page = new Page<>(apiLeaderListDto.getPageNum(), apiLeaderListDto.getPageSize());
        IPage<MallTeamLeader> mallTeamLeaderIPage = this.baseMapper.selectApiLeaderListInPage(page, apiLeaderListDto);
        return MallTeamLeaderConversion.INSTANCE.entitysToVos(mallTeamLeaderIPage.getRecords());
    }
    @Override
    public FebsResponse leaderState() {
        MallMember member = LoginUserUtil.getLoginUser();
        Long memberId = member.getId();
        ApiMallleaderStateVo apiMallleaderStateVo = new ApiMallleaderStateVo();
        List<MallTeamLeader> mallTeamLeadersIng = this.baseMapper.selectListByMemberIdAndState(memberId, MallTeamLeader.STATE_ING);
        List<MallTeamLeader> mallTeamLeadersNo = this.baseMapper.selectListByMemberIdAndState(memberId, MallTeamLeader.STATE_NO);
        List<MallTeamLeader> mallTeamLeadersYes = this.baseMapper.selectListByMemberIdAndState(memberId, MallTeamLeader.STATE_YES);
        if(CollUtil.isNotEmpty(mallTeamLeadersIng) ||CollUtil.isNotEmpty(mallTeamLeadersYes)){
            apiMallleaderStateVo.setState(2);
        }else if(CollUtil.isNotEmpty(mallTeamLeadersNo)){
            apiMallleaderStateVo.setState(1);
        }else{
            apiMallleaderStateVo.setState(1);
        }
        return new FebsResponse().success().data(apiMallleaderStateVo);
    }
    @Override
    public FebsResponse getApiLeaderInfoVoById(Long id) {
        MallTeamLeader mallTeamLeader = this.baseMapper.selectById(id);
        ApiLeaderInfoVo apiLeaderInfoVo = new ApiLeaderInfoVo();
        apiLeaderInfoVo.setName(mallTeamLeader.getName());
        apiLeaderInfoVo.setPhone(mallTeamLeader.getPhone());
        apiLeaderInfoVo.setAddressPic(mallTeamLeader.getAddressPic());
        apiLeaderInfoVo.setUniqueCode(mallTeamLeader.getUniqueCode());
        apiLeaderInfoVo.setProvince(mallTeamLeader.getProvince());
        apiLeaderInfoVo.setCity(mallTeamLeader.getCity());
        apiLeaderInfoVo.setTownship(mallTeamLeader.getTownship());
        apiLeaderInfoVo.setDetailAddress(mallTeamLeader.getDetailAddress());
        apiLeaderInfoVo.setAddressArea(mallTeamLeader.getAddressArea());
        return new FebsResponse().success().data(apiLeaderInfoVo);
    }
    @Override
    public List<OrderListVo> findLeaderOrderListInPage(ApiLeaderOrderListDto apiLeaderOrderListDto) {
        MallMember member = LoginUserUtil.getLoginUser();
        IPage<MallOrderInfo> page = new Page<>(apiLeaderOrderListDto.getPageNum(), apiLeaderOrderListDto.getPageSize());
        apiLeaderOrderListDto.setMemberId(member.getId());
        IPage<MallOrderInfo> mallOrderInfos = this.baseMapper.selectApiLeaderOrderListInPage(page, apiLeaderOrderListDto);
        return MallOrderInfoConversion.INSTANCE.entitysToVos(mallOrderInfos.getRecords());
    }
    private final MallOrderInfoMapper mallOrderInfoMapper;
    @Override
    @Transactional
    public FebsResponse leaderOrderConfirm(ApiLeaderOrderConfirmDto apiLeaderOrderConfirmDto) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(apiLeaderOrderConfirmDto.getOrderNo());
        if(ObjectUtil.isEmpty(mallOrderInfo)){
            return new FebsResponse().fail().message("订单不存在");
        }
        Integer status = mallOrderInfo.getStatus();
        if(OrderStatusEnum.WAIT_SHIPPING.getValue() != status){
            return new FebsResponse().fail().message("订单不是待确认到货状态");
        }
        Integer deliveryType = mallOrderInfo.getDeliveryType();
        if(1 != deliveryType){
            return new FebsResponse().fail().message("订单的配送方式不是自提");
        }
        mallOrderInfo.setStatus(OrderStatusEnum.WAIT_FINISH.getValue());
        mallOrderInfoMapper.updateById(mallOrderInfo);
        return new FebsResponse().success().message("确认成功");
    }
    @Override
    public FebsResponse leaderTitle(ApiLeaderTitleDto apiLeaderTitleDto) {
        String uniqueCode = apiLeaderTitleDto.getUniqueCode();
        Double longitude = apiLeaderTitleDto.getLongitude() == null ? 0 : apiLeaderTitleDto.getLongitude();
        Double latitude = apiLeaderTitleDto.getLatitude() == null ? 0 : apiLeaderTitleDto.getLatitude();
        ApiLeaderInfoVo apiLeaderInfoVo = new ApiLeaderInfoVo();
        MallTeamLeader mallTeamLeader = new MallTeamLeader();
        //特征码扫码
        if(StrUtil.isNotEmpty(uniqueCode)){
            mallTeamLeader = this.baseMapper.selectLeaderByUniqueCode(uniqueCode);
        //经纬度定位
        }else if(longitude != 0 && latitude != 0){
            mallTeamLeader = this.baseMapper.selectLeaderByLonAndLat(longitude,latitude);
        //直接进入,默认选择列表第一个
        }else{
            List<MallTeamLeader> mallTeamLeaderList = this.baseMapper.getMallTeamLeaderList();
            if(CollUtil.isNotEmpty(mallTeamLeaderList)){
                mallTeamLeader = mallTeamLeaderList.get(0);
            }
        }
        if(ObjectUtil.isNotEmpty(mallTeamLeader)){
            apiLeaderInfoVo.setId(mallTeamLeader.getId());
            apiLeaderInfoVo.setName(mallTeamLeader.getName());
            apiLeaderInfoVo.setPhone(mallTeamLeader.getPhone());
            apiLeaderInfoVo.setAddressPic(mallTeamLeader.getAddressPic());
            apiLeaderInfoVo.setUniqueCode(mallTeamLeader.getUniqueCode());
            apiLeaderInfoVo.setProvince(mallTeamLeader.getProvince());
            apiLeaderInfoVo.setCity(mallTeamLeader.getCity());
            apiLeaderInfoVo.setTownship(mallTeamLeader.getTownship());
            apiLeaderInfoVo.setDetailAddress(mallTeamLeader.getDetailAddress());
            apiLeaderInfoVo.setAddressArea(mallTeamLeader.getAddressArea());
        }
        return new FebsResponse().success().data(apiLeaderInfoVo);
    }
}
src/main/java/cc/mrbird/febs/mall/vo/AdminMallOrderInfoVo.java
@@ -71,4 +71,6 @@
    private String memberEmail;
    private Integer carriage;
    //配送方式 1:自提 2:快递
    private Integer deliveryType;
}
src/main/java/cc/mrbird/febs/mall/vo/AdminMallTeamLeaderVo.java
New file
@@ -0,0 +1,40 @@
package cc.mrbird.febs.mall.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "AdminMallTeamLeaderVo", description = "信息返回类")
public class AdminMallTeamLeaderVo {
    //ID
    private Long id;
    //用户ID
    private Long memberId;
    //申请状态 1:审核通过 2:审核不通过 3:申请中
    private Integer state;
    //团长姓名
    private String name;
    //手机号码
    private String phone;
    //自提点照片
    private String addressPic;
    //省
    private String province;
    //市
    private String city;
    //区
    private String township;
    //小区名称(自提点名称)
    private String addressArea;
    //详细地址
    private String detailAddress;
    //经度
    private Double longitude;
    //纬度
    private Double latitude;
    private Date createdTime;
}
src/main/java/cc/mrbird/febs/mall/vo/AdminSelectListLeaderVo.java
New file
@@ -0,0 +1,14 @@
package cc.mrbird.febs.mall.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel(value = "AdminSelectListLeaderVo", description = "信息返回类")
public class AdminSelectListLeaderVo {
    private String uniqueCode;
    private String name;
}
src/main/java/cc/mrbird/febs/mall/vo/ApiLeaderInfoVo.java
New file
@@ -0,0 +1,39 @@
package cc.mrbird.febs.mall.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ApiLeaderInfoVo", description = "信息返回类")
public class ApiLeaderInfoVo {
    private Long id;
    //团长姓名
    @ApiModelProperty(value = "团长姓名")
    private String name;
    //手机号码
    @ApiModelProperty(value = "手机号码")
    private String phone;
    //团长特征码
    @ApiModelProperty(value = "团长特征码")
    private String uniqueCode;
    //自提点照片
    @ApiModelProperty(value = "自提点照片")
    private String addressPic;
    //省
    @ApiModelProperty(value = "省")
    private String province;
    //市
    @ApiModelProperty(value = "市")
    private String city;
    //区
    @ApiModelProperty(value = "区")
    private String township;
    //小区名称
    @ApiModelProperty(value = "小区名称(自提点名称)")
    private String addressArea;
    //详细地址
    @ApiModelProperty(value = "详细地址")
    private String detailAddress;
}
src/main/java/cc/mrbird/febs/mall/vo/ApiLeaderListVo.java
New file
@@ -0,0 +1,50 @@
package cc.mrbird.febs.mall.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "AdminMallTeamLeaderVo", description = "信息返回类")
public class ApiLeaderListVo {
    private Long id;
    //团长姓名
    @ApiModelProperty(value = "团长姓名")
    private String name;
    //手机号码
    @ApiModelProperty(value = "手机号码")
    private String phone;
    //团长特征码
    @ApiModelProperty(value = "团长特征码")
    private String uniqueCode;
    //自提点照片
    @ApiModelProperty(value = "自提点照片")
    private String addressPic;
    //省
    @ApiModelProperty(value = "省")
    private String province;
    //市
    @ApiModelProperty(value = "市")
    private String city;
    //区
    @ApiModelProperty(value = "区")
    private String township;
    //小区名称
    @ApiModelProperty(value = "小区名称(自提点名称)")
    private String addressArea;
    //详细地址
    @ApiModelProperty(value = "详细地址")
    private String detailAddress;
    @ApiModelProperty(value = "距离")
    private Double distance;
    //经度
    @ApiModelProperty(value = "经度")
    private Double longitude;
    //纬度
    @ApiModelProperty(value = "纬度")
    private Double latitude;
}
src/main/java/cc/mrbird/febs/mall/vo/ApiMallleaderStateVo.java
New file
@@ -0,0 +1,14 @@
package cc.mrbird.febs.mall.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ApiMallTeamLeaderVo", description = "信息返回类")
public class ApiMallleaderStateVo {
    @ApiModelProperty(value = "1:可申请 2:不可申请")
    private Integer state;
}
src/main/java/cc/mrbird/febs/mall/vo/MallMemberVo.java
@@ -27,7 +27,7 @@
    @ApiModelProperty(value = "性别")
    private String sex;
    @ApiModelProperty(value = "邀请码")
    @ApiModelProperty(value = "邀请码(如果是团长,邀请码就是团长特征码)")
    private String inviteId;
    @ApiModelProperty(value = "头像")
@@ -72,4 +72,7 @@
    @ApiModelProperty(value = "抽奖积分")
    private BigDecimal prizeScore;
    @ApiModelProperty(value = "是否是团长 1: 是 2:否")
    private Integer isTeamLeader;
}
src/main/java/cc/mrbird/febs/mall/vo/OrderDetailVo.java
@@ -1,5 +1,6 @@
package cc.mrbird.febs.mall.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -84,5 +85,27 @@
    @ApiModelProperty(value = "评价状态 1:待评价 2:已评价")
    private Integer commentState;
    //提货码
    @ApiModelProperty(value = "提货码")
    private String takeCode;
    /**
     * 自提点信息
     */
    @ApiModelProperty(value = "团长姓名")
    private String leaderName;
    @ApiModelProperty(value = "团长电话")
    private String leaderPhone;
    @ApiModelProperty(value = "自提点图片")
    private String addressPic;
    @ApiModelProperty(value = "自提点省")
    private String province;
    @ApiModelProperty(value = "自提点市")
    private String city;
    @ApiModelProperty(value = "自提点区")
    private String township;
    @ApiModelProperty(value = "自提点名称")
    private String addressArea;
    @ApiModelProperty(value = "自提点详细地址")
    private String detailAddress;
}
src/main/java/cc/mrbird/febs/mall/vo/OrderListVo.java
@@ -42,4 +42,7 @@
    @ApiModelProperty(value = "评价状态 1:待评价 2:已评价")
    private Integer commentState;
    @ApiModelProperty(value = "提货码")
    private String takeCode;
}
src/main/java/cc/mrbird/febs/pay/controller/XcxPayController.java
New file
@@ -0,0 +1,131 @@
package cc.mrbird.febs.pay.controller;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
import cc.mrbird.febs.pay.model.NotifyData;
import cc.mrbird.febs.pay.util.PayThreadPool;
import cc.mrbird.febs.pay.util.Signature;
import cc.mrbird.febs.pay.util.Util;
import cc.mrbird.febs.pay.util.WechatConfigure;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
@Slf4j
@RestController
@RequestMapping(value = "/api/xcxPay")
public class XcxPayController {
    @Autowired
    MallOrderInfoMapper mallOrderInfoMapper;
    /**
     * 微信支付回调接口
     */
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping(value = "/wxpayCallback")
    public void payCallBack(HttpServletResponse response, HttpServletRequest request) throws IOException {
        log.info("微信支付回调start....");
        // 获取输入参数
        String inputLine;
        StringBuffer notityXml = new StringBuffer();
        String resXml = "";
        String orderId = "";
        FebsResponse threadResult = new FebsResponse();
        try {
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml.append(inputLine);
            }
            request.getReader().close();
            log.info("notityXml ---- :{} ", notityXml);
            // XMl转对象
            Object bb = Util.getObjectFromXML(notityXml.toString(), NotifyData.class);
            NotifyData data = new NotifyData();
            BeanUtils.copyProperties(bb,data);
            log.info("----return_code = {}", data.getReturn_code());
            // 返回状态码 SUCCESS/FAIL
            if (WechatConfigure.CODE_SUCCESS.equals(data.getReturn_code())) {
                orderId = data.getAttach();
                // 检验订单状态
                MallOrderInfo order = mallOrderInfoMapper.selectById(Long.valueOf(orderId));
                // 校验签名
                String paySecret = WechatConfigure.WECHARPAY_SECRET;
                if (Signature.checkIsSignValidFromResponseString(notityXml.toString(),paySecret)) {
                    // 校验业务结果
                    if (WechatConfigure.CODE_SUCCESS.equals(data.getResult_code())) {
                        // 返回SUCCESS报文
                        resXml = WechatConfigure.RESULT_XML_SUCCESS;
                        // 支付费用
                        Double total_fee = Double.parseDouble(data.getTotal_fee());
                        // 商户订单号
                        String payNum = data.getOut_trade_no();
                        log.info("支付回调关键信息---total_fee:{},payNum:{},orderId:{}", total_fee, payNum, orderId);
                        // 订单ID
                        BigDecimal payMoney = new BigDecimal(total_fee).divide(new BigDecimal(100), 2,
                                RoundingMode.HALF_UP);
                        if (order != null && OrderStatusEnum.WAIT_PAY.getValue() == order.getStatus()) {
                            log.debug("检查支付金额payMoney={},order.getPayMoney()={}", payMoney, order.getAmount());
                            order.setStatus(OrderStatusEnum.WAIT_SHIPPING.getValue());
                            mallOrderInfoMapper.updateById(order);
                            threadResult.success().message("支付成功");
                        } else {
                            log.info("订单状态不为待付款,order status=", order.getStatus());
                        }
                    } else {
                        log.info("微信标识业务是失败");
                        threadResult.fail().message("查询支付信息失败,请联系客服或者刷新支付信息(错误码:001)");
//                        resXml = AppConstance.RESULT_XML_FAIL.replace(ERRORMSG, "微信标识业务是失败");
                    }
                } else {
                    log.info("无效签名");
                    threadResult.fail().message("查询支付信息失败,请联系客服或者刷新支付信息(错误码:002)");
//                    resXml = AppConstance.RESULT_XML_FAIL.replace(ERRORMSG, "微信标识业务是失败");
                }
            } else {
                log.info("通信标识失败");
                threadResult.fail().message("查询支付信息失败,请联系客服或者刷新支付信息(错误码:003)");
//                resXml = AppConstance.RESULT_XML_FAIL.replace(ERRORMSG, "通信标识失败");
            }
        } catch (Exception e) {
            log.error("支付回调签名错误", e);
            threadResult.fail().message("查询支付信息失败,请联系客服或者刷新支付信息(错误码:004)");
//            resXml = AppConstance.RESULT_XML_FAIL.replace(ERRORMSG, "支付回调签名错误");
        } finally {
            // 通知线程消息
            PayThreadPool.notifyThread(Integer.valueOf(orderId), threadResult);
            sendResultBack(response, resXml);
        }
        return;
    }
    private void sendResultBack(HttpServletResponse response, String resXml) throws IOException {
        log.info("返回微信数据={}", resXml);
        ServletOutputStream out = response.getOutputStream();
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }
}
src/main/java/cc/mrbird/febs/pay/model/BrandWCPayRequestData.java
New file
@@ -0,0 +1,117 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.common.utils.AppContants;
import cc.mrbird.febs.pay.util.RandomStringGenerator;
import cc.mrbird.febs.pay.util.Signature;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class BrandWCPayRequestData {
    //每个字段具体的意思请查看API文档
    private String appId = "";
    private String timeStamp = "";
    private String nonceStr = "";
    private String prepay_id = "";
    private String signType = "";
    private String paySign = "";
    public BrandWCPayRequestData(String prepay_id, String appID, String paySecret){
        //默认必须设置
        setAppId(appID);
        //随机字符串,不长于32 位
        setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
        setTimeStamp(Long.toString(System.currentTimeMillis() / 1000L));
        setPrepay_id("prepay_id="+prepay_id);
        //根据API给的签名规则进行签名 【 必须要放在本方法的最后】
        setSignType(AppContants.SIGN_MD5);
        String sign = Signature.getSign(toMap(),paySecret);
        setPaySign(sign);//把签名数据设置到Sign这个属性中
    }
    public String getAppId() {
        return appId;
    }
    public void setAppId(String appId) {
        this.appId = appId;
    }
    public String getTimeStamp() {
        return timeStamp;
    }
    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }
    public String getNonceStr() {
        return nonceStr;
    }
    public void setNonceStr(String nonceStr) {
        this.nonceStr = nonceStr;
    }
    public String getPrepay_id() {
        return prepay_id;
    }
    public void setPrepay_id(String prepay_id) {
        this.prepay_id = prepay_id;
    }
    public String getSignType() {
        return signType;
    }
    public void setSignType(String signType) {
        this.signType = signType;
    }
    public String getPaySign() {
        return paySign;
    }
    public void setPaySign(String paySign) {
        this.paySign = paySign;
    }
    public Map<String,Object> toMap(){
        Map<String,Object> map = new HashMap<String, Object>();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object obj;
            try {
                obj = field.get(this);
                if(obj!=null){
                    if(field.getName().equals("prepay_id")){
                        map.put("package", obj);
                    }else{
                        map.put(field.getName(), obj);
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
src/main/java/cc/mrbird/febs/pay/model/JsApiPayBusiness.java
New file
@@ -0,0 +1,141 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.pay.service.impl.JsApiPayComService;
import cc.mrbird.febs.pay.service.impl.JsApiPayService;
import cc.mrbird.febs.pay.service.impl.RefundService;
import cc.mrbird.febs.pay.service.impl.ScanPayQueryService;
import cc.mrbird.febs.pay.util.Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@Slf4j
public class JsApiPayBusiness {
    private JsApiPayService jsApiPayService;
    public JsApiPayBusiness() throws Exception {
        jsApiPayService = new JsApiPayService();
    }
    /**
     *
     * 生成预付订单
     * @author:姜友瑶
     *            返回类型 void
     * @throws Exception
     * @date 2016年10月13日
     */
    public JsApiPayResData createPrapareOrder(JsApiPayReqData jsApiPayReqData) throws Exception {
        // 接受API返回
        String payServiceResponseString;
        long costTimeStart = System.currentTimeMillis();
        payServiceResponseString = jsApiPayService.request(jsApiPayReqData);
        long costTimeEnd = System.currentTimeMillis();
        long totalTimeCost = costTimeEnd - costTimeStart;
        log.info("------------------request createPrapareOrder taking :" + totalTimeCost + "ms"+"--response="+payServiceResponseString);
        // 将从API返回的XML数据映射到Java对象
        Object data =  Util.getObjectFromXML(payServiceResponseString,
                JsApiPayResData.class);
        JsApiPayResData jsApiPayResData=new JsApiPayResData();
        BeanUtils.copyProperties(data,jsApiPayResData);
        return jsApiPayResData;
    }
    /**
     *
     * 支付成功后查询微信订单
     * @author:jiangyouyao
     *            返回类型 void
     * @throws Exception
     * @date 2016年10月13日
     */
    public ScanPayQueryResData queryPrapareOrder(ScanPayQueryService scanPayQueryService , ScanPayQueryReqData scanPayQueryReqData) throws Exception {
        // 接受API返回
        String payServiceResponseString;
        long costTimeStart = System.currentTimeMillis();
        payServiceResponseString = scanPayQueryService.request(scanPayQueryReqData);
        long costTimeEnd = System.currentTimeMillis();
        long totalTimeCost = costTimeEnd - costTimeStart;
        log.info("------------------request createPrapareOrder taking :" + totalTimeCost + "ms"+"--response="+payServiceResponseString);
        // 将从API返回的XML数据映射到Java对象
        ScanPayQueryResData scanPayQueryResData = (ScanPayQueryResData) Util.getObjectFromXML(payServiceResponseString,
                ScanPayQueryResData.class);
        return scanPayQueryResData;
    }
    /**
     *
     * 专家提现,商家向用户(该系统中的专家)支付
     * @author:jiangyouyao
     *            返回类型 void
     * @throws Exception
     * @date 2017年5月25日
     */
    public JsApiPayComResData payComOrder(JsApiPayComService jsApiPayComService , JsApiPayComReqData jsApiPayComReqData) throws Exception {
        // 接受API返回
        String payServiceResponseString;
        long costTimeStart = System.currentTimeMillis();
        payServiceResponseString = jsApiPayComService.request(jsApiPayComReqData);
        long costTimeEnd = System.currentTimeMillis();
        long totalTimeCost = costTimeEnd - costTimeStart;
        log.info("------------------request createPrapareOrder taking :" + totalTimeCost + "ms"+"--response="+payServiceResponseString);
        // 将从API返回的XML数据映射到Java对象
        JsApiPayComResData jsApiPayComResData = (JsApiPayComResData) Util.getObjectFromXML(payServiceResponseString,
                JsApiPayComResData.class);
        return jsApiPayComResData;
    }
    /**
     *
     * 退款,商家向用户(该系统中的专家)支付
     * @author:jiangyouyao
     * @param scanPayReqData
     *            返回类型 void
     * @throws Exception
     * @date 2017年5月25日
     */
    public RefundResData refundComOrder(RefundService refundService , RefundReqData refundReqData) throws Exception {
        // 接受API返回
        String payServiceResponseString;
        long costTimeStart = System.currentTimeMillis();
        payServiceResponseString = refundService.request(refundReqData);
        long costTimeEnd = System.currentTimeMillis();
        long totalTimeCost = costTimeEnd - costTimeStart;
        log.info("------------------request createPrapareOrder taking :" + totalTimeCost + "ms"+"--response="+payServiceResponseString);
        // 将从API返回的XML数据映射到Java对象
        RefundResData RefundResData = (RefundResData) Util.getObjectFromXML(payServiceResponseString,
                RefundResData.class);
        return RefundResData;
    }
}
src/main/java/cc/mrbird/febs/pay/model/JsApiPayComReqData.java
New file
@@ -0,0 +1,179 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.pay.util.RandomStringGenerator;
import cc.mrbird.febs.pay.util.Signature;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
 * 企业支付请求参数
 *
 * @author:jiangyouyao
 * @date 2017年5月25日
 */
public class JsApiPayComReqData {
    //每个字段具体的意思请查看API文档
    /**
     * 商户号
     */
    private String mchid = "";
    private String mch_appid = "";
    /**
     * 商户企业付款单号
     */
    private String partner_trade_no = "";
    /**
     * 随机字符串
     */
    private String nonce_str = "";
    private String check_name = "";
    /**
     * 签名
     */
    private String sign = "";
    /**
     * 付款金额    RMB(分)
     */
    private int amount = 0;
    /**
     * 备注
     */
    private String desc = "";
    private String openid = "";
    public JsApiPayComReqData() {
    }
    /**
     *
     * @author wzy
     * @param desc         描述
     * @param outTradeNo   商户企业付款单号
     * @param totalFee     付款金额
     * @param bankCode     收款号开户行
     */
    public JsApiPayComReqData(String mchID,String mch_appid,String paySecret ,String desc, String outTradeNo, int totalFee,
                              String openid, String check_name, String bankCode) {
        setMch_appid(mch_appid);
        //默认必须设置
        setMchid(mchID);
        setDesc(desc);
        setPartner_trade_no(outTradeNo);
        setAmount(totalFee);
        setOpenid(openid);
        setCheck_name(check_name);
        //随机字符串,不长于32 位
        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        //根据API给的签名规则进行签名 【 必须要放在本方法的最后】
        String sign = Signature.getSign(toMap(),paySecret);
        setSign(sign);//把签名数据设置到Sign这个属性中
    }
    public String getMch_appid() {
        return mch_appid;
    }
    public void setMch_appid(String mch_appid) {
        this.mch_appid = mch_appid;
    }
    public String getCheck_name() {
        return check_name;
    }
    public void setCheck_name(String check_name) {
        this.check_name = check_name;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getPartner_trade_no() {
        return partner_trade_no;
    }
    public void setPartner_trade_no(String partner_trade_no) {
        this.partner_trade_no = partner_trade_no;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public int getAmount() {
        return amount;
    }
    public void setAmount(int amount) {
        this.amount = amount;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public Map<String, Object> toMap() {
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object obj;
            try {
                obj = field.get(this);
                if (obj != null) {
                    map.put(field.getName(), obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
src/main/java/cc/mrbird/febs/pay/model/JsApiPayComResData.java
New file
@@ -0,0 +1,207 @@
package cc.mrbird.febs.pay.model;
/**
 * User: rizenguo
 * Date: 2014/10/22
 * Time: 16:42
 */
/**
 * 被扫支付提交Post数据给到API之后,API会返回XML格式的数据,这个类用来装这些数据
 */
public class JsApiPayComResData {
    //协议层
    private String return_code = "";
    private String return_msg = "";
    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
    private String mch_appid = "";
    private String mchid = "";
    private String nonce_str = "";
    //private String sign = "";
    private String result_code = "";
    private String err_code = "";
    private String err_code_des = "";
    private String device_info = "";
    //业务返回的具体数据(以下字段在return_code 和result_code 都为SUCCESS 的时候有返回)
    private String payment_no = "";
    private String partner_trade_no = "";
    private String payment_time="";
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    public String getMch_appid() {
        return mch_appid;
    }
    public void setMch_appid(String mch_appid) {
        this.mch_appid = mch_appid;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String err_code) {
        this.err_code = err_code;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String err_code_des) {
        this.err_code_des = err_code_des;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getPayment_no() {
        return payment_no;
    }
    public void setPayment_no(String payment_no) {
        this.payment_no = payment_no;
    }
    public String getPartner_trade_no() {
        return partner_trade_no;
    }
    public void setPartner_trade_no(String partner_trade_no) {
        this.partner_trade_no = partner_trade_no;
    }
    public String getPayment_time() {
        return payment_time;
    }
    public void setPayment_time(String payment_time) {
        this.payment_time = payment_time;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    @Override
    public String toString() {
        return "JsApiPayComResData [return_code=" + return_code + ", return_msg=" + return_msg + ", mch_appid=" + mch_appid + ", mchid=" + mchid + ", nonce_str=" + nonce_str + ", result_code=" + result_code + ", err_code=" + err_code + ", err_code_des=" + err_code_des + ", device_info=" + device_info + ", payment_no=" + payment_no + ", partner_trade_no=" + partner_trade_no + ", payment_time=" + payment_time + "]";
    }
}
src/main/java/cc/mrbird/febs/pay/model/JsApiPayReqData.java
New file
@@ -0,0 +1,298 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.pay.util.RandomStringGenerator;
import cc.mrbird.febs.pay.util.Signature;
import cc.mrbird.febs.pay.util.WechatConfigure;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
 *
*  预付订单请求参数
* @author:姜友瑶
* @date 2016年10月14日
 */
public class JsApiPayReqData {
    //每个字段具体的意思请查看API文档
    private String appid = "";
    private String mch_id = "";
    private String device_info = "";
    private String nonce_str = "";
    private String sign = "";
    private String body = "";
    private String detail = "";
    private String attach = "";
    private String out_trade_no = "";
    private String fee_type = "";
    private int total_fee = 0;
    /**
     * 接收微信支付异步通知回调地址
     */
    private String trade_type = WechatConfigure.TRADE_TYPE_JSAPI;
    private String notify_url ;
    private String openid = "";
    private String limit_pay = "";
    private String spbill_create_ip = "";
    private String product_id = "";
    private String time_start = "";
    private String time_expire = "";
    private String goods_tag = "";
    private String auth_code = "";
    public JsApiPayReqData() {
    }
    /**appID 收款应用id
     * mchID 商户号
     * @param authCode 这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
     * @param body 要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
     * @param attach 支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回
     * @param outTradeNo 商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
     * @param totalFee 订单总金额,单位为“分”,只能整数
     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
     * @param spBillCreateIP 订单生成的机器IP
     * @param timeStart 订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
     * @param timeExpire 订单失效时间,格式同上
     * @param goodsTag 商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
     */
    public JsApiPayReqData(String appID, String mchID, String paySecret, String notify_url, String body, String outTradeNo, int totalFee, String spBillCreateIP, String openid, String attach){
        //默认必须设置
        setAppid(appID);
        setMch_id(mchID);
        setNotify_url(notify_url);
        setBody(body);
        setOut_trade_no(outTradeNo);
        setTotal_fee(totalFee);
        setSpbill_create_ip(spBillCreateIP);
        setAttach(attach);
        //随机字符串,不长于32 位
        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        setOpenid(openid);
        //根据API给的签名规则进行签名 【 必须要放在本方法的最后】
        String sign = Signature.getSign(toMap(),paySecret);
        setSign(sign);//把签名数据设置到Sign这个属性中
    }
    public JsApiPayReqData(String appID, String mchID, String paySecret, String notify_url, String body, String outTradeNo, int totalFee, String spBillCreateIP, String attach){
        //默认必须设置
        setAppid(appID);
        setMch_id(mchID);
        setBody(body);
        setNotify_url(notify_url);
        setOut_trade_no(outTradeNo);
        setTotal_fee(totalFee);
        setSpbill_create_ip(spBillCreateIP);
        setAttach(attach);
        //随机字符串,不长于32 位
        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        //根据API给的签名规则进行签名 【 必须要放在本方法的最后】
        String sign = Signature.getSign(toMap(),paySecret);
        setSign(sign);//把签名数据设置到Sign这个属性中
    }
    public String getDetail() {
        return detail;
    }
    public void setDetail(String detail) {
        this.detail = detail;
    }
    public String getFee_type() {
        return fee_type;
    }
    public void setFee_type(String fee_type) {
        this.fee_type = fee_type;
    }
    public String getNotify_url() {
        return notify_url;
    }
    public void setNotify_url(String notify_url) {
        this.notify_url = notify_url;
    }
    public String getTrade_type() {
        return trade_type;
    }
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public String getLimit_pay() {
        return limit_pay;
    }
    public void setLimit_pay(String limit_pay) {
        this.limit_pay = limit_pay;
    }
    public String getProduct_id() {
        return product_id;
    }
    public void setProduct_id(String product_id) {
        this.product_id = product_id;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getBody() {
        return body;
    }
    /**
     *
    * body最大长度128
    * @author:姜友瑶
    * @param body
    * 返回类型  void
    * @date 2016年10月13日
     */
    public void setBody(String body) {
        if(body.length()>128){
            body=body.substring(0, 128);
        }
        this.body = body;
    }
    public String getAttach() {
        return attach;
    }
    public void setAttach(String attach) {
        this.attach = attach;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public int getTotal_fee() {
        return total_fee;
    }
    public void setTotal_fee(int total_fee) {
        this.total_fee = total_fee;
    }
    public String getSpbill_create_ip() {
        return spbill_create_ip;
    }
    public void setSpbill_create_ip(String spbill_create_ip) {
        this.spbill_create_ip = spbill_create_ip;
    }
    public String getTime_start() {
        return time_start;
    }
    public void setTime_start(String time_start) {
        this.time_start = time_start;
    }
    public String getTime_expire() {
        return time_expire;
    }
    public void setTime_expire(String time_expire) {
        this.time_expire = time_expire;
    }
    public String getGoods_tag() {
        return goods_tag;
    }
    public void setGoods_tag(String goods_tag) {
        this.goods_tag = goods_tag;
    }
    public String getAuth_code() {
        return auth_code;
    }
    public void setAuth_code(String auth_code) {
        this.auth_code = auth_code;
    }
    public Map<String,Object> toMap(){
        Map<String,Object> map = new HashMap<String, Object>();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object obj;
            try {
                obj = field.get(this);
                if(obj!=null){
                    map.put(field.getName(), obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
src/main/java/cc/mrbird/febs/pay/model/JsApiPayResData.java
New file
@@ -0,0 +1,232 @@
package cc.mrbird.febs.pay.model;
/**
 * User: rizenguo
 * Date: 2014/10/22
 * Time: 16:42
 */
/**
 * 被扫支付提交Post数据给到API之后,API会返回XML格式的数据,这个类用来装这些数据
 */
public class JsApiPayResData {
    //协议层
    private String return_code = "";
    private String return_msg = "";
    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
    private String appid = "";
    private String mch_id = "";
    private String nonce_str = "";
    private String sign = "";
    private String result_code = "";
    private String err_code = "";
    private String err_code_des = "";
    private String device_info = "";
    //业务返回的具体数据(以下字段在return_code 和result_code 都为SUCCESS 的时候有返回)
    private String openid = "";
    private String is_subscribe = "";
    private String trade_type = "";
    private String bank_type = "";
    private String total_fee = "";
    private String coupon_fee = "";
    private String fee_type = "";
    private String transaction_id = "";
    private String out_trade_no = "";
    private String attach = "";
    private String time_end = "";
    private String prepay_id = "";
    public String getPrepay_id() {
        return prepay_id;
    }
    public void setPrepay_id(String prepay_id) {
        this.prepay_id = prepay_id;
    }
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String err_code) {
        this.err_code = err_code;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String err_code_des) {
        this.err_code_des = err_code_des;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public String getIs_subscribe() {
        return is_subscribe;
    }
    public void setIs_subscribe(String is_subscribe) {
        this.is_subscribe = is_subscribe;
    }
    public String getTrade_type() {
        return trade_type;
    }
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
    public String getBank_type() {
        return bank_type;
    }
    public void setBank_type(String bank_type) {
        this.bank_type = bank_type;
    }
    public String getTotal_fee() {
        return total_fee;
    }
    public void setTotal_fee(String total_fee) {
        this.total_fee = total_fee;
    }
    public String getCoupon_fee() {
        return coupon_fee;
    }
    public void setCoupon_fee(String coupon_fee) {
        this.coupon_fee = coupon_fee;
    }
    public String getFee_type() {
        return fee_type;
    }
    public void setFee_type(String fee_type) {
        this.fee_type = fee_type;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getAttach() {
        return attach;
    }
    public void setAttach(String attach) {
        this.attach = attach;
    }
    public String getTime_end() {
        return time_end;
    }
    public void setTime_end(String time_end) {
        this.time_end = time_end;
    }
    @Override
    public String toString() {
        return "JsApiPayResData [return_code=" + return_code + ", return_msg=" + return_msg + ", appid=" + appid
                + ", mch_id=" + mch_id + ", nonce_str=" + nonce_str + ", sign=" + sign + ", result_code=" + result_code
                + ", err_code=" + err_code + ", err_code_des=" + err_code_des + ", device_info=" + device_info
                + ", openid=" + openid + ", is_subscribe=" + is_subscribe + ", trade_type=" + trade_type
                + ", bank_type=" + bank_type + ", total_fee=" + total_fee + ", coupon_fee=" + coupon_fee + ", fee_type="
                + fee_type + ", transaction_id=" + transaction_id + ", out_trade_no=" + out_trade_no + ", attach="
                + attach + ", time_end=" + time_end + ", prepay_id=" + prepay_id + "]";
    }
}
src/main/java/cc/mrbird/febs/pay/model/NotifyData.java
New file
@@ -0,0 +1,145 @@
package cc.mrbird.febs.pay.model;
/**
 * User: rizenguo
 * Date: 2014/10/25
 * Time: 13:54
 */
public class NotifyData {
    private String appid = "";
    private String bank_type = "";
    private String cash_fee = "";
    private String fee_type = "";
    private String is_subscribe = "";
    private String mch_id = "";
    private String nonce_str = "";
    private String openid = "";
    private String out_trade_no = "";
    private String result_code = "";
    private String return_code = "";
    private String sign = "";
    private String attach = "";
    private String time_end = "";
    private String total_fee = "";
    private String trade_type = "";
    private String transaction_id = "";
    public String getAttach() {
        return attach;
    }
    public void setAttach(String attach) {
        this.attach = attach;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getBank_type() {
        return bank_type;
    }
    public void setBank_type(String bank_type) {
        this.bank_type = bank_type;
    }
    public String getCash_fee() {
        return cash_fee;
    }
    public void setCash_fee(String cash_fee) {
        this.cash_fee = cash_fee;
    }
    public String getFee_type() {
        return fee_type;
    }
    public void setFee_type(String fee_type) {
        this.fee_type = fee_type;
    }
    public String getIs_subscribe() {
        return is_subscribe;
    }
    public void setIs_subscribe(String is_subscribe) {
        this.is_subscribe = is_subscribe;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getTime_end() {
        return time_end;
    }
    public void setTime_end(String time_end) {
        this.time_end = time_end;
    }
    public String getTotal_fee() {
        return total_fee;
    }
    public void setTotal_fee(String total_fee) {
        this.total_fee = total_fee;
    }
    public String getTrade_type() {
        return trade_type;
    }
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    @Override
    public String toString() {
        return "{appid:"+appid+","+"cash_fee:"+cash_fee
                +","+"result_code:"+result_code+","+"openid:"+openid
                +","+"total_fee:"+total_fee
                +","+"attach:"+attach
                +","+"transaction_id:"+transaction_id
                +","+"out_trade_no:"+out_trade_no+"}";
    }
}
src/main/java/cc/mrbird/febs/pay/model/RefundReqData.java
New file
@@ -0,0 +1,192 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.pay.util.RandomStringGenerator;
import cc.mrbird.febs.pay.util.Signature;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
 * User: rizenguo
 * Date: 2014/10/25
 * Time: 16:12
 */
public class RefundReqData {
    //每个字段具体的意思请查看API文档
    private String appid = "";
    private String mch_id = "";
    private String device_info = "";
    private String nonce_str = "";
    private String sign = "";
    private String transaction_id = "";
    private String out_trade_no = "";
    private String out_refund_no = "";
    private int total_fee = 0;
    private int refund_fee = 0;
    private String refund_fee_type = "CNY";
    private String op_user_id = "";
    /**
     * 请求退款服务
     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
     * @param deviceInfo 微信支付分配的终端设备号,与下单一致
     * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
     * @param totalFee 订单总金额,单位为分
     * @param refundFee 退款总金额,单位为分,可以做部分退款
     * @param opUserID 操作员帐号, 默认为商户号
     * @param refundFeeType 货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
     */
    public RefundReqData(String mchID,String appID,String paySecret ,String outTradeNo,String outRefundNo,int totalFee,int refundFee,String opUserID){
         //微信分配的公众号ID(开通公众号之后可以获取到)
        setAppid(appID);
        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
        setMch_id(mchID);
        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
        //setTransaction_id(transactionID);
        //商户系统自己生成的唯一的订单号
        setOut_trade_no(outTradeNo);
        //微信支付分配的终端设备号,与下单一致
        //setDevice_info(deviceInfo);
        setOut_refund_no(outRefundNo);
        setTotal_fee(totalFee);
        setRefund_fee(refundFee);
        setOp_user_id(opUserID);
        //随机字符串,不长于32 位
        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        //根据API给的签名规则进行签名
        String sign = Signature.getSign(toMap(),paySecret);
        setSign(sign);//把签名数据设置到Sign这个属性中
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getOut_refund_no() {
        return out_refund_no;
    }
    public void setOut_refund_no(String out_refund_no) {
        this.out_refund_no = out_refund_no;
    }
    public int getTotal_fee() {
        return total_fee;
    }
    public void setTotal_fee(int total_fee) {
        this.total_fee = total_fee;
    }
    public int getRefund_fee() {
        return refund_fee;
    }
    public void setRefund_fee(int refund_fee) {
        this.refund_fee = refund_fee;
    }
    public String getOp_user_id() {
        return op_user_id;
    }
    public void setOp_user_id(String op_user_id) {
        this.op_user_id = op_user_id;
    }
    public String getRefund_fee_type() {
        return refund_fee_type;
    }
    public void setRefund_fee_type(String refund_fee_type) {
        this.refund_fee_type = refund_fee_type;
    }
    public Map<String,Object> toMap(){
        Map<String,Object> map = new HashMap<String, Object>();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object obj;
            try {
                obj = field.get(this);
                if(obj!=null){
                    map.put(field.getName(), obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
src/main/java/cc/mrbird/febs/pay/model/RefundResData.java
New file
@@ -0,0 +1,168 @@
package cc.mrbird.febs.pay.model;
/**
 * User: rizenguo
 * Date: 2014/10/25
 * Time: 16:12
 */
public class RefundResData {
    //协议层
    private String return_code = "";
    private String return_msg = "";
    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
    private String appid = "";
    private String mch_id = "";
    private String sub_mch_id = "";
    private String device_info = "";
    private String nonce_str = "";
    private String sign = "";
    private String result_code = "";
    private String err_code = "";
    private String err_code_des = "";
    private String transaction_id = "";
    private String out_trade_no = "";
    private String out_refund_no = "";
    private String refund_id = "";
    private String refund_fee = "";
    private String coupon_refund_fee = "";
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getSub_mch_id() {
        return sub_mch_id;
    }
    public void setSub_mch_id(String sub_mch_id) {
        this.sub_mch_id = sub_mch_id;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String err_code) {
        this.err_code = err_code;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String err_code_des) {
        this.err_code_des = err_code_des;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getOut_refund_no() {
        return out_refund_no;
    }
    public void setOut_refund_no(String out_refund_no) {
        this.out_refund_no = out_refund_no;
    }
    public String getRefund_id() {
        return refund_id;
    }
    public void setRefund_id(String refund_id) {
        this.refund_id = refund_id;
    }
    public String getRefund_fee() {
        return refund_fee;
    }
    public void setRefund_fee(String refund_fee) {
        this.refund_fee = refund_fee;
    }
    public String getCoupon_refund_fee() {
        return coupon_refund_fee;
    }
    public void setCoupon_refund_fee(String coupon_refund_fee) {
        this.coupon_refund_fee = coupon_refund_fee;
    }
}
src/main/java/cc/mrbird/febs/pay/model/ScanPayQueryReqData.java
New file
@@ -0,0 +1,125 @@
package cc.mrbird.febs.pay.model;
import cc.mrbird.febs.pay.util.RandomStringGenerator;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
 * User: rizenguo
 * Date: 2014/10/25
 * Time: 13:54
 */
public class ScanPayQueryReqData {
    //每个字段具体的意思请查看API文档
    private String appid = "";
    private String mch_id = "";
    private String transaction_id = "";
    private String out_trade_no = "";
    private String nonce_str = "";
    private String sign = "";
    /**
     * 请求支付查询服务
     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
     * @return API返回的XML数据
     * @throws Exception
     */
    public ScanPayQueryReqData(String transactionID, String outTradeNo){
        //--------------------------------------------------------------------
        //以下是测试数据,请商户按照自己的实际情况填写具体的值进去
        //--------------------------------------------------------------------
        //微信分配的公众号ID(开通公众号之后可以获取到)
        //setAppid(WechatConfigure.appID);
        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
        // setMch_id(WechatConfigure.mchID);
        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
        setTransaction_id(transactionID);
        //商户系统自己生成的唯一的订单号
        setOut_trade_no(outTradeNo);
        //随机字符串,不长于32 位
        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        //根据API给的签名规则进行签名
        //String sign = Signature.getSign(toMap());
        setSign(sign);//把签名数据设置到Sign这个属性中
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public Map<String,Object> toMap(){
        Map<String,Object> map = new HashMap<String, Object>();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            Object obj;
            try {
                obj = field.get(this);
                if(obj!=null){
                    map.put(field.getName(), obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
src/main/java/cc/mrbird/febs/pay/model/ScanPayQueryResData.java
New file
@@ -0,0 +1,236 @@
package cc.mrbird.febs.pay.model;
/**
 * User: rizenguo
 * Date: 2014/10/25
 * Time: 13:54
 */
public class ScanPayQueryResData {
    //协议层
    private String return_code = "";
    private String return_msg = "";
    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
    private String appid = "";
    private String mch_id = "";
    private String sub_mch_id = "";//新增
    private String nonce_str = "";
    private String sign = "";
    private String result_code = "";
    private String err_code = "";
    private String err_code_des = "";
    //以下字段在return_code 和result_code 都为SUCCESS 的时候有返回
    private String trade_state = "";
    //trade_state的几种可能取值:
    //    SUCCESS--支付成功
    //    REFUND--转入退款
    //    NOTPAY--未支付
    //    CLOSED--已关闭
    //    REVOKED--已撤销
    //    USERPAYING--用户支付中
    //    NOPAY--未支付(确认支付超时)
    //    PAYERROR--支付失败(其他原因,
    //            如银行返回失败)
    //以下字段在trade_state 为SUCCESS 或者REFUND 的时候有返回
    private String device_info = "";
    private String openid = "";
    private String is_subscribe = "";
    private String trade_type = "";
    private String bank_type = "";
    private String total_fee = "";
    private String coupon_fee = "";
    private String fee_type = "";
    private String transaction_id = "";
    private String out_trade_no = "";
    private String attach = "";
    private String time_end = "";
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String return_code) {
        this.return_code = return_code;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String return_msg) {
        this.return_msg = return_msg;
    }
    public String getAppid() {
        return appid;
    }
    public void setAppid(String appid) {
        this.appid = appid;
    }
    public String getMch_id() {
        return mch_id;
    }
    public void setMch_id(String mch_id) {
        this.mch_id = mch_id;
    }
    public String getSub_mch_id() {
        return sub_mch_id;
    }
    public void setSub_mch_id(String sub_mch_id) {
        this.sub_mch_id = sub_mch_id;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonce_str) {
        this.nonce_str = nonce_str;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String result_code) {
        this.result_code = result_code;
    }
    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String err_code) {
        this.err_code = err_code;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String err_code_des) {
        this.err_code_des = err_code_des;
    }
    public String getTrade_state() {
        return trade_state;
    }
    public void setTrade_state(String trade_state) {
        this.trade_state = trade_state;
    }
    public String getDevice_info() {
        return device_info;
    }
    public void setDevice_info(String device_info) {
        this.device_info = device_info;
    }
    public String getOpenid() {
        return openid;
    }
    public void setOpenid(String openid) {
        this.openid = openid;
    }
    public String getIs_subscribe() {
        return is_subscribe;
    }
    public void setIs_subscribe(String is_subscribe) {
        this.is_subscribe = is_subscribe;
    }
    public String getTrade_type() {
        return trade_type;
    }
    public void setTrade_type(String trade_type) {
        this.trade_type = trade_type;
    }
    public String getBank_type() {
        return bank_type;
    }
    public void setBank_type(String bank_type) {
        this.bank_type = bank_type;
    }
    public String getTotal_fee() {
        return total_fee;
    }
    public void setTotal_fee(String total_fee) {
        this.total_fee = total_fee;
    }
    public String getCoupon_fee() {
        return coupon_fee;
    }
    public void setCoupon_fee(String coupon_fee) {
        this.coupon_fee = coupon_fee;
    }
    public String getFee_type() {
        return fee_type;
    }
    public void setFee_type(String fee_type) {
        this.fee_type = fee_type;
    }
    public String getTransaction_id() {
        return transaction_id;
    }
    public void setTransaction_id(String transaction_id) {
        this.transaction_id = transaction_id;
    }
    public String getOut_trade_no() {
        return out_trade_no;
    }
    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }
    public String getAttach() {
        return attach;
    }
    public void setAttach(String attach) {
        this.attach = attach;
    }
    public String getTime_end() {
        return time_end;
    }
    public void setTime_end(String time_end) {
        this.time_end = time_end;
    }
}
src/main/java/cc/mrbird/febs/pay/service/IServiceRequest.java
New file
@@ -0,0 +1,20 @@
package cc.mrbird.febs.pay.service;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
/**
 * User: rizenguo
 * Date: 2014/12/10
 * Time: 15:16
 * 这里定义服务层需要请求器标准接口
 */
public interface IServiceRequest {
    //Service依赖的底层https请求器必须实现这么一个接口
    public String sendPost(String api_url, Object xmlObj) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException;
}
src/main/java/cc/mrbird/febs/pay/service/IXcxPayService.java
New file
@@ -0,0 +1,12 @@
package cc.mrbird.febs.pay.service;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
public interface IXcxPayService {
    /**
     * 发起支付(创建预付订单)
     */
    BrandWCPayRequestData startPayment(MallOrderInfo mallOrderInfo) throws Exception;
}
src/main/java/cc/mrbird/febs/pay/service/impl/BaseService.java
New file
@@ -0,0 +1,47 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.pay.service.IServiceRequest;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
/**
 * User: rizenguo
 * Date: 2014/12/10
 * Time: 15:44
 * 服务的基类
 */
public class BaseService {
    //API的地址
    private String apiURL;
    //发请求的HTTPS请求器
    private IServiceRequest serviceRequest;
    public BaseService(String api, String HttpsRequestClassName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        apiURL = api;
        Class<?> c = Class.forName(HttpsRequestClassName);
        serviceRequest = (IServiceRequest) c.newInstance();
    }
    protected String sendPost(Object xmlObj) throws UnrecoverableKeyException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        return serviceRequest.sendPost(apiURL,xmlObj);
    }
    /**
     * 供商户想自定义自己的HTTP请求器用
     * @param request 实现了IserviceRequest接口的HttpsRequest
     */
    public void setServiceRequest(IServiceRequest request){
        serviceRequest = request;
    }
    public IServiceRequest getServiceRequest() {
        return serviceRequest;
    }
}
src/main/java/cc/mrbird/febs/pay/service/impl/JsApiPayComService.java
New file
@@ -0,0 +1,34 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.pay.model.JsApiPayComReqData;
import cc.mrbird.febs.pay.util.WechatConfigure;
/**
 * User: rizenguo
 * Date: 2014/10/29
 * Time: 16:04
 */
public class JsApiPayComService extends BaseService{
    public JsApiPayComService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        super(WechatConfigure.COM_PAY_API, WechatConfigure.HttpsRequestClassName2);
    }
    /**
     * 请求支付查询服务
     * @return API返回的XML数据
     * @throws Exception
     */
    public String request(JsApiPayComReqData jsApiPayComReqData) throws Exception {
        //--------------------------------------------------------------------
        //发送HTTPS的Post请求到API地址
        //--------------------------------------------------------------------
        String responseString = sendPost(jsApiPayComReqData);
        return responseString;
    }
}
src/main/java/cc/mrbird/febs/pay/service/impl/JsApiPayService.java
New file
@@ -0,0 +1,55 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.pay.model.JsApiPayReqData;
import cc.mrbird.febs.pay.util.WechatConfigure;
/**
 * User: rizenguo
 * Date: 2014/10/29
 * Time: 16:03
 */
public class JsApiPayService extends BaseService{
    public JsApiPayService() throws Exception {
        super(WechatConfigure.UNIFIEDORDER, WechatConfigure.HttpsRequestClassName);
    }
    /**
     * 请求支付服务
     * @param jsApiPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
     * @return API返回的数据
     * @throws Exception
     */
    public String request(JsApiPayReqData jsApiPayReqData) throws Exception {
        //--------------------------------------------------------------------
        //发送HTTPS的Post请求到API地址
        //--------------------------------------------------------------------
        String responseString = sendPost(jsApiPayReqData);
        return responseString;
    }
    /**
     * 请求openid
     * @param
     * @return API返回的数据
     * @throws Exception
     */
    public String requestOpenid(JsApiPayReqData jsApiPayReqData) throws Exception {
        //--------------------------------------------------------------------
        //发送HTTPS的Post请求到API地址
        //--------------------------------------------------------------------
        String responseString = sendPost(jsApiPayReqData);
        return responseString;
    }
}
src/main/java/cc/mrbird/febs/pay/service/impl/RefundService.java
New file
@@ -0,0 +1,33 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.pay.model.RefundReqData;
import cc.mrbird.febs.pay.util.WechatConfigure;
/**
 * User: rizenguo
 * Date: 2014/10/29
 * Time: 16:04
 */
public class RefundService extends BaseService{
    public RefundService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        super(WechatConfigure.REFUND_API, WechatConfigure.HttpsRequestClassName2);
    }
    /**
     * 请求支付查询服务
     * @return API返回的XML数据
     * @throws Exception
     */
    public String request(RefundReqData refundReqData) throws Exception {
        //--------------------------------------------------------------------
        //发送HTTPS的Post请求到API地址
        //--------------------------------------------------------------------
        String responseString = sendPost(refundReqData);
        return responseString;
    }
}
src/main/java/cc/mrbird/febs/pay/service/impl/ScanPayQueryService.java
New file
@@ -0,0 +1,29 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.pay.model.ScanPayQueryReqData;
import cc.mrbird.febs.pay.util.WechatConfigure;
public class ScanPayQueryService extends BaseService{
    public ScanPayQueryService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        super(WechatConfigure.PAY_QUERY_API, WechatConfigure.HttpsRequestClassName);
    }
    /**
     * 请求支付查询服务
     * @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
     * @return API返回的XML数据
     * @throws Exception
     */
    public String request(ScanPayQueryReqData scanPayQueryReqData) throws Exception {
        //--------------------------------------------------------------------
        //发送HTTPS的Post请求到API地址
        //--------------------------------------------------------------------
        String responseString = sendPost(scanPayQueryReqData);
        return responseString;
    }
}
src/main/java/cc/mrbird/febs/pay/service/impl/XcxPayServiceImpl.java
New file
@@ -0,0 +1,93 @@
package cc.mrbird.febs.pay.service.impl;
import cc.mrbird.febs.common.properties.XcxProperties;
import cc.mrbird.febs.common.utils.SpringContextHolder;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.entity.MallOrderItem;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.service.IXcxPayService;
import cc.mrbird.febs.pay.util.WeixinServiceUtil;
import cn.hutool.log.Log;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
@Slf4j
@Service
public class XcxPayServiceImpl implements IXcxPayService {
    @Autowired
    MallOrderInfoMapper mallOrderInfoMapper;
    @Autowired
    MallMemberMapper mallMemberMapper;
    @Autowired
    WeixinServiceUtil weixinServiceUtil;
    private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class);
    @Override
    public BrandWCPayRequestData startPayment(MallOrderInfo mallOrderInfo) throws Exception {
        BigDecimal unit = new BigDecimal("100");
        BigDecimal money = new BigDecimal(mallOrderInfo.getAmount().toString());
        BrandWCPayRequestData payData;
        String productNames = getProductNames(mallOrderInfo.getMemberId(), mallOrderInfo.getId());
        MallMember mallMember = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
        Boolean debug = xcxProperties.getDebug();
        if (debug) {
            payData = weixinServiceUtil.createOrder("[测试]" + productNames, mallOrderInfo.getOrderNo(),
                    1, mallMember.getOpenId(), String.valueOf(mallOrderInfo.getId()));
        } else {
            payData = weixinServiceUtil.createOrder(productNames, mallOrderInfo.getOrderNo(),
                    unit.multiply(money).intValue(),mallMember.getOpenId(), String.valueOf(mallOrderInfo.getId()));
        }
        mallOrderInfo.setWxOrderNo(payData.getPrepay_id());
        mallOrderInfoMapper.updateById(mallOrderInfo);
        return payData;
    }
    /**
     * 根据用户ID和订单ID获取所购买商品名称
     * @return 所含商品名称(多个以","隔开)
     */
    public String getProductNames(Long memberId, Long orderId) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderByMemberIdAndId(memberId, orderId);
        List<MallOrderItem> details = mallOrderInfo.getItems();
        if (CollectionUtils.isEmpty(details)) {
            return "";
        }
        StringBuffer productNameBuffer = new StringBuffer();
        Integer maxLength = 30;
        for (int i = 0; i< details.size(); i++) {
            MallOrderItem mallOrderItem = details.get(i);
            String goodsName = mallOrderItem.getGoodsName();
            if (goodsName == null) {
                continue;
            }
            if (i == 0 && goodsName.length() > maxLength) {
                productNameBuffer.append(goodsName.substring(0, maxLength) + "...");
                break;
            }
            if ((productNameBuffer.length() + goodsName.length()) > maxLength) {
                productNameBuffer.append("等");
                break;
            }
            productNameBuffer.append(goodsName + ",");
        }
        String productNames = productNameBuffer.toString();
        if (productNames.endsWith(",")) {
            productNames = productNames.substring(0, productNames.length() - 1);
        }
        if (productNames.endsWith(",等")) {
            productNames = productNames.substring(0, productNames.length() - 2) + "等";
        }
        return productNames;
    }
}
src/main/java/cc/mrbird/febs/pay/util/MD5.java
New file
@@ -0,0 +1,59 @@
package cc.mrbird.febs.pay.util;
import java.security.MessageDigest;
/**
 * User: rizenguo
 * Date: 2014/10/23
 * Time: 15:43
 */
public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};
    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }
    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
    /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes("utf-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }
}
src/main/java/cc/mrbird/febs/pay/util/PayThreadPool.java
New file
@@ -0,0 +1,46 @@
package cc.mrbird.febs.pay.util;
import cc.mrbird.febs.common.entity.FebsResponse;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class PayThreadPool {
    private static Map<Integer, Object> PAY_WAIT_POOL = new HashMap<>();
    private static Map<Integer, FebsResponse> PAY_THREAD_MSG = new HashMap<>();
    public static void waitThread(Integer orderId, Object lock) {
        PAY_WAIT_POOL.put(orderId, lock);
        synchronized (lock) {
            try {
                // 设置线程最多等待15s
                lock.wait(1000 * 15);
            } catch (InterruptedException e) {
                log.debug("线程等待失败", e);
            }
        }
    }
    public static FebsResponse getThreadResult(Integer orderId) {
        //获取一次后删除结果对象
        // TODO 需要优化可能存在对象积压过多内存溢出风险
        return PAY_THREAD_MSG.remove(orderId);
    }
    public static void notifyThread(Integer orderId, FebsResponse result) {
        Object lock = PAY_WAIT_POOL.get(orderId);
        if (lock != null) {
            synchronized (lock) {
                log.debug("尝试释放锁{}", orderId);
                PAY_THREAD_MSG.put(orderId, result);
                PAY_WAIT_POOL.remove(orderId);
                lock.notifyAll();
            }
        }
    }
}
src/main/java/cc/mrbird/febs/pay/util/RandomStringGenerator.java
New file
@@ -0,0 +1,23 @@
package cc.mrbird.febs.pay.util;
import java.util.Random;
public class RandomStringGenerator {
    /**
     * 获取一定长度的随机字符串
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}
src/main/java/cc/mrbird/febs/pay/util/Signature.java
New file
@@ -0,0 +1,144 @@
package cc.mrbird.febs.pay.util;
import org.apache.commons.codec.digest.DigestUtils;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
/**
 * User: rizenguo Date: 2014/10/29 Time: 15:23
 */
public class Signature {
    /**
     * 签名算法
     *
     * @param o
     *            要参与签名的数据对象
     * @return 签名
     * @throws IllegalAccessException
     */
    public static String getSign(Object o,String paySecret) throws IllegalAccessException {
        ArrayList<String> list = new ArrayList<String>();
        Class<? extends Object> cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.get(o) != null && f.get(o) != "") {
                list.add(f.getName() + "=" + f.get(o) + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" +paySecret;
        Util.log("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        Util.log("Sign Result:" + result);
        return result;
    }
    public static String getSign(Map<String, Object> map,String paySecret) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != "") {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + paySecret;
        Util.log("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result).toUpperCase();
        Util.log("Sign Result:" + result);
        return result;
    }
    /**
     * 从API返回的XML数据里面重新计算一次签名
     *
     * @param responseString
     *            API返回的XML数据
     * @return 新鲜出炉的签名
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static String getSignFromResponseString(String responseString,String paySecret)
            throws IOException, SAXException, ParserConfigurationException {
        Map<String, Object> map = XMLParser.getMapFromXML(responseString);
        // 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign", "");
        // 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        return Signature.getSign(map,paySecret);
    }
    /**
     * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
     *
     * @param responseString
     *            API返回的XML数据字符串
     * @return API签名是否合法
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static boolean checkIsSignValidFromResponseString(String responseString,String paySecret)
            throws ParserConfigurationException, IOException, SAXException {
        Map<String, Object> map = XMLParser.getMapFromXML(responseString);
        Util.log(map.toString());
        String signFromAPIResponse = map.get("sign").toString();
        if (signFromAPIResponse == "" || signFromAPIResponse == null) {
            Util.log("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
            return false;
        }
        Util.log("服务器回包里面的签名是:" + signFromAPIResponse);
        // 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign", "");
        // 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        String signForAPIResponse = Signature.getSign(map,paySecret);
        if (!signForAPIResponse.equals(signFromAPIResponse)) {
            // 签名验不过,表示这个API返回的数据有可能已经被篡改了
            Util.log("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
            return false;
        }
        Util.log("恭喜,API返回的数据签名验证通过!!!");
        return true;
    }
    /**
     *
    *  JS-SDK权限验证的签名
    * @author:姜友瑶
    * 返回类型  void
    * @date 2016年10月18日
     */
    public static String getJsSdkSign(String jsapi_ticket,String noncestr,String timestamp,String url) {
        String string1="jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url="+url;
        Util.log("Sign Before sha1Hex:" + string1);
        String signature= DigestUtils.sha1Hex(string1);
        Util.log("Sign Before sha1Hex:" + signature);
        return signature;
    }
}
src/main/java/cc/mrbird/febs/pay/util/Util.java
New file
@@ -0,0 +1,119 @@
package cc.mrbird.febs.pay.util;
import com.thoughtworks.xstream.XStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Map;
/**
 * User: rizenguo
 * Date: 2014/10/23
 * Time: 14:59
 */
public class Util {
    //打log用
    /**
     * 通过反射的方式遍历对象的属性和属性值,方便调试
     *
     * @param o 要遍历的对象
     * @throws Exception
     */
    public static void reflect(Object o) throws Exception {
        Class<? extends Object> cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            f.setAccessible(true);
            Util.log(f.getName() + " -> " + f.get(o));
        }
    }
    public static byte[] readInput(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
        out.close();
        in.close();
        return out.toByteArray();
    }
    public static String inputStreamToString(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i;
        while ((i = is.read()) != -1) {
            baos.write(i);
        }
        return baos.toString();
    }
    public static InputStream getStringStream(String sInputString) {
        ByteArrayInputStream tInputStringStream = null;
        if (sInputString != null && !sInputString.trim().equals("")) {
            tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
        }
        return tInputStringStream;
    }
    public static Object getObjectFromXML(String xml, Class<?> tClass) {
        //将从API返回的XML数据映射到Java对象
        XStream xStreamForResponseData = new XStream();
        XStream.setupDefaultSecurity(xStreamForResponseData);
        xStreamForResponseData.allowTypes(new Class[]{tClass});
        xStreamForResponseData.alias("xml", tClass);
        xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段
        return xStreamForResponseData.fromXML(xml);
    }
    public static String getStringFromMap(Map<String, Object> map, String key, String defaultValue) {
        if (key == "" || key == null) {
            return defaultValue;
        }
        String result = (String) map.get(key);
        if (result == null) {
            return defaultValue;
        } else {
            return result;
        }
    }
    public static int getIntFromMap(Map<String, Object> map, String key) {
        if (key == "" || key == null) {
            return 0;
        }
        if (map.get(key) == null) {
            return 0;
        }
        return Integer.parseInt((String) map.get(key));
    }
    /**
     * 打log接口
     * @param log 要打印的log字符串
     * @return 返回log
     */
    public static String log(Object log){
        System.out.println(log.toString());
        return log.toString();
    }
    /**
     * 读取本地的xml数据,一般用来自测用
     * @param localPath 本地xml文件路径
     * @return 读到的xml字符串
     */
    public static String getLocalXMLString(String localPath) throws IOException {
        return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));
    }
}
src/main/java/cc/mrbird/febs/pay/util/WebUtil.java
New file
@@ -0,0 +1,298 @@
package cc.mrbird.febs.pay.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.util.Map;
/**
 * 针对ssh项目提供的一些实用性的方法。
 *
 * @author JIANGYOUYAO
 * @email 935090232@qq.com
 * @date Dec 11, 2017
 */
@Component
public class WebUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        WebUtil.applicationContext = applicationContext;
    }
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }
    public static <T> T getBean(String beanName, Class<T> clazz) {
        return applicationContext.getBean(beanName, clazz);
    }
    /**
     * 获得web资源的绝对路径
     *
     * @author JiangYouYao
     * @date 2014年10月14日-上午8:31:01
     * @param path
     * @return
     */
    public static String getResourceRealPath(String path) {
        return getServletContext().getRealPath(path);
    }
    /**
     *
     *  获取web项目的访问URl
     * @author:姜友瑶
     * @return 返回类型 String
     * @date 2016年11月16日
     */
    public static String getWebUrl() {
        return getRequest().getScheme() + "://" + getRequest().getServerName() + ":" + getRequest().getServerPort()
                + getRequest().getContextPath() + "/";
    }
    /**
     *  获得该类的泛型类型
     * @Return: Class 泛型的类型
     * @Author: JiangYouYao
     * @Version: V1.00 (版本号1.0)
     * @Create Date: 2014-8-12 (创建日期)
     */
    @SuppressWarnings("rawtypes")
    public static Class getClass(Class clazz) {
        // 泛型转换
        ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass();
        return (Class) pt.getActualTypeArguments()[0];
    }
    /**
     * 2016/6/2
     *
     * @author xieguangya
     * @return getRequest
     */
    public static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }
    /**
     *
     *  在当前请求的request中获取一个值
     * @author:姜友瑶
     * @return
     * @date 2016年11月11日
     */
    public static Object getRequestAttribute(String name) {
        return getRequest().getAttribute(name);
    }
    /**
     *
     *  在当前请求的request中新增一个值
     * @author:姜友瑶
     * @return
     * @date 2016年11月11日
     */
    public static void setRequestAttribute(String name, Object o) {
        getRequest().setAttribute(name, o);
    }
    /**
     *
     *  在request中删除一个值
     * @author:姜友瑶
     * @return
     * @date 2016年11月11日
     */
    public static void removeRequestAttribute(String name) {
        getRequest().removeAttribute(name);
    }
    /**
     *
     *  在Session中新增一个值
     * @author:姜友瑶
     * @return
     * @date 2016年11月11日
     */
    public static void setSessionAttribute(String name, Object o) {
        getSession().setAttribute(name, o);
    }
    /**
     *
     *  在当前session中获取一个值
     * @author:姜友瑶
     * @param <T>
     * @return
     * @date 2016年11月11日
     */
    public static <T> T getSessionAttribute(String name) {
        return (T) getSession().getAttribute(name);
    }
    /**
     *
     *  在Session中删除一个值
     * @author:姜友瑶
     * @return
     * @date 2016年11月11日
     */
    public static void removeSessionAttribute(String name) {
        getSession().removeAttribute(name);
    }
    /**
     * 获取session
     *
     * @author Matrix-J
     * @return HttpSession
     */
    /**
     * 获取session
     *
     * @author Matrix-J
     * @return HttpSession
     */
    public static HttpSession getSession() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession();
    }
    /**
     * 2016年6月15日 获取ServletContext
     *
     * @author Matrix-J
     * @return getServletContext
     */
    public static ServletContext getServletContext() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession()
                .getServletContext();
    }
    public static final String LEFT_SLASH = "/";
    /**
     * 常量“字符.”
     */
    public static final String CHARACTER_ALL = "\\.";
    /**
     * 常量“.class”
     */
    public static final String CLASS_FILE_EXTEND_NAME = ".class";
    /**
     * 常量“一个空格”
     */
    public static final String CHARACTER_BLANK = " ";
    /**
     * 空格转码后结果
     */
    public static final String SPACE_REPLEACE_STRING = "%20";
    /**
     * 常量“字符左斜杠”
     */
    public static final String CHARACTER_LEFT = "\\/";
    /**
     * 常量"WEB-INF"路径
     */
    public static final String CONFIG_ROOT = "WEB-INF/";
    /**
     * 文件协议
     */
    public static final String FILE_PROTOCOL = "file:";
    /**
     * <li>功能简述:获取项目的实际路径
     * <li>详细描述:WEB-INF
     */
    public static String getContextPath() {
        String name = WebUtil.class.getName();
        name = LEFT_SLASH + name.replaceAll(CHARACTER_ALL, CHARACTER_LEFT) + CLASS_FILE_EXTEND_NAME;
        String space = SPACE_REPLEACE_STRING;
        String path = WebUtil.class.getResource(name).getPath();
        path = path.substring(0, path.indexOf(CONFIG_ROOT) + CONFIG_ROOT.length());
        path = path.replaceAll(space, CHARACTER_BLANK);
        if (path.startsWith(FILE_PROTOCOL)) {
            path = path.substring(FILE_PROTOCOL.length());
        }
        return path;
    }
    /**
     * <li>功能简述:获得发布目录路径
     * <li>详细描述:webapps
     */
    public static String getDeployPath() {
        File tempDir = new File(getContextPath());
        return tempDir.getParentFile().getParentFile().getAbsolutePath();
    }
    /**
     * <li>功能简述:获得项目目录
     */
    public static String getWebPath() {
        File tempDir = new File(getContextPath());
        return tempDir.getParentFile().getAbsolutePath();
    }
    /**
     * 获取当前访问路径含参数
     */
    public static String getLocation() {
        Map<String, String[]> params = getRequest().getParameterMap();
        String queryString = "";
        if (params.keySet().size() > 0) {
            queryString = "?";
            for (String key : params.keySet()) {
                String[] values = params.get(key);
                for (int i = 0; i < values.length; i++) {
                    String value = values[i];
                    queryString += key + "=" + value + "&";
                }
            }
        }
        return getRequest().getScheme() + "://" + getRequest().getServerName() + ":" + getRequest().getServerPort()
                + getRequest().getRequestURI() + queryString;
    }
    /**
     *
     *
     * @description 获取客户端ip地址
     * @data 2015年8月6日 下午7:15:38
     * @author Administrator
     * @return
     */
    public static String getCustomerIp() {
        HttpServletRequest request = getRequest();
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
src/main/java/cc/mrbird/febs/pay/util/WechatConfigure.java
New file
@@ -0,0 +1,53 @@
package cc.mrbird.febs.pay.util;
public class WechatConfigure {
    public static String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**
     * 发送http请求类
     */
    public static String HttpsRequestClassName = "com.matrix.component.wechat.externalInterface.common.HttpsRequest";
    public static final String TRADE_TYPE_JSAPI = "JSAPI";
    // 2)被扫支付查询API
    public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery";
    /**
     * 微信商户号
     */
    public static final String WECHARPAY_MCHID = "1605533690";
    /**
     * 支付秘钥
     */
    public static final String WECHARPAY_SECRET = "CSxc168888CSxc168888CSxc168888xc";
    /**
     * 小程序APPID
     */
    public static final String MINIPROGRAM_APPID = "wx5cc58f796224af61";
    // 8) 企业付款API
    public static String COM_PAY_API="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    /**
     * 发送  SSL请求,企业付款,退款用
     */
    public static String HttpsRequestClassName2 = "com.matrix.component.wechat.externalInterface.common.HttpsRequest2";
    // 3)退款API
    public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    /**
     * 成功
     */
    public static final String CODE_SUCCESS = "SUCCESS";
    /**
     * SUCCESS报文
     */
    public static final String RESULT_XML_SUCCESS = "<xml><return_code><![CDATA[SUCCESS]]></return_code>"
            + "<return_msg><![CDATA[OK]]></return_msg></xml> ";
}
src/main/java/cc/mrbird/febs/pay/util/WeixinServiceUtil.java
New file
@@ -0,0 +1,151 @@
package cc.mrbird.febs.pay.util;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.properties.XcxProperties;
import cc.mrbird.febs.common.utils.SpringContextHolder;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.model.JsApiPayBusiness;
import cc.mrbird.febs.pay.model.JsApiPayReqData;
import cc.mrbird.febs.pay.model.JsApiPayResData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/**微信工具类
 * @author jiangyouyao
 *
 */
@Slf4j
@Service(value="weixinServiceUtil")
public class WeixinServiceUtil {
    private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class);
    /**
     * 支付"175.9.82.254"
     * WebUtil.getRequest().getRemoteAddr()
     * getRemortIP(WebUtil.getRequest())
     * @Description 公众号支付,生成预支付订单
       @date 2017年6月27日
       @atuhor jiangyouyao
     * @param desc 描述信息
     * @param outTradeNo 订单id
     * @param price 订单价格,类型为整型,单位是分,不是元,等于你的实际价格*100
     * @param openId  支付者的微信openId
     * @return 预支付订单返回的结果对象(该结果对象已封装),在H5页面使用该对象信息
     * @throws Exception
     */
    public BrandWCPayRequestData createOrder(String desc, String outTradeNo, int price, String openId, String attach) throws Exception {
        String wecharPaynotifyUrl = xcxProperties.getWecharPaynotifyUrl();
        return buildBrandWCPayRequestData(desc, outTradeNo, price, openId, attach, wecharPaynotifyUrl);
    }
    private BrandWCPayRequestData buildBrandWCPayRequestData(String desc, String outTradeNo, int price, String openId, String attach, String notifyUrl) throws Exception {
        // 创建微信支付预付接口
        JsApiPayBusiness jsApiPayBusiness = new JsApiPayBusiness();
        String idAddr = getIpAddr(WebUtil.getRequest());
        String mchID = WechatConfigure.WECHARPAY_MCHID;
        String paySecret = WechatConfigure.WECHARPAY_SECRET;
        String appId = WechatConfigure.MINIPROGRAM_APPID;
        JsApiPayReqData jsApiPayReqData = new JsApiPayReqData(
                appId, mchID, paySecret, notifyUrl, desc,
                outTradeNo, price, idAddr, openId, attach);
        // 创建预付订单并返回请求结果
        JsApiPayResData result = jsApiPayBusiness.createPrapareOrder(jsApiPayReqData);
        // 把预付订单的信息存放在request域中
        WebUtil.getRequest().setAttribute("msg", result.toString());
        log.info("#---返回码:return_code = {}" , result.getReturn_code());
        log.info("#---签名信息:return_msg = {}" , result.getReturn_msg());
        if (result.getReturn_code().equals("SUCCESS")) {
            // 请求成功, 构建BrandWCPayRequest发起支付需要的参数
            BrandWCPayRequestData payData = new BrandWCPayRequestData(result.getPrepay_id(),appId,paySecret);
            WebUtil.getRequest().setAttribute("payData", payData);
            return payData;
        }else{
            log.error("创建微信支付订单失败msg={}",result.getReturn_msg());
            throw new FebsException("创建微信支付订单失败,请检查程序配置");
        }
    }
    /**@Description 退款,企业付款到个人
       @date 2017年5月26日
       @atuhor jiangyouyao
     * @param outTradeNo 商户订单编号(原订单编号)
     * @param outRefundNo 退款编号
     * @param totalFee 原订单金额(分)
     * @param refundFee 退款金额(分)
     * @param opUserID 操作员id,默认为商户号
     * @return
     */
//    public boolean comRefund(String outTradeNo, String outRefundNo,int totalFee,
//            int refundFee, String opUserID){
//        LogUtil.info("#---outTradeNo:{}#---outRefundNo:{}#---totalFee:{}#---refundFee:{}",
//                outTradeNo,outRefundNo,totalFee,refundFee);
//        BusParameterSettings mchID = busParameterSettingsDao.selectCompanyParamByCode(AppConstance.WECHARPAY_MCHID, HostInterceptor.getCompanyId());
//        if(opUserID==null){
//            opUserID=mchID.getParamValue();
//        }
//        RefundResData result=null;
//        boolean flag=false;
//        try {
//            JsApiPayBusiness jsApiPayBusiness = new JsApiPayBusiness();
//            Long companyId=HostInterceptor.getCompanyId();
//            BusParameterSettings paySecret = busParameterSettingsDao.selectCompanyParamByCode(AppConstance.WECHARPAY_SECRET, companyId);
//            BusParameterSettings appId = busParameterSettingsDao.selectCompanyParamByCode(AppConstance.MINIPROGRAM_APPID, companyId);
//            BusParameterSettings certLocalPath = busParameterSettingsDao.selectCompanyParamByCode(AppConstance.WECHARPAY_CERTLOCAL_PATH, companyId);
//
//            RefundReqData refundReqData=new RefundReqData(mchID.getParamValue(),appId.getParamValue(),paySecret.getParamValue(), outTradeNo, outRefundNo, totalFee, refundFee,opUserID);
//            RefundService refundService=new RefundService();
//            HttpsRequest2 request2= (HttpsRequest2) refundService.getServiceRequest();
//            request2.setCertLocalPath(certLocalPath.getParamValue());
//            request2.setMchId(mchID.getParamValue());
//
//            result = jsApiPayBusiness.refundComOrder(refundService, refundReqData);
//            LogUtil.info("#退款,企业付款到个人---result:{}",result);
//            //如果返回余额不足时
//            if (StringUtils.equals(AppConstance.REFUND_FAIL_NOTENOUGH, result.getErr_code())) {
//                LogUtil.info("#退款失败,{}!", "商户余额不足");
//                throw new GlobleException("退款失败,请联系管理员!");
//            }
//        } catch (Exception e) {
//            LogUtil.error("#企业付款到个人异常#退款#outTradeNo:{}#opUserID:{}", e, outTradeNo,opUserID);
//        }
//
//        if (result.getResult_code().equals(WechatConfigure.SUCCESS)) {
//             flag=true;
//        }else{
//             flag=false;
//             throw new GlobleException(result.getErr_code_des());
//        }
//        return flag;
//    }
    /**@Description 支付获取远程设备的ip
       @date 2017年6月27日
       @atuhor jiangyouyao
     * @param request
     * @return
     */
    public String getIpAddr(HttpServletRequest request) {
           String ip = request.getHeader("x-forwarded-for");
          /* if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
               ip = request.getHeader("Proxy-Client-IP");
           }
           if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
               ip = request.getHeader("WL-Proxy-Client-IP");
           } */
           if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
               ip = request.getRemoteAddr();
           }
           if(ip!=null){
            ip=ip.split(",")[0];
           }
           return ip;
       }
}
src/main/java/cc/mrbird/febs/pay/util/XMLParser.java
New file
@@ -0,0 +1,84 @@
package cc.mrbird.febs.pay.util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
 * User: rizenguo
 * Date: 2014/11/1
 * Time: 14:06
 */
public class XMLParser {
    /**
     * 从RefunQueryResponseString里面解析出退款订单数据
     * @param refundQueryResponseString RefundQuery API返回的数据
     * @return 因为订单数据有可能是多个,所以返回一个列表
    public static List<RefundOrderData> getRefundOrderList(String refundQueryResponseString) throws IOException, SAXException, ParserConfigurationException {
        List list = new ArrayList();
        Map<String,Object> map = XMLParser.getMapFromXML(refundQueryResponseString);
       int count = Integer.parseInt((String) map.get("refund_count"));
       Util.log("count:" + count);
        if(count<1){
            return list;
        }
        RefundOrderData refundOrderData;
        for(int i=0;i<count;i++){
            refundOrderData = new RefundOrderData();
            refundOrderData.setOutRefundNo(Util.getStringFromMap(map,"out_refund_no_" + i,""));
            refundOrderData.setRefundID(Util.getStringFromMap(map,"refund_id_" + i,""));
            refundOrderData.setRefundChannel(Util.getStringFromMap(map,"refund_channel_" + i,""));
            refundOrderData.setRefundFee(Util.getIntFromMap(map,"refund_fee_" + i));
            refundOrderData.setCouponRefundFee(Util.getIntFromMap(map,"coupon_refund_fee_" + i));
            refundOrderData.setRefundStatus(Util.getStringFromMap(map,"refund_status_" + i,""));
            list.add(refundOrderData);
        }
        return list;
    }
*/
    public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {
        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is =  Util.getStringStream(xmlString);
        Document document = builder.parse(is);
        //获取到document里面的全部结点
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        Map<String, Object> map = new HashMap<String, Object>();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
              map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        return map;
    }
}
src/main/resources/application-dev.yml
@@ -18,7 +18,7 @@
          username: ct_test
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://120.27.238.55:3306/db_amz?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
          url: jdbc:mysql://120.27.238.55:3306/db_pingtuan?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
#          username: db_mall
#          password: mall!@#123
#          driver-class-name: com.mysql.cj.jdbc.Driver
@@ -62,3 +62,10 @@
    # 回调地址
    noticeUrl: http://120.27.238.55:8801/api/pay/aliCallBack
    domain: https://openapi.alipaydev.com/gateway.do
xcx:
  wechar_login_url: https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code
  xcx_appid: wx5cc58f796224af61
  xcx_secret: cab68768a444f9e25bb3d1bc208fb546
  debug: true
  wecharPaynotifyUrl: http://120.27.238.55:8801/api/xcxPay/wxpayCallback
src/main/resources/application-prod.yml
@@ -18,7 +18,7 @@
          username: db_mall
          password: mall!@#123
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/db_mall?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
          url: jdbc:mysql://127.0.0.1:3306/db_pingtuan?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
  redis:
    # Redis数据库索引(默认为 0)
@@ -58,3 +58,10 @@
    # 回调地址
    noticeUrl: http://120.27.238.55:8801/api/pay/aliCallBack
    domain: https://openapi.alipay.com/gateway.do
xcx:
  wechar_login_url: https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code
  xcx_appid: wx5cc58f796224af61
  xcx_secret: cab68768a444f9e25bb3d1bc208fb546
  debug: false
  wecharPaynotifyUrl: http://120.27.238.55:8801/api/xcxPay/wxpayCallback
src/main/resources/application-test.yml
@@ -18,7 +18,7 @@
          username: ct_test
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://120.27.238.55:3306/db_amz?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
          url: jdbc:mysql://120.27.238.55:3306/db_pingtuan?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8
  redis:
    # Redis数据库索引(默认为 0)
@@ -58,3 +58,12 @@
    # 回调地址
    noticeUrl: http://120.27.238.55:8801/api/pay/aliCallBack
    domain: https://openapi.alipaydev.com/gateway.do
xcx:
  wechar_login_url: https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code
#  xcx_appid: wx5cc58f796224af61
#  xcx_secret: cab68768a444f9e25bb3d1bc208fb546
  xcx_appid: wx5cc58f796224af61
  xcx_secret: 71403646f666f9b9dca308d4f357765c
  debug: true
  wecharPaynotifyUrl: http://120.27.238.55:8801/api/xcxPay/wxpayCallback
src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -400,4 +400,11 @@
        select * from mall_member
        where level=#{level}
    </select>
    <select id="selectMemberByOpenId" resultType="cc.mrbird.febs.mall.entity.MallMember">
        SELECT a.*
        FROM mall_member a
        where a.open_id = #{openId} limit 1
    </select>
</mapper>
src/main/resources/mapper/modules/MallOrderInfoMapper.xml
@@ -15,9 +15,18 @@
            b.sku_image,
            b.cnt,
            b.price,
            b.amount
            b.amount,
            c.name leader_name,
            c.phone leader_phone,
            c.address_pic,
            c.address_area,
            c.province,
            c.city,
            c.township,
            c.detail_address
        from mall_order_info a
        inner join mall_order_item b on a.id=b.order_id
        inner join mall_team_leader c on a.take_unique_code=c.unique_code
        <where>
            a.del_flag=2
            <if test="record.status == 4 and record.status != 0">
@@ -35,6 +44,12 @@
            <if test="record.orderType != null">
                and a.order_type=#{record.orderType}
            </if>
            <if test="record.deliveryType != null">
                and a.delivery_type=#{record.deliveryType}
            </if>
            <if test="record.takeUniqueCode != null">
                and a.take_unique_code=#{record.takeUniqueCode}
            </if>
        </where>
        order by a.created_time desc
    </select>
@@ -50,6 +65,7 @@
               b.phone memberPhone
        from mall_order_info a
        left join mall_member b on a.member_id = b.id
        left join mall_team_leader c on a.take_unique_code = c.unique_code
        <where>
            a.del_flag=2
            <if test="record != null">
@@ -62,11 +78,17 @@
                <if test="record.status != null and record.status != ''">
                    and a.status = #{record.status}
                </if>
                <if test="record.deliveryType != null and record.deliveryType != ''">
                    and a.delivery_type = #{record.deliveryType}
                </if>
                <if test="record.orderNo != null and record.orderNo != ''">
                    and a.order_no like CONCAT('%', CONCAT(#{record.orderNo}, '%'))
                </if>
                <if test="record.name != null and record.name != ''">
                    and b.name like CONCAT('%', CONCAT(#{record.name}, '%'))
                </if>
                <if test="record.uniqueCode != null and record.uniqueCode != ''">
                    and a.take_unique_code = #{record.uniqueCode}
                </if>
            </if>
        </where>
@@ -99,7 +121,17 @@
        <result column="comment_state" property="commentState" />
        <result column="carriage" property="carriage" />
        <result column="remark" property="remark" />
        <result column="take_code" property="takeCode" />
        <result column="take_unique_code" property="takeUniqueCode" />
        <result column="del_flag" property="delFlag" />
        <result column="leader_name" property="leaderName" />
        <result column="leader_phone" property="leaderPhone" />
        <result column="address_pic" property="addressPic" />
        <result column="address_area" property="addressArea" />
        <result column="province" property="province" />
        <result column="city" property="city" />
        <result column="township" property="township" />
        <result column="detail_address" property="detailAddress" />
        <collection property="items" ofType="cc.mrbird.febs.mall.entity.MallOrderItem">
            <id property="id" column="item_id" />
            <result property="orderId" column="order_id" />
@@ -129,9 +161,18 @@
               b.sku_image,
               b.cnt,
               b.price,
               b.amount
               b.amount,
               c.name leader_name,
               c.phone leader_phone,
               c.address_pic,
               c.address_area,
               c.province,
               c.city,
               c.township,
               c.detail_address
        from mall_order_info a
         inner join mall_order_item b on a.id=b.order_id
         inner join mall_team_leader c on a.take_unique_code=c.unique_code
        <where>
            a.del_flag=2
            <if test="record.query != null and record.query != ''">
@@ -170,9 +211,18 @@
            b.cnt,
            b.price,
            b.amount,
            b.is_normal
            b.is_normal,
            c.name leader_name,
            c.phone leader_phone,
            c.address_pic,
            c.address_area,
            c.province,
            c.city,
            c.township,
            c.detail_address
        from mall_order_info a
             inner join mall_order_item b on a.id=b.order_id
             inner join mall_team_leader c on a.take_unique_code=c.unique_code
        where a.id=#{id}
    </select>
src/main/resources/mapper/modules/MallTeamLeaderMapper.xml
New file
@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cc.mrbird.febs.mall.mapper.MallTeamLeaderMapper">
    <select id="selectLeaderListInPage" resultType="cc.mrbird.febs.mall.vo.AdminMallTeamLeaderVo">
        select
            a.*
        from mall_team_leader a
        <where>
            <if test="record != null">
                <if test="record.name != null and record.name != ''">
                    and a.name like CONCAT('%', CONCAT(#{record.name}, '%'))
                </if>
                <if test="record.state != null and record.state != ''">
                    and a.state = #{record.state}
                </if>
            </if>
        </where>
        order by a.created_time desc
    </select>
    <select id="selectApiLeaderListInPage" resultType="cc.mrbird.febs.mall.entity.MallTeamLeader">
        select
        a.*,
        ROUND(
            6378.138 * 2 * ASIN(
                SQRT(
                    POW(SIN((#{record.latitude} * PI() / 180 - a.latitude * PI() / 180) / 2),2)
                        + COS(40.0497810000 * PI() / 180) * COS(a.latitude * PI() / 180)
                        * POW(SIN((#{record.longitude}  * PI() / 180 - a.longitude * PI() / 180) / 2),2)
                )
            ) * 1000
        ) AS distance
        from mall_team_leader a
        <where>
            a.state = 1
            <if test="record.query != null and record.query != ''">
                and (a.name like CONCAT('%', CONCAT(#{record.query}, '%'))
                    or a.phone like CONCAT('%', CONCAT(#{record.query}, '%'))
                    or a.address_area like CONCAT('%', CONCAT(#{record.query}, '%')))
            </if>
        </where>
        order by distance ASC
    </select>
    <select id="selectListByMemberIdAndState" resultType="cc.mrbird.febs.mall.entity.MallTeamLeader">
        select
        a.*
        from mall_team_leader a
        where a.state = #{state} and a.member_id = #{memberId}
    </select>
    <resultMap id="OrderInfoMap" type="cc.mrbird.febs.mall.entity.MallOrderInfo">
        <id column="id" property="id" />
        <result column="order_no" property="orderNo" />
        <result column="member_id" property="memberId" />
        <result column="order_time" property="orderTime" />
        <result column="pay_time" property="payTime" />
        <result column="amount" property="amount" />
        <result column="pay_method" property="payMethod" />
        <result column="pay_order_no" property="payOrderNo" />
        <result column="pay_result" property="payResult" />
        <result column="status" property="status" />
        <result column="cancel_type" property="cancelType" />
        <result column="name" property="name" />
        <result column="phone" property="phone" />
        <result column="address" property="address" />
        <result column="longitude" property="longitude" />
        <result column="latitude" property="latitude" />
        <result column="order_type" property="orderType" />
        <result column="comment_state" property="commentState" />
        <result column="carriage" property="carriage" />
        <result column="remark" property="remark" />
        <result column="del_flag" property="delFlag" />
        <collection property="items" ofType="cc.mrbird.febs.mall.entity.MallOrderItem">
            <id property="id" column="item_id" />
            <result property="orderId" column="order_id" />
            <result property="goodsId" column="goods_id" />
            <result property="skuId" column="sku_id" />
            <result property="goodsName" column="goods_name" />
            <result property="styleName" column="style_name" />
            <result property="skuName" column="sku_name" />
            <result property="skuImage" column="sku_image" />
            <result property="cnt" column="cnt" />
            <result property="price" column="price" />
            <result property="amount" column="amount" />
            <result property="isNormal" column="is_normal" />
        </collection>
    </resultMap>
    <select id="selectApiLeaderOrderListInPage" resultMap="OrderInfoMap">
        select
        a.*,
        b.id item_id,
        b.order_id,
        b.goods_id,
        b.sku_id,
        b.goods_name,
        b.style_name,
        b.sku_name,
        b.sku_image,
        b.cnt,
        b.price,
        b.amount
        from mall_order_info a
        inner join mall_order_item b on a.id=b.order_id
        inner join mall_member c on a.take_unique_code=c.invite_id
        <where>
            a.del_flag=2
            and a.delivery_type = 1
            and c.id=#{record.memberId}
            <if test="record.query != null and record.query != ''">
                and ( a.name like CONCAT('%', CONCAT(#{record.query}, '%'))
                    or a.phone like CONCAT('%', CONCAT(#{record.query}, '%'))
                    or a.take_code like CONCAT('%', CONCAT(#{record.query}, '%'))
                    )
            </if>
            <if test="record.status == 4 and record.status != 0">
                and a.status = 4
            </if>
            <if test="record.status != 4 and record.status != 1 and record.status != 0 and record.status != 5">
                and a.status = #{record.status}
            </if>
            <if test="record.status == 5">
                and a.status = 7
            </if>
            <if test="record.status == 1">
                and a.status = 2
            </if>
            <if test="record.orderType != null">
                and a.order_type=#{record.orderType}
            </if>
        </where>
        order by a.created_time desc
    </select>
    <select id="getMallTeamLeaderList" resultType="cc.mrbird.febs.mall.entity.MallTeamLeader">
        select
            a.*
        from mall_team_leader a
        where a.state = 1
    </select>
    <select id="selectLeaderByUniqueCode" resultType="cc.mrbird.febs.mall.entity.MallTeamLeader">
        select
            a.*
        from mall_team_leader a
        where a.unique_code = #{uniqueCode} limit 1
    </select>
    <select id="selectLeaderByLonAndLat" resultType="cc.mrbird.febs.mall.entity.MallTeamLeader">
        select
        a.*,
        ROUND(
        6378.138 * 2 * ASIN(
        SQRT(
        POW(SIN((#{latitude} * PI() / 180 - a.latitude * PI() / 180) / 2),2)
        + COS(40.0497810000 * PI() / 180) * COS(a.latitude * PI() / 180)
        * POW(SIN((#{longitude}  * PI() / 180 - a.longitude * PI() / 180) / 2),2)
        )
        ) * 1000
        ) AS distance
        from mall_team_leader a
        where a.state = 1
        order by distance ASC limit 1
    </select>
</mapper>
src/main/resources/templates/febs/views/modules/leader/leaderList.html
New file
@@ -0,0 +1,185 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-leader" lay-title="团长列表">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-card">
                <div class="layui-card-body febs-table-full">
                    <form class="layui-form layui-table-form" lay-filter="user-table-form">
                        <div class="layui-row">
                            <div class="layui-col-md10">
                                <div class="layui-form-item">
                                    <div class="layui-inline">
                                        <div class="layui-input-inline">
                                            <input type="text" placeholder="名称" name="name" autocomplete="off" class="layui-input">
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">审核状态</label>
                                        <div class="layui-input-inline">
                                            <select name="state">
                                                <option value="">请选择</option>
                                                <option value="1">通过</option>
                                                <option value="2">不通过</option>
                                                <option value="3">申请中</option>
                                            </select>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
                                    <i class="layui-icon">&#xe848;</i>
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset">
                                    <i class="layui-icon">&#xe79b;</i>
                                </div>
                            </div>
                        </div>
                    </form>
                    <table lay-filter="leaderTable" lay-data="{id: 'leaderTable'}"></table>
                    <style type="text/css">
                        .layui-table-cell{
                            text-align:center;
                            height: auto;
                            white-space: nowrap; /*文本不会换行,在同一行显示*/
                            overflow: hidden; /*超出隐藏*/
                            text-overflow: ellipsis; /*省略号显示*/
                        }
                        .layui-table img{
                            max-width:100px
                        }
                    </style>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- 表格操作栏 start -->
<script type="text/html" id="user-option">
    <span shiro:lacksPermission="user:view,user:update,user:delete">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
    </span>
    <a lay-event="edit" shiro:hasPermission="user:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
</script>
<!-- 表格操作栏 end -->
<script data-th-inline="none" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            $view = $('#febs-leader'),
            $query = $view.find('#query'),
            $reset = $view.find('#reset'),
            $searchForm = $view.find('form'),
            sortObject = {field: 'phone', type: null},
            tableIns;
        form.render();
        // 表格初始化
        initTable();
        // 初始化表格操作栏各个按钮功能
        table.on('tool(leaderTable)', function (obj) {
            var data = obj.data,
                layEvent = obj.event;
            if (layEvent === 'leaderUpdate') {
                febs.modal.open('编辑', 'modules/leader/leaderUpdate/' + data.id, {
                    btn: ['提交', '取消'],
                    area:['100%','100%'],
                    yes: function (index, layero) {
                        $('#febs-leader-update').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'seeImgThumb') {
                var t = $view.find('#seeImgThumb'+data.id+'');
                //页面层
                layer.open({
                    type: 1,
                    title: "图片",
                    skin: 'layui-layer-rim', //加上边框
                    area: ['80%', '80%'], //宽高
                    shadeClose: true, //开启遮罩关闭
                    end: function (index, layero) {
                        return false;
                    },
                    content: '<div style="text-align:center"><img src="' + $(t).attr('src') + '" /></div>'
                });
            }
        });
        // 查询按钮
        $query.on('click', function () {
            var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type});
            tableIns.reload({where: params, page: {curr: 1}});
        });
        // 刷新按钮
        $reset.on('click', function () {
            $searchForm[0].reset();
            sortObject.type = 'null';
            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
        });
        function initTable() {
            tableIns = febs.table.init({
                elem: $view.find('table'),
                id: 'leaderTable',
                url: ctx + 'admin/leader/leaderList',
                cols: [[
                    {field: 'name', title: '姓名', minWidth: 150,align:'left'},
                    {field: 'phone', title: '电话', minWidth: 150,align:'left'},
                    {field: 'addressPic', title: '自提点照片',
                        templet: function (d) {
                            return '<a lay-event="seeImgThumb"><img id="seeImgThumb'+d.id+'" src="'+d.addressPic+'" alt=""></a>';
                        }, minWidth: 150,align:'center'},
                    {field: 'state', title: '状态',
                        templet: function (d) {
                            if (d.state === 1) {
                                return '<span style="color:green;">通过</span>'
                            } else if (d.state === 2) {
                                return '<span style="color:red;">拒绝</span>'
                            }else if (d.state === 3) {
                                return '<span style="color:blue;">待审核</span>'
                            }else{
                                return ''
                            }
                        }, minWidth: 80,align:'center'},
                    {title: '操作',
                        templet: function (d) {
                            if (d.state === 3) {
                                return ''
                                    + '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="leaderUpdate" shiro:hasPermission="user:update">审核</button>'
                            }else{
                                return '';
                            }
                        },minWidth: 160,align:'center'}
                ]]
            });
        }
        form.on('switch(startOrCloseSwitch)', function (data) {
            if (data.elem.checked) {
                startAct(data.value);
            } else {
                closeAct(data.value);
            }
        })
        // 获取查询参数
        function getQueryParams() {
            return {
                name: $searchForm.find('input[name="name"]').val().trim(),
                state: $searchForm.find("select[name='state']").val(),
            };
        }
    })
</script>
src/main/resources/templates/febs/views/modules/leader/leaderUpdate.html
New file
@@ -0,0 +1,143 @@
<style>
    #febs-leader-update {
        padding: 20px 25px 25px 0;
    }
    #febs-leader-update .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #febs-leader-update #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #febs-leader-update .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
    #febs-leader-update img{
        max-width:200px
    }
</style>
<div class="layui-fluid" id="febs-leader-update">
    <form class="layui-form" action="" lay-filter="febs-leader-update-form">
        <div class="layui-form-item febs-hide">
            <label class="layui-form-label">id:</label>
            <div class="layui-input-block">
                <input type="text" name="id">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">姓名:</label>
            <div class="layui-input-block">
                <input type="text" name="name" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">手机号码:</label>
            <div class="layui-input-block">
                <input type="text" name="phone" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">省:</label>
            <div class="layui-input-block">
                <input type="text" name="province" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">市:</label>
            <div class="layui-input-block">
                <input type="text" name="city" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">区:</label>
            <div class="layui-input-block">
                <input type="text" name="township" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">详细地址:</label>
            <div class="layui-input-block">
                <input type="text" name="detailAddress" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">自提点名称:</label>
            <div class="layui-input-block">
                <input type="text" name="addressArea" class="layui-input" readonly>
                <div class="layui-form-mid layui-word-aux">小区名称(自提点名称)</div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">自提点照片:</label>
            <div class="layui-input-block">
                <img alt="头像" data-th-src="${leaderInfo.addressPic}" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">经度:</label>
            <div class="layui-input-block">
                <input type="text" name="longitude" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">纬度:</label>
            <div class="layui-input-block">
                <input type="text" name="latitude" class="layui-input" readonly>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">审核结果:</label>
            <div class="layui-input-block">
                <input type="radio" name="isOk" value="1" title="同意" checked="">
                <input type="radio" name="isOk" value="2" title="拒绝">
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="febs-leader-update-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects',  'treeSelect', 'eleTree'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
            form = layui.form,
            leaderInfo = [[${leaderInfo}]],
            $view = $('#febs-leader-update'),
            _deptTree;
        form.render();
        initUserValue();
        function initUserValue() {
            form.val("febs-leader-update-form", {
                "id": leaderInfo.id,
                "name": leaderInfo.name,
                "phone": leaderInfo.phone,
                "addressPic": leaderInfo.addressPic,
                "province": leaderInfo.province,
                "city": leaderInfo.city,
                "township": leaderInfo.township,
                "addressArea": leaderInfo.addressArea,
                "detailAddress": leaderInfo.detailAddress,
                "longitude": leaderInfo.longitude,
                "latitude": leaderInfo.latitude
            });
        }
        form.on('submit(febs-leader-update-submit)', function (data) {
            febs.post(ctx + 'admin/leader/leaderUpdate', data.field, function () {
                layer.closeAll();
                febs.alert.success('操作成功');
                $('#febs-leader').find('#reset').click();
            });
            return false;
        });
    });
</script>
src/main/resources/templates/febs/views/modules/order/orderList.html
@@ -32,6 +32,24 @@
                                    </div>
                                </div>
                                <div class="layui-inline">
                                    <label class="layui-form-label">团长:</label>
                                    <div class="layui-input-inline">
                                        <select name="uniqueCode" class="order-takeUniqueCode">
                                            <option value="">请选择</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="layui-inline">
                                    <label class="layui-form-label layui-form-label-sm">配送方式</label>
                                    <div class="layui-input-inline">
                                        <select name="deliveryType">
                                            <option value="">请选择</option>
                                            <option value="1">自提</option>
                                            <option value="2">快递</option>
                                        </select>
                                    </div>
                                </div>
                                <div class="layui-inline">
                                    <label class="layui-form-label layui-form-label-sm">支付状态</label>
                                    <div class="layui-input-inline">
                                        <select name="payResult">
@@ -81,14 +99,15 @@
</script>
<script type="text/html" id="tableToolBar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" lay-event="exportDeliver">导出未发货订单</button>
        <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" lay-event="exportDeliverOne">导出未发货订单(自提)</button>
        <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" lay-event="exportDeliverTwo">导出未发货订单(快递)</button>
        <button class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain" id="importDeliver" lay-event="importDeliver">导入发货</button>
    </div>
</script>
<!-- 表格操作栏 end -->
<script data-th-inline="none" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs', 'upload'], function () {
    layui.use([ 'jquery', 'form', 'table', 'febs', 'formSelects', 'upload'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
@@ -100,18 +119,40 @@
            $searchForm = $view.find('form'),
            $add = $view.find('#add'),
            sortObject = {field: 'phone', type: null},
            formSelects = layui.formSelects,
            tableIns;
        form.render();
        formSelects.render();
        //(下拉框)
        $.get(ctx + 'admin/leader/selectList', function (data) {
            for (var k in data)
            {
                $(".order-takeUniqueCode").append("<option value='" + data[k].uniqueCode + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                form.render();
            });
        });
        // 表格初始化
        initTable();
        table.on('toolbar(orderTable)', function(obj){
            var event = obj.event;
            if (event == 'exportDeliverOne') {
                let uniqueCodeValue = $searchForm.find("select[name='uniqueCode']").val();
                if(uniqueCodeValue == '' || uniqueCodeValue == null){
                    febs.alert.warn('请选择团长');
                    return;
                }
                window.location.href = ctx + "admin/order/exportOrderListOne?orderType=1&status=2&deliveryType=1&takeUniqueCode="+uniqueCodeValue;
            }
            if (event == 'exportDeliver') {
                window.location.href = ctx + "admin/order/exportOrderList?orderType=1&status=2";
            if (event == 'exportDeliverTwo') {
                window.location.href = ctx + "admin/order/exportOrderList?orderType=1&status=2&deliveryType=2";
            }
        });
@@ -205,6 +246,16 @@
                        {field: 'amount', title: '订单金额', minWidth: 120,align:'left'},
                        {field: 'carriage', title: '运费', minWidth: 120,align:'left'},
                        {field: 'orderTime', title: '下单时间', minWidth: 200,align:'left'},
                        {field: 'deliveryType', title: '配送方式',
                            templet: function (d) {
                                if (d.deliveryType === 1) {
                                    return '<span style="color:dodgerblue;">自提</span>'
                                } else if (d.deliveryType === 2) {
                                    return '<span style="color:forestgreen;">快递</span>'
                                }else{
                                    return ''
                                }
                            }, minWidth: 120,align:'center'},
                        {field: 'status', title: '状态',
                            templet: function (d) {
                                if (d.status === 1) {
@@ -230,7 +281,7 @@
                        {field: 'payOrderNo', title: '支付订单号', minWidth: 200,align:'left'},
                        {title: '操作',
                            templet: function (d) {
                                    if (d.status === 2) {
                                    if (d.status === 2 && d.deliveryType === 2) {
                                        return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="deliverGoods" shiro:hasPermission="user:update">发货</button>'
                                            +'<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>'
                                    }else{
@@ -249,6 +300,8 @@
                orderNo: $searchForm.find('input[name="orderNo"]').val().trim(),
                payResult: $searchForm.find("select[name='payResult']").val(),
                status: $searchForm.find("select[name='status']").val(),
                deliveryType: $searchForm.find("select[name='deliveryType']").val(),
                uniqueCode: $searchForm.find("select[name='uniqueCode']").val(),
            };
        }