Эх сурвалжийг харах

邮件服务+portal构建方式修改

yingp 7 жил өмнө
parent
commit
80686d1454
37 өөрчлөгдсөн 1594 нэмэгдсэн , 63 устгасан
  1. 1 0
      base-servers/gateway-server/src/main/resources/application.yml
  2. 23 0
      base-servers/mail/mail-api/pom.xml
  3. 191 0
      base-servers/mail/mail-api/src/main/java/com/usoftchina/saas/mail/MailBuilder.java
  4. 33 0
      base-servers/mail/mail-api/src/main/java/com/usoftchina/saas/mail/api/MailApi.java
  5. 0 1
      base-servers/mail/mail-dto/pom.xml
  6. 0 11
      base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/MailDto.java
  7. 57 0
      base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/MailLogDTO.java
  8. 89 0
      base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/TemplateMailMessage.java
  9. 11 25
      base-servers/mail/mail-server/pom.xml
  10. 6 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/MailApplication.java
  11. 88 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/controller/MailController.java
  12. 26 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/mapper/MailLogMapper.java
  13. 40 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/mapper/MailTemplateMapper.java
  14. 110 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/po/MailLog.java
  15. 38 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/po/MailTemplate.java
  16. 29 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/MailLogService.java
  17. 42 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/MailTemplateService.java
  18. 39 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/impl/MailLogServiceImpl.java
  19. 38 0
      base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/impl/MailTemplateServiceImpl.java
  20. 85 0
      base-servers/mail/mail-server/src/main/resources/application.yml
  21. 12 0
      base-servers/mail/mail-server/src/main/resources/config/application-docker-dev.yml
  22. 10 0
      base-servers/mail/mail-server/src/main/resources/config/application-docker.yml
  23. 0 0
      base-servers/mail/mail-server/src/main/resources/i18n/messages_en_US.properties
  24. 0 0
      base-servers/mail/mail-server/src/main/resources/i18n/messages_zh_CN.properties
  25. 113 0
      base-servers/mail/mail-server/src/main/resources/logback-spring.xml
  26. 31 0
      base-servers/mail/mail-server/src/main/resources/mapper/MailLogMapper.xml
  27. 29 0
      base-servers/mail/mail-server/src/main/resources/mapper/MailTemplateMapper.xml
  28. 0 1
      base-servers/mail/pom.xml
  29. 7 3
      frontend/saas-portal-web/README.md
  30. 0 5
      frontend/saas-portal-web/config/dev.env.js
  31. 15 0
      frontend/saas-portal-web/config/env.js
  32. 0 5
      frontend/saas-portal-web/config/prod.env.js
  33. 4 1
      frontend/saas-portal-web/package.json
  34. 23 8
      frontend/saas-portal-web/webpack.conf.js
  35. 47 0
      frontend/saas-portal-web/webpack.dev.conf.js
  36. 337 3
      frontend/saas-portal-web/yarn.lock
  37. 20 0
      script/mysql/init/mail.sql

+ 1 - 0
base-servers/gateway-server/src/main/resources/application.yml

@@ -177,3 +177,4 @@ auth:
     - /api/auth/authorize
     - /api/account/account/register
     - /api/account/company/register
+    - /api/auth/info

+ 23 - 0
base-servers/mail/mail-api/pom.xml

@@ -11,4 +11,27 @@
 
     <artifactId>mail-api</artifactId>
     <description>mail api</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>mail-dto</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+    </dependencies>
 </project>

+ 191 - 0
base-servers/mail/mail-api/src/main/java/com/usoftchina/saas/mail/MailBuilder.java

@@ -0,0 +1,191 @@
+package com.usoftchina.saas.mail;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.mail.api.MailApi;
+import com.usoftchina.saas.mail.dto.TemplateMailMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.SimpleMailMessage;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public abstract class MailBuilder {
+
+    private Logger logger = LoggerFactory.getLogger(MailBuilder.class);
+
+    protected String from;
+    protected String[] to;
+    protected String[] cc;
+    protected String[] bcc;
+
+    /**
+     * 发送人
+     *
+     * @param from
+     * @return
+     */
+    public MailBuilder from(String from) {
+        this.from = from;
+        return this;
+    }
+
+    /**
+     * 接收人
+     *
+     * @param to
+     * @return
+     */
+    public MailBuilder to(String... to) {
+        this.to = to;
+        return this;
+    }
+
+    /**
+     * 接收人
+     *
+     * @param to
+     * @return
+     */
+    public MailBuilder to(List<String> to) {
+        this.to = to.toArray(new String[]{});
+        return this;
+    }
+
+    /**
+     * @param cc
+     * @return
+     */
+    public MailBuilder cc(String... cc) {
+        this.cc = cc;
+        return this;
+    }
+
+    /**
+     * @param cc
+     * @return
+     */
+    public MailBuilder cc(List<String> cc) {
+        this.cc = cc.toArray(new String[]{});
+        return this;
+    }
+
+    /**
+     * @param bcc
+     * @return
+     */
+    public MailBuilder bcc(String... bcc) {
+        this.bcc = bcc;
+        return this;
+    }
+
+    /**
+     * @param bcc
+     * @return
+     */
+    public MailBuilder bcc(List<String> bcc) {
+        this.bcc = bcc.toArray(new String[]{});
+        return this;
+    }
+
+    /**
+     * 发送邮件
+     *
+     * @param api
+     * @return
+     */
+    protected abstract Result send(MailApi api);
+
+    /**
+     * 发送邮件
+     */
+    public void send() {
+        MailApi api = SpringContextHolder.getBean(MailApi.class);
+        Result result = send(api);
+        if (!result.isSuccess()) {
+            logger.error("failed to send mail, " + result.getMessage());
+            throw new BizException(result.getCode(), result.getMessage());
+        }
+    }
+
+    public static SimpleMailBuilder simple() {
+        return new SimpleMailBuilder();
+    }
+
+    public static TemplateMailBuilder template(String templateId) {
+        return new TemplateMailBuilder(templateId);
+    }
+
+    private static class SimpleMailBuilder extends MailBuilder{
+        private String subject;
+        private String text;
+
+        /**
+         * 邮件主题
+         *
+         * @param subject
+         * @return
+         */
+        public MailBuilder subject(String subject) {
+            this.subject = subject;
+            return this;
+        }
+
+        /**
+         * 邮件内容
+         *
+         * @param text
+         * @return
+         */
+        public MailBuilder text(String text) {
+            this.text = text;
+            return this;
+        }
+
+        @Override
+        protected Result send(MailApi api) {
+            SimpleMailMessage message = new SimpleMailMessage();
+            message.setFrom(from);
+            message.setTo(to);
+            message.setCc(cc);
+            message.setBcc(bcc);
+            message.setSubject(subject);
+            message.setText(text);
+            return api.send(message);
+        }
+    }
+
+    private static class TemplateMailBuilder extends MailBuilder{
+        private String templateId;
+        private Map<String, Object> metadata;
+
+        public TemplateMailBuilder(String templateId) {
+            this.templateId = templateId;
+        }
+
+        public TemplateMailBuilder metadata(Map<String, Object> metadata) {
+            this.metadata = metadata;
+            return this;
+        }
+
+        public TemplateMailBuilder set(String key, String value) {
+            if (null == metadata) {
+                metadata = new HashMap<>(1);
+            }
+            metadata.put(key, value);
+            return this;
+        }
+
+        @Override
+        protected Result send(MailApi api) {
+            return api.sendTemplate(new TemplateMailMessage(templateId, to, cc, bcc, metadata));
+        }
+    }
+}

