zhoudw 7 лет назад
Родитель
Сommit
516ed20e61
100 измененных файлов с 1795 добавлено и 401 удалено
  1. 8 0
      README.md
  2. 2 0
      applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/CommonsApplication.java
  3. 2 1
      applications/document/document-server/src/main/java/com/usoftchina/saas/document/DocumentApplication.java
  4. 2 1
      applications/money/money-server/src/main/java/com/usoftchina/saas/money/MoneyApplicatiion.java
  5. 2 2
      applications/money/money-server/src/main/resources/mapper/PaybalancedetMapper.xml
  6. 2 1
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java
  7. 2 0
      applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/SaleApplication.java
  8. 2 1
      applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/StorageApplication.java
  9. 2 2
      base-servers/account/README.md
  10. 4 0
      base-servers/account/account-api/pom.xml
  11. 10 0
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/AccountApi.java
  12. 26 0
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/ResourceApi.java
  13. 65 0
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/cache/AccountCache.java
  14. 68 0
      base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/cache/ResourceCache.java
  15. 54 6
      base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/AccountDTO.java
  16. 27 1
      base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/RoleBaseDTO.java
  17. 11 1
      base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/UrlResourceDTO.java
  18. 1 1
      base-servers/account/account-server/pom.xml
  19. 74 7
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/AccountController.java
  20. 1 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/ResourceController.java
  21. 22 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/RoleController.java
  22. 10 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/AccountMapper.java
  23. 9 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/AccountRoleMapper.java
  24. 16 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/ResourceMapper.java
  25. 11 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/RoleMapper.java
  26. 22 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/RoleResourceMapper.java
  27. 12 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/Account.java
  28. 14 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/AccountRole.java
  29. 14 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/Resource.java
  30. 14 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/ResourceGroup.java
  31. 26 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/RoleResource.java
  32. 33 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/AccountService.java
  33. 16 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/ResourceService.java
  34. 12 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/RoleService.java
  35. 37 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/AccountServiceImpl.java
  36. 14 0
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/ResourceServiceImpl.java
  37. 24 1
      base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/RoleServiceImpl.java
  38. 3 0
      base-servers/account/account-server/src/main/resources/application.yml
  39. 7 1
      base-servers/account/account-server/src/main/resources/mapper/AccountMapper.xml
  40. 4 1
      base-servers/account/account-server/src/main/resources/mapper/AccountRoleMapper.xml
  41. 9 1
      base-servers/account/account-server/src/main/resources/mapper/ResourceMapper.xml
  42. 6 1
      base-servers/account/account-server/src/main/resources/mapper/RoleMapper.xml
  43. 15 1
      base-servers/account/account-server/src/main/resources/mapper/RoleResourceMapper.xml
  44. 65 6
      base-servers/account/account-server/src/test/java/com/usoftchina/saas/account/controller/AccountControllerTest.java
  45. 0 4
      base-servers/auth/auth-api/pom.xml
  46. 8 0
      base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/AuthApi.java
  47. 0 47
      base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/cache/TokenCache.java
  48. 19 0
      base-servers/auth/auth-server/src/main/java/com/usoftchina/saas/auth/controller/AuthController.java
  49. 4 0
      base-servers/gateway-server/pom.xml
  50. 4 1
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/GatewayApplication.java
  51. 53 1
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthFilter.java
  52. 18 0
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/context/SpringContextListener.java
  53. 20 0
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/error/PermissionException.java
  54. 177 0
      base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/util/AntPathRequestMatcher.java
  55. 3 0
      base-servers/gateway-server/src/main/resources/application.yml
  56. 2 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/UiApplication.java
  57. 0 4
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/co/CoViewController.java
  58. 4 2
      framework/core/pom.xml
  59. 8 11
      framework/core/src/main/java/com/usoftchina/saas/base/Result.java
  60. 1 0
      framework/core/src/main/java/com/usoftchina/saas/exception/ExceptionCode.java
  61. 112 5
      framework/core/src/main/java/com/usoftchina/saas/utils/CollectionUtils.java
  62. 44 1
      framework/core/src/main/java/com/usoftchina/saas/utils/JsonUtils.java
  63. 0 1
      frontend/saas-web/app/Application.scss
  64. 0 26
      frontend/saas-web/app/model/Account.js
  65. 73 21
      frontend/saas-web/app/model/Session.js
  66. 9 0
      frontend/saas-web/app/store/Company.js
  67. 0 1
      frontend/saas-web/app/util/BaseUtil.js
  68. 37 0
      frontend/saas-web/app/view/auth/CompanyPicker.js
  69. 38 0
      frontend/saas-web/app/view/auth/CompanyPicker.scss
  70. 54 26
      frontend/saas-web/app/view/auth/LoginController.js
  71. 1 1
      frontend/saas-web/app/view/core/dbfind/MultiDbfindGridPanel.js
  72. 7 1
      frontend/saas-web/app/view/document/kind/ChildForm.js
  73. 6 4
      frontend/saas-web/app/view/document/kind/Kind.js
  74. 9 8
      frontend/saas-web/app/view/document/product/FormController.js
  75. 44 8
      frontend/saas-web/app/view/document/product/FormPanel.js
  76. 0 15
      frontend/saas-web/app/view/main/List.js
  77. 27 11
      frontend/saas-web/app/view/main/Main.js
  78. 29 0
      frontend/saas-web/app/view/main/MainController.js
  79. 0 1
      frontend/saas-web/app/view/main/MainModel.js
  80. 18 0
      frontend/saas-web/app/view/money/fundtransfer/FormPanelController.js
  81. 2 2
      frontend/saas-web/app/view/money/othreceipts/FormPanelController.js
  82. 28 19
      frontend/saas-web/app/view/money/payBalance/FormPanel.js
  83. 9 5
      frontend/saas-web/app/view/money/payBalance/FormPanelController.js
  84. 3 3
      frontend/saas-web/app/view/money/payBalance/QueryPanel.js
  85. 10 7
      frontend/saas-web/app/view/money/recBalance/FormPanelController.js
  86. 2 4
      frontend/saas-web/app/view/purchase/purchase/FormPanelController.js
  87. 4 5
      frontend/saas-web/app/view/purchase/purchaseIn/FormPanelController.js
  88. 4 5
      frontend/saas-web/app/view/purchase/purchaseOut/FormPanelController.js
  89. 1 1
      frontend/saas-web/app/view/sale/sale/FormPanelController.js
  90. 1 1
      frontend/saas-web/app/view/sale/saleIn/FormPanelController.js
  91. 1 1
      frontend/saas-web/app/view/sale/saleOut/FormPanelController.js
  92. 7 9
      frontend/saas-web/app/view/stock/appropriationInOut/FormPanelController.js
  93. 25 20
      frontend/saas-web/app/view/stock/make/FormPanelController.js
  94. 6 8
      frontend/saas-web/app/view/stock/otherIn/FormPanelController.js
  95. 6 8
      frontend/saas-web/app/view/stock/otherOut/FormPanelController.js
  96. 2 2
      frontend/saas-web/app/view/sys/maxnumbers/DataList.js
  97. 12 5
      frontend/saas-web/app/view/sys/messagelog/DataList.js
  98. 39 53
      frontend/saas-web/app/view/viewport/ViewportController.js
  99. 14 1
      frontend/saas-web/app/view/viewport/ViewportModel.js
  100. 10 1
      frontend/saas-web/overrides/data/Connection.js

+ 8 - 0
README.md

@@ -13,12 +13,20 @@
 │  |  |  |─document-dto-----------------------基础资料数据传输对象
 │  |  |  |─document-server--------------------基础资料服务
 │  |  ├─money---------------------------------资金
+│  |  |  |─money-api--------------------------资金服务api
+│  |  |  |─money-dto--------------------------资金服务数据传输对象
+│  |  |  |─money-server-----------------------资金服务
 │  |  ├─purchase------------------------------采购
 │  |  |  |─purchase-api-----------------------采购服务api
 │  |  |  |─purchase-dto-----------------------采购服务数据传输对象
 │  |  |  |─purchase-server--------------------采购服务
 │  |  ├─sale----------------------------------销售
+│  |  |  |─sale-dto---------------------------销售服务数据传输对象
+│  |  |  |─sale-server------------------------销售服务
 │  |  ├─storage-------------------------------库存
+│  |  |  |─storage-api------------------------库存服务api
+│  |  |  |─storage-dto------------------------库存服务数据传输对象
+│  |  |  |─storage-server---------------------库存服务
 │  │ 
 │  ├─base-servers-----------------------------基础服务
 │  |  ├─admin-server--------------------------spring-boot-admin监控中心

+ 2 - 0
applications/commons/commons-server/src/main/java/com/usoftchina/saas/commons/CommonsApplication.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.commons;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @EnableTransactionManagement
 @EnableFeignClients("com.usoftchina.saas")
 @MapperScan("com.usoftchina.saas.commons.mapper")
