Jelajahi Sumber

Merge branch 'develop'

songfuqiang 2 tahun lalu
induk
melakukan
bbf5210cc6
94 mengubah file dengan 3994 tambahan dan 330 penghapusan
  1. 13 0
      backend-common/src/main/java/constant/CommonConstant.java
  2. 17 0
      backend-common/src/main/java/utils/DateUtils.java
  3. 54 49
      backend-common/src/main/java/utils/EmailUtils.java
  4. 7 0
      backend-core/pom.xml
  5. 1 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/client/ComPdfKitClient.java
  6. 344 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/client/OssFileClient.java
  7. 19 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/config/OssConfig.java
  8. 6 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/config/oauth/AuthExceptionEntryPoint.java
  9. 4 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/constant/AuthConstant.java
  10. 4 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/constant/OrderConstant.java
  11. 35 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AdvertisementController.java
  12. 1 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AlipayController.java
  13. 25 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AuthController.java
  14. 47 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AvatarController.java
  15. 8 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/ConvertTypeController.java
  16. 31 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/DeviceController.java
  17. 30 4
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/MembersController.java
  18. 10 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/MissionFilesController.java
  19. 12 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/PricingController.java
  20. 30 4
      backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/SubscriptionController.java
  21. 1 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/CaptchaActionEnum.java
  22. 25 7
      backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/FileTypeEnum.java
  23. 2 2
      backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/GoodsTypeEnum.java
  24. 45 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/LanguageEnum.java
  25. 10 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/ProviderEnum.java
  26. 33 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/mapper/ExpensesMapper.java
  27. 21 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/mapper/ext/ExtSetPricingsMapper.java
  28. 202 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/model/Expenses.java
  29. 816 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/model/ExpensesExample.java
  30. 1 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/model/member/SubPricing.java
  31. 2 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/model/member/SubSetPricing.java
  32. 3 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/model/pricing/QueryPricingResp.java
  33. 34 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/AppLogoutParam.java
  34. 22 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/CheckExistsParam.java
  35. 19 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/ExpenseParam.java
  36. 27 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryAdvertisementParam.java
  37. 16 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryConvertTypeParam.java
  38. 22 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryPricingParam.java
  39. 16 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/ExistsMemberVo.java
  40. 4 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/MissionFileVO.java
  41. 26 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/AdvertisementVo.java
  42. 3 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/BindAccountVo.java
  43. 31 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/CreateSubVo.java
  44. 20 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/ExpenseVo.java
  45. 10 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/LoginInfoVo.java
  46. 27 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/MemberInfoVo.java
  47. 20 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/RemindVo.java
  48. 15 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/ThirdOrderVo.java
  49. 14 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/UpTokenVo.java
  50. 20 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/WxAndroidSignVo.java
  51. 5 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/comPdfKit/FileInfoDto.java
  52. 26 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/properties/OssProperties.java
  53. 21 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AdvertisementService.java
  54. 2 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AlipayService.java
  55. 20 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AuthService.java
  56. 34 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AvatarService.java
  57. 21 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/DeviceService.java
  58. 38 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/MemberService.java
  59. 6 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/MissionFilesService.java
  60. 2 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/OrderService.java
  61. 16 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/OutputFileService.java
  62. 8 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/PricingService.java
  63. 10 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SetPricingService.java
  64. 8 6
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SocialAccountService.java
  65. 27 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SubscriptionService.java
  66. 4 2
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/WXPayService.java
  67. 105 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AdvertisementServiceImpl.java
  68. 26 7
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AlipayServiceImpl.java
  69. 99 24
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AuthServiceImpl.java
  70. 154 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AvatarServiceImpl.java
  71. 5 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/ConvertFileServiceImpl.java
  72. 55 5
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/DeviceServiceImpl.java
  73. 202 65
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MemberServiceImpl.java
  74. 10 1
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MissionFileServiceImpl.java
  75. 16 8
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MissionServiceImpl.java
  76. 46 13
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/OrderServiceImpl.java
  77. 27 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/OutputFileServiceImpl.java
  78. 27 17
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/PricingServiceImpl.java
  79. 16 4
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SetPricingServiceImpl.java
  80. 73 28
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SocialAccountServiceImpl.java
  81. 175 19
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SubscriptionServiceImpl.java
  82. 9 4
      backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/WXPayServiceImpl.java
  83. 81 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/CommonBusinessUtils.java
  84. 11 10
      backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/TencentUtils.java
  85. 10 8
      backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/WechatUtils.java
  86. 4 0
      backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/wxpay/WXPayConstants.java
  87. 22 4
      backend-core/src/main/resources/application-local.yml
  88. 1 4
      backend-core/src/main/resources/application-test-db.properties
  89. 39 14
      backend-core/src/main/resources/application-test.yml
  90. 1 1
      backend-core/src/main/resources/application.yml
  91. 8 7
      backend-core/src/main/resources/generatorConfig.xml
  92. 289 0
      backend-core/src/main/resources/sqlmap/ExpensesMapper.xml
  93. 3 1
      backend-core/src/main/resources/sqlmap/ext/ExtMissionFilesMapper.xml
  94. 27 0
      backend-core/src/main/resources/sqlmap/ext/ExtSetPricingsMapper.xml

+ 13 - 0
backend-common/src/main/java/constant/CommonConstant.java

@@ -126,6 +126,19 @@ public interface CommonConstant {
             "<p>如果无法点击,请将链接复制到浏览器地址栏,访问该地址进行重置</p>\n" +
             "<p>系统邮件,请勿回复。</p>";
 
+    String registerEmailTemplate = "<p><b>尊敬的PDF Reader用户,</b></p>\n" +
+            "\n" +
+            "<p>您正在注册长沙凯钿软件PDF Reader 平台账号,</p>\n" +
+            "\n" +
+            "<p>验证码是:<b>\"%s\"</b>,请复制该验证码并完成电子邮件验证过程,</p>\n" +
+            "\n" +
+            "<p>出于安全考虑,该验证码<b>3分钟内</b>有效,且只能使用一次,请及时输入。</p>\n" +
+            "\n" +
+            "<p>PS:如果没有验证码,您的账户将无法访问;如果您没有提交该请求,请忽略本条消息</p>\n" +
+            "\n" +
+            "<p>非常感谢您对PDF Reader的支持,祝您一切顺利</p>\n" +
+            "<p>长沙凯钿软件</p>";
+
     /**
      * 名称校验不通过信息
      */

+ 17 - 0
backend-common/src/main/java/utils/DateUtils.java

@@ -217,4 +217,21 @@ public class DateUtils {
         return time.convert(l, TimeUnit.MILLISECONDS);
     }
 
+
+    /**
+     * 日期加减天数,day是正数为加法,是负数为减法
+     * @param date 被操作的日期
+     * @param day day是正数为加法,是负数为减法
+     * @return 操作后的日期
+     */
+    public static Date addDate(Date date, int day) {
+        Calendar rightNow = Calendar.getInstance();
+        rightNow.setTime(date);
+//      rightNow.add(Calendar.YEAR,-1);//日期减1年
+//      rightNow.add(Calendar.MONTH,3);//日期加3个月
+//      rightNow.add(Calendar.DAY_OF_YEAR,5);//日期加5天
+        rightNow.add(Calendar.DAY_OF_YEAR,day);
+        return rightNow.getTime();
+    }
+
 }

+ 54 - 49
backend-common/src/main/java/utils/EmailUtils.java

@@ -1,15 +1,12 @@
 package utils;
 
-import com.sun.mail.util.MailSSLSocketFactory;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.mail.javamail.MimeMessageHelper;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.Resource;
 import javax.mail.*;
-import javax.mail.internet.*;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
 import java.util.Date;
 import java.util.List;
 import java.util.Properties;
@@ -42,51 +39,59 @@ public class EmailUtils {
 
     public boolean sendMail(String subject,String text,List<String> emails){
         try {
-        //用于读取配置文件
-        Properties props=new Properties();
-        //开启Debug调试
-        props.setProperty("mail.debug", "true");
-        //发送服务器需要身份验证
-        props.setProperty("mail.smtp.auth", "true");
-        //发送邮件服务器的主机名
-        props.setProperty("mail.smtp.host", "smtp.qq.com");
-        //端口号
-        props.setProperty("mail.smtp.port", "465");
-        //发送邮件协议
-        props.setProperty("mail.transport.protocol", "smtp");
-        //开启ssl加密(并不是所有的邮箱服务器都需要,但是qq邮箱服务器是必须的)
-        MailSSLSocketFactory msf= new MailSSLSocketFactory();
-        msf.setTrustAllHosts(true);
-        props.put("mail.smtp.ssl.enable", "true");
-        props.put("mail.smtp.ssl.socketFactory",msf);
-        //获取Session会话实例(javamail Session与HttpSession的区别是Javamail的Session只是配置信息的集合)
-        Session session=Session.getInstance(props,new javax.mail.Authenticator(){
-            protected PasswordAuthentication getPasswordAuthentication(){
-                //用户名密码验证(取得的授权吗)
-                return new PasswordAuthentication ("316531990@qq.com","fcczojbobpusbjfh");
-            }
-        });
+            //用于读取配置文件
+            Properties props=new Properties();
+            //发送服务器需要身份验证
+            props.setProperty("mail.smtp.auth", "true");
+            //发送邮件服务器的主机名
+            props.setProperty("mail.smtp.host", "smtpdm.aliyun.com");
+            //端口号
+            props.setProperty("mail.smtp.port", "465");
+            //发送邮件协议
+            props.setProperty("mail.transport.protocol", "smtp");
+            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+            props.put("mail.smtp.socketFactory.port", "465");
+            props.put("mail.smtp.port", "465");
 
-        //抽象类MimeMessage为实现类 消息载体封装了邮件的所有消息
-        MimeMessage message=new MimeMessage(session);
-        //设置发件人地址
-        message.setFrom(new InternetAddress("316531990@qq.com"));
-        //此类的功能是发送邮件 又会话获得实例
-        Transport transport=session.getTransport();
-        //开启连接
-        transport.connect();
-        //设置收件人地址邮件信息
-        for (int i = 0; i < emails.size(); i++) {
-            MimeMessageHelper messageHelper = new MimeMessageHelper(message, true,"utf-8");
-                // 设置收件人邮箱
-            messageHelper.setTo(emails.get(i));
-            messageHelper.setSubject(subject);
-            messageHelper.setText(text, true);
-            messageHelper.setSentDate(new Date());
-            transport.sendMessage(message,new Address[]{new InternetAddress(emails.get(i))});
-            //邮件发送后关闭信息
-            transport.close();
-        }
+            //mailfrom 参数
+            props.put("mail.smtp.from", "admin@sketchpi.com");
+            // 发件人的账号(在控制台创建的发信地址)
+            props.put("mail.user", "admin@sketchpi.com");
+            // 发信地址的smtp密码(在控制台选择发信地址进行设置)
+            props.put("mail.password", "Kdan24373514");
+            // 构建授权信息,用于进行SMTP进行身份验证
+            Authenticator authenticator = new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    // 用户名、密码
+                    String userName = props.getProperty("mail.user");
+                    String password = props.getProperty("mail.password");
+                    return new PasswordAuthentication(userName, password);
+                }
+            };
+            Session mailSession = Session.getInstance(props, authenticator);
+            //开启debug模式
+            mailSession.setDebug(true);
+            //抽象类MimeMessage为实现类 消息载体封装了邮件的所有消息
+            MimeMessage message = new MimeMessage(mailSession);
+            //设置发件人地址
+            message.setFrom(new InternetAddress("admin@sketchpi.com","Admin"));
+            //此类的功能是发送邮件 又会话获得实例
+            Transport transport=mailSession.getTransport();
+            //开启连接
+            transport.connect();
+            //设置收件人地址邮件信息
+            for (int i = 0; i < emails.size(); i++) {
+                MimeMessageHelper messageHelper = new MimeMessageHelper(message, true,"utf-8");
+                    // 设置收件人邮箱
+                messageHelper.setTo(emails.get(i));
+                messageHelper.setSubject(subject);
+                messageHelper.setText(text, true);
+                messageHelper.setSentDate(new Date());
+                transport.sendMessage(message,new Address[]{new InternetAddress(emails.get(i))});
+                //邮件发送后关闭信息
+                transport.close();
+            }
             return true;
         } catch (Exception e) {
             log.error("send mail error : " + e.getMessage(), e);

+ 7 - 0
backend-core/pom.xml

@@ -153,6 +153,13 @@
             <artifactId>alipay-sdk-java</artifactId>
             <version>4.31.72.ALL</version>
         </dependency>
+
+        <!-- oss上传 -->
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.15.1</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 1 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/client/ComPdfKitClient.java

@@ -82,7 +82,7 @@ public class ComPdfKitClient {
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         Map<String, String> tokenParam = new HashMap<>();
-        tokenParam.put("projectKey", projectKey);
+        tokenParam.put("publicKey", projectKey);
         tokenParam.put("secretKey", secretKey);
         ResponseEntity<ComPdfKitResult<ComPdfKitOauthResult>> responseEntity;
         ParameterizedTypeReference<ComPdfKitResult<ComPdfKitOauthResult>> typeRef = new ParameterizedTypeReference<ComPdfKitResult<ComPdfKitOauthResult>>() {};

+ 344 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/client/OssFileClient.java

@@ -0,0 +1,344 @@
+package cn.kdan.pdf.backend.core.client;
+
+import cn.kdan.pdf.backend.core.properties.OssProperties;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.common.utils.BinaryUtil;
+import com.aliyun.oss.internal.OSSHeaders;
+import com.aliyun.oss.model.*;
+import exception.BackendRuntimeException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.util.*;
+
+/**
+ * @author ZhouQiang 2022/7/13
+ */
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class OssFileClient {
+
+    private final OssProperties ossProperties;
+    private final OSS ossClient;
+
+    public OSS ossClient() {
+        return new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+    }
+
+    /**
+     * 普通上传
+     *
+     * @param bytes    文件字节数组
+     * @param fileName 文件名
+     * @return fileKey
+     * @throws IOException 异常
+     */
+    public String upload(byte[] bytes, String fileName) throws IOException {
+        String fileKey = generateFileKey(fileName);
+        PutObjectRequest request = new PutObjectRequest(ossProperties.getBucketName(), fileKey, new ByteArrayInputStream(bytes));
+        ossClient.putObject(request);
+        return fileKey;
+    }
+
+    /**
+     * 普通上传
+     *
+     * @param file 文件
+     * @param isPic 是否是图片
+     * @return fileKey
+     * @throws IOException 异常
+     */
+    public String upload(MultipartFile file, boolean isPic) throws IOException {
+        String fileKey = generateFileKey(file.getOriginalFilename());
+        PutObjectRequest request;
+        if(isPic) {
+            ObjectMetadata meta = new ObjectMetadata();
+            meta.setContentType("image/jpg");
+            request = new PutObjectRequest(ossProperties.getBucketName(), fileKey, file.getInputStream(), meta);
+        }else{
+            request = new PutObjectRequest(ossProperties.getBucketName(), fileKey, file.getInputStream());
+        }
+        ossClient.putObject(request);
+        return fileKey;
+    }
+
+    /**
+     * 普通上传
+     *
+     * @param filePath 文件路径
+     * @param fileName 文件名
+     * @return fileKey 文件key
+     * @throws IOException 异常
+     */
+    public String upload(String filePath, String fileName) throws IOException {
+        String fileKey = generateFileKey(fileName);
+        PutObjectRequest request = new PutObjectRequest(ossProperties.getBucketName(), fileKey, new BufferedInputStream(new FileInputStream(filePath)));
+        ObjectMetadata metadata = new ObjectMetadata();
+        metadata.setHeader(OSSHeaders.CONTENT_DISPOSITION, "attachment;filename="+
+                URLEncoder.encode(fileName,"UTF-8")+";filename*=UTF-8''" +
+                URLEncoder.encode(fileName,"UTF-8"));
+        request.setMetadata(metadata);
+        ossClient.putObject(request);
+        return fileKey;
+    }
+
+    /**
+     * 分片上传
+     *
+     * @param file      文件
+     * @param sliceSize 分片
+     * @return fileKey
+     */
+    public String fragmentUpload(MultipartFile file, Long sliceSize) {
+
+        String fileKey = generateFileKey(file.getOriginalFilename());
+        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(ossProperties.getBucketName(), fileKey);
+        try {
+            // 初始化分片。
+            InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(request);
+            // 返回uploadId,它是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作,例如取消分片上传、查询分片上传等。
+            String uploadId = upResult.getUploadId();
+
+            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
+            List<PartETag> partETags = new ArrayList<>();
+            // 每个分片的大小,用于计算文件有多少个分片。单位为字节。
+            final long partSize = sliceSize == null ? 1024 * 1024L : sliceSize;   //1 MB。
+
+            // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
+            long fileLength = file.getSize();
+            int partCount = (int) (fileLength / partSize);
+            if (fileLength % partSize != 0) {
+                partCount++;
+            }
+            // 遍历分片上传。
+            for (int i = 0; i < partCount; i++) {
+                long startPos = i * partSize;
+                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
+                // 跳过已经上传的分片。
+                InputStream is = file.getInputStream();
+                is.skip(startPos);
+                UploadPartRequest uploadPartRequest = new UploadPartRequest();
+                uploadPartRequest.setBucketName(ossProperties.getBucketName());
+                uploadPartRequest.setKey(fileKey);
+                uploadPartRequest.setUploadId(uploadId);
+                uploadPartRequest.setInputStream(is);
+                // 设置分片大小。除了最后一个分片没有大小限制,其他的分片最小为100 KB。
+                uploadPartRequest.setPartSize(curPartSize);
+                // 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出此范围,OSS将返回InvalidArgument错误码。
+                uploadPartRequest.setPartNumber(i + 1);
+                // 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
+                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
+                // 每次上传分片之后,OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
+                partETags.add(uploadPartResult.getPartETag());
+            }
+
+            // 创建CompleteMultipartUploadRequest对象。
+            // 在执行完成分片上传操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
+            CompleteMultipartUploadRequest completeMultipartUploadRequest =
+                    new CompleteMultipartUploadRequest(ossProperties.getBucketName(), fileKey, uploadId, partETags);
+
+            // 完成分片上传。
+            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
+            System.out.println(completeMultipartUploadResult.getETag());
+
+            return fileKey;
+        } catch (IOException e) {
+            log.error("分片上传异常", e);
+            throw new BackendRuntimeException("文件上传异常");
+        }
+    }
+
+    /**
+     * 文件下载
+     *
+     * @param fileObject 文件Key
+     * @param pathName   下载保存的文件全路径
+     */
+    public void download(String fileObject, String pathName) {
+        ossClient.getObject(new GetObjectRequest(ossProperties.getBucketName(), fileObject), new File(pathName));
+    }
+
+    /**
+     * 文件下载
+     *
+     * @param fileObject 文件key
+     * @return 文件流
+     */
+    public InputStream download(String fileObject) {
+        OSS oss = ossClient();
+        OSSObject ossObject = oss.getObject(ossProperties.getBucketName(), fileObject);
+        return ossObject.getObjectContent();
+    }
+
+    /**
+     * 生成有时效性的oss文件下载地址
+     *
+     * @param fileObject 文件key
+     * @param expiration 有效时间(毫秒)
+     * @return URL
+     */
+    public URL generateTermUrl(String fileObject, long expiration) {
+        return ossClient.generatePresignedUrl(ossProperties.getBucketName(), fileObject, new Date(System.currentTimeMillis() + expiration));
+    }
+
+    /**
+     * 生成fileKey
+     *
+     * @param fileName 文件名
+     * @return fileKey
+     */
+    private String generateFileKey(String fileName) {
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        return ossProperties.getFilePrefix() + "/" + LocalDate.now().toString().replaceAll("-", "/") + "/" + uuid + "@" + fileName;
+    }
+
+    /**
+     * police策略
+     *
+     * @return map
+     */
+    public Map<String, String> policy() {
+
+        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
+        String dir = LocalDate.now().toString().replaceAll("-", "/");
+        long expireTime = 30;
+        long expireEndTime = expireTime * 1000;
+        Date expiration = new Date(System.currentTimeMillis() + expireEndTime);
+        // 修改自己服务的回调接口
+        String callbackUrl = "https://localhost/upload/callback";
+        PolicyConditions policyConds = new PolicyConditions();
+        policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 10L * 1024 * 1024 * 1024);
+        policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
+
+        String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
+        byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
+        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
+        String postSignature = ossClient.calculatePostSignature(postPolicy);
+
+        Map<String, String> respMap = new LinkedHashMap<>();
+        respMap.put("accessid", ossProperties.getAccessKeyId());
+        respMap.put("policy", encodedPolicy);
+        respMap.put("signature", postSignature);
+        respMap.put("dir", dir);
+        respMap.put("host", ossProperties.getEndpoint().replaceFirst("https://", "https://" + ossProperties.getBucketName() + "."));
+        respMap.put("expire", String.valueOf(expireEndTime / 1000));
+
+        JSONObject jasonCallback = new JSONObject();
+        jasonCallback.put("callbackUrl", callbackUrl);
+        jasonCallback.put("callbackBody",
+                "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
+        jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
+        String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
+        respMap.put("callback", base64CallbackBody);
+
+        return respMap;
+    }
+
+
+    public void deletePrefixFile(String fileDirectory) {
+        String bucketName = ossProperties.getBucketName();
+        String filePrefix = ossProperties.getFilePrefix();
+        StringBuilder prefix = new StringBuilder(filePrefix);
+        prefix.append("/").append(fileDirectory).append("/");
+        //avatars/{param}/
+        try {
+            // 删除目录及目录下的所有文件。
+            String nextMarker = null;
+            ObjectListing objectListing = null;
+            do {
+                ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName)
+                        .withPrefix(prefix.toString())
+                        .withMarker(nextMarker);
+
+                objectListing = ossClient.listObjects(listObjectsRequest);
+                if (objectListing.getObjectSummaries().size() > 0) {
+                    List<String> keys = new ArrayList<>();
+                    for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
+                        keys.add(s.getKey());
+                    }
+                    DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url");
+                    DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
+                    List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
+                    try {
+                        for (String obj : deletedObjects) {
+                            String deleteObj = URLDecoder.decode(obj, "UTF-8");
+                            System.out.println(deleteObj);
+                        }
+                    } catch (UnsupportedEncodingException e) {
+                        e.printStackTrace();
+                    }
+                }
+
+                nextMarker = objectListing.getNextMarker();
+            } while (objectListing.isTruncated());
+        } catch (OSSException oe) {
+            log.error("oss删除文件报错:{},Error Code:{},Request ID:{},Host ID:{}",oe.getMessage(), oe.getErrorCode(),oe.getRequestId(),oe.getHostId());
+        } catch (ClientException ce) {
+            log.error("oss删除文件连接客户端报错:{}",ce.getMessage());
+        }
+    }
+
+    public void delete(String objectName){
+        String bucketName = ossProperties.getBucketName();
+        try {
+            // 删除文件或目录。如果要删除目录,目录必须为空。
+            ossClient.deleteObject(bucketName, objectName);
+        } catch (OSSException oe) {
+            log.error("oss删除文件报错:{},Error Code:{},Request ID:{},Host ID:{}",oe.getMessage(), oe.getErrorCode(),oe.getRequestId(),oe.getHostId());
+        } catch (ClientException ce) {
+            log.error("oss删除文件连接客户端报错:{}",ce.getMessage());
+        }
+    }
+
+    /**
+     * 生成访问路径
+     * @param objectName 文件路径(包名开始)
+     * @return 访问路径url
+     */
+    public URL getUrl(String objectName){
+        // 填写Bucket名称,例如examplebucket。
+        String bucketName = ossProperties.getBucketName();
+        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectName);
+        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
+        generatePresignedUrlRequest.setExpiration(expiration);
+        URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
+        System.out.println(url);
+        return url;
+    }
+
+    /**
+     * 设置文件访问权限(读权限)
+     * @param objectName 文件路径(包名开始)
+     * @return 设置权限是否成功
+     */
+    public boolean setAcl(String objectName){
+        boolean flag = false;
+        String bucketName = ossProperties.getBucketName();
+        try {
+            // 创建SetObjectAclRequest对象,此示例中设置文件的访问权限为公共读。
+            SetObjectAclRequest setObjectAclRequest = new SetObjectAclRequest(bucketName, objectName, CannedAccessControlList.PublicRead);
+            // 设置指定文件的权限。
+            ossClient.setObjectAcl(setObjectAclRequest);
+            flag = true;
+        } catch (OSSException oe) {
+            log.error("oss设置权限访问出错:{},Error Code:{},Request ID:{},Host ID:{}",oe.getMessage(), oe.getErrorCode(),oe.getRequestId(),oe.getHostId());
+        } catch (ClientException ce) {
+            log.error("oss删除文件连接客户端报错:{}",ce.getMessage());
+        }
+        return flag;
+    }
+
+}

+ 19 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/config/OssConfig.java