+ 33 - 0
base-servers/mail/mail-api/src/main/java/com/usoftchina/saas/mail/api/MailApi.java

@@ -0,0 +1,33 @@
+package com.usoftchina.saas.mail.api;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.mail.dto.TemplateMailMessage;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.web.bind.annotation.PostMapping;
+
+/**
+ * 邮件接口
+ *
+ * @author yingp
+ * @date 2018/11/13
+ */
+@FeignClient(name = "mail-server")
+public interface MailApi {
+    /**
+     * 发送邮件
+     *
+     * @param message
+     * @return
+     */
+    @PostMapping(value = "/send")
+    Result send(SimpleMailMessage message);
+    /**
+     * 指定模板发送邮件
+     *
+     * @param message
+     * @return
+     */
+    @PostMapping(value = "/template/send")
+    Result sendTemplate(TemplateMailMessage message);
+}

+ 0 - 1
base-servers/mail/mail-dto/pom.xml

@@ -12,5 +12,4 @@
     <artifactId>mail-dto</artifactId>
     <description>mail data transfer object</description>
 
-
 </project>

+ 0 - 11
base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/MailDto.java

@@ -1,11 +0,0 @@
-package com.usoftchina.saas.mail.dto;
-
-import java.io.Serializable;
-
-/**
- * @author yingp
- * @date 2018/10/3
- */
-public class MailDto implements Serializable {
-
-}

+ 57 - 0
base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/MailLogDTO.java

@@ -0,0 +1,57 @@
+package com.usoftchina.saas.mail.dto;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public class MailLogDTO implements Serializable{
+    private String subject;
+    private String message;
+    private String recipients;
+    private Date createTime;
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getRecipients() {
+        return recipients;
+    }
+
+    public void setRecipients(String recipients) {
+        this.recipients = recipients;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "MailLogDTO{" +
+                "subject='" + subject + '\'' +
+                ", message='" + message + '\'' +
+                ", recipients='" + recipients + '\'' +
+                ", createTime=" + createTime +
+                '}';
+    }
+}

+ 89 - 0
base-servers/mail/mail-dto/src/main/java/com/usoftchina/saas/mail/dto/TemplateMailMessage.java

