hy 7 years ago
parent
commit
191c544597
46 changed files with 1348 additions and 88 deletions
  1. 11 6
      applications/purchase/purchase-server/src/main/resources/application.yml
  2. 7 6
      base-servers/ui-server/pom.xml
  3. 2 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/UiApplication.java
  4. 32 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/ViewController.java
  5. 40 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/co/CoViewController.java
  6. 9 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/core/Const.java
  7. 79 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/Component.java
  8. 53 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/View.java
  9. 89 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoComponent.java
  10. 63 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoView.java
  11. 38 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ComponentRepository.java
  12. 27 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ViewRepository.java
  13. 32 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoComponentRepository.java
  14. 29 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoViewRepository.java
  15. 67 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ComponentService.java
  16. 51 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ViewService.java
  17. 71 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoComponentService.java
  18. 55 0
      base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoViewService.java
  19. 46 0
      base-servers/ui-server/src/main/resources/application.yml
  20. BIN
      base-servers/ui-server/src/main/resources/auth/pub.key
  21. 15 0
      base-servers/ui-server/src/main/resources/banner.txt
  22. 4 0
      base-servers/ui-server/src/main/resources/config/application-docker.yml
  23. 64 0
      base-servers/ui-server/src/main/resources/logback-spring.xml
  24. 148 0
      base-servers/ui-server/src/test/java/com/usoftchina/saas/ui/test/ViewServiceTest.java
  25. 18 0
      framework/core/src/main/java/com/usoftchina/saas/utils/StringUtils.java
  26. 7 4
      frontend/saas-web/app/util/GridUtil.js
  27. 35 5
      frontend/saas-web/app/view/core/form/FormPanel.js
  28. 6 0
      frontend/saas-web/app/view/core/form/FormPanelController.js
  29. 40 0
      frontend/saas-web/app/view/core/form/field/DetailGridField.js
  30. 33 0
      frontend/saas-web/app/view/core/form/field/DetailGridFieldController.js
  31. 3 3
      frontend/saas-web/app/view/core/grid/GridPanel.js
  32. 19 0
      frontend/saas-web/app/view/core/grid/GridPanelController.js
  33. 16 46
      frontend/saas-web/app/view/main/MainController.js
  34. 9 4
      frontend/saas-web/app/view/main/MainModel.js
  35. 3 3
      frontend/saas-web/app/view/purchase/list/GridPanel1.js
  36. 9 0
      frontend/saas-web/app/view/purchase/list/GridPanel2.js
  37. 12 0
      frontend/saas-web/app/view/purchase/list/ListController1.js
  38. 12 0
      frontend/saas-web/app/view/purchase/list/ListController2.js
  39. 6 0
      frontend/saas-web/app/view/purchase/order/FormController.js
  40. 14 0
      frontend/saas-web/app/view/purchase/order/FormModel.js
  41. 10 0
      frontend/saas-web/app/view/purchase/order/FormPanel.js
  42. 17 0
      frontend/saas-web/resources/json/detailGridColumns1.json
  43. 32 0
      frontend/saas-web/resources/json/formItems.json
  44. 0 0
      frontend/saas-web/resources/json/navigation.json
  45. 12 0
      script/docker-base.yaml
  46. 3 11
      script/mysql/init/ui.sql

+ 11 - 6
applications/purchase/purchase-server/src/main/resources/application.yml

@@ -6,11 +6,16 @@ spring:
       name: admin
       password: select111***
   datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://192.168.253.12:3306/saas_biz?characterEncoding=utf-8&useSSL=false
+    username: root
+    password: select111***
     hikari:
-      driver-class-name: com.mysql.cj.jdbc.Driver
-      jdbc-url: jdbc:mysql://192.168.253.12:3306/saas_biz?characterEncoding=utf-8&useSSL=false
-      username: root
-      password: select111***
+      minimum-idle: 5
+      maximum-pool-size: 50
+      idle-timeout: 30000
+      max-lifetime: 1800000
+      connection-timeout: 30000
   messages:
     basename: i18n/messages
 eureka:
@@ -24,9 +29,9 @@ eureka:
   client:
     registryFetchIntervalSeconds: 5
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:8500/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8500/eureka/
 server:
-  port: 8580
+  port: 8800
   tomcat:
     uri-encoding: UTF-8
 info:

+ 7 - 6
base-servers/ui-server/pom.xml

@@ -31,12 +31,8 @@
         </dependency>
         <!-- db -->
         <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.mybatis.spring.boot</groupId>
-            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
         </dependency>
         <!-- sleuth -->
         <dependency>
@@ -47,6 +43,11 @@
             <groupId>org.springframework.amqp</groupId>
             <artifactId>spring-rabbit</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>

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

@@ -2,6 +2,7 @@ package com.usoftchina.saas.ui;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
@@ -12,6 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @SpringBootApplication
 @EnableEurekaClient
 @EnableTransactionManagement
