Browse Source

合并代码

rainco 7 years ago
parent
commit
008545fd2d
61 changed files with 1534 additions and 273 deletions
  1. 57 0
      applications/commons/commons-dto/src/main/java/com/usoftchina/saas/commons/dto/ShareAddDTO.java
  2. 2 0
      applications/commons/commons-dto/src/main/java/com/usoftchina/saas/commons/exception/BizExceptionCode.java
  3. 19 0
      applications/commons/commons-server/pom.xml
  4. 194 0
      applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/controller/ShareController.java
  5. 39 0
      applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/utils/SHA1.java
  6. 104 0
      applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/utils/WeixinTokenUtil.java
  7. 1 1
      applications/commons/commons-server/src/main/resources/i18n/messages_zh_CN.properties
  8. 81 0
      applications/commons/commons-server/src/test/java/com/usoftchina/saas/commons/controller/ShareControllerTest.java
  9. 56 0
      applications/commons/commons-server/src/test/java/com/usoftchina/saas/commons/utils/UrlBase64EncoderTest.java
  10. 1 0
      applications/purchase/purchase-server/src/main/resources/mapper/PurchaseReportMapper.xml
  11. 1 1
      applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/service/impl/ProdInOutServiceImpl.java
  12. 6 1
      applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/service/impl/SaleServiceImpl.java
  13. 2 2
      applications/sale/sale-server/src/main/resources/mapper/ProdIODetailMapper.xml
  14. 5 3
      applications/sale/sale-server/src/main/resources/mapper/SaleMapper.xml
  15. 4 0
      applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/mapper/ProdInOutMapper.java
  16. 16 1
      applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/service/impl/ProdInOutServiceImpl.java
  17. 6 0
      applications/storage/storage-server/src/main/resources/mapper/ProdInOutMapper.xml
  18. 9 0
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/AccountApi.java
  19. 14 67
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/AccountController.java
  20. 14 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/RoleController.java
  21. 15 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/AccountService.java
  22. 181 4
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/AccountServiceImpl.java
  23. 11 1
      base-servers/account/account-server/src/main/resources/mapper/AccountMapper.xml
  24. 13 0
      base-servers/auth/auth-server/src/test/java/com/usoftchina/saas/auth/controller/AuthControllerTest.java
  25. 3 0
      base-servers/gateway-server/src/main/resources/application.yml
  26. 4 0
      base-servers/sms/sms-api/pom.xml
  27. 2 2
      base-servers/sms/sms-api/src/main/java/com/usoftchina/saas/sms/api/SmsApi.java
  28. 86 0
      base-servers/sms/sms-api/src/main/java/com/usoftchina/saas/sms/cache/SmsCache.java
  29. 1 1
      base-servers/sms/sms-server/src/main/java/com/usoftchina/saas/sms/controller/SmsController.java
  30. 1 1
      base-servers/sms/sms-server/src/test/java/com/usoftchina/saas/sms/api/SmsApiTest.java
  31. 48 0
      base-servers/sms/sms-server/src/test/java/com/usoftchina/saas/sms/cache/SmsCacheTest.java
  32. 3 1
      framework/core/src/main/java/com/usoftchina/saas/exception/ExceptionCode.java
  33. 6 0
      framework/core/src/main/java/com/usoftchina/saas/utils/StringUtils.java
  34. 13 7
      frontend/saas-portal-web/src/components/conenter/addenterprise.vue
  35. 23 3
      frontend/saas-portal-web/src/components/conenter/enterprise.vue
  36. 320 0
      frontend/saas-portal-web/src/components/conenter/invitation.vue
  37. 4 1
      frontend/saas-portal-web/src/pages/index/index.vue
  38. 6 0
      frontend/saas-portal-web/src/router/index.js
  39. 1 0
      frontend/saas-portal-web/src/store/index.js
  40. 1 0
      frontend/saas-portal-web/static/MP_verify_BMkQAHplMGROBlAn.txt
  41. BIN
      frontend/saas-portal-web/static/img/beijing.png
  42. 0 1
      frontend/saas-web/app.json
  43. 1 1
      frontend/saas-web/app/model/document/bomdetail.js
  44. 1 1
      frontend/saas-web/app/model/sale/SaleOutDetail.js
  45. 10 38
      frontend/saas-web/app/model/stock/OtherIn.js
  46. 10 38
      frontend/saas-web/app/model/stock/OtherOut.js
  47. 0 4
      frontend/saas-web/app/view/core/chart/ChartBase.js
  48. 0 1
      frontend/saas-web/app/view/core/form/field/DetailGridField.js
  49. 1 1
      frontend/saas-web/app/view/core/query/QueryFormPanel.js
  50. 6 2
      frontend/saas-web/app/view/core/report/ReportPanelController.js
  51. 41 35
      frontend/saas-web/app/view/home/InfoCard.scss
  52. 2 11
      frontend/saas-web/app/view/main/Main.js
  53. 38 21
      frontend/saas-web/app/view/main/Navigation.scss
  54. 4 4
      frontend/saas-web/app/view/money/payBalance/FormPanelController.js
  55. 4 4
      frontend/saas-web/app/view/money/recBalance/FormPanelController.js
  56. 11 6
      frontend/saas-web/app/view/money/report/CustomerCheck.js
  57. 11 1
      frontend/saas-web/app/view/money/report/VendorCheck.js
  58. 1 1
      frontend/saas-web/app/view/money/verification/FormPanelController.js
  59. 6 5
      frontend/saas-web/app/view/stock/inventory/EditDataList.js
  60. 13 0
      frontend/saas-web/app/view/viewport/ViewportModel.js
  61. 1 1
      frontend/saas-web/electron/package.json

+ 57 - 0
applications/commons/commons-dto/src/main/java/com/usoftchina/saas/commons/dto/ShareAddDTO.java