@@ -0,0 +1,19 @@
+package cn.kdan.pdf.backend.core.config;
+
+import cn.kdan.pdf.backend.core.properties.OssProperties;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author ZhouQiang 2022/7/13
+ */
+@Configuration
+public class OssConfig {
+
+    @Bean
+    public OSS ossClient(OssProperties ossProperties) {
+        return new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
+    }
+}

+ 6 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/config/oauth/AuthExceptionEntryPoint.java

@@ -2,6 +2,7 @@ package cn.kdan.pdf.backend.core.config.oauth;
 
 import cn.kdan.pdf.backend.core.constant.AuthConstant;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
 import org.springframework.security.web.AuthenticationEntryPoint;
@@ -13,6 +14,7 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
+@Slf4j
 public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
     /**
      * 处理token过期的返回内容
@@ -31,7 +33,10 @@ public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
             map.put("code", AuthConstant.EXCEPTION_CODE_USER_NOT_LOGIN);
             map.put("msg", AuthConstant.EXCEPTION_MSG_USER_NOT_LOGIN);
         }
-        map.put("data", authException.getMessage());
+        //modify app端解析该内容报错,故置空该返回值 by songfuqiang 2022年12月16日09:34:01
+//        map.put("data", authException.getMessage());
+        log.info(map.get("msg").toString() + ":" + authException.getMessage());
+        map.put("data", "");
         map.put("path", request.getServletPath());
         map.put("timestamp", String.valueOf(System.currentTimeMillis()));
         response.setContentType("application/json");

+ 4 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/constant/AuthConstant.java

@@ -114,6 +114,10 @@ public interface AuthConstant {
 
     Long VERIFY_CODE_KEY_EXPIRE_TIME = 15 * 60L;
 
+    Long EMAIL_VERIFY_CODE_KEY_EXPIRE_TIME = 3 * 60L;
+
+    Long VERIFY_CODE_KEY_EXPIRE_TIME_FORGET = 15 * 60L;
+
     Long VERIFY_CODE_KEY_RESEND_TIME = 60L;
 
     String VERIFY_CODE_SEND_TOO_QUICKLY = "您的操作过于频繁,请稍后再试";

+ 4 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/constant/OrderConstant.java

@@ -6,4 +6,8 @@ package cn.kdan.pdf.backend.core.constant;
 public interface OrderConstant {
 
     String EXCEPTION_MSG_GET_ORDER_EXIST = "订单已支付";
+
+    Integer ALIPAY_EXPIRE_TIME = 12;
+
+    Integer WXPAY_EXPIRE_TIME = 2;
 }

+ 35 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AdvertisementController.java

@@ -0,0 +1,35 @@
+package cn.kdan.pdf.backend.core.controller;
+
+import cn.kdan.pdf.backend.core.params.QueryAdvertisementParam;
+import cn.kdan.pdf.backend.core.pojo.app.AdvertisementVo;
+import cn.kdan.pdf.backend.core.service.AdvertisementService;
+import constant.CommonConstant;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import pojo.AppRequestParam;
+import pojo.AppResultMap;
+
+import java.util.List;
+
+/**
+ * @author sfq
+ * @description
+ */
+@RestController
+@RequestMapping("/advertisement")
+public class AdvertisementController {
+
+    @Autowired
+    private AdvertisementService advertisementService;
+
+    /**
+     * 条件查询广告数据
+     * @param param 查询条件
+     * @return 广告信息
+     */
+    @GetMapping("/list")
+    public AppResultMap<List<AdvertisementVo>> list( QueryAdvertisementParam param){
+        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,advertisementService.list(param));
+    }
+
+}

+ 1 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AlipayController.java

@@ -23,7 +23,7 @@ public class AlipayController {
 
     @GetMapping("/pay")
     public String pay() {
-        return alipayService.createAlipayPageUrl("17PDF会员订阅", "20210817010101014", 0.01f, null);
+        return alipayService.createAlipayPageUrl("17PDF会员订阅", "20210817010101014", 0.01f, null, "android");
     }
 
     @GetMapping("/query")

+ 25 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AuthController.java

@@ -3,11 +3,13 @@ package cn.kdan.pdf.backend.core.controller;
 import cn.kdan.pdf.backend.core.constant.AuthConstant;
 import cn.kdan.pdf.backend.core.enums.CaptchaActionEnum;
 import cn.kdan.pdf.backend.core.enums.VerifyTypeEnum;
+import cn.kdan.pdf.backend.core.params.AppLogoutParam;
 import cn.kdan.pdf.backend.core.params.RelationParam;
 import cn.kdan.pdf.backend.core.pojo.app.LoginInfoVo;
 import cn.kdan.pdf.backend.core.pojo.oauth2.TokenPOJO;
 import cn.kdan.pdf.backend.core.service.AuthService;
 import constant.CommonConstant;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import pojo.AppRequestParam;
 import pojo.AppResultMap;
@@ -102,7 +104,29 @@ public class AuthController {
      */
     @PostMapping("/appGetToken")
     public AppResultMap<LoginInfoVo> appGetToken(@RequestBody AppRequestParam<RelationParam> param){
-        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,authService.appGetToken(param.getData()));
+        LoginInfoVo loginInfoVo = authService.appGetToken(param.getData());
+        if(StringUtils.isEmpty(loginInfoVo.getMessage())){
+            return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,loginInfoVo);
+        }else{
+            return new AppResultMap<>(CommonConstant.EXCEPTION_CODE_RUNTIME_ERROR,loginInfoVo.getMessage(),loginInfoVo);
+        }
+
+    }
+
+    @PostMapping("/logout")
+    public AppResultMap<String> logOut(@RequestBody AppLogoutParam param) {
+        authService.logout(param);
+        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,"登出成功");
+    }
+
+    /**
+     * 清除设备信息并清除token信息
+     * @param id 用户id
+     * @return
+     */
+    @GetMapping("/clearDevice")
+    public AppResultMap<String> clearDevice(@RequestParam("id") String id){
+        return new AppResultMap<>(CommonConstant.SUCCESS, CommonConstant.CODE_SUCCESS, authService.clearDevice(id));
     }
 
 }

+ 47 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/AvatarController.java

@@ -0,0 +1,47 @@
+package cn.kdan.pdf.backend.core.controller;
+
+import cn.kdan.pdf.backend.core.model.Avatars;
+import cn.kdan.pdf.backend.core.pojo.app.UpTokenVo;
+import cn.kdan.pdf.backend.core.service.AvatarService;
+import constant.CommonConstant;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.beans.factory.annotation.Autowired;
+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 org.springframework.web.multipart.MultipartFile;
+import pojo.AppResultMap;
+
+import java.util.List;
+
+/**
+ * @author sfq
+ * @description
+ */
+@RestController
+@RequestMapping("/avatar")
+public class AvatarController {
+
+    @Autowired
+    private AvatarService avatarService;
+
+    /**
+     * 查询头像列表
+     * @return 头像列表信息
+     */
+    @GetMapping("/list")
+    public AppResultMap<List<Avatars>> list(){
+        return new AppResultMap(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,avatarService.list());
+    }
+
+    /**
+     * 获取头像上传的token
+     * @return token+用户信息
+     */
+    @PostMapping("/picUpload")
+    public AppResultMap<UpTokenVo> picUpload(@Param("file")MultipartFile file){
+        return new AppResultMap(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,avatarService.picUpload(file));
+    }
+
+}

+ 8 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/ConvertTypeController.java

@@ -1,5 +1,6 @@
 package cn.kdan.pdf.backend.core.controller;
 
+import cn.kdan.pdf.backend.core.params.QueryConvertTypeParam;
 import cn.kdan.pdf.backend.core.pojo.ConvertTypeVo;
 import cn.kdan.pdf.backend.core.pojo.MissionVO;
 import cn.kdan.pdf.backend.core.service.ConvertFileService;
@@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import pojo.AppResultMap;
 import pojo.ResultMap;
 
 import java.util.List;
@@ -23,7 +25,7 @@ public class ConvertTypeController {
 
     @GetMapping("/getConvertTypeList")
     public ResultMap<List<ConvertTypeVo>> getConvertTypeList(@RequestParam("input") String inputFileType, @RequestParam("output") String outputFileType) {
-        return new ResultMap<>(CommonConstant.SUCCESS, "获取转档类型列表", convertFileService.getConvertTypeList(inputFileType, outputFileType));
+        return new ResultMap<>(CommonConstant.SUCCESS, "获取转档类型列表成功", convertFileService.getConvertTypeList(inputFileType, outputFileType));
     }
 
     @GetMapping("/getFileStatus")
@@ -31,4 +33,9 @@ public class ConvertTypeController {
         return new ResultMap<>(CommonConstant.SUCCESS, "获取文件状态成功", convertFileService.getFileStatus(mid));
     }
 
+    @GetMapping("/appList")
+    public AppResultMap<List<ConvertTypeVo>> appList(QueryConvertTypeParam param){
+        return new AppResultMap<>(CommonConstant.SUCCESS, "获取转档类型列表成功", convertFileService.getConvertTypeList(param.getIn(), param.getOut()));
+    }
+
 }

+ 31 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/DeviceController.java

@@ -0,0 +1,31 @@
+package cn.kdan.pdf.backend.core.controller;
+
+import cn.kdan.pdf.backend.core.params.RelationParam;
+import cn.kdan.pdf.backend.core.service.DeviceService;
+import constant.CommonConstant;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import pojo.AppRequestParam;
+import pojo.AppResultMap;
+import pojo.Device;
+
+/**
+ * @author sfq
+ * @description
+ */
+@RestController
+@RequestMapping("/device")
+public class DeviceController {
+
+    @Autowired
+    private DeviceService deviceService;
+
+    @PutMapping("/updateInfo")
+    public AppResultMap<Device> updateInfo(@RequestBody AppRequestParam<RelationParam> param){
+        return new AppResultMap(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,deviceService.updateInfo(param.getData()));
+    }
+
+}

+ 30 - 4
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/MembersController.java

@@ -9,12 +9,14 @@ import cn.kdan.pdf.backend.core.model.member.MemberRegisterReq;
 import cn.kdan.pdf.backend.core.model.member.MemberRegisterResp;
 import cn.kdan.pdf.backend.core.model.member.ModifyPasswordReq;
 import cn.kdan.pdf.backend.core.params.BindAccountParam;
+import cn.kdan.pdf.backend.core.params.CheckExistsParam;
 import cn.kdan.pdf.backend.core.params.UserResetPwdParams;
+import cn.kdan.pdf.backend.core.pojo.ExistsMemberVo;
 import cn.kdan.pdf.backend.core.pojo.app.BindAccountVo;
+import cn.kdan.pdf.backend.core.pojo.app.MemberInfoVo;
 import cn.kdan.pdf.backend.core.pojo.app.MemberVo;
 import cn.kdan.pdf.backend.core.service.AuthService;
 import cn.kdan.pdf.backend.core.service.MemberService;
-import com.sun.org.apache.xpath.internal.objects.XString;
 import constant.CommonConstant;
 import exception.BackendRuntimeException;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -110,6 +112,21 @@ public class MembersController {
         }
     }
 
+    /**
+     * 用于忘记密码时重置密码
+     *
+     * @param params params
+     * @return Boolean
+     */
+    @PostMapping("/appResetPassword")
+    public AppResultMap<String> appResetPassword(@RequestBody AppRequestParam<UserResetPwdParams> params) {
+        if (memberService.appResetPassword(params.getData())) {
+            return new AppResultMap<>(CommonConstant.SUCCESS, MembersConstant.PASSWORD_UPDATE_SUCCESS, params.getData().getAccount());
+        } else {
+            return new AppResultMap<>(CommonConstant.SUCCESS, MembersConstant.PASSWORD_UPDATE_ERROR, "发送邮件失败");
+        }
+    }
+
 
     /**
      * 用于忘记密码时检查重置密码连接是否失效
@@ -165,8 +182,8 @@ public class MembersController {
      * @return 用户信息
      */
     @GetMapping("appGetMemberInfo")
-    public AppResultMap<MemberInfoResp> appGetMemberInfo(@RequestParam("subscription") String subscription, @RequestParam("withSocial") String withSocial){
-        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,memberService.getMemberDetail(null));
+    public AppResultMap<MemberInfoVo> appGetMemberInfo(@RequestParam("subscription") String subscription, @RequestParam("withSocial") String withSocial){
+        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,memberService.appGetMemberInfo(subscription, withSocial));
     }
 
     /**
@@ -175,9 +192,18 @@ public class MembersController {
      * @return 用户信息
      */
     @PutMapping("appModifyName")
-    public AppResultMap<MemberVo> appModifyName(@RequestParam("name") AppRequestParam<String> param){
+    public AppResultMap<MemberVo> appModifyName(@RequestBody AppRequestParam<String> param){
         return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,memberService.appModifyName(param.getData()));
     }
 
+    /**
+     * 检查内容是否存在
+     * @param param param
+     * @return vo
+     */
+    @PostMapping("/checkExists")
+    public AppResultMap<ExistsMemberVo> checkExists(@RequestBody AppRequestParam<CheckExistsParam> param){
+        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,memberService.checkExists(param.getData()));
+    }
 
 }

+ 10 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/MissionFilesController.java

@@ -10,6 +10,7 @@ import constant.CommonConstant;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import pojo.AppResultMap;
 import pojo.ResultMap;
 
 import javax.servlet.http.HttpServletResponse;
@@ -97,4 +98,13 @@ public class MissionFilesController {
         }
         inputStream.close();
     }
+
+    /**
+     * 获取转档文件总数
+     * @return 文件总数
+     */
+    @GetMapping("/getTotalConvertFile")
+    public AppResultMap<Integer> getTotalConvertFile(){
+        return new AppResultMap<>(CommonConstant.SUCCESS, CommonConstant.RESULT_SUCCESS, missionFilesService.getTotalConvertFile());
+    }
 }

+ 12 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/PricingController.java

@@ -2,10 +2,12 @@ package cn.kdan.pdf.backend.core.controller;
 
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingReq;
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingResp;
+import cn.kdan.pdf.backend.core.params.QueryPricingParam;
 import cn.kdan.pdf.backend.core.service.PricingService;
 import constant.CommonConstant;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
+import pojo.AppResultMap;
 import pojo.ResultMap;
 
 /**
@@ -27,4 +29,14 @@ public class PricingController {
         return new ResultMap<>(CommonConstant.SUCCESS, "查询券服务列表成功", pricingList);
     }
 
+    /**
+     * app端获取商品价目表
+     * @param param 入参
+     * @return 商品价目表列表
+     */
+    @GetMapping("/appList")
+    public AppResultMap<QueryPricingResp> appList(QueryPricingParam param){
+        return new AppResultMap<>(CommonConstant.SUCCESS,CommonConstant.CODE_SUCCESS,pricingService.appList(param));
+    }
+
 }

+ 30 - 4
backend-core/src/main/java/cn/kdan/pdf/backend/core/controller/SubscriptionController.java

@@ -1,13 +1,15 @@
 package cn.kdan.pdf.backend.core.controller;
 
+import cn.kdan.pdf.backend.core.params.ExpenseParam;
 import cn.kdan.pdf.backend.core.params.SubscriptionCreateParams;
 import cn.kdan.pdf.backend.core.pojo.SubscriptionVO;
+import cn.kdan.pdf.backend.core.pojo.app.CreateSubVo;
+import cn.kdan.pdf.backend.core.pojo.app.ExpenseVo;
+import cn.kdan.pdf.backend.core.pojo.app.RemindVo;
 import cn.kdan.pdf.backend.core.service.SubscriptionService;
 import constant.CommonConstant;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import pojo.AppResultMap;
 import pojo.ResultMap;
 
 import javax.annotation.Resource;
@@ -32,4 +34,28 @@ public class SubscriptionController {
     public ResultMap<SubscriptionVO> create(@RequestBody SubscriptionCreateParams params) {
         return new ResultMap<>(CommonConstant.SUCCESS, CommonConstant.RESULT_SUCCESS, subscriptionService.create(params.getClient(), params.getPayment(), params.getTargetType(), params.getTargetId()));
     }
+
+    @PostMapping("/appCreate")
+    public AppResultMap<CreateSubVo> appCreate(@RequestBody SubscriptionCreateParams params) {
+        return new AppResultMap<>(CommonConstant.SUCCESS, CommonConstant.RESULT_SUCCESS, subscriptionService.appCreate(params.getClient(), params.getPayment(), params.getTargetType(), params.getTargetId()));
+    }
+
+    /**
+     * 转档券消耗
+     * @param param 券消耗接口参数
+     * @return 券消耗接口返回
+     */
+    @PostMapping("/expense")
+    public AppResultMap<ExpenseVo> expense(@RequestBody ExpenseParam param){
+        return new AppResultMap(CommonConstant.SUCCESS, CommonConstant.RESULT_SUCCESS,subscriptionService.expense(param));
+    }
+
+    /**
+     * 获取套餐过期信息
+     * @return 套餐过期信息返回
+     */
+    @GetMapping("/remindRenew")
+    public AppResultMap<RemindVo> remindRenew(){
+        return new AppResultMap(CommonConstant.SUCCESS, CommonConstant.RESULT_SUCCESS,subscriptionService.remindRenew());
+    }
 }

+ 1 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/CaptchaActionEnum.java

@@ -6,7 +6,7 @@ package cn.kdan.pdf.backend.core.enums;
 
 public enum CaptchaActionEnum {
     //注册用户
-    USER_REGISTER("0", "注册用户", ""),
+    USER_REGISTER("0", "注册用户", "PDF Reader - 验证您的电子邮件!"),
     //忘记密码
     FORGET_PASSWORD("1", "忘记密码", "17PDF Reader(Staging)账号密码重置");
 

+ 25 - 7
backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/FileTypeEnum.java

@@ -2,23 +2,41 @@ package cn.kdan.pdf.backend.core.enums;
 
 /**
  * 文件类行枚举
+ * @author sfq
  */
 public enum FileTypeEnum {
 
+    /**
+     * pdf文件类型
+     */
     PDF("pdf"),
-
+    /**
+     * png文件类型
+     */
     PNG("png"),
-
+    /**
+     * jpg文件类型
+     */
     JPG("jpg"),
-
+    /**
+     * txt文件类型
+     */
     TXT("txt"),
-
+    /**
+     * docx文件类型
+     */
     DOCX("docx"),
-
+    /**
+     * pptx文件类型
+     */
     PPTX("pptx"),
-
+    /**
+     * xlsx文件类型
+     */
     XLSX("xlsx"),
-
+    /**
+     * doc文件类型
+     */
     DOC("doc");
 
 

+ 2 - 2
backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/GoodsTypeEnum.java

@@ -7,11 +7,11 @@ package cn.kdan.pdf.backend.core.enums;
 public enum GoodsTypeEnum {
 
     /**
-     * 在售
+     * 
      */
     Pricing("Pricing"),
     /**
-     * 下架
+     * 会员
      */
     SetPricing("SetPricing");
 

+ 45 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/LanguageEnum.java

@@ -0,0 +1,45 @@
+package cn.kdan.pdf.backend.core.enums;
+
+/**
+ * @author : sfq
+ * @date : 2022/12/14 19:47
+ * @description 'zh-CN': 0, 'en': 1
+ */
+public enum LanguageEnum {
+
+    /**
+     * 中文
+     */
+    ZH_CN("zh-CN",0),
+    /**
+     * 英文
+     */
+    EN("en",1);
+
+    private final String name;
+    private final Integer value;
+
+    LanguageEnum(String name, Integer value){
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Integer getValue() {
+        return value;
+    }
+
+    public static Integer getCodeByName(String name){
+        Integer value = 0;
+        for (LanguageEnum languageEnum : LanguageEnum.values()) {
+            if(languageEnum.getName().equals(name)){
+                value = languageEnum.getValue();
+            }
+        }
+        return value;
+    }
+
+}

+ 10 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/enums/ProviderEnum.java

@@ -42,4 +42,14 @@ public enum ProviderEnum {
         }
         return value;
     }
+
+    public static String getNameByCode(Integer code){
+        String value = "tencent";
+        for (ProviderEnum providerEnum : ProviderEnum.values()) {
+            if(providerEnum.getValue().equals(code)){
+                value = providerEnum.getName();
+            }
+        }
+        return value;
+    }
 }

+ 33 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/mapper/ExpensesMapper.java

@@ -0,0 +1,33 @@
+package cn.kdan.pdf.backend.core.mapper;
+
+import cn.kdan.pdf.backend.core.model.Expenses;
+import cn.kdan.pdf.backend.core.model.ExpensesExample;
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.session.RowBounds;
+
+public interface ExpensesMapper {
+    long countByExample(ExpensesExample example);
+
+    int deleteByExample(ExpensesExample example);
+
+    int deleteByPrimaryKey(String id);
+
+    int insert(Expenses record);
+
+    int insertSelective(Expenses record);
+
+    List<Expenses> selectByExampleWithRowbounds(ExpensesExample example, RowBounds rowBounds);
+
+    List<Expenses> selectByExample(ExpensesExample example);
+
+    Expenses selectByPrimaryKey(String id);
+
+    int updateByExampleSelective(@Param("record") Expenses record, @Param("example") ExpensesExample example);
+
+    int updateByExample(@Param("record") Expenses record, @Param("example") ExpensesExample example);
+
+    int updateByPrimaryKeySelective(Expenses record);
+
+    int updateByPrimaryKey(Expenses record);
+}

+ 21 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/mapper/ext/ExtSetPricingsMapper.java

@@ -1,4 +1,25 @@
 package cn.kdan.pdf.backend.core.mapper.ext;
 
+import cn.kdan.pdf.backend.core.model.Subscriptions;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
 public interface ExtSetPricingsMapper {
+
+    /**
+     * 查询mode为0的会员服务
+     * @param memberId 用户id
+     * @return 订阅服务集合
+     */
+    List<Subscriptions> selectMode0(@Param("memberId") String memberId);
+
+    /**
+     * 根据mode和用户id查询券服务
+     * @param memberId 用户id
+     * @param mode 模式
+     * @return 订阅服务集合
+     */
+    List<Subscriptions> selectByModeAndMemberId(@Param("memberId") String memberId, @Param("mode")String mode);
+
 }

+ 202 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/model/Expenses.java

@@ -0,0 +1,202 @@
+package cn.kdan.pdf.backend.core.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class Expenses implements Serializable {
+    private String id;
+
+    private String memberId;
+
+    private String uniqueKey;
+
+    private String uniqueValue;
+
+    private Integer points;
+
+    private String info;
+
+    private Date createdAt;
+
+    private Date updatedAt;
+
+    private Date deletedAt;
+
+    private static final long serialVersionUID = 1L;
+
+    public String getId() {
+        return id;
+    }
+
+    public Expenses withId(String id) {
+        this.setId(id);
+        return this;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getMemberId() {
+        return memberId;
+    }
+
+    public Expenses withMemberId(String memberId) {
+        this.setMemberId(memberId);
+        return this;
+    }
+
+    public void setMemberId(String memberId) {
+        this.memberId = memberId;
+    }
+
+    public String getUniqueKey() {
+        return uniqueKey;
+    }
+
+    public Expenses withUniqueKey(String uniqueKey) {
+        this.setUniqueKey(uniqueKey);
+        return this;
+    }
+
+    public void setUniqueKey(String uniqueKey) {
+        this.uniqueKey = uniqueKey;
+    }
+
+    public String getUniqueValue() {
+        return uniqueValue;
+    }
+
+    public Expenses withUniqueValue(String uniqueValue) {
+        this.setUniqueValue(uniqueValue);
+        return this;
+    }
+
+    public void setUniqueValue(String uniqueValue) {
+        this.uniqueValue = uniqueValue;
+    }
+
+    public Integer getPoints() {
+        return points;
+    }
+
+    public Expenses withPoints(Integer points) {
+        this.setPoints(points);
+        return this;
+    }
+
+    public void setPoints(Integer points) {
+        this.points = points;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+
+    public Expenses withInfo(String info) {
+        this.setInfo(info);
+        return this;
+    }
+
+    public void setInfo(String info) {
+        this.info = info;
+    }
+
+    public Date getCreatedAt() {
+        return createdAt;
+    }
+
+    public Expenses withCreatedAt(Date createdAt) {
+        this.setCreatedAt(createdAt);
+        return this;
+    }
+
+    public void setCreatedAt(Date createdAt) {
+        this.createdAt = createdAt;
+    }
+
+    public Date getUpdatedAt() {
+        return updatedAt;
+    }
+
+    public Expenses withUpdatedAt(Date updatedAt) {
+        this.setUpdatedAt(updatedAt);
+        return this;
+    }
+
+    public void setUpdatedAt(Date updatedAt) {
+        this.updatedAt = updatedAt;
+    }
+
+    public Date getDeletedAt() {
+        return deletedAt;
+    }
+
+    public Expenses withDeletedAt(Date deletedAt) {
+        this.setDeletedAt(deletedAt);
+        return this;
+    }
+
+    public void setDeletedAt(Date deletedAt) {
+        this.deletedAt = deletedAt;
+    }
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        Expenses other = (Expenses) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getMemberId() == null ? other.getMemberId() == null : this.getMemberId().equals(other.getMemberId()))
+            && (this.getUniqueKey() == null ? other.getUniqueKey() == null : this.getUniqueKey().equals(other.getUniqueKey()))
+            && (this.getUniqueValue() == null ? other.getUniqueValue() == null : this.getUniqueValue().equals(other.getUniqueValue()))
+            && (this.getPoints() == null ? other.getPoints() == null : this.getPoints().equals(other.getPoints()))
+            && (this.getInfo() == null ? other.getInfo() == null : this.getInfo().equals(other.getInfo()))
+            && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt()))
+            && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt()))
+            && (this.getDeletedAt() == null ? other.getDeletedAt() == null : this.getDeletedAt().equals(other.getDeletedAt()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getMemberId() == null) ? 0 : getMemberId().hashCode());
+        result = prime * result + ((getUniqueKey() == null) ? 0 : getUniqueKey().hashCode());
+        result = prime * result + ((getUniqueValue() == null) ? 0 : getUniqueValue().hashCode());
+        result = prime * result + ((getPoints() == null) ? 0 : getPoints().hashCode());
+        result = prime * result + ((getInfo() == null) ? 0 : getInfo().hashCode());
+        result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
+        result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode());
+        result = prime * result + ((getDeletedAt() == null) ? 0 : getDeletedAt().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", memberId=").append(memberId);
+        sb.append(", uniqueKey=").append(uniqueKey);
+        sb.append(", uniqueValue=").append(uniqueValue);
+        sb.append(", points=").append(points);
+        sb.append(", info=").append(info);
+        sb.append(", createdAt=").append(createdAt);
+        sb.append(", updatedAt=").append(updatedAt);
+        sb.append(", deletedAt=").append(deletedAt);
+        sb.append(", serialVersionUID=").append(serialVersionUID);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 816 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/model/ExpensesExample.java