+@EnableAuthClient
 public class CommonsApplication {
     public static void main(String[] args) {
         SpringApplication.run(CommonsApplication.class, args);

+ 2 - 1
applications/document/document-server/src/main/java/com/usoftchina/saas/document/DocumentApplication.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.document;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +10,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 @SpringBootApplication
 @EnableEurekaClient
-//@EnableAuthClient
+@EnableAuthClient
 @EnableTransactionManagement
 @EnableFeignClients("com.usoftchina.saas")
 @MapperScan("com.usoftchina.saas.document.mapper")

+ 2 - 1
applications/money/money-server/src/main/java/com/usoftchina/saas/money/MoneyApplicatiion.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.money;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -16,7 +17,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @EnableEurekaClient
 @EnableTransactionManagement
 @EnableFeignClients("com.usoftchina.saas")
-//@EnableAuthClient
+@EnableAuthClient
 @MapperScan("com.usoftchina.saas.money.mapper")
 public class MoneyApplicatiion {
     public static void main(String[] args) {

+ 2 - 2
applications/money/money-server/src/main/resources/mapper/PaybalancedetMapper.xml

@@ -2,7 +2,7 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 <mapper namespace="com.usoftchina.saas.money.mapper.PaybalancedetMapper" >
   <resultMap id="BaseResultMap" type="com.usoftchina.saas.money.po.Paybalancedet" >
-    <id column="pd_id" property="pdId" jdbcType="INTEGER" />
+    <id column="pd_id" property="id" jdbcType="INTEGER" />
     <result column="pd_rbid" property="pdRbid" jdbcType="INTEGER" />
     <result column="pd_detno" property="pdDetno" jdbcType="INTEGER" />
     <result column="pd_ym" property="pdYm" jdbcType="INTEGER" />
@@ -31,7 +31,7 @@
     select 
     <include refid="Base_Column_List" />
     from paybalancedet
-    where pd_rbid = #{pdRbId,jdbcType=INTEGER}
+    where pd_rbid = #{id,jdbcType=INTEGER}
   </select>
   <delete id="deleteItem" parameterType="java.lang.Integer" >
     delete from paybalancedet

+ 2 - 1
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java

@@ -1,6 +1,7 @@
 package com.usoftchina.saas.purchase;
 
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -18,7 +19,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
 @EnableEurekaClient
 @EnableTransactionManagement
 @EnableFeignClients("com.usoftchina.saas")
-//@EnableAuthClient
+@EnableAuthClient
 @MapperScan("com.usoftchina.saas.purchase.mapper")
 public class PurchaseApplication   extends WebMvcConfigurerAdapter{
     public static void main(String[] args) {

+ 2 - 0
applications/sale/sale-server/src/main/java/com/usoftchina/saas/sale/SaleApplication.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.sale;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -15,6 +16,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
 @MapperScan("com.usoftchina.saas.sale.mapper")
 @EnableEurekaClient
 @EnableFeignClients("com.usoftchina.saas")
+@EnableAuthClient
 public class SaleApplication{
     public static void main(String[] args) {
         SpringApplication.run(SaleApplication.class, args);

+ 2 - 1
applications/storage/storage-server/src/main/java/com/usoftchina/saas/storage/StorageApplication.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.storage;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,7 +10,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 @SpringBootApplication
 @EnableEurekaClient
-//@EnableAuthClient
+@EnableAuthClient
 @EnableTransactionManagement
 @EnableFeignClients("com.usoftchina.saas")
 @MapperScan("com.usoftchina.saas.storage.mapper")

+ 2 - 2
base-servers/account/README.md

@@ -21,8 +21,8 @@
 | :----:   | ---------  |
 | id | 主键,自动生成  |
 | group_id | 资源分组ID,参考ac_resource_group、ac_resource_module表 |
-| name | 名称,统一叫法:查询、新增、修改、审核、反审核、删除、打印、(其它,字数≤5) |
+| name | 名称,统一叫法:查询、新增、修改、审核、反审核、删除、打印、导入、导出、(其它,字数≤5) |
 | type | 类型,MENU(Navigation的资源)、BUTTON (页面按钮资源)、API... |
 | url | 请求url |
 | method | http请求头方法:GET, POST, PUT, DELETE |
-| classify | 归类:QUERY, ADD, UPDATE, AUDIT, UNAUDIT, DELETE, PRINT, OTHER  |
+| classify | 归类:QUERY, ADD, UPDATE, AUDIT, UNAUDIT, DELETE, PRINT, IMPORT, EXPORT, OTHER  |

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

@@ -25,6 +25,10 @@
             <groupId>com.usoftchina.saas</groupId>
             <artifactId>core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

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

@@ -4,6 +4,7 @@ import com.usoftchina.saas.account.dto.AccountDTO;
 import com.usoftchina.saas.base.Result;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestParam;
 
 /**
@@ -30,4 +31,13 @@ public interface AccountApi {
      */
     @GetMapping(value = "/account/read")
     Result<AccountDTO> getAccount(@RequestParam(value = "username") String username);
+
+    /**
+     * 按用户名查找账户
+     *
+     * @param id
+     * @return
+     */
+    @GetMapping(value = "/account/{id}")
+    Result<AccountDTO> getAccountById(@PathVariable("id") Long id);
 }

+ 26 - 0
base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/api/ResourceApi.java

@@ -0,0 +1,26 @@
+package com.usoftchina.saas.account.api;
+
+import com.usoftchina.saas.account.dto.UrlResourceDTO;
+import com.usoftchina.saas.base.Result;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/11/1
+ */
+@FeignClient(name = "account-server")
+public interface ResourceApi {
+
+    /**
+     * 查找应用的全部url资源
+     *
+     * @param appId
+     * @return
+     */
+    @GetMapping(value = "/resource/url/list")
+    Result<List<UrlResourceDTO>> getUrlResourcesByAppId(@RequestParam(value = "appId") String appId);
+}

+ 65 - 0
base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/cache/AccountCache.java

@@ -0,0 +1,65 @@
+package com.usoftchina.saas.account.cache;
+
+import com.usoftchina.saas.account.api.AccountApi;
+import com.usoftchina.saas.account.dto.AccountDTO;
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.cache.RedisHashCache;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.utils.JsonUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.Optional;
+import java.util.function.Supplier;
+
+/**
+ * @author yingp
+ * @date 2018/11/1
+ */
+public class AccountCache extends RedisHashCache<String, String, String> {
+    private final long id;
+
+    private static final RedisTemplate<String, String> REDIS_TEMPLATE = SpringContextHolder.getBean("redisTemplate", RedisTemplate.class);
+    private AccountApi accountApi;
+
+    private AccountCache(long id) {
+        super(() -> REDIS_TEMPLATE);
+        this.id = id;
+    }
+
+    public static AccountCache of(long id) {
+        return new AccountCache(id);
+    }
+
+    @Override
+    protected String field() {
+        return String.valueOf(id);
+    }
+
+    @Override
+    protected String key() {
+        return generateKey("account", "account");
+    }
+
+    @Override
+    protected Supplier<String> getSupplier() {
+        return () -> {
+            if (null == accountApi) {
+                accountApi = SpringContextHolder.getBean(AccountApi.class);
+            }
+            Result<AccountDTO> result = accountApi.getAccountById(id);
+            if (result.isSuccess()) {
+                return JsonUtils.toJsonString(result.getData());
+            }
+            throw new BizException(result.getCode(), result.getMessage());
+        };
+    }
+
+    public AccountDTO getAccount() {
+        Optional<String> value = get();
+        if (value.isPresent()) {
+            return JsonUtils.fromJsonString(value.get(), AccountDTO.class);
+        }
+        return null;
+    }
+}

+ 68 - 0
base-servers/account/account-api/src/main/java/com/usoftchina/saas/account/cache/ResourceCache.java

@@ -0,0 +1,68 @@
+package com.usoftchina.saas.account.cache;
+
+import com.usoftchina.saas.account.api.ResourceApi;
+import com.usoftchina.saas.account.dto.UrlResourceDTO;
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.cache.RedisHashCache;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.exception.BizException;
+import com.usoftchina.saas.utils.JsonUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+/**
+ * @author yingp
+ * @date 2018/11/1
+ */
+public class ResourceCache extends RedisHashCache<String, String, String> {
+
+    private final String appId;
+
+    private static final RedisTemplate<String, String> REDIS_TEMPLATE = SpringContextHolder.getBean("redisTemplate", RedisTemplate.class);
+    private ResourceApi resourceApi;
+
+    private ResourceCache(String appId) {
+        super(() -> REDIS_TEMPLATE);
+        this.appId = appId;
+    }
+
+    public static ResourceCache of(String appId) {
+        return new ResourceCache(appId);
+    }
+
+    @Override
+    protected String field() {
+        return appId;
+    }
+
+    @Override
+    protected String key() {
+        return generateKey("account", "resource");
+    }
+
+    @Override
+    protected Supplier<String> getSupplier() {
+        return () -> {
+			if (null == resourceApi) {
+				resourceApi = SpringContextHolder.getBean(ResourceApi.class);
+			}
+            Result<List<UrlResourceDTO>> result = resourceApi.getUrlResourcesByAppId(appId);
+            if (result.isSuccess()) {
+                return JsonUtils.toJsonString(result.getData());
+            }
+            throw new BizException(result.getCode(), result.getMessage());
+        };
+    }
+
+    public List<UrlResourceDTO> getUrlResources() {
+        Optional<String> value = get();
+        if (value.isPresent()) {
+            return JsonUtils.fromJsonArray(value.get(), UrlResourceDTO.class);
+        }
+        return null;
+    }
+
+}

+ 54 - 6
base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/AccountDTO.java

@@ -1,10 +1,14 @@
 package com.usoftchina.saas.account.dto;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.usoftchina.saas.account.constant.AccountType;
+import com.usoftchina.saas.utils.CollectionUtils;
 import io.swagger.annotations.ApiModel;
 
 import java.io.Serializable;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author yingp
@@ -17,6 +21,10 @@ public class AccountDTO implements Serializable {
     private String realname;
     private String email;
     private String mobile;
+    /**
+     * 头像
+     */
+    private String avatarUrl;
     /**
      * 账号类型 0 - 管理员
      */
@@ -32,9 +40,13 @@ public class AccountDTO implements Serializable {
     /**
      * 所拥有的资源
      *
+     * <String> appId
+     * <Long> companyId
+     * <Long> resourceId
+     *
      * @return
      */
-    private Map<Long, List<UrlResourceDTO>> resourcesMap;
+    private Map<String, Map<Long, Set<Long>>> resourcesTable;
 
     public Long getId() {
         return id;
@@ -76,6 +88,14 @@ public class AccountDTO implements Serializable {
         this.mobile = mobile;
     }
 
+    public String getAvatarUrl() {
+        return avatarUrl;
+    }
+
+    public void setAvatarUrl(String avatarUrl) {
+        this.avatarUrl = avatarUrl;
+    }
+
     public Integer getType() {
         return type;
     }
@@ -100,12 +120,39 @@ public class AccountDTO implements Serializable {
         this.rolesMap = rolesMap;
     }
 
-    public Map<Long, List<UrlResourceDTO>> getResourcesMap() {
-        return resourcesMap;
+    public Map<String, Map<Long, Set<Long>>> getResourcesTable() {
+        return resourcesTable;
     }
 
-    public void setResourcesMap(Map<Long, List<UrlResourceDTO>> resourcesMap) {
-        this.resourcesMap = resourcesMap;
+    public void setResourcesTable(Map<String, Map<Long, Set<Long>>> resourcesTable) {
+        this.resourcesTable = resourcesTable;
+    }
+
+    /**
+     * 是否管理账户
+     *
+     * @param companyId
+     * @return
+     */
+    @JsonIgnore
+    public boolean isAdmin(Long companyId) {
+        boolean is = null != type && type == AccountType.ADMIN.getType();
+        if (!is && null != companyId && null != rolesMap) {
+            // 是否管理角色
+            List<RoleBaseDTO> roles = rolesMap.get(companyId);
+            if (!CollectionUtils.isEmpty(roles)) {
+                return roles.stream().anyMatch(RoleBaseDTO::isAdmin);
+            }
+        }
+        return is;
+    }
+
+    @JsonIgnore
+    public Set<Long> getResources(String appId, Long companyId) {
+        if (null != resourcesTable && resourcesTable.containsKey(appId)) {
+            return resourcesTable.get(appId).get(companyId);
+        }
+        return null;
     }
 
     @Override
@@ -116,10 +163,11 @@ public class AccountDTO implements Serializable {
                 ", realname='" + realname + '\'' +
                 ", email='" + email + '\'' +
                 ", mobile='" + mobile + '\'' +
+                ", avatarUrl='" + avatarUrl + '\'' +
                 ", type=" + type +
                 ", companies=" + companies +
                 ", rolesMap=" + rolesMap +
-                ", resourcesMap=" + resourcesMap +
+                ", resourcesTable=" + resourcesTable +
                 '}';
     }
 }

+ 27 - 1
base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/RoleBaseDTO.java

@@ -1,5 +1,8 @@
 package com.usoftchina.saas.account.dto;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.usoftchina.saas.account.constant.RoleType;
+
 import java.io.Serializable;
 
 /**
@@ -8,7 +11,7 @@ import java.io.Serializable;
  * @author yingp
  * @date 2018/10/10
  */
-public class RoleBaseDTO implements Serializable{
+public class RoleBaseDTO implements Serializable {
     private Long id;
     /**
      * 公司
@@ -22,6 +25,10 @@ public class RoleBaseDTO implements Serializable{
      * 角色名称
      */
     private String name;
+    /**
+     * 类型
+     */
+    private Integer type;
 
     public Long getId() {
         return id;
@@ -55,6 +62,24 @@ public class RoleBaseDTO implements Serializable{
         this.name = name;
     }
 
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    /**
+     * 是否管理角色
+     *
+     * @return
+     */
+    @JsonIgnore
+    public boolean isAdmin() {
+        return null != type && type == RoleType.ADMIN.getType();
+    }
+
     @Override
     public String toString() {
         return "RoleBaseDTO{" +
@@ -62,6 +87,7 @@ public class RoleBaseDTO implements Serializable{
                 ", companyId=" + companyId +
                 ", code='" + code + '\'' +
                 ", name='" + name + '\'' +
+                ", type=" + type +
                 '}';
     }
 }

+ 11 - 1
base-servers/account/account-dto/src/main/java/com/usoftchina/saas/account/dto/UrlResourceDTO.java

@@ -9,6 +9,7 @@ import java.io.Serializable;
  * @date 2018/10/26
  */
 public class UrlResourceDTO implements Serializable{
+    private Long id;
     /**
      * 名称
      */
@@ -22,6 +23,14 @@ public class UrlResourceDTO implements Serializable{
      */
     private String method;
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
     public String getName() {
         return name;
     }
@@ -49,7 +58,8 @@ public class UrlResourceDTO implements Serializable{
     @Override
     public String toString() {
         return "UrlResourceDTO{" +
-                "name='" + name + '\'' +
+                "id=" + id +
+                ", name='" + name + '\'' +
                 ", url='" + url + '\'' +
                 ", method='" + method + '\'' +
                 '}';

+ 1 - 1
base-servers/account/account-server/pom.xml

@@ -19,7 +19,7 @@
         </dependency>
         <dependency>
             <groupId>com.usoftchina.saas</groupId>
-            <artifactId>account-dto</artifactId>
+            <artifactId>account-api</artifactId>
         </dependency>
         <!-- db -->
         <dependency>

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

@@ -1,20 +1,28 @@
 package com.usoftchina.saas.account.controller;
 
+import com.usoftchina.saas.account.cache.AccountCache;
 import com.usoftchina.saas.account.dto.AccountDTO;
 import com.usoftchina.saas.account.dto.AccountRegDTO;
 import com.usoftchina.saas.account.dto.CompanyBaseDTO;
+import com.usoftchina.saas.account.dto.RoleBaseDTO;
 import com.usoftchina.saas.account.po.Account;
+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.account.vo.CompanyBaseVO;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.context.BaseContextHolder;
 import com.usoftchina.saas.exception.ExceptionCode;
 import com.usoftchina.saas.utils.BeanMapper;
+import com.usoftchina.saas.utils.CollectionUtils;
 import com.usoftchina.saas.utils.RegexpUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * @author yingp
@@ -30,6 +38,9 @@ public class AccountController {
     @Autowired
     private CompanyService companyService;
 
+    @Autowired
+    private RoleService roleService;
+
     /**
      * 注册
      *
@@ -84,14 +95,41 @@ public class AccountController {
             return Result.error(ExceptionCode.USER_PWD_ERROR);
         }
 
+        return Result.success(getAccountDTO(account));
+    }
+
+    /**
+     * 账户 + 账户的全部绑定信息
+     *
+     * @param account
+     * @return
+     */
+    private AccountDTO getAccountDTO(Account account) {
         AccountDTO accountDTO = BeanMapper.map(account, AccountDTO.class);
         // 绑定的公司
         List<CompanyBaseVO> companyBaseVOS = companyService.findBaseByAccountId(account.getId());
         accountDTO.setCompanies(BeanMapper.mapList(companyBaseVOS, CompanyBaseDTO.class));
-
-        return Result.success(accountDTO);
+        List<RoleBaseDTO> roleBaseDTOS = roleService.findByAccountId(accountDTO.getId());
+        if (!CollectionUtils.isEmpty(roleBaseDTOS)) {
+            // 绑定的 公司->角色
+            accountDTO.setRolesMap(CollectionUtils.groupBy(roleBaseDTOS, RoleBaseDTO::getCompanyId));
+            List<RoleResource> roleResourceVOS = accountService.findRoleResourcesByAccountId(accountDTO.getId());
+            if (!CollectionUtils.isEmpty(roleBaseDTOS)) {
+                // 绑定的 应用+公司->资源
+                Map<String, Map<Long, Set<Long>>> resourcesTable = CollectionUtils.distinctBy(roleResourceVOS,
+                        RoleResource::getAppId, RoleResource::getCompanyId, RoleResource::getResourceId);
+                accountDTO.setResourcesTable(resourcesTable);
+            }
+        }
+        return accountDTO;
     }
 
+    /**
+     * 匹配前端多种输入账号类型
+     *
+     * @param username
+     * @return
+     */
     private Account getAccountByUsername(String username) {
         Account account;
         if (RegexpUtils.isMobile(username)) {
@@ -117,12 +155,23 @@ public class AccountController {
             return Result.error(ExceptionCode.USER_NOT_EXIST);
         }
 
-        AccountDTO accountDTO = BeanMapper.map(account, AccountDTO.class);
-        // 绑定的公司
-        List<CompanyBaseVO> companyBaseVOS = companyService.findBaseByAccountId(account.getId());
-        accountDTO.setCompanies(BeanMapper.mapList(companyBaseVOS, CompanyBaseDTO.class));
+        return Result.success(getAccountDTO(account));
+    }
+
+    /**
+     * 按ID查找账户
+     *
+     * @param id
+     * @return
+     */
+    @GetMapping("/{id}")
+    public Result<AccountDTO> getAccountById(@PathVariable Long id) {
+        Account account = accountService.findByPrimaryKey(id);
+        if (null == account) {
+            return Result.error(ExceptionCode.USER_NOT_EXIST);
+        }
 
-        return Result.success(accountDTO);
+        return Result.success(getAccountDTO(account));
     }
 
     /**
@@ -135,6 +184,7 @@ public class AccountController {
     @PostMapping("/bind/company")
     public Result bindCompany(@RequestParam long accountId, @RequestParam long companyId) {
         accountService.bindCompany(accountId, companyId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -148,6 +198,7 @@ public class AccountController {
     @PostMapping("/unbind/company")
     public Result unbindCompany(@RequestParam long accountId, @RequestParam long companyId) {
         accountService.unbindCompany(accountId, companyId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -161,6 +212,7 @@ public class AccountController {
     @PostMapping("/bind/role")
     public Result bindRole(@RequestParam long accountId, @RequestParam long roleId) {
         accountService.bindRole(accountId, roleId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -174,6 +226,7 @@ public class AccountController {
     @PostMapping("/unbind/role")
     public Result unbindRole(@RequestParam long accountId, @RequestParam long roleId) {
         accountService.unbindRole(accountId, roleId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -186,6 +239,7 @@ public class AccountController {
     @PostMapping("/disable")
     public Result disableAccount(@RequestParam long accountId) {
         accountService.disable(accountId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -198,6 +252,7 @@ public class AccountController {
     @PostMapping("/enable")
     public Result enableAccount(@RequestParam long accountId) {
         accountService.enable(accountId);
+        accountService.clearCache(accountId);
         return Result.success();
     }
 
@@ -209,7 +264,19 @@ public class AccountController {
      */
     @PostMapping("/delete/{id}")
     public Result deleteAccount(@PathVariable Long id) {
+        accountService.clearCache(id);
         accountService.removeByPrimaryKey(id);
         return Result.success();
     }
+
+    /**
+     * 账户缓存清除
+     *
+     * @return
+     */
+    @GetMapping("/cache/clear")
+    public Result clearCache() {
+        accountService.clearCache(BaseContextHolder.getUserId());
+        return Result.success();
+    }
 }

+ 1 - 1
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/ResourcesController.java → base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/controller/ResourceController.java

@@ -19,7 +19,7 @@ import java.util.List;
  */
 @RestController
 @RequestMapping("/resource")
-public class ResourcesController {
+public class ResourceController {
 
     @Autowired
     private ResourceService resourcesService;

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

@@ -1,9 +1,12 @@
 package com.usoftchina.saas.account.controller;
 
+import com.usoftchina.saas.account.cache.AccountCache;
 import com.usoftchina.saas.account.dto.RoleDTO;
 import com.usoftchina.saas.account.dto.RoleSaveDTO;
 import com.usoftchina.saas.account.dto.RoleUpdateDTO;
+import com.usoftchina.saas.account.po.Account;
 import com.usoftchina.saas.account.po.Role;
+import com.usoftchina.saas.account.service.AccountService;
 import com.usoftchina.saas.account.service.RoleService;
 import com.usoftchina.saas.base.Result;
 import com.usoftchina.saas.commons.dto.DocBaseDTO;
@@ -27,6 +30,9 @@ public class RoleController {
     @Autowired
     private RoleService roleService;
 
+    @Autowired
+    private AccountService accountService;
+
     /**
      * 保存
      *
@@ -50,6 +56,7 @@ public class RoleController {
     public Result update(@RequestBody RoleUpdateDTO roleUpdateDTO) {
         Role role = BeanMapper.map(roleUpdateDTO, Role.class);
         roleService.updateByPrimaryKey(role);
+        clearAccountCacheByRoleId(roleUpdateDTO.getId());
         return Result.success();
     }
 
@@ -61,6 +68,7 @@ public class RoleController {
      */
     @PostMapping("/delete/{id}")
     public Result delete(@PathVariable Long id) {
+        clearAccountCacheByRoleId(id);
         roleService.removeByPrimaryKey(id);
         return Result.success();
     }
@@ -104,6 +112,7 @@ public class RoleController {
     @PostMapping("/bind/resource")
     public Result bindResource(@RequestParam long roleId, @RequestParam long resourceId) {
         roleService.bindResource(roleId, resourceId);
+        clearAccountCacheByRoleId(roleId);
         return Result.success();
     }
 
@@ -117,6 +126,19 @@ public class RoleController {
     @PostMapping("/unbind/resource")
     public Result unbindResource(@RequestParam long roleId, @RequestParam long resourceId) {
         roleService.unbindResource(roleId, resourceId);
+        clearAccountCacheByRoleId(roleId);
         return Result.success();
     }
+
+    /**
+     * 清除角色相关所有账户的缓存
+     *
+     * @param roleId
+     */
+    private void clearAccountCacheByRoleId(long roleId) {
+        List<Account> accounts = accountService.findByRoleId(roleId);
+        if (!CollectionUtils.isEmpty(accounts)) {
+            accounts.forEach(account -> accountService.clearCache(account.getId()));
+        }
+    }
 }

+ 10 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/AccountMapper.java

@@ -3,6 +3,8 @@ package com.usoftchina.saas.account.mapper;
 import com.usoftchina.saas.account.po.Account;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * @author yingp
  * @date 2018/10/2
@@ -56,6 +58,14 @@ public interface AccountMapper {
      */
     Account selectByEmail(@Param("email") String email);
 
+    /**
+     * 按角色查找
+     *
+     * @param roleId
+     * @return
+     */
+    List<Account> selectByRoleId(@Param("roleId") Long roleId);
+
     /**
      * 删除
      *

+ 9 - 1
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/AccountRoleMapper.java

@@ -10,11 +10,12 @@ public interface AccountRoleMapper {
     /**
      * 新增
      *
+     * @param companyId
      * @param accountId
      * @param roleId
      * @return
      */
-    int insert(@Param("accountId") Long accountId, @Param("roleId") Long roleId);
+    int insert(@Param("companyId") Long companyId, @Param("accountId") Long accountId, @Param("roleId") Long roleId);
 
     /**
      * 删除
@@ -31,6 +32,13 @@ public interface AccountRoleMapper {
      */
     void deleteByAccountId(@Param("accountId") Long accountId);
 
+    /**
+     * 按公司删除
+     *
+     * @param companyId
+     */
+    void deleteByCompanyId(@Param("companyId") Long companyId);
+
     /**
      * 按角色删除
      *

+ 16 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/ResourceMapper.java

@@ -26,4 +26,20 @@ public interface ResourceMapper {
      * @return
      */
     List<Resource> selectByAppId(@Param("appId") String appId);
+
+    /**
+     * 按角色查找
+     *
+     * @param roleId
+     * @return
+     */
+    List<Resource> selectByRoleId(@Param("roleId") Long roleId);
+
+    /**
+     * 按主键查找
+     *
+     * @param id
+     * @return
+     */
+    Resource selectByPrimaryKey(@Param("id") Long id);
 }

+ 11 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/RoleMapper.java

@@ -2,10 +2,21 @@ package com.usoftchina.saas.account.mapper;
 
 import com.usoftchina.saas.account.po.Role;
 import com.usoftchina.saas.base.mapper.CommonBaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * @author yingp
  * @date 2018/10/2
  */
 public interface RoleMapper extends CommonBaseMapper<Role> {
+
+    /**
+     * 按账户查找绑定的角色
+     *
+     * @param accountId
+     * @return
+     */
+    List<Role> selectByAccountId(@Param("accountId") long accountId);
 }

+ 22 - 1
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/mapper/RoleResourceMapper.java

@@ -1,7 +1,10 @@
 package com.usoftchina.saas.account.mapper;
 
+import com.usoftchina.saas.account.po.RoleResource;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * @author yingp
  * @date 2018/10/2
@@ -10,11 +13,13 @@ public interface RoleResourceMapper {
     /**
      * 新增
      *
+     * @param appId
+     * @param companyId
      * @param roleId
      * @param resourceId
      * @return
      */
-    int insert(@Param("roleId") Long roleId, @Param("resourceId") Long resourceId);
+    int insert(@Param("appId") String appId, @Param("companyId") Long companyId, @Param("roleId") Long roleId, @Param("resourceId") Long resourceId);
 
     /**
      * 删除
@@ -32,4 +37,20 @@ public interface RoleResourceMapper {
      * @return
      */
     int deleteByRoleId(@Param("roleId") Long roleId);
+
+    /**
+     * 按公司删除
+     *
+     * @param companyId
+     * @return
+     */
+    int deleteByCompanyId(@Param("companyId") Long companyId);
+
+    /**
+     * 按账户查询绑定的角色+资源
+     *
+     * @param accountId
+     * @return
+     */
+    List<RoleResource> selectByAccountId(@Param("accountId") Long accountId);
 }

+ 12 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/Account.java

@@ -17,6 +17,10 @@ public class Account implements Serializable {
     private String realname;
     private String email;
     private String mobile;
+    /**
+     * 头像
+     */
+    private String avatarUrl;
     /**
      * 账号类型 0 - 管理员
      */
@@ -75,6 +79,14 @@ public class Account implements Serializable {
         this.mobile = mobile;
     }
 
+    public String getAvatarUrl() {
+        return avatarUrl;
+    }
+
+    public void setAvatarUrl(String avatarUrl) {
+        this.avatarUrl = avatarUrl;
+    }
+
     public Integer getType() {
         return type;
     }

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

@@ -11,6 +11,12 @@ import java.io.Serializable;
 public class AccountRole implements Serializable {
     private long accountId;
     private long roleId;
+    /**
+     * 角色所属公司
+     *
+     * <p>冗余字段,方便查询</p>
+     */
+    private long companyId;
 
     public long getAccountId() {
         return accountId;
@@ -27,4 +33,12 @@ public class AccountRole implements Serializable {
     public void setRoleId(long roleId) {
         this.roleId = roleId;
     }
+
+    public long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(long companyId) {
+        this.companyId = companyId;
+    }
 }

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

@@ -10,6 +10,12 @@ import java.io.Serializable;
  */
 public class Resource implements Serializable {
     private Long id;
+    /**
+     * 归属应用
+     *
+     * <p>冗余字段,方便查询</p>
+     */
+    private String appId;
     /**
      * 资源组
      */
@@ -51,6 +57,14 @@ public class Resource implements Serializable {
         this.id = id;
     }
 
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
     public String getType() {
         return type;
     }

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

@@ -11,6 +11,12 @@ import java.io.Serializable;
  */
 public class ResourceGroup implements Serializable {
     private Long id;
+    /**
+     * 归属应用
+     *
+     * <p>冗余字段,方便查询</p>
+     */
+    private String appId;
     private Long moduleId;
     private String name;
 
@@ -22,6 +28,14 @@ public class ResourceGroup implements Serializable {
         this.id = id;
     }
 
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
     public Long getModuleId() {
         return moduleId;
     }

+ 26 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/po/RoleResource.java

@@ -10,7 +10,33 @@ import java.io.Serializable;
  */
 public class RoleResource implements Serializable {
     private long roleId;
+    /**
+     * 资源所属应用
+     * <p>冗余字段,方便查询</p>
+     */
+    private String appId;
     private long resourceId;
+    /**
+     * 角色所属公司
+     * <p>冗余字段,方便查询</p>
+     */
+    private long companyId;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(long companyId) {
+        this.companyId = companyId;
+    }
 
     public long getRoleId() {
         return roleId;

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

@@ -1,6 +1,9 @@
 package com.usoftchina.saas.account.service;
 
 import com.usoftchina.saas.account.po.Account;
+import com.usoftchina.saas.account.po.RoleResource;
+
+import java.util.List;
 
 /**
  * @author yingp
@@ -39,6 +42,22 @@ public interface AccountService {
      */
     Account findByEmail(String email);
 
+    /**
+     * 按主键查找
+     *
+     * @param id
+     * @return
+     */
+    Account findByPrimaryKey(Long id);
+
+    /**
+     * 按角色查找
+     *
+     * @param roleId
+     * @return
+     */
+    List<Account> findByRoleId(Long roleId);
+
     /**
      * 校验密码
      *
@@ -111,4 +130,18 @@ public interface AccountService {
      */
     void enable(Long accountId);
 
+    /**
+     * 按账户查找绑定的角色+资源
+     *
+     * @param accountId
+     * @return
+     */
+    List<RoleResource> findRoleResourcesByAccountId(Long accountId);
+
+    /**
+     * 清除账户相关缓存
+     *
+     * @param accountId
+     */
+    void clearCache(Long accountId);
 }

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

@@ -26,4 +26,20 @@ public interface ResourceService {
      * @return
      */
     List<UrlResourceDTO> findUrlResourcesByAppId(String appId);
+
+    /**
+     * 按角色查找绑定的资源
+     *
+     * @param roleId
+     * @return
+     */
+    List<UrlResourceDTO> findUrlResourcesByRoleId(Long roleId);
+
+    /**
+     * 按主键查找资源
+     *
+     * @param id
+     * @return
+     */
+    Resource findByPrimaryKey(Long id);
 }

+ 12 - 1
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/RoleService.java

@@ -1,14 +1,17 @@
 package com.usoftchina.saas.account.service;
 
+import com.usoftchina.saas.account.dto.RoleBaseDTO;
 import com.usoftchina.saas.account.mapper.RoleMapper;
 import com.usoftchina.saas.account.po.Role;
 import com.usoftchina.saas.base.service.CommonBaseService;
 
+import java.util.List;
+
 /**
  * @author yingp
  * @date 2018/10/24
  */
-public interface RoleService extends CommonBaseService<RoleMapper, Role>{
+public interface RoleService extends CommonBaseService<RoleMapper, Role> {
 
     /**
      * 角色绑定资源
@@ -25,4 +28,12 @@ public interface RoleService extends CommonBaseService<RoleMapper, Role>{
      * @param resourceId
      */
     void unbindResource(long roleId, long resourceId);
+
+    /**
+     * 按账户查找绑定角色
+     *
+     * @param accountId
+     * @return
+     */
+    List<RoleBaseDTO> findByAccountId(Long accountId);
 }

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

@@ -1,15 +1,22 @@
 package com.usoftchina.saas.account.service.impl;
 
+import com.usoftchina.saas.account.cache.AccountCache;
 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.Role;
+import com.usoftchina.saas.account.po.RoleResource;
 import com.usoftchina.saas.account.service.AccountService;
+import com.usoftchina.saas.account.service.RoleService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.DigestUtils;
 
+import java.util.List;
+
 /**
  * @author yingp
  * @date 2018/10/2
@@ -26,6 +33,12 @@ public class AccountServiceImpl implements AccountService {
     @Autowired
     private AccountRoleMapper accountRoleMapper;
 
+    @Autowired
+    private RoleService roleService;
+
+    @Autowired
+    private RoleResourceMapper roleResourceMapper;
+
     @Override
     public boolean save(Account account) {
         return accountMapper.insert(account) > 0;
@@ -46,6 +59,11 @@ public class AccountServiceImpl implements AccountService {
         return accountMapper.selectByEmail(email);
     }
 
+    @Override
+    public Account findByPrimaryKey(Long id) {
+        return accountMapper.selectByPrimaryKey(id);
+    }
+
     @Override
     public boolean checkPwd(Account account, String plainPassword) {
         return getEncryptedPassword(plainPassword, account.getSalt()).equals(account.getPassword());
@@ -75,7 +93,10 @@ public class AccountServiceImpl implements AccountService {
 
     @Override
     public void bindRole(Long accountId, Long roleId) {
-        accountRoleMapper.insert(accountId, roleId);
+        Role role = roleService.findByPrimaryKey(roleId);
+        if (null != role) {
+            accountRoleMapper.insert(role.getCompanyId(), accountId, roleId);
+        }
     }
 
     @Override
@@ -106,4 +127,19 @@ public class AccountServiceImpl implements AccountService {
             accountMapper.updateEnabled(accountId, false);
         }
     }
+
+    @Override
+    public List<RoleResource> findRoleResourcesByAccountId(Long accountId) {
+        return roleResourceMapper.selectByAccountId(accountId);
+    }
+
+    @Override
+    public List<Account> findByRoleId(Long roleId) {
+        return accountMapper.selectByRoleId(roleId);
+    }
+
+    @Override
+    public void clearCache(Long accountId) {
+        AccountCache.of(accountId).hdel();
+    }
 }

+ 14 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/ResourceServiceImpl.java

@@ -101,4 +101,18 @@ public class ResourceServiceImpl implements ResourceService {
         }
         return null;
     }
+
+    @Override
+    public List<UrlResourceDTO> findUrlResourcesByRoleId(Long roleId) {
+        List<Resource> resources = resourceMapper.selectByRoleId(roleId);
+        if (!CollectionUtils.isEmpty(resources)) {
+            return BeanMapper.mapList(resources, UrlResourceDTO.class);
+        }
+        return null;
+    }
+
+    @Override
+    public Resource findByPrimaryKey(Long id) {
+        return resourceMapper.selectByPrimaryKey(id);
+    }
 }

+ 24 - 1
base-servers/account/account-server/src/main/java/com/usoftchina/saas/account/service/impl/RoleServiceImpl.java

@@ -1,18 +1,25 @@
 package com.usoftchina.saas.account.service.impl;
 
 import com.usoftchina.saas.account.constant.RoleType;
+import com.usoftchina.saas.account.dto.RoleBaseDTO;
 import com.usoftchina.saas.account.mapper.AccountRoleMapper;
 import com.usoftchina.saas.account.mapper.RoleMapper;
 import com.usoftchina.saas.account.mapper.RoleResourceMapper;
+import com.usoftchina.saas.account.po.Resource;
 import com.usoftchina.saas.account.po.Role;
+import com.usoftchina.saas.account.service.ResourceService;
 import com.usoftchina.saas.account.service.RoleService;
 import com.usoftchina.saas.base.service.CommonBaseServiceImpl;
+import com.usoftchina.saas.utils.BeanMapper;
+import com.usoftchina.saas.utils.CollectionUtils;
 import com.usoftchina.saas.utils.StringUtils;
 import org.apache.commons.lang.RandomStringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
+
 /**
  * @author yingp
  * @date 2018/10/24
@@ -28,6 +35,9 @@ public class RoleServiceImpl extends CommonBaseServiceImpl<RoleMapper, Role> imp
     @Autowired
     private AccountRoleMapper accountRoleMapper;
 
+    @Autowired
+    private ResourceService resourceService;
+
     @Override
     public boolean save(Role role) {
         if (StringUtils.isEmpty(role.getCode())) {
@@ -40,7 +50,11 @@ public class RoleServiceImpl extends CommonBaseServiceImpl<RoleMapper, Role> imp
 
     @Override
     public void bindResource(long roleId, long resourceId) {
-        roleResourceMapper.insert(roleId, resourceId);
+        Role role = findByPrimaryKey(roleId);
+        Resource resource = resourceService.findByPrimaryKey(resourceId);
+        if (null != role && null != resource) {
+            roleResourceMapper.insert(resource.getAppId(), role.getCompanyId(), roleId, resourceId);
+        }
     }
 
     @Override
@@ -55,4 +69,13 @@ public class RoleServiceImpl extends CommonBaseServiceImpl<RoleMapper, Role> imp
         roleResourceMapper.deleteByRoleId(id);
         return super.removeByPrimaryKey(id);
     }
+
+    @Override
+    public List<RoleBaseDTO> findByAccountId(Long accountId) {
+        List<Role> roles = getMapper().selectByAccountId(accountId);
+        if (!CollectionUtils.isEmpty(roles)) {
+            return BeanMapper.mapList(roles, RoleBaseDTO.class);
+        }
+        return null;
+    }
 }

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

@@ -35,6 +35,9 @@ spring:
       connection-timeout: 30000
   messages:
     basename: i18n/messages
+  redis:
+    host: 192.168.253.12
+    port: 6379
 eureka:
   instance:
     leaseRenewalIntervalInSeconds: 10

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

@@ -17,7 +17,9 @@
         <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
     </resultMap>
     <sql id="baseColumns">
-        id,username,password,salt,realname,email,mobile,type,enabled,creator_id,create_time,updater_id,update_time
+        ac_account.id,ac_account.username,ac_account.password,ac_account.salt,ac_account.realname,ac_account.email,
+        ac_account.mobile,ac_account.type,ac_account.enabled,ac_account.creator_id,ac_account.create_time,
+        ac_account.updater_id,ac_account.update_time
     </sql>
     <insert id="insert" parameterType="com.usoftchina.saas.account.po.Account">
         insert into ac_account(username,password,salt,realname,email,mobile,type,enabled,creator_id,create_time,updater_id,update_time)
@@ -116,6 +118,10 @@
     <select id="selectByEmail" parameterType="java.lang.String" resultMap="BaseResultMap">
         select <include refid="baseColumns"/> from ac_account where email=#{email}
     </select>
+    <select id="selectByRoleId" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from ac_account,ac_account_role where
+        ac_account.id=ac_account_role.account_id and ac_account_role.role_id=#{roleId,jdbcType=BIGINT}
+    </select>
     <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
         delete from ac_account where id=#{id}
     </delete>

+ 4 - 1
base-servers/account/account-server/src/main/resources/mapper/AccountRoleMapper.xml

@@ -2,7 +2,7 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 <mapper namespace="com.usoftchina.saas.account.mapper.AccountRoleMapper">
     <insert id="insert">
-        insert into ac_account_role(account_id,role_id) values (#{accountId}, #{roleId})
+        insert into ac_account_role(company_id,account_id,role_id) values (#{companyId}, #{accountId}, #{roleId})
     </insert>
     <delete id="delete">
         delete from ac_account_role where account_id=#{accountId} and role_id=#{roleId}
@@ -13,4 +13,7 @@
     <delete id="deleteByRoleId" parameterType="java.lang.Long">
         delete from ac_account_role where role_id=#{roleId}
     </delete>
+    <delete id="deleteByCompanyId" parameterType="java.lang.Long">
+        delete from ac_account_role where company_id=#{companyId}
+    </delete>
 </mapper>

+ 9 - 1
base-servers/account/account-server/src/main/resources/mapper/ResourceMapper.xml

@@ -3,6 +3,7 @@
 <mapper namespace="com.usoftchina.saas.account.mapper.ResourceMapper">
     <resultMap id="BaseResultMap" type="com.usoftchina.saas.account.po.Resource">
         <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="app_id" jdbcType="VARCHAR" property="appId"/>
         <result column="name" jdbcType="VARCHAR" property="name"/>
         <result column="group_id" jdbcType="BIGINT" property="groupId"/>
         <result column="type" jdbcType="VARCHAR" property="type"/>
@@ -11,7 +12,7 @@
         <result column="classify" jdbcType="VARCHAR" property="classify"/>
     </resultMap>
     <sql id="baseColumns">
-        ac_resource.id,ac_resource.name,ac_resource.group_id,ac_resource.type,ac_resource.url,ac_resource.method,ac_resource.classify
+        ac_resource.id,ac_resource.app_id,ac_resource.name,ac_resource.group_id,ac_resource.type,ac_resource.url,ac_resource.method,ac_resource.classify
     </sql>
     <select id="selectByGroupId" parameterType="java.lang.Long" resultMap="BaseResultMap">
         select <include refid="baseColumns"/> from ac_resource where group_id=#{groupId,jdbcType=BIGINT}
@@ -21,4 +22,11 @@
         ac_resource_module.id=ac_resource_group.module_id and ac_resource_group.id=ac_resource.group_id
         and ac_resource_module.app_id=#{appId,jdbcType=VARCHAR}
     </select>
+    <select id="selectByRoleId" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from ac_resource,ac_role_resource where
+        ac_resource.id=ac_role_resource.resource_id and ac_role_resource.role_id=#{roleId,jdbcType=BIGINT}
+    </select>
+    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from ac_resource where id=#{id,jdbcType=BIGINT}
+    </select>
 </mapper>

+ 6 - 1
base-servers/account/account-server/src/main/resources/mapper/RoleMapper.xml

@@ -14,7 +14,8 @@
         <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
     </resultMap>
     <sql id="baseColumns">
-        id,code,name,description,type,company_id,creator_id,create_time,updater_id,update_time
+        ac_role.id,ac_role.code,ac_role.name,ac_role.description,ac_role.type,ac_role.company_id,
+        ac_role.creator_id,ac_role.create_time,ac_role.updater_id,ac_role.update_time
     </sql>
     <insert id="insert" parameterType="com.usoftchina.saas.account.po.Role"
             useGeneratedKeys="true" keyProperty="id">
@@ -99,4 +100,8 @@
     <select id="selectByCompanyId" parameterType="java.lang.Long" resultMap="BaseResultMap">
         select <include refid="baseColumns"/> from ac_role where company_id=#{companyId,jdbcType=BIGINT}
     </select>
+    <select id="selectByAccountId" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from ac_role,ac_account_role
+        where ac_role.id=ac_account_role.role_id and ac_account_role.account_id=#{accountId,jdbcType=BIGINT}
+    </select>
 </mapper>

+ 15 - 1
base-servers/account/account-server/src/main/resources/mapper/RoleResourceMapper.xml

@@ -2,7 +2,7 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 <mapper namespace="com.usoftchina.saas.account.mapper.RoleResourceMapper">
     <insert id="insert">
-        insert into ac_role_resource(role_id,resource_id) values (#{roleId}, #{resourceId})
+        insert into ac_role_resource(app_id,company_id,role_id,resource_id) values (#{appId}, #{companyId}, #{roleId}, #{resourceId})
     </insert>
     <delete id="delete">
         delete from ac_role_resource where role_id=#{roleId} and resource_id=#{resourceId}
@@ -10,4 +10,18 @@
     <delete id="deleteByRoleId" parameterType="java.lang.Long">
         delete from ac_role_resource where role_id=#{roleId}
     </delete>
+    <delete id="deleteByCompanyId" parameterType="java.lang.Long">
+        delete from ac_role_resource where company_id=#{companyId}
+    </delete>
+    <resultMap id="BaseResultMap" type="com.usoftchina.saas.account.po.RoleResource">
+        <result column="role_id" jdbcType="BIGINT" property="roleId"/>
+        <result column="app_id" jdbcType="VARCHAR" property="appId"/>
+        <result column="company_id" jdbcType="BIGINT" property="companyId"/>
+        <result column="resource_id" jdbcType="BIGINT" property="resourceId"/>
+    </resultMap>
+    <select id="selectByAccountId" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select ac_role_resource.* from ac_account_role,ac_role_resource
+        where ac_account_role.role_id=ac_role_resource.role_id
+        and ac_account_role.account_id=#{accountId,jdbcType=BIGINT}
+    </select>
 </mapper>

+ 65 - 6
base-servers/account/account-server/src/test/java/com/usoftchina/saas/account/controller/AccountControllerTest.java

@@ -3,7 +3,9 @@ package com.usoftchina.saas.account.controller;
 import com.usoftchina.saas.account.constant.AccountType;
 import com.usoftchina.saas.account.dto.AccountDTO;
 import com.usoftchina.saas.account.dto.AccountRegDTO;
+import com.usoftchina.saas.account.dto.RoleSaveDTO;
 import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.commons.dto.DocBaseDTO;
 import com.usoftchina.saas.test.BaseControllerTest;
 import com.usoftchina.saas.test.TestConstant;
 import org.junit.*;
@@ -58,14 +60,53 @@ public class AccountControllerTest extends BaseControllerTest {
                 .andExpect(isFail());
     }
 
-    @Test
-    public void testD_getAccount() throws Exception {
-        AccountDTO accountDTO = getAccountDTO();
-        Assert.assertEquals(accountDTO.getMobile(), mobile);
+    private DocBaseDTO createRole() throws Exception {
+        RoleSaveDTO role = new RoleSaveDTO();
+        role.setName("Tester");
+        role.setDescription("测试员");
+
+        MvcResult mvcResult = mockMvc.perform(requestBody("/role/save", role))
+                .andExpect(isSuccess())
+                .andReturn();
+        Result<DocBaseDTO> result = result(mvcResult, DocBaseDTO.class);
+        return result.getData();
+    }
+
+    private void deleteRole(Long roleId) throws Exception {
+        mockMvc.perform(post("/role/delete/{id}", roleId))
+                .andExpect(isSuccess());
+    }
+
+    private void roleBindResource(Long roleId, Long resourceId) throws Exception{
+        mockMvc.perform(post("/role/bind/resource")
+                .param("roleId", String.valueOf(roleId))
+                .param("resourceId", String.valueOf(resourceId)))
+                .andExpect(isSuccess());
+    }
+
+    private void roleUnbindResource(Long roleId, Long resourceId) throws Exception{
+        mockMvc.perform(post("/role/unbind/resource")
+                .param("roleId", String.valueOf(roleId))
+                .param("resourceId", String.valueOf(resourceId)))
+                .andExpect(isSuccess());
+    }
+
+    private void accountBindRole(Long accountId, Long roleId) throws Exception{
+        mockMvc.perform(post("/account/bind/role")
+                .param("accountId", String.valueOf(accountId))
+                .param("roleId", String.valueOf(roleId)))
+                .andExpect(isSuccess());
+    }
+
+    private void accountUnbindRole(Long accountId, Long roleId) throws Exception{
+        mockMvc.perform(post("/account/unbind/role")
+                .param("accountId", String.valueOf(accountId))
+                .param("roleId", String.valueOf(roleId)))
+                .andExpect(isSuccess());
     }
 
     private AccountDTO getAccountDTO() throws Exception {
-        MvcResult mvcResult = mockMvc.perform(get("/account")
+        MvcResult mvcResult = mockMvc.perform(get("/account/read")
                 .param("username", mobile))
                 .andExpect(isSuccess())
                 .andReturn();
@@ -75,7 +116,7 @@ public class AccountControllerTest extends BaseControllerTest {
     }
 
     @Test
-    public void testE_bindCompany() throws Exception {
+    public void testD_bindCompany() throws Exception {
         AccountDTO accountDTO = getAccountDTO();
         mockMvc.perform(post("/account/bind/company")
                 .param("accountId", String.valueOf(accountDTO.getId()))
@@ -83,6 +124,24 @@ public class AccountControllerTest extends BaseControllerTest {
                 .andExpect(isSuccess());
     }
 
+    @Test
+    public void testE_bindRole() throws Exception {
+        AccountDTO accountDTO = getAccountDTO();
+        DocBaseDTO role = createRole();
+        roleBindResource(role.getId(), 1L);
+        roleBindResource(role.getId(), 2L);
+        accountBindRole(accountDTO.getId(), role.getId());
+
+        getAccountDTO();
+
+        accountUnbindRole(accountDTO.getId(), role.getId());
+        roleUnbindResource(role.getId(), 2L);
+        roleUnbindResource(role.getId(), 1L);
+        deleteRole(role.getId());
+
+        getAccountDTO();
+    }
+
     @Test
     public void testF_unbindCompany() throws Exception {
         AccountDTO accountDTO = getAccountDTO();

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

@@ -25,10 +25,6 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-redis</artifactId>
-        </dependency>
     </dependencies>
 
 </project>

+ 8 - 0
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/api/AuthApi.java

@@ -32,4 +32,12 @@ public interface AuthApi {
      */
     @GetMapping(value = "/api/auth/switch/company")
     Result<TokenDTO> switchCompany(@RequestParam(value = "companyId") String companyId);
+
+    /**
+     * 获取auth信息
+     *
+     * @return
+     */
+    @GetMapping("/info")
+    Result<AuthDTO> getInfo();
 }

+ 0 - 47
base-servers/auth/auth-api/src/main/java/com/usoftchina/saas/auth/cache/TokenCache.java

@@ -1,47 +0,0 @@
-package com.usoftchina.saas.auth.cache;
-
-import com.usoftchina.saas.auth.api.AuthApi;
-import com.usoftchina.saas.cache.RedisHashCache;
-import com.usoftchina.saas.context.SpringContextHolder;
-import org.springframework.data.redis.core.RedisTemplate;
-
-import java.util.function.Supplier;
-
-/**
- * @author yingp
- * @date 2018/9/30
- */
-public class TokenCache extends RedisHashCache<String, String, String> {
-
-    private final String account;
-
-    private final String password;
-
-    private final AuthApi authApi;
-
-    private TokenCache(String account, String password) {
-        super(() -> SpringContextHolder.getBean(RedisTemplate.class));
-        this.account = account;
-        this.password = password;
-        this.authApi = SpringContextHolder.getBean(AuthApi.class);
-    }
-
-    public static TokenCache of(String account, String password) {
-        return new TokenCache(account, password);
-    }
-
-    @Override
-    protected String key() {
-        return generateKey("auth", "token");
-    }
-
-    @Override
-    protected String field() {
-        return String.valueOf(account);
-    }
-
-    @Override
-    protected Supplier<String> getSupplier() {
-        return () -> authApi.authorize(account, password).getData().getToken().getToken();
-    }
-}

+ 19 - 0
base-servers/auth/auth-server/src/main/java/com/usoftchina/saas/auth/controller/AuthController.java

@@ -87,6 +87,25 @@ public class AuthController {
         return Result.error(ExceptionCode.COMPANY_NOT_BIND);
     }
 
+    /**
+     * 获取auth信息
+     *
+     * @param request
+     * @return
+     */
+    @GetMapping("/info")
+    public Result<AuthDTO> getInfo(HttpServletRequest request) {
+        String token = request.getHeader(authHeader);
+        JwtInfo infoFromToken = JwtHelper.getInfoFromToken(token, publicKeyPath);
+        Result<AccountDTO> result = accountApi.getAccount(infoFromToken.getUserName());
+        if (result.isSuccess()) {
+            TokenVO tokenVO = JwtHelper.generateToken(infoFromToken, privateKeyPath, expire);
+            TokenDTO tokenDTO = BeanMapper.map(tokenVO, TokenDTO.class);
+            return Result.success(new AuthDTO(tokenDTO, result.getData()));
+        }
+        return Result.error(result);
+    }
+
     /**
      * 指定公司是否可用:
      * 公司是否存在 + 是否已绑定

+ 4 - 0
base-servers/gateway-server/pom.xml

@@ -68,6 +68,10 @@
             <groupId>com.usoftchina.saas</groupId>
             <artifactId>auth-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>account-api</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>

+ 4 - 1
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/GatewayApplication.java

@@ -11,7 +11,10 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
  */
 @SpringBootApplication
 @EnableEurekaClient
-@EnableFeignClients(basePackages = "com.usoftchina.saas.auth.api")
+@EnableFeignClients(basePackages = {
+        "com.usoftchina.saas.account.api",
+        "com.usoftchina.saas.auth.api"
+})
 public class GatewayApplication {
     public static void main(String[] args) {
         SpringApplication.run(GatewayApplication.class, args);

+ 53 - 1
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/config/AuthFilter.java

@@ -1,9 +1,16 @@
 package com.usoftchina.saas.gateway.config;
 
+import com.usoftchina.saas.account.cache.AccountCache;
+import com.usoftchina.saas.account.cache.ResourceCache;
+import com.usoftchina.saas.account.dto.AccountDTO;
+import com.usoftchina.saas.account.dto.UrlResourceDTO;
 import com.usoftchina.saas.auth.common.jwt.JwtHelper;
 import com.usoftchina.saas.auth.common.jwt.JwtInfo;
 import com.usoftchina.saas.exception.BizException;
 import com.usoftchina.saas.exception.ExceptionCode;
+import com.usoftchina.saas.gateway.error.PermissionException;
+import com.usoftchina.saas.gateway.util.AntPathRequestMatcher;
+import com.usoftchina.saas.utils.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.cloud.gateway.filter.GatewayFilterChain;
@@ -15,6 +22,8 @@ import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
 
 /**
  * 全局过滤器鉴权
@@ -33,12 +42,55 @@ public class AuthFilter implements GlobalFilter, Ordered {
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         if (!isIgnore(exchange.getRequest())) {
             // 鉴别身份信息
-//            JwtInfo jwt = getJwtInfoFromHeader(exchange.getRequest());
+            JwtInfo jwt = getJwtInfoFromHeader(exchange.getRequest());
+            AccountDTO accountDTO = AccountCache.of(jwt.getUserId()).getAccount();
+            if (null == accountDTO) {
+                throw new BizException(ExceptionCode.USER_NOT_EXIST);
+            }
             // 鉴别角色权限
+            checkPermission(exchange.getRequest(), jwt, accountDTO);
         }
         return chain.filter(exchange);
     }
 
+    /**
+     * 鉴别角色权限
+     *
+     * @param request
+     * @param jwt
+     * @param accountDTO
+     */
+    private void checkPermission(ServerHttpRequest request, JwtInfo jwt, AccountDTO accountDTO) {
+        if (!accountDTO.isAdmin(jwt.getCompanyId())) {
+            // 非管理账户,需要鉴权
+            List<UrlResourceDTO> resources = ResourceCache.of(jwt.getAppId()).getUrlResources();
+            if (!CollectionUtils.isEmpty(resources)) {
+                // 本次请求相关的资源
+                Stream<UrlResourceDTO> permissions = resources.parallelStream().filter(resource -> {
+                    AntPathRequestMatcher matcher = new AntPathRequestMatcher(resource.getUrl(), resource.getMethod());
+                    return matcher.matches(request);
+                });
+                if (permissions.count() > 0) {
+                    Set<Long> resourceIds = accountDTO.getResources(jwt.getAppId(), jwt.getCompanyId());
+                    boolean permitted = false;
+                    if (null != resourceIds) {
+                        // 权限匹配
+                        permitted = permissions.anyMatch(resource -> resourceIds.contains(resource.getId()));
+                    }
+                    if (!permitted) {
+                        throw new PermissionException(permissions.findFirst().get());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 是否设置为忽略鉴权的请求
+     *
+     * @param request
+     * @return
+     */
     private boolean isIgnore(ServerHttpRequest request) {
         String path = request.getPath().value();
         return authConfig.getIgnores().stream().anyMatch(ignore -> ignore.equals(path));

+ 18 - 0
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/context/SpringContextListener.java

@@ -0,0 +1,18 @@
+package com.usoftchina.saas.gateway.context;
+
+import com.usoftchina.saas.context.SpringContextHolder;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * @author yingp
+ * @date 2018/7/18
+ */
+@Configuration
+public class SpringContextListener implements ApplicationListener<ContextRefreshedEvent> {
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        SpringContextHolder.setContext(event.getApplicationContext());
+    }
+}

+ 20 - 0
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/error/PermissionException.java

@@ -0,0 +1,20 @@
+package com.usoftchina.saas.gateway.error;
+
+import com.usoftchina.saas.account.dto.UrlResourceDTO;
+import com.usoftchina.saas.exception.BaseUncheckedException;
+import com.usoftchina.saas.exception.ExceptionCode;
+
+/**
+ * @author yingp
+ * @date 2018/11/2
+ */
+public class PermissionException extends BaseUncheckedException {
+    public PermissionException(int code, String message) {
+        super(code, message);
+    }
+
+    public PermissionException(UrlResourceDTO resource) {
+        super(ExceptionCode.MISSING_PERMISSIONS.getCode(),
+                String.format("没有 %s 权限", resource.getName()));
+    }
+}

+ 177 - 0
base-servers/gateway-server/src/main/java/com/usoftchina/saas/gateway/util/AntPathRequestMatcher.java

@@ -0,0 +1,177 @@
+package com.usoftchina.saas.gateway.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/11/1
+ */
+public final class AntPathRequestMatcher {
+    private static final Log logger = LogFactory.getLog(AntPathRequestMatcher.class);
+    private static final String MATCH_ALL = "/**";
+    private final Matcher matcher;
+    private final String pattern;
+    private final HttpMethod httpMethod;
+    private final boolean caseSensitive;
+
+    public AntPathRequestMatcher(String pattern) {
+        this(pattern, null);
+    }
+
+    public AntPathRequestMatcher(String pattern, String httpMethod) {
+        this(pattern, httpMethod, true);
+    }
+
+    public AntPathRequestMatcher(String pattern, String httpMethod, boolean caseSensitive) {
+        Assert.hasText(pattern, "Pattern cannot be null or empty");
+        this.caseSensitive = caseSensitive;
+
+        if (pattern.equals(MATCH_ALL) || pattern.equals("**")) {
+            pattern = MATCH_ALL;
+            this.matcher = null;
+        }
+        else {
+            // If the pattern ends with {@code /**} and has no other wildcards or path
+            // variables, then optimize to a sub-path match
+            if (pattern.endsWith(MATCH_ALL)
+                    && (pattern.indexOf('?') == -1 && pattern.indexOf('{') == -1
+                    && pattern.indexOf('}') == -1)
+                    && pattern.indexOf("*") == pattern.length() - 2) {
+                this.matcher = new SubpathMatcher(pattern.substring(0, pattern.length() - 3), caseSensitive);
+            }
+            else {
+                this.matcher = new SpringAntMatcher(pattern, caseSensitive);
+            }
+        }
+
+        this.pattern = pattern;
+        this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod.resolve(httpMethod)
+                : null;
+    }
+
+    public boolean matches(ServerHttpRequest request) {
+        if (this.httpMethod != null && this.httpMethod != request.getMethod()) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Request '" + request.getMethodValue() + " "
+                        + getRequestPath(request) + "'" + " doesn't match '"
+                        + this.httpMethod + " " + this.pattern);
+            }
+            return false;
+        }
+
+        if (this.pattern.equals(MATCH_ALL)) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Request '" + getRequestPath(request)
+                        + "' matched by universal pattern '/**'");
+            }
+
+            return true;
+        }
+
+        String url = getRequestPath(request);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Checking match of request : '" + url + "'; against '"
+                    + this.pattern + "'");
+        }
+
+        return this.matcher.matches(url);
+    }
+
+    private String getRequestPath(ServerHttpRequest request) {
+        return request.getPath().value();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof AntPathRequestMatcher)) {
+            return false;
+        }
+
+        AntPathRequestMatcher other = (AntPathRequestMatcher) obj;
+        return this.pattern.equals(other.pattern) && this.httpMethod == other.httpMethod
+                && this.caseSensitive == other.caseSensitive;
+    }
+
+    @Override
+    public int hashCode() {
+        int code = 31 ^ this.pattern.hashCode();
+        if (this.httpMethod != null) {
+            code ^= this.httpMethod.hashCode();
+        }
+        return code;
+    }
+
+    private interface Matcher {
+        boolean matches(String path);
+
+        Map<String, String> extractUriTemplateVariables(String path);
+    }
+
+    /**
+     * Optimized matcher for trailing wildcards
+     */
+    private static class SubpathMatcher implements Matcher {
+        private final String subpath;
+        private final int length;
+        private final boolean caseSensitive;
+
+        private SubpathMatcher(String subpath, boolean caseSensitive) {
+            assert!subpath.contains("*");
+            this.subpath = caseSensitive ? subpath : subpath.toLowerCase();
+            this.length = subpath.length();
+            this.caseSensitive = caseSensitive;
+        }
+
+        @Override
+        public boolean matches(String path) {
+            if (!this.caseSensitive) {
+                path = path.toLowerCase();
+            }
+            return path.startsWith(this.subpath)
+                    && (path.length() == this.length || path.charAt(this.length) == '/');
+        }
+
+        @Override
+        public Map<String, String> extractUriTemplateVariables(String path) {
+            return Collections.emptyMap();
+        }
+    }
+
+    private static class SpringAntMatcher implements Matcher {
+        private final AntPathMatcher antMatcher;
+
+        private final String pattern;
+
+        private SpringAntMatcher(String pattern, boolean caseSensitive) {
+            this.pattern = pattern;
+            this.antMatcher = createMatcher(caseSensitive);
+        }
+
+        @Override
+        public boolean matches(String path) {
+            return this.antMatcher.match(this.pattern, path);
+        }
+
+        @Override
+        public Map<String, String> extractUriTemplateVariables(String path) {
+            return this.antMatcher.extractUriTemplateVariables(this.pattern, path);
+        }
+
+        private static AntPathMatcher createMatcher(boolean caseSensitive) {
+            AntPathMatcher matcher = new AntPathMatcher();
+            matcher.setTrimTokens(false);
+            matcher.setCaseSensitive(caseSensitive);
+            return matcher;
+        }
+    }
+}

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

@@ -104,6 +104,9 @@ spring:
         - Path=/api/commons/**
         filters:
         - RewritePath=/api/commons/(?<segment>.*), /$\{segment}
+  redis:
+    host: 192.168.253.12
+    port: 6379
 server:
   port: 8560
   tomcat:

+ 2 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/UiApplication.java

@@ -1,5 +1,6 @@
 package com.usoftchina.saas.ui;
 
+import com.usoftchina.saas.auth.client.EnableAuthClient;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cache.annotation.EnableCaching;
@@ -14,6 +15,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @EnableEurekaClient
 @EnableTransactionManagement
 @EnableCaching
+@EnableAuthClient
 public class UiApplication {
     public static void main(String[] args) {
         SpringApplication.run(UiApplication.class, args);

+ 0 - 4
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/co/CoViewController.java

@@ -40,10 +40,6 @@ public class CoViewController {
             coViewService.cacheEvict(name);
             viewService.cacheEvict(name);
         }
-        // TODO 开发默认设置,及时去掉
-        if (null == BaseContextHolder.getCompanyId()) {
-            BaseContextHolder.setCompanyId(0);
-        }
         Object config = coViewService.getDeepConfig(name);
         if (null == config && null != useDefault && useDefault) {
             // 企业配置不存在则取标准配置

+ 4 - 2
framework/core/pom.xml

@@ -47,12 +47,14 @@
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
-            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
         </dependency>
     </dependencies>
 

+ 8 - 11
framework/core/src/main/java/com/usoftchina/saas/base/Result.java

@@ -1,13 +1,10 @@
 package com.usoftchina.saas.base;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.usoftchina.saas.exception.BaseException;
 import com.usoftchina.saas.exception.BaseExceptionCode;
 import com.usoftchina.saas.utils.JsonUtils;
-import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
 
 import java.io.Serializable;
-import java.lang.reflect.Type;
 
 /**
  * 结果
@@ -89,6 +86,13 @@ public class Result<T> implements Serializable {
         return result;
     }
 
+    public static Result error(Result from) {
+        Result result = error();
+        result.setCode(from.getCode());
+        result.setMessage(from.getMessage());
+        return result;
+    }
+
     public static Result error(int code, String message) {
         Result result = error();
         result.setCode(code);
@@ -135,13 +139,6 @@ public class Result<T> implements Serializable {
      * @return
      */
     public static <T> Result<T> fromJsonString(String jsonString, Class<T> targetCls) {
-        Type[] types = new Type[]{targetCls};
-        final ParameterizedTypeImpl type = ParameterizedTypeImpl.make(Result.class, types, Result.class.getDeclaringClass());
-        return JsonUtils.fromJsonString(jsonString, new TypeReference<Result<T>>() {
-            @Override
-            public Type getType() {
-                return type;
-            }
-        });
+        return JsonUtils.fromJsonString(jsonString, Result.class, targetCls);
     }
 }

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

@@ -35,6 +35,7 @@ public enum ExceptionCode implements BaseExceptionCode {
     USER_NOT_EXIST(53005, "用户不存在"),
     USER_NOT_ENABLE(53006, "用户禁止使用"),
     ROLE_NOT_EXIST(53020, "角色不存在"),
+    MISSING_PERMISSIONS(53030, "权限缺失"),
 
     // 文件相关
     FOLDER_NULL(55000, "文件夹为空"),

+ 112 - 5
framework/core/src/main/java/com/usoftchina/saas/utils/CollectionUtils.java

@@ -1,16 +1,18 @@
 package com.usoftchina.saas.utils;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+
+import java.util.*;
 import java.util.function.Function;
 
 /**
  * @author yingp
  * @date 2018/10/10
  */
-public abstract class CollectionUtils extends org.springframework.util.CollectionUtils{
+public abstract class CollectionUtils extends org.springframework.util.CollectionUtils {
     /**
      * 按指定方法,将list分组返回map
      *
@@ -36,4 +38,109 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
         }
         return map;
     }
+
+    /**
+     * 按两个指定方法,将list分组返回复合键map
+     *
+     * @param sources
+     * @param rKeyGetter
+     * @param cKeyGetter
+     * @param <R>
+     * @param <C>
+     * @param <V>
+     * @return
+     */
+    public static <R, C, V> Table<R, C, List<V>> groupBy(List<V> sources, Function<V, R> rKeyGetter, Function<V, C> cKeyGetter) {
+        Table<R, C, List<V>> table = HashBasedTable.create();
+        if (!isEmpty(sources)) {
+            sources.forEach(source -> {
+                R r = rKeyGetter.apply(source);
+                C c = cKeyGetter.apply(source);
+                if (table.contains(r, c)) {
+                    table.get(r, c).add(source);
+                } else {
+                    List<V> childList = new ArrayList<>();
+                    childList.add(source);
+                    table.put(r, c, childList);
+                }
+            });
+        }
+        return table;
+    }
+
+    /**
+     * 按三个指定方法,将list分组返回复合键map
+     *
+     * @param sources
+     * @param rKeyGetter
+     * @param cKeyGetter
+     * @param valueGetter
+     * @param <R>
+     * @param <C>
+     * @param <V>
+     * @param <S>
+     * @return
+     */
+    public static <R, C, V, S> Map<R, Map<C, List<V>>> groupBy(List<S> sources, Function<S, R> rKeyGetter, Function<S, C> cKeyGetter, Function<S, V> valueGetter) {
+        Map<R, Map<C, List<V>>> table = new HashMap<>(1);
+        if (!isEmpty(sources)) {
+            sources.forEach(source -> {
+                R r = rKeyGetter.apply(source);
+                C c = cKeyGetter.apply(source);
+                V v = valueGetter.apply(source);
+
+                if (table.containsKey(r)) {
+                    Map<C, List<V>> rows = table.get(r);
+                    if (rows.containsKey(c)) {
+                        rows.get(c).add(v);
+                    } else {
+                        rows.put(c, Lists.newArrayList(v));
+                    }
+                } else {
+                    Map<C, List<V>> rows = new HashMap<>(1);
+                    rows.put(c, Lists.newArrayList(v));
+                    table.put(r, rows);
+                }
+            });
+        }
+        return table;
+    }
+
+    /**
+     * 按三个指定方法,将list分组返回复合键map
+     *
+     * @param sources
+     * @param rKeyGetter
+     * @param cKeyGetter
+     * @param valueGetter
+     * @param <R>
+     * @param <C>
+     * @param <V>
+     * @param <S>
+     * @return
+     */
+    public static <R, C, V, S> Map<R, Map<C, Set<V>>> distinctBy(List<S> sources, Function<S, R> rKeyGetter, Function<S, C> cKeyGetter, Function<S, V> valueGetter) {
+        Map<R, Map<C, Set<V>>> table = new HashMap<>(1);
+        if (!isEmpty(sources)) {
+            sources.forEach(source -> {
+                R r = rKeyGetter.apply(source);
+                C c = cKeyGetter.apply(source);
+                V v = valueGetter.apply(source);
+
+                if (table.containsKey(r)) {
+                    Map<C, Set<V>> rows = table.get(r);
+                    if (rows.containsKey(c)) {
+                        rows.get(c).add(v);
+                    } else {
+                        rows.put(c, Sets.newHashSet(v));
+                    }
+                } else {
+                    Map<C, Set<V>> rows = new HashMap<>(1);
+                    rows.put(c, Sets.newHashSet(v));
+                    table.put(r, rows);
+                }
+            });
+        }
+        return table;
+    }
 }

+ 44 - 1
framework/core/src/main/java/com/usoftchina/saas/utils/JsonUtils.java

@@ -1,8 +1,10 @@
 package com.usoftchina.saas.utils;
 
 import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.springframework.util.StringUtils;
+
+import java.util.List;
 
 /**
  * @author yingp
@@ -38,6 +40,47 @@ public class JsonUtils {
         try {
             return mapper.readValue(json, valueTypeRef);
         } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static JavaType getJavaType(Class<?> targetClass, Class<?>... elementClasses) {
+        return mapper.getTypeFactory().constructParametricType(targetClass, elementClasses);
+    }
+
+    public static <T> T fromJsonString(String json, Class<?> targetClass, Class<?>... elementClasses) {
+        if (StringUtils.isEmpty(json)) {
+            return null;
+        }
+        try {
+            return mapper.readValue(json, getJavaType(targetClass, elementClasses));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static <T> T fromJsonString(String json, JavaType type) {
+        if (StringUtils.isEmpty(json)) {
+            return null;
+        }
+        try {
+            return mapper.readValue(json, type);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static <T> List<T> fromJsonArray(String json, Class<T> targetCls) {
+        if (StringUtils.isEmpty(json)) {
+            return null;
+        }
+        try {
+            return mapper.readValue(json, getJavaType(List.class, targetCls));
+        } catch (Exception e) {
+            e.printStackTrace();
             return null;
         }
     }

+ 0 - 1
frontend/saas-web/app/Application.scss

@@ -63,7 +63,6 @@ html, body {
   
   .x-fa {
     display: inline-block;
-    font: normal normal normal 14px/1 $font-family;
   }
   
   .alignRight {

+ 0 - 26
frontend/saas-web/app/model/Account.js

@@ -1,26 +0,0 @@
-Ext.define('saas.model.Account', {
-    extend: 'saas.model.Base',
-
-    fields: [
-        { name: 'username', type: 'string' },
-        { name: 'realname', type: 'string' },
-        { name: 'email', type: 'string' },
-        { name: 'mobile', type: 'string' }
-    ],
-
-    proxy: {
-        api: {
-            prefix: 'Server.people'
-        }
-    },
-
-    statics: {
-        load: function(id, options, session) {
-            var record = Ext.create('saas.model.Account');
-            record.setSession(session);
-            record.load(
-                Ext.apply({ params: { id: id } }, options)
-            );
-        }
-    }
-});

+ 73 - 21
frontend/saas-web/app/model/Session.js

@@ -3,43 +3,95 @@ Ext.define('saas.model.Session', {
 
     fields: [
         { name: 'token', type: 'string' },
-        { name: 'expires', type: 'number' },
+        { name: 'expire', type: 'number' },
         { name: 'timestamp', type: 'number' },
-        { name: 'account', reference: 'Account' }
+        { name: 'span', type: 'number' },
+        { name: 'account' }
     ],
 
     statics: {
         login: function(username, password) {
             return new Ext.Promise(function (resolve, reject) {
-                Server.auth.login({
-                    username: username,
-                    password: password
-                }, function(result, response, success) {
-                    if (!success) {
-                        return reject(result.message);
+				Ext.Ajax.request({
+                    url: '/api/auth/authorize',
+                    params: {
+                        username: username,
+                        password: password
+                    },
+                    method: 'POST',
+                    success: function (response) {
+                        var res = Ext.decode(response.responseText);
+                        if (res.success) {
+                            var session = saas.model.Session.loadData(res.data.token);
+                            session.set('account', res.data.account);
+                            // 服务端与本地存在时间差
+                            session.set('span', session.get('timestamp') - new Date().getTime());
+                            if (!session.isValid()) {
+                                reject({
+                                    message: '登录失败,无效身份令牌'
+                                });
+                            } else {
+                                resolve(session);
+                            }
+                        } else {
+                            Ext.log.error('request failure with code: ', res.code, ', message: ', res.message);
+                            reject(res);
+                        }
+                    },
+                    failure: function (response) {
+                        Ext.log.error('server-side failure with status code: ', response.status);
+                        reject(response);
                     }
-
-                    var session = saas.model.Session.loadData(result);
-                    if (!session.isValid()) {
-                        return reject({ errors: {
-                            username: 'Login failed: invalid session'
-                        }});
-                    }
-
-                    resolve(session);
                 });
             });
+        },
+        switchCompany: function(oldSession, companyId) {
+            return new Ext.Promise(function (resolve, reject) {
+				Ext.Ajax.request({
+                    url: '/api/auth/switch/company',
+                    params: {
+                        companyId: companyId
+                    },
+                    method: 'GET',
+                    headers: {
+                        'Authorization': oldSession.get('token')
+                    },
+                    success: function (response) {
+                        var res = Ext.decode(response.responseText);
+                        if (res.success) {
+                            var newSession = saas.model.Session.loadData(res.data);
+                            newSession.set('account', oldSession.get('account'));
+                            // 服务端与本地存在时间差
+                            newSession.set('span', newSession.get('timestamp') - new Date().getTime());
+                            if (!newSession.isValid()) {
+                                reject({
+                                    message: '切换失败,无效身份令牌'
+                                });
+                            } else {
+                                resolve(newSession);
+                            }
+                        } else {
+                            Ext.log.error('request failure with code: ', res.code, ', message: ', res.message);
+                            reject(res);
+                        }
+                    },
+                    failure: function (response) {
+                        Ext.log.error('server-side failure with status code: ', response.status);
+                        reject(response);
+                    }
+                });
+            });            
         }
     },
 
     isValid: function() {
-        return !Ext.isEmpty(this.get('token'))
-            && this.get('timestamp') + this.get('expires') * 1000 > new Date().getTime();
+        return !Ext.isEmpty(this.get('token')) && this.get('token').length > 128
+            && this.get('timestamp') + this.get('expire') * 1000 > new Date().getTime() + this.get('span');
     },
-
+    
     logout: function() {
         return new Ext.Promise(function (resolve, reject) {
-            Server.auth.logout({}, resolve);
+            resolve({});
         });
     }
 });

+ 9 - 0
frontend/saas-web/app/store/Company.js

@@ -0,0 +1,9 @@
+Ext.define('saas.store.Company', {
+    extend: 'Ext.data.Store',
+
+    fields: [
+        { name: 'id', type: 'int' },
+        { name: 'name', type: 'string' },
+        { name: 'logoUrl', type: 'string' }
+    ]
+});

+ 0 - 1
frontend/saas-web/app/util/BaseUtil.js

@@ -11,7 +11,6 @@ Ext.define('saas.util.BaseUtil', {
             method = config.method || 'GET',
             timeout = config.timeout || 8000,
             defaultHeaders = {
-                'Authorization': ' ',
                 'Access-Control-Allow-Origin': '*',
                 "Content-Type": 'application/json;charset=UTF-8' 
             };

+ 37 - 0
frontend/saas-web/app/view/auth/CompanyPicker.js

@@ -0,0 +1,37 @@
+Ext.define('saas.view.auth.CompanyPicker', {
+    extend: 'Ext.window.Window',
+    xtype: 'companypicker',
+    controller: 'login',
+
+    title: '选择登录公司',
+    width: 500,
+    scrollable: true,
+    resizable: false,
+    autoShow: true,
+    bodyPadding: 10,
+    modal: true,
+    closable: false,
+
+    items: [{
+        xtype: 'dataview',
+        id: 'companies',
+        bind: {
+            store: '{companies}'
+        },
+        tpl: new Ext.XTemplate(
+            '<tpl for=".">',
+                '<div class="thumb">',
+                    '<img src="{logoUrl}" />',
+                    '<strong>{name}</strong>',
+                '</div>',
+            '</tpl>'
+        ),
+        itemSelector: 'div.thumb',
+        overItemCls: 'thumb-hover',
+        listeners: {
+            select: 'selectCompany'
+        }
+    }],
+
+    renderTo: Ext.getBody()
+});

+ 38 - 0
frontend/saas-web/app/view/auth/CompanyPicker.scss

@@ -0,0 +1,38 @@
+#companies {
+    background-color: #fff;
+    text-shadow: #fff 0 1px 0;
+    position: relative;
+    display: block;
+    height: auto;
+
+    div.thumb {
+        @include box-shadow(rgba(0,0,0,0.2) 0 0 8px);
+        float: left;
+        padding: 15px;
+        margin: 5px;
+        text-align: center;
+        line-height: 14px;
+        height: 120px;
+        width: 140px;
+        color: #333;
+        overflow: hidden;
+        border-top: 1px solid transparent;
+        cursor: pointer;
+
+        img {
+            margin-bottom: 10px;
+        }
+
+        strong {
+            display: block;
+        }
+    }
+
+    div.thumb-hover {
+        background-color: $base-over-color;
+    }
+
+    .x-item-selected {
+        background-color: #d3e1f1 !important;
+    }
+}

+ 54 - 26
frontend/saas-web/app/view/auth/LoginController.js

@@ -7,38 +7,66 @@ Ext.define('saas.view.auth.LoginController', {
     },
 
     onLoginButton: function() {
-        // var me = this,
-        //     form = me.lookup('authdialog'),
-        //     values = form.getValues();
-
-        // me.getView().setMasked(true);
-
-        // saas.model.Session.login(values.username, values.password)
-        //     .then(function(session) {
-        //         me.fireEvent('login', session);
-        //     })
-        //     .catch(function(error) {
-        //         showToast(error);
-        //     })
-        //     .then(function(session) {
-        //         me.getView().setMasked(false);
-        //     });
-        this.fireEvent('login', new saas.model.Session({
-            token: 'XXXXXX',
-            expires: 180000,
-            timestamp: new Date().getTime(),
-            account: new saas.model.Account({
-                username: 'XXXXXX',
-                realname: '张三',
-                email: 'zhangs@gmail.com',
-                mobile: '15812345678'
+        var me = this, view = me.getView(),
+            form = me.lookup('authdialog'),
+            values = form.getValues();
+
+        view.mask('请稍等...');
+
+        saas.model.Session.login(values.username, values.password)
+            .then(function(session) {
+                view.isMasked() && view.unmask();
+                me.getViewModel().set('session', session);
+				var cos = session.get("account").companies;
+				if (cos && cos.length) {
+                    if (cos.length == 1) {
+                        session.get('account').companyId = cos[0].id;
+                        me.fireEvent('login', session);
+                    } else {
+                        Ext.create({
+                            xtype: 'companypicker',
+                            viewModel: {
+                                stores: {
+                                    companies: Ext.create('saas.store.Company', {
+                                        data: cos
+                                    })
+                                }
+                            }
+                        });
+                    }
+				} else {
+                    me.fireEvent('login', session);
+                }
             })
-        }));
+            .catch(function(error) {
+                view.isMasked() && view.unmask();
+                showToast(error.message);
+            });
     },
 
     onWeixinLogin : function() {
     },
 
     onNewAccount:  function() {
+    },
+
+    selectCompany: function(view, record) {
+        var me = this, view = me.getView(), oldSession = me.getViewModel().get('session'),
+            companyId = record.get('id');
+        
+        view.mask('请稍等...');
+
+        saas.model.Session.switchCompany(oldSession, companyId)
+            .then(function(newSession) {
+                newSession.get('account').companyId = companyId;
+				me.fireEvent('login', newSession);
+            })
+            .catch(function(error) {
+                showToast(error.message);
+            })
+            .then(function() {
+                view.isMasked() && view.unmask();
+                view.ownerCt.destroy();
+            });        
     }
 });

+ 1 - 1
frontend/saas-web/app/view/core/dbfind/MultiDbfindGridPanel.js

@@ -23,7 +23,7 @@ Ext.define('saas.view.core.dbfind.MultiDbfindGridPanel', {
                     var selectRecordArr = selModel.view.ownerCt.selectRecordArr;
                     var index = -1;
                     index = selectRecordArr.findIndex(function(f){
-                        return f.id==id
+                        return f.id==record.id
                     });
                     if(index>-1){
                         selectRecordArr.splice(index,1);

+ 7 - 1
frontend/saas-web/app/view/document/kind/ChildForm.js

@@ -169,7 +169,7 @@ Ext.define('KitchenSink.view.binding.ChildForm', {
             },{
                 xtype:'textfield',
                 fieldLabel: '单据名称',
-                name: 'mn_caller',
+                name: 'mn_name',
                 allowBlank:false,
                 editable:false,
                 readOnly:true
@@ -219,6 +219,8 @@ Ext.define('KitchenSink.view.binding.ChildForm', {
                 align: 'stretch'
             },
             defaults: {
+                labelAlign:'right',
+                beforeLabelTextTpl: "<font color=\"red\" style=\"position:relative; top:2px;right:2px; font-weight: bolder;\">*</font>",
                 xtype: 'textfield'
             },
             buttons: [{
@@ -235,7 +237,9 @@ Ext.define('KitchenSink.view.binding.ChildForm', {
         return Ext.apply(conf, me.etc[kind]);
     },
     onSave:function(){
+        var me = this;
         var belong = this.belong;
+        me.setLoading(true);
         var form=this.down('form');
         var combo = this._combo;
         var params = {};
@@ -258,6 +262,7 @@ Ext.define('KitchenSink.view.binding.ChildForm', {
             method: 'POST',
         })
         .then(function(localJson) {
+            me.setLoading(false);
             if(localJson.success){
                 showToast('保存成功');
                 var grid = form.ownerCt._parent.lookup('document-kind-Grid');
@@ -273,6 +278,7 @@ Ext.define('KitchenSink.view.binding.ChildForm', {
             }
         })
         .catch(function(res) {
+            me.setLoading(false);
             console.error(res);
             showToast('保存失败: ' + res.message);
         });

+ 6 - 4
frontend/saas-web/app/view/document/kind/Kind.js

@@ -31,13 +31,13 @@ Ext.define('saas.view.document.kind.Kind', {
             value: 'vendorkind',
             typeText:'供应商类型'
         }, {
-            text: '商品',
+            text: '物料',
             value: 'productkind',
-            typeText:'商品类型'
+            typeText:'物料类型'
         }, {
             text: '收支',
             value: 'inoutkind',
-            typeText:'收支类'
+            typeText:'收支类'
         }],
         listeners: {
             toggle: 'onKindToggle'
@@ -130,11 +130,13 @@ Ext.define('saas.view.document.kind.Kind', {
                 dataIndex: 'bk_bankname',
                 flex: 1
             },{
+                hidden:true,
                 xtype:'datecolumn',
                 text: '日期',
                 dataIndex: 'bk_date',
                 flex: 1
             },{
+                hidden:true,
                 text: '账户类型',
                 dataIndex: 'bk_type',
                 flex: 1
@@ -153,7 +155,7 @@ Ext.define('saas.view.document.kind.Kind', {
         },
         inoutkind:{
             columns: [{
-                text: '收支类',
+                text: '收支类',
                 dataIndex: 'ft_name',
                 flex: 1
             }],

+ 9 - 8
frontend/saas-web/app/view/document/product/FormController.js

@@ -26,14 +26,15 @@ Ext.define('saas.view.document.product.FormController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
+                        defaultCondition: 've_statuscode="OPEN"',
                         //放大镜窗口字段
                         dbSearchFields:[{
-                            xtype : "textfield", 
-                            name : "ve_name", 
-                            conditionExpression:"ve_name like '{0}%'",//传入后台条件  替换占位符
-                            fieldLabel : "供应商名称", 
+                            xtype : "textfield",
+                            name: 'name',
+                            getCondition: function(v) {
+                                return "upper(ve_code) like '%"+v.toUpperCase()+"%' or upper(ve_name) like '%"+v.toUpperCase()+"%'";
+                            },
+                            emptyText : "请输入供应商编号或名称", 
                             columnWidth : 0.25
                         }],
                         //放大镜窗口列表
@@ -93,11 +94,11 @@ Ext.define('saas.view.document.product.FormController', {
                         dbSearchFields:[{
                             emptyText:'输入仓库编号或仓库名称或仓库类型',
                             xtype : "textfield", 
-                            name : "wh_code", 
+                            name : "name", 
                             allowBlank : true, 
                             width:260,
                             getCondition:function(v){
-                                return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%' or wh_type like '%" + v + "%'";
+                                return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         //窗口列设置

+ 44 - 8
frontend/saas-web/app/view/document/product/FormPanel.js

@@ -31,20 +31,20 @@ Ext.define('saas.view.document.product.FormPanel', {
         columnWidth: 0.25
     },{
         xtype: 'textfield',
-        name: 'pr_detail',
-        fieldLabel: '物料名称',
+        name: 'pr_code',
+        fieldLabel: '物料编号',
         allowBlank: false,
         columnWidth: 0.25
     },{
         xtype: 'textfield',
-        name: 'pr_code',
-        fieldLabel: '物料编号',
+        name: 'pr_detail',
+        fieldLabel: '物料名称',
         allowBlank: false,
         columnWidth: 0.25
     },{
-        xtype: 'textfield',
+        xtype: 'hidden',
         name: 'pr_status',
-        fieldLabel: '可用状态',
+        fieldLabel: '状态',
         allowBlank: true,
         columnWidth: 0.25
     },{
@@ -53,6 +53,12 @@ Ext.define('saas.view.document.product.FormPanel', {
         fieldLabel: '状态码',
         allowBlank: true,
         columnWidth: 0.25
+    },{
+        xtype: 'textfield',
+        name: 'pr_spec',
+        fieldLabel: '规格',
+        allowBlank: false,
+        columnWidth: 0.25
     },{
         editable:false,
         xtype : "remotecombo", 
@@ -79,6 +85,12 @@ Ext.define('saas.view.document.product.FormPanel', {
             this.dialog.show();
         }
     },{
+        xtype: 'textfield',
+        name: 'pr_orispeccode',
+        fieldLabel: '型号',
+        allowBlank: true,
+        columnWidth: 0.25
+    },{  
         editable:false,
         xtype : "remotecombo", 
         storeUrl:'/api/document/productunit/getCombo',
@@ -153,24 +165,48 @@ Ext.define('saas.view.document.product.FormPanel', {
     }, {
         xtype : "textfield", 
         name : "pr_whname", 
-        bind : "{pr_whname}", 
         fieldLabel : "仓库名称", 
         allowBlank : true, 
         columnWidth : 0.25
     },{
+        ignore:true,
+        readOnly:true,
         xtype : "numberfield", 
         name : "pr_standardprice", 
-        bind : "{pr_standardprice}", 
         fieldLabel : "标准单价", 
         allowBlank : true, 
         columnWidth : 0.25
     },{
+        ignore:true,
+        readOnly:true,
+        xtype : "numberfield", 
+        name : "pr_purcprice", 
+        fieldLabel : "最新采购单价", 
+        allowBlank : true, 
+        columnWidth : 0.25
+    },{
+        ignore:true,
+        readOnly:true,
+        xtype : "numberfield", 
+        name : "pr_saleprice", 
+        fieldLabel : "最新出货单价", 
+        allowBlank : true, 
+        columnWidth : 0.25
+    },{
+        xtype : "numberfield", 
+        name : "pr_zxbzs", 
+        fieldLabel : "最小包装数", 
+        allowBlank : true, 
+        columnWidth : 0.25
+    },{  
+        hidden:true,
         xtype : "datefield", 
         name : "createTime", 
         fieldLabel : "创建时间", 
         allowBlank : true, 
         columnWidth : 0.25
     },{  
+        hidden:true,
         xtype : "datefield", 
         name : "updateTime", 
         fieldLabel : "更新时间", 

+ 0 - 15
frontend/saas-web/app/view/main/List.js

@@ -1,15 +0,0 @@
-/**
- * This view is an example list of people.
- */
-Ext.define('saas.view.main.List', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'mainlist',
-
-    title: 'Personnel',
-
-    columns: [
-        { text: 'Name',  dataIndex: 'name' },
-        { text: 'Email', dataIndex: 'email', flex: 1 },
-        { text: 'Phone', dataIndex: 'phone', flex: 1 }
-    ]
-});

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

@@ -40,39 +40,55 @@ Ext.define('saas.view.main.Main', {
                     id: 'main-navigation-btn',
                     handler: 'onToggleNavigationSize'
                 },
+                {
+                    margin: '0 0 0 8',
+                    xtype: 'tbtext',
+                    bind: {
+                        html: '{company.name}'
+                    }
+                },
                 '->',
                 {
                     iconCls:'x-fa fa-search',
                     ui: 'header',
-                    tooltip: 'See latest search'
+                    tooltip: '搜索'
                 },
                 {
                     iconCls:'x-fa fa-bell',
                     ui: 'header',
-                    tooltip: 'Check your messages'
+                    tooltip: '消息'
                 },
                 {
                     iconCls:'x-fa fa-question',
                     ui: 'header',
-                    tooltip: 'Help / FAQ\'s'
+                    tooltip: '帮助'
                 },
                 {
+                    reference: 'mainprofile',
                     iconCls:'x-fa fa-th-large',
+                    arrowVisible: false,
                     ui: 'header',
-                    tooltip: 'See your profile'
-                },
-                {
-                    xtype: 'tbtext',
-                    text: 'administrator',
-                    cls: 'top-user-name'
+                    tooltip: '账户',
+                    bind: {
+                        text: '{account.realname}'
+                    },
+                    menu: {
+                        items: [{
+                            xtype: 'menuseparator'
+                        }, {
+                            text: '退出',
+                            handler: 'onLogout'
+                        }]
+                    }
                 },
                 {
                     xtype: 'image',
                     cls: 'header-right-profile-image',
                     height: 35,
                     width: 35,
-                    alt:'current user image',
-                    src: 'resources/images/default/user-profile-default.png'
+                    bind: {
+                        src: '{avatarUrl}'
+                    }
                 }
             ]
         },

+ 29 - 0
frontend/saas-web/app/view/main/MainController.js

@@ -7,6 +7,27 @@ Ext.define('saas.view.main.MainController', {
 
     alias: 'controller.main',
 
+    init: function() {
+        this.setCompanyMenu();
+    },
+
+    setCompanyMenu: function() {
+        var me = this, view = me.getView(), viewModel = me.getViewModel(),
+            account = viewModel.get('account'), companies = account && account.companies,
+            companyMenu = view.lookup('mainprofile').getMenu(), items = [];
+        if (companies) {
+            items = companies.map(function(c){
+                return {
+                    text: c.name,
+                    value: c.id,
+                    handler: 'selectCompany',
+                    iconCls: c.id == account.companyId ? 'x-fa fa-check' : ''
+                }
+            });
+        }
+        companyMenu.insert(0, items);
+    },
+
     onToggleNavigationSize: function () {
         var me = this,
         refs = me.getReferences(),
@@ -22,5 +43,13 @@ Ext.define('saas.view.main.MainController', {
         navigationList.el[ope]('nav-collapsed');
 
         navigationList.navCollapsed = navCollapsed;
+    },
+
+    selectCompany: function(item) {
+        this.fireEvent('selectCompany', item.value);
+    },
+
+    onLogout: function() {
+        this.fireEvent('logout');
     }
 });

+ 0 - 1
frontend/saas-web/app/view/main/MainModel.js

@@ -7,6 +7,5 @@ Ext.define('saas.view.main.MainModel', {
     alias: 'viewmodel.main',
 
     data: {
-        
     }
 });

+ 18 - 0
frontend/saas-web/app/view/money/fundtransfer/FormPanelController.js

@@ -22,6 +22,15 @@ Ext.define('saas.view.money.fundtransfer.FormPanelController', {
                         },{
                             field:'bk_bankname',width:100
                         }],
+                        dbSearchFields:[{
+                            xtype : "textfield",
+                            name: 'name',
+                            getCondition: function(v) {
+                                return "upper(bk_bankcode) like '%"+v.toUpperCase()+"%' or upper(bk_bankname) like '%"+v.toUpperCase()+"%'";
+                            },
+                            emptyText : "请输入账户编号或名称", 
+                            columnWidth : 0.25
+                        }],
                         dbColumns:[{
                             "text": "账户ID",
                             "flex": 0,
@@ -80,6 +89,15 @@ Ext.define('saas.view.money.fundtransfer.FormPanelController', {
                         },{
                             field:'bk_bankname',width:100
                         }],
+                        dbSearchFields:[{
+                            xtype : "textfield", 
+                            name: 'name',
+                            getCondition: function(v) {
+                                return "upper(bk_bankcode) like '%"+v.toUpperCase()+"%' or upper(bk_bankname) like '%"+v.toUpperCase()+"%'";
+                            },
+                            emptyText:'输入账户编号或名称',
+                            columnWidth : 0.25
+                        }],
                         dbColumns:[{
                             "text": "账户ID",
                             "flex": 0,

+ 2 - 2
frontend/saas-web/app/view/money/othreceipts/FormPanelController.js

@@ -34,7 +34,7 @@ Ext.define('saas.view.money.othreceipts.FormPanelController', {
                             xtype: "textfield",
                             name: "search",
                             getCondition: function (v) {
-                                return "CONCAT(cu_code, cu_name) like '%" + v + "%'";
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank: true,
                             columnWidth: 0.25
@@ -133,7 +133,7 @@ Ext.define('saas.view.money.othreceipts.FormPanelController', {
                             xtype: "textfield",
                             name: "search",
                             getCondition: function (v) {
-                                return "CONCAT(bk_bankcode, bk_bankname) like '%" + v + "%'";
+                                return "upper(bk_bankcode) like '%"+v.toUpperCase()+"%' or upper(bk_bankname) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank: true,
                             columnWidth: 0.25

+ 28 - 19
frontend/saas-web/app/view/money/payBalance/FormPanel.js

@@ -83,41 +83,44 @@ Ext.define('saas.view.money.payBalance.FormPanel', {
     }, {
         xtype: "detailGridField",
         storeModel: 'saas.model.money.PayBalance1',
-        detnoColumn: 'pb_detno',
+        detnoColumn: 'pd_detno',
         deleteDetailUrl: '/api/money/paybalance/deleteDetail1/',
         columns: [{
             text: 'ID',
             dataIndex: 'id',
             hidden: true
         }, {
-            // text: '期间',
-            // dataIndex: 'pb_ym'
+            text: '期间',
+            dataIndex: 'pd_ym',
             // editor: {
             //     xtype: 'hidden',
-            //     // xtype: 'textfield,
-            //     // xtype: 'datefield''
+                // xtype: 'textfield,
+                // xtype: 'datefield''
             // }
-        // }, {
-        //     text: '结算账户ID',
-        //     dataIndex: 'pb_bankid'
-        // }, {
+        }, {
+            text: '结算账户ID',
+            dataIndex: 'pd_bankid',
+            editor:{
+                xtype:'hidden'
+            }
+        }, {
         //     text: '结算账户编号',
         //     dataIndex: 'paybalancedet'
         // }, {
             text: '结算账户',
-            dataIndex: 'pb_bankname'
+            dataIndex: 'pd_bankname'
         }, {
             text: "付款金额",
-            dataIndex: "pb_amount",
+            dataIndex: "pd_amount",
             editor:{
                 xtype: 'numberfield'
             }
         }, {
             text: "结算方式",
-            dataIndex: "pb_paymethod"
+            dataIndex: "pd_paymethod"
         }, {
             text: "结算号",
-            dataIndex: "pb_paycode"
+            dataIndex: "pd_paycode"
         }, {
             text: "备注",
             dataIndex: "pb_remark",
@@ -135,12 +138,18 @@ Ext.define('saas.view.money.payBalance.FormPanel', {
             dataIndex: 'id',
             hidden: true
         }, {
-        //     text: '期间',
-        //     dataIndex: 'pbd_ym'
-        // }, {
-        //     text: '来源ID',
-        //     dataIndex: 'pbd_slid'
-        // }, {
+            text: '期间',
+            dataIndex: 'pbd_ym',
+            editor:{
+                xtype:'hidden'
+            }
+        }, {
+            text: '来源ID',
+            dataIndex: 'pbd_slid',
+            editor:{
+                xtype:'hidden'
+            }
+        }, {
             text: '源单编号',
             dataIndex: 'pbd_slcode'
         // }, {

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

@@ -28,11 +28,15 @@ Ext.define('saas.view.money.payBalance.FormPanelController', {
                         //联想查询条件
                         dbtplfield:"ve_name",
                         //放大镜窗口字段
-                        dbSearchFields:[{
-                            xtype : "textfield", 
-                            name : "ve_name", 
-                            fieldLabel : "供应商名称", 
-                            columnWidth : 0.25
+                        dbSearchFields: [{
+                            emptyText: '输入供应商编号或名称',
+                            xtype: "textfield",
+                            name: "search",
+                            getCondition: function (v) {
+                                return "upper(ve_code) like '%"+v.toUpperCase()+"%' or upper(ve_name) like '%"+v.toUpperCase()+"%'";
+                            },
+                            allowBlank: true,
+                            columnWidth: 0.25
                         }],
                         //放大镜窗口列表
                         dbColumns:[{

+ 3 - 3
frontend/saas-web/app/view/money/payBalance/QueryPanel.js

@@ -42,16 +42,16 @@ Ext.define('saas.view.money.paybalance.QueryPanel', {
         }, {
             text: '供应商编号',
             dataIndex: 'pb_vendcode',
-            width: 200
+            width: 200,
+            hidden:true
         }, {
             text: '供应商名称',
             dataIndex: 'pb_vendname',
-            width: 120
+            width: 120,
         }, {
             text: '收款人',
             dataIndex: 'pb_manname',
             width: 120,
-            hidden:true
         }, {
             text: '付款金额',
             dataIndex: 'pb_pdamount',

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

@@ -26,13 +26,14 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                         },{
                             field:'cu_name',width:100
                         }],
-                        //联想查询条件
-                        dbCondition:"CONCAT(cu_code, cu_name) like '{0}%'",
+                        defaultCondition: 'cu_statuscode="OPEN"',
                         //放大镜窗口字段
                         dbSearchFields:[{
-                            xtype : "textfield", 
+                            emptyText:'输入客户编号或名称',
                             name : "cu_name", 
-                            conditionExpression:"cu_name like '{0}%'",//传入后台条件  替换占位符
+                            getCondition: function(v) {
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
+                            },
                             fieldLabel : "客户名称", 
                             columnWidth : 0.25
                         }],
@@ -84,12 +85,14 @@ Ext.define('saas.view.money.recBalance.FormPanelController', {
                             field:'cu_name',width:100
                         }],
                         //联想查询条件
-                        dbCondition:"CONCAT(cu_code, cu_name) like '{0}%'",
+                        defaultCondition: 'cu_statuscode="OPEN"',
                         //放大镜窗口字段
                         dbSearchFields:[{
-                            xtype : "textfield", 
+                            emptyText:'输入客户编号或名称',
                             name : "cu_name", 
-                            conditionExpression:"cu_name like '{0}%'",//传入后台条件  替换占位符
+                            getCondition: function(v) {
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
+                            },
                             fieldLabel : "客户名称", 
                             columnWidth : 0.25
                         }],

+ 2 - 4
frontend/saas-web/app/view/purchase/purchase/FormPanelController.js

@@ -25,15 +25,13 @@ Ext.define('saas.view.purchase.purchase.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
                             xtype : "textfield", 
                             name : "search", 
                             getCondition: function(v) {
-                                return "CONCAT(ve_code, ve_name) like '%" + v + "%'";
+                                return "upper(ve_code) like '%"+v.toUpperCase()+"%' or upper(ve_name) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank : true, 
                             columnWidth : 0.25
@@ -121,7 +119,7 @@ Ext.define('saas.view.purchase.purchase.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%' or pr_spec like '%"+ v +"%'";
+                                return "upper(pr_code) like '%" + v.toUpperCase() + "%' or upper(pr_detail like '%"+ v.toUpperCase() +"%' or upper(pr_spec) like '%"+ v.toUpperCase() +"%'";
                             }
                         }],
                         //窗口列设置

+ 4 - 5
frontend/saas-web/app/view/purchase/purchaseIn/FormPanelController.js

@@ -33,8 +33,6 @@ Ext.define('saas.view.purchase.purchaseIn.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
@@ -43,7 +41,7 @@ Ext.define('saas.view.purchase.purchaseIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "ve_name like '%" + v + "%' or ve_code like '%"+ v +"%'";
+                                return "upper(ve_code) like '%"+v.toUpperCase()+"%' or upper(ve_name) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -112,6 +110,7 @@ Ext.define('saas.view.purchase.purchaseIn.FormPanelController', {
                         },{
                             field:'pr_spec',width:100
                         }],
+                        defaultCondition: 'pr_statuscode="OPEN"',
                         //窗口字段设置
                         dbSearchFields:[{
                             emptyText:'输入物料编号或物料名称',
@@ -120,7 +119,7 @@ Ext.define('saas.view.purchase.purchaseIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%'";
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         //窗口列设置
@@ -260,7 +259,7 @@ Ext.define('saas.view.purchase.purchaseIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                                return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{

+ 4 - 5
frontend/saas-web/app/view/purchase/purchaseOut/FormPanelController.js

@@ -32,8 +32,6 @@ Ext.define('saas.view.purchase.purchaseOut.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
@@ -42,7 +40,7 @@ Ext.define('saas.view.purchase.purchaseOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "ve_name like '%" + v + "%' or ve_code like '%"+ v +"%'";
+                                return "upper(ve_name) like '%"+v.toUpperCase()+"%' or upper(ve_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -111,6 +109,7 @@ Ext.define('saas.view.purchase.purchaseOut.FormPanelController', {
                         },{
                             field:'pr_unit',width:100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
                             emptyText:'输入物料编号、名称或规格',
@@ -119,7 +118,7 @@ Ext.define('saas.view.purchase.purchaseOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%' or pr_spec like '%"+ v +"%'";
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%' or upper(pr_spec) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                       
                         //窗口列设置
@@ -259,7 +258,7 @@ Ext.define('saas.view.purchase.purchaseOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                                return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{

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

@@ -32,7 +32,7 @@ Ext.define('saas.view.sale.sale.FormPanelController', {
                             xtype : "textfield", 
                             name : "search", 
                             getCondition: function(v) {
-                                return "CONCAT(cu_code, cu_name) like '%" + v + "%'";
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank : true, 
                             columnWidth : 0.25

+ 1 - 1
frontend/saas-web/app/view/sale/saleIn/FormPanelController.js

@@ -33,7 +33,7 @@ Ext.define('saas.view.sale.saleIn.FormPanelController', {
                             xtype : "textfield", 
                             name : "search", 
                             getCondition: function(v) {
-                                return "CONCAT(cu_code, cu_name) like '%" + v + "%'";
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank : true, 
                             columnWidth : 0.25

+ 1 - 1
frontend/saas-web/app/view/sale/saleOut/FormPanelController.js

@@ -34,7 +34,7 @@ Ext.define('saas.view.sale.saleout.FormPanelController', {
                             xtype : "textfield", 
                             name : "search", 
                             getCondition: function(v) {
-                                return "CONCAT(cu_code, cu_name) like '%" + v + "%'";
+                                return "upper(cu_code) like '%"+v.toUpperCase()+"%' or upper(cu_name) like '%"+v.toUpperCase()+"%'";
                             },
                             allowBlank : true, 
                             columnWidth : 0.25

+ 7 - 9
frontend/saas-web/app/view/stock/appropriationInOut/FormPanelController.js

@@ -32,8 +32,6 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
@@ -42,7 +40,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "ve_name like '%" + v + "%' or ve_code like '%"+ v +"%'";
+                                return "upper(ve_name) like '%"+v.toUpperCase()+"%' or upper(ve_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -101,8 +99,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                         },{
                             field:'pi_custname',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"cu_name",
+                        defaultCondition:"cu_statuscode='OPEN'",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入客户编号或名称',
@@ -111,7 +108,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "cu_name like '%" + v + "%' or cu_code like '%"+ v +"%'";
+                                return "upper(cu_name) like '%"+v.toUpperCase()+"%' or upper(cu_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -199,6 +196,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                         },{
                             field:'pr_spec',width:100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
                             emptyText:'输入物料编号、名称或规格',
@@ -207,7 +205,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%' or pr_spec like '%"+ v +"%'";
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%' or upper(pr_spec) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                         
                         dbColumns:[{
@@ -345,7 +343,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                         allowBlank : true, 
                         columnWidth : 0.25,
                         getCondition:function(v){
-                            return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                            return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                         }
                     }],                    
                     dbColumns:[{
@@ -401,7 +399,7 @@ Ext.define('saas.view.stock.appropriationInOut.FormPanelController', {
                     allowBlank : true, 
                     columnWidth : 0.25,
                     getCondition:function(v){
-                        return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                        return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                     }
                 }],                 
                  dbColumns:[{

+ 25 - 20
frontend/saas-web/app/view/stock/make/FormPanelController.js

@@ -24,15 +24,17 @@ Ext.define('saas.view.stock.make.FormPanelController', {
             //             },{
             //                 field:'ve_name',width:100
             //             }],
-            //             //联想查询条件
-            //             dbCondition:"CONCAT(ve_code, ve_name) like '{0}%'",
+            //             defaultCondition:"ve_statuscode='OPEN'",
             //             //放大镜窗口字段
             //             dbSearchFields:[{
+            //                 emptyText:'输入仓库编号或名称',
             //                 xtype : "textfield", 
-            //                 name : "ve_name", 
-            //                 conditionExpression:"ve_name like '{0}%'",//传入后台条件  替换占位符
-            //                 fieldLabel : "供应商名称", 
-            //                 columnWidth : 0.25
+            //                 name : "name", 
+            //                 allowBlank : true, 
+            //                 columnWidth : 0.25,
+            //                 getCondition:function(v){
+            //                     return "upper(ve_code) like '%"+v.toUpperCase()+"%' or upper(ve_name) like '%"+v.toUpperCase()+"%'";
+            //                 }
             //             }],
             //             //放大镜窗口列表
             //             dbColumns:[{
@@ -64,7 +66,6 @@ Ext.define('saas.view.stock.make.FormPanelController', {
             //                 "items": null
             //             }]
             //         }) ;   
-
             //     }
             // },
             //从表单选放大镜赋值关系 以及 tpl模板
@@ -81,22 +82,23 @@ Ext.define('saas.view.stock.make.FormPanelController', {
                         },{
                             from:'pr_unit',to:'pd_unit'
                         }],
-                        //联想查询条件
-                        dbCondition:"CONCAT(pr_code, pr_detail) like '{0}%'",
                         //联想设置
                         dbtpls:[{
                             field:'pr_code',width:100
                         },{
                             field:'pr_detail',width:100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
-                            emptyText:'输入物料编号或物料名称',
+                            emptyText:'输入仓库编号或名称',
                             xtype : "textfield", 
-                            name : "search", 
-                            conditionExpression:"CONCAT(pr_code, pr_detail) like '{0}%'",
+                            name : "name", 
                             allowBlank : true, 
-                            columnWidth : 0.25
+                            columnWidth : 0.25,
+                            getCondition:function(v){
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%'";
+                            }
                         }],
                         //窗口列设置
                         dbColumns:[{
@@ -136,29 +138,32 @@ Ext.define('saas.view.stock.make.FormPanelController', {
                 beforerender:function(f){
                     Ext.apply(f,{
                         //数据接口
-                        dataUrl:'http://192.168.253.31:9480/product/getProductsByCondition',
+                        dataUrl:'/api/document/product/list',
+                        addXtype: 'document-product-formpanel',
+                        addTitle: '物料资料',
                         //放大镜赋值设置
                         dbfinds:[{
                             from:'pr_code',to:'pd_prodcode'
                         },{
                             from:'pr_unit',to:'pd_unit'
                         }],
-                        //联想查询条件
-                        dbCondition:"CONCAT(pr_code, pr_detail) like '{0}%'",
                         //联想设置
                         dbtpls:[{
                             field:'pr_code',width:100
                         },{
                             field:'pr_detail',width:100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
-                            emptyText:'输入物料编号或物料名称',
+                            emptyText:'输入仓库编号或名称',
                             xtype : "textfield", 
-                            name : "search", 
-                            conditionExpression:"CONCAT(pr_code, pr_detail) like '{0}%'",
+                            name : "name", 
                             allowBlank : true, 
-                            columnWidth : 0.25
+                            columnWidth : 0.25,
+                            getCondition:function(v){
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%'";
+                            }
                         }],
                         //窗口列设置
                         dbColumns:[{

+ 6 - 8
frontend/saas-web/app/view/stock/otherIn/FormPanelController.js

@@ -26,8 +26,6 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
@@ -36,7 +34,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "ve_name like '%" + v + "%' or ve_code like '%"+ v +"%'";
+                                return "upper(ve_name) like '%"+v.toUpperCase()+"%' or upper(ve_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -100,8 +98,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             field: 'pi_custname',
                             width: 100
                         }],
-                        //联想查询条件
-                        dbtplfield:"cu_name",
+                        defaultCondition:"cu_statuscode='OPEN'",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入客户编号或名称',
@@ -110,7 +107,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "cu_name like '%" + v + "%' or cu_code like '%"+ v +"%'";
+                                return "upper(cu_name) like '%"+v.toUpperCase()+"%' or upper(cu_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -205,6 +202,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             field: 'pr_spec',
                             width: 100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
                             emptyText:'输入物料编号、名称或规格',
@@ -213,7 +211,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%' or pr_spec like '%"+ v +"%'";
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%' or upper(pr_spec) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{
@@ -356,7 +354,7 @@ Ext.define('saas.view.stock.otherIn.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                                return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns: [{

+ 6 - 8
frontend/saas-web/app/view/stock/otherOut/FormPanelController.js

@@ -26,8 +26,6 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                         },{
                             field:'ve_name',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"ve_name",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入供应商编号或名称',
@@ -36,7 +34,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "ve_name like '%" + v + "%' or ve_code like '%"+ v +"%'";
+                                return "upper(ve_name) like '%"+v.toUpperCase()+"%' or upper(ve_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{
@@ -95,8 +93,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                         },{
                             field:'pi_custname',width:100
                         }],
-                        //联想查询条件
-                        dbtplfield:"cu_name",
+                        defaultCondition:"pi_statuscode='OPEN'",
                         //放大镜窗口字段
                         dbSearchFields:[{
                             emptyText:'输入客户编号或名称',
@@ -105,7 +102,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "cu_name like '%" + v + "%' or cu_code like '%"+ v +"%'";
+                                return "upper(cu_name) like '%"+v.toUpperCase()+"%' or upper(cu_code) like '%"+v.toUpperCase()+"%'";
                             }
                         }],
                         dbColumns:[{
@@ -193,6 +190,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                         },{
                             field:'pr_spec',width:100
                         }],
+                        defaultCondition:"pr_statuscode='OPEN'",
                         //窗口字段设置
                         dbSearchFields:[{
                             emptyText:'输入物料编号、名称或规格',
@@ -201,7 +199,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "pr_code like '%" + v + "%' or pr_detail like '%"+ v +"%' or pr_spec like '%"+ v +"%'";
+                                return "upper(pr_code) like '%"+v.toUpperCase()+"%' or upper(pr_detail) like '%"+v.toUpperCase()+"%' or upper(pr_spec) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{
@@ -340,7 +338,7 @@ Ext.define('saas.view.stock.otherOut.FormPanelController', {
                             allowBlank : true, 
                             columnWidth : 0.25,
                             getCondition:function(v){
-                                return "wh_code like '%" + v + "%' or wh_description like '%"+ v +"%'";
+                                return "upper(wh_code) like '%"+v.toUpperCase()+"%' or upper(wh_description) like '%"+v.toUpperCase()+"%'";
                             }
                         }],                        
                         dbColumns:[{

+ 2 - 2
frontend/saas-web/app/view/sys/maxnumbers/DataList.js

@@ -17,7 +17,7 @@ Ext.define('saas.view.sys.maxnumbers.DataList', {
 
     tbar: [{
         width: 150,
-        name: 'mn_caller',
+        name: 'mn_name',
         xtype: 'textfield',
         emptyText : '单据名称'
     },{
@@ -81,7 +81,7 @@ Ext.define('saas.view.sys.maxnumbers.DataList', {
     },{
         text : "单据名称", 
         width : 200.0, 
-        dataIndex : "mn_caller", 
+        dataIndex : "mn_name", 
         xtype : "", 
     }, 
     {

+ 12 - 5
frontend/saas-web/app/view/sys/messagelog/DataList.js

@@ -9,9 +9,9 @@ Ext.define('saas.view.sys.messagelog.DataList', {
 
     tbar: [{
         width: 150,
-        name: 'ml_caller',
+        name: 'ml_name',
         xtype: 'textfield',
-        emptyText : '单据Caller'
+        emptyText : '单据类别'
     },{
         width: 150,
         name: 'ml_code',
@@ -52,9 +52,9 @@ Ext.define('saas.view.sys.messagelog.DataList', {
         dataIndex : "id", 
         xtype : "numbercolumn",   
     },{
-        text:'单据Caller',
-        dataIndex : "ml_caller",
-        width : 200.0, 
+        text:'单据类别',
+        dataIndex : "ml_name",
+        width : 120.0, 
     },{
         text : "单据编号", 
         width : 200.0, 
@@ -65,6 +65,13 @@ Ext.define('saas.view.sys.messagelog.DataList', {
         dataIndex : "ml_content", 
         width : 220.0, 
     }, 
+    {
+        xtype:'datecolumn',
+        format:'Y-m-d H:i:s',
+        text : "操作时间", 
+        dataIndex : "createTime", 
+        width : 200.0, 
+    },
     {
         text : "结果", 
         dataIndex : "ml_result", 

+ 39 - 53
frontend/saas-web/app/view/viewport/ViewportController.js

@@ -7,6 +7,7 @@ Ext.define('saas.view.viewport.ViewportController', {
             '*': {
                 login: 'onLogin',
                 logout: 'onLogout',
+                selectCompany: 'onSelectCompany',
                 unmatchedroute: 'handleUnmatchedRoute'
             }
         }
@@ -17,7 +18,7 @@ Ext.define('saas.view.viewport.ViewportController', {
     },
 
     init: function() {
-        this.initDirect();
+        this.originalRoute = saas.getApplication().getDefaultToken();
         this.restoreSession();
     },
 
@@ -41,7 +42,8 @@ Ext.define('saas.view.viewport.ViewportController', {
     },
 
     showMain: function() {
-        this.showView('main');
+        var me = this;
+        me.showView('main');
     },
 
     // ROUTING
@@ -75,51 +77,14 @@ Ext.define('saas.view.viewport.ViewportController', {
         }
     },
 
-    // EXT DIRECT
-
-    initDirect: function() {
-        // var api = Server.API;
-        // if (!api) {
-        //     Ext.raise('Failed to load Direct API');
-        // }
-
-        // Ext.direct.Manager.addProvider(Ext.applyIf({
-        //     id: 'server',
-        //     listeners: {
-        //         data: 'onDirectData',
-        //         scope: this
-        //     }
-        // }, api));
-    },
-
-    setDirectToken: function(token) {
-        // var provider = Ext.direct.Manager.getProvider('server'),
-        //     headers = provider.getHeaders() || {};
-
-        // if (token) {
-        //     headers['Authorization'] = 'Bearer ' + token;
-        // } else {
-        //     delete headers['Authorization'];
-        // }
-
-        // provider.setHeaders(headers);
-    },
-
-    onDirectData: function(provider, e) {
-        if (e.type !== 'exception') {
-            return;
-        }
-
-        var message = e.message || {};
-        switch (message.code) {
-        case -32098:    // AuthTokenExpired
-        case -32097:    // AuthTokenInvalid
-            // Defer user deauthentication until the current direct transaction is done.
-            Ext.asap(this.terminateSession, this);
-            break;
-        default:
-            break;
+    setRequestToken: function(token) {
+        var headers = Ext.Ajax.getDefaultHeaders() || {};
+        if (token) {
+            headers['Authorization'] = token;
+        } else {
+            delete headers['Authorization'];
         }
+        Ext.Ajax.setDefaultHeaders(headers);
     },
 
     // SESSION MANAGEMENT
@@ -138,20 +103,20 @@ Ext.define('saas.view.viewport.ViewportController', {
     },
 
     initiateSession: function(session) {
-        this.setDirectToken(session.get('token'));
+        this.setRequestToken(session.get('token'));
         this.saveSession(session);
         this.showMain();
     },
 
     terminateSession: function() {
-        this.setDirectToken(null);
+        this.setRequestToken(null);
         this.saveSession(null);
         this.showAuth();
     },
 
     saveSession: function(session) {
         saas.util.State.set('session', session && session.getData(true));
-        // this.getViewModel().set('account', session && session.getAccount(false).getData(true));
+        this.getViewModel().set('account', session && session.get('account'));
         this.session = session;
     },
 
@@ -175,15 +140,36 @@ Ext.define('saas.view.viewport.ViewportController', {
             return false;
         }
 
-        view.setMasked(true);
-        session.logout().catch(function() {
-            // TODO handle errors
+        view.mask();
+        session.logout().catch(function(error) {
+            showToast(error.message);
         }).then(function() {
             me.originalRoute = Ext.History.getToken();
             me.terminateSession();
-            view.setMasked(false);
+            view.unmask();
             me.redirectTo('login', {replace: true});
         });
+    },
+
+    onSelectCompany: function(companyId) {
+        var me = this, view = me.getView(), viewModel = me.getViewModel(), 
+            oldSession = me.session, company = viewModel.get('company');
+
+        if (company.id != companyId) {
+            view.mask('请稍等...');
+
+            saas.model.Session.switchCompany(oldSession, companyId)
+                .then(function(newSession) {
+                    newSession.get('account').companyId = companyId;
+                    me.initiateSession(newSession);
+                })
+                .catch(function(error) {
+                    showToast(error.message);
+                })
+                .then(function() {
+                    view.isMasked() && view.unmask();
+                }); 
+        }        
     }
 });
 

+ 14 - 1
frontend/saas-web/app/view/viewport/ViewportModel.js

@@ -4,5 +4,18 @@ Ext.define('saas.view.viewport.ViewportModel', {
 
     data: {
         account: null
-    }
+    },
+
+    formulas: {
+        company: function (get) {
+            var account = get('account');
+            return account && account.companies.find(function(c){
+                return c.id == account.companyId;
+            });
+        },
+        avatarUrl: function (get) {
+            var account = get('account');
+            return (account && account.avatarUrl) || 'resources/images/default/user-profile-default.png'
+        }
+    }    
 });

+ 10 - 1
frontend/saas-web/overrides/data/Connection.js

@@ -7,13 +7,22 @@ Ext.define('saas.override.data.Connection', {
  
     urlRegexp: /(http|ftp|https):\/\//,
 
+    config: {
+        /**
+         * @cfg {Object} defaultServerHeaders
+         * 与defaultHeaders有区别,只在调用server api的时候才添加的headers
+         */
+        defaultServerHeaders: null
+    },
+
     privates: {
         setupServerOptions: function(options) {
             var serverOptions = Ext.manifest.server, originUrl = options.url;
             if (serverOptions && serverOptions.basePath && !this.urlRegexp.test(originUrl) &&
               (!serverOptions.urlPattern || new RegExp(serverOptions.urlPattern).test(originUrl))) {
-                Ext.apply(options, {
+                Ext.Object.merge(options, {
                     url: serverOptions.basePath + (originUrl.indexOf('/') == 0 ? '' : '/') + originUrl,
+                    headers: this.getDefaultServerHeaders() || {}
                 });
             }
         }

Некоторые файлы не были показаны из-за большого количества измененных файлов