@@ -0,0 +1,57 @@
+package com.usoftchina.saas.commons.dto;
+
+import java.io.Serializable;
+
+/**
+ * @Description 分享加入界面,提交传输对象
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+public class ShareAddDTO implements Serializable {
+
+    private String username;
+    private String mobile;
+    private String validCode;
+    private String roleId;
+    private Long companyId;
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+
+    public String getValidCode() {
+        return validCode;
+    }
+
+    public void setValidCode(String validCode) {
+        this.validCode = validCode;
+    }
+
+    public String getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(String roleId) {
+        this.roleId = roleId;
+    }
+}

+ 2 - 0
applications/commons/commons-dto/src/main/java/com/usoftchina/saas/commons/exception/BizExceptionCode.java

@@ -126,6 +126,8 @@ public enum BizExceptionCode implements BaseExceptionCode {
     UNENOUGH_DETAIL_STOCK(76300, "行%s库存不足"),
     UNENOUGH_STOCK(76400, "%s :库存不足"),
     UNPOSTSTOCKPROFIT_EXISTS(76500, "存在当前仓库+物料未审核的盘盈盘亏单"),
+    STORAGE_WAREHOUSE_SAME(76501, "调拨单拨入拨出仓库一致"),
+    STORAGE_WAREHOUSE_SAMES(76502, "调拨单: %s 拨入拨出仓库一致"),
     STOCKPROFIT_NULL(76600, "没有需要生成的盘盈盘亏单")
     ;
     private int code;

+ 19 - 0
applications/commons/commons-server/pom.xml

@@ -23,6 +23,14 @@
             <groupId>com.usoftchina.saas</groupId>
             <artifactId>server-starter</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>auth-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>sms-api</artifactId>
+        </dependency>
         <!-- db -->
         <dependency>
             <groupId>mysql</groupId>
@@ -79,6 +87,17 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
         </dependency>
+        <!-- ZXING 二维码 -->
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
+            <version>3.3.0</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 194 - 0
applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/controller/ShareController.java

@@ -0,0 +1,194 @@
+package com.usoftchina.saas.commons.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.usoftchina.saas.account.api.AccountApi;
+import com.usoftchina.saas.auth.common.crypto.base64.UrlBase64;
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
+import com.usoftchina.saas.commons.utils.WeixinTokenUtil;
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.exception.ExceptionCode;
+import com.usoftchina.saas.sms.api.SmsApi;
+import com.usoftchina.saas.sms.cache.SmsCache;
+import com.usoftchina.saas.sms.dto.SmsDTO;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description 分享加入
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+@Controller
+@RequestMapping("/share")
+public class ShareController {
+
+    @Autowired
+    private AccountApi accountApi;
+    @Autowired
+    private SmsApi smsApi;
+
+    //验证码短信模板
+    private final String validTemplateCode = "SMS_152856542";
+
+    /**
+     * 生成分享二维码
+     * @param response
+     * @param basePath
+     */
+    @GetMapping("/qrcode")
+    public void qrcode(HttpServletResponse response,String companyName, String basePath, @RequestParam(value = "delay", defaultValue = "1") Long delay){
+        Long companyId = BaseContextHolder.getCompanyId();
+        String username = BaseContextHolder.getUserName();
+        try {
+            OutputStream outputStream = response.getOutputStream();
+            buildQrcode(basePath, username, companyId, delay, companyName, outputStream);
+            outputStream.flush();
+            outputStream.close();
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 将前台传入的encode参数decode并校验,返回给前端
+     * @param param
+     * @return
+     */
+    @PostMapping("/valid/param")
+    @ResponseBody
+    public Result validParam(String param){
+        if (!StringUtils.isEmpty(param)){
+            String data = new String(UrlBase64.decode(param));
+            Map<String, String> paramData = parseParam(data);
+            return Result.success(paramData);
+        }
+        return Result.error(ExceptionCode.ILLEGAL_ARGUMENTS);
+    }
+
+    /**
+     * 生成微信需要的签名
+     * @param targetUrl
+     * @return
+     */
+    @GetMapping("/weixin/ticket")
+    @ResponseBody
+    public Result getWXTicket(@RequestParam("targetUrl") String targetUrl){
+        Map<String, String> map = null;
+        try {
+            map = WeixinTokenUtil.getConfigData(targetUrl);
+            return Result.success(map);
+        } catch (Exception e) {
+            return Result.error("处理失败");
+        }
+    }
+
+    /**
+     * 获取短信验证码
+     * @param mobile
+     * @return
+     */
+    @PostMapping("/getSmsCode")
+    @ResponseBody
+    public Result getSmsCode(String mobile){
+        String validCode = StringUtils.createValidCode(6);
+        SmsDTO smsDTO = new SmsDTO();
+        smsDTO.setSignName("优软云");
+        smsDTO.setMobile(mobile);
+        smsDTO.setTemplateCode(validTemplateCode);
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("code", validCode);
+        smsDTO.setTemplateParam(jsonObject.toJSONString());
+        //加入redis缓存,有效期5分钟
+        SmsCache smsCache = SmsCache.of(mobile);
+        smsCache.set(validCode, 60 * 5);
+        Result result = smsApi.sendMsg(smsDTO);
+        return Result.success();
+    }
+
+    /**
+     * 提交
+     * @param shareAddDTO
+     * @return
+     */
+    @PostMapping("/submit")
+    @ResponseBody
+    public Result submit(@RequestBody ShareAddDTO shareAddDTO){
+        return accountApi.shareJoin(shareAddDTO);
+    }
+
+
+    /**
+     * 生成二维码
+     * @param basePath
+     * @param username
+     * @param companyId
+     * @param outputStream
+     */
+    private void buildQrcode(String basePath, String username, Long companyId, Long delay, String companyName, OutputStream outputStream) throws WriterException, IOException {
+        String params = "username=" + username + "&companyId=" + companyId + "&timestamp=" + new Date().getTime() + "&delay=" + delay + "&companyName=" + companyName;
+        String encodeParams = new String(UrlBase64.encode(params.getBytes()));
+//        String text = basePath + "/xxx.html" + "?param=" + encodeParams;
+        String text = "https://www.baidu.com";
+        int width = 140;
+        int height = 140;
+        String format = "png";
+        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+        hints.put(EncodeHintType.MARGIN, 1);
+        //生成矩阵
+        BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
+        //输出图像
+        MatrixToImageWriter.writeToStream(bitMatrix, format, outputStream);
+    }
+
+    /**
+     * 解析请求的参数
+     * @param data
+     * @return
+     */
+    private Map<String,String> parseParam(String data) {
+        Map<String, String> map = new HashMap<String, String>();
+        int firstEndIndex = data.indexOf("&");
+        int secondEndIndex = data.indexOf("&", firstEndIndex + 1);
+        int thirdEndIndex = data.indexOf("&", secondEndIndex + 1);
+        int lastEndIndex = data.indexOf("&", thirdEndIndex + 1);
+        map.put("username", data.substring(9, firstEndIndex));
+        map.put("companyId", data.substring(firstEndIndex + 11, secondEndIndex));
+        map.put("timestamp", data.substring(secondEndIndex + 11, thirdEndIndex));
+        map.put("delay", data.substring(thirdEndIndex + 7, lastEndIndex));
+        map.put("companyName", data.substring(lastEndIndex + 13));
+
+        /* 校验参数合法性 */
+        //1.校验参数值不为空
+        if (StringUtils.isEmpty(map.get("username")) || StringUtils.isEmpty(map.get("companyId"))
+                || StringUtils.isEmpty(map.get("timestamp")) || StringUtils.isEmpty(map.get("delay"))){
+            throw new BizException(ExceptionCode.ILLEGAL_ARGUMENTS);
+        }
+        //2.校验有效期
+        Long createTime = Long.parseLong(map.get("timestamp"));
+        Long delay = Long.parseLong(map.get("delay"));
+        Long expireTime = createTime + delay * 24 * 60 * 60 * 1000;
+        if (expireTime < new Date().getTime()){
+            throw new BizException(ExceptionCode.ILLEGAL_ARGUMENTS);
+        }
+        return map;
+    }
+
+}

+ 39 - 0
applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/utils/SHA1.java

@@ -0,0 +1,39 @@
+package com.usoftchina.saas.commons.utils;
+
+import java.security.MessageDigest;
+
+/**
+ * @Description 微信公众平台用到的SHA1加密算法
+ * @Author chenwei
+ * @Date 2018/12/20
+ */
+public class SHA1 {
+
+    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
+            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+    private static String getFormattedText(byte[] bytes) {
+        int len = bytes.length;
+        StringBuilder buf = new StringBuilder(len * 2);
+        // 把密文转换成十六进制的字符串形式
+        for (int j = 0; j < len; j++) {
+            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
+            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
+        }
+        return buf.toString();
+    }
+
+    public static String encode(String str) {
+        if (str == null) {
+            return null;
+        }
+        try {
+            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
+            messageDigest.update(str.getBytes());
+            return getFormattedText(messageDigest.digest());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 104 - 0
applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/utils/WeixinTokenUtil.java

@@ -0,0 +1,104 @@
+package com.usoftchina.saas.commons.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.usoftchina.saas.utils.http.HttpUtil;
+
+import java.security.MessageDigest;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * @Description 生成微信token
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+public class WeixinTokenUtil {
+
+    public final static String GetPageAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
+    public final static String GetPageJSapiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
+    public final static String SOURCE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
+    public final static String APPID = "wxbc1f8607137d3b8a";
+    public final static String APPSECRET = "cadf13c4e21c2c122cb2341b341e5c22";
+
+    /**
+     * 获取accessToken
+     * @param appId
+     * @param appSecret
+     * @return
+     * @throws Exception
+     */
+    public static String getAccessToken(String appId, String appSecret) throws Exception {
+        String requestUrl = GetPageAccessTokenUrl.replace("APPID", appId).replace("SECRET", appSecret);
+        HttpUtil.Response response = HttpUtil.sendGetRequest(requestUrl, null);
+        if (response.getStatusCode() == 200){
+            JSONObject jsonObject = (JSONObject) JSONObject.parse(response.getResponseText());
+            return jsonObject.getString("access_token");
+        }
+        return null;
+    }
+
+    /**
+     * 获取ticket
+     * @param accessToken
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, String> getJsapiTicket(String accessToken) throws Exception {
+        Map<String, String> result = new HashMap<String, String>();
+        String requestUrl = GetPageJSapiTicketUrl.replace("ACCESS_TOKEN", accessToken);
+        HttpUtil.Response response = HttpUtil.sendGetRequest(requestUrl, null);
+        if (response.getStatusCode() == 200){
+            JSONObject jsonObject = (JSONObject) JSONObject.parse(response.getResponseText());
+            result.put("errCode", jsonObject.getString("errcode"));
+            result.put("errMsg", jsonObject.getString("errmsg"));
+            result.put("ticket", jsonObject.getString("ticket"));
+            result.put("expires_in", jsonObject.getString("expires_in"));
+            return result;
+        }
+        return result;
+    }
+
+    /**
+     * 生成微信需要的config参数
+     * @param targetUrl
+     * @return
+     * @throws Exception
+     */
+    public static Map<String, String> getConfigData(String targetUrl) throws Exception {
+        String noncestr = generateString(new Random(), SOURCE_CHARACTERS, 32);
+        Long timestamp = new Date().getTime();
+        //accessToken
+        String accessToken = getAccessToken(APPID, APPSECRET);
+        Map<String, String> map = getJsapiTicket(accessToken);
+
+        String str = "jsapi_ticket=" + map.get("ticket") + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + targetUrl;
+        String signature = SHA1.encode(str);
+
+        Map<String, String> resultMap = new HashMap<String, String>();
+        resultMap.put("timestamp", String.valueOf(timestamp));
+        resultMap.put("accessToken", accessToken);
+        resultMap.put("ticket", map.get("ticket"));
+        resultMap.put("noncestr", noncestr);
+        resultMap.put("signature", signature);
+        resultMap.put("appId", APPID);
+        return resultMap;
+    }
+
+    /**
+     * 生成指定位数的随机字符串
+     * @param random
+     * @param characters
+     * @param length
+     * @return
+     */
+    public static String generateString(Random random, String characters, int length){
+        char[] text = new char[length];
+        for (int i = 0; i < length; i++) {
+            text[i] = characters.charAt(random.nextInt(characters.length()));
+        }
+        return new String(text);
+    }
+
+}

+ 1 - 1
applications/commons/commons-server/src/main/resources/i18n/messages_zh_CN.properties

@@ -95,7 +95,7 @@ msg.turnARBill=\u5f00\u7968\u4f5c\u4e1a
 msg.turnNotify=\u8f6c\u901a\u77e5\u5355\u64cd\u4f5c
 msg.turnStorage=\u8f6c\u5165\u5e93
 msg.turnProdIO=\u8f6c\u51fa\u5e93\u5355\u64cd\u4f5c
-msg.turnProdIOReturn=\u8F6C\u9500\u552E\u9A8C\u9000\u5355
+msg.turnProdIOReturn=\u8f6c\u9500\u552e\u9000\u8d27\u5355
 msg.turnProdIO\!OtherOut=\u8f6c\u5176\u5b83\u51fa\u5e93\u5355\u64cd\u4f5c
 msg.turnProdIO\!OtherPurcOut=\u8f6c\u5176\u5b83\u91c7\u8d2d\u51fa\u5e93\u5355
 msg.turnSendNotify=\u8f6c\u53d1\u8d27\u901a\u77e5\u5355\u64cd\u4f5c

+ 81 - 0
applications/commons/commons-server/src/test/java/com/usoftchina/saas/commons/controller/ShareControllerTest.java

@@ -0,0 +1,81 @@
+package com.usoftchina.saas.commons.controller;
+
+import com.usoftchina.saas.auth.common.crypto.base64.UrlBase64;
+import com.usoftchina.saas.auth.common.crypto.base64.UrlBase64Encoder;
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
+import com.usoftchina.saas.test.BaseControllerTest;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MvcResult;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 分享加入controller测试
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ShareControllerTest extends BaseControllerTest {
+
+    private final String PARAMS = "username=陈炜&companyId=262&timestmap=" + new Date().getTime() + "&delay=1&companyName=陈炜";
+    private final String mobile = "18702604854";
+
+    @Test
+    public void qrcode() throws Exception {
+        mockMvc.perform(get("/share/qrcode")
+                .accept(MediaType.ALL)
+                .contentType(MediaType.ALL))
+                .andExpect(isSuccess());
+    }
+
+    @Test
+    public void validParam() throws Exception {
+        String param = new String(UrlBase64.encode(PARAMS.getBytes()));
+        mockMvc.perform(post("/share/valid/param")
+               .param("param", param))
+               .andExpect(isSuccess())
+               .andReturn();
+    }
+
+    @Test
+    public void getWXTicket() throws Exception {
+        MvcResult mvcResult = mockMvc.perform(get("/share/weixin/ticket")
+               .param("basePath", "https://saas.usoftchina.com"))
+               .andExpect(isSuccess())
+               .andReturn();
+        Result<HashMap> result = result(mvcResult, HashMap.class);
+        System.out.println(result);
+    }
+
+    @Test
+    public void getSmsCode() throws Exception {
+        mockMvc.perform(post("/share/getSmsCode")
+                .param("mobile", "18702604709"))
+                .andExpect(isSuccess())
+                .andReturn();
+    }
+
+    @Test
+    public void submit() throws Exception {
+        ShareAddDTO shareAddDTO = new ShareAddDTO();
+        shareAddDTO.setCompanyId(262L);
+        shareAddDTO.setUsername("何炎");
+        shareAddDTO.setMobile("18702604709");
+        shareAddDTO.setValidCode("123456");
+        shareAddDTO.setRoleId("0");
+
+        mockMvc.perform(requestBody("/share/submit", shareAddDTO))
+               .andExpect(isSuccess())
+               .andReturn();
+    }
+
+}

+ 56 - 0
applications/commons/commons-server/src/test/java/com/usoftchina/saas/commons/utils/UrlBase64EncoderTest.java

@@ -0,0 +1,56 @@
+package com.usoftchina.saas.commons.utils;
+
+import com.usoftchina.saas.auth.common.crypto.base64.UrlBase64;
+import org.junit.Test;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description 测试URLEncode
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+public class UrlBase64EncoderTest {
+
+    private final String PARAMS = "username=陈炜&companyId=262&timestmap=" + new Date().getTime() + "&delay=1&companyName=陈炜";
+
+    @Test
+    public void testA_UrlEncocde(){
+        byte[] encodeBytes = UrlBase64.encode(PARAMS.getBytes());
+        String encodeStr = new String(encodeBytes);
+        System.out.println("encodeStr:========" + encodeStr + "============");
+
+        byte[] decodeBytes = UrlBase64.decode(encodeStr);
+        String decodeStr = new String(decodeBytes);
+        System.out.println("decodeBytes:========" + decodeStr + "============");
+    }
+    
+    @Test
+    public void testB_parseParam(){
+        Map<String, String> map = new HashMap<String, String>();
+        int firstEndIndex = PARAMS.indexOf("&");
+        int secondEndIndex = PARAMS.indexOf("&", firstEndIndex + 1);
+        int thirdEndIndex = PARAMS.indexOf("&", secondEndIndex + 1);
+        int lastEndIndex = PARAMS.indexOf("&", thirdEndIndex + 1);
+
+        map.put("username", PARAMS.substring(9, firstEndIndex));
+        map.put("companyId", PARAMS.substring(firstEndIndex + 11, secondEndIndex));
+        map.put("timestamp", PARAMS.substring(secondEndIndex + 11, lastEndIndex));
+        map.put("delay", PARAMS.substring(thirdEndIndex + 7, lastEndIndex));
+        map.put("companyName", PARAMS.substring(lastEndIndex + 13));
+        System.out.println(map);
+    }
+
+    @Test
+    public void testC_Timeconpare(){
+        Long createTime = 1545196813279L;
+        Long expireTime = createTime + 5 * 60 * 1000;
+        Long now = new Date().getTime();
+        System.out.println("NOW:==========" + now + "==========");
+        System.out.println("expireTime:==========" + expireTime + "==========");
+        System.out.println(now.compareTo(expireTime) > 0);
+    }
+
+}

+ 1 - 0
applications/purchase/purchase-server/src/main/resources/mapper/PurchaseReportMapper.xml

@@ -151,6 +151,7 @@
       <if test="companyId != null">
         and   purchase.companyId = #{companyId}
       </if>
+      and pu_statuscode='AUDITED'
     </where>  order by pu_date desc
   </select>
 

+ 1 - 1
applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/service/impl/ProdInOutServiceImpl.java

@@ -204,7 +204,7 @@ public class ProdInOutServiceImpl extends CommonBaseServiceImpl<ProdInOutMapper,
         //更新明细金额等
         setTotal(prodInOut);
         //日志
-      messageLogService.deleteDetail(docBaseDTO);
+        messageLogService.delete(docBaseDTO);
     }
 
     @Override

+ 6 - 1
applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/service/impl/SaleServiceImpl.java

@@ -310,6 +310,11 @@ public class SaleServiceImpl implements SaleService{
             throw new BizException(BizExceptionCode.SALE_EXISTS_PURCHASE.getCode(),
                     String.format(BizExceptionCode.SALE_EXISTS_PURCHASE.getMessage(),purchaseCode));
         }
+        //检测客户是否禁用
+        Integer ban = saleMapper.checkCustomer(id);
+        if (ban > 0) {
+            throw new BizException(7890001, "存在已禁用客户");
+        }
         singleUnAudit(id);
     }
 
@@ -742,7 +747,7 @@ public class SaleServiceImpl implements SaleService{
             if (!StringUtils.isEmpty(custAudit)) {
                 String message = BizExceptionCode.SALE_ORDER_CUSTBANDED.getMessage();
                 int code = BizExceptionCode.SALE_ORDER_CUSTBANDED.getCode();
-                throw new BizException(code, String.format(message, "审核")+custAudit);
+                throw new BizException(code, String.format(message, "审核")+custAudit);
             }
         }else{
             //存在未审核单据,单据编号:XXXX

+ 2 - 2
applications/sale/sale-server/src/main/resources/mapper/ProdIODetailMapper.xml

@@ -759,14 +759,14 @@
   <update id="updatePDSaleIN" parameterType="long">
    update prodiodetail set
    pd_ordertotal=round(IFNULL(pd_inqty,0)*IFNULL(pd_sendprice,0),2),
-   pd_netprice = round(IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100),2),
+   pd_netprice = round(IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100),4),
    pd_nettotal = round((IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100))*IFNULL(pd_inqty,0),2)
    where pd_piid=#{id}
   </update>
   <update id="updatePDSaleOut" parameterType="long">
     update prodiodetail set
     pd_ordertotal=round(IFNULL(pd_outqty,0)*IFNULL(pd_sendprice,0),2),