@@ -0,0 +1,816 @@
+package cn.kdan.pdf.backend.core.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class ExpensesExample {
+    protected String orderByClause;
+
+    protected boolean distinct;
+
+    protected List<Criteria> oredCriteria;
+
+    public ExpensesExample() {
+        oredCriteria = new ArrayList<Criteria>();
+    }
+
+    public void setOrderByClause(String orderByClause) {
+        this.orderByClause = orderByClause;
+    }
+
+    public String getOrderByClause() {
+        return orderByClause;
+    }
+
+    public void setDistinct(boolean distinct) {
+        this.distinct = distinct;
+    }
+
+    public boolean isDistinct() {
+        return distinct;
+    }
+
+    public List<Criteria> getOredCriteria() {
+        return oredCriteria;
+    }
+
+    public void or(Criteria criteria) {
+        oredCriteria.add(criteria);
+    }
+
+    public Criteria or() {
+        Criteria criteria = createCriteriaInternal();
+        oredCriteria.add(criteria);
+        return criteria;
+    }
+
+    public Criteria createCriteria() {
+        Criteria criteria = createCriteriaInternal();
+        if (oredCriteria.size() == 0) {
+            oredCriteria.add(criteria);
+        }
+        return criteria;
+    }
+
+    protected Criteria createCriteriaInternal() {
+        Criteria criteria = new Criteria();
+        return criteria;
+    }
+
+    public void clear() {
+        oredCriteria.clear();
+        orderByClause = null;
+        distinct = false;
+    }
+
+    protected abstract static class GeneratedCriteria {
+        protected List<Criterion> criteria;
+
+        protected GeneratedCriteria() {
+            super();
+            criteria = new ArrayList<Criterion>();
+        }
+
+        public boolean isValid() {
+            return criteria.size() > 0;
+        }
+
+        public List<Criterion> getAllCriteria() {
+            return criteria;
+        }
+
+        public List<Criterion> getCriteria() {
+            return criteria;
+        }
+
+        protected void addCriterion(String condition) {
+            if (condition == null) {
+                throw new RuntimeException("Value for condition cannot be null");
+            }
+            criteria.add(new Criterion(condition));
+        }
+
+        protected void addCriterion(String condition, Object value, String property) {
+            if (value == null) {
+                throw new RuntimeException("Value for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value));
+        }
+
+        protected void addCriterion(String condition, Object value1, Object value2, String property) {
+            if (value1 == null || value2 == null) {
+                throw new RuntimeException("Between values for " + property + " cannot be null");
+            }
+            criteria.add(new Criterion(condition, value1, value2));
+        }
+
+        public Criteria andIdIsNull() {
+            addCriterion("id is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdIsNotNull() {
+            addCriterion("id is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdEqualTo(String value) {
+            addCriterion("id =", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotEqualTo(String value) {
+            addCriterion("id <>", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdGreaterThan(String value) {
+            addCriterion("id >", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdGreaterThanOrEqualTo(String value) {
+            addCriterion("id >=", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLessThan(String value) {
+            addCriterion("id <", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLessThanOrEqualTo(String value) {
+            addCriterion("id <=", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLike(String value) {
+            addCriterion("id like", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotLike(String value) {
+            addCriterion("id not like", value, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdIn(List<String> values) {
+            addCriterion("id in", values, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotIn(List<String> values) {
+            addCriterion("id not in", values, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdBetween(String value1, String value2) {
+            addCriterion("id between", value1, value2, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdNotBetween(String value1, String value2) {
+            addCriterion("id not between", value1, value2, "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdIsNull() {
+            addCriterion("member_id is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdIsNotNull() {
+            addCriterion("member_id is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdEqualTo(String value) {
+            addCriterion("member_id =", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdNotEqualTo(String value) {
+            addCriterion("member_id <>", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdGreaterThan(String value) {
+            addCriterion("member_id >", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdGreaterThanOrEqualTo(String value) {
+            addCriterion("member_id >=", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdLessThan(String value) {
+            addCriterion("member_id <", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdLessThanOrEqualTo(String value) {
+            addCriterion("member_id <=", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdLike(String value) {
+            addCriterion("member_id like", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdNotLike(String value) {
+            addCriterion("member_id not like", value, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdIn(List<String> values) {
+            addCriterion("member_id in", values, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdNotIn(List<String> values) {
+            addCriterion("member_id not in", values, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdBetween(String value1, String value2) {
+            addCriterion("member_id between", value1, value2, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdNotBetween(String value1, String value2) {
+            addCriterion("member_id not between", value1, value2, "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyIsNull() {
+            addCriterion("unique_key is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyIsNotNull() {
+            addCriterion("unique_key is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyEqualTo(String value) {
+            addCriterion("unique_key =", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyNotEqualTo(String value) {
+            addCriterion("unique_key <>", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyGreaterThan(String value) {
+            addCriterion("unique_key >", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyGreaterThanOrEqualTo(String value) {
+            addCriterion("unique_key >=", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyLessThan(String value) {
+            addCriterion("unique_key <", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyLessThanOrEqualTo(String value) {
+            addCriterion("unique_key <=", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyLike(String value) {
+            addCriterion("unique_key like", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyNotLike(String value) {
+            addCriterion("unique_key not like", value, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyIn(List<String> values) {
+            addCriterion("unique_key in", values, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyNotIn(List<String> values) {
+            addCriterion("unique_key not in", values, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyBetween(String value1, String value2) {
+            addCriterion("unique_key between", value1, value2, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyNotBetween(String value1, String value2) {
+            addCriterion("unique_key not between", value1, value2, "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueIsNull() {
+            addCriterion("unique_value is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueIsNotNull() {
+            addCriterion("unique_value is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueEqualTo(String value) {
+            addCriterion("unique_value =", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueNotEqualTo(String value) {
+            addCriterion("unique_value <>", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueGreaterThan(String value) {
+            addCriterion("unique_value >", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueGreaterThanOrEqualTo(String value) {
+            addCriterion("unique_value >=", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueLessThan(String value) {
+            addCriterion("unique_value <", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueLessThanOrEqualTo(String value) {
+            addCriterion("unique_value <=", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueLike(String value) {
+            addCriterion("unique_value like", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueNotLike(String value) {
+            addCriterion("unique_value not like", value, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueIn(List<String> values) {
+            addCriterion("unique_value in", values, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueNotIn(List<String> values) {
+            addCriterion("unique_value not in", values, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueBetween(String value1, String value2) {
+            addCriterion("unique_value between", value1, value2, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueNotBetween(String value1, String value2) {
+            addCriterion("unique_value not between", value1, value2, "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsIsNull() {
+            addCriterion("points is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsIsNotNull() {
+            addCriterion("points is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsEqualTo(Integer value) {
+            addCriterion("points =", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsNotEqualTo(Integer value) {
+            addCriterion("points <>", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsGreaterThan(Integer value) {
+            addCriterion("points >", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsGreaterThanOrEqualTo(Integer value) {
+            addCriterion("points >=", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsLessThan(Integer value) {
+            addCriterion("points <", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsLessThanOrEqualTo(Integer value) {
+            addCriterion("points <=", value, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsIn(List<Integer> values) {
+            addCriterion("points in", values, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsNotIn(List<Integer> values) {
+            addCriterion("points not in", values, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsBetween(Integer value1, Integer value2) {
+            addCriterion("points between", value1, value2, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andPointsNotBetween(Integer value1, Integer value2) {
+            addCriterion("points not between", value1, value2, "points");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoIsNull() {
+            addCriterion("info is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoIsNotNull() {
+            addCriterion("info is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoEqualTo(String value) {
+            addCriterion("info =", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoNotEqualTo(String value) {
+            addCriterion("info <>", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoGreaterThan(String value) {
+            addCriterion("info >", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoGreaterThanOrEqualTo(String value) {
+            addCriterion("info >=", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoLessThan(String value) {
+            addCriterion("info <", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoLessThanOrEqualTo(String value) {
+            addCriterion("info <=", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoLike(String value) {
+            addCriterion("info like", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoNotLike(String value) {
+            addCriterion("info not like", value, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoIn(List<String> values) {
+            addCriterion("info in", values, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoNotIn(List<String> values) {
+            addCriterion("info not in", values, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoBetween(String value1, String value2) {
+            addCriterion("info between", value1, value2, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoNotBetween(String value1, String value2) {
+            addCriterion("info not between", value1, value2, "info");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtIsNull() {
+            addCriterion("created_at is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtIsNotNull() {
+            addCriterion("created_at is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtEqualTo(Date value) {
+            addCriterion("created_at =", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtNotEqualTo(Date value) {
+            addCriterion("created_at <>", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtGreaterThan(Date value) {
+            addCriterion("created_at >", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtGreaterThanOrEqualTo(Date value) {
+            addCriterion("created_at >=", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtLessThan(Date value) {
+            addCriterion("created_at <", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtLessThanOrEqualTo(Date value) {
+            addCriterion("created_at <=", value, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtIn(List<Date> values) {
+            addCriterion("created_at in", values, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtNotIn(List<Date> values) {
+            addCriterion("created_at not in", values, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtBetween(Date value1, Date value2) {
+            addCriterion("created_at between", value1, value2, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andCreatedAtNotBetween(Date value1, Date value2) {
+            addCriterion("created_at not between", value1, value2, "createdAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtIsNull() {
+            addCriterion("updated_at is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtIsNotNull() {
+            addCriterion("updated_at is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtEqualTo(Date value) {
+            addCriterion("updated_at =", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtNotEqualTo(Date value) {
+            addCriterion("updated_at <>", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtGreaterThan(Date value) {
+            addCriterion("updated_at >", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtGreaterThanOrEqualTo(Date value) {
+            addCriterion("updated_at >=", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtLessThan(Date value) {
+            addCriterion("updated_at <", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtLessThanOrEqualTo(Date value) {
+            addCriterion("updated_at <=", value, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtIn(List<Date> values) {
+            addCriterion("updated_at in", values, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtNotIn(List<Date> values) {
+            addCriterion("updated_at not in", values, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtBetween(Date value1, Date value2) {
+            addCriterion("updated_at between", value1, value2, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andUpdatedAtNotBetween(Date value1, Date value2) {
+            addCriterion("updated_at not between", value1, value2, "updatedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtIsNull() {
+            addCriterion("deleted_at is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtIsNotNull() {
+            addCriterion("deleted_at is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtEqualTo(Date value) {
+            addCriterion("deleted_at =", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtNotEqualTo(Date value) {
+            addCriterion("deleted_at <>", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtGreaterThan(Date value) {
+            addCriterion("deleted_at >", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtGreaterThanOrEqualTo(Date value) {
+            addCriterion("deleted_at >=", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtLessThan(Date value) {
+            addCriterion("deleted_at <", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtLessThanOrEqualTo(Date value) {
+            addCriterion("deleted_at <=", value, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtIn(List<Date> values) {
+            addCriterion("deleted_at in", values, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtNotIn(List<Date> values) {
+            addCriterion("deleted_at not in", values, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtBetween(Date value1, Date value2) {
+            addCriterion("deleted_at between", value1, value2, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeletedAtNotBetween(Date value1, Date value2) {
+            addCriterion("deleted_at not between", value1, value2, "deletedAt");
+            return (Criteria) this;
+        }
+
+        public Criteria andIdLikeInsensitive(String value) {
+            addCriterion("upper(id) like", value.toUpperCase(), "id");
+            return (Criteria) this;
+        }
+
+        public Criteria andMemberIdLikeInsensitive(String value) {
+            addCriterion("upper(member_id) like", value.toUpperCase(), "memberId");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueKeyLikeInsensitive(String value) {
+            addCriterion("upper(unique_key) like", value.toUpperCase(), "uniqueKey");
+            return (Criteria) this;
+        }
+
+        public Criteria andUniqueValueLikeInsensitive(String value) {
+            addCriterion("upper(unique_value) like", value.toUpperCase(), "uniqueValue");
+            return (Criteria) this;
+        }
+
+        public Criteria andInfoLikeInsensitive(String value) {
+            addCriterion("upper(info) like", value.toUpperCase(), "info");
+            return (Criteria) this;
+        }
+    }
+
+    public static class Criteria extends GeneratedCriteria {
+
+        protected Criteria() {
+            super();
+        }
+    }
+
+    public static class Criterion {
+        private String condition;
+
+        private Object value;
+
+        private Object secondValue;
+
+        private boolean noValue;
+
+        private boolean singleValue;
+
+        private boolean betweenValue;
+
+        private boolean listValue;
+
+        private String typeHandler;
+
+        public String getCondition() {
+            return condition;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public Object getSecondValue() {
+            return secondValue;
+        }
+
+        public boolean isNoValue() {
+            return noValue;
+        }
+
+        public boolean isSingleValue() {
+            return singleValue;
+        }
+
+        public boolean isBetweenValue() {
+            return betweenValue;
+        }
+
+        public boolean isListValue() {
+            return listValue;
+        }
+
+        public String getTypeHandler() {
+            return typeHandler;
+        }
+
+        protected Criterion(String condition) {
+            super();
+            this.condition = condition;
+            this.typeHandler = null;
+            this.noValue = true;
+        }
+
+        protected Criterion(String condition, Object value, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.typeHandler = typeHandler;
+            if (value instanceof List<?>) {
+                this.listValue = true;
+            } else {
+                this.singleValue = true;
+            }
+        }
+
+        protected Criterion(String condition, Object value) {
+            this(condition, value, null);
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+            super();
+            this.condition = condition;
+            this.value = value;
+            this.secondValue = secondValue;
+            this.typeHandler = typeHandler;
+            this.betweenValue = true;
+        }
+
+        protected Criterion(String condition, Object value, Object secondValue) {
+            this(condition, value, secondValue, null);
+        }
+    }
+}

+ 1 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/model/member/SubPricing.java

@@ -13,7 +13,7 @@ public class SubPricing {
     private Float price;
     private Date startDate;
     private Integer status;
-    private String targetId;
+    private Integer targetId;
     private String targetType;
     private String totalPeriod;
     private Integer totalPoints;

+ 2 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/model/member/SubSetPricing.java

@@ -20,4 +20,6 @@ public class SubSetPricing {
 
     private SetPricings setPricings;
 
+    private Date createDate;
+
 }

+ 3 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/model/pricing/QueryPricingResp.java

@@ -1,6 +1,6 @@
 package cn.kdan.pdf.backend.core.model.pricing;
 
-import cn.kdan.pdf.backend.core.model.SetPricings;
+import cn.kdan.pdf.backend.core.pojo.SetPricingVO;
 import lombok.Data;
 
 import java.util.List;
@@ -10,6 +10,8 @@ public class QueryPricingResp {
 
     private List<PricingVo> pricingList;
 
+    private List<SetPricingVO> setPricingList;
+
     private String type;
 
 }

+ 34 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/AppLogoutParam.java

@@ -0,0 +1,34 @@
+package cn.kdan.pdf.backend.core.params;
+
+import lombok.Data;
+import pojo.Device;
+import pojo.Location;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class AppLogoutParam {
+
+    /**
+     * 登录token
+     */
+    private String accessToken;
+
+    /**
+     * 用户id
+     */
+    private String memberId;
+
+    /**
+     * 设备
+     */
+    private Device device;
+
+    /**
+     * 位置
+     */
+    private Location location;
+
+}

+ 22 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/CheckExistsParam.java

@@ -0,0 +1,22 @@
+package cn.kdan.pdf.backend.core.params;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class CheckExistsParam {
+
+    private String name;
+
+    private String email;
+
+    private String phone;
+
+    @JsonProperty("phone_zone")
+    private String phoneZone;
+
+}

+ 19 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/ExpenseParam.java

@@ -0,0 +1,19 @@
+package cn.kdan.pdf.backend.core.params;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class ExpenseParam {
+
+    private Integer points;
+    @JsonProperty("unique_key")
+    private String uniqueKey;
+    @JsonProperty("unique_value")
+    private String uniqueValue;
+
+}

+ 27 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryAdvertisementParam.java

@@ -0,0 +1,27 @@
+package cn.kdan.pdf.backend.core.params;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class QueryAdvertisementParam {
+
+    private String slug;
+
+    private String dimension;
+
+    private String language;
+
+    @JsonProperty("version_name")
+    private String versionName;
+
+    /**
+     * 是否只获取一条:1.是;0.否
+     */
+    private String isFetchOne;
+
+}

+ 16 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryConvertTypeParam.java

@@ -0,0 +1,16 @@
+package cn.kdan.pdf.backend.core.params;
+
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class QueryConvertTypeParam {
+
+    private String in;
+    private String out;
+    private String ocr;
+
+}

+ 22 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/params/QueryPricingParam.java

@@ -0,0 +1,22 @@
+package cn.kdan.pdf.backend.core.params;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class QueryPricingParam {
+
+    private String type;
+
+    private String client;
+
+    private String language;
+
+    @JsonProperty("version_name")
+    private String versionName;
+
+}

+ 16 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/ExistsMemberVo.java

@@ -0,0 +1,16 @@
+package cn.kdan.pdf.backend.core.pojo;
+
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class ExistsMemberVo {
+
+    private String key;
+
+    private String value;
+
+}

+ 4 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/MissionFileVO.java

@@ -59,6 +59,10 @@ public class MissionFileVO {
      * 文件大小
      */
     private BigDecimal size;
+    /**
+     * 转档后文件大小
+     */
+    private Integer convertSize;
     /**
      * 源文件类型
      */

+ 26 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/AdvertisementVo.java

@@ -0,0 +1,26 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class AdvertisementVo {
+
+    private String id;
+    private String slug;
+    private String language;
+    private String title;
+    private String dimension;
+    private String linkText;
+    private String linkUrl;
+    private String description;
+    private String imageUrl;
+    private Map<String, String> imageUrls;
+    private Map<String,String> extraInfo;
+
+}

+ 3 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/BindAccountVo.java

@@ -2,6 +2,8 @@ package cn.kdan.pdf.backend.core.pojo.app;
 
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * @author sfq
  * @description
@@ -11,6 +13,6 @@ public class BindAccountVo {
 
     private MemberVo member;
 
-    private SocialAccountVo socialAccount;
+    private List<SocialAccountVo> socialAccounts;
 
 }

+ 31 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/CreateSubVo.java

@@ -0,0 +1,31 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import cn.kdan.pdf.backend.core.model.Pricings;
+import cn.kdan.pdf.backend.core.model.SetPricings;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class CreateSubVo {
+
+    private String id;
+    private String targetType;
+    private Integer targetId;
+    private Float price;
+    private Integer status;
+    private Integer totalPoints;
+    private String totalPeriod;
+    private Date startDate;
+    private Date endDate;
+
+    private Pricings pricing;
+    private SetPricings setPricing;
+
+    private ThirdOrderVo order;
+
+}

+ 20 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/ExpenseVo.java

@@ -0,0 +1,20 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class ExpenseVo {
+
+    private Integer memberPoints;
+    private String uniqueKey;
+    private String uniqueValue;
+    private Integer point;
+    private Date createdAt;
+
+}

+ 10 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/LoginInfoVo.java

@@ -20,4 +20,14 @@ public class LoginInfoVo {
      */
     private MemberVo member;
 
+    /**
+     * 用户id
+     */
+    private String id;
+
+    /**
+     * 返回信息
+     */
+    private String message;
+
 }

+ 27 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/MemberInfoVo.java

@@ -0,0 +1,27 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import cn.kdan.pdf.backend.core.model.member.MemberInfo;
+import cn.kdan.pdf.backend.core.model.member.SubPricing;
+import cn.kdan.pdf.backend.core.model.member.SubSetPricing;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class MemberInfoVo {
+
+    private String type;
+
+    private MemberInfo memberInfo;
+
+    private List<SubPricing> pricingList;
+
+    private List<SubSetPricing> setPricingList;
+
+    private List<SocialAccountVo> socialAccountList;
+
+}

+ 20 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/RemindVo.java

@@ -0,0 +1,20 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import cn.kdan.pdf.backend.core.model.Pricings;
+import cn.kdan.pdf.backend.core.model.Subscriptions;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class RemindVo {
+
+    private String remindType;
+    private String remindMsg;
+    private Subscriptions remindSubscription;
+    private Pricings remindPricing;
+    private Subscriptions freeSubscription;
+
+}

+ 15 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/ThirdOrderVo.java

@@ -0,0 +1,15 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import cn.kdan.pdf.backend.core.model.Orders;
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class ThirdOrderVo extends Orders {
+
+    private WxAndroidSignVo wxAndroidSign;
+
+}

+ 14 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/UpTokenVo.java

@@ -0,0 +1,14 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class UpTokenVo {
+
+    private MemberVo member;
+
+}

+ 20 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/app/WxAndroidSignVo.java

@@ -0,0 +1,20 @@
+package cn.kdan.pdf.backend.core.pojo.app;
+
+import lombok.Data;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Data
+public class WxAndroidSignVo {
+
+    private String appId;
+    private String partnerId;
+    private String packageSign;
+    private String timestamp;
+    private String prepayId;
+    private String nonceStr;
+    private String sign;
+
+}

+ 5 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/pojo/comPdfKit/FileInfoDto.java

@@ -45,6 +45,11 @@ public class FileInfoDto {
      */
     private String fileSize;
 
+    /**
+     * 转档后文件大小
+     */
+    private String convertSize;
+
     /**
      * 转换消耗时间
      */

+ 26 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/properties/OssProperties.java

@@ -0,0 +1,26 @@
+package cn.kdan.pdf.backend.core.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author ZhouQiang 2022/7/13
+ */
+@ConfigurationProperties(prefix = "17pdf.oss")
+@Configuration
+@Data
+public class OssProperties {
+
+    private String bucketName;
+
+    private String endpoint;
+
+    private String accessKeyId;
+
+    private String accessKeySecret;
+
+    private String filePrefix;
+
+    private String viewUrl;
+}

+ 21 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AdvertisementService.java

@@ -0,0 +1,21 @@
+package cn.kdan.pdf.backend.core.service;
+
+import cn.kdan.pdf.backend.core.params.QueryAdvertisementParam;
+import cn.kdan.pdf.backend.core.pojo.app.AdvertisementVo;
+
+import java.util.List;
+
+/**
+ * @author : sfq
+ * @date : 2022/12/14 17:45
+ */
+public interface AdvertisementService {
+
+    /**
+     * 查询广告数据
+     * @param param 查询条件
+     * @return 广告信息
+     */
+    List<AdvertisementVo> list(QueryAdvertisementParam param);
+
+}

+ 2 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AlipayService.java

@@ -18,9 +18,10 @@ public interface AlipayService {
      * @param tradeNo      交易号
      * @param price        交易价格
      * @param subscription 订阅记录
+     * @param client 客户端(web、android)
      * @return 支付宝调用结果
      */
-    String createAlipayPageUrl(String subject, String tradeNo, Float price, Subscriptions subscription);
+    String createAlipayPageUrl(String subject, String tradeNo, Float price, Subscriptions subscription, String client);
 
     /**
      * 查询订单状态接口

+ 20 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AuthService.java

@@ -4,6 +4,7 @@ import cn.kdan.pdf.backend.core.enums.CaptchaActionEnum;
 import cn.kdan.pdf.backend.core.enums.ImageCodeTypeEnum;
 import cn.kdan.pdf.backend.core.enums.VerifyTypeEnum;
 import cn.kdan.pdf.backend.core.model.OauthClientDetails;
+import cn.kdan.pdf.backend.core.params.AppLogoutParam;
 import cn.kdan.pdf.backend.core.params.RelationParam;
 import cn.kdan.pdf.backend.core.pojo.app.LoginInfoVo;
 import cn.kdan.pdf.backend.core.pojo.oauth2.TokenPOJO;
@@ -122,4 +123,23 @@ public interface AuthService {
      * @return token
      */
     LoginInfoVo appGetToken(RelationParam param);
+
+    /**
+     * 登出
+     * @param param
+     */
+    void logout(AppLogoutParam param);
+
+    /**
+     * 失效token
+     * @param token 用户token
+     */
+    void invalidToken(String token);
+
+    /**
+     * 清除设备信息并失效token
+     * @param id 用户id
+     * @return
+     */
+    String clearDevice(String id);
 }

+ 34 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/AvatarService.java

@@ -0,0 +1,34 @@
+package cn.kdan.pdf.backend.core.service;
+
+import cn.kdan.pdf.backend.core.model.Avatars;
+import cn.kdan.pdf.backend.core.pojo.app.UpTokenVo;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * @author : sfq
+ * @date : 2022/12/14 16:32
+ */
+public interface AvatarService {
+
+    /**
+     * 查询头像列表信息
+     * @return 头像信息集合
+     */
+    List<Avatars> list();
+
+    /**
+     * 根据用户id查询头像路径
+     * @param memberId 用户id
+     * @return 头像路径
+     */
+    String selectAvatarByMemberId(String memberId);
+
+    /**
+     * 获取头像上传的token
+     * @return token+用户信息
+     */
+    UpTokenVo picUpload(MultipartFile file);
+
+}

+ 21 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/DeviceService.java

@@ -1,6 +1,8 @@
 package cn.kdan.pdf.backend.core.service;
 
 import cn.kdan.pdf.backend.core.model.Devices;
+import cn.kdan.pdf.backend.core.params.RelationParam;
+import pojo.Device;
 
 /**
  * @author : SongFuQiang
@@ -30,4 +32,23 @@ public interface DeviceService {
      */
     void update(Devices device, String uuid);
 
+    /**
+     * 更新设备信息
+     * @param param device+location
+     * @return device
+     */
+    Device updateInfo(RelationParam param);
+
+    /**
+     * 根据uuid和用户id删除设备数据
+     * @param uuid 设备唯一id
+     * @param memberId 用户id
+     */
+    void deleteByUuid(String uuid, String memberId);
+
+    /**
+     * 清除登录设备信息
+     * @param memberId 用户id
+     */
+    void clearDevice(String memberId);
 }

+ 38 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/MemberService.java

@@ -6,8 +6,11 @@ import cn.kdan.pdf.backend.core.model.member.MemberRegisterReq;
 import cn.kdan.pdf.backend.core.model.member.MemberRegisterResp;
 import cn.kdan.pdf.backend.core.model.member.ModifyPasswordReq;
 import cn.kdan.pdf.backend.core.params.BindAccountParam;
+import cn.kdan.pdf.backend.core.params.CheckExistsParam;
 import cn.kdan.pdf.backend.core.params.UserResetPwdParams;
+import cn.kdan.pdf.backend.core.pojo.ExistsMemberVo;
 import cn.kdan.pdf.backend.core.pojo.app.BindAccountVo;
+import cn.kdan.pdf.backend.core.pojo.app.MemberInfoVo;
 import cn.kdan.pdf.backend.core.pojo.app.MemberVo;
 
 public interface MemberService {
@@ -49,6 +52,13 @@ public interface MemberService {
      */
     Members getCurrentUser();
 
+    /**
+     * 判断用户会员状态,并在会员过期后更新会员信息
+     * @param memberId 用户id
+     * @return 会员状态
+     */
+    Integer judgeSubscribeType(String memberId);
+
     /**
      * 根据id查询用户
      *
@@ -103,4 +113,32 @@ public interface MemberService {
      * @return 用户信息
      */
     MemberVo appModifyName(String name);
+
+    /**
+     * 根据用户id删除用户
+     * @param memberId 用户ID
+     */
+    void deleteByMemberId(String memberId);
+
+    /**
+     * app获取用户信息
+     * @param subscription 1:不显示订阅信息 0:显示订阅信息
+     * @param withSocial 如果是QQ、微信登录,传入字段可实现第三方登录的信息。0:不显示, 1:显示
+     * @return 用户详细信息
+     */
+    MemberInfoVo appGetMemberInfo(String subscription, String withSocial);
+
+    /**
+     * 检查内容是否存在
+     * @param param param
+     * @return vo
+     */
+    ExistsMemberVo checkExists(CheckExistsParam param);
+
+    /**
+     * app端修改密码
+     * @param param param
+     * @return 是否成功
+     */
+    boolean appResetPassword(UserResetPwdParams param);
 }

+ 6 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/MissionFilesService.java

@@ -96,4 +96,10 @@ public interface MissionFilesService {
      * @return 文件集合
      */
     List<MissionFiles> getBySaasId(String id);
+
+    /**
+     * 获取转档文件总数
+     * @return 文件总数
+     */
+    Integer getTotalConvertFile();
 }

+ 2 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/OrderService.java

@@ -18,9 +18,10 @@ public interface OrderService {
      *
      * @param memberId     用户id
      * @param subscription 订阅
+     * @param client 客户端(web、android)
      * @return Orders
      */
-    Orders findMemberUnPayedOrders(String memberId, Subscriptions subscription);
+    Orders findMemberUnPayedOrders(String memberId, Subscriptions subscription, String client);
 
     /**
      * 根据商户订单号获取订单

+ 16 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/OutputFileService.java

@@ -0,0 +1,16 @@
+package cn.kdan.pdf.backend.core.service;
+
+import cn.kdan.pdf.backend.core.model.OutputFiles;
+
+/**
+ * @author : sfq
+ * @date : 2023/1/10 15:00
+ */
+public interface OutputFileService {
+
+    /**
+     * 插入数据
+     */
+    void insert(OutputFiles outputFile);
+
+}

+ 8 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/PricingService.java

@@ -5,6 +5,7 @@ import cn.kdan.pdf.backend.core.model.Pricings;
 import cn.kdan.pdf.backend.core.model.PricingDiscounts;
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingReq;
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingResp;
+import cn.kdan.pdf.backend.core.params.QueryPricingParam;
 
 import java.util.List;
 
@@ -62,4 +63,11 @@ public interface PricingService {
      * @return 券数量
      */
     Integer countPointsAmount(Pricings item, PricingDiscounts pricingDiscount);
+
+    /**
+     * app端获取商品价目表
+     * @param param 入参
+     * @return 商品价目表列表
+     */
+    QueryPricingResp appList(QueryPricingParam param);
 }

+ 10 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SetPricingService.java

@@ -4,6 +4,7 @@ package cn.kdan.pdf.backend.core.service;
 import cn.kdan.pdf.backend.core.model.Members;
 import cn.kdan.pdf.backend.core.model.PricingDiscounts;
 import cn.kdan.pdf.backend.core.model.SetPricings;
+import cn.kdan.pdf.backend.core.model.Subscriptions;
 import cn.kdan.pdf.backend.core.pojo.SetPricingVO;
 
 import java.util.List;
@@ -78,4 +79,13 @@ public interface SetPricingService {
      * @return float
      */
     float countPrice(SetPricings item, PricingDiscounts activeDiscount, Members member, String client);
+
+    /**
+     * 查询mode为0的会员服务
+     * @param memberId 用户id
+     * @return Subscriptions
+     */
+    List<Subscriptions> selectMode0(String memberId);
+
+    List<Subscriptions> selectPByModeAndMemberId(String memberId,String mode);
 }

+ 8 - 6
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SocialAccountService.java

@@ -3,6 +3,9 @@ package cn.kdan.pdf.backend.core.service;
 import cn.kdan.pdf.backend.core.model.Members;
 import cn.kdan.pdf.backend.core.model.SocialAccounts;
 import cn.kdan.pdf.backend.core.params.BindAccountParam;
+import cn.kdan.pdf.backend.core.pojo.app.SocialAccountVo;
+
+import java.util.List;
 
 /**
  * @author : SongFuQiang
@@ -27,10 +30,9 @@ public interface SocialAccountService {
     /**
      * 根据用户id查询社交账号表数据
      * @param userId 用户id
-     * @param provider 第三方
      * @return 社交账号信息
      */
-    SocialAccounts selectByMemberId(String userId, Integer provider);
+    List<SocialAccounts> selectByMemberId(String userId);
 
     /**
      * 根据用户id删除社交账号信息
@@ -42,14 +44,14 @@ public interface SocialAccountService {
      * 绑定社交账号
      * @param member 当前用户
      * @param param 绑定参数
+     * @param socialAccounts 社交账号返回信息
      */
-    String bindSocialAccount(Members member, BindAccountParam param);
+    List<SocialAccountVo> bindSocialAccount(Members member, BindAccountParam param, List<SocialAccountVo> socialAccounts);
 
     /**
      * 解绑账号
      * @param currentUser 当前用户
-     * @param param 绑定参数
-     * @return socialAccount的id
+     * @param provider 第三方
      */
-    String unbindSocialAccount(Members currentUser, BindAccountParam param);
+    List<SocialAccountVo> unbindSocialAccount(Members currentUser, String provider, List<SocialAccountVo> list);
 }

+ 27 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/SubscriptionService.java

@@ -3,7 +3,11 @@ package cn.kdan.pdf.backend.core.service;
 
 import cn.kdan.pdf.backend.core.model.Members;
 import cn.kdan.pdf.backend.core.model.Subscriptions;
+import cn.kdan.pdf.backend.core.params.ExpenseParam;
 import cn.kdan.pdf.backend.core.pojo.SubscriptionVO;
+import cn.kdan.pdf.backend.core.pojo.app.CreateSubVo;
+import cn.kdan.pdf.backend.core.pojo.app.ExpenseVo;
+import cn.kdan.pdf.backend.core.pojo.app.RemindVo;
 
 /**
  * @author tangxiangan
@@ -57,4 +61,27 @@ public interface SubscriptionService {
      * @return Subscriptions
      */
     Subscriptions getById(String subscriptionId);
+
+    /**
+     * 获取套餐过期信息
+     * @return 过期信息返回
+     */
+    RemindVo remindRenew();
+
+    /**
+     * 转换券消耗
+     * @param param param
+     * @return 券消耗信息返回
+     */
+    ExpenseVo expense(ExpenseParam param);
+
+    /**
+     * app端创建订单
+     * @param client
+     * @param payment
+     * @param targetType
+     * @param targetId
+     * @return
+     */
+    CreateSubVo appCreate(String client, Integer payment, String targetType, String targetId);
 }

+ 4 - 2
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/WXPayService.java

@@ -3,6 +3,8 @@ package cn.kdan.pdf.backend.core.service;
 
 import cn.kdan.pdf.backend.core.utils.wxpay.WXPayOrderQueryResult;
 
+import java.util.Map;
+
 /**
  * @author tangxiangan
  */
@@ -15,9 +17,9 @@ public interface WXPayService {
      * @param subject 主题
      * @param orderNo 订单号
      * @param price   价格
-     * @return 二维码url
+     * @return 微信返回
      */
-    String unifiedOrder(String subject, String orderNo, Float price);
+    Map<String,String> unifiedOrder(String subject, String orderNo, Float price, String client);
 
     /**
      * 查询订单支付结果

+ 105 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AdvertisementServiceImpl.java

@@ -0,0 +1,105 @@
+package cn.kdan.pdf.backend.core.service.impl;
+
+import cn.kdan.pdf.backend.core.enums.LanguageEnum;
+import cn.kdan.pdf.backend.core.mapper.AdvertisementsMapper;
+import cn.kdan.pdf.backend.core.model.Advertisements;
+import cn.kdan.pdf.backend.core.model.AdvertisementsExample;
+import cn.kdan.pdf.backend.core.params.QueryAdvertisementParam;
+import cn.kdan.pdf.backend.core.pojo.app.AdvertisementVo;
+import cn.kdan.pdf.backend.core.properties.OssProperties;
+import cn.kdan.pdf.backend.core.service.AdvertisementService;
+import cn.kdan.pdf.backend.core.utils.CommonBusinessUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Service
+public class AdvertisementServiceImpl implements AdvertisementService {
+
+    @Autowired
+    private AdvertisementsMapper advertisementsMapper;
+    @Autowired
+    private OssProperties ossProperties;
+
+    @Override
+    public List<AdvertisementVo> list(QueryAdvertisementParam param) {
+        List<AdvertisementVo> result = new ArrayList<>();
+        String slug = param.getSlug();
+        String isFetchOne = param.getIsFetchOne();
+        String language = param.getLanguage();
+        if(!StringUtils.isEmpty(language)) {
+            language = CommonBusinessUtils.judgeLanguage(language);
+        }
+        AdvertisementsExample example = new AdvertisementsExample();
+        AdvertisementsExample.Criteria criteria = example.createCriteria();
+        if(!StringUtils.isEmpty(slug)) {
+            criteria.andSlugEqualTo(slug);
+        }
+        if(!StringUtils.isEmpty(slug)) {
+            criteria.andLanguageEqualTo(LanguageEnum.getCodeByName(language));
+        }
+        //获取访问域名
+        String viewUrl = ossProperties.getViewUrl();
+        List<Advertisements> advertisementList = advertisementsMapper.selectByExample(example);
+        if(!CollectionUtils.isEmpty(advertisementList) && "1".equals(isFetchOne)){
+            AdvertisementVo vo = new AdvertisementVo();
+            Advertisements adv = advertisementList.get(0);
+            BeanUtils.copyProperties(adv,vo);
+            vo.setImageUrl(viewUrl + adv.getImage());
+            setExtraInfo(vo,adv);
+            increaseHit(adv);
+            result.add(vo);
+        }else{
+            for (Advertisements adv : advertisementList) {
+                AdvertisementVo vo = new AdvertisementVo();
+                BeanUtils.copyProperties(adv,vo);
+                vo.setImageUrl(viewUrl+adv.getImage());
+                setExtraInfo(vo,adv);
+                result.add(vo);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 设置广告额外信息
+     * @param vo 返回广告vo
+     * @param adv 数据库查询广告信息
+     * 需要注意第二个=号切割的时候,有可能出现没有list【1】的值,需要进行处理
+     */
+    public void setExtraInfo(AdvertisementVo vo, Advertisements adv){
+        Map<String, String> map = new HashMap<>();
+        String extraInfo = adv.getExtraInfo();
+        if(!StringUtils.isEmpty(extraInfo)){
+            String[] array = extraInfo.split("&");
+            for (int i = 0; i < array.length; i++) {
+                String[] list = array[i].split("=");
+                if(list.length == 2) {
+                    map.put(list[0], list[1]);
+                }else{
+                    map.put(list[0], null);
+                }
+            }
+        }
+        vo.setExtraInfo(map);
+    }
+
+    /**
+     * 增加广告点击量
+     * @param adv adv
+     */
+    public void increaseHit(Advertisements adv){
+        adv.setTotalHits(adv.getTotalHits()+1);
+        adv.setUpdatedAt(new Date());
+        advertisementsMapper.updateByPrimaryKey(adv);
+    }
+
+}

+ 26 - 7
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AlipayServiceImpl.java

@@ -1,16 +1,20 @@
 package cn.kdan.pdf.backend.core.service.impl;
 
+import cn.kdan.pdf.backend.core.constant.OrderConstant;
+import cn.kdan.pdf.backend.core.enums.ClientEnum;
 import cn.kdan.pdf.backend.core.model.Subscriptions;
 import cn.kdan.pdf.backend.core.service.AlipayService;
 import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
+import com.alipay.api.AlipayRequest;
+import com.alipay.api.AlipayResponse;
 import com.alipay.api.domain.AlipayTradePagePayModel;
+import com.alipay.api.request.AlipayTradeAppPayRequest;
 import com.alipay.api.request.AlipayTradeCloseRequest;
 import com.alipay.api.request.AlipayTradePagePayRequest;
 import com.alipay.api.request.AlipayTradeQueryRequest;
 import com.alipay.api.response.AlipayTradeCloseResponse;
-import com.alipay.api.response.AlipayTradePagePayResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
 import enums.CommonEnum;
 import exception.BackendRuntimeException;
@@ -48,20 +52,31 @@ public class AlipayServiceImpl implements AlipayService {
      * @return 支付宝调用结果
      */
     @Override
-    public String createAlipayPageUrl(String subject, String tradeNo, Float price, Subscriptions subscription) {
+    public String createAlipayPageUrl(String subject, String tradeNo, Float price, Subscriptions subscription, String client) {
         //封装bizModel对象
         AlipayTradePagePayModel model =new AlipayTradePagePayModel();
         model.setOutTradeNo(tradeNo);
         model.setTotalAmount(price.toString());
         model.setSubject(subject);
-        model.setProductCode("FAST_INSTANT_TRADE_PAY");
-        Date date = DateUtils.addHours(new Date(), 12, 1);
+        if(ClientEnum.WEB.value().equals(client)) {
+            model.setProductCode("FAST_INSTANT_TRADE_PAY");
+        }else {
+            model.setProductCode("QUICK_MSECURITY_PAY");
+        }
+
+        Date date = DateUtils.addHours(new Date(), OrderConstant.ALIPAY_EXPIRE_TIME, 1);
         String timeExpire = DateUtils.dateToString(date, "yyyy-MM-dd HH:mm:ss");
         //todo 暂定当前时间12小时后过期
         model.setTimeExpire(timeExpire);
 
         // 最终目的是获取url路径,联调支付宝
-        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
+        AlipayRequest request;
+        if(ClientEnum.WEB.value().equals(client)) {
+            request = new AlipayTradePagePayRequest();
+        }else {
+            request = new AlipayTradeAppPayRequest();
+        }
+//        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
         if(CommonEnum.SubscriptionTypeEnum.SET_PRICING.value().equals(subscription.getTargetType())){
             request.setReturnUrl(config.getProperty("ali.pay.setPricingReturnUrl"));
         }else if(CommonEnum.SubscriptionTypeEnum.PRICING.value().equals(subscription.getTargetType())){
@@ -72,11 +87,15 @@ public class AlipayServiceImpl implements AlipayService {
         //设置回调return_url、响应url
         request.setNotifyUrl(config.getProperty("ali.pay.notifyUrl"));
         request.setBizModel(model);
-        AlipayTradePagePayResponse response = null;
+        AlipayResponse response = null;
         try {
             log.info("支付宝支付调用参数:{}", JSONObject.toJSONString(request));
             //get方式请求,即生成url链接
-            response = alipayClient.pageExecute(request,"GET");
+            if(ClientEnum.WEB.value().equals(client)) {
+                response = alipayClient.pageExecute(request, "GET");
+            }else {
+                response = alipayClient.sdkExecute(request);
+            }
             log.info("支付宝支付调用成功:{}", JSONObject.toJSONString(response));
         } catch (AlipayApiException e) {
             log.error("支付宝支付调用失败:{}", e.getMessage());

+ 99 - 24
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AuthServiceImpl.java

@@ -9,6 +9,7 @@ import cn.kdan.pdf.backend.core.enums.VerifyTypeEnum;
 import cn.kdan.pdf.backend.core.mapper.OauthClientDetailsMapper;
 import cn.kdan.pdf.backend.core.model.*;
 import cn.kdan.pdf.backend.core.params.AppLoginParam;
+import cn.kdan.pdf.backend.core.params.AppLogoutParam;
 import cn.kdan.pdf.backend.core.params.RelationParam;
 import cn.kdan.pdf.backend.core.pojo.app.LoginInfoVo;
 import cn.kdan.pdf.backend.core.pojo.app.MemberVo;
@@ -17,6 +18,7 @@ import cn.kdan.pdf.backend.core.pojo.third.Tencent;
 import cn.kdan.pdf.backend.core.pojo.third.Wechat;
 import cn.kdan.pdf.backend.core.properties.Oauth2LoginProperties;
 import cn.kdan.pdf.backend.core.service.*;
+import cn.kdan.pdf.backend.core.utils.CommonBusinessUtils;
 import cn.kdan.pdf.backend.core.utils.TencentUtils;
 import cn.kdan.pdf.backend.core.utils.TokenUtils;
 import cn.kdan.pdf.backend.core.utils.WechatUtils;
@@ -31,13 +33,17 @@ import org.apache.http.entity.ContentType;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.OAuth2RefreshToken;
+import org.springframework.security.oauth2.provider.token.TokenStore;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import pojo.CustomUserDetails;
 import pojo.Device;
@@ -99,6 +105,8 @@ public class AuthServiceImpl implements AuthService {
     private LocationService locationService;
     @Resource
     private MemberServiceImpl memberService;
+    @Resource
+    private AvatarService avatarService;
 
     @Override
     public OauthClientDetails getById(String clientId) {
@@ -194,7 +202,7 @@ public class AuthServiceImpl implements AuthService {
     @Override
     public boolean getVerifyCode(CaptchaActionEnum action, VerifyTypeEnum type, String receiver) {
         boolean flag = false;
-        if (redisUtils.hexists(AuthConstant.VERIFY_CODE_TIME_OUT + action.value(), receiver)) {
+        if (!CaptchaActionEnum.FORGET_PASSWORD.value().equals(action.value())&&redisUtils.hexists(AuthConstant.VERIFY_CODE_TIME_OUT + action.value(), receiver)) {
             throw new BackendRuntimeException(AuthConstant.VERIFY_CODE_SEND_TOO_QUICKLY);
         }
         String code = CommonUtils.generateVerifyCode();
@@ -208,10 +216,16 @@ public class AuthServiceImpl implements AuthService {
                 break;
             //发送邮件
             case EMAIL:
-                //忘记密码时邮箱验证 发送重置密码邮件
-                if (CaptchaActionEnum.FORGET_PASSWORD.value().equals(action.value())) {
-                    String content = String.format(CommonConstant.resetPasswordEmailTemplate, url + "resetPsw?verifyCode=" + code + "&account=" + receiver, action.action());
-                    flag = emailUtils.sendMail(action.subject(), content, Collections.singletonList(receiver));
+                // 判断是否属于黑名单格式的邮箱
+                if(!CommonBusinessUtils.verifyBlackEmail(receiver)) {
+                    //忘记密码时邮箱验证 发送重置密码邮件
+                    if (CaptchaActionEnum.FORGET_PASSWORD.value().equals(action.value())) {
+                        String content = String.format(CommonConstant.resetPasswordEmailTemplate, url + "resetPsw?verifyCode=" + code + "&account=" + receiver);
+                        flag = emailUtils.sendMail(action.subject(), content, Collections.singletonList(receiver));
+                    } else {
+                        String content = String.format(CommonConstant.registerEmailTemplate, code);
+                        flag = emailUtils.sendMail(action.subject(), content, Collections.singletonList(receiver));
+                    }
                 }
                 break;
             default:
@@ -219,14 +233,19 @@ public class AuthServiceImpl implements AuthService {
         }
         //存入缓存
         if (flag) {
-            redisUtils.hset(AuthConstant.VERIFY_CODE_KEY + action.value(), receiver, code, AuthConstant.VERIFY_CODE_KEY_EXPIRE_TIME);
+            if (CaptchaActionEnum.FORGET_PASSWORD.value().equals(action.value())) {
+                // 注册用户:verifyCode_1:{13433334444,code}
+                redisUtils.hset(AuthConstant.VERIFY_CODE_KEY + action.value(), receiver, code, AuthConstant.VERIFY_CODE_KEY_EXPIRE_TIME);
+            }else{
+                // 注册用户:verifyCode_0:{test@qq.com,code}
+                redisUtils.hset(AuthConstant.VERIFY_CODE_KEY + action.value(), receiver, code, AuthConstant.EMAIL_VERIFY_CODE_KEY_EXPIRE_TIME);
+            }
             //再次发送计时
             redisUtils.hset(AuthConstant.VERIFY_CODE_TIME_OUT + action.value(), receiver, "1", AuthConstant.VERIFY_CODE_KEY_RESEND_TIME);
         }
         return flag;
     }
 
-
     @Override
     public boolean checkExist(String key, String account, String code) {
         if (!isImageCodeValid(key, ImageCodeTypeEnum.FORGET_PASSWORD, code)) {
@@ -247,6 +266,7 @@ public class AuthServiceImpl implements AuthService {
     @Override
     @Transactional(rollbackFor = BackendRuntimeException.class)
     public LoginInfoVo appGetToken(RelationParam param) {
+        LoginInfoVo vo = new LoginInfoVo();
         AppLoginParam attribute= param.getAttribute();
         String provider = attribute.getProvider();
         String password = attribute.getPassword();
@@ -289,22 +309,23 @@ public class AuthServiceImpl implements AuthService {
                 if(ObjectUtils.isEmpty(member)) {
                     member = new Members();
                     member.setName(String.valueOf(System.currentTimeMillis()).substring(0, 10));
+                    member.setPhone(account);
                     memberId = memberService.insertMembers(member, password);
                     memberVo.setName(member.getName());
                     memberVo.setEmail(member.getEmail());
                     memberVo.setPhone(member.getPhone());
                     memberVo.setPhoneZone(member.getPhoneZone());
                     memberVo.setTimeZone(member.getTimeZone());
-                    memberVo.setAvatarUrl("");
+                    memberVo.setAvatarUrl(avatarService.selectAvatarByMemberId(memberId));
                 }else {
                     if("false".equals(password)){
                         memberVo.setName(member.getName());
                         memberVo.setEmail(member.getEmail());
                         memberVo.setPhone(member.getPhone());
                         memberVo.setPhoneZone(member.getPhoneZone());
-                        memberVo.setAvatarUrl("");
                         memberVo.setTimeZone(member.getTimeZone());
                         memberId = member.getId();
+                        memberVo.setAvatarUrl(avatarService.selectAvatarByMemberId(memberId));
                     }
                 }
             }else {
@@ -317,9 +338,9 @@ public class AuthServiceImpl implements AuthService {
                         memberVo.setEmail(member.getEmail());
                         memberVo.setPhone(member.getPhone());
                         memberVo.setPhoneZone(member.getPhoneZone());
-                        memberVo.setAvatarUrl("");
                         memberVo.setTimeZone(member.getTimeZone());
                         memberId = member.getId();
+                        memberVo.setAvatarUrl(avatarService.selectAvatarByMemberId(memberId));
                     }else {
                         throw new BackendRuntimeException("账号/密码输入有误");
                     }
@@ -329,9 +350,16 @@ public class AuthServiceImpl implements AuthService {
             }
         }
 
-        //增加设备数据 todo 踢下线功能(需配合退出登录)
+        //增加设备数据
         Device loginDevice = param.getDevice();
-        Devices queryDevice = deviceService.selectByMemberId(memberId,loginDevice.getUuid());
+        Devices queryDevice;
+        try {
+            queryDevice = deviceService.selectByMemberId(memberId, loginDevice.getUuid());
+        }catch (BackendRuntimeException e){
+            vo.setId(memberId);
+            vo.setMessage(e.getMessage());
+            return vo;
+        }
         // 如果查询的设备为空,并且传参进来的device不为空,新增一条device数据
         if(ObjectUtils.isEmpty(queryDevice)) {
             if (StringUtils.isNotBlank(loginDevice.getUuid())) {
@@ -370,19 +398,16 @@ public class AuthServiceImpl implements AuthService {
                 locationService.update(queryLocation);
             }
         }
-
-        LoginInfoVo vo = new LoginInfoVo();
-        //根据用户id查询token todo token过期设置
-//        String token = redisUtils.hget("token", memberId);
-        TokenPOJO tokenPOJO = new TokenPOJO();
-//        if(StringUtils.isNotBlank(token)){
-//            tokenPOJO.setAccessToken(token);
-//            tokenPOJO.setTokenType("bearer");
-//        }else {
-            tokenPOJO = getTokenByUserId(memberId);
-//        }
-//        redisUtils.hset("token",memberId,tokenPOJO.getAccessToken(),60*60*24*15);
+        //根据用户id查询token
+        TokenPOJO tokenPOJO = getTokenByUserId(memberId);
+        // 更新accessToken信息至members表
+        Members members = memberService.getById(memberId);
+        members.setActivationToken(tokenPOJO.getAccessToken());
+        members.setResetToken(tokenPOJO.getRefreshToken());
+        members.setUpdatedAt(new Date());
+        memberService.update(members);
         vo.setToken(tokenPOJO);
+        vo.setId(memberId);
         //获取用户信息
         memberVo.setId(memberId);
         vo.setMember(memberVo);
@@ -460,4 +485,54 @@ public class AuthServiceImpl implements AuthService {
         account.setProvider(providerValue);
         socialAccountService.insertSocialAccount(account);
     }
+
+    @Resource
+    @Lazy
+    private TokenStore tokenStore;
+
+    @Override
+    public void logout(AppLogoutParam param) {
+        String accessToken = param.getAccessToken();
+        Assert.notNull(accessToken, "传参错误,入参accessToken为空");
+        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken);
+        Device device = param.getDevice();
+        if (oAuth2AccessToken != null) {
+            deviceService.deleteByUuid(device.getUuid(),param.getMemberId());
+            OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
+            //从tokenStore中移除token
+            tokenStore.removeAccessToken(oAuth2AccessToken);
+            tokenStore.removeRefreshToken(oAuth2RefreshToken);
+            tokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
+        } else {
+            throw new BackendRuntimeException("token已失效,请勿重复登出");
+        }
+    }
+
+    @Override
+    public void invalidToken(String token) {
+        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
+        if (oAuth2AccessToken != null) {
+            OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
+            //从tokenStore中移除token
+            tokenStore.removeAccessToken(oAuth2AccessToken);
+            tokenStore.removeRefreshToken(oAuth2RefreshToken);
+            tokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public String clearDevice(String id) {
+        Members member = memberService.getById(id);
+        //清除设备信息
+        deviceService.clearDevice(id);
+        invalidToken(member.getActivationToken());
+
+        // 置空用户token信息
+        member.setUpdatedAt(new Date());
+        member.setActivationToken("");
+        member.setResetToken("");
+        memberService.update(member);
+        return "清除设备信息成功";
+    }
 }

+ 154 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/AvatarServiceImpl.java

@@ -0,0 +1,154 @@
+package cn.kdan.pdf.backend.core.service.impl;
+
+import cn.kdan.pdf.backend.core.client.OssFileClient;
+import cn.kdan.pdf.backend.core.mapper.AvatarsMapper;
+import cn.kdan.pdf.backend.core.model.Avatars;
+import cn.kdan.pdf.backend.core.model.AvatarsExample;
+import cn.kdan.pdf.backend.core.model.Members;
+import cn.kdan.pdf.backend.core.pojo.app.MemberVo;
+import cn.kdan.pdf.backend.core.pojo.app.UpTokenVo;
+import cn.kdan.pdf.backend.core.properties.OssProperties;
+import cn.kdan.pdf.backend.core.service.AvatarService;
+import cn.kdan.pdf.backend.core.service.MemberService;
+import cn.kdan.pdf.backend.core.utils.CommonBusinessUtils;
+import exception.BackendRuntimeException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.multipart.MultipartFile;
+import utils.CommonUtils;
+
+import javax.activation.MimetypesFileTypeMap;
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Slf4j
+@Service
+public class AvatarServiceImpl implements AvatarService {
+
+    @Resource
+    private AvatarsMapper avatarsMapper;
+    @Autowired
+    private OssFileClient ossFileClient;
+    @Autowired
+    private MemberService memberService;
+    @Autowired
+    private OssProperties ossProperties;
+
+    // 图片文件类型
+    public static String IMG_TYPE_PNG = "PNG";
+    public static String IMG_TYPE_JPG = "JPG";
+    public static String IMG_TYPE_JPEG = "JPEG";
+    public static String IMG_TYPE_DMG = "BMP";
+    public static String IMG_TYPE_GIF = "GIF";
+    public static String IMG_TYPE_SVG = "SVG";
+
+
+    @Override
+    public List<Avatars> list() {
+        AvatarsExample example = new AvatarsExample();
+        example.createCriteria().andMemberIdIsNull();
+        List<Avatars> avatars = avatarsMapper.selectByExample(example);
+        String viewUrl = ossProperties.getViewUrl();
+        for (Avatars avatar : avatars) {
+            avatar.setAvatar(viewUrl + avatar.getAvatar());
+        }
+        return avatars;
+    }
+
+    @Override
+    public String selectAvatarByMemberId(String memberId) {
+        AvatarsExample example = new AvatarsExample();
+        example.createCriteria().andMemberIdEqualTo(memberId);
+        List<Avatars> avatars = avatarsMapper.selectByExample(example);
+        if(CollectionUtils.isEmpty(avatars)){
+            return "";
+        }
+        String viewUrl = ossProperties.getViewUrl();
+        return viewUrl + avatars.get(0).getAvatar();
+    }
+
+    @Override
+    public UpTokenVo picUpload(MultipartFile file) {
+        UpTokenVo upTokenVo = new UpTokenVo();
+        checkFile(file);
+        Members currentUser = memberService.getCurrentUser();
+        String memberId = currentUser.getId();
+
+        String ossFileName = "";
+        try {
+            //上传文件并授权为可读写
+            ossFileName = ossFileClient.upload(file,true);
+            //设置读权限
+//            ossFileClient.setAcl(ossFileName);
+        } catch (IOException e) {
+            log.error("上传头像失败:{}",e.getMessage());
+        }
+        //判断是否已存在用户头像数据,有就更新,没有就新增
+        AvatarsExample example = new AvatarsExample();
+        example.createCriteria().andMemberIdEqualTo(memberId);
+        List<Avatars> list = avatarsMapper.selectByExample(example);
+        Date now = new Date();
+        if(!CollectionUtils.isEmpty(list)){
+            Avatars avatars = list.get(0);
+            // 将用户原来的头像数据先删除
+            String oldUrl = avatars.getAvatar();
+            ossFileClient.delete(oldUrl);
+            avatars.setAvatar(ossFileName);
+            avatars.setUpdatedAt(now);
+            avatarsMapper.updateByPrimaryKey(avatars);
+        }else {
+            Avatars avatars = new Avatars();
+            avatars.setAvatar(ossFileName);
+            avatars.setId(CommonUtils.generateId());
+            avatars.setMemberId(memberId);
+            avatars.setAppScope(1);
+            avatars.setNumber(0);
+            avatars.setCreatedAt(now);
+            avatars.setUpdatedAt(now);
+            avatarsMapper.insert(avatars);
+        }
+        MemberVo member = new MemberVo();
+        BeanUtils.copyProperties(currentUser,member);
+        member.setPhone(currentUser.getPhone());
+        member.setName(currentUser.getName());
+        member.setStatus("register");
+        member.setTimeZone(currentUser.getTimeZone());
+        member.setEmail(currentUser.getEmail());
+        member.setPhoneZone(currentUser.getPhoneZone());
+        String viewUrl = ossProperties.getViewUrl();
+        member.setAvatarUrl(viewUrl+ossFileName);
+        upTokenVo.setMember(member);
+        return upTokenVo;
+    }
+
+    /**
+     * 检查文件类型大小等
+     * @param file
+     */
+    private void checkFile(MultipartFile file) {
+        long size = file.getSize();
+        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
+        if(!(IMG_TYPE_DMG.equals(suffix.toUpperCase()) ||
+                IMG_TYPE_GIF.equals(suffix.toUpperCase()) ||
+                IMG_TYPE_JPEG.equals(suffix.toUpperCase()) ||
+                IMG_TYPE_JPG.equals(suffix.toUpperCase()) ||
+                IMG_TYPE_PNG.equals(suffix.toUpperCase()) ||
+                IMG_TYPE_SVG.equals(suffix.toUpperCase()))){
+            throw new BackendRuntimeException("请上传图片类型的文件!");
+        }
+        boolean flag = CommonBusinessUtils.checkFileSize(size, 2, "M");
+        if(!flag){
+            throw new BackendRuntimeException("上传图片太大!");
+        }
+    }
+
+}

+ 5 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/ConvertFileServiceImpl.java

@@ -50,7 +50,11 @@ public class ConvertFileServiceImpl implements ConvertFileService {
     public List<ConvertTypeVo> getConvertTypeList(String inputFileType, String outputFileType) {
         List<ConvertTypeVo> result = new ArrayList<>();
         ConvertTypesExample example = new ConvertTypesExample();
-        example.createCriteria().andInputTypeEqualTo(inputFileType).andOutputTypeEqualTo(outputFileType).andDeletedAtIsNull();
+        ConvertTypesExample.Criteria criteria = example.createCriteria();
+        if(!StringUtils.isEmpty(outputFileType)){
+            criteria.andOutputTypeEqualTo(outputFileType);
+        }
+        criteria.andInputTypeEqualTo(inputFileType).andDeletedAtIsNull();
         List<ConvertTypes> convertTypes = convertTypesMapper.selectByExample(example);
 
         for (ConvertTypes type : convertTypes) {

+ 55 - 5
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/DeviceServiceImpl.java

@@ -3,12 +3,17 @@ package cn.kdan.pdf.backend.core.service.impl;
 import cn.kdan.pdf.backend.core.mapper.DevicesMapper;
 import cn.kdan.pdf.backend.core.model.Devices;
 import cn.kdan.pdf.backend.core.model.DevicesExample;
+import cn.kdan.pdf.backend.core.model.Members;
+import cn.kdan.pdf.backend.core.params.RelationParam;
 import cn.kdan.pdf.backend.core.service.DeviceService;
+import cn.kdan.pdf.backend.core.service.MemberService;
 import exception.BackendRuntimeException;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
+import pojo.Device;
 
 import javax.annotation.Resource;
 import java.util.Date;
@@ -24,6 +29,8 @@ public class DeviceServiceImpl implements DeviceService {
 
     @Resource
     private DevicesMapper devicesMapper;
+    @Resource
+    private MemberService memberService;
 
     @Override
     @Transactional(rollbackFor = BackendRuntimeException.class)
@@ -50,10 +57,22 @@ public class DeviceServiceImpl implements DeviceService {
         //再根据用户id+设备唯一标识uuid查询
         List<Devices> list = devicesMapper.selectByExample(example);
         //如果数据大于等于3条,不允许新增数据,只能更新
-        if(devices.size() >= 3 && CollectionUtils.isEmpty(list)){
-            return devices.get(0);
+        if(!CollectionUtils.isEmpty(list)){
+            return list.get(0);
+        }else{
+            if(devices.size() >= 3){
+                throw new BackendRuntimeException("当前已登录3台设备,无法在进行登录");
+            }else{
+                return null;
+            }
         }
-        return list.get(0);
+//        if(devices.size() >= 3 && CollectionUtils.isEmpty(list)){
+//            return devices.get(0);
+//        }else if ((devices.size() >= 3 && !CollectionUtils.isEmpty(list))){
+//            return list.get(0);
+//        }else {
+//            return null;
+//        }
     }
 
     @Override
@@ -61,8 +80,39 @@ public class DeviceServiceImpl implements DeviceService {
     public void update(Devices device, String uuid) {
         Date date = new Date();
         device.setUpdatedAt(date);
+        devicesMapper.updateByPrimaryKey(device);
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public Device updateInfo(RelationParam param) {
+        Members currentUser = memberService.getCurrentUser();
+        Device device = param.getDevice();
+        DevicesExample example = new DevicesExample();
+        example.createCriteria().andMemberIdEqualTo(currentUser.getId()).andUuidEqualTo(device.getUuid());
+        List<Devices> devices = devicesMapper.selectByExample(example);
+        if(!CollectionUtils.isEmpty(devices)){
+            Devices dev = devices.get(0);
+            BeanUtils.copyProperties(device,dev);
+            dev.setUpdatedAt(new Date());
+            devicesMapper.updateByExample(dev,example);
+        }
+        return device;
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public void deleteByUuid(String uuid, String memberId){
+        DevicesExample example = new DevicesExample();
+        example.createCriteria().andMemberIdEqualTo(memberId).andUuidEqualTo(uuid);
+        devicesMapper.deleteByExample(example);
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public void clearDevice(String memberId) {
         DevicesExample example = new DevicesExample();
-        example.createCriteria().andMemberIdEqualTo(device.getMemberId()).andUuidEqualTo(uuid);
-        devicesMapper.updateByExample(device,example);
+        example.createCriteria().andMemberIdEqualTo(memberId);
+        devicesMapper.deleteByExample(example);
     }
 }

+ 202 - 65
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MemberServiceImpl.java

@@ -2,23 +2,20 @@ package cn.kdan.pdf.backend.core.service.impl;
 
 import cn.kdan.pdf.backend.core.constant.AuthConstant;
 import cn.kdan.pdf.backend.core.constant.MembersConstant;
-import cn.kdan.pdf.backend.core.enums.CaptchaActionEnum;
-import cn.kdan.pdf.backend.core.enums.ProviderEnum;
-import cn.kdan.pdf.backend.core.enums.SubscriberTypeEnum;
-import cn.kdan.pdf.backend.core.enums.VerifyTypeEnum;
+import cn.kdan.pdf.backend.core.enums.*;
 import cn.kdan.pdf.backend.core.mapper.*;
 import cn.kdan.pdf.backend.core.mapper.ext.ExtMembersMapper;
 import cn.kdan.pdf.backend.core.model.*;
 import cn.kdan.pdf.backend.core.model.member.*;
 import cn.kdan.pdf.backend.core.params.BindAccountParam;
+import cn.kdan.pdf.backend.core.params.CheckExistsParam;
 import cn.kdan.pdf.backend.core.params.UserResetPwdParams;
+import cn.kdan.pdf.backend.core.pojo.ExistsMemberVo;
 import cn.kdan.pdf.backend.core.pojo.app.BindAccountVo;
+import cn.kdan.pdf.backend.core.pojo.app.MemberInfoVo;
 import cn.kdan.pdf.backend.core.pojo.app.MemberVo;
 import cn.kdan.pdf.backend.core.pojo.app.SocialAccountVo;
-import cn.kdan.pdf.backend.core.service.AuthService;
-import cn.kdan.pdf.backend.core.service.MemberService;
-import cn.kdan.pdf.backend.core.service.SocialAccountService;
-import cn.kdan.pdf.backend.core.service.UserService;
+import cn.kdan.pdf.backend.core.service.*;
 import constant.CommonConstant;
 import enums.CommonEnum;
 import exception.BackendRuntimeException;
@@ -38,7 +35,6 @@ import utils.CommonUtils;
 import utils.RedisUtils;
 import utils.SMSUtils;
 
-import javax.naming.Name;
 import java.math.BigDecimal;
 import java.util.*;
 
@@ -59,7 +55,7 @@ public class MemberServiceImpl implements MemberService {
     @Autowired
     private SMSUtils smsUtils;
     @Autowired
-    private AvatarsMapper avatarsMapper;
+    private AvatarService avatarService;
     @Autowired
     private RedisUtils redisUtils;
     @Autowired
@@ -125,6 +121,15 @@ public class MemberServiceImpl implements MemberService {
                 // 验证成功删除验证码缓存
                 redisUtils.hdel(AuthConstant.VERIFY_CODE_KEY + CaptchaActionEnum.USER_REGISTER.value(), username);
             }
+        }else{
+            // 验证邮箱验证码
+            String verifyCode = redisUtils.hget(AuthConstant.VERIFY_CODE_KEY + CaptchaActionEnum.USER_REGISTER.value(), username);
+            if (!req.getVerifyCode().equals(verifyCode)) {
+                throw new BackendRuntimeException(AuthConstant.EXCEPTION_MSG_CODE_ERROR);
+            } else {
+                // 验证成功删除验证码缓存
+                redisUtils.hdel(AuthConstant.VERIFY_CODE_KEY + CaptchaActionEnum.USER_REGISTER.value(), username);
+            }
         }
 
         // 根据用户名查询数据库是否已有数据,判断该账号是否已注册过
@@ -287,18 +292,15 @@ public class MemberServiceImpl implements MemberService {
         } else {
             memberInfo.setUsedSpacePercent(BigDecimal.ZERO);
         }
-        AvatarsExample avatarsExample = new AvatarsExample();
-        avatarsExample.createCriteria().andMemberIdEqualTo(member.getId());
-        List<Avatars> avatars = avatarsMapper.selectByExample(avatarsExample);
-        if (!CollectionUtils.isEmpty(avatars)) {
-            memberInfo.setAvatarUrl(avatars.get(0).getAvatar());
-        }
+
+        memberInfo.setAvatarUrl(avatarService.selectAvatarByMemberId(member.getId()));
 
         //根据用户id查询订阅数据
         SubscriptionsExample example = new SubscriptionsExample();
         SubscriptionsExample.Criteria criteria = example.createCriteria();
         criteria.andMemberIdEqualTo(memberInfo.getId());
         criteria.andStatusNotBetween(0, 1);
+        example.setOrderByClause("updated_at DESC");
         List<Subscriptions> subscriptionsList = subscriptionsMapper.selectByExample(example);
 
         //根据targetType区分券服务与会员服务数据
@@ -316,6 +318,7 @@ public class MemberServiceImpl implements MemberService {
                 SubSetPricing subSetPricing = new SubSetPricing();
                 BeanUtils.copyProperties(subscription, subSetPricing);
                 subSetPricing.setSetPricings(setPricingMap.get(subscription.getTargetId()));
+                subSetPricing.setCreateDate(subscription.getCreatedAt());
                 subSetPricingList.add(subSetPricing);
             }
         }
@@ -390,6 +393,40 @@ public class MemberServiceImpl implements MemberService {
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public Integer judgeSubscribeType(String memberId) {
+        SubscriptionsExample example = new SubscriptionsExample();
+        SubscriptionsExample.Criteria criteria = example.createCriteria();
+        criteria.andMemberIdEqualTo(memberId);
+        criteria.andStatusNotBetween(0, 1);
+        criteria.andTargetTypeEqualTo(GoodsTypeEnum.SetPricing.value());
+        example.setOrderByClause("updated_at DESC");
+        List<Subscriptions> subscriptionsList = subscriptionsMapper.selectByExample(example);
+        List<SubSetPricing> subSetPricingList = new ArrayList<>();
+        for (Subscriptions subscription : subscriptionsList) {
+            if (subscription.getTargetType().equals(CommonEnum.SubscriptionTypeEnum.SET_PRICING.value())) {
+                SubSetPricing subSetPricing = new SubSetPricing();
+                BeanUtils.copyProperties(subscription, subSetPricing);
+                subSetPricingList.add(subSetPricing);
+            }
+        }
+        //获取会员剩余天数
+        long day = getLeftDay(subSetPricingList);
+        //如果会员天数小于0,修改会员状态为否
+        if(day == 0){
+            Members member = getCurrentUser();
+            if(SubscriberTypeEnum.yes.value().equals(member.getSubscriberType())) {
+                member.setUpdatedAt(new Date());
+                member.setSubscriberType(SubscriberTypeEnum.no.value());
+                membersMapper.updateByPrimaryKey(member);
+            }
+            return SubscriberTypeEnum.no.value();
+        }else{
+            return SubscriberTypeEnum.yes.value();
+        }
+    }
+
     @Override
     public Members getById(String userId) {
         Members members = membersMapper.selectByPrimaryKey(userId);
@@ -415,6 +452,9 @@ public class MemberServiceImpl implements MemberService {
             //根据code和邮箱验证用户
             if (!authService.checkVerifyCode(CaptchaActionEnum.FORGET_PASSWORD.value(), params.getAccount(), params.getVerifyCode())) {
                 throw new BackendRuntimeException(AuthConstant.EXCEPTION_MSG_RESET_PASSWORD_ERROR);
+            }else {
+                // 验证成功删除验证码缓存
+                redisUtils.hdel(AuthConstant.VERIFY_CODE_KEY + CaptchaActionEnum.FORGET_PASSWORD.value(), params.getAccount());
             }
             example.createCriteria().andEmailEqualTo(params.getAccount());
         }
@@ -431,6 +471,11 @@ public class MemberServiceImpl implements MemberService {
         return Boolean.TRUE;
     }
 
+    @Override
+    public boolean appResetPassword(UserResetPwdParams param) {
+        return authService.getVerifyCode(CaptchaActionEnum.FORGET_PASSWORD, VerifyTypeEnum.EMAIL, param.getAccount());
+    }
+
     /**
      * 获取会员剩余天数
      */
@@ -490,7 +535,7 @@ public class MemberServiceImpl implements MemberService {
     @Transactional(rollbackFor = BackendRuntimeException.class)
     public BindAccountVo bindAccount(BindAccountParam param) {
         BindAccountVo bindAccountVo = new BindAccountVo();
-        SocialAccountVo socialAccountVo = new SocialAccountVo();
+        List<SocialAccountVo> socialAccounts = new ArrayList<>();
         MemberVo memberVo = new MemberVo();
         Members currentUser = getCurrentUser();
         BeanUtils.copyProperties(currentUser,memberVo);
@@ -499,55 +544,78 @@ public class MemberServiceImpl implements MemberService {
 
         String provider = param.getProvider();
         if("phone".equals(provider)){
-            String phone = param.getPhone();
-            if(StringUtils.isEmpty(phone)){
-                throw new BackendRuntimeException("手机号不能为空");
-            }
-            Members member = userService.getByAccount(phone);
-            if(member != null){
-                //不允许绑定自己
-                if(member.getId().equals(currentUser.getId())) {
-                    throw new BackendRuntimeException("不允许绑定自己");
-                }else{
-                    if(member.getTotalPoints() <= 10 && SubscriberTypeEnum.no.value().equals(member.getSubscriberType())){
-                        //删除该手机的账号数据,然后更新手机到当前用户
-                        membersMapper.deleteByPrimaryKey(member.getId());
-                        //更新当前账号的手机号为phone参数
-                        if(!StringUtils.isEmpty(param.getPhoneZone())){
-                            currentUser.setPhoneZone(param.getPhoneZone());
-                        }
-                        currentUser.setPhone(phone);
-                        currentUser.setUpdatedAt(new Date());
-                        update(currentUser);
-                    }else{
-                        throw new BackendRuntimeException("不允许绑定该账号,因为充过钱了!");
-                    }
-                }
-            }else{
-                //直接更新当前账号的手机号为phone参数
-                if(!StringUtils.isEmpty(param.getPhoneZone())){
-                    currentUser.setPhoneZone(param.getPhoneZone());
-                }
-                currentUser.setPhone(phone);
-                currentUser.setUpdatedAt(new Date());
-                update(currentUser);
-            }
+            bindPhone(param, socialAccounts, currentUser);
+            memberVo.setPhone(param.getPhone());
         } else{
             //绑定第三方账号
-            String accountId = socialAccountService.bindSocialAccount(currentUser,param);
-            SocialAccounts socialAccounts = socialAccountService.selectByAccountId(accountId);
-            BeanUtils.copyProperties(socialAccounts,socialAccountVo);
-            bindAccountVo.setSocialAccount(socialAccountVo);
+            socialAccounts = socialAccountService.bindSocialAccount(currentUser, param, socialAccounts);
         }
+        bindAccountVo.setSocialAccounts(socialAccounts);
         return bindAccountVo;
     }
 
+    /**
+     * 手机号绑定
+     * @param param 入参
+     * @param socialAccounts 社交账号
+     * @param currentUser 当前用户
+     */
+    private void bindPhone(BindAccountParam param, List<SocialAccountVo> socialAccounts, Members currentUser) {
+        String phone = param.getPhone();
+        if(StringUtils.isEmpty(phone)){
+            throw new BackendRuntimeException("手机号不能为空");
+        }
+        Members member = userService.getByAccount(phone);
+        if(member != null){
+            //不允许绑定自己
+            if(member.getId().equals(currentUser.getId())) {
+                throw new BackendRuntimeException("不允许绑定自己");
+            }else{
+                if(member.getTotalPoints() <= 10 && SubscriberTypeEnum.no.value().equals(member.getSubscriberType())){
+                    // 当该手机用户已经绑定了第三方账号的时候,不允许此次绑定
+                    List<SocialAccounts> list = socialAccountService.selectByMemberId(member.getId());
+                    if(!CollectionUtils.isEmpty(list)){
+                        throw new BackendRuntimeException("该账号已被绑定,不允许再次绑定");
+                    }
+                    //删除该手机的账号数据,然后更新手机到当前用户
+                    membersMapper.deleteByPrimaryKey(member.getId());
+                    //更新当前账号的手机号为phone参数
+                    if(!StringUtils.isEmpty(param.getPhoneZone())){
+                        currentUser.setPhoneZone(param.getPhoneZone());
+                    }
+                    currentUser.setPhone(phone);
+                    currentUser.setUpdatedAt(new Date());
+                    update(currentUser);
+                }else{
+                    throw new BackendRuntimeException("不允许绑定该账号,因为充过钱了!");
+                }
+            }
+        }else{
+            //直接更新当前账号的手机号为phone参数
+            if(!StringUtils.isEmpty(param.getPhoneZone())){
+                currentUser.setPhoneZone(param.getPhoneZone());
+            }
+            currentUser.setPhone(phone);
+            currentUser.setUpdatedAt(new Date());
+            update(currentUser);
+        }
+
+        List<SocialAccounts> list = socialAccountService.selectByMemberId(currentUser.getId());
+        for (SocialAccounts account : list) {
+            SocialAccountVo vo = new SocialAccountVo();
+            vo.setProvider(ProviderEnum.getNameByCode(account.getProvider()));
+            vo.setName(account.getName());
+            vo.setAccountId(account.getAccountId());
+            socialAccounts.add(vo);
+        }
+    }
+
     @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
     public BindAccountVo unbindAccount(BindAccountParam param) {
         BindAccountVo bindAccountVo = new BindAccountVo();
+        List<SocialAccountVo> socialAccounts = new ArrayList<>();
         MemberVo memberVo = new MemberVo();
-        SocialAccountVo accountVo = new SocialAccountVo();
-
         Members currentUser = getCurrentUser();
         BeanUtils.copyProperties(currentUser,memberVo);
         memberVo.setStatus("verified");
@@ -556,17 +624,25 @@ public class MemberServiceImpl implements MemberService {
         String provider = param.getProvider();
         if("phone".equals(provider)){
             currentUser.setPhone("");
+            bindAccountVo.getMember().setPhone("");
             update(currentUser);
+            List<SocialAccounts> list = socialAccountService.selectByMemberId(currentUser.getId());
+            for (SocialAccounts account : list) {
+                SocialAccountVo vo = new SocialAccountVo();
+                vo.setProvider(ProviderEnum.getNameByCode(account.getProvider()));
+                vo.setName(account.getName());
+                vo.setAccountId(account.getAccountId());
+                socialAccounts.add(vo);
+            }
         } else {
-            String accountId = socialAccountService.unbindSocialAccount(currentUser,param);
-            SocialAccounts socialAccounts = socialAccountService.selectByAccountId(accountId);
-            BeanUtils.copyProperties(socialAccounts,accountVo);
-            bindAccountVo.setSocialAccount(accountVo);
+            socialAccountService.unbindSocialAccount(currentUser, provider, socialAccounts);
         }
+        bindAccountVo.setSocialAccounts(socialAccounts);
         return bindAccountVo;
     }
 
     @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
     public MemberVo appModifyName(String name) {
         modifyNickname(name);
         Members currentUser = getCurrentUser();
@@ -581,11 +657,72 @@ public class MemberServiceImpl implements MemberService {
     public MemberVo createMemberVo(Members member){
         MemberVo vo = new MemberVo();
         BeanUtils.copyProperties(member,vo);
-        AvatarsExample example = new AvatarsExample();
-        example.createCriteria().andMemberIdEqualTo(member.getId());
-        List<Avatars> avatars = avatarsMapper.selectByExample(example);
-        if(!CollectionUtils.isEmpty(avatars)){
-            vo.setAvatarUrl(avatars.get(0).getAvatar());
+        vo.setAvatarUrl(avatarService.selectAvatarByMemberId(member.getId()));
+        return vo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public void deleteByMemberId(String memberId) {
+        membersMapper.deleteByPrimaryKey(memberId);
+    }
+
+    @Override
+    public MemberInfoVo appGetMemberInfo(String subscription, String withSocial) {
+        MemberInfoVo memberInfoVo = new MemberInfoVo();
+        MemberInfoResp memberDetail = getMemberDetail(null);
+        memberInfoVo.setType("members");
+        memberInfoVo.setMemberInfo(memberDetail.getMemberInfo());
+        //1:显示订阅信息 0:不显示订阅信息
+        if("1".equals(subscription)){
+            memberInfoVo.setSetPricingList(memberDetail.getSetPricingList());
+            memberInfoVo.setPricingList(memberDetail.getPricingList());
+        }
+        // 如果是QQ、微信登录,传入字段可实现第三方登录的信息。0:不显示, 1:显示
+        if("1".equals(withSocial)){
+            List<SocialAccountVo> list = new ArrayList<>();
+            List<SocialAccounts> socialAccounts = socialAccountService.selectByMemberId(memberDetail.getMemberInfo().getId());
+            if(!CollectionUtils.isEmpty(socialAccounts)) {
+                for (SocialAccounts account : socialAccounts) {
+                    SocialAccountVo vo = new SocialAccountVo();
+                    BeanUtils.copyProperties(account, vo);
+                    vo.setProvider(ProviderEnum.getNameByCode(account.getProvider()));
+                    list.add(vo);
+                }
+            }
+            memberInfoVo.setSocialAccountList(list);
+        }
+        return memberInfoVo;
+    }
+
+    @Override
+    public ExistsMemberVo checkExists(CheckExistsParam param) {
+        ExistsMemberVo vo = new ExistsMemberVo();
+        String email = param.getEmail();
+        String name = param.getName();
+        String phone = param.getPhone();
+        MembersExample example = new MembersExample();
+        MembersExample.Criteria criteria = example.createCriteria();
+        if(!StringUtils.isEmpty(email)){
+            criteria.andEmailEqualTo(email);
+        }else if(!StringUtils.isEmpty(name)){
+            criteria.andNameEqualTo(name);
+        }else{
+            criteria.andPhoneEqualTo(phone);
+        }
+        List<Members> list = membersMapper.selectByExample(example);
+        if(!CollectionUtils.isEmpty(list)){
+            Members members = list.get(0);
+            if(!StringUtils.isEmpty(email)){
+                vo.setKey("eamil");
+                vo.setValue(members.getEmail());
+            }else if(!StringUtils.isEmpty(name)){
+                vo.setKey("name");
+                vo.setValue(members.getName());
+            }else{
+                vo.setKey("phone");
+                vo.setValue(members.getPhone());
+            }
         }
         return vo;
     }

+ 10 - 1
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MissionFileServiceImpl.java

@@ -74,8 +74,9 @@ public class MissionFileServiceImpl implements MissionFilesService {
             missionFile.setTraceResult(result.getFileUrl());
             missionFilesMapper.updateByPrimaryKeySelective(missionFile);
         } catch (Exception e) {
+            log.error("上传文件失败,{},{}", e, e.getMessage());
             missionFile.setStatus(MissionFileStatusEnum.FAILED.value());
-            missionFile.setFailReason(MissionConstant.UNKNOWN_ERROR_MSG);
+            missionFile.setFailReason(e.getMessage());
             missionFilesMapper.updateByPrimaryKeySelective(missionFile);
             throw new BackendRuntimeException(e.getMessage());
         }
@@ -136,4 +137,12 @@ public class MissionFileServiceImpl implements MissionFilesService {
         example.createCriteria().andSaasTaskIdEqualTo(id);
         return missionFilesMapper.selectByExample(example);
     }
+
+    @Override
+    public Integer getTotalConvertFile() {
+        MissionFilesExample example = new MissionFilesExample();
+        long l = missionFilesMapper.countByExample(example);
+        return (int)l;
+    }
+
 }

+ 16 - 8
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/MissionServiceImpl.java

@@ -5,10 +5,7 @@ import cn.kdan.pdf.backend.core.constant.MissionConstant;
 import cn.kdan.pdf.backend.core.enums.MissionFileStatusEnum;
 import cn.kdan.pdf.backend.core.enums.SubscriberTypeEnum;
 import cn.kdan.pdf.backend.core.mapper.MissionsMapper;
-import cn.kdan.pdf.backend.core.model.ConvertTypes;
-import cn.kdan.pdf.backend.core.model.Members;
-import cn.kdan.pdf.backend.core.model.MissionFiles;
-import cn.kdan.pdf.backend.core.model.Missions;
+import cn.kdan.pdf.backend.core.model.*;
 import cn.kdan.pdf.backend.core.model.member.MemberInfo;
 import cn.kdan.pdf.backend.core.params.MissionCreateParam;
 import cn.kdan.pdf.backend.core.pojo.ConvertTypeVo;
@@ -18,10 +15,7 @@ import cn.kdan.pdf.backend.core.pojo.comPdfKit.CreateTaskResult;
 import cn.kdan.pdf.backend.core.pojo.comPdfKit.FileInfoDto;
 import cn.kdan.pdf.backend.core.pojo.comPdfKit.QueryTaskInfoResult;
 import cn.kdan.pdf.backend.core.pojo.comPdfKit.WebhookSendDTO;
-import cn.kdan.pdf.backend.core.service.ConvertFileService;
-import cn.kdan.pdf.backend.core.service.MemberService;
-import cn.kdan.pdf.backend.core.service.MissionFilesService;
-import cn.kdan.pdf.backend.core.service.MissionService;
+import cn.kdan.pdf.backend.core.service.*;
 import cn.kdan.pdf.backend.core.utils.ComPdfKitUtils;
 import constant.CommonConstant;
 import exception.BackendRuntimeException;
@@ -59,6 +53,8 @@ public class MissionServiceImpl implements MissionService {
     ConvertFileService convertFileService;
     @Resource
     private DistributedLocker distributedLocker;
+    @Resource
+    private OutputFileService outputFileService;
 
     /**
      * saas任务完成状态
@@ -114,6 +110,7 @@ public class MissionServiceImpl implements MissionService {
             //插入list返回前端
             MissionFileVO missionFileVO = new MissionFileVO();
             BeanUtils.copyProperties(missionFile, missionFileVO);
+            missionFileVO.setOutputType(param.getOutput());
             missionFilePoJos.add(missionFileVO);
         }
         //插入任务表
@@ -311,6 +308,16 @@ public class MissionServiceImpl implements MissionService {
                         missionFiles.setStatus(MissionFileStatusEnum.SUCCESS.value());
                         missionFiles.setUpdatedAt(new Date());
                         missionFilesService.update(missionFiles);
+                        OutputFiles outputFile = new OutputFiles();
+                        outputFile.setId(CommonUtils.generateId());
+                        outputFile.setMissionId(missionFiles.getMissionId());
+                        outputFile.setMemberId(members.getId());
+                        outputFile.setMissionFileId(missionFiles.getId());
+                        outputFile.setFileName(missionFiles.getOutFilename());
+                        outputFile.setOriginalFilename(missionFiles.getOriginalFilename());
+                        outputFile.setPath(missionFiles.getPath());
+                        outputFile.setSize(Integer.valueOf(file.getConvertSize()));
+                        outputFileService.insert(outputFile);
                     }
                 }else if ("failed".equals(file.getStatus())){
                     //先查询文件状态是否已更新成失败状态,已更新则不返回券数
@@ -344,6 +351,7 @@ public class MissionServiceImpl implements MissionService {
             missionFiles.setFailReason(file.getFailureReason());
         }
         missionFiles.setPrice(0);
+//        missionFiles.setSize(BigDecimal.ZERO);
         missionFiles.setUpdatedAt(new Date());
         missionFiles.setConvertEndAt(new Date());
         missionFilesService.update(missionFiles);

+ 46 - 13
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/OrderServiceImpl.java

@@ -77,8 +77,23 @@ public class OrderServiceImpl implements OrderService {
             .setNameFormat("PAY_NOTIFY_THREAD_POOL").build(), new ThreadPoolExecutor.AbortPolicy());
 
 
+    /**
+     * 根据订阅id查询订单
+     * @param subId 订阅id
+     * @return 订单
+     */
+    public Orders selectBySubId(String subId){
+        OrdersExample example = new OrdersExample();
+        example.createCriteria().andSubscriptionIdEqualTo(subId);
+        List<Orders> orders = ordersMapper.selectByExample(example);
+        if(!CollectionUtils.isEmpty(orders)){
+            return orders.get(0);
+        }
+        return null;
+    }
+
     @Override
-    public Orders findMemberUnPayedOrders(String memberId, Subscriptions subscription){
+    public Orders findMemberUnPayedOrders(String memberId, Subscriptions subscription, String client){
         OrdersExample example = new OrdersExample();
         example.createCriteria().andMemberIdEqualTo(memberId).andStatusEqualTo(OrdersStatusEnum.UNPAYED.value()).andPaymentEqualTo(subscription.getPayment()).andSubscriptionIdEqualTo(subscription.getId());
         List<Orders> list  = ordersMapper.selectByExample(example);
@@ -94,19 +109,30 @@ public class OrderServiceImpl implements OrderService {
             order.setUpdatedAt(new Date());
             order.setPrice(subscription.getPrice());
             //设置支付的url
-            setOrderPayUrlByPayment(subscription, order);
+            setOrderPayUrlByPayment(subscription, order, client);
             //插入
             ordersMapper.insert(order);
             return order;
+        }else{
+            //更新价格
+            Orders order = selectBySubId(subscription.getId());
+            if(order != null && !order.getPrice().equals(subscription.getPrice())) {
+                order.setPrice(subscription.getPrice());
+                order.setCreatedAt(new Date());
+                order.setUpdatedAt(new Date());
+                //设置支付的url
+                setOrderPayUrlByPayment(subscription, order, client);
+                ordersMapper.updateByPrimaryKey(order);
+            }
         }
         //如果微信url为空或者微信url超过两小时过期了,则重重新生成
-        boolean wxCheckDateFlag = StringUtils.isEmpty(list.get(0).getQrcodeUrl()) || DateUtils.addHours(list.get(0).getUpdatedAt(),2,1).compareTo(new Date())<0;
-        boolean aliCheckDateFlag = StringUtils.isEmpty(list.get(0).getPagePayUrl()) || DateUtils.addHours(list.get(0).getUpdatedAt(),2,1).compareTo(new Date())<0;
+        boolean wxCheckDateFlag = StringUtils.isEmpty(list.get(0).getQrcodeUrl()) || DateUtils.addHours(list.get(0).getUpdatedAt(),OrderConstant.WXPAY_EXPIRE_TIME,1).compareTo(new Date())<0;
+        boolean aliCheckDateFlag = StringUtils.isEmpty(list.get(0).getPagePayUrl()) || DateUtils.addHours(list.get(0).getUpdatedAt(),OrderConstant.ALIPAY_EXPIRE_TIME,1).compareTo(new Date())<0;
         boolean wxResetFlag = PaymentEnum.WXPAY.value().equals(subscription.getPayment()) && wxCheckDateFlag;
         boolean aliResetFlag = PaymentEnum.ALIPAY.value().equals(subscription.getPayment()) && aliCheckDateFlag;
         if(wxResetFlag||aliResetFlag){
             //处理必要的订单号 支付主题等数据
-            resetPayUrl(subscription, list.get(0));
+            resetPayUrl(subscription, list.get(0), client);
         }
        return list.get(0);
     }
@@ -116,8 +142,8 @@ public class OrderServiceImpl implements OrderService {
      * @param subscription 订阅
      * @param order 订单
      */
-    private void resetPayUrl(Subscriptions subscription, Orders order) {
-        setOrderPayUrlByPayment(subscription, order);
+    private void resetPayUrl(Subscriptions subscription, Orders order, String client) {
+        setOrderPayUrlByPayment(subscription, order, client);
         order.setUpdatedAt(new Date());
         ordersMapper.updateByPrimaryKey(order);
     }
@@ -127,14 +153,21 @@ public class OrderServiceImpl implements OrderService {
      * @param subscription 订阅
      * @param order 订单
      */
-    private void setOrderPayUrlByPayment(Subscriptions subscription, Orders order) {
+    private void setOrderPayUrlByPayment(Subscriptions subscription, Orders order, String client) {
         String subject = handleTradeNoAndSubject(subscription, order);
         if(PaymentEnum.WXPAY.value().equals(subscription.getPayment())){
-            order.setQrcodeUrl(wxPayService.unifiedOrder(subject,order.getTradeNo(),order.getPrice()));
+            Map<String, String> resp = wxPayService.unifiedOrder(subject, order.getTradeNo(), order.getPrice(), client);
+            order.setQrcodeUrl(resp.get(WXPayConstants.CODE_URL));
+            order.setAndroidSign2(JSON.toJSONString(resp));
         }
         if(PaymentEnum.ALIPAY.value().equals(subscription.getPayment())){
-            // 调用阿里支付下单接口
-            order.setPagePayUrl(alipayService.createAlipayPageUrl(subject,order.getTradeNo(),order.getPrice(),subscription));
+            // 调用阿里支付下单接口,web端返回支付url,android端返回androidSign
+            String alipayResult = alipayService.createAlipayPageUrl(subject, order.getTradeNo(), order.getPrice(), subscription, client);
+            if(ClientEnum.WEB.value().equals(client)) {
+                order.setPagePayUrl(alipayResult);
+            }else {
+                order.setAndroidSign(alipayResult);
+            }
         }
     }
 
@@ -289,7 +322,7 @@ public class OrderServiceImpl implements OrderService {
     private void handleWxPayOrderClosed(Orders order){
         //关闭订单后更新订阅表
         Subscriptions subscription = new Subscriptions();
-        subscription.setId(order.getMemberId());
+        subscription.setId(order.getSubscriptionId());
         subscription.setStatus(SubscriptionStatusEnum.UNPAYED.value());
         subscriptionService.update(subscription);
     }
@@ -298,7 +331,7 @@ public class OrderServiceImpl implements OrderService {
     private void handleWxPayOrderRefund(Orders order){
         //关闭订单后更新订阅表
         Subscriptions subscription = new Subscriptions();
-        subscription.setId(order.getMemberId());
+        subscription.setId(order.getSubscriptionId());
         subscription.setStatus(SubscriptionStatusEnum.UNPAYED.value());
         subscriptionService.update(subscription);
     }

+ 27 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/OutputFileServiceImpl.java

@@ -0,0 +1,27 @@
+package cn.kdan.pdf.backend.core.service.impl;
+
+import cn.kdan.pdf.backend.core.mapper.OutputFilesMapper;
+import cn.kdan.pdf.backend.core.model.OutputFiles;
+import cn.kdan.pdf.backend.core.service.OutputFileService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Service
+public class OutputFileServiceImpl implements OutputFileService {
+
+    @Autowired
+    private OutputFilesMapper outputFilesMapper;
+
+    @Override
+    public void insert(OutputFiles outputFile) {
+        outputFile.setCreatedAt(new Date());
+        outputFile.setUpdatedAt(new Date());
+        outputFilesMapper.insert(outputFile);
+    }
+}

+ 27 - 17
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/PricingServiceImpl.java

@@ -1,6 +1,7 @@
 package cn.kdan.pdf.backend.core.service.impl;
 
 import cn.kdan.pdf.backend.core.enums.ClientEnum;
+import cn.kdan.pdf.backend.core.enums.GoodsTypeEnum;
 import cn.kdan.pdf.backend.core.enums.SaleStatusEnum;
 import cn.kdan.pdf.backend.core.enums.SubscriberTypeEnum;
 import cn.kdan.pdf.backend.core.mapper.PricingsMapper;
@@ -8,10 +9,10 @@ import cn.kdan.pdf.backend.core.model.*;
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingReq;
 import cn.kdan.pdf.backend.core.model.pricing.QueryPricingResp;
 import cn.kdan.pdf.backend.core.model.pricing.PricingVo;
-import cn.kdan.pdf.backend.core.service.MemberService;
-import cn.kdan.pdf.backend.core.service.PricingDiscountService;
-import cn.kdan.pdf.backend.core.service.PricingService;
-import cn.kdan.pdf.backend.core.service.SubscriptionService;
+import cn.kdan.pdf.backend.core.params.QueryPricingParam;
+import cn.kdan.pdf.backend.core.pojo.SetPricingVO;
+import cn.kdan.pdf.backend.core.service.*;
+import cn.kdan.pdf.backend.core.utils.CommonBusinessUtils;
 import enums.CommonEnum;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
@@ -36,14 +37,8 @@ public class PricingServiceImpl implements PricingService {
     private SubscriptionService subscriptionService;
     @Autowired
     private MemberService memberService;
-
-    /**
-     * 语言(zh、zh-CN、zh-Hans表示汉语,en表示英语)
-     */
-    private final static String ZH = "zh";
-    private final static String ZH_CN = "zh-CN";
-    private final static String ZH_HANS = "zh-Hans";
-    private final static String EN = "en";
+    @Autowired
+    private SetPricingService setPricingService;
 
     /**
      * 1个月
@@ -61,11 +56,7 @@ public class PricingServiceImpl implements PricingService {
             client = ClientEnum.WEB.value();
         }
         String language = req.getLanguage();
-        if ("".equals(language) || ZH.equals(language) || ZH_CN.equals(language) || ZH_HANS.equals(language)) {
-            language = ZH_CN;
-        } else {
-            language = EN;
-        }
+        language = CommonBusinessUtils.judgeLanguage(language);
 
         Members member = memberService.getCurrentUser();
         PricingsExample example = new PricingsExample();
@@ -207,4 +198,23 @@ public class PricingServiceImpl implements PricingService {
         //为空的时候不加额外的券数
         return ObjectUtils.isEmpty(pricingDiscount) ? item.getAmount() : item.getAmount() + pricingDiscount.getExtraPoints();
     }
+
+    @Override
+    public QueryPricingResp appList(QueryPricingParam param) {
+        QueryPricingResp resp = new QueryPricingResp();
+        Members currentUser = memberService.getCurrentUser();
+        QueryPricingReq req = new QueryPricingReq();
+        String client = param.getClient();
+        req.setClient(client);
+        req.setLanguage(param.getLanguage());
+        String type = param.getType();
+        if(GoodsTypeEnum.Pricing.value().equals(type)){
+            resp = getPricingList(req);
+        }else{
+            List<SetPricingVO> list = setPricingService.list(client, currentUser);
+            resp.setSetPricingList(list);
+            resp.setType(GoodsTypeEnum.SetPricing.value());
+        }
+        return resp;
+    }
 }

+ 16 - 4
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SetPricingServiceImpl.java

@@ -4,10 +4,8 @@ import cn.kdan.pdf.backend.core.enums.ClientEnum;
 import cn.kdan.pdf.backend.core.enums.SaleStatusEnum;
 import cn.kdan.pdf.backend.core.enums.SubscriberTypeEnum;
 import cn.kdan.pdf.backend.core.mapper.SetPricingsMapper;
-import cn.kdan.pdf.backend.core.model.Members;
-import cn.kdan.pdf.backend.core.model.PricingDiscounts;
-import cn.kdan.pdf.backend.core.model.SetPricings;
-import cn.kdan.pdf.backend.core.model.SetPricingsExample;
+import cn.kdan.pdf.backend.core.mapper.ext.ExtSetPricingsMapper;
+import cn.kdan.pdf.backend.core.model.*;
 import cn.kdan.pdf.backend.core.pojo.SetPricingVO;
 import cn.kdan.pdf.backend.core.service.*;
 import lombok.extern.slf4j.Slf4j;
@@ -15,6 +13,7 @@ import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 
 import java.util.ArrayList;
@@ -35,6 +34,8 @@ public class SetPricingServiceImpl implements SetPricingService {
     private PricingDiscountService pricingDiscountService;
     @Autowired
     private SubscriptionService subscriptionService;
+    @Autowired
+    private ExtSetPricingsMapper extSetPricingsMapper;
 
     @Override
     public List<SetPricingVO> list(String client,Members member) {
@@ -176,4 +177,15 @@ public class SetPricingServiceImpl implements SetPricingService {
     private boolean isGooglePlay(SetPricings item) {
         return item.getProductCode().contains("17pdf");
     }
+
+
+    @Override
+    public List<Subscriptions> selectMode0(String memberId) {
+        return extSetPricingsMapper.selectMode0(memberId);
+    }
+
+    @Override
+    public List<Subscriptions> selectPByModeAndMemberId(String memberId, String mode) {
+        return extSetPricingsMapper.selectByModeAndMemberId(memberId,mode);
+    }
 }

+ 73 - 28
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SocialAccountServiceImpl.java

@@ -1,20 +1,27 @@
 package cn.kdan.pdf.backend.core.service.impl;
 
 import cn.kdan.pdf.backend.core.enums.ProviderEnum;
+import cn.kdan.pdf.backend.core.enums.SubscriberTypeEnum;
 import cn.kdan.pdf.backend.core.mapper.SocialAccountsMapper;
 import cn.kdan.pdf.backend.core.model.Members;
 import cn.kdan.pdf.backend.core.model.SocialAccounts;
 import cn.kdan.pdf.backend.core.model.SocialAccountsExample;
 import cn.kdan.pdf.backend.core.params.BindAccountParam;
+import cn.kdan.pdf.backend.core.pojo.app.SocialAccountVo;
 import cn.kdan.pdf.backend.core.pojo.third.Tencent;
 import cn.kdan.pdf.backend.core.pojo.third.Wechat;
+import cn.kdan.pdf.backend.core.service.MemberService;
 import cn.kdan.pdf.backend.core.service.SocialAccountService;
 import cn.kdan.pdf.backend.core.utils.TencentUtils;
 import cn.kdan.pdf.backend.core.utils.WechatUtils;
+import exception.BackendRuntimeException;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+import utils.CommonUtils;
 
 import javax.annotation.Resource;
 import java.util.Date;
@@ -30,6 +37,8 @@ public class SocialAccountServiceImpl implements SocialAccountService {
 
     @Resource
     private SocialAccountsMapper socialAccountsMapper;
+    @Resource
+    private MemberService memberService;
 
     @Override
     public SocialAccounts selectByAccountId(String accountId) {
@@ -52,14 +61,20 @@ public class SocialAccountServiceImpl implements SocialAccountService {
     }
 
     @Override
-    public SocialAccounts selectByMemberId(String userId, Integer provider) {
+    public List<SocialAccounts> selectByMemberId(String userId) {
+        SocialAccountsExample example = new SocialAccountsExample();
+        example.createCriteria().andMemberIdEqualTo(userId);
+        return socialAccountsMapper.selectByExample(example);
+    }
+
+    public SocialAccounts selectByMemberIdAndProvider(String userId, Integer provider){
         SocialAccountsExample example = new SocialAccountsExample();
         example.createCriteria().andMemberIdEqualTo(userId).andProviderEqualTo(provider);
         List<SocialAccounts> list = socialAccountsMapper.selectByExample(example);
-        if(CollectionUtils.isEmpty(list)){
-            return null;
+        if(!CollectionUtils.isEmpty(list)){
+            return list.get(0);
         }
-        return list.get(0);
+        return null;
     }
 
     @Override
@@ -70,18 +85,22 @@ public class SocialAccountServiceImpl implements SocialAccountService {
     }
 
     @Override
-    public String bindSocialAccount(Members member, BindAccountParam param) {
-        String accountId = "";
+    public List<SocialAccountVo> bindSocialAccount(Members member, BindAccountParam param, List<SocialAccountVo> socialAccounts) {
         String accessToken = param.getAccessToken();
         String openid = param.getOpenid();
         String provider = param.getProvider();
         if(ProviderEnum.TENCENT.getName().equals(provider)){
             Tencent userInfo = TencentUtils.getUserInfo(accessToken);
             String unionId = userInfo.getUnionId();
-            accountId = unionId;
+            if(StringUtils.isEmpty(unionId)){
+                log.info("未找到第三方账号,accessToken:{},openid:{}",accessToken,openid);
+                throw new BackendRuntimeException("未找到第三方账号");
+            }
             SocialAccounts socialAccount = selectByAccountId(unionId);
             //看看有没有该账号,没有就新增一条,有就更新用户id
             if(ObjectUtils.isEmpty(socialAccount)){
+                socialAccount = new SocialAccounts();
+                socialAccount.setId(CommonUtils.generateId());
                 socialAccount.setAccountId(unionId);
                 socialAccount.setMemberId(member.getId());
                 socialAccount.setName(userInfo.getNickname());
@@ -89,15 +108,24 @@ public class SocialAccountServiceImpl implements SocialAccountService {
                 socialAccount.setAvatar(userInfo.getFigureUrl());
                 insertSocialAccount(socialAccount);
             } else{
+                //如果有第三方账号,需要先将原用户账号删除,再进行绑定当前用户账号
+                String memberId = socialAccount.getMemberId();
+                verifyMemberPayed(memberId);
+                memberService.deleteByMemberId(memberId);
                 socialAccount.setMemberId(member.getId());
                 updateSocialAccount(socialAccount);
             }
         }else{
             Wechat userInfo = WechatUtils.getUserInfo(openid, accessToken);
             String unionId = userInfo.getUnionId();
-            accountId = unionId;
+            if(StringUtils.isEmpty(unionId)){
+                log.info("未找到第三方账号,accessToken:{},openid:{}",accessToken,openid);
+                throw new BackendRuntimeException("未找到第三方账号");
+            }
             SocialAccounts socialAccount = selectByAccountId(unionId);
             if(ObjectUtils.isEmpty(socialAccount)){
+                socialAccount = new SocialAccounts();
+                socialAccount.setId(CommonUtils.generateId());
                 socialAccount.setAvatar(userInfo.getHeadImgUrl());
                 socialAccount.setAccountId(unionId);
                 socialAccount.setProvider(ProviderEnum.getCodeByName(provider));
@@ -105,11 +133,34 @@ public class SocialAccountServiceImpl implements SocialAccountService {
                 socialAccount.setName(userInfo.getNickname());
                 insertSocialAccount(socialAccount);
             } else{
+                //如果有第三方账号,需要先将原用户账号删除,再进行绑定当前用户账号
+                String memberId = socialAccount.getMemberId();
+                verifyMemberPayed(memberId);
+                memberService.deleteByMemberId(memberId);
                 socialAccount.setMemberId(member.getId());
                 updateSocialAccount(socialAccount);
             }
         }
-        return accountId;
+        List<SocialAccounts> list = selectByMemberId(member.getId());
+        for (SocialAccounts account : list) {
+            SocialAccountVo vo = new SocialAccountVo();
+            vo.setProvider(ProviderEnum.getNameByCode(account.getProvider()));
+            vo.setName(account.getName());
+            vo.setAccountId(account.getAccountId());
+            socialAccounts.add(vo);
+        }
+        return socialAccounts;
+    }
+
+    /**
+     * 判断用户是否付费过
+     * @param memberId 用户id
+     */
+    public void verifyMemberPayed(String memberId){
+        Members member = memberService.getById(memberId);
+        if(member.getTotalPoints() > 10 || SubscriberTypeEnum.yes.value().equals(member.getSubscriberType())){
+            throw new BackendRuntimeException("不允许绑定该账号,因为充过钱了!");
+        }
     }
 
     /**
@@ -124,26 +175,20 @@ public class SocialAccountServiceImpl implements SocialAccountService {
     }
 
     @Override
-    public String unbindSocialAccount(Members currentUser, BindAccountParam param) {
-        String accountId = "";
-        String accessToken = param.getAccessToken();
-        String openid = param.getOpenid();
-        String provider = param.getProvider();
+    public List<SocialAccountVo> unbindSocialAccount(Members currentUser, String provider, List<SocialAccountVo> accounts) {
         SocialAccountsExample example = new SocialAccountsExample();
-        if(ProviderEnum.TENCENT.getName().equals(provider)){
-            Tencent userInfo = TencentUtils.getUserInfo(accessToken);
-            String unionId = userInfo.getUnionId();
-            accountId = unionId;
-            example.createCriteria().andAccountIdEqualTo(unionId);
-            socialAccountsMapper.deleteByExample(example);
-        } else {
-            Wechat userInfo = WechatUtils.getUserInfo(openid, accessToken);
-            String unionId = userInfo.getUnionId();
-            accountId = unionId;
-            SocialAccounts socialAccount = selectByAccountId(unionId);
-            example.createCriteria().andAccountIdEqualTo(unionId);
-            socialAccountsMapper.deleteByExample(example);
+        SocialAccounts socialAccount = selectByMemberIdAndProvider(currentUser.getId(), ProviderEnum.getCodeByName(provider));
+        example.createCriteria().andAccountIdEqualTo(socialAccount.getAccountId());
+        socialAccountsMapper.deleteByExample(example);
+        List<SocialAccounts> list = selectByMemberId(currentUser.getId());
+        for (SocialAccounts account : list) {
+            SocialAccountVo vo = new SocialAccountVo();
+            vo.setProvider(ProviderEnum.getNameByCode(account.getProvider()));
+            vo.setName(account.getName());
+            vo.setAccountId(account.getAccountId());
+            accounts.add(vo);
         }
-        return accountId;
+
+        return accounts;
     }
 }

+ 175 - 19
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/SubscriptionServiceImpl.java

@@ -2,12 +2,19 @@ package cn.kdan.pdf.backend.core.service.impl;
 
 import cn.kdan.pdf.backend.core.constant.SubscriptionConstant;
 import cn.kdan.pdf.backend.core.enums.*;
+import cn.kdan.pdf.backend.core.mapper.ExpensesMapper;
 import cn.kdan.pdf.backend.core.mapper.PricingDiscountsMapper;
 import cn.kdan.pdf.backend.core.mapper.SubscriptionsMapper;
 import cn.kdan.pdf.backend.core.model.*;
+import cn.kdan.pdf.backend.core.params.ExpenseParam;
 import cn.kdan.pdf.backend.core.pojo.SubscriptionVO;
+import cn.kdan.pdf.backend.core.pojo.app.*;
 import cn.kdan.pdf.backend.core.service.*;
 import cn.kdan.pdf.backend.core.utils.PeriodUtils;
+import cn.kdan.pdf.backend.core.utils.wxpay.MyConfig;
+import cn.kdan.pdf.backend.core.utils.wxpay.WXPayConstants;
+import cn.kdan.pdf.backend.core.utils.wxpay.WXPayUtil;
+import com.alibaba.fastjson.JSON;
 import enums.CommonEnum;
 import exception.BackendRuntimeException;
 import lombok.extern.slf4j.Slf4j;
@@ -19,6 +26,7 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 import utils.CommonUtils;
+import utils.DateUtils;
 
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
@@ -45,6 +53,10 @@ public class SubscriptionServiceImpl implements SubscriptionService {
     private OrderService orderService;
     @Autowired
     private PricingDiscountsMapper pricingDiscountsMapper;
+    @Autowired
+    private ExpensesMapper expensesMapper;
+    @Autowired
+    private MyConfig myWXConfig;
 
     @Override
     public long countTimesById(String memberId, String discountId) {
@@ -53,6 +65,63 @@ public class SubscriptionServiceImpl implements SubscriptionService {
         return subscriptionsMapper.countByExample(example);
     }
 
+    @Override
+    public CreateSubVo appCreate(String client, Integer payment, String targetType, String targetId) {
+        CreateSubVo createSubVo = new CreateSubVo();
+        //业务流程开始
+        SubscriptionVO subscriptionVO = create(client, payment, targetType, targetId);
+        BeanUtils.copyProperties(subscriptionVO,createSubVo);
+        ThirdOrderVo orderVo = new ThirdOrderVo();
+        Orders order = subscriptionVO.getOrder();
+        BeanUtils.copyProperties(order, orderVo);
+        createSubVo.setOrder(orderVo);
+        // 设置androidSign
+        if(PaymentEnum.ALIPAY.value().equals(payment)){
+            orderVo.setAndroidSign(order.getAndroidSign());
+        }else{
+            WxAndroidSignVo wxAndroidSign = new WxAndroidSignVo();
+
+            String androidSign2 = order.getAndroidSign2();
+            Map map = JSON.parseObject(androidSign2, Map.class);
+            try {
+                // 调起支付接口签名返回给app端,和统一下单参数的签名不一样,因为参数不一样
+                Map<String, String> signMmap = new HashMap<>();
+                signMmap.put("appid", myWXConfig.getAppID());
+                signMmap.put("partnerid", myWXConfig.getMchID());
+                signMmap.put("prepayid", map.get(WXPayConstants.PREPAY_ID).toString());
+                signMmap.put("package", "Sign=WXPay");
+                signMmap.put("noncestr", WXPayUtil.generateNonceStr());
+                signMmap.put("timestamp", String.valueOf(System.currentTimeMillis()).substring(0, 10));
+                String sign = WXPayUtil.generateSignature(signMmap, myWXConfig.getKey(), WXPayConstants.SignType.MD5);
+
+                wxAndroidSign.setNonceStr(signMmap.get("noncestr"));
+                wxAndroidSign.setPrepayId(signMmap.get("prepayid"));
+                wxAndroidSign.setAppId(signMmap.get("appid"));
+                wxAndroidSign.setPartnerId(signMmap.get("partnerid"));
+                wxAndroidSign.setTimestamp(signMmap.get("timestamp"));
+                wxAndroidSign.setPackageSign(signMmap.get("package"));
+                wxAndroidSign.setSign(sign);
+                orderVo.setWxAndroidSign(wxAndroidSign);
+            }catch (Exception e){
+                log.info("签名出错"+e.getMessage());
+            }
+        }
+
+        if(GoodsTypeEnum.SetPricing.value().equals(targetType)){
+            List<SetPricings> list = setPricingService.getForSaleRMBById(targetId);
+            if(!CollectionUtils.isEmpty(list)){
+                createSubVo.setSetPricing(list.get(0));
+            }
+        }else if(GoodsTypeEnum.Pricing.value().equals(targetType)){
+            List<Pricings> list = pricingService.getForSaleRMBById(targetId);
+            if(!CollectionUtils.isEmpty(list)){
+                createSubVo.setPricing(list.get(0));
+            }
+        }
+
+        return createSubVo;
+    }
+
     @Transactional(rollbackFor = BackendRuntimeException.class)
     @Override
     public SubscriptionVO create(String client, Integer payment, String targetType, String targetId) {
@@ -80,24 +149,33 @@ public class SubscriptionServiceImpl implements SubscriptionService {
         example.createCriteria().andMemberIdEqualTo(member.getId()).andTargetIdEqualTo(targetId).andPaymentEqualTo(payment).andTargetTypeEqualTo(targetType).andStatusEqualTo(SubscriptionStatusEnum.UNPAYED.value());
         List<Subscriptions> subscriptionsList = subscriptionsMapper.selectByExample(example);
         //如果该用户没有未支付的订阅记录,则插入一条
+        if (GoodsTypeEnum.SetPricing.value().equals(targetType)) {
+            SetPricings setPricings = setPricingService.getById(targetId);
+            return getSubscriptions(member, targetType, targetId, payment, client, subscriptionsList, setPricings);
+        }else if(GoodsTypeEnum.Pricing.value().equals(targetType)) {
+            Pricings pricings = pricingService.getById(targetId);
+            return getSubscriptions(member, targetType, targetId, payment, client, subscriptionsList, pricings);
+        }
+        return null;
+    }
+
+
+    private Subscriptions getSubscriptions(Members member, String targetType, Integer targetId, Integer payment, String client, List<Subscriptions> subscriptionsList, Object target) {
         if (CollectionUtils.isEmpty(subscriptionsList)) {
-            if (GoodsTypeEnum.SetPricing.value().equals(targetType)) {
-                SetPricings setPricings = setPricingService.getById(targetId);
-                Subscriptions subscriptions = getSubscriptions(member, targetType, targetId, payment);
-                // 计算订阅的开始时间和结束时间
-                renewInfo(true,client,subscriptions,member,setPricings);
-                subscriptionsMapper.insert(subscriptions);
-                return subscriptions;
-            }else if(GoodsTypeEnum.Pricing.value().equals(targetType)){
-                Pricings pricings = pricingService.getById(targetId);
-                Subscriptions subscriptions = getSubscriptions(member, targetType, targetId, payment);
-                // 计算订阅的开始时间和结束时间
-                renewInfo(true,client,subscriptions,member,pricings);
-                subscriptionsMapper.insert(subscriptions);
-                return subscriptions;
-            }
+            Subscriptions subscriptions = getSubscriptions(member, targetType, targetId, payment);
+            // 计算订阅的开始时间和结束时间
+            renewInfo(true, client, subscriptions, member, target);
+            subscriptionsMapper.insert(subscriptions);
+            return subscriptions;
+        } else {
+            //即使已经存在订阅要重新计算订阅开始时间
+            Date now = new Date();
+            subscriptionsList.get(0).setUpdatedAt(now);
+            subscriptionsList.get(0).setCreatedAt(now);
+            renewInfo(true, client, subscriptionsList.get(0), member, target);
+            subscriptionsMapper.updateByPrimaryKeySelective(subscriptionsList.get(0));
+            return subscriptionsList.get(0);
         }
-        return subscriptionsList.get(0);
     }
 
     /**
@@ -114,10 +192,12 @@ public class SubscriptionServiceImpl implements SubscriptionService {
             throw new BackendRuntimeException(SubscriptionConstant.EXCEPTION_MSG_INVALID_TARGET_ID);
         }
         Members members = memberService.getCurrentUser();
+        Integer subscribeType = memberService.judgeSubscribeType(members.getId());
+        members.setSubscriberType(subscribeType);
         //查找用户未支付状态的会员服务 没有则插入
         Subscriptions subscription = findMemberUnPayedSubscription(members, targetType, Integer.parseInt(targetId), payment, client);
         //查找用户有没有没有支付的微信订单,没有则插入(填充用户订单信息)
-        Orders order = orderService.findMemberUnPayedOrders(members.getId(), subscription);
+        Orders order = orderService.findMemberUnPayedOrders(members.getId(), subscription, client);
         SubscriptionVO pojo = new SubscriptionVO();
         BeanUtils.copyProperties(subscription, pojo);
         pojo.setOrder(order);
@@ -268,11 +348,12 @@ public class SubscriptionServiceImpl implements SubscriptionService {
         if(CommonEnum.SubscriptionTypeEnum.SET_PRICING.value().equals(subscriptions.getTargetType())){
             SetPricings setPricings = setPricingService.getById(targetId);
             if(SetPricingModeEnum.member_v2.value().equals(setPricings.getMode())){
+                // 拿到结束时间最晚的一个订阅作为上一个订阅
                 List<Subscriptions> list = getSubscriptionList(subscriptions,members);
                 for (Subscriptions subs : list) {
                     if(lastSub != null){
                         return lastSub;
-                    } else if(!ObjectUtils.isEmpty(subs) && setPricings.getMode().equals(SetPricingModeEnum.free.value())){
+                    } else if(!ObjectUtils.isEmpty(subs) && !setPricings.getMode().equals(SetPricingModeEnum.free.value())){
                         lastSub = subs;
                     }
                 }
@@ -299,7 +380,8 @@ public class SubscriptionServiceImpl implements SubscriptionService {
         SubscriptionsExample example = new SubscriptionsExample();
         example.createCriteria().andMemberIdEqualTo(members.getId())
                 .andStatusEqualTo(SubscriptionStatusEnum.ACTIVED.value()).andTargetTypeEqualTo(sub.getTargetType())
-                .andIdNotEqualTo(sub.getId());
+                .andIdNotEqualTo(sub.getId()).andEndDateGreaterThanOrEqualTo(new Date());
+        example.setOrderByClause("end_date DESC");
         return subscriptionsMapper.selectByExample(example);
     }
 
@@ -312,4 +394,78 @@ public class SubscriptionServiceImpl implements SubscriptionService {
     public Subscriptions getById(String subscriptionId) {
         return subscriptionsMapper.selectByPrimaryKey(subscriptionId);
     }
+
+    @Override
+    public RemindVo remindRenew() {
+        Members currentUser = memberService.getCurrentUser();
+        String memberId = currentUser.getId();
+
+        //查询出mode为0的setPricing且生效的订阅
+        List<Subscriptions> list = setPricingService.selectMode0(memberId);
+        //查出即将过期的订阅
+        Date now = new Date();
+        Date date1 = DateUtils.addDate(now, -7);
+        SubscriptionsExample example = new SubscriptionsExample();
+        example.setOrderByClause("start_date desc");
+        SubscriptionsExample.Criteria criteria = example.createCriteria();
+        List<Integer> statusList = new ArrayList<>();
+        statusList.add(2);
+        statusList.add(3);
+        criteria.andTargetTypeEqualTo("SetPricing").andMemberIdEqualTo(memberId).andEndDateBetween(date1,now).andStatusIn(statusList);
+        List<Subscriptions> subscriptions = subscriptionsMapper.selectByExample(example);
+        RemindVo vo = new RemindVo();
+        if(list.size() == 0 && !CollectionUtils.isEmpty(subscriptions)){
+            Subscriptions expire = subscriptions.get(0);
+            vo.setRemindType("set_pricing");
+            int expireDay = (int) (expire.getEndDate().getTime() - now.getTime()) / 86400000;
+            String remindMsg = "你的会员还有"+expireDay+"天到期,续费享受享7折优惠哦";
+            vo.setRemindMsg(remindMsg);
+            vo.setFreeSubscription(null);
+        }else{
+            List<Subscriptions> list1 = setPricingService.selectPByModeAndMemberId(memberId, "1");
+            if(!CollectionUtils.isEmpty(list1) && list1.size() >= 1){
+                vo.setRemindType("space");
+            }
+        }
+        return vo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = BackendRuntimeException.class)
+    public ExpenseVo expense(ExpenseParam param) {
+        Members currentUser = memberService.getCurrentUser();
+        Integer points = param.getPoints();
+        //参数校验
+        if(points == 0){
+            throw new BackendRuntimeException("扣券不能为零");
+        }
+        int leftPoint = currentUser.getPoints() - points;
+        if(leftPoint < 0){
+            throw new BackendRuntimeException("剩余"+currentUser.getPoints()+"券不够用");
+        }
+        Expenses expenses = new Expenses();
+        expenses.setId(CommonUtils.generateId());
+        expenses.setMemberId(currentUser.getId());
+        expenses.setUniqueKey(param.getUniqueKey());
+        expenses.setUniqueValue(param.getUniqueValue());
+        expenses.setPoints(points);
+        Date now = new Date();
+        expenses.setCreatedAt(now);
+        expenses.setUpdatedAt(now);
+        expensesMapper.insert(expenses);
+        // 真实的扣券行为
+
+        currentUser.setPoints(leftPoint);
+        currentUser.setUpdatedAt(now);
+        memberService.update(currentUser);
+
+        // 返回本次消耗券以及会员剩余券
+        ExpenseVo expenseVo = new ExpenseVo();
+        expenseVo.setMemberPoints(currentUser.getPoints());
+        expenseVo.setPoint(param.getPoints());
+        expenseVo.setUniqueKey(param.getUniqueKey());
+        expenseVo.setUniqueValue(param.getUniqueValue());
+        expenseVo.setCreatedAt(now);
+        return expenseVo;
+    }
 }

+ 9 - 4
backend-core/src/main/java/cn/kdan/pdf/backend/core/service/impl/WXPayServiceImpl.java

@@ -1,6 +1,7 @@
 package cn.kdan.pdf.backend.core.service.impl;
 
 
+import cn.kdan.pdf.backend.core.enums.ClientEnum;
 import cn.kdan.pdf.backend.core.service.WXPayService;
 import cn.kdan.pdf.backend.core.utils.wxpay.MyConfig;
 import cn.kdan.pdf.backend.core.utils.wxpay.WXPay;
@@ -31,21 +32,25 @@ public class WXPayServiceImpl implements WXPayService {
     private MyConfig myWXConfig;
 
     @Override
-    public String unifiedOrder(String subject, String orderNo, Float price) {
+    public Map<String,String> unifiedOrder(String subject, String orderNo, Float price, String client) {
         WXPay wxpay = new WXPay(myWXConfig);
         Map<String, String> data = new HashMap<>();
         data.put("body", subject);
         data.put("out_trade_no", orderNo);
         //data.put("total_fee", String.valueOf(Math.round(price*100)));
-        data.put("total_fee", "1");
+        data.put("total_fee", String.valueOf(price*100));
         //回调地址
         data.put("notify_url", notifyUrl);
         //扫码支付
-        data.put("trade_type", "NATIVE");
+        if(ClientEnum.WEB.value().equals(client)) {
+            data.put("trade_type", "NATIVE");
+        }else {
+            data.put("trade_type", "APP");
+        }
         try {
             Map<String, String> resp = wxpay.unifiedOrder(data);
             if (CommonConstant.CODE_SUCCESS.equals(resp.get(WXPayConstants.RESULT_CODE))) {
-                return resp.get(WXPayConstants.CODE_URL);
+                return resp;
             } else {
                 log.error(resp.get(WXPayConstants.RETURN_MSG));
                 throw new BackendRuntimeException(WXPayConstants.UNIFIEDORDER_ERROR);

+ 81 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/CommonBusinessUtils.java

@@ -0,0 +1,81 @@
+package cn.kdan.pdf.backend.core.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author sfq
+ * @description
+ */
+@Component
+@Slf4j
+public class CommonBusinessUtils {
+
+    /**
+     * 语言(zh、zh-CN、zh-Hans表示汉语,en表示英语)
+     */
+    private final static String ZH = "zh";
+    private final static String ZH_CN = "zh-CN";
+    private final static String ZH_HANS = "zh-Hans";
+    private final static String EN = "en";
+
+    private final static String[] EMAIL_REGEX = {"chuge\\..*@test.com",".*@upburv.com",".*@chacuo.net","111222@qq.com"};
+
+    /**
+     * 判断语言
+     * @param language 语言类型
+     * @return 语言类型
+     */
+    public static String judgeLanguage(String language){
+        if ("".equals(language) || ZH.equals(language) || ZH_CN.equals(language) || ZH_HANS.equals(language)) {
+            language = ZH_CN;
+        } else {
+            language = EN;
+        }
+        return language;
+    }
+
+    /**
+     * 判断是否属于黑名单格式的邮箱,属于黑名单则返回true,不属于则返回false
+     * @param email 邮箱
+     * @return 是否属于黑名单邮箱或邮箱格式
+     */
+    public static boolean verifyBlackEmail(String email){
+        if(StringUtils.isEmpty(email)){
+            return false;
+        }
+        for (int i = 0; i < EMAIL_REGEX.length; i++) {
+            boolean matches = email.matches(EMAIL_REGEX[i]);
+            if(matches){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断文件大小
+     * @param len 文件长度
+     * @param size 限制大小
+     * @param unit 限制单位(B,K,M,G)
+     * @return 是否结果大于
+     */
+    public static boolean checkFileSize(Long len, int size, String unit) {
+        double fileSize = 0;
+        if ("B".equals(unit.toUpperCase())) {
+            fileSize = (double) len;
+        } else if ("K".equals(unit.toUpperCase())) {
+            fileSize = (double) len / 1024;
+        } else if ("M".equals(unit.toUpperCase())) {
+            fileSize = (double) len / 1048576;
+        } else if ("G".equals(unit.toUpperCase())) {
+            fileSize = (double) len / 1073741824;
+        }
+        if (fileSize > size) {
+            return false;
+        }
+        return true;
+    }
+
+}

+ 11 - 10
backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/TencentUtils.java

@@ -47,7 +47,7 @@ public class TencentUtils {
      * @return 返回qq用户信息
      */
     public static Tencent getUserInfo(String accessToken){
-        Tencent tencent = new Tencent();
+        Tencent tencent;
         TencentMe me = me(accessToken);
         if (ObjectUtils.isEmpty(me)) {
             throw new BackendRuntimeException("获取QQ用户权限信息失败");
@@ -56,20 +56,21 @@ public class TencentUtils {
         String openid = me.getOpenid();
         String unionId = me.getUnionId();
         String url = ENDPOINT.replace("CLIENT_ID",clientId).replace("OPENID",openid).replace("ACCESS_TOKEN",accessToken);
+        String resp = "";
         try{
-            String resp = HttpClientUtils.get(url);
+            resp = HttpClientUtils.get(url);
             tencent = JsonUtils.jsonStringToBean(resp, Tencent.class);
-            if(ObjectUtils.isNotEmpty(tencent) && StringUtils.isBlank(tencent.getNickname())){
-                log.error("获取QQ用户信息失败:{},accessToken:{}",resp,accessToken);
-                throw new BackendRuntimeException("获取QQ用户信息失败");
-            }
-            tencent.setAccessToken(accessToken);
-            tencent.setClientId(clientId);
-            tencent.setUnionId(unionId);
-            return tencent;
         }catch (Exception e){
             log.error("获取QQ用户信息失败:{},{}",e,e.getMessage());
+            throw new BackendRuntimeException("获取QQ用户信息失败");
+        }
+        if(ObjectUtils.isNotEmpty(tencent) && StringUtils.isBlank(tencent.getNickname())){
+            log.error("获取QQ用户信息失败:{},accessToken:{}",resp,accessToken);
+            throw new BackendRuntimeException("获取QQ用户信息失败");
         }
+        tencent.setAccessToken(accessToken);
+        tencent.setClientId(clientId);
+        tencent.setUnionId(unionId);
         return tencent;
     }
 

+ 10 - 8
backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/WechatUtils.java

@@ -25,17 +25,19 @@ public class WechatUtils {
     public static Wechat getUserInfo(String openid, String accessToken){
         Wechat wechat = new Wechat();
         String url = ENDPOINT.replace("OPEN_ID",openid).replace("ACCESS_TOKEN",accessToken);
+        String resp = "";
         try {
-            String resp = HttpClientUtils.get(url);
+            resp = HttpClientUtils.get(url);
             wechat = JsonUtils.jsonStringToBean(resp, Wechat.class);
-            if(ObjectUtils.isNotEmpty(wechat)) {
-                if (StringUtils.isEmpty(wechat.getUnionId()) || StringUtils.isEmpty(wechat.getOpenid())) {
-                    log.error("获取微信用户信息失败:{},token:{}", resp, accessToken);
-                    throw new BackendRuntimeException("获取微信用户信息失败");
-                }
-            }
         }catch (Exception e){
-            log.error("获取微信用户信息失败:{},{}",e,e.getMessage());
+            log.error("获取微信用户信息失败:{},token:{}", resp, accessToken);
+            throw new BackendRuntimeException("获取微信用户信息失败");
+        }
+        if(ObjectUtils.isNotEmpty(wechat)) {
+            if (StringUtils.isEmpty(wechat.getUnionId()) || StringUtils.isEmpty(wechat.getOpenid())) {
+                log.error("获取微信用户信息失败:{},token:{}", resp, accessToken);
+                throw new BackendRuntimeException("获取微信用户信息失败");
+            }
         }
         return wechat;
     }

+ 4 - 0
backend-core/src/main/java/cn/kdan/pdf/backend/core/utils/wxpay/WXPayConstants.java

@@ -16,6 +16,10 @@ public class WXPayConstants {
     public static final String RESULT_CODE = "result_code";
 
     public static final String CODE_URL = "code_url";
+    public static final String APP_ID = "appid";
+    public static final String NONCE_STR = "nonce_str";
+    public static final String MCH_ID = "mch_id";
+    public static final String PREPAY_ID = "prepay_id";
 
     public static final String RETURN_MSG = "return_msg";
     public static final String FAIL = "FAIL";

+ 22 - 4
backend-core/src/main/resources/application-local.yml

@@ -33,17 +33,24 @@ security:
         user-info-uri: http://localhost:8999/17pdf-backend-core/user/me
 mob:
   sms:
-    apikey: 36d87b0ca422f
+#    apikey: 36d87b0ca422f
+    apikey: 1cda03938f4bd
     sendUrl: https://webapi.sms.mob.com/sms/sendmsg
     verifyUrl: https://webapi.sms.mob.com/sms/verify
 
 web:
   url: http://localhost:3000/
 
+#wx:
+#  pay:
+#    appId: wx65c8fde4990db757
+#    mchId: 1510572871
+#    partnerKey: a3d45dca15b42197505a3a82ec27df13
+#    notifyUrl: "http://81.68.234.235:8999/17pdf-backend-core/order/syncOrder"
 wx:
   pay:
-    appId: wx65c8fde4990db757
-    mchId: 1510572871
+    appId: wx4036abaaa34316d0
+    mchId: 1481085892
     partnerKey: a3d45dca15b42197505a3a82ec27df13
     notifyUrl: "http://81.68.234.235:8999/17pdf-backend-core/order/syncOrder"
 
@@ -61,7 +68,7 @@ ali:
     publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkM3w1f0kbiLzFderT1bD6tycLHVyeiJSVT2VzMQfbFEDSvag5zpj9j4UgGGm6nTWfrtwN1Z8ytUoeZ33/rUcuxDyUTCYXFNuabRajNaVPIzmx7SZLelytLRUhrtfKjx1XTr7GPFosPxdGInP8UK9uX2Wc517s0UKp2gLpaNyiMk4Pfct2uwZVx1haPdmbyTfMdp3s3Mn5jHvicPlDNmZDYm6OPU5c6NGlVIgz8UR41Y0R9Xou4nhn4+ZrP9agIr+xb5I6/Zj9n3uuVpiyq7mnxva0d5voGAbZR3EYkUxJDpaYcOZBhCogblPf+4NprH0PFLLMXnWY1vevv6ati5PJwIDAQAB
     # 页面跳转同步通知页面
     returnUrl: http://localhost:3000/members/me/expenses
-    setPricingReturnUrl: http://localhost:3000/members/me/expenses
+    setPricingReturnUrl: http://localhost:3000/members/me/vip
     pricingReturnUrl: http://localhost:3000/members/me/points
 #    returnUrl: http://192.168.10.143:8082/members/me/expenses
     # 异步跳转路径
@@ -73,3 +80,14 @@ com:
       address: http://101.132.103.13:8090/server
       projectKey: 17PDF
       secretKey: 17PDF@123
+
+17pdf:
+  oss:
+    bucketName: kdan-account-file
+    endpoint: https://oss-cn-shanghai.aliyuncs.com
+    accessKeyId: LTAIBSxSrO3XuszA
+    accessKeySecret: ylqpMGyA4qpsaobhZ34gJzNZzcnYmT
+    filePrefix: avatars
+    viewUrl: https://kdan-account-file.oss-cn-shanghai.aliyuncs.com/
+    #    bucketName: data-center-mainland-dev
+    #    viewUrl: http://data-center-mainland-dev.oss-cn-shanghai.aliyuncs.com/

+ 1 - 4
backend-core/src/main/resources/application-test-db.properties

@@ -1,7 +1,4 @@
 jdbc.driverClassName=com.mysql.cj.jdbc.Driver
-#jdbc.url=jdbc\:mysql\://139.196.160.101\:3306/17pdf_backend_test?useUnicode\=true&characterEncoding\=UTF-8&useSSL\=false
-#jdbc.username=debian-sys-maint
-#jdbc.password=tRF4SWujyo6rZ4Qm
-jdbc.url=jdbc\:mysql\://81.68.234.235\:33056/17pdf_backend_dev?autoReconnect\=true&&useSSL\=false
+jdbc.url=jdbc\:mysql\://139.196.160.101\:33056/17pdf_backend_test?autoReconnect\=true&&useSSL\=false
 jdbc.username=root
 jdbc.password=root123

File diff ditekan karena terlalu besar
+ 39 - 14
backend-core/src/main/resources/application-test.yml


+ 1 - 1
backend-core/src/main/resources/application.yml

@@ -79,7 +79,7 @@ cors:
   allow-origins: "*"
   allow-max-age: "3600"
 httpMatchers:
-  request: "/login,/logout,/members/resetPassword,/members/checkResetPasswordValid,/oauth/**,/auth/**,/members/register,/order/syncOrder,/order/alipaySyncOrder,/alipayRedirect/callback,/pricing/list,/setPricing/listForVisitor,/mission/saasCallback"
+  request: "/login,/logout,/members/resetPassword,/members/checkResetPasswordValid,/oauth/**,/auth/**,/members/register,/order/syncOrder,/order/alipaySyncOrder,/alipayRedirect/callback,/pricing/list,/setPricing/listForVisitor,/mission/saasCallback,/members/checkExists,/advertisement/list,/members/appResetPassword,/missionFile/getTotalConvertFile"
   web: "/hystrix.stream,/webjars/**,/resources/**,/swagger-ui.html,/swagger-resources/**,/v2/api-docs"
 
 

+ 8 - 7
backend-core/src/main/resources/generatorConfig.xml

@@ -53,12 +53,13 @@
         <!--            <columnOverride column="result" javaType="java.lang.String" jdbcType="VARCHAR" />-->
         <!--        </table>-->
 <!--        <table tableName="missions"/>-->
-        <table tableName="advertisements">
-            <columnOverride column="description" javaType="java.lang.String" jdbcType="VARCHAR" />
-            <columnOverride column="extra_info" javaType="java.lang.String" jdbcType="VARCHAR" />
-        </table>
-        <table tableName="devices"/>
-        <table tableName="locations"/>
-        <table tableName="social_accounts"/>
+<!--        <table tableName="advertisements">-->
+<!--            <columnOverride column="description" javaType="java.lang.String" jdbcType="VARCHAR" />-->
+<!--            <columnOverride column="extra_info" javaType="java.lang.String" jdbcType="VARCHAR" />-->
+<!--        </table>-->
+<!--        <table tableName="devices"/>-->
+<!--        <table tableName="locations"/>-->
+<!--        <table tableName="social_accounts"/>-->
+        <table tableName="expenses"/>
     </context>
 </generatorConfiguration>

+ 289 - 0
backend-core/src/main/resources/sqlmap/ExpensesMapper.xml

@@ -0,0 +1,289 @@
+<?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="cn.kdan.pdf.backend.core.mapper.ExpensesMapper">
+  <resultMap id="BaseResultMap" type="cn.kdan.pdf.backend.core.model.Expenses">
+    <id column="id" jdbcType="VARCHAR" property="id" />
+    <result column="member_id" jdbcType="VARCHAR" property="memberId" />
+    <result column="unique_key" jdbcType="VARCHAR" property="uniqueKey" />
+    <result column="unique_value" jdbcType="VARCHAR" property="uniqueValue" />
+    <result column="points" jdbcType="INTEGER" property="points" />
+    <result column="info" jdbcType="VARCHAR" property="info" />
+    <result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
+    <result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" />
+    <result column="deleted_at" jdbcType="TIMESTAMP" property="deletedAt" />
+  </resultMap>
+  <sql id="Example_Where_Clause">
+    <where>
+      <foreach collection="oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
+        </if>
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Update_By_Example_Where_Clause">
+    <where>
+      <foreach collection="example.oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
+        </if>
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Base_Column_List">
+    id, member_id, unique_key, unique_value, points, info, created_at, updated_at, deleted_at
+  </sql>
+  <select id="selectByExample" parameterType="cn.kdan.pdf.backend.core.model.ExpensesExample" resultMap="BaseResultMap">
+    select
+    <if test="distinct">
+      distinct
+    </if>
+    <include refid="Base_Column_List" />
+    from expenses
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+    <if test="orderByClause != null">
+      order by ${orderByClause}
+    </if>
+  </select>
+  <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from expenses
+    where id = #{id,jdbcType=VARCHAR}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.String">
+    delete from expenses
+    where id = #{id,jdbcType=VARCHAR}
+  </delete>
+  <delete id="deleteByExample" parameterType="cn.kdan.pdf.backend.core.model.ExpensesExample">
+    delete from expenses
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </delete>
+  <insert id="insert" parameterType="cn.kdan.pdf.backend.core.model.Expenses">
+    insert into expenses (id, member_id, unique_key, 
+      unique_value, points, info, 
+      created_at, updated_at, deleted_at
+      )
+    values (#{id,jdbcType=VARCHAR}, #{memberId,jdbcType=VARCHAR}, #{uniqueKey,jdbcType=VARCHAR}, 
+      #{uniqueValue,jdbcType=VARCHAR}, #{points,jdbcType=INTEGER}, #{info,jdbcType=VARCHAR}, 
+      #{createdAt,jdbcType=TIMESTAMP}, #{updatedAt,jdbcType=TIMESTAMP}, #{deletedAt,jdbcType=TIMESTAMP}
+      )
+  </insert>
+  <insert id="insertSelective" parameterType="cn.kdan.pdf.backend.core.model.Expenses">
+    insert into expenses
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        id,
+      </if>
+      <if test="memberId != null">
+        member_id,
+      </if>
+      <if test="uniqueKey != null">
+        unique_key,
+      </if>
+      <if test="uniqueValue != null">
+        unique_value,
+      </if>
+      <if test="points != null">
+        points,
+      </if>
+      <if test="info != null">
+        info,
+      </if>
+      <if test="createdAt != null">
+        created_at,
+      </if>
+      <if test="updatedAt != null">
+        updated_at,
+      </if>
+      <if test="deletedAt != null">
+        deleted_at,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        #{id,jdbcType=VARCHAR},
+      </if>
+      <if test="memberId != null">
+        #{memberId,jdbcType=VARCHAR},
+      </if>
+      <if test="uniqueKey != null">
+        #{uniqueKey,jdbcType=VARCHAR},
+      </if>
+      <if test="uniqueValue != null">
+        #{uniqueValue,jdbcType=VARCHAR},
+      </if>
+      <if test="points != null">
+        #{points,jdbcType=INTEGER},
+      </if>
+      <if test="info != null">
+        #{info,jdbcType=VARCHAR},
+      </if>
+      <if test="createdAt != null">
+        #{createdAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updatedAt != null">
+        #{updatedAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="deletedAt != null">
+        #{deletedAt,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <select id="countByExample" parameterType="cn.kdan.pdf.backend.core.model.ExpensesExample" resultType="java.lang.Long">
+    select count(*) from expenses
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </select>
+  <update id="updateByExampleSelective" parameterType="map">
+    update expenses
+    <set>
+      <if test="record.id != null">
+        id = #{record.id,jdbcType=VARCHAR},
+      </if>
+      <if test="record.memberId != null">
+        member_id = #{record.memberId,jdbcType=VARCHAR},
+      </if>
+      <if test="record.uniqueKey != null">
+        unique_key = #{record.uniqueKey,jdbcType=VARCHAR},
+      </if>
+      <if test="record.uniqueValue != null">
+        unique_value = #{record.uniqueValue,jdbcType=VARCHAR},
+      </if>
+      <if test="record.points != null">
+        points = #{record.points,jdbcType=INTEGER},
+      </if>
+      <if test="record.info != null">
+        info = #{record.info,jdbcType=VARCHAR},
+      </if>
+      <if test="record.createdAt != null">
+        created_at = #{record.createdAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="record.updatedAt != null">
+        updated_at = #{record.updatedAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="record.deletedAt != null">
+        deleted_at = #{record.deletedAt,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByExample" parameterType="map">
+    update expenses
+    set id = #{record.id,jdbcType=VARCHAR},
+      member_id = #{record.memberId,jdbcType=VARCHAR},
+      unique_key = #{record.uniqueKey,jdbcType=VARCHAR},
+      unique_value = #{record.uniqueValue,jdbcType=VARCHAR},
+      points = #{record.points,jdbcType=INTEGER},
+      info = #{record.info,jdbcType=VARCHAR},
+      created_at = #{record.createdAt,jdbcType=TIMESTAMP},
+      updated_at = #{record.updatedAt,jdbcType=TIMESTAMP},
+      deleted_at = #{record.deletedAt,jdbcType=TIMESTAMP}
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByPrimaryKeySelective" parameterType="cn.kdan.pdf.backend.core.model.Expenses">
+    update expenses
+    <set>
+      <if test="memberId != null">
+        member_id = #{memberId,jdbcType=VARCHAR},
+      </if>
+      <if test="uniqueKey != null">
+        unique_key = #{uniqueKey,jdbcType=VARCHAR},
+      </if>
+      <if test="uniqueValue != null">
+        unique_value = #{uniqueValue,jdbcType=VARCHAR},
+      </if>
+      <if test="points != null">
+        points = #{points,jdbcType=INTEGER},
+      </if>
+      <if test="info != null">
+        info = #{info,jdbcType=VARCHAR},
+      </if>
+      <if test="createdAt != null">
+        created_at = #{createdAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updatedAt != null">
+        updated_at = #{updatedAt,jdbcType=TIMESTAMP},
+      </if>
+      <if test="deletedAt != null">
+        deleted_at = #{deletedAt,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=VARCHAR}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="cn.kdan.pdf.backend.core.model.Expenses">
+    update expenses
+    set member_id = #{memberId,jdbcType=VARCHAR},
+      unique_key = #{uniqueKey,jdbcType=VARCHAR},
+      unique_value = #{uniqueValue,jdbcType=VARCHAR},
+      points = #{points,jdbcType=INTEGER},
+      info = #{info,jdbcType=VARCHAR},
+      created_at = #{createdAt,jdbcType=TIMESTAMP},
+      updated_at = #{updatedAt,jdbcType=TIMESTAMP},
+      deleted_at = #{deletedAt,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=VARCHAR}
+  </update>
+  <select id="selectByExampleWithRowbounds" parameterType="cn.kdan.pdf.backend.core.model.ExpensesExample" resultMap="BaseResultMap">
+    select
+    <if test="distinct">
+      distinct
+    </if>
+    <include refid="Base_Column_List" />
+    from expenses
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+    <if test="orderByClause != null">
+      order by ${orderByClause}
+    </if>
+  </select>
+</mapper>

+ 3 - 1
backend-core/src/main/resources/sqlmap/ext/ExtMissionFilesMapper.xml

@@ -32,12 +32,14 @@
         <result column="ocr_code" jdbcType="VARCHAR" property="ocrCode"/>
         <result column="input_type" jdbcType="VARCHAR" property="inputType"/>
         <result column="output_type" jdbcType="VARCHAR" property="outputType"/>
+        <result column="convert_size" jdbcType="INTEGER" property="convertSize"/>
     </resultMap>
 
     <select id="getMissionFileListWithConvertType" resultMap="BaseResultMap">
-        select mf.*, ct.input_type, ct.output_type
+        select mf.*, o.size as convert_size, ct.input_type, ct.output_type
         from mission_files mf
                  left join convert_types ct on ct.id = mf.convert_type_id
+                 left join output_files o on o.mission_file_id = mf.id
         where mf.member_id = #{memberId}
           and mf.deleted_at is null
           and status not in(0,1)

+ 27 - 0
backend-core/src/main/resources/sqlmap/ext/ExtSetPricingsMapper.xml

@@ -25,4 +25,31 @@
         <result column="description2" jdbcType="LONGVARCHAR" property="description2"/>
     </resultMap>
 
+    <select id="selectMode0" resultMap="cn.kdan.pdf.backend.core.mapper.SubscriptionsMapper.BaseResultMap">
+        SELECT
+            a.*
+        FROM
+            subscriptions a
+                LEFT JOIN set_pricings b ON a.target_id = b.id
+        WHERE
+            a.target_type = 'SetPricing'
+          AND a.member_id = #{memberId}
+          AND b.mode != '0'
+          AND a.status = '2'
+          AND a.end_date >= now()
+    </select>
+
+    <select id="selectByModeAndMemberId" resultMap="cn.kdan.pdf.backend.core.mapper.SubscriptionsMapper.BaseResultMap">
+        SELECT
+            a.*
+        FROM
+            subscriptions a
+                LEFT JOIN set_pricings b ON a.target_id = b.id
+        WHERE
+            a.target_type = 'Pricing'
+          AND a.member_id = #{memberId}
+          AND b.mode = #{mode}
+          AND a.status in ('2','3')
+    </select>
+
 </mapper>