+@EnableCaching
 public class UiApplication {
     public static void main(String[] args) {
         SpringApplication.run(UiApplication.class, args);

+ 32 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/controller/ViewController.java

@@ -0,0 +1,32 @@
+package com.usoftchina.saas.ui.controller;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.ui.service.ViewService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RestController
+@RequestMapping("/api/ui/view")
+public class ViewController {
+
+    @Autowired
+    private ViewService viewService;
+
+    /**
+     * 获取通用视图配置
+     *
+     * @param name
+     * @return
+     */
+    @GetMapping("/config")
+    public Result<Object> getViewConfig(@RequestParam String name) {
+        return Result.success(viewService.getDeepConfig(name));
+    }
+}

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

@@ -0,0 +1,40 @@
+package com.usoftchina.saas.ui.controller.co;
+
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.ui.service.ViewService;
+import com.usoftchina.saas.ui.service.co.CoViewService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RestController
+@RequestMapping("/api/ui/co_view")
+public class CoViewController {
+    @Autowired
+    private CoViewService coViewService;
+
+    @Autowired
+    private ViewService viewService;
+
+    /**
+     * 获取企业视图配置
+     *
+     * @param name
+     * @return
+     */
+    @GetMapping("/config")
+    public Result<Object> getViewConfig(@RequestParam String name) {
+        Object config = coViewService.getDeepConfig(name);
+        if (null == config) {
+            // 企业配置不存在则取标准配置
+            config = viewService.getDeepConfig(name);
+        }
+        return Result.success(config);
+    }
+}

+ 9 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/core/Const.java

@@ -0,0 +1,9 @@
+package com.usoftchina.saas.ui.core;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+public class Const {
+    public static final String DEFAULT_CHILDREN_PROPERTY = "items";
+}

+ 79 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/Component.java

@@ -0,0 +1,79 @@
+package com.usoftchina.saas.ui.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_component")
+public class Component {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_component_view_index")
+    private String viewName;
+    @Indexed(name = "ui_component_pid_index")
+    private String parentId;
+    private String description;
+    private Integer orderNum;
+    private Object config;
+    private String childrenProperty;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getViewName() {
+        return viewName;
+    }
+
+    public void setViewName(String viewName) {
+        this.viewName = viewName;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+
+    public String getChildrenProperty() {
+        return childrenProperty;
+    }
+
+    public void setChildrenProperty(String childrenProperty) {
+        this.childrenProperty = childrenProperty;
+    }
+}

+ 53 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/View.java

@@ -0,0 +1,53 @@
+package com.usoftchina.saas.ui.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_view")
+public class View implements Serializable{
+    @Id
+    private String _id;
+    @Indexed(name = "ui_view_name_index", unique = true)
+    private String name;
+    private String description;
+    private Object config;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+}

+ 89 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoComponent.java

@@ -0,0 +1,89 @@
+package com.usoftchina.saas.ui.po.co;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_component_co")
+public class CoComponent {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_component_co_index")
+    private Long companyId;
+    @Indexed(name = "ui_component_view_index")
+    private String viewName;
+    @Indexed(name = "ui_component_pid_index")
+    private String parentId;
+    private String description;
+    private Integer orderNum;
+    private Object config;
+    private String childrenProperty;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getViewName() {
+        return viewName;
+    }
+
+    public void setViewName(String viewName) {
+        this.viewName = viewName;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+
+    public String getChildrenProperty() {
+        return childrenProperty;
+    }
+
+    public void setChildrenProperty(String childrenProperty) {
+        this.childrenProperty = childrenProperty;
+    }
+}

+ 63 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/po/co/CoView.java

@@ -0,0 +1,63 @@
+package com.usoftchina.saas.ui.po.co;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Document(collection = "ui_view_co")
+public class CoView implements Serializable {
+    @Id
+    private String _id;
+    @Indexed(name = "ui_view_co_index")
+    private Long companyId;
+    @Indexed(name = "ui_view_co_name_index", unique = true)
+    private String name;
+    private String description;
+    private Object config;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Object getConfig() {
+        return config;
+    }
+
+    public void setConfig(Object config) {
+        this.config = config;
+    }
+}

+ 38 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ComponentRepository.java

@@ -0,0 +1,38 @@
+package com.usoftchina.saas.ui.repository;
+
+import com.usoftchina.saas.ui.po.Component;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface ComponentRepository extends MongoRepository<Component, String> {
+    /**
+     * 查找view下的组件
+     *
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    List<Component> findByViewNameAndParentIdOrderByOrderNum(String viewName, String parentId);
+
+    /**
+     * 查找view下的组件
+     *
+     * @param parentId
+     * @return
+     */
+    List<Component> findByParentIdOrderByOrderNum(String parentId);
+
+    /**
+     * 按view删除
+     *
+     * @param viewName
+     */
+    void deleteByViewName(String viewName);
+}

+ 27 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/ViewRepository.java

@@ -0,0 +1,27 @@
+package com.usoftchina.saas.ui.repository;
+
+import com.usoftchina.saas.ui.po.View;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface ViewRepository extends MongoRepository<View, String> {
+    /**
+     * 按名称查找
+     *
+     * @param name
+     * @return
+     */
+    View findByName(String name);
+
+    /**
+     * 按名称删除
+     *
+     * @param name
+     */
+    void deleteByName(String name);
+}

+ 32 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoComponentRepository.java

@@ -0,0 +1,32 @@
+package com.usoftchina.saas.ui.repository.co;
+
+import com.usoftchina.saas.ui.po.co.CoComponent;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface CoComponentRepository extends MongoRepository<CoComponent, String> {
+    /**
+     * 查找view下的组件
+     *
+     * @param companyId
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    List<CoComponent> findByCompanyIdAndViewNameAndParentIdOrderByOrderNum(Long companyId, String viewName, String parentId);
+
+    /**
+     * 按view删除
+     *
+     * @param companyId
+     * @param viewName
+     */
+    void deleteByCompanyIdAndViewName(Long companyId, String viewName);
+}

+ 29 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/repository/co/CoViewRepository.java

@@ -0,0 +1,29 @@
+package com.usoftchina.saas.ui.repository.co;
+
+import com.usoftchina.saas.ui.po.co.CoView;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Repository
+public interface CoViewRepository extends MongoRepository<CoView, String> {
+    /**
+     * 按名称查找
+     *
+     * @param companyId
+     * @param name
+     * @return
+     */
+    CoView findByCompanyIdAndName(Long companyId, String name);
+
+    /**
+     * 按名称删除
+     *
+     * @param companyId
+     * @param name
+     */
+    void deleteByCompanyIdAndName(Long companyId, String name);
+}

+ 67 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ComponentService.java

@@ -0,0 +1,67 @@
+package com.usoftchina.saas.ui.service;
+
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.repository.ComponentRepository;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class ComponentService {
+
+    @Autowired
+    private ComponentRepository componentRepository;
+
+    @CacheEvict(value = "viewConfig", key = "#component.viewName")
+    public Component save(Component component) {
+        return componentRepository.save(component);
+    }
+
+    @CacheEvict(value = "viewConfig", key = "#viewName")
+    public void deleteByView(String viewName) {
+        componentRepository.deleteByViewName(viewName);
+    }
+
+    /**
+     * 按viewName深度查找config
+     *
+     * @param viewName
+     * @return
+     */
+    public List<Object> getDeepConfigsByView(String viewName) {
+        return getDeepConfigsByParent(viewName, null);
+    }
+
+    /**
+     * 按parentId深度查找config
+     *
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    private List<Object> getDeepConfigsByParent(String viewName, String parentId) {
+        List<Component> components = componentRepository.findByViewNameAndParentIdOrderByOrderNum(viewName, parentId);
+        if (!CollectionUtils.isEmpty(components)) {
+            return components.stream().map(cmp -> {
+                Map<String, Object> config = (Map<String, Object>) cmp.getConfig();
+                List<Object> childrenConfigs = getDeepConfigsByParent(viewName, cmp.get_id());
+                if (!CollectionUtils.isEmpty(childrenConfigs)) {
+                    config.put(StringUtils.nullIf(cmp.getChildrenProperty(), Const.DEFAULT_CHILDREN_PROPERTY), childrenConfigs);
+                }
+                return config;
+            }).collect(Collectors.toList());
+        }
+        return null;
+    }
+}

+ 51 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/ViewService.java

@@ -0,0 +1,51 @@
+package com.usoftchina.saas.ui.service;
+
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.repository.ViewRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class ViewService {
+
+    @Autowired
+    private ViewRepository viewRepository;
+
+    @Autowired
+    private ComponentService componentService;
+
+    @CacheEvict(value = "viewConfig", key = "#view.name")
+    public View save(View view) {
+        return viewRepository.save(view);
+    }
+
+    @Cacheable(value = "viewConfig", key = "#name")
+    public Object getDeepConfig(String name) {
+        View view = viewRepository.findByName(name);
+        if (null != view && null != view.getConfig()) {
+            Map<String, Object> config = (Map<String, Object>) view.getConfig();
+            List<Object> items = componentService.getDeepConfigsByView(name);
+            if (!CollectionUtils.isEmpty(items)) {
+                config.put(Const.DEFAULT_CHILDREN_PROPERTY, items);
+            }
+            return config;
+        }
+        return null;
+    }
+
+    @CacheEvict(value = "viewConfig", key = "#name")
+    public void deleteView(String name) {
+        viewRepository.deleteByName(name);
+    }
+}

+ 71 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoComponentService.java

@@ -0,0 +1,71 @@
+package com.usoftchina.saas.ui.service.co;
+
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.po.co.CoComponent;
+import com.usoftchina.saas.ui.repository.co.CoComponentRepository;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class CoComponentService {
+
+    @Autowired
+    private CoComponentRepository componentRepository;
+
+    @CacheEvict(value = "coViewConfig", key = "#component.viewName")
+    public CoComponent save(CoComponent component) {
+        component.setCompanyId(BaseContextHolder.getCompanyId());
+        return componentRepository.save(component);
+    }
+
+    @CacheEvict(value = "coViewConfig", key = "#viewName")
+    public void deleteByView(String viewName) {
+        componentRepository.deleteByCompanyIdAndViewName(BaseContextHolder.getCompanyId(), viewName);
+    }
+
+    /**
+     * 按viewName深度查找config
+     *
+     * @param viewName
+     * @return
+     */
+    public List<Object> getDeepConfigsByView(String viewName) {
+        return getDeepConfigsByParent(BaseContextHolder.getCompanyId(), viewName, null);
+    }
+
+    /**
+     * 按parentId深度查找config
+     *
+     * @param companyId
+     * @param viewName
+     * @param parentId
+     * @return
+     */
+    private List<Object> getDeepConfigsByParent(Long companyId, String viewName, String parentId) {
+        List<CoComponent> components = componentRepository.findByCompanyIdAndViewNameAndParentIdOrderByOrderNum(companyId, viewName, parentId);
+        if (!CollectionUtils.isEmpty(components)) {
+            return components.stream().map(cmp -> {
+                Map<String, Object> config = (Map<String, Object>) cmp.getConfig();
+                List<Object> childrenConfigs = getDeepConfigsByParent(companyId, viewName, cmp.get_id());
+                if (!CollectionUtils.isEmpty(childrenConfigs)) {
+                    config.put(StringUtils.nullIf(cmp.getChildrenProperty(), Const.DEFAULT_CHILDREN_PROPERTY), childrenConfigs);
+                }
+                return config;
+            }).collect(Collectors.toList());
+        }
+        return null;
+    }
+}

+ 55 - 0
base-servers/ui-server/src/main/java/com/usoftchina/saas/ui/service/co/CoViewService.java

@@ -0,0 +1,55 @@
+package com.usoftchina.saas.ui.service.co;
+
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.ui.core.Const;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.po.co.CoView;
+import com.usoftchina.saas.ui.repository.ViewRepository;
+import com.usoftchina.saas.ui.repository.co.CoViewRepository;
+import com.usoftchina.saas.ui.service.ComponentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@Service
+public class CoViewService {
+    @Autowired
+    private CoViewRepository viewRepository;
+
+    @Autowired
+    private CoComponentService componentService;
+
+    @CacheEvict(value = "coViewConfig", key = "#view.name")
+    public CoView save(CoView view) {
+        view.setCompanyId(BaseContextHolder.getCompanyId());
+        return viewRepository.save(view);
+    }
+
+    @Cacheable(value = "coViewConfig", key = "#name")
+    public Object getDeepConfig(String name) {
+        CoView view = viewRepository.findByCompanyIdAndName(BaseContextHolder.getCompanyId(), name);
+        if (null != view && null != view.getConfig()) {
+            Map<String, Object> config = (Map<String, Object>) view.getConfig();
+            List<Object> items = componentService.getDeepConfigsByView(name);
+            if (!CollectionUtils.isEmpty(items)) {
+                config.put(Const.DEFAULT_CHILDREN_PROPERTY, items);
+            }
+            return config;
+        }
+        return null;
+    }
+
+    @CacheEvict(value = "coViewConfig", key = "#name")
+    public void deleteView(String name) {
+        viewRepository.deleteByCompanyIdAndName(BaseContextHolder.getCompanyId(), name);
+    }
+}

+ 46 - 0
base-servers/ui-server/src/main/resources/application.yml

@@ -0,0 +1,46 @@
+spring:
+  application:
+    name: ui-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  rabbitmq:
+    host: 192.168.0.176
+    port: 5672
+    password: guest
+    username: guest
+  zipkin:
+    sender:
+      type: rabbit
+  sleuth:
+    sampler:
+      percentage: 1.0
+  data:
+    mongodb:
+      uri: mongodb://192.168.253.12:27017/saas_ui
+server:
+  port: 8620
+  tomcat:
+    uri-encoding: UTF-8
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@192.168.0.181:8500/eureka/
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+auth:
+  public-key: auth/pub.key

BIN
base-servers/ui-server/src/main/resources/auth/pub.key


+ 15 - 0
base-servers/ui-server/src/main/resources/banner.txt

@@ -0,0 +1,15 @@
+${AnsiColor.BRIGHT_YELLOW}
+
+88        88   ad88888ba     ,ad8888ba,    88888888888  888888888888  ,ad8888ba,   88        88  88  888b      88         db
+88        88  d8"     "8b   d8"'    `"8b   88                88      d8"'    `"8b  88        88  88  8888b     88        d88b
+88        88  Y8,          d8'        `8b  88                88     d8'            88        88  88  88 `8b    88       d8'`8b
+88        88  `Y8aaaaa,    88          88  88aaaaa           88     88             88aaaaaaaa88  88  88  `8b   88      d8'  `8b
+88        88    `"""""8b,  88          88  88"""""           88     88             88""""""""88  88  88   `8b  88     d8YaaaaY8b
+88        88          `8b  Y8,        ,8P  88                88     Y8,            88        88  88  88    `8b 88    d8""""""""8b
+Y8a.    .a8P  Y8a     a8P   Y8a.    .a8P   88                88      Y8a.    .a8P  88        88  88  88     `8888   d8'        `8b
+ `"Y8888Y"'    "Y88888P"     `"Y8888Y"'    88                88       `"Y8888Y"'   88        88  88  88      `888  d8'          `8b
+
+
+Application Version: ${application.version}${application.formatted-version}
+Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
+${AnsiColor.DEFAULT}

+ 4 - 0
base-servers/ui-server/src/main/resources/config/application-docker.yml

@@ -0,0 +1,4 @@
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server:8500/eureka/

+ 64 - 0
base-servers/ui-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
+    <jmxConfigurator/>
+
+    <!--
+    %m
+    输出代码中指定的消息
+    %p
+    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
+    %r
+    输出自应用启动到输出该log信息耗费的毫秒数
+    %c
+    输出所属的类目,通常就是所在类的全名
+    %t
+    输出产生该日志事件的线程名
+    %n
+    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
+    %d
+    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
+    输出类似:2002年10月18日 22:10:28,921
+    %l
+    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
+    -->
+
+    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/saas/ui-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="ui-server"/>
+    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
+    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
+    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
+
+    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
+
+
+    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${log.level.console}</level>
+        </filter>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/root.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 每天一归档 -->
+            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
+            <!-- 单个日志文件最多 100MB, 60天的日志周期,最大不能超过20GB -->
+            <maxFileSize>128MB</maxFileSize>
+            <maxHistory>60</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="${log.level.console}">
+        <appender-ref ref="CONSOLE_APPENDER"/>
+        <appender-ref ref="ROOT_APPENDER"/>
+    </root>
+
+</configuration>

+ 148 - 0
base-servers/ui-server/src/test/java/com/usoftchina/saas/ui/test/ViewServiceTest.java

@@ -0,0 +1,148 @@
+package com.usoftchina.saas.ui.test;
+
+import com.usoftchina.saas.ui.po.Component;
+import com.usoftchina.saas.ui.po.View;
+import com.usoftchina.saas.ui.service.ComponentService;
+import com.usoftchina.saas.ui.service.ViewService;
+import com.usoftchina.saas.utils.JsonUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class ViewServiceTest {
+
+    @Autowired
+    private ViewService viewService;
+
+    @Autowired
+    private ComponentService componentService;
+
+    private String viewName = "test.form";
+
+    @Before
+    public void generateData() {
+        viewData();
+        part1Data();
+        part2Data();
+    }
+
+    private void viewData() {
+        View view = new View();
+        view.setName(viewName);
+        view.setDescription("测试表单");
+
+        Map<String, Object> config = new HashMap<>(2);
+        config.put("xtype", "container");
+        config.put("layout", "vbox");
+        view.setConfig(config);
+
+        view = viewService.save(view);
+
+        System.out.println(JsonUtils.toJsonString(view));
+    }
+
+    private void part1Data() {
+        Component part1 = new Component();
+        part1.setViewName(viewName);
+        part1.setOrderNum(1);
+        part1.setDescription("抬头Form");
+        Map<String, Object> part1Config = new HashMap<>(3);
+        part1Config.put("xtype", "form");
+        part1Config.put("height", 180);
+        part1Config.put("layout", "column");
+        part1.setConfig(part1Config);
+        part1 = componentService.save(part1);
+        System.out.println(JsonUtils.toJsonString(part1));
+
+        Component field1 = new Component();
+        field1.setViewName(viewName);
+        field1.setOrderNum(1);
+        field1.setDescription("编号");
+        field1.setParentId(part1.get_id());
+        Map<String, Object> field1Config = new HashMap<>(4);
+        field1Config.put("xtype", "textfield");
+        field1Config.put("name", "code");
+        field1Config.put("columnWidth", 0.25);
+        field1Config.put("fieldLabel", "编号");
+        field1.setConfig(field1Config);
+        componentService.save(field1);
+
+        Component field2 = new Component();
+        field2.setViewName(viewName);
+        field2.setOrderNum(2);
+        field2.setDescription("单据日期");
+        field2.setParentId(part1.get_id());
+        Map<String, Object> field2Config = new HashMap<>(3);
+        field2Config.put("xtype", "textfield");
+        field1Config.put("name", "docDate");
+        field2Config.put("columnWidth", 0.25);
+        field2Config.put("fieldLabel", "单据日期");
+        field2.setConfig(field2Config);
+        componentService.save(field2);
+    }
+
+    private void part2Data() {
+        Component part2 = new Component();
+        part2.setViewName(viewName);
+        part2.setOrderNum(2);
+        part2.setDescription("明细Grid");
+        part2.setChildrenProperty("columns");
+        Map<String, Object> part2Config = new HashMap<>(3);
+        part2Config.put("xtype", "grid");
+        part2Config.put("flex", 1);
+        part2Config.put("title", "商品清单");
+        part2.setConfig(part2Config);
+        part2 = componentService.save(part2);
+        System.out.println(JsonUtils.toJsonString(part2));
+
+        Component col1 = new Component();
+        col1.setViewName(viewName);
+        col1.setOrderNum(1);
+        col1.setDescription("商品编号");
+        col1.setParentId(part2.get_id());
+        Map<String, Object> col1Config = new HashMap<>(4);
+        col1Config.put("xtype", "triggercolumn");
+        col1Config.put("dataIndex", "pr_code");
+        col1Config.put("text", "商品编号");
+        col1.setConfig(col1Config);
+        componentService.save(col1);
+
+        Component col2 = new Component();
+        col2.setViewName(viewName);
+        col2.setOrderNum(2);
+        col2.setDescription("单位");
+        col2.setParentId(part2.get_id());
+        Map<String, Object> col2Config = new HashMap<>(3);
+        col2Config.put("xtype", "gridcolumn");
+        col2Config.put("dataIndex", "pr_unit");
+        col2Config.put("text", "单位");
+        col2.setConfig(col2Config);
+        componentService.save(col2);
+    }
+
+    @Test
+    public void getViewConfig() {
+        Object config = viewService.getDeepConfig(viewName);
+        System.out.println(JsonUtils.toJsonString(config));
+        // {"layout":"vbox","xtype":"container","items":[{"layout":"column","xtype":"form","height":180,"items":[{"name":"code","columnWidth":0.25,"xtype":"textfield","fieldLabel":"编号"},{"columnWidth":0.25,"xtype":"textfield","fieldLabel":"单据日期"}]},{"title":"商品清单","flex":1,"xtype":"grid","columns":[{"dataIndex":"pr_code","xtype":"triggercolumn","text":"商品编号"},{"dataIndex":"pr_unit","xtype":"gridcolumn","text":"单位"}]}]}
+    }
+
+    @After
+    public void deleteData() {
+        componentService.deleteByView(viewName);
+        viewService.deleteView(viewName);
+    }
+}

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

@@ -0,0 +1,18 @@
+package com.usoftchina.saas.utils;
+
+/**
+ * @author yingp
+ * @date 2018/10/10
+ */
+public class StringUtils {
+    /**
+     * 为空取值
+     *
+     * @param target
+     * @param nullValue
+     * @return
+     */
+    public static String nullIf(String target, String nullValue) {
+        return (null == target || target.isEmpty()) ? nullValue : target;
+    }
+}

+ 7 - 4
frontend/saas-web/app/util/GridUtil.js

@@ -4,7 +4,7 @@ Ext.define('saas.util.GridUtil', {
      * @param grid grid组件
      * @param url 请求url
      */
-    getGridColumns: function(grid, url, callback) {
+    setColumns: function(grid, url) {
         Ext.Ajax.request({
             url: url,
             success: function(response, opts) {
@@ -13,9 +13,12 @@ Ext.define('saas.util.GridUtil', {
                 var store = Ext.create('Ext.data.Store', {
                     fields,
                 });
+                if(grid.showIndex) {
+                    columns.unshift({ xtype: 'rownumberer' });
+                }
                 grid.reconfigure(store, columns);
 
-                typeof callback == 'function' && callback(grid, columns);
+                grid.fireEvent('afterSetColumns', grid, columns);
             },
        
             failure: function(response, opts) {
@@ -29,14 +32,14 @@ Ext.define('saas.util.GridUtil', {
      * @param grid grid组件
      * @param url 请求url
      */
-    loadData: function(grid, url, callback) {
+    loadData: function(grid, url) {
         Ext.Ajax.request({
             url: url,
             success: function(response, opts) {
                 var data = Ext.decode(response.responseText);
                 grid.getStore().loadData(data);
 
-                typeof callback == 'function' && callback(grid, data);
+                grid.fireEvent('afterLoadData', grid, data);
             },
        
             failure: function(response, opts) {

+ 35 - 5
frontend/saas-web/app/view/core/form/FormPanel.js

@@ -4,16 +4,46 @@ Ext.define('saas.view.core.form.FormPanel', {
 
     FormUtil: Ext.create('saas.util.FormUtil'),
 
-    layout: 'column',
+    controller: 'core-form-formpanel',
 
-    configUrl: '',
+    layout: 'column',
+    autoScroll: true,
+    border: 1,
+    bodyPadding: 5,
 
-    defautls: {
-        margin: '0 2 2 0',
+    fieldDefaults: {
+        margin: '0 5 5 0',
         labelAlign: 'right',
-        labelWidth: 90
+        labelWidth: 90,
+        columnWidth: 0.25,
+        blankText: '该字段不能为空'
     },
 
+    dockedItems: [{
+        xtype: 'toolbar',
+        dock: 'top',
+        style: {
+            'border-bottom': '1px solid #35baf6 !important'
+        },
+        items: [{
+            xtype: 'tbtext',
+            bind: '单据编号:{id}'
+        }, '->', {
+            xtype: 'button',
+            text: '新增',
+        }, {
+            xtype: 'button',
+            text: '保存'
+        }, {
+            xtype: 'button',
+            text: '审核'
+        }]
+    }],
+
+    items: [],
+    
+    configUrl: '',
+    
     initComponent: function() {
         var me = this;
         me.configUrl && me.FormUtil.getFormItems(me, me.configUrl);

+ 6 - 0
frontend/saas-web/app/view/core/form/FormPanelController.js

@@ -0,0 +1,6 @@
+Ext.define('saas.view.core.form.FormPanelController', {
+    extend: 'Ext.app.ViewController',
+    alias: 'controller.core-form-formpanel',
+
+    
+});

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

@@ -0,0 +1,40 @@
+Ext.define('saas.view.core.form.field.DetailGridField', {
+    extend: 'Ext.grid.Panel',
+    xtype: 'detailGridField',
+
+    GridUtil: Ext.create('saas.util.GridUtil'),
+
+    border: 1,
+    margin: '0 5 5 0', // formpanel的fieldDefaults未生效
+    height: 300,
+
+    controller: 'core-form-field-detailgridfield',
+
+    dockedItems: [{
+        xtype: 'toolbar',
+        dock: 'bottom',
+        items: [{
+            iconCls: 'x-fa fa-plus',
+            handler: 'addDetail'
+        }, {
+            iconCls: 'x-fa fa-delete',
+            handler: 'deleteDetail'
+        }, {
+            text: '审核',
+            handler: 'add10EmptyRow'
+        }]
+    }],
+
+    store: {
+        data: []
+    },
+
+    showIndex: true,
+    configUrl: '',
+
+    initComponent: function() {
+        var me = this;
+        me.configUrl && me.GridUtil.setColumns(me, me.configUrl);
+        me.callParent(arguments);
+    },
+});

+ 33 - 0
frontend/saas-web/app/view/core/form/field/DetailGridFieldController.js

@@ -0,0 +1,33 @@
+Ext.define('saas.view.core.form.field.MyFieldController', {
+    extend: 'Ext.app.ViewController',
+    alias: 'controller.core-form-field-detailgridfield',
+
+    control: {
+        'grid': {
+            afterSetColumns: 'add10EmptyRow'
+        }
+    },
+
+    add10EmptyRow: function() {
+        var me = this,
+            grid = me.getView(),
+            store = grid.getStore(),
+            selectedRecord = grid.selModel.lastSelected,
+            datas = [];
+
+        Ext.Array.each(new Array(10), function() {
+            datas.push({});
+        })
+        grid.store.insert(store.indexOf(selectedRecord) + 1, datas);
+    },
+
+    addDetail: function() {
+        var me = this,
+            grid = me.getView(),
+            store = grid.getStore(),
+            selectedRecord = grid.selModel.lastSelected;
+
+        grid.store.insert(store.indexOf(selectedRecord) + 1, {});
+    }
+
+});

+ 3 - 3
frontend/saas-web/app/view/core/grid/GridPanel.js

@@ -4,14 +4,14 @@ Ext.define('saas.view.core.grid.GridPanel', {
 
     GridUtil: Ext.create('saas.util.GridUtil'),
 
+    controller: 'core-grid-gridpanel',
+
     configUrl: '',
     dataUrl: '',
 
     initComponent: function() {
         var me = this;
-        me.configUrl && me.GridUtil.getGridColumns(me, me.configUrl, function() {
-            me.dataUrl && me.GridUtil.loadData(me, me.dataUrl);
-        });
+        me.configUrl && me.GridUtil.setColumns(me, me.configUrl);
         me.callParent(arguments);
     }
 });

+ 19 - 0
frontend/saas-web/app/view/core/grid/GridPanelController.js

@@ -0,0 +1,19 @@
+Ext.define('saas.view.core.grid.GridPanelController', {
+    extend: 'Ext.app.ViewController',
+    alias: 'controller.core-grid-gridpanel',
+
+    control: {
+        'grid': {
+            afterSetColumns: '_initLoadData'
+        }
+    },
+
+    _initLoadData: function() {
+        var me = this,
+            grid = me.getView(),
+            GridUtil = grid.GridUtil,
+            dataUrl = grid.dataUrl;
+        
+        dataUrl && GridUtil.loadData(grid, dataUrl);
+    }
+});

+ 16 - 46
frontend/saas-web/app/view/main/MainController.js

@@ -9,23 +9,29 @@ Ext.define('saas.view.main.MainController', {
 
     onNavigationTreeSelectionChange: function (tree, node) {
         if (node && node.get('viewType')) {
-            this.setActiveTab(node.get('id'), node.get('viewType'), node.get('text'));
+            this.setActiveTab(node.getData());
         }
     },
 
-    setActiveTab: function(id, type, title) {
-        debugger
+    setActiveTab: function(nodeData) {
         var me = this,
             refs = me.getReferences(),
             mainTab = refs.mainTabPanel,
             // existingItem = mainTab.child(type),
-            existingItem = mainTab.down('[id=' + id + ']'),
-            newView;
+            newView,
+            id = 'maintab-' + nodeData.id 
 
-        lastView = mainTab.getActiveTab();
+,
+            title = nodeData.text;
+            existingItem = mainTab.down('[id=' + id + ']'),
+            lastView = mainTab.getActiveTab();
 
         if (!existingItem) {
-            newView = me.createTab({ type: type, title: title, id: id });
+            newView = Ext.create('saas.view.core.tab.Panel', {
+                id: id,
+                title: title,
+                tabConfig: nodeData
+            });
         }
 
         if (!newView || !newView.isWindow) {
@@ -52,44 +58,6 @@ Ext.define('saas.view.main.MainController', {
         }
     },
 
-    createTab: function(tabConfig) {
-        var me = this,
-            type = tabConfig.type;
-        
-        if(type == 'grid') {
-            return me.createGrid(tabConfig);
-        }else if(type == 'form') {
-            return me.createForm(tabConfig);
-        }else {
-            var { id, title } = tabConfig;
-            return Ext.create('Ext.panel.Panel', {
-                id,
-                title,
-                html: '无效类型'
-            });
-        }
-    },
-
-    createGrid: function(tabConfig) {
-        var me = this;
-        var { id, title } = tabConfig;
-        var grid = Ext.create('saas.view.purchase.list.GridPanel', {
-            id,
-            title
-        });
-        return grid;
-    },
-
-    createForm: function(tabConfig) {
-        var me = this;
-        var { id, title } = tabConfig;
-        var form = Ext.create('saas.view.core.form.Panel', {
-            id,
-            title
-        });
-        return form;
-    },
-
     onToggleNavigationSize: function () {
         var me = this,
             refs = me.getReferences(),
@@ -98,7 +66,9 @@ Ext.define('saas.view.main.MainController', {
             collapsing = !navigationList.getMicro(),
             new_width = collapsing ? 64 : 250;
 
-        if (Ext.isIE9m || !Ext.os.is.Desktop) {
+        if (Ext.isIE9m || !Ext.os.is 
+
+.Desktop) {
             Ext.suspendLayouts();
 
             refs.mainLogo.setWidth(new_width);

+ 9 - 4
frontend/saas-web/app/view/main/MainModel.js

@@ -30,18 +30,23 @@ Ext.define('saas.view.main.MainModel', {
                                         text: '采购单',
                                         viewType: 'grid',
                                         leaf: true
+                                    }, {
+                                        id: 'list1',
+                                        text: '列表界面1',
+                                        viewType: 'purchase-list-gridpanel1',
+                                        leaf: true
                                     },
                                     {
                                         id: 'list2',
                                         text: '列表界面2',
-                                        viewType: 'grid',
+                                        viewType: 'purchase-list-gridpanel2',
                                         leaf: true
                                     },
                                     {
                                         id: 'form1',
-                                        text: '采购订单',
-                                        viewType: 'panel',
-                                        leaf: true                                     
+                                        text: '主从表界面1',
+                                        viewType: 'purchase-order-formpanel',
+                                        leaf: true
                                     },
                                     {
                                         id: 'ghdd',

+ 3 - 3
frontend/saas-web/app/view/purchase/list/GridPanel.js → frontend/saas-web/app/view/purchase/list/GridPanel1.js

@@ -1,8 +1,8 @@
-Ext.define('saas.view.purchase.list.GridPanel', {
+Ext.define('saas.view.purchase.list.GridPanel1', {
     extend: 'saas.view.core.grid.GridPanel',
-    xtype: 'purchase-list-gridpanel',
+    xtype: 'purchase-list-gridpanel1',
 
-    controller: 'purchase-list-listcontroller',
+    controller: 'purchase-list-listcontroller1',
     
     configUrl: 'resources/json/gridColumns1.json',
     dataUrl: 'resources/json/gridData1.json'

+ 9 - 0
frontend/saas-web/app/view/purchase/list/GridPanel2.js

@@ -0,0 +1,9 @@
+Ext.define('saas.view.purchase.list.GridPanel2', {
+    extend: 'saas.view.core.grid.GridPanel',
+    xtype: 'purchase-list-gridpanel2',
+
+    controller: 'purchase-list-listcontroller2',
+    
+    configUrl: 'resources/json/gridColumns2.json',
+    dataUrl: 'resources/json/gridData2.json'
+});

+ 12 - 0
frontend/saas-web/app/view/purchase/list/ListController1.js

@@ -0,0 +1,12 @@
+Ext.define('saas.view.purchase.list.ListController1', {
+    extend: 'saas.view.core.grid.GridPanelController',
+    alias: 'controller.purchase-list-listcontroller1',
+
+    control: {
+        'grid': {
+            itemClick: function() {
+                console.log('grid1: click.....');
+            }
+        }
+    },
+});

+ 12 - 0
frontend/saas-web/app/view/purchase/list/ListController2.js

@@ -0,0 +1,12 @@
+Ext.define('saas.view.purchase.list.ListController2', {
+    extend: 'saas.view.core.grid.GridPanelController',
+    alias: 'controller.purchase-list-listcontroller2',
+
+    control: {
+        'grid': {
+            itemClick: function() {
+                console.log('grid2: click.....');
+            }
+        }
+    },
+});

+ 6 - 0
frontend/saas-web/app/view/purchase/order/FormController.js

@@ -0,0 +1,6 @@
+Ext.define('saas.view.purchase.order.FormController', {
+    extend: 'saas.view.core.form.FormPanelController',
+    alias: 'controller.purchase-order-formcontroller',
+
+
+});

+ 14 - 0
frontend/saas-web/app/view/purchase/order/FormModel.js

@@ -0,0 +1,14 @@
+Ext.define('saas.view.purchase.order.FormModel', {
+    extend: 'Ext.app.ViewModel',
+    alias: 'viewmodel.purchase-order-formmodel',
+
+    data: {
+        id: 'TC-1032301'
+    },
+
+    formulas: {
+        sum: function(get) {
+            return get('num1') + get('num2');
+        }
+    }
+});

+ 10 - 0
frontend/saas-web/app/view/purchase/order/FormPanel.js

@@ -0,0 +1,10 @@
+Ext.define('saas.view.purchase.order.FormPanel', {
+    extend: 'saas.view.core.form.FormPanel',
+    xtype: 'purchase-order-formpanel',
+
+    controller: 'purchase-order-formcontroller',
+    viewModel: 'purchase-order-formmodel',
+
+    configUrl: 'resources/json/formItems.json',
+
+});

+ 17 - 0
frontend/saas-web/resources/json/detailGridColumns1.json

@@ -0,0 +1,17 @@
+[{
+    "text": "列1",
+    "dataIndex": "col1",
+    "width": 100
+}, {
+    "text": "列2",
+    "dataIndex": "col2",
+    "width": 200
+}, {
+    "text": "列3",
+    "dataIndex": "col3",
+    "width": 400
+}, {
+    "text": "列4",
+    "dataIndex": "col4",
+    "width": 600
+}]

+ 32 - 0
frontend/saas-web/resources/json/formItems.json

@@ -26,4 +26,36 @@
     "fieldLabel": "和",
     "allowBlank": false,
     "columnWidth": 1
+}, {
+    "xtype": "detailGridField",
+    "columnWidth": 1,
+    "configUrl": "resources/json/detailGridColumns1.json"
+}, {
+    "xtype": "datefield",
+    "name": "createTime",
+    "bind": "{createTime}",
+    "fieldLabel": "制单日期",
+    "allowBlank": true,
+    "columnWidth": 0.25 
+}, {
+    "xtype": "textfield",
+    "name": "creator",
+    "bind": "{creator}",
+    "fieldLabel": "制单人",
+    "allowBlank": true,
+    "columnWidth": 0.25 
+}, {
+    "xtype": "textfield",
+    "name": "field1",
+    "bind": "{field1}",
+    "fieldLabel": "field1",
+    "allowBlank": true,
+    "columnWidth": 1 
+}, {
+    "xtype": "textfield",
+    "name": "field2",
+    "bind": "{field2}",
+    "fieldLabel": "field2",
+    "allowBlank": true,
+    "columnWidth": 1 
 }]

+ 0 - 0
frontend/saas-web/resources/json/navigation.json


+ 12 - 0
script/docker-base.yaml

@@ -12,6 +12,18 @@ services:
       - "25672:25672"
     networks:
       - saas
+  mongodb:
+    image: mongo
+    container_name: mongodb
+    ports:
+      - "27017:27017"
+    volumes:
+      - /data/mongodb:/data/db
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: root
+      MONGO_INITDB_ROOT_PASSWORD: select111***
+    networks:
+      - saas
 #  mysql:
 #    image: mysql:5.7
 #    container_name: mysql

+ 3 - 11
script/mysql/init/ui.sql

@@ -1,17 +1,9 @@
 CREATE DATABASE `saas_ui` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
 use `saas_ui`;
 
-create table `ui_page`(
+create table `ui_component`(
   id int unsigned primary key not null auto_increment,
+  parent_id varchar(100),
   description varchar(500) not null,
-  xtype varchar(50),
-  layout json
-);
-
-create table `ui_form`(
-  id int unsigned primary key not null auto_increment,
-  page_id varchar(100) not null,
-  field_name varchar(100) not null,
-  field_desc varchar(100) not null,
-  field_order int not null
+  config json not null
 );