-    pd_netprice = round(IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100),2),
+    pd_netprice = round(IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100),4),
     pd_nettotal = round((IFNULL(pd_sendprice,0)/(1+IFNULL(pd_taxrate,0)/100))*IFNULL(pd_outqty,0),2)
     where pd_piid=#{id}
   </update>

+ 5 - 3
applications/sale/sale-server/src/main/resources/mapper/SaleMapper.xml

@@ -400,7 +400,7 @@
     select sa_code from sale where IFNULL(sa_sendstatuscode,' ')='CLOSE' and sa_id=#{id}
   </select>
   <select id="validateCustAudit" parameterType="com.usoftchina.saas.commons.dto.DocBaseDTO" resultType="java.lang.String">
-    select GROUP_CONCAT(sa_code) from sale left join customer on cu_id=sa_custid  where IFNULL(sa_statuscode,' ')='AUDITED' and IFNULL(cu_statuscode,' ')='BANNED' and sa_id in
+    select GROUP_CONCAT(sa_code) from sale left join customer on cu_id=sa_custid  where IFNULL(cu_statuscode,' ')='BANNED' and sa_id in
     <foreach collection="list" item="item" open="(" close=")" separator=",">
       #{item.id}
     </foreach>
@@ -418,7 +418,9 @@
     select sa_code from sale where sa_id = #{id} and IFNULL(sa_statuscode,'UNAUDITED')='UNAUDITED'
   </select>
   <update id="updateTotal" parameterType="long">
-    	update sale a set sa_total=(select sum(sd_price*sd_qty) from saledetail b where b.sd_said=a.sa_id ) where sa_id=#{id};
+ update sale a set sa_total=
+ (select sum(sd_price*sd_qty) from saledetail b where b.sd_said=a.sa_id ),sa_nettotal=(select sum(sd_netprice*sd_qty)
+ from saledetail where sd_said=sa_id) where sa_id=#{id};
   </update>
 
   <update id="updateTotalAndNetPrice" parameterType="long">
@@ -447,7 +449,7 @@
     and purchasedetail.companyid= #{companyid}
   </select>
   <select id="checkCustomer" parameterType="long" resultType="integer">
-    select count(1) from sale left join  customer on sa_custid=cu_id  where  cu_statuscode='CLOSE' and sa_id=#{id}
+    select count(1) from sale left join  customer on sa_custid=cu_id  where  cu_statuscode='BANNED' and sa_id=#{id}
   </select>
   <update id="updateAudit">
     update sale set sa_status=#{status},sa_statuscode=#{statuscode},sa_auditman=#{name},sa_auditdate=#{format} where sa_id=#{id}

+ 4 - 0
applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/mapper/ProdInOutMapper.java

@@ -2,9 +2,11 @@ package com.usoftchina.saas.storage.mapper;
 
 
 import com.usoftchina.saas.base.mapper.CommonBaseMapper;