@@ -0,0 +1,89 @@
+package com.usoftchina.saas.mail.dto;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public class TemplateMailMessage implements Serializable{
+    private String templateId;
+    private String from;
+    private String[] to;
+    private String[] cc;
+    private String[] bcc;
+    private Map<String, Object> metadata;
+
+    public TemplateMailMessage() {
+    }
+
+    public TemplateMailMessage(String templateId, String from, String[] to, String[] cc, String[] bcc, Map<String, Object> metadata) {
+        this.templateId = templateId;
+        this.from = from;
+        this.to = to;
+        this.cc = cc;
+        this.bcc = bcc;
+        this.metadata = metadata;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    public void setFrom(String from) {
+        this.from = from;
+    }
+
+    public String[] getTo() {
+        return to;
+    }
+
+    public void setTo(String[] to) {
+        this.to = to;
+    }
+
+    public String[] getCc() {
+        return cc;
+    }
+
+    public void setCc(String[] cc) {
+        this.cc = cc;
+    }
+
+    public String[] getBcc() {
+        return bcc;
+    }
+
+    public void setBcc(String[] bcc) {
+        this.bcc = bcc;
+    }
+
+    public String getTemplateId() {
+        return templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public Map<String, Object> getMetadata() {
+        return metadata;
+    }
+
+    public void setMetadata(Map<String, Object> metadata) {
+        this.metadata = metadata;
+    }
+
+    @Override
+    public String toString() {
+        return "TemplateMailMessage{" +
+                "templateId='" + templateId + '\'' +
+                ", from='" + from + '\'' +
+                ", to=" + Arrays.toString(to) +
+                ", cc=" + Arrays.toString(cc) +
+                ", bcc=" + Arrays.toString(bcc) +
+                ", metadata=" + metadata +
+                '}';
+    }
+}

+ 11 - 25
base-servers/mail/mail-server/pom.xml

@@ -19,7 +19,7 @@
         </dependency>
         <dependency>
             <groupId>com.usoftchina.saas</groupId>
-            <artifactId>core</artifactId>
+            <artifactId>server-starter</artifactId>
         </dependency>
         <dependency>
             <groupId>com.usoftchina.saas</groupId>
@@ -27,30 +27,7 @@
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.hibernate</groupId>
-                    <artifactId>hibernate-validator</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.apache.tomcat.embed</groupId>
-                    <artifactId>tomcat-embed-websocket</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <!-- management -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-security</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+            <artifactId>spring-boot-starter-mail</artifactId>
         </dependency>
         <!-- db -->
         <dependency>
@@ -61,6 +38,10 @@
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
         <!-- api doc -->
         <dependency>
             <groupId>io.springfox</groupId>
@@ -70,6 +51,11 @@
             <groupId>io.springfox</groupId>
             <artifactId>springfox-swagger2</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 6 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/MailApplication.java

@@ -1,8 +1,11 @@
 package com.usoftchina.saas.mail;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 /**
  * @author yingp
@@ -10,6 +13,9 @@ import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
  */
 @SpringBootApplication
 @EnableEurekaClient
+@EnableAuthClient
+@MapperScan
+@EnableTransactionManagement
 public class MailApplication {
     public static void main(String[] args) {
         SpringApplication.run(MailApplication.class, args);

+ 88 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/controller/MailController.java

@@ -0,0 +1,88 @@
+package com.usoftchina.saas.mail.controller;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.mail.dto.TemplateMailMessage;
+import com.usoftchina.saas.mail.po.MailLog;
+import com.usoftchina.saas.mail.po.MailTemplate;
+import com.usoftchina.saas.mail.service.MailLogService;
+import com.usoftchina.saas.mail.service.MailTemplateService;
+import freemarker.template.Template;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+@RestController
+@RequestMapping
+public class MailController {
+
+    @Autowired
+    private MailTemplateService mailTemplateService;
+
+    @Autowired
+    private MailLogService mailLogService;
+
+    @Autowired
+    private JavaMailSender javaMailSender;
+
+    /**
+     * 发送邮件
+     *
+     * @param message
+     * @return
+     */
+    @PostMapping(value = "/send")
+    public Result send(SimpleMailMessage message) {
+        javaMailSender.send(message);
+        mailLogService.save(new MailLog(message));
+        return Result.success();
+    }
+
+    /**
+     * 指定模板发送邮件
+     *
+     * @param message
+     * @return
+     */
+    @PostMapping(value = "/template/send")
+    public Result sendTemplate(TemplateMailMessage message) throws Exception{
+        SimpleMailMessage mailMessage = getMessageByTemplate(message);
+        javaMailSender.send(mailMessage);
+        MailLog log = new MailLog(mailMessage);
+        log.setTemplateId(message.getTemplateId());
+        mailLogService.save(log);
+        return Result.success();
+    }
+
+    /**
+     * freemarker模板处理
+     *
+     * @param message
+     * @return
+     * @throws Exception
+     */
+    private SimpleMailMessage getMessageByTemplate(TemplateMailMessage message) throws Exception{
+        MailTemplate mailTemplate = mailTemplateService.findByPrimaryKey(message.getTemplateId());
+        Template template = new Template(mailTemplate.getId(),
+                new StringReader(mailTemplate.getText()), null);
+        StringWriter text = new StringWriter();
+        template.process(message.getMetadata(), text);
+        SimpleMailMessage mailMessage = new SimpleMailMessage();
+        mailMessage.setBcc(message.getBcc());
+        mailMessage.setCc(message.getCc());
+        mailMessage.setTo(message.getTo());
+        mailMessage.setFrom(message.getFrom());
+        mailMessage.setSubject(mailTemplate.getSubject());
+        mailMessage.setText(text.toString());
+        return mailMessage;
+    }
+}

+ 26 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/mapper/MailLogMapper.java

@@ -0,0 +1,26 @@
+package com.usoftchina.saas.mail.mapper;
+
+import com.usoftchina.saas.mail.po.MailLog;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public interface MailLogMapper {
+    /**
+     * 新增
+     *
+      * @param log
+     * @return
+     */
+    int insert(MailLog log);
+
+    /**
+     * 查找
+     *
+     * @return
+     */
+    List<MailLog> selectAll();
+}

+ 40 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/mapper/MailTemplateMapper.java

@@ -0,0 +1,40 @@
+package com.usoftchina.saas.mail.mapper;
+
+import com.usoftchina.saas.mail.po.MailTemplate;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public interface MailTemplateMapper {
+    /**
+     * 新增
+     *
+     * @param template
+     * @return
+     */
+    int insert(MailTemplate template);
+
+    /**
+     * 更新
+     * @param template
+     * @return
+     */
+    int updateByPrimaryKey(MailTemplate template);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    int deleteByPrimaryKey(@Param("id") String id);
+    /**
+     * 查询
+     *
+     * @param id
+     * @return
+     */
+    MailTemplate selectByPrimaryKey(@Param("id") String id);
+}

+ 110 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/po/MailLog.java

@@ -0,0 +1,110 @@
+package com.usoftchina.saas.mail.po;
+
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.mail.SimpleMailMessage;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public class MailLog implements Serializable{
+    private Long id;
+    private String templateId;
+    private String subject;
+    private String text;
+    private String from;
+    private String to;
+    private Long companyId;
+    private Long creatorId;
+    private Date createTime;
+
+    public MailLog() {
+        this.companyId = BaseContextHolder.getCompanyId();
+        this.creatorId = BaseContextHolder.getUserId();
+        this.createTime = new Date();
+    }
+
+    public MailLog(SimpleMailMessage message) {
+        this();
+        this.from = message.getFrom();
+        this.to = StringUtils.arrayToCommaDelimitedString(message.getTo());
+        this.subject = message.getSubject();
+        this.text = message.getText();
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTemplateId() {
+        return templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    public void setFrom(String from) {
+        this.from = from;
+    }
+
+    public String getTo() {
+        return to;
+    }
+
+    public void setTo(String to) {
+        this.to = to;
+    }
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}

+ 38 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/po/MailTemplate.java

@@ -0,0 +1,38 @@
+package com.usoftchina.saas.mail.po;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public class MailTemplate implements Serializable{
+
+    private String id;
+    private String subject;
+    private String text;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+}

+ 29 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/MailLogService.java

@@ -0,0 +1,29 @@
+package com.usoftchina.saas.mail.service;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.mail.dto.MailLogDTO;
+import com.usoftchina.saas.mail.po.MailLog;
+import com.usoftchina.saas.page.PageRequest;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public interface MailLogService {
+
+    /**
+     * 保存日志
+     *
+     * @param log
+     * @return
+     */
+    boolean save(MailLog log);
+
+    /**
+     * 分页查找日志
+     *
+     * @param page
+     * @return
+     */
+    PageInfo<MailLogDTO> findPage(PageRequest page);
+}

+ 42 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/MailTemplateService.java

@@ -0,0 +1,42 @@
+package com.usoftchina.saas.mail.service;
+
+import com.usoftchina.saas.mail.po.MailTemplate;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+public interface MailTemplateService {
+
+    /**
+     * 新增
+     *
+     * @param template
+     * @return
+     */
+    boolean save(MailTemplate template);
+
+    /**
+     * 更新
+     *
+     * @param template
+     * @return
+     */
+    boolean updateByPrimaryKey(MailTemplate template);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(String id);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    MailTemplate findByPrimaryKey(String id);
+}

+ 39 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/impl/MailLogServiceImpl.java

@@ -0,0 +1,39 @@
+package com.usoftchina.saas.mail.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.mail.dto.MailLogDTO;
+import com.usoftchina.saas.mail.mapper.MailLogMapper;
+import com.usoftchina.saas.mail.po.MailLog;
+import com.usoftchina.saas.mail.service.MailLogService;
+import com.usoftchina.saas.page.PageRequest;
+import com.usoftchina.saas.utils.BeanMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+@Service
+public class MailLogServiceImpl implements MailLogService{
+
+    @Autowired
+    private MailLogMapper mailLogMapper;
+
+    @Override
+    @Async
+    public boolean save(MailLog log) {
+        return mailLogMapper.insert(log) > 0;
+    }
+
+    @Override
+    public PageInfo<MailLogDTO> findPage(PageRequest page) {
+        PageHelper.startPage(page.getNumber(), page.getSize());
+        List<MailLog> logs = mailLogMapper.selectAll();
+        return new PageInfo<>(BeanMapper.mapList(logs, MailLogDTO.class));
+    }
+}

+ 38 - 0
base-servers/mail/mail-server/src/main/java/com/usoftchina/saas/mail/service/impl/MailTemplateServiceImpl.java

@@ -0,0 +1,38 @@
+package com.usoftchina.saas.mail.service.impl;
+
+import com.usoftchina.saas.mail.mapper.MailTemplateMapper;
+import com.usoftchina.saas.mail.po.MailTemplate;
+import com.usoftchina.saas.mail.service.MailTemplateService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author yingp
+ * @date 2018/11/13
+ */
+@Service
+public class MailTemplateServiceImpl implements MailTemplateService{
+
+    @Autowired
+    private MailTemplateMapper mailTemplateMapper;
+
+    @Override
+    public boolean save(MailTemplate template) {
+        return mailTemplateMapper.insert(template) > 0;
+    }
+
+    @Override
+    public boolean updateByPrimaryKey(MailTemplate template) {
+        return mailTemplateMapper.updateByPrimaryKey(template) > 0;
+    }
+
+    @Override
+    public boolean removeByPrimaryKey(String id) {
+        return mailTemplateMapper.deleteByPrimaryKey(id) > 0;
+    }
+
+    @Override
+    public MailTemplate findByPrimaryKey(String id) {
+        return mailTemplateMapper.selectByPrimaryKey(id);
+    }
+}

+ 85 - 0
base-servers/mail/mail-server/src/main/resources/application.yml

@@ -0,0 +1,85 @@
+spring:
+  application:
+    name: mail-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  rabbitmq:
+    host: 192.168.0.176
+    port: 5672
+    virtual-host: dev
+    username: saas
+    password: select123***
+  zipkin:
+    sender:
+      type: rabbit
+    locator:
+      discovery:
+        enabled: true
+  sleuth:
+    sampler:
+      probability: 1.0
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://192.168.253.12:3306/saas_mail?characterEncoding=utf-8&useSSL=false
+    username: root
+    password: select111***
+    hikari:
+      minimum-idle: 5
+      maximum-pool-size: 50
+      idle-timeout: 30000
+      max-lifetime: 1800000
+      connection-timeout: 30000
+  messages:
+    basename: i18n/messages
+  redis:
+    host: 192.168.253.12
+    port: 6379
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  mail:
+    host: smtp.mxhichina.com
+    username: service@ubtob.com
+    password: Aaabbb111
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8510/eureka/
+server:
+  port: 8660
+  tomcat:
+    uri-encoding: UTF-8
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: always
+    shutdown:
+      enabled: true
+    restart:
+      enabled: true
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+mybatis:
+  type-aliases-package: com.usoftchina.saas.mail.po
+  mapper-locations: classpath:mapper/*.xml
+auth:
+  public-key: auth/pub.key

+ 12 - 0
base-servers/mail/mail-server/src/main/resources/config/application-docker-dev.yml

@@ -0,0 +1,12 @@
+eureka:
+  instance:
+    hostname: saas-mail-server-dev
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-dev:8510/eureka/
+spring:
+  rabbitmq:
+    virtual-host: dev
+server:
+  port: 8670

+ 10 - 0
base-servers/mail/mail-server/src/main/resources/config/application-docker.yml

@@ -0,0 +1,10 @@
+eureka:
+  instance:
+    hostname: saas-mail-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server:8500/eureka/
+spring:
+  rabbitmq:
+    virtual-host: docker

+ 0 - 0
base-servers/mail/mail-server/src/main/resources/i18n/messages_en_US.properties


+ 0 - 0
base-servers/mail/mail-server/src/main/resources/i18n/messages_zh_CN.properties


+ 113 - 0
base-servers/mail/mail-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml" />
+    <jmxConfigurator/>
+
+    <!--
+    %m
+    输出代码中指定的消息
+    %p
+    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
+    %r
+    输出自应用启动到输出该log信息耗费的毫秒数
+    %c
+    输出所属的类目,通常就是所在类的全名
+    %t
+    输出产生该日志事件的线程名
+    %n
+    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
+    %d
+    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
+    输出类似:2002年10月18日 22:10:28,921
+    %l
+    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
+    -->
+
+    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/saas/mail-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="mail-server"/>
+    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
+    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
+    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
+    <springProperty scope="context" name="log.destination" source="logging.destination" defaultValue="192.168.253.3:5000"/>
+
+    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
+
+    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${log.level.console}</level>
+        </filter>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/root.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
+            <maxFileSize>128MB</maxFileSize>
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- Appender to log in a JSON format -->
+    <appender name="JSON_APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+        <destination>${log.destination}</destination>
+        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
+            <providers>
+                <pattern>
+                    <pattern>
+                        {
+                        "severity": "%level",
+                        "service": "${spring.application.name:-}",
+                        "trace": "%X{X-B3-TraceId:-}",
+                        "span": "%X{X-B3-SpanId:-}",
+                        "parent": "%X{X-B3-ParentSpanId:-}",
+                        "exportable": "%X{X-Span-Export:-}",
+                        "pid": "${PID:-}",
+                        "thread": "%thread",
+                        "class": "%logger{40}",
+                        "rest": "%message"
+                        }
+                    </pattern>
+                </pattern>
+            </providers>
+        </encoder>
+    </appender>
+
+    <logger name="org.springframework" level="INFO"/>
+    <logger name="com.usoftchina.saas" level="INFO"/>
+
+    <springProfile name="dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="test">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="ROOT_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.saas" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+</configuration>

+ 31 - 0
base-servers/mail/mail-server/src/main/resources/mapper/MailLogMapper.xml

@@ -0,0 +1,31 @@
+<?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="com.usoftchina.saas.mail.mapper.MailLogMapper">
+
+    <insert id="insert" parameterType="com.usoftchina.saas.mail.po.MailLog"
+            useGeneratedKeys="true" keyProperty="id">
+        insert into m_log(template_id,subject,text,to,company_id,creator_id,create_time)
+        values (#{templateId,jdbcType=VARCHAR},#{subject,jdbcType=VARCHAR},#{text,jdbcType=VARCHAR},
+        #{from,jdbcType=VARCHAR},#{to,jdbcType=VARCHAR},#{companyId,jdbcType=BIGINT},
+        #{creatorId,jdbcType=BIGINT},#{createTime,jdbcType=TIMESTAMP})
+    </insert>
+
+    <resultMap id="BaseResultMap" type="com.usoftchina.saas.mail.po.MailLog">
+        <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="template_id" jdbcType="BIGINT" property="templateId"/>
+        <result column="subject" jdbcType="VARCHAR" property="subject"/>
+        <result column="text" jdbcType="VARCHAR" property="text"/>
+        <result column="from" jdbcType="VARCHAR" property="from"/>
+        <result column="to" jdbcType="VARCHAR" property="to"/>
+        <result column="company_id" jdbcType="INTEGER" property="companyId"/>
+        <result column="creator_id" jdbcType="BIGINT" property="creatorId"/>
+        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
+    </resultMap>
+    <sql id="baseColumns">
+        id,template_id,subject,text,from,to,company_id,create_time
+    </sql>
+
+    <select id="selectAll" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from m_log order by create_time desc
+    </select>
+</mapper>

+ 29 - 0
base-servers/mail/mail-server/src/main/resources/mapper/MailTemplateMapper.xml

@@ -0,0 +1,29 @@
+<?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="com.usoftchina.saas.mail.mapper.MailTemplateMapper">
+
+    <insert id="insert" parameterType="com.usoftchina.saas.mail.po.MailTemplate">
+        insert into `m_template`(`id`,`subject`,`text`)
+        values (#{id,jdbcType=VARCHAR},#{subject,jdbcType=VARCHAR},#{text,jdbcType=VARCHAR})
+    </insert>
+    <update id="updateByPrimaryKey" parameterType="com.usoftchina.saas.mail.po.MailTemplate">
+        update `m_template` set `subject`=#{subject,jdbcType=VARCHAR},`text`=#{text,jdbcType=VARCHAR}
+        where `id`=#{id,jdbcType=VARCHAR}
+    </update>
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.String">
+        delete from `m_template` where `id`=#{id}
+    </delete>
+
+    <resultMap id="BaseResultMap" type="com.usoftchina.saas.mail.po.MailTemplate">
+        <id column="id" jdbcType="VARCHAR" property="id"/>
+        <result column="subject" jdbcType="VARCHAR" property="subject"/>
+        <result column="text" jdbcType="VARCHAR" property="text"/>
+    </resultMap>
+    <sql id="baseColumns">
+        `id`,`subject`,`text`
+    </sql>
+
+    <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from `m_template` where `id`=#{id}
+    </select>
+</mapper>

+ 0 - 1
base-servers/mail/pom.xml

@@ -18,5 +18,4 @@
         <module>mail-dto</module>
     </modules>
 
-
 </project>

+ 7 - 3
frontend/saas-portal-web/README.md

@@ -7,9 +7,13 @@ yarn
 # 或者
 npm install --registry=https://registry.npm.taobao.org
 
-# Serve at 127.0.0.1
+# Serve at http://127.0.0.1
 npm run dev
 
-# Build for production with minification
-npm run build
+# Build for development
+
+npm run dev-build
+
+# Build for production
+npm run prod-build
 ```

+ 0 - 5
frontend/saas-portal-web/config/dev.env.js

@@ -1,5 +0,0 @@
-'use strict'
-module.exports = {
-  NODE_ENV: '"development"',
-  BASE_API: '"http://192.168.0.181:8560"',
-}

+ 15 - 0
frontend/saas-portal-web/config/env.js

@@ -0,0 +1,15 @@
+if (process.env.NODE_ENV == 'production') {
+    window.env = {
+        profile: 'production',
+        server: {
+            baseUrl: 'http://192.168.0.181:8560'
+        }
+    }
+} else {
+    window.env = {
+        profile: 'development',
+        server: {
+            baseUrl: 'http://192.168.0.181:8560'
+        }
+    }
+}

+ 0 - 5
frontend/saas-portal-web/config/prod.env.js

@@ -1,5 +0,0 @@
-'use strict'
-module.exports = {
-  NODE_ENV: '"production"',
-  BASE_API: '"http://192.168.0.181:8560"',
-}

+ 4 - 1
frontend/saas-portal-web/package.json

@@ -4,7 +4,7 @@
   "description": "saas portal",
   "main": "index.js",
   "scripts": {
-    "dev": "webpack-dev-server --inline --progress --config ./webpack.conf.js",
+    "dev": "webpack-dev-server --mode development --inline --progress --config ./webpack.dev.conf.js",
     "start": "npm run dev",
     "build": "webpack --mode production --config ./webpack.conf.js"
   },
@@ -14,6 +14,9 @@
   "author": "yingp@usoftchina.com",
   "license": "ISC",
   "devDependencies": {
+    "clean-webpack-plugin": "^1.0.0",
+    "copy-webpack-plugin": "^4.6.0",
+    "html-webpack-plugin": "^3.2.0",
     "webpack": "^4.25.1",
     "webpack-cli": "^3.1.2",
     "webpack-dev-server": "^3.1.10"

+ 23 - 8
frontend/saas-portal-web/webpack.conf.js

@@ -1,12 +1,27 @@
 const path = require('path')
+const cleanWebpackPlugin = require('clean-webpack-plugin')
+const copyWebpackPlugin = require('copy-webpack-plugin')
+const htmlWebpackPlugin = require('html-webpack-plugin')
 
 module.exports = {
-    devServer: {
-        clientLogLevel: 'warning',
-        quiet: true,
-        open: true,
-        contentBase: path.join(__dirname, "src"),
-        port: 80,
-        host: '127.0.0.1'
-    }
+    entry: {
+        env: './config/env.js'
+    },
+    output: {
+		path: path.resolve(__dirname, 'dist'),
+		filename: 'js/[name].js'
+    },
+    plugins: [
+        new cleanWebpackPlugin(["dist"]),
+		new htmlWebpackPlugin({
+			filename: 'index.html',
+			template: './src/index.html',
+			inject: 'head'
+        }),
+        new copyWebpackPlugin([{
+            from: path.resolve(__dirname, 'src'),
+            to: path.resolve(__dirname, 'dist'),
+            ignore: ["index.html", "js/env.js"]
+        }])
+    ]
 }

+ 47 - 0
frontend/saas-portal-web/webpack.dev.conf.js

@@ -0,0 +1,47 @@
+const path = require('path')
+const webpack = require('webpack')
+const copyWebpackPlugin = require('copy-webpack-plugin')
+const htmlWebpackPlugin = require('html-webpack-plugin')
+
+module.exports = {
+    entry: {
+        env: './config/env.js'
+    },
+    output: {
+		path: path.resolve(__dirname, 'dist'),
+		filename: 'js/[name].js'
+    },
+    module: {
+        rules: [{
+            test: /\.css$/,
+            use: [
+                { loader: 'style-loader' },
+                {
+                    loader: 'css-loader',
+                    options: { modules: true}
+                }
+            ]
+        }]
+    },
+    plugins: [
+		new htmlWebpackPlugin({
+			filename: 'index.html',
+			template: './src/index.html',
+			inject: 'head'
+        }),
+        new copyWebpackPlugin([{
+            from: path.resolve(__dirname, 'src'),
+            to: path.resolve(__dirname, 'dist'),
+            ignore: ["index.html", "js/env.js"]
+        }]),
+        new webpack.HotModuleReplacementPlugin()
+    ],
+    devServer: {
+        clientLogLevel: 'warning',
+        quiet: true,
+        open: true,
+        contentBase: path.join(__dirname, "dist"),
+        port: 80,
+        host: '127.0.0.1'
+    }
+}

+ 337 - 3
frontend/saas-portal-web/yarn.lock

@@ -247,6 +247,10 @@ array-unique@^0.3.2:
   version "0.3.2"
   resolved "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
 
+arrify@^1.0.1:
+  version "1.0.1"
+  resolved "http://registry.npm.taobao.org/arrify/download/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
 asn1.js@^4.0.0:
   version "4.10.1"
   resolved "http://registry.npm.taobao.org/asn1.js/download/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
@@ -343,6 +347,10 @@ bonjour@^3.5.0:
     multicast-dns "^6.0.1"
     multicast-dns-service-types "^1.1.0"
 
+boolbase@~1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+
 brace-expansion@^1.1.7:
   version "1.1.11"
   resolved "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -482,6 +490,13 @@ cache-base@^1.0.1:
     union-value "^1.0.0"
     unset-value "^1.0.0"
 
+camel-case@3.0.x:
+  version "3.0.0"
+  resolved "http://registry.npm.taobao.org/camel-case/download/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
 camelcase@^4.1.0:
   version "4.1.0"
   resolved "http://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -539,6 +554,18 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
+clean-css@4.2.x:
+  version "4.2.1"
+  resolved "http://registry.npm.taobao.org/clean-css/download/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+  dependencies:
+    source-map "~0.6.0"
+
+clean-webpack-plugin@^1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.taobao.org/clean-webpack-plugin/download/clean-webpack-plugin-1.0.0.tgz#f184b9c26d12983d639828e0548ae2080e84b6a7"
+  dependencies:
+    rimraf "^2.6.1"
+
 cliui@^4.0.0:
   version "4.1.0"
   resolved "http://registry.npm.taobao.org/cliui/download/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
@@ -568,6 +595,10 @@ color-name@1.1.3:
   version "1.1.3"
   resolved "http://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
 
+commander@2.17.x, commander@~2.17.1:
+  version "2.17.1"
+  resolved "http://registry.npm.taobao.org/commander/download/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+
 commander@~2.13.0:
   version "2.13.0"
   resolved "http://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
@@ -660,6 +691,19 @@ copy-descriptor@^0.1.0:
   version "0.1.1"
   resolved "http://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
 
+copy-webpack-plugin@^4.6.0:
+  version "4.6.0"
+  resolved "http://registry.npm.taobao.org/copy-webpack-plugin/download/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae"
+  dependencies:
+    cacache "^10.0.4"
+    find-cache-dir "^1.0.0"
+    globby "^7.1.1"
+    is-glob "^4.0.0"
+    loader-utils "^1.1.0"
+    minimatch "^3.0.4"
+    p-limit "^1.0.0"
+    serialize-javascript "^1.4.0"
+
 core-util-is@~1.0.0:
   version "1.0.2"
   resolved "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -718,6 +762,19 @@ crypto-browserify@^3.11.0:
     randombytes "^2.0.0"
     randomfill "^1.0.3"
 
+css-select@^1.1.0:
+  version "1.2.0"
+  resolved "http://registry.npm.taobao.org/css-select/download/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
+  dependencies:
+    boolbase "~1.0.0"
+    css-what "2.1"
+    domutils "1.5.1"
+    nth-check "~1.0.1"
+
+css-what@2.1:
+  version "2.1.2"
+  resolved "http://registry.npm.taobao.org/css-what/download/css-what-2.1.2.tgz#c0876d9d0480927d7d4920dcd72af3595649554d"
+
 cyclist@~0.2.2:
   version "0.2.2"
   resolved "http://registry.npm.taobao.org/cyclist/download/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
@@ -769,6 +826,12 @@ default-gateway@^2.6.0:
     execa "^0.10.0"
     ip-regex "^2.1.0"
 
+define-properties@^1.1.2:
+  version "1.1.3"
+  resolved "http://registry.npm.taobao.org/define-properties/download/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+  dependencies:
+    object-keys "^1.0.12"
+
 define-property@^0.2.5:
   version "0.2.5"
   resolved "http://registry.npm.taobao.org/define-property/download/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
@@ -834,6 +897,13 @@ diffie-hellman@^5.0.0:
     miller-rabin "^4.0.0"
     randombytes "^2.0.0"
 
+dir-glob@^2.0.0:
+  version "2.0.0"
+  resolved "http://registry.npm.taobao.org/dir-glob/download/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
+  dependencies:
+    arrify "^1.0.1"
+    path-type "^3.0.0"
+
 dns-equal@^1.0.0:
   version "1.0.0"
   resolved "http://registry.npm.taobao.org/dns-equal/download/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -851,10 +921,50 @@ dns-txt@^2.0.2:
   dependencies:
     buffer-indexof "^1.0.0"
 
+dom-converter@~0.2:
+  version "0.2.0"
+  resolved "http://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
+  dependencies:
+    utila "~0.4"
+
+dom-serializer@0:
+  version "0.1.0"
+  resolved "http://registry.npm.taobao.org/dom-serializer/download/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
+  dependencies:
+    domelementtype "~1.1.1"
+    entities "~1.1.1"
+
 domain-browser@^1.1.1:
   version "1.2.0"
   resolved "http://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
 
+domelementtype@1:
+  version "1.2.1"
+  resolved "http://registry.npm.taobao.org/domelementtype/download/domelementtype-1.2.1.tgz#578558ef23befac043a1abb0db07635509393479"
+
+domelementtype@~1.1.1:
+  version "1.1.3"
+  resolved "http://registry.npm.taobao.org/domelementtype/download/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
+
+domhandler@2.1:
+  version "2.1.0"
+  resolved "http://registry.npm.taobao.org/domhandler/download/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594"
+  dependencies:
+    domelementtype "1"
+
+domutils@1.1:
+  version "1.1.6"
+  resolved "http://registry.npm.taobao.org/domutils/download/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
+  dependencies:
+    domelementtype "1"
+
+domutils@1.5.1:
+  version "1.5.1"
+  resolved "http://registry.npm.taobao.org/domutils/download/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
 duplexify@^3.4.2, duplexify@^3.6.0:
   version "3.6.1"
   resolved "http://registry.npm.taobao.org/duplexify/download/duplexify-3.6.1.tgz#b1a7a29c4abfd639585efaecce80d666b1e34125"
@@ -902,12 +1012,34 @@ enhanced-resolve@^4.1.0:
     memory-fs "^0.4.0"
     tapable "^1.0.0"
 
+entities@~1.1.1:
+  version "1.1.2"
+  resolved "http://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+
 errno@^0.1.3, errno@~0.1.7:
   version "0.1.7"
   resolved "http://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
   dependencies:
     prr "~1.0.1"
 
+es-abstract@^1.5.1:
+  version "1.12.0"
+  resolved "http://registry.npm.taobao.org/es-abstract/download/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
+  dependencies:
+    es-to-primitive "^1.1.1"
+    function-bind "^1.1.1"
+    has "^1.0.1"
+    is-callable "^1.1.3"
+    is-regex "^1.0.4"
+
+es-to-primitive@^1.1.1:
+  version "1.2.0"
+  resolved "http://registry.npm.taobao.org/es-to-primitive/download/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
+  dependencies:
+    is-callable "^1.1.4"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.2"
+
 escape-html@~1.0.3:
   version "1.0.3"
   resolved "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -1168,6 +1300,10 @@ fsevents@^1.2.2:
     nan "^2.9.2"
     node-pre-gyp "^0.10.0"
 
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "http://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+
 gauge@~2.7.3:
   version "2.7.4"
   resolved "http://registry.npm.taobao.org/gauge/download/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -1225,6 +1361,17 @@ globby@^6.1.0:
     pify "^2.0.0"
     pinkie-promise "^2.0.0"
 
+globby@^7.1.1:
+  version "7.1.1"
+  resolved "http://registry.npm.taobao.org/globby/download/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680"
+  dependencies:
+    array-union "^1.0.1"
+    dir-glob "^2.0.0"
+    glob "^7.1.2"
+    ignore "^3.3.5"
+    pify "^3.0.0"
+    slash "^1.0.0"
+
 graceful-fs@^4.1.11, graceful-fs@^4.1.2:
   version "4.1.15"
   resolved "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
@@ -1237,6 +1384,10 @@ has-flag@^3.0.0:
   version "3.0.0"
   resolved "http://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
 
+has-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+
 has-unicode@^2.0.0:
   version "2.0.1"
   resolved "http://registry.npm.taobao.org/has-unicode/download/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -1268,6 +1419,12 @@ has-values@^1.0.0:
     is-number "^3.0.0"
     kind-of "^4.0.0"
 
+has@^1.0.1:
+  version "1.0.3"
+  resolved "http://registry.npm.taobao.org/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  dependencies:
+    function-bind "^1.1.1"
+
 hash-base@^3.0.0:
   version "3.0.4"
   resolved "http://registry.npm.taobao.org/hash-base/download/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
@@ -1282,6 +1439,10 @@ hash.js@^1.0.0, hash.js@^1.0.3:
     inherits "^2.0.3"
     minimalistic-assert "^1.0.1"
 
+he@1.2.x:
+  version "1.2.0"
+  resolved "http://registry.npm.taobao.org/he/download/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+
 hmac-drbg@^1.0.0:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -1303,6 +1464,39 @@ html-entities@^1.2.0:
   version "1.2.1"
   resolved "http://registry.npm.taobao.org/html-entities/download/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
 
+html-minifier@^3.2.3:
+  version "3.5.21"
+  resolved "http://registry.npm.taobao.org/html-minifier/download/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.2.x"
+    commander "2.17.x"
+    he "1.2.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.4.x"
+
+html-webpack-plugin@^3.2.0:
+  version "3.2.0"
+  resolved "http://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b"
+  dependencies:
+    html-minifier "^3.2.3"
+    loader-utils "^0.2.16"
+    lodash "^4.17.3"
+    pretty-error "^2.0.2"
+    tapable "^1.0.0"
+    toposort "^1.0.0"
+    util.promisify "1.0.0"
+
+htmlparser2@~3.3.0:
+  version "3.3.0"
+  resolved "http://registry.npm.taobao.org/htmlparser2/download/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe"
+  dependencies:
+    domelementtype "1"
+    domhandler "2.1"
+    domutils "1.1"
+    readable-stream "1.0"
+
 http-deceiver@^1.2.7:
   version "1.2.7"
   resolved "http://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@@ -1367,6 +1561,10 @@ ignore-walk@^3.0.1:
   dependencies:
     minimatch "^3.0.4"
 
+ignore@^3.3.5:
+  version "3.3.10"
+  resolved "http://registry.npm.taobao.org/ignore/download/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+
 import-local@^2.0.0:
   version "2.0.0"
   resolved "http://registry.npm.taobao.org/import-local/download/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
@@ -1454,6 +1652,10 @@ is-buffer@^1.1.5:
   version "1.1.6"
   resolved "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
 
+is-callable@^1.1.3, is-callable@^1.1.4:
+  version "1.1.4"
+  resolved "http://registry.npm.taobao.org/is-callable/download/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
+
 is-data-descriptor@^0.1.4:
   version "0.1.4"
   resolved "http://registry.npm.taobao.org/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -1466,6 +1668,10 @@ is-data-descriptor@^1.0.0:
   dependencies:
     kind-of "^6.0.0"
 
+is-date-object@^1.0.1:
+  version "1.0.1"
+  resolved "http://registry.npm.taobao.org/is-date-object/download/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
+
 is-descriptor@^0.1.0:
   version "0.1.6"
   resolved "http://registry.npm.taobao.org/is-descriptor/download/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
@@ -1546,10 +1752,22 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
   dependencies:
     isobject "^3.0.1"
 
+is-regex@^1.0.4:
+  version "1.0.4"
+  resolved "http://registry.npm.taobao.org/is-regex/download/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
+  dependencies:
+    has "^1.0.1"
+
 is-stream@^1.1.0:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
 
+is-symbol@^1.0.2:
+  version "1.0.2"
+  resolved "http://registry.npm.taobao.org/is-symbol/download/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
+  dependencies:
+    has-symbols "^1.0.0"
+
 is-windows@^1.0.2:
   version "1.0.2"
   resolved "http://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -1558,6 +1776,10 @@ is-wsl@^1.1.0:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
 
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+
 isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
   version "1.0.0"
   resolved "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -1626,6 +1848,15 @@ loader-runner@^2.3.0:
   version "2.3.1"
   resolved "http://registry.npm.taobao.org/loader-runner/download/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979"
 
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "http://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
 loader-utils@^1.1.0:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/loader-utils/download/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
@@ -1652,7 +1883,7 @@ lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "http://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
 
-lodash@^4.17.5:
+lodash@^4.17.3, lodash@^4.17.5:
   version "4.17.11"
   resolved "http://registry.npm.taobao.org/lodash/download/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
 
@@ -1660,6 +1891,10 @@ loglevel@^1.4.1:
   version "1.6.1"
   resolved "http://registry.npm.taobao.org/loglevel/download/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
 
+lower-case@^1.1.1:
+  version "1.1.4"
+  resolved "http://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+
 lru-cache@^4.1.1:
   version "4.1.3"
   resolved "http://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
@@ -1904,6 +2139,12 @@ nice-try@^1.0.4:
   version "1.0.5"
   resolved "http://registry.npm.taobao.org/nice-try/download/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
 
+no-case@^2.2.0:
+  version "2.3.2"
+  resolved "http://registry.npm.taobao.org/no-case/download/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  dependencies:
+    lower-case "^1.1.1"
+
 node-forge@0.7.5:
   version "0.7.5"
   resolved "http://registry.npm.taobao.org/node-forge/download/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
@@ -1990,6 +2231,12 @@ npmlog@^4.0.2:
     gauge "~2.7.3"
     set-blocking "~2.0.0"
 
+nth-check@~1.0.1:
+  version "1.0.2"
+  resolved "http://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
+  dependencies:
+    boolbase "~1.0.0"
+
 number-is-nan@^1.0.0:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@@ -2006,12 +2253,23 @@ object-copy@^0.1.0:
     define-property "^0.2.5"
     kind-of "^3.0.3"
 
+object-keys@^1.0.12:
+  version "1.0.12"
+  resolved "http://registry.npm.taobao.org/object-keys/download/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
+
 object-visit@^1.0.0:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/object-visit/download/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
   dependencies:
     isobject "^3.0.0"
 
+object.getownpropertydescriptors@^2.0.3:
+  version "2.0.3"
+  resolved "http://registry.npm.taobao.org/object.getownpropertydescriptors/download/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.5.1"
+
 object.pick@^1.3.0:
   version "1.3.0"
   resolved "http://registry.npm.taobao.org/object.pick/download/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -2089,7 +2347,7 @@ p-is-promise@^1.1.0:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/p-is-promise/download/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e"
 
-p-limit@^1.1.0:
+p-limit@^1.0.0, p-limit@^1.1.0:
   version "1.3.0"
   resolved "http://registry.npm.taobao.org/p-limit/download/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
   dependencies:
@@ -2137,6 +2395,12 @@ parallel-transform@^1.1.0:
     inherits "^2.0.3"
     readable-stream "^2.1.5"
 
+param-case@2.1.x:
+  version "2.1.1"
+  resolved "http://registry.npm.taobao.org/param-case/download/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  dependencies:
+    no-case "^2.2.0"
+
 parse-asn1@^5.0.0:
   version "5.1.1"
   resolved "http://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8"
@@ -2183,6 +2447,12 @@ path-to-regexp@0.1.7:
   version "0.1.7"
   resolved "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
 
+path-type@^3.0.0:
+  version "3.0.0"
+  resolved "http://registry.npm.taobao.org/path-type/download/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+  dependencies:
+    pify "^3.0.0"
+
 pbkdf2@^3.0.3:
   version "3.0.17"
   resolved "http://registry.npm.taobao.org/pbkdf2/download/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
@@ -2235,6 +2505,13 @@ posix-character-classes@^0.1.0:
   version "0.1.1"
   resolved "http://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
 
+pretty-error@^2.0.2:
+  version "2.1.1"
+  resolved "http://registry.npm.taobao.org/pretty-error/download/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
+  dependencies:
+    renderkid "^2.0.1"
+    utila "~0.4"
+
 process-nextick-args@~2.0.0:
   version "2.0.0"
   resolved "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
@@ -2363,6 +2640,15 @@ rc@^1.2.7:
     string_decoder "~1.1.1"
     util-deprecate "~1.0.1"
 
+readable-stream@1.0:
+  version "1.0.34"
+  resolved "http://registry.npm.taobao.org/readable-stream/download/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
 readdirp@^2.0.0:
   version "2.2.1"
   resolved "http://registry.npm.taobao.org/readdirp/download/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@@ -2378,10 +2664,24 @@ regex-not@^1.0.0, regex-not@^1.0.2:
     extend-shallow "^3.0.2"
     safe-regex "^1.1.0"
 
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "http://registry.npm.taobao.org/relateurl/download/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+
 remove-trailing-separator@^1.0.1:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
 
+renderkid@^2.0.1:
+  version "2.0.2"
+  resolved "http://registry.npm.taobao.org/renderkid/download/renderkid-2.0.2.tgz#12d310f255360c07ad8fde253f6c9e9de372d2aa"
+  dependencies:
+    css-select "^1.1.0"
+    dom-converter "~0.2"
+    htmlparser2 "~3.3.0"
+    strip-ansi "^3.0.0"
+    utila "^0.4.0"
+
 repeat-element@^1.1.2:
   version "1.1.3"
   resolved "http://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
@@ -2580,6 +2880,10 @@ signal-exit@^3.0.0:
   version "3.0.2"
   resolved "http://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
 
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.taobao.org/slash/download/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "http://registry.npm.taobao.org/snapdragon-node/download/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -2647,7 +2951,7 @@ source-map@^0.5.6:
   version "0.5.7"
   resolved "http://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
 
-source-map@^0.6.1, source-map@~0.6.1:
+source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
   version "0.6.1"
   resolved "http://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
 
@@ -2750,6 +3054,10 @@ string_decoder@^1.0.0, string_decoder@~1.1.1:
   dependencies:
     safe-buffer "~5.1.0"
 
+string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "http://registry.npm.taobao.org/string_decoder/download/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
 strip-ansi@^3.0.0, strip-ansi@^3.0.1:
   version "3.0.1"
   resolved "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@@ -2835,6 +3143,10 @@ to-regex@^3.0.1, to-regex@^3.0.2:
     regex-not "^1.0.2"
     safe-regex "^1.1.0"
 
+toposort@^1.0.0:
+  version "1.0.7"
+  resolved "http://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
+
 tslib@^1.9.0:
   version "1.9.3"
   resolved "http://registry.npm.taobao.org/tslib/download/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
@@ -2861,6 +3173,13 @@ uglify-es@^3.3.4:
     commander "~2.13.0"
     source-map "~0.6.1"
 
+uglify-js@3.4.x:
+  version "3.4.9"
+  resolved "http://registry.npm.taobao.org/uglify-js/download/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
+  dependencies:
+    commander "~2.17.1"
+    source-map "~0.6.1"
+
 uglifyjs-webpack-plugin@^1.2.4:
   version "1.3.0"
   resolved "http://registry.npm.taobao.org/uglifyjs-webpack-plugin/download/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de"
@@ -2910,6 +3229,10 @@ upath@^1.0.5:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/upath/download/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
 
+upper-case@^1.1.1:
+  version "1.1.3"
+  resolved "http://registry.npm.taobao.org/upper-case/download/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+
 uri-js@^4.2.2:
   version "4.2.2"
   resolved "http://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
@@ -2942,6 +3265,13 @@ util-deprecate@~1.0.1:
   version "1.0.2"
   resolved "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
 
+util.promisify@1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.taobao.org/util.promisify/download/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
+  dependencies:
+    define-properties "^1.1.2"
+    object.getownpropertydescriptors "^2.0.3"
+
 util@0.10.3:
   version "0.10.3"
   resolved "http://registry.npm.taobao.org/util/download/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
@@ -2954,6 +3284,10 @@ util@^0.10.3:
   dependencies:
     inherits "2.0.3"
 
+utila@^0.4.0, utila@~0.4:
+  version "0.4.0"
+  resolved "http://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
+
 utils-merge@1.0.1:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"

+ 20 - 0
script/mysql/init/mail.sql

@@ -0,0 +1,20 @@
+CREATE DATABASE `saas_mail` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
+use `saas_mail`;
+
+create table `m_log` (
+  `id` int unsigned primary key not null auto_increment,
+  `template_id` int comment '模板',
+  `subject` varchar(300) not null comment '主题',
+  `text` text comment '内容',
+  `from` varchar(100) comment '发送人',
+  `to` varchar(1000) comment '接收人',
+  `company_id` int,
+  `creator_id` int,
+  `create_time` datetime
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件日志';
+
+create table `m_template` (
+  `id` varchar(300) primary key not null,
+  `subject` varchar(300) not null comment '主题',
+  `text` text comment '内容'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件模板';