+import com.usoftchina.saas.commons.dto.DocBaseDTO;
 import com.usoftchina.saas.storage.po.ProdInOut;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
 import java.util.Map;
 
 public interface ProdInOutMapper extends CommonBaseMapper<ProdInOut> {
@@ -31,4 +33,6 @@ public interface ProdInOutMapper extends CommonBaseMapper<ProdInOut> {
     void unPost(Map<String, Object> map);
 
     void updateCreator(@Param("userId") Long userId,@Param("userName") String userName,@Param("id") Long pi_id);
+
+    String checkWarehouse(List<DocBaseDTO> baseDTOs);
 }

+ 16 - 1
applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/service/impl/ProdInOutServiceImpl.java

@@ -219,6 +219,17 @@ public class ProdInOutServiceImpl extends CommonBaseServiceImpl<ProdInOutMapper,
         Long id = null;
         DocBaseDTO baseDTO = new DocBaseDTO();
         if (null != formData) {
+            //检测调拨单拨入、拨出仓库是否一致
+            List<ProdIODetailDTO> items = formData.getItems();
+            int count = 0;
+            for (ProdIODetailDTO item : items) {
+                if (item.getPd_inwhcode().equals(item.getPd_whcode())) {
+                    count++;
+                }
+            }
+            if (count > 0) {
+                throw new BizException(BizExceptionCode.STORAGE_WAREHOUSE_SAME);
+            }
             id = formData.getMain().getId();
             if (StringUtils.isEmpty(id)|| "0".equals(String.valueOf(id))) {
                 baseDTO = saveFormData(formData);
@@ -232,7 +243,7 @@ public class ProdInOutServiceImpl extends CommonBaseServiceImpl<ProdInOutMapper,
     }
 
     @Transactional(propagation = Propagation.REQUIRED)
-    private void singleAudit(ProdInOutDTO prodInOutDTO) {
+    public void singleAudit(ProdInOutDTO prodInOutDTO) {
         String pi_class= prodInOutDTO.getPi_class();
         String pi_inoutno = prodInOutDTO.getPi_inoutno();
         String pi_statuscode = prodInOutDTO.getPi_statuscode();
@@ -263,6 +274,10 @@ public class ProdInOutServiceImpl extends CommonBaseServiceImpl<ProdInOutMapper,
                 baseDTOs.getBaseDTOs().size() == 0) {
             return "没有可审核单据。";
         }
+        String codes = getMapper().checkWarehouse(baseDTOs.getBaseDTOs());
+        if (!StringUtils.isEmpty(codes)) {
+            throw new BizException(BizExceptionCode.STORAGE_WAREHOUSE_SAMES.getCode(), String.format(BizExceptionCode.STORAGE_WAREHOUSE_SAMES.getMessage(), codes));
+        }
         StringBuffer errorMsg = new StringBuffer();
         for (DocBaseDTO base : baseDTOs.getBaseDTOs()) {
             try {

+ 6 - 0
applications/storage/storage-server/src/main/resources/mapper/ProdInOutMapper.xml

@@ -418,6 +418,12 @@
     update prodinout set creatorId = #{userId} , creatorName=#{userName},createTime=NOW() where pi_id=#{id}
   </update>
 
+  <select id="checkWarehouse" resultType="string" parameterType="com.usoftchina.saas.commons.dto.DocBaseDTO">
+    select GROUP_CONCAT( DISTINCT pi_inoutno) from prodinout left join prodiodetail on pi_id=pd_piid where pd_whcode=pd_inwhcode and pi_id in
+    <foreach collection="list" item="item" open="(" close=")" separator=",">
+      #{item.id}
+    </foreach>
+  </select>
 
     <select id="post" parameterMap="postParamMap" statementType="CALLABLE">
         CALL SP_COMMITPRODINOUT(?, ?, ?, ?, ?)

+ 9 - 0
base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/AccountApi.java

@@ -5,6 +5,7 @@ import com.usoftchina.saas.account.dto.AccountDTO;
 import com.usoftchina.saas.account.dto.AccountRegDTO;
 import com.usoftchina.saas.account.dto.AccountUpdateDTO;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.*;
 
@@ -96,4 +97,12 @@ public interface AccountApi {
      */
     @PostMapping("/bind/roles")
     Result bindRoles(@RequestParam("accountId") Long accountId, @RequestParam("roleIds") String roleIds);
+
+    /**
+     * 二维码分享加入
+     * @param shareAddDTO
+     * @return
+     */
+    @PostMapping("/account/share/join")
+    Result shareJoin(@RequestBody ShareAddDTO shareAddDTO);
 }

+ 14 - 67
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/AccountController.java

@@ -1,9 +1,7 @@
 package com.usoftchina.saas.account.controller;
 
-import com.alibaba.fastjson.JSONObject;
 import com.usoftchina.saas.account.dto.*;
 import com.usoftchina.saas.account.po.Account;
-import com.usoftchina.saas.account.po.Company;
 import com.usoftchina.saas.account.po.RoleResource;
 import com.usoftchina.saas.account.service.AccountService;
 import com.usoftchina.saas.account.service.CompanyService;
@@ -12,17 +10,16 @@ import com.usoftchina.saas.account.vo.CompanyBaseVO;
 import com.usoftchina.saas.auth.client.annotation.IgnoreAuth;
 import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.commons.dto.ListReqDTO;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
 import com.usoftchina.saas.context.BaseContextHolder;
 import com.usoftchina.saas.exception.BizException;
 import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.page.PageDefault;
 import com.usoftchina.saas.page.PageRequest;
 import com.usoftchina.saas.sms.api.SmsApi;
-import com.usoftchina.saas.sms.dto.SmsDTO;
 import com.usoftchina.saas.utils.BeanMapper;
 import com.usoftchina.saas.utils.CollectionUtils;
 import com.usoftchina.saas.utils.RegexpUtils;
-import com.usoftchina.saas.utils.StringUtils;
 import com.usoftchina.sso.api.SsoUserApi;
 import com.usoftchina.sso.api.SsoUserSpaceApi;
 import com.usoftchina.sso.dto.*;
@@ -128,69 +125,7 @@ public class AccountController {
      */
     @PostMapping("/register/add")
     public Result AddAccount(@RequestBody AccountAddDTO accountAddDTO) {
-        String mobile = accountAddDTO.getMobile();
-        Account account = null;
-        // 根据手机号、邮箱、用户名片段判断是否已注册
-        boolean checked = accountService.findByUsernameOrMobileOrEmail(accountAddDTO.getUsername(), accountAddDTO.getMobile(), accountAddDTO.getEmail());
-        //不存在 ——> 保存 , 存在 ——> 更新
-        if (!checked) {
-            account = BeanMapper.map(accountAddDTO, Account.class);
-            account.setEnabled(true);
-            accountService.save(account);
-            if (!accountAddDTO.isHasRegister()) {
-                //1.添加至优软云
-                String password = StringUtils.createInitPassword(mobile.substring(mobile.length() - 3, mobile.length()));
-                Company company = companyService.findByPrimaryKey(BaseContextHolder.getCompanyId());
-                String companyName = company.getName();
-
-                //可能存在开通企业时UU号同步到优软云出错的情况,再重新同步一次
-                if (company.getUu() == null) {
-                    Account accountTmp = accountService.findByPrimaryKey(company.getCreatorId());
-                    ssoUserSpaceApi.registerLogin(companyName, company.getBusinessCode(), accountTmp.getUu());
-                    SsoUserSpaceList ssoUserSpaceList = ssoUserApi.getUserSpacesByMobile(accountTmp.getMobile());
-                    List<SsoUserSpace> ssoUserSpaces = ssoUserSpaceList.getSpaces();
-                    if (ssoUserSpaces.size() > 0) {
-                        for (SsoUserSpace ssoUserspace : ssoUserSpaces) {
-                            if (companyName.equals(ssoUserspace.getSpaceName())) {
-                                company.setUu(ssoUserspace.getSpaceUU());
-                                companyService.updateUUByPrimaryKey(company.getId(), ssoUserspace.getSpaceUU());
-                            }
-                        }
-                    }
-                }
-                SsoResult result = ssoUserApi.add("add", "sp", accountAddDTO.getRealname(), mobile, password, company.getUu());
-                //2.调用短信服务,将密码以短信的形式发送到用户的手机上
-                if (result.isSuccess()) {
-                    SmsDTO smsDTO = new SmsDTO();
-                    smsDTO.setMobile(mobile);
-                    smsDTO.setSignName("优软云");
-                    smsDTO.setTemplateCode(msgTemplateCode);
-                    JSONObject jsonObject = new JSONObject();
-                    jsonObject.put("password", password);
-                    smsDTO.setTemplateParam(jsonObject.toJSONString());
-                    Result sendResult = smsApi.sendRegisterMsg(smsDTO);
-                    if (!sendResult.isSuccess()) {
-                        return sendResult;
-                    }
-                }
-            }
-        }else{
-            Account accountTemp = accountService.findByMobile(accountAddDTO.getMobile());
-            if (accountTemp == null){
-                accountTemp = accountService.findByEmail(accountAddDTO.getEmail());
-            }
-            account = BeanMapper.map(accountAddDTO, Account.class);
-            account.setEnabled(true);
-            account.setId(accountTemp.getId());
-            accountService.updateByPrimaryKeySelective(account);
-        }
-        account = accountService.findByMobile(accountAddDTO.getMobile());
-        //绑定企业
-        accountService.bindCompany(account.getId(), BaseContextHolder.getCompanyId());
-        //绑定角色
-        accountService.bindRoles(account.getId(), accountAddDTO.getRoleIds());
-        accountService.clearCache(account.getId());
-        return Result.success();
+        return accountService.addAccount(accountAddDTO);
     }
 
     /**
@@ -530,4 +465,16 @@ public class AccountController {
         accountService.clearCache(BaseContextHolder.getUserId());
         return Result.success();
     }
+
+    /**
+     * 分享加入
+     * @param shareAddDTO
+     * @return
+     */
+    @PostMapping("/share/join")
+    @IgnoreAuth
+    public Result shareJoin(@RequestBody ShareAddDTO shareAddDTO){
+        accountService.shareJoin(shareAddDTO);
+        return Result.success();
+    }
 }

+ 14 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/RoleController.java

@@ -114,6 +114,20 @@ public class RoleController {
         return Result.success(BeanMapper.mapList(roles, RoleDTO.class));
     }
 
+    @GetMapping("/list/{id}")
+    public Result<List<RoleDTO>> getByCompanyId(@PathVariable("id") Long companyId){
+        List<Role> roles = roleService.findByCompanyId(companyId);
+        if (CollectionUtils.isEmpty(roles)) {
+            return Result.success();
+        }
+        for (int i = 0; i < roles.size(); i++){
+            if (roles.get(i).getType() == 0){
+                roles.remove(i);
+            }
+        }
+        return Result.success(BeanMapper.mapList(roles, RoleDTO.class));
+    }
+
     /**
      * 角色绑定资源
      *

+ 15 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/AccountService.java

@@ -1,10 +1,13 @@
 package com.usoftchina.saas.account.service;
 
 import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.account.dto.AccountAddDTO;
 import com.usoftchina.saas.account.dto.AccountRoleDTO;
 import com.usoftchina.saas.account.po.Account;
 import com.usoftchina.saas.account.po.RoleResource;
+import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.commons.dto.ListReqDTO;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
 import com.usoftchina.saas.page.PageRequest;
 
 import java.util.List;
@@ -202,4 +205,16 @@ public interface AccountService {
      * @param status
      */
     void updateBindCompanyStatus(Long accountId, Long companyId, String status);
+
+    /**
+     * 新增用户,已注册的更新,未注册的后台自动注册
+     * @param accountAddDTO
+     */
+    Result addAccount(AccountAddDTO accountAddDTO);
+
+    /**
+     * 分享加入
+     * @param shareAddDTO
+     */
+    void shareJoin(ShareAddDTO shareAddDTO);
 }

+ 181 - 4
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/AccountServiceImpl.java

@@ -1,21 +1,40 @@
 package com.usoftchina.saas.account.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.usoftchina.saas.account.cache.AccountCache;
+import com.usoftchina.saas.account.dto.AccountAddDTO;
 import com.usoftchina.saas.account.dto.AccountRoleDTO;
 import com.usoftchina.saas.account.mapper.AccountCompanyMapper;
 import com.usoftchina.saas.account.mapper.AccountMapper;
 import com.usoftchina.saas.account.mapper.AccountRoleMapper;
 import com.usoftchina.saas.account.mapper.RoleResourceMapper;
 import com.usoftchina.saas.account.po.Account;
+import com.usoftchina.saas.account.po.Company;
 import com.usoftchina.saas.account.po.Role;
 import com.usoftchina.saas.account.po.RoleResource;
 import com.usoftchina.saas.account.service.AccountService;
+import com.usoftchina.saas.account.service.CompanyService;
 import com.usoftchina.saas.account.service.RoleService;
+import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.commons.dto.ListReqDTO;
+import com.usoftchina.saas.commons.dto.ShareAddDTO;
 import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.page.PageRequest;
+import com.usoftchina.saas.sms.api.SmsApi;
+import com.usoftchina.saas.sms.cache.SmsCache;
+import com.usoftchina.saas.sms.dto.SmsDTO;
+import com.usoftchina.saas.utils.BeanMapper;
+import com.usoftchina.saas.utils.StringUtils;
+import com.usoftchina.sso.api.SsoUserApi;
+import com.usoftchina.sso.api.SsoUserSpaceApi;
+import com.usoftchina.sso.dto.SsoCheckMobile;
+import com.usoftchina.sso.dto.SsoResult;
+import com.usoftchina.sso.dto.SsoUserSpace;
+import com.usoftchina.sso.dto.SsoUserSpaceList;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -23,6 +42,7 @@ import org.springframework.util.DigestUtils;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * @author yingp
@@ -33,18 +53,25 @@ public class AccountServiceImpl implements AccountService {
 
     @Autowired
     private AccountMapper accountMapper;
-
     @Autowired
     private AccountCompanyMapper accountCompanyMapper;
-
     @Autowired
     private AccountRoleMapper accountRoleMapper;
-
     @Autowired
     private RoleService roleService;
-
     @Autowired
     private RoleResourceMapper roleResourceMapper;
+    @Autowired
+    private CompanyService companyService;
+    @Autowired
+    private SsoUserSpaceApi ssoUserSpaceApi;
+    @Autowired
+    private SsoUserApi ssoUserApi;
+    @Autowired
+    private SmsApi smsApi;
+
+    //注册短信模板
+    private final String msgTemplateCode = "SMS_152288990";
 
     @Override
     public boolean save(Account account) {
@@ -214,4 +241,154 @@ public class AccountServiceImpl implements AccountService {
         accountMapper.updateBindCompanyStatus(accountId, companyId, status);
     }
 
+    @Override
+    public Result addAccount(AccountAddDTO accountAddDTO){
+        Account account = new Account();
+        // 根据手机号、邮箱、用户名片段判断是否已注册
+        boolean checked = findByUsernameOrMobileOrEmail(accountAddDTO.getUsername(), accountAddDTO.getMobile(), accountAddDTO.getEmail());
+        //不存在 ——> 保存 , 存在 ——> 更新
+        addOrUpdate(checked, accountAddDTO);
+
+        account = findByMobile(accountAddDTO.getMobile());
+        //绑定企业
+        bindCompany(account.getId(), BaseContextHolder.getCompanyId());
+        //绑定角色
+        bindRoles(account.getId(), accountAddDTO.getRoleIds());
+        clearCache(account.getId());
+        return Result.success();
+    }
+
+    /**
+     * 保存账户: 存在则更新,不存在自动注册
+     * @param checked
+     * @param accountAddDTO
+     */
+    private void addOrUpdate(boolean checked, AccountAddDTO accountAddDTO){
+        Account account = new Account();
+        if (!checked) {
+            account = BeanMapper.map(accountAddDTO, Account.class);
+            account.setEnabled(true);
+            save(account);
+            if (!accountAddDTO.isHasRegister()) {
+                //用户未注册优软云
+                registerAccount(accountAddDTO.getMobile(), accountAddDTO.getRealname());
+            }
+        }else{
+            Account accountTemp = findByMobile(accountAddDTO.getMobile());
+            if (accountTemp == null){
+                accountTemp = findByEmail(accountAddDTO.getEmail());
+            }
+            account = BeanMapper.map(accountAddDTO, Account.class);
+            account.setEnabled(true);
+            account.setId(accountTemp.getId());
+            updateByPrimaryKeySelective(account);
+        }
+    }
+
+    /**
+     * 用户未注册优软云,后台自动注册
+     * @param mobile
+     * @param realname
+     */
+    private void registerAccount(String mobile, String realname){
+        //1.添加至优软云
+        String password = StringUtils.createInitPassword(mobile.substring(mobile.length() - 3, mobile.length()));
+        Company company = companyService.findByPrimaryKey(BaseContextHolder.getCompanyId());
+        String companyName = company.getName();
+
+        //可能存在开通企业时UU号同步到优软云出错的情况,再重新同步一次
+        if (company.getUu() == null) {
+            Account accountTmp = findByPrimaryKey(company.getCreatorId());
+            ssoUserSpaceApi.registerLogin(companyName, company.getBusinessCode(), accountTmp.getUu());
+            SsoUserSpaceList ssoUserSpaceList = ssoUserApi.getUserSpacesByMobile(accountTmp.getMobile());
+            List<SsoUserSpace> ssoUserSpaces = ssoUserSpaceList.getSpaces();
+            if (ssoUserSpaces.size() > 0) {
+                for (SsoUserSpace ssoUserspace : ssoUserSpaces) {
+                    if (companyName.equals(ssoUserspace.getSpaceName())) {
+                        company.setUu(ssoUserspace.getSpaceUU());
+                        companyService.updateUUByPrimaryKey(company.getId(), ssoUserspace.getSpaceUU());
+                    }
+                }
+            }
+        }
+        SsoResult result = ssoUserApi.add("add", "sp", realname, mobile, password, company.getUu());
+        //2.调用短信服务,将密码以短信的形式发送到用户的手机上
+        if (result.isSuccess()) {
+            SmsDTO smsDTO = new SmsDTO();
+            smsDTO.setMobile(mobile);
+            smsDTO.setSignName("优软云");
+            smsDTO.setTemplateCode(msgTemplateCode);
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("password", password);
+            smsDTO.setTemplateParam(jsonObject.toJSONString());
+            smsApi.sendMsg(smsDTO);
+        }
+    }
+
+    /**
+     * 分享加入
+     * @param shareAddDTO
+     */
+    @Override
+    public void shareJoin(ShareAddDTO shareAddDTO) {
+        String mobile = shareAddDTO.getMobile();
+        String realname = shareAddDTO.getUsername();
+        Long companyId = shareAddDTO.getCompanyId();
+        //1.校验短信验证码是否正确
+        validSmsCode(shareAddDTO.getMobile(), shareAddDTO.getValidCode());
+
+
+
+        //2.开通
+        //2.1构造AccountAddDTO对象
+        AccountAddDTO accountAddDTO = new AccountAddDTO();
+        accountAddDTO.setUsername(mobile);
+        accountAddDTO.setMobile(mobile);
+        accountAddDTO.setRealname(realname);
+        accountAddDTO.setRoleIds(shareAddDTO.getRoleId());
+        //2.2增加用户
+        //根据手机号、邮箱、用户名片段判断是否已注册
+        boolean checked = findByUsernameOrMobileOrEmail(accountAddDTO.getUsername(), accountAddDTO.getMobile(), accountAddDTO.getEmail());
+        if (!checked){
+            SsoCheckMobile ssoCheckMobile = ssoUserApi.checkMobile(mobile);
+            if (ssoCheckMobile.isHasRegister()){
+                accountAddDTO.setHasRegister(true);
+            }
+        }else {
+            /* 是否已加入企业 */
+            Account account = findByMobile(mobile);
+            boolean hasBind = companyService.hasBind(account.getId(), companyId);
+            if (hasBind){
+                throw new BizException(ExceptionCode.HAS_BIND_COMPANY);
+            }
+        }
+
+        //不存在 ——> 保存 , 存在 ——> 更新
+        addOrUpdate(checked, accountAddDTO);
+
+        Account account = findByMobile(accountAddDTO.getMobile());
+        //绑定企业
+        bindCompany(account.getId(), companyId);
+        //绑定角色
+        bindRoles(account.getId(), accountAddDTO.getRoleIds());
+        //清除缓存
+        clearCache(account.getId());
+    }
+
+    /**
+     * 校验短信验证码准确性
+     * @param mobile
+     * @param smsCode
+     */
+    private void validSmsCode(String mobile, String smsCode){
+        SmsCache smsCache = SmsCache.of(mobile);
+        Optional<String> optional = smsCache.getCache();
+        if (!optional.isPresent()){
+            throw new BizException(ExceptionCode.SMS_VALIDCODE_EXPIRE);
+        }
+        if (!optional.get().equals(smsCode)){
+            throw new BizException(ExceptionCode.SMS_VALIDCODE_ERROR);
+        }
+    }
+
 }

+ 11 - 1
base-servers/account/account-server/src/main/resources/mapper/AccountMapper.xml

@@ -208,7 +208,17 @@
     </select>
     <select id="findByUsernameOrMobileOrEmail" resultType="int">
         SELECT COUNT(*) FROM AC_ACCOUNT
-        WHERE USERNAME = #{username} OR MOBILE = #{mobile} OR EMAIL = #{email};
+        <where>
+            <if test="username != null">
+                username = #{username}
+            </if>
+            <if test="email != null">
+                or email = #{email}
+            </if>
+            <if test="mobile != null">
+                or mobile = #{mobile}
+            </if>
+        </where>
     </select>
     <update id="updateBindCompanyStatus">
         UPDATE AC_ACCOUNT_COMPANY SET STATUS = #{status} WHERE ACCOUNT_ID = #{accountId} AND COMPANY_ID = #{companyId}

+ 13 - 0
base-servers/auth/auth-server/src/test/java/com/usoftchina/saas/auth/controller/AuthControllerTest.java

@@ -14,6 +14,8 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.test.web.servlet.MvcResult;
 
+import javax.servlet.http.Cookie;
+
 @RunWith(SpringRunner.class)
 @SpringBootTest
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -45,4 +47,15 @@ public class AuthControllerTest extends BaseControllerTest {
         System.out.println(result.getData());
     }
 
+    @Test
+    public void testC_info() throws Exception {
+        Cookie cookie = new Cookie("uid", "4sjrtiHZOu38BaF-9lOyB1jEPXOxBgJ_3jjuugBiDcZs9xlBhPHqdaypVsfMCD42Vnkf8n4lqYvq5UwbButjlIsnvRvw8GWLSh_G4XeYdKCvR9dO6lD3bGUZMIIvck0gAhKf_sazt4Ao3D8eMaLvwyGu0s6-AvNpWa6hRfvwM4WA-rHhu1IugVmtE5FD446qTiXl7A9xbA3q5jIR8Mqj4g8MVV08cV8AYZ0ZQDDiEWgk7tBzsXkkcptG0ZPY-nlEuEgWX8zhzuERmvXea9a7aM4LwX0BNcyJrOFeBz-NI6Tdqo-nw1E__RFznZaAOsHubjeLkyqynezPlXsHpvzanlG9LKqUXUHdZ7TFiKtLyK7ZDr2EcUVejn5UJ2c3cpJZ0_h6242O_E7Ojva4vGDcmbWQ_Q6MbFdG39WDM3kfsYibVgizgUxA45CFO657MQVd03DeE1XfiyZ5ohVN27U7-suyv4JeA_uXkzhEPAQRUkiG5ldUYSF0Q-7y8vPTShgx02Ku5m7IvnMQK87AKx1zalO-WJGw6e1-YbygLbCUdz0QlKUUdPmdfr9QNbnBrO0.");
+        MvcResult mvcResult = mockMvc.perform(get("/info")
+                .cookie(cookie))
+                .andExpect(isSuccess())
+                .andReturn();
+        Result<AuthDTO> result = result(mvcResult, AuthDTO.class);
+        System.out.println("result:========" + result.getData());
+    }
+
 }

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

@@ -186,6 +186,9 @@ auth:
     - /ws/**
     - /api/file/download
     - /api/commons/excel/import/templet
+    - /api/commons/share/**
+    - /api/account/role/list/**
+    - /api/account/account/share/join
   cookie:
     name: uid
     secret-key: 0taQcW073Z7G628g5H

+ 4 - 0
base-servers/sms/sms-api/pom.xml

@@ -38,6 +38,10 @@
             <groupId>io.github.openfeign.form</groupId>
             <artifactId>feign-form-spring</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
     </dependencies>
 
 

+ 2 - 2
base-servers/sms/sms-api/src/main/java/com.usoftchina.saas.sms.api/SmsApi.java → base-servers/sms/sms-api/src/main/java/com/usoftchina/saas/sms/api/SmsApi.java

@@ -13,6 +13,6 @@ public interface SmsApi {
      * 注册成功发送手机短信
      * @param smsDTO
      */
-    @PostMapping(value = "/msg/register")
-    Result sendRegisterMsg(@RequestBody SmsDTO smsDTO);
+    @PostMapping(value = "/msg/send")
+    Result sendMsg(@RequestBody SmsDTO smsDTO);
 }

+ 86 - 0
base-servers/sms/sms-api/src/main/java/com/usoftchina/saas/sms/cache/SmsCache.java

@@ -0,0 +1,86 @@
+package com.usoftchina.saas.sms.cache;
+
+import com.usoftchina.saas.cache.BaseRedisCache;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+/**
+ * @Description 短信验证码
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+public class SmsCache<K, V> extends BaseRedisCache<String, String> {
+
+    private String mobile;
+
+    private static final RedisTemplate<String, String> REDIS_TEMPLATE = SpringContextHolder.getBean("redisTemplate", RedisTemplate.class);
+
+    private SmsCache() {
+        super(() -> REDIS_TEMPLATE);
+    }
+
+    public static SmsCache of(String mobile){
+        SmsCache cache = new SmsCache();
+        cache.mobile = mobile;
+        return cache;
+    }
+
+    @Override
+    protected String key() {
+        return generatePublicKey("sms", this.mobile);
+    }
+    protected BoundValueOperations<String, String> getBoundValueOperations() {
+        RedisTemplate<String, String> redisTemplate = super.getRedisTemplate();
+        redisTemplate.setValueSerializer(new StringRedisSerializer());
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        return redisTemplate.boundValueOps(key());
+    }
+
+    @Override
+    public Optional<String> getCache() {
+        String value = this.getBoundValueOperations().get();
+        if (!StringUtils.isEmpty(value)){
+            return Optional.of(value);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    protected Supplier<String> getSupplier() {
+        return null;
+    }
+
+    @Override
+    public void set(String value) {
+        this.getBoundValueOperations().set(value);
+    }
+
+    @Override
+    public void set(String value, int seconds) {
+        this.getBoundValueOperations().set(value, seconds, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 根据缓存中的key 清除
+     */
+    @Override
+    public void clear() {
+        super.clear();
+    }
+
+    /**
+     * 根据缓存中的key 清除
+     */
+    public void del(String key){
+        this.getRedisTemplate().delete(key);
+    }
+
+}

+ 1 - 1
base-servers/sms/sms-server/src/main/java/com/usoftchina/saas/sms/controller/SmsController.java

@@ -19,7 +19,7 @@ public class SmsController {
     @Autowired
     private SmsService smsService;
 
-    @PostMapping("/msg/register")
+    @PostMapping("/msg/send")
     public Result sendRegisterMsg(@RequestBody SmsDTO smsDTO){
         try {
             smsService.sendMessage(smsConfig, smsDTO);

+ 1 - 1
base-servers/sms/sms-server/src/test/java/com/usoftchina/saas/sms/api/SmsApiTest.java

@@ -36,7 +36,7 @@ public class SmsApiTest {
         JSONObject jsonObject = new JSONObject();
         jsonObject.put("password", password);
         smsDTO.setTemplateParam(jsonObject.toJSONString());
-        Result sendResult = smsApi.sendRegisterMsg(smsDTO);
+        Result sendResult = smsApi.sendMsg(smsDTO);
         System.out.println(sendResult.getCode() + "========" + sendResult.getMessage());
     }
 

+ 48 - 0
base-servers/sms/sms-server/src/test/java/com/usoftchina/saas/sms/cache/SmsCacheTest.java

@@ -0,0 +1,48 @@
+package com.usoftchina.saas.sms.cache;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Optional;
+
+/**
+ * @Description TODO
+ * @Author chenwei
+ * @Date 2018/12/19
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class SmsCacheTest {
+
+    private final String mobile = "18702604854";
+    private final String mobile2 = "18702604709";
+
+    @Test
+    public void testA_set(){
+        SmsCache cache = SmsCache.of(mobile2);
+        cache.set("123456", 60 * 60);
+        Optional<String> optional = cache.getCache();
+        if (optional.isPresent()){
+            System.out.println(optional.toString());
+            System.out.println(mobile2 + "value:\t===========" + optional.get());
+        }else {
+            System.out.println("empty");
+        }
+    }
+
+    @Test
+    public void testB_del(){
+        SmsCache cache = SmsCache.of(mobile);
+        //cache.set("1234");
+        Optional<String> optional = cache.getCache();
+        System.out.println(optional.isPresent());
+        if (optional.isPresent()){
+            System.out.println(mobile + "value:\t===========" + optional.get());
+        }else {
+            System.out.println("empty");
+        }
+    }
+
+}

+ 3 - 1
framework/core/src/main/java/com/usoftchina/saas/exception/ExceptionCode.java

@@ -48,7 +48,9 @@ public enum ExceptionCode implements BaseExceptionCode {
     USER_COMPANY_EXIST(53007, "企业已存在账户"),
     ROLE_HAS_USE(54030, "存在已使用该角色的账户,不允许删除"),
     APPLY_DOING_EXIST(54031, "已存在待处理的加入申请"),
-    HAS_BIND_COMPANY(54032, "已绑定该企业"),
+    HAS_BIND_COMPANY(54032, "已加入企业"),
+    SMS_VALIDCODE_EXPIRE(54033, "短信验证码已过期"),
+    SMS_VALIDCODE_ERROR(54034, "短信验证码错误"),
 
     // 文件相关
     FOLDER_NOT_EXISTS(55000, "文件夹不存在"),

+ 6 - 0
framework/core/src/main/java/com/usoftchina/saas/utils/StringUtils.java

@@ -59,4 +59,10 @@ public abstract class StringUtils extends org.springframework.util.StringUtils{
         value.append(suffix);
         return value.toString();
     }
+
+    public static String createValidCode(int len){
+        int max = (int) Math.pow(10, len) - 1;
+        int min = (int) Math.pow(10, len - 1);
+        return String.valueOf(new Random().nextInt(max) % (max - min + 1) + min);
+    }
 }

+ 13 - 7
frontend/saas-portal-web/src/components/conenter/addenterprise.vue

@@ -75,11 +75,11 @@
                     <ul style="padding:0">
                         <li>
                             <span class="qy-biaoti"><span class="xingxing marght">*</span>查找企业</span>
-                            <input @blur.prevent="Testingqyname" ref="lookupqyname" class="inpind" type="text" value="" placeholder="输入企业名称或管理员">
+                            <input @blur.prevent="Testingqyname" @keyup.13="Testingqyname" ref="lookupqyname" class="inpind" type="text"  placeholder="输入企业名称或管理员">
                             <span class="warning" ref="warningqyname"></span>
                         </li>
                         <!-- 匹配企业后显示的内容 -->
-                        <li class="hied" :class= "{showlookup:islookup}">
+                        <li v-if="isqylist" class="hied" :class= "{showlookup:islookup}">
                             <div class="lookup">
                                 <ul>
                                     <li v-for="(d, i) in arr" :key="i" @click="qylist(i)" :class="{'hui':newindex === i}">
@@ -121,8 +121,8 @@ import { setTimeout } from 'timers';
                 qymingzi: false,//企业名是否注册
                 Email: '',
                 mytoken: Session.get(),//本地储存的用户信息
-                reg: new RegExp(/[\@\#\$\%\&\*!\¥]/),//非法字符
-                regname:new RegExp(/[\@\#\$\%\&\*!\¥0-9]/),//非法字符加数字
+                reg: new RegExp(/[\@\#\$\%\&\*!\¥]/),//非法字符
+                regname:new RegExp(/[\@\#\$\%\&\*!\¥0-9a-zA-Z]/),//非法字符加数字加中文
                 isaddress: false,//公司地址验证
                 isaddressname: false,//公司地址是否为空
                 isname: true,//姓名验证
@@ -143,6 +143,7 @@ import { setTimeout } from 'timers';
                 isregname:false,
                 companyId:null,
                 admin:null,
+                isqylist:true,
                 arr:[]
             }
         },
@@ -196,6 +197,7 @@ import { setTimeout } from 'timers';
             },
             //检测企业名称2
             Testingqyname(){
+                this.$refs.lookupqyname.blur();
                 let qyname = this.$refs.lookupqyname.value.replace(/\s+/g, "");//企业名字
                 let token = this.mytoken.token;
                 if (qyname == '') {
@@ -217,7 +219,9 @@ import { setTimeout } from 'timers';
                             this.newindex = '';
                             this.arr = res.data.data;
                             this.$refs.warningqyname.innerHTML = '<img style="width:14px" src="/static/img/ok.png" alt="">';
-                            this.islookup = true;   
+                            this.islookup = true;
+                            this.isqylist = true;
+                            this.companyId = null;
                         } else if (res.data.success == false && res.data.message == '公司不存在') {
                             this.$refs.warningqyname.innerHTML = '<img style="width:14px" src="/static/img/warning.png" alt=""> 该企业不存在';
                             this.islookup = false; 
@@ -253,7 +257,7 @@ import { setTimeout } from 'timers';
                 } else {
                     this.isTestingname = true;
                     if (this.regname.test(name)) {
-                        this.$refs.warningname.innerHTML = '<img style="width:14px" src="/static/img/warning.png" alt=""> 姓名不能包含符号、数字等非法字符';
+                        this.$refs.warningname.innerHTML = '<img style="width:14px" src="/static/img/warning.png" alt=""> 姓名不能包含符号、数字、英文等非法字符';
                         this.isregname = false;
                     } else {
                         this.$refs.warningname.innerHTML = '<img style="width:14px" src="/static/img/ok.png" alt="">';
@@ -265,7 +269,9 @@ import { setTimeout } from 'timers';
             qylist(i){
                 this.companyId = this.arr[i].id,
                 this.admin = this.arr[i].admin,
-                this.newindex = i
+                this.newindex = i,
+                this.$refs.lookupqyname.value = this.arr[i].name,
+                this.isqylist = false
             },
             //加入企业提交按钮
             Submission(){

+ 23 - 3
frontend/saas-portal-web/src/components/conenter/enterprise.vue

@@ -17,6 +17,7 @@
             </div>
             <div class="collapse navbar-collapse navbar-right" role="navigation">
                 <ul id="nav" class="nav navbar-nav menu">
+                    <!-- <li><router-link to="/invitation">邀请</router-link></li> -->
                     <li><router-link to="/home"><a href="#" @click="setTurnHome"><span style="color: white">首页</span></a></router-link></li>
                     <li><a href="https://uas.usoftchina.com/about" target="_blank"><span>关于我们</span></a></li>
                     <li style="margin-left:30px;margin-top: 13px;cursor: pointer;">
@@ -187,7 +188,7 @@ import { setTimeout } from 'timers';
                 ],
                 arr: [],
                 listtotal:1,
-                size:10,//每页显示数量
+                size: 10,//每页显示数量
             }
         },
         mounted(){
@@ -240,7 +241,15 @@ import { setTimeout } from 'timers';
                     })
                     .then(res=>{
                         if (res.data.success) {
-                            this.arr = res.data.data.list;
+                            let list = res.data.data.list;
+                            for (let i = 0; i < list.length - 1; i++) {
+                                for (let j = 0; j < list.length - i - 1; j++) {
+                                    if (list[i].companyName == list[j].companyName && list[i].status == 0) {
+                                        delete list[i]
+                                    }
+                                }
+                                this.arr.push(list[i])
+                            }
                             this.listtotal = res.data.data.total;
                             this.$store.state.ishongdian = false;
                         }
@@ -297,7 +306,18 @@ import { setTimeout } from 'timers';
                 })
                 .then(res=>{
                     if (res.data.success) {
-                        this.arr = res.data.data.list;
+                        // this.arr = res.data.data.list;
+                        let arr2 = [];
+                        let list = res.data.data.list;
+                        for (let i = 0; i < list.length - 1; i++) {
+                            for (let j = 0; j < list.length - i - 1; j++) {
+                                if (list[i].companyName == list[j].companyName && list[i].status == 0) {
+                                    delete list[i]
+                                }
+                            }
+                            arr2.push(list[i])
+                        }
+                        this.arr = arr2
                     }
                 })
             },

+ 320 - 0
frontend/saas-portal-web/src/components/conenter/invitation.vue

@@ -0,0 +1,320 @@
+<template>
+    <div class="invitation">
+        <img src="/static/img/beijing.png" alt="">
+        <div class="centent">
+            <img src="/static/img/assets/logo@2x.png" alt="">
+            <p class="inv-logo">U企云服</p>
+            <div class="inv-title">
+                <p>{{enterprise.username}}</p>
+                <p>
+                    <span class="inv-text">邀请您加入</span>
+                    <span>{{enterprise.companyName}}</span>
+                    <span class="inv-text">SAAS服务</span>
+                </p>
+            </div>
+            <input type="text" ref="phone" @blur="phone" placeholder="请输入手机号">
+            <div class="Verification">
+                <input type="text" ref="Verification" @change="validCode" placeholder="请输入验证码">
+                <span v-if="isobtaincode" class="xs" @click="Obtaincode">获取验证码</span>
+                <span v-if="!isobtaincode" ref="obtaincode">{{time}}</span>
+            </div>
+            <input type="text" ref="name" @blur="name" placeholder="请输入姓名">
+            <select class="role" ref="role" @blur="roles">
+                <option value="">岗位角色</option>
+                <option v-for="(d,i) in arr" :key="i" :value=d.id>{{d.name}}</option>
+            </select>
+            <button class="login" @click="login">提交</button>
+        </div>
+        <div class="bottom">
+            <p>U企云服|电子行业企业管理云端解决方案</p>
+            <p>版权所有:深圳市优软科技有限公司 Copyright @ 2017 All Rights Reserved</p>
+        </div>
+    </div>
+</template>
+
+<script>
+import Session from '@/utils/session'
+import { setTimeout } from 'timers';
+    export default {
+        data(){
+            return {
+                isobtaincode:true,
+                time:60,
+                isphone:false,
+                isregphone:false,
+                isname:false,
+                isregname:false,
+                regname:new RegExp(/[\@\#\$\%\&\*!!\¥0-9a-zA-Z]/),//非法字符加数字加中文
+                isvalidCode:false,
+                isrole:false,
+                enterprise:[],
+                arr:[],
+                roleId:''
+            }
+        },
+        created(){
+            this.$store.state.isinvitation = false;
+            this.param();//获取页面参数
+        },
+        mounted(){
+            //获取角色
+            setTimeout(()=>{
+                this.role()
+            },800)
+        },
+        destroyed(){
+            this.$store.state.isinvitation = true
+        },
+        methods:{
+            //验证手机
+            phone(){
+                let phone = this.$refs.phone.value;//手机 
+                let reg = new RegExp('^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$');
+                if (phone == '') {
+                    this.$message.error('手机号码不能为空');
+                    this.isphone = false;
+                } else {
+                    this.isphone = true;
+                    if (!reg.test(phone)) {
+                        this.$message.error('请输入正确的手机号码');
+                        this.isregphone = false;
+                    } else {
+                        this.isregphone = true;
+                    }
+                }
+            },
+            //验证姓名
+            name(){
+                let name = this.$refs.name.value;
+                if (name == '') {
+                    this.$message.error('姓名不能为空')
+                    this.isname = false;
+                } else {
+                    this.isname = true;
+                    if (this.regname.test(name)) {
+                        this.$message.error('姓名不能包含符号、数字、英文等非法字符');
+                        this.isregname = false
+                    } else {
+                        this.isregname = true
+                    }
+                }
+            },
+            //验证码
+            validCode(){
+                let Verification = this.$refs.Verification.value;//验证码
+                if (Verification == '') {
+                    this.$message.error('请输入验证码')
+                    this.isvalidCode = false;
+                } else {
+                    this.isvalidCode = true;
+                }
+            },
+            // 验证角色
+            roles(){
+                let roleid = this.$refs.role.value;//角色
+                if (roleid == '') {
+                    this.$message.error('请选择岗位角色');
+                    this.isrole = false;
+                } else {
+                    this.isrole = true;
+                }
+            },
+            // 获取验证码
+            Obtaincode(){
+                if (!this.isphone) {
+                    this.$message.error('手机号码不能为空');
+                } else if (!this.isregphone){
+                    this.$message.error('请输入正确的手机号码');
+                } else {
+                    let phone = this.$refs.phone.value;//手机 
+                    this.$ajax({
+                        url:'http://192.168.253.31:8560/api/commons/share/getSmsCode',
+                        method:'POST',
+                        data:{
+                            mobile:phone
+                        },
+                        headers:{
+                            "Authorization":Session.getToken(),
+                        }
+                    })
+                    .then(res=>{
+                        console.log(res)
+                        if (res.data.success) {
+                            this.isobtaincode = false;
+                            this.settime()
+                        }
+                    })
+                }
+            },
+            // 提交
+            login(){
+                let phone = this.$refs.phone.value;//手机
+                let Verification = this.$refs.Verification.value;//验证码
+                let name = this.$refs.name.value;//姓名
+                let roleid = this.$refs.role.value;//角色
+                if (!this.isphone) {
+                    this.$message.error('手机号码不能为空');
+                } else if (!this.isregphone){
+                    this.$message.error('请输入正确的手机号码');
+                } else if (!this.isname) {
+                    this.$message.error('姓名不能为空')
+                } else if (!this.isregname) {
+                    this.$message.error("姓名不能包含符号、数字、英文等非法字符")
+                } else if(!this.isvalidCode){
+                    this.$message.error("请输入验证码")
+                } else if(!this.isrole){
+                    this.$message.error('请选择岗位角色');
+                } else {
+                    this.$ajax({
+                        url:'http://192.168.253.31:8560/api/commons/share/submit',
+                        method:'POST',
+                        data:{
+                            username:name,
+                            mobile:phone,
+                            companyId:this.enterprise.companyId,
+                            roleId:roleid,
+                            validCode:Verification,
+                        }
+                    })
+                }
+            },
+            //倒计时
+            settime(){
+                if (this.time == 0) {
+                    this.isobtaincode = true;
+                    clearTimeout(times)
+                } else {
+                    this.time--
+                }
+                let times = setTimeout(()=>{
+                    this.settime(this.time)
+                },1000)
+            },
+            //获取角色
+            role(){
+                let companyId = this.enterprise.companyId;
+                this.$ajax({
+                    url:'http://192.168.253.31:8560/api/account/role/list'+`?id=${companyId}`,
+                    headers:{
+                        "Authorization":Session.getToken(),
+                    }
+                })
+                .then(res=>{
+                    if (res.data.success) {
+                        this.arr = res.data.data
+                    }
+                })
+            },
+            //获取页面参数
+            param(){
+                let param = "dXNlcm5hbWU96ZmI54KcJmNvbXBhbnlJZD0yNjImdGltZXN0bWFwPTE1NDUyODAyODU1MjQmZGVsYXk9MSZjb21wYW55TmFtZT3pmYjngpw."
+                this.$ajax({
+                    url:"http://192.168.253.31:8560/api/commons/share/valid/param"+`?param=${param}`,
+                    method:'POST',
+                    headers:{
+                        "Authorization":Session.getToken(),
+                    }
+                })
+                .then(res=>{
+                    if (res.data.success) {
+                        this.enterprise = res.data.data;
+                    }
+                })
+            },
+        }
+    }
+</script>
+
+<style scoped>
+.invitation > img{
+    width: 100%;
+}
+.centent {
+    width: 352px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    text-align: center
+}
+.inv-logo {
+    font-family: PingFangSC-Medium;
+    font-size: 26px;
+    color: #FFFFFF;
+    letter-spacing: 3.25px;
+}
+
+.centent > input {
+    width: 100%;
+    margin-bottom: 16px;
+    opacity: 0.95;
+    background: #FFFFFF;
+    box-shadow: 0 2px 4px 0 #3C8EFF;
+    font-size: 15px;
+    padding: 3px 0px 3px 5px;
+    border: 0;
+}
+.inv-title {
+    text-align: left;
+    margin-top: 37px;
+    margin-bottom: 40px;
+}
+.inv-title > p{
+    font-family: PingFangSC-Medium;
+    font-size: 18px;
+    color: #FFFFFF;
+    letter-spacing: 2.25px;
+    text-shadow: 0 2px 4px #1B5099;
+}
+.inv-title >p:nth-child(1) {
+    margin-bottom: 16px;
+}
+.inv-text {
+    font-family: PingFangSC-Regular;
+}
+.login {
+    background: #004CE0;
+    width: 100%;
+    border: 0;
+    height: 36px;
+}
+.role {
+    width: 100%;
+    margin-bottom: 32px;
+    padding: 3px 0px;
+}
+.Verification {
+    border: 0;
+    opacity: 0.95;
+    background: #FFFFFF;
+    box-shadow: 0 2px 4px 0 #3C8EFF;
+    margin-bottom: 16px;
+}
+.Verification > input {
+    width: 68%;
+    border: 0;
+    font-size: 15px;
+    padding: 3px 0px 3px 5px;
+}
+.Verification > span {
+    width: 30%;
+    display: inline-block;
+    border-left: 1px solid #2F86FE;
+    font-family: PingFangSC-Regular;
+    font-size: 12px;
+    color: #2F86FE;
+    letter-spacing: 1.5px;
+}
+.bottom {
+    height: 100px;
+    background: #FAFCFF;
+    text-align: center;
+    padding: 27px 0px;
+}
+.bottom > p{
+    font-family: PingFangSC-Regular;
+    font-size: 16px;
+    color: #666666;
+    letter-spacing: 2px;
+}
+</style>

+ 4 - 1
frontend/saas-portal-web/src/pages/index/index.vue

@@ -4,7 +4,7 @@
       <div class="loadingtxt">加载中...</div>
     </div>
     <router-view/>
-    <footers></footers>
+    <footers v-if="isinvitation"></footers>
   </div>
 </template>
 <script>
@@ -22,6 +22,9 @@ export default {
   computed:{
     isloading:function(){
       return this.$store.state.isloading
+    },
+    isinvitation:function(){
+      return this.$store.state.isinvitation
     }
   }
 }

+ 6 - 0
frontend/saas-portal-web/src/router/index.js

@@ -5,6 +5,7 @@ import enterprise from '../components/conenter/enterprise.vue'//企业设置首
 import company from '../components/conenter/company.vue'//企业列表
 import addenterprise from '../components/conenter/addenterprise.vue'//添加公司
 import details from '../components/conenter/details.vue'//企业详细
+import invitation from '../components/conenter/invitation.vue'//邀请页面
 
 Vue.use(Router)
 
@@ -19,6 +20,11 @@ export default new Router({
       path: '*',
       redirect:'/home'
     },
+    {
+      path:'/invitation',
+      name:'invitation',
+      component:invitation
+    },
     {
       path: '/enterprise',
       name: 'enterprise',

+ 1 - 0
frontend/saas-portal-web/src/store/index.js

@@ -8,6 +8,7 @@ export default new Vuex.Store({
         isproblem: '',//常见问题
         isloading:false,
         ishongdian:false,
+        isinvitation:true,
     },
     mutations:{
          Logintrue(state) {

+ 1 - 0
frontend/saas-portal-web/static/MP_verify_BMkQAHplMGROBlAn.txt


BIN
frontend/saas-portal-web/static/img/beijing.png


+ 0 - 1
frontend/saas-web/app.json

@@ -20,7 +20,6 @@
         "font-awesome",
         "ux",
         "modern-locale",
-        "charts",
         "font-saas"
     ],
     "locale":"zh_CN",

+ 1 - 1
frontend/saas-web/app/model/document/bomdetail.js

@@ -7,7 +7,7 @@ Ext.define('saas.model.document.bomdetail', {
         { name: 'bd_sonid', type: 'int' },
         { name: 'bd_soncode', type: 'string' },
         { name: 'bd_unit', type: 'string' },
-        { name: 'bd_baseqty', type: 'string' },
+        { name: 'bd_baseqty', type: 'float' },
         { name: 'bd_replace', type: 'string' },
         { name: 'bd_remark', type: 'string' },
         { name: 'companyid', type: 'int' },

+ 1 - 1
frontend/saas-web/app/model/sale/SaleOutDetail.js

@@ -10,7 +10,7 @@ Ext.define('saas.model.sale.SaleOutDetail', {
         { name: 'pr_detail', type: 'string' }, // 名称
         { name: 'pr_orispeccode', type: 'string' }, // 型号
         { name: 'pr_spec', type: 'string' }, // 规格
-        { name: 'pd_outqty', type: 'int' }, // 出货数量
+        { name: 'pd_outqty', type: 'float' }, // 出货数量
         { name: 'pr_unit', type: 'string' }, // 单位
         { name: 'pd_whid', type: 'int' }, // 仓库id
         { name: 'pd_whcode', type: 'float' }, // 仓库编号

+ 10 - 38
frontend/saas-web/app/model/stock/OtherIn.js

@@ -12,45 +12,17 @@ Ext.define('saas.model.stock.OtherIn', {
         { name: 'pr_spec', type: 'string' }, // 规格
         { name: 'pd_inqty', type: 'float' }, // 数量
         { name: 'pr_unit', type: 'string' }, // 单位
-        { name: 'pd_netprice', type: 'float' }, // 单价
-        { name: 'pd_orderprice', type: 'float', // 含税单价
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_netprice') * (1 + rec.get('pd_taxrate') / 100);
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 4, false));
-            // },
-            // depends: ['pd_netprice', 'pd_taxrate']
+        { name: 'pd_price', type: 'float'}, // 金额
+        { name: 'pd_total', type: 'float', // 金额
+            convert: function(v, rec) {
+                var t = rec.get('pd_price') * rec.get('pd_inqty');
+                return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
+            },
+            depends: ['pd_price', 'pd_inqty']
         },
-        { name: 'pd_nettotal', type: 'float', // 金额
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_netprice') * rec.get('pd_outqty');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_netprice', 'pd_outqty']
-        },
-        { name: 'pd_taxrate', type: 'float' }, // 税率
-        { name: 'pd_taxamount', type: 'float', // 税额
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_ordertotal') - rec.get('pd_nettotal');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_ordertotal', 'pd_nettotal']
-        },
-        { name: 'pd_ordertotal', type: 'float', // 价税合计
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_orderprice') * rec.get('pd_outqty');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_orderprice', 'pd_outqty']
-        },
-        { name: 'pd_whid', type: 'int' }, // 拨出仓库id
-        { name: 'pd_whcode', type: 'string' }, // 拨出仓库编号
-        { name: 'pd_whname', type: 'string' }, // 拨出仓库
-        { name: 'pd_inwhid', type: 'int' }, // 拨入仓库id
-        { name: 'pd_inwhcode', type: 'string' }, // 拨入仓库编号
-        { name: 'pd_inwhname', type: 'string' }, // 拨入仓库
-        { name: 'pd_ioid', type: 'int' }, // 验收明细id
-        { name: 'iocode', type: 'string' }, // 验收单号
-        { name: 'iodetno', type: 'int' }, // 验收序号
+        { name: 'pd_whid', type: 'int' }, // 仓库id
+        { name: 'pd_whcode', type: 'string' }, // 仓库编号
+        { name: 'pd_whname', type: 'string' }, // 仓库
         { name: 'pd_remark', type: 'string' }, // 备注
 
         { name: 'pd_text1', type: 'string' },

+ 10 - 38
frontend/saas-web/app/model/stock/OtherOut.js

@@ -12,45 +12,17 @@ Ext.define('saas.model.stock.OtherOut', {
         { name: 'pr_spec', type: 'string' }, // 规格
         { name: 'pd_outqty', type: 'float' }, // 数量
         { name: 'pr_unit', type: 'string' }, // 单位
-        { name: 'pd_netprice', type: 'float' }, // 单价
-        { name: 'pd_orderprice', type: 'float', // 含税单价
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_netprice') * (1 + rec.get('pd_taxrate') / 100);
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 4, false));
-            // },
-            // depends: ['pd_netprice', 'pd_taxrate']
+        { name: 'pd_price', type: 'float'}, // 成本单价
+        { name: 'pd_total', type: 'float', // 金额
+            convert: function(v, rec) {
+                var t = rec.get('pd_price') * rec.get('pd_outqty');
+                return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
+            },
+            depends: ['pd_price', 'pd_outqty']
         },
-        { name: 'pd_nettotal', type: 'float', // 金额
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_netprice') * rec.get('pd_outqty');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_netprice', 'pd_outqty']
-        },
-        { name: 'pd_taxrate', type: 'float' }, // 税率
-        { name: 'pd_taxamount', type: 'float', // 税额
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_ordertotal') - rec.get('pd_nettotal');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_ordertotal', 'pd_nettotal']
-        },
-        { name: 'pd_ordertotal', type: 'float', // 价税合计
-            // convert: function(v, rec) {
-            //     var t = rec.get('pd_orderprice') * rec.get('pd_outqty');
-            //     return Number(saas.util.BaseUtil.numberFormat(t, 2, false));
-            // },
-            // depends: ['pd_orderprice', 'pd_outqty']
-        },
-        { name: 'pd_whid', type: 'int' }, // 拨出仓库id
-        { name: 'pd_whcode', type: 'string' }, // 拨出仓库编号
-        { name: 'pd_whname', type: 'string' }, // 拨出仓库
-        { name: 'pd_inwhid', type: 'int' }, // 拨入仓库id
-        { name: 'pd_inwhcode', type: 'string' }, // 拨入仓库编号
-        { name: 'pd_inwhname', type: 'string' }, // 拨入仓库
-        { name: 'pd_ioid', type: 'int' }, // 验收明细id
-        { name: 'iocode', type: 'string' }, // 验收单号
-        { name: 'iodetno', type: 'int' }, // 验收序号
+        { name: 'pd_whid', type: 'int' }, // 仓库id
+        { name: 'pd_whcode', type: 'string' }, // 仓库编号
+        { name: 'pd_whname', type: 'string' }, // 仓库
         { name: 'pd_remark', type: 'string' }, // 备注
 
         { name: 'pd_text1', type: 'string' },

+ 0 - 4
frontend/saas-web/app/view/core/chart/ChartBase.js

@@ -1,10 +1,6 @@
 Ext.define('saas.view.core.chart.ChartBase', {
     extend: 'Ext.panel.Panel',
 
-    requires: [
-        'Ext.chart.*'
-    ],
-
     height: 300,
     bodyPadding: '16 16 16 0',
 

+ 0 - 1
frontend/saas-web/app/view/core/form/field/DetailGridField.js

@@ -12,7 +12,6 @@ Ext.define('saas.view.core.form.field.DetailGridField', {
     columnWidth : 1.0, 
 
     requires: [
-        'Ext.Action',
         'Ext.grid.plugin.CellEditing',
         'Ext.selection.CellModel'
     ],

+ 1 - 1
frontend/saas-web/app/view/core/query/QueryFormPanel.js

@@ -122,7 +122,7 @@ Ext.define('saas.view.core.query.QueryFormPanel', {
         rows = rows ? rows : allRows,
         showMore = rows == allRows;
 
-        var n_height = 14 + rows * ( 32 + 10 );
+        var n_height = 14 + rows * ( 32 + 10 - 1 );
 
         unanimate ? me.setHeight(n_height) : me.animate({dynamic: true, duration: 500, to: {height: n_height + 'px'}});
         me.setToggleBtn(showMore);

+ 6 - 2
frontend/saas-web/app/view/core/report/ReportPanelController.js

@@ -4,7 +4,6 @@ Ext.define('saas.view.core.report.ReportPanelController', {
 
     requires: [
         'Ext.exporter.text.CSV',
-        'Ext.exporter.text.TSV',
         'Ext.exporter.text.Html',
         'Ext.exporter.excel.Xml',
         'Ext.exporter.excel.Xlsx'
@@ -14,7 +13,12 @@ Ext.define('saas.view.core.report.ReportPanelController', {
         var me = this,
         reportPanel = me.getView(),
         grid = reportPanel.getListGrid();
-        grid.store.loadPage(1);
+
+        if(reportPanel.fireEvent('beforequery', reportPanel) == false) {
+            return false;
+        }else {
+            grid.store.loadPage(1);
+        }
     },
     exportTo:function(btn){
         var me = this,

+ 41 - 35
frontend/saas-web/app/view/home/InfoCard.scss

@@ -4,45 +4,51 @@ $max-card-width: 235px;
 
     .x-panel-bodyWrap {
         .x-autocontainer-innerCt {
-
-            .x-row {
+            .x-component {
                 display: flex;
-                width: 100%;
-                justify-content: flex-start;
-            
-                .x-col {
-            
-                    flex: 1;
-                    max-width: $max-card-width;
-                    color: #fff;
-                    padding: 10px;
-            
-                    .x-box {
-                        padding: 16px;
-                        height: 120px;
-                        border-radius: 0.5rem;
-                        position: relative;
-                        display: block;
-                        cursor: pointer;
-            
-                        &:hover {
-                            opacity: 0.7;
-                        }
+                flex-direction: column;
+                justify-content: center;
+                height: 100%;
 
-                        h3 {
-                            text-align: center;
-                            font-size: 16px;
+                .x-row {
+                    display: flex;
+                    width: 100%;
+                    justify-content: flex-start;
+                
+                    .x-col {
+                
+                        flex: 1;
+                        max-width: $max-card-width;
+                        color: #fff;
+                        padding: 10px;
+                
+                        .x-box {
+                            padding: 16px;
+                            height: 120px;
+                            border-radius: 0.5rem;
+                            position: relative;
+                            display: block;
+                            cursor: pointer;
+                
+                            &:hover {
+                                opacity: 0.7;
+                            }
+    
+                            h3 {
+                                text-align: center;
+                                font-size: 16px;
+                            }
+                
+                            p {
+                                font-size: 24px;
+                                text-align: center;
+                                margin-top: 32px;
+                            }
+                
                         }
-            
-                        p {
-                            font-size: 24px;
-                            text-align: center;
-                            margin-top: 32px;
+                        .x-box.x-view-item-focused {
+                            outline: none !important;
                         }
-            
-                    }
-                    .x-box.x-view-item-focused {
-                        outline: none !important;
                     }
                 }
             }

+ 2 - 11
frontend/saas-web/app/view/main/Main.js

@@ -160,7 +160,7 @@ Ext.define('saas.view.main.Main', {
                         html:'<img class="x-img x-box-item x-toolbar-item x-img-header" style="height:35px;width:35px;margin-top: 6px;margin-left: 14px;" src="{avatarUrl}" alt="">'
                     }, 
                     menu: {
-                        height: 132,
+                        // height: 132,
                         cls:'x-main-menu2 sa-nav-menu', 
                         items: [ {  
                             text: '账户中心',
@@ -179,21 +179,12 @@ Ext.define('saas.view.main.Main', {
                             handler:'feedbackMsg'
                         }, {  
                             text: '加入申请',
-                            hidden:true,
                             name:'join',
                             iconCls:'x-fa fa-handshake-o sa-navicon',
                             handler:function(b){
                                 saas.util.BaseUtil.openTab('sys-invitation-datalist','申请列表', 'sys-invitation-datalist');
                             },
-                            listeners:{
-                                afterrender:function(b){
-                                    if(b.ownerCt.ownerCmp.ownerCt.ownerCt.isAdmin){
-                                        b.show();
-                                    }else{
-                                        b.ownerCt.el.dom.style.height = "100px"
-                                    }
-                                }
-                            }
+                            bind: {hidden: '{!isAdmin}'}
                         }, {
                             text: '退出',
                             iconCls:'x-fa fa-power-off sa-navicon',

+ 38 - 21
frontend/saas-web/app/view/main/Navigation.scss

@@ -1,6 +1,8 @@
+$nav-body-background-color: #484A69;
 $nav-font-size: 16px;
 $nav-font-color: #EEEEF2;
 $nav-font-color-over: #fff;
+$menu-body-background-color: #65678C;
 
 .x-navpanel {
     overflow: visible;
@@ -18,7 +20,7 @@ $nav-font-color-over: #fff;
             overflow: visible;
     
             .x-autocontainer-outerCt {
-                background-color: #484A69;
+                background-color: $nav-body-background-color;
     
                 .x-autocontainer-innerCt {
     
@@ -38,7 +40,6 @@ $nav-font-color-over: #fff;
                             outline: none !important;
                             
                             .x-navitem-body {
-                                background: #505275;
     
                                 .nav-inner-wrap {
                                     position: relative;
@@ -74,22 +75,17 @@ $nav-font-color-over: #fff;
                         }
                         .x-navitem-over {
                             .x-navitem-body {
-                                background: #474968;
-                                box-shadow: inset 0 1px 4px 0 rgba(0,0,0,0.50);
+                                background: #65678C;
 
                                 .nav-inner-wrap {
 
-                                    &:after {
+                                    &:before {
                                         content: ' ';
-                                        width: 0;
-                                        height: 0;
-                                        border: 8px solid transparent;
-                                        border-right-color: #595B7E;
-                                        border-left: none;
                                         position: absolute;
-                                        right: 0;
-                                        top: 22px;
-                                        z-index: 999999;
+                                        width: 8px;
+                                        height: 60px;
+                                        background: #34baf6;
+                                        left: 0;
                                     }
 
                                     .nav-inner-icon {
@@ -118,6 +114,7 @@ $nav-font-color-over: #fff;
     position: absolute;
     z-index: 9999;
     top: 0;
+    border-left: 1px solid $nav-body-background-color;
     background: white;
     overflow: hidden;
 
@@ -133,23 +130,34 @@ $nav-font-color-over: #fff;
             flex-direction: column;
 
             &:nth-child(2) {
-                .menu-content {
+                .menu-title {
                     border-left: 1px solid #A4ABBC;
                     &:before {
                         content: '';
                         position: absolute;
                         width: 2px;
                         height: 22px;
-                        margin-left: -2px;
-                        background: #484A69;
+                        margin-left: -31px;
+                        background: $menu-body-background-color;
                     }
+                }
+                .menu-content {
+                    border-left: 1px solid #A4ABBC;
+                    // &:before {
+                    //     content: '';
+                    //     position: absolute;
+                    //     width: 2px;
+                    //     height: 22px;
+                    //     margin-left: -2px;
+                    //     background: $menu-body-background-color;
+                    // }
                     &:after {
                         content: '';
                         position: absolute;
                         width: 2px;
                         height: 22px;
                         margin-left: -2px;
-                        background: #484A69;
+                        background: $menu-body-background-color;
                         bottom: 0;
                     }
                 }
@@ -157,7 +165,7 @@ $nav-font-color-over: #fff;
 
             .menu-title {
                 padding-left: 30px;
-                background: #484A69;
+                background: $menu-body-background-color;
 
                 .menu-title-text {
                     height: 40px;
@@ -172,7 +180,7 @@ $nav-font-color-over: #fff;
 
             .menu-content {
                 height: 100%;
-                background: #484A69;
+                background: $menu-body-background-color;
                 
                 .menuitem {
                     padding-left: 25px;
@@ -198,7 +206,7 @@ $nav-font-color-over: #fff;
                         color: #fff;
                         display: none;
                         padding: 3px 6px;
-                        border-radius: 3px;
+                        // border-radius: 3px;
                         margin-right: 5px;
                         height: 24px;
                         margin-top: 5px;
@@ -209,9 +217,18 @@ $nav-font-color-over: #fff;
                     }
 
                     &:hover {
-                        border-radius: 4px;
+                        // border-radius: 4px;
                         background-color: #595B7E;
 
+                        &:before {
+                            content: ' ';
+                            position: absolute;
+                            width: 6px;
+                            height: 34px;
+                            background: #34baf6;
+                            margin-left: -25px;
+                        }
+
                         .item-icon {
                             display: block;
                         }

+ 4 - 4
frontend/saas-web/app/view/money/payBalance/FormPanelController.js

@@ -134,7 +134,7 @@ Ext.define('saas.view.money.payBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     pb_vendname = viewModel.get('pb_vendname');
                     if(!pb_vendname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">供应商名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">供应商名称</span>】');
                         return false;
                     }
                 },
@@ -143,7 +143,7 @@ Ext.define('saas.view.money.payBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     pb_vendname = viewModel.get('pb_vendname');
                     if(!pb_vendname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">供应商名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">供应商名称</span>】');
                         return false;
                     }
                 }
@@ -171,7 +171,7 @@ Ext.define('saas.view.money.payBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('pb_vendname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">供应商名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">供应商名称</span>】');
                         return false;
                     }
                 },
@@ -180,7 +180,7 @@ Ext.define('saas.view.money.payBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('pb_vendname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">供应商名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">供应商名称</span>】');
                         return false;
                     }
                 }

+ 4 - 4
frontend/saas-web/app/view/money/recBalance/FormPanelController.js

@@ -115,7 +115,7 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('rb_custname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">客户名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">客户名称</span>】');
                         return false;
                     }
                 },
@@ -124,7 +124,7 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('rb_custname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">客户名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">客户名称</span>】');
                         return false;
                     }
                 }
@@ -168,7 +168,7 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('rb_custname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">客户名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">客户名称</span>】');
                         return false;
                     }
                 },
@@ -177,7 +177,7 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                     viewModel = me.getViewModel(),
                     rb_custname = viewModel.get('rb_custname');
                     if(!rb_custname) {
-                        saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">客户名称</span>】');
+                        saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">客户名称</span>】');
                         return false;
                     }
                 }

+ 11 - 6
frontend/saas-web/app/view/money/report/CustomerCheck.js

@@ -19,18 +19,12 @@ Ext.define('saas.view.money.report.CustomerCheckCheck', {
         name: 'pi_custname',
         fieldLabel: '客户名称',
         columnWidth: 0.2,
-        allowBlank: false,
         listeners: {
             beforequery: function(f) {
                 return !!f.value;
             }
         }
     }, {
-    //     xtype: 'monthdatefield',
-    //     name: 'ym',
-    //     fieldLabel: '期初日期',
-    //     columnWidth: 0.2
-    // }, {
         xtype: 'condatefield',
         name: 'pi_date',
         fieldLabel: '单据日期',
@@ -197,6 +191,17 @@ Ext.define('saas.view.money.report.CustomerCheckCheck', {
         afterrender: function(panel) {
             panel.setLoadButtonDisabled(true);
         },
+        beforequery: function(panel) {
+            var form = panel.items.items[0];
+            var values = form.getValues();
+            var pi_custname = values.pi_custname;
+
+            if(!pi_custname) {
+                saas.util.BaseUtil.showErrorToast('请先选择【<span style="color: red;">客户名称</span>】');
+                return false;
+            }
+            return true;
+        }
     },
 
     setLoadButtonDisabled: function (disabled) {

+ 11 - 1
frontend/saas-web/app/view/money/report/VendorCheck.js

@@ -19,7 +19,6 @@ Ext.define('saas.view.money.report.VendorCheck', {
         name: 'pi_vendname',
         fieldLabel: '供应商名称',
         columnWidth: 0.2,
-        allowBlank:false,
         listeners: {
             beforequery: function(f) {
                 return !!f.value;
@@ -200,6 +199,17 @@ Ext.define('saas.view.money.report.VendorCheck', {
         afterrender: function(panel) {
             panel.setLoadButtonDisabled(true);
         },
+        beforequery: function(panel) {
+            var form = panel.items.items[0];
+            var values = form.getValues();
+            var pi_vendname = values.pi_vendname;
+
+            if(!pi_vendname) {
+                saas.util.BaseUtil.showErrorToast('请先选择【<span style="color: red;">供应商名称</span>】');
+                return false;
+            }
+            return true;
+        }
     },
 
     setLoadButtonDisabled: function (disabled) {

+ 1 - 1
frontend/saas-web/app/view/money/verification/FormPanelController.js

@@ -477,7 +477,7 @@ Ext.define('saas.view.money.verification.FormPanelController', {
         }).fieldLabel;
         var fieldValue = viewModel.get(fieldName);
         if(!fieldValue) {
-            saas.util.BaseUtil.showErrorToast('请先录入主表字段【' + '<span style="color: red;">' + fieldLabel + '</span>】');
+            saas.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">' + fieldLabel + '</span>】');
             return null;
         }
         var defaultCondition = defaultConditionMode.replace(reg, '$1' + fieldValue + '$3');

+ 6 - 5
frontend/saas-web/app/view/stock/inventory/EditDataList.js

@@ -1,9 +1,11 @@
+/**
+ * 盘点单
+ */
 Ext.define('saas.view.stock.inventory.EditDataList', {
     extend: 'Ext.grid.Panel',
     xtype: 'stock-inventory-editdatalist',
     viewModel: 'stock-inventory-editdatalist',
 
-
     autoScroll: true,
     frame:true,
     layout:'fit',
@@ -12,7 +14,6 @@ Ext.define('saas.view.stock.inventory.EditDataList', {
     buildUrl:'/api/storage/stocktaking/build',
     stockUrl:'/api/storage/stocktaking/stock',
     requires: [
-        'Ext.Action',
         'Ext.grid.plugin.CellEditing',
         'Ext.selection.CellModel',
         'Ext.grid.plugin.Exporter'
@@ -220,7 +221,7 @@ Ext.define('saas.view.stock.inventory.EditDataList', {
             var fields = me.columns.map(column => column.dataIndex);
             me.store = Ext.create('Ext.data.Store', {
                 fields: fields,
-                autoLoad: true,
+                autoLoad: false,
                 pageSize: 15,
                 data: [],
                 proxy: {
@@ -420,8 +421,8 @@ Ext.define('saas.view.stock.inventory.EditDataList', {
     },
     refresh:function(){
         var me = this;
-        // me.onbuild();
-        me.reload();
+        me.onbuild();
+        // me.reload();
     },
     reload:function(){
         var me = this;    

+ 13 - 0
frontend/saas-web/app/view/viewport/ViewportModel.js

@@ -16,6 +16,19 @@ Ext.define('saas.view.viewport.ViewportModel', {
         avatarUrl: function (get) {
             var account = get('account');
             return (account && account.avatarUrl) || 'resources/images/default/user-icon.png'
+        },
+        isAdmin: function(get) {
+            var account = get('account');
+            if (account && 0 == account.type) {
+                return true;
+            }
+            if (account && account.rolesMap) {
+                var roles = account.rolesMap[account.companyId];
+                return roles && roles.some(function(r){
+                    return 0 == r.type;
+                });
+            }
+            return false;
         }
     }    
 });

+ 1 - 1
frontend/saas-web/electron/package.json

@@ -1,6 +1,6 @@
 {
   "name": "UsoftchinaSaasClient",
-  "version": "0.0.1",
+  "version": "0.0.2",
   "description": "saas在线进销存系统",
   "main": "./main.js",
   "scripts": {