瀏覽代碼

调整ignore文件

yingp 7 年之前
父節點
當前提交
9d1cf6449f
共有 25 個文件被更改,包括 1269 次插入4 次删除
  1. 16 1
      README.md
  2. 7 3
      applications/purchase/pom.xml
  3. 16 0
      applications/purchase/purchase-api/pom.xml
  4. 15 0
      applications/purchase/purchase-dto/pom.xml
  5. 57 0
      applications/purchase/purchase-server/pom.xml
  6. 19 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java
  7. 20 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/controller/PurchaseController.java
  8. 20 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/mapper/PurchaseMapper.java
  9. 135 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/po/Purchase.java
  10. 177 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/po/PurchaseItem.java
  11. 19 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/service/PurchaseService.java
  12. 20 0
      applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/service/impl/PurchaseServiceImpl.java
  13. 40 0
      applications/purchase/purchase-server/src/main/resources/application.yml
  14. 15 0
      applications/purchase/purchase-server/src/main/resources/banner.txt
  15. 64 0
      applications/purchase/purchase-server/src/main/resources/logback-spring.xml
  16. 38 0
      applications/purchase/purchase-server/src/main/resources/mapper/PurchaseMapper.xml
  17. 117 0
      frontend/saas-web/ext/classic/classic/src/fx/target/Component.js
  18. 79 0
      frontend/saas-web/ext/classic/classic/src/fx/target/CompositeElement.js
  19. 22 0
      frontend/saas-web/ext/classic/classic/src/fx/target/CompositeElementCSS.js
  20. 31 0
      frontend/saas-web/ext/classic/classic/src/fx/target/CompositeSprite.js
  21. 94 0
      frontend/saas-web/ext/classic/classic/src/fx/target/Element.js
  22. 74 0
      frontend/saas-web/ext/classic/classic/src/fx/target/ElementCSS.js
  23. 125 0
      frontend/saas-web/ext/classic/classic/src/fx/target/Sprite.js
  24. 39 0
      frontend/saas-web/ext/classic/classic/src/fx/target/Target.js
  25. 10 0
      pom.xml

+ 16 - 1
README.md

@@ -8,6 +8,9 @@
 │  |  ├─money---------------------------------资金
 │  |  ├─product-------------------------------物料
 │  |  ├─purchase------------------------------采购
+│  |  |  |─purchase-api-----------------------采购服务api
+│  |  |  |─purchase-dto-----------------------采购服务数据传输对象
+│  |  |  |─purchase-server--------------------采购服务
 │  |  ├─sale----------------------------------销售
 │  |  ├─storage-------------------------------库存
 │  |  ├─ui------------------------------------UI配置
@@ -53,4 +56,16 @@
 │  |  ├─mysql---------------------------------mysql脚本
 │  |  |  |─init-------------------------------mysql数据库初始化脚本
 │  │
-```
+```
+
+# 数据库:
+
+> 开发环境
+
+| 数据库      | 地址   |  账号  |  密码  |  说明  |
+| --------   | :-----:  | :----:  | :----: | :------  |
+| saas_account | 192.168.253.12:3306 |  root  | select111*** |  账户中心  |
+| saas_auth | 192.168.253.12:3306 |  root  | select111*** |  鉴权系统  |
+| saas_biz | 192.168.253.12:3306 |  root  | select111*** |  业务系统  |
+| saas_ui | 192.168.253.12:3306 |  root  | select111*** |  UI配置  |
+| saas_zipkin | 192.168.253.12:3306 |  root  | select111*** |  服务监控  |

+ 7 - 3
applications/purchase/pom.xml

@@ -10,7 +10,11 @@
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>purchase</artifactId>
-    <description>purchase server</description>
-
-
+    <description>purchase module</description>
+    <modules>
+        <module>purchase-api</module>
+        <module>purchase-server</module>
+        <module>purchase-dto</module>
+    </modules>
+    <packaging>pom</packaging>
 </project>

+ 16 - 0
applications/purchase/purchase-api/pom.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>purchase</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>purchase-api</artifactId>
+    <description>purchase server api</description>
+
+
+</project>

+ 15 - 0
applications/purchase/purchase-dto/pom.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>purchase</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>purchase-dto</artifactId>
+    <description>purchase data transfer object</description>
+
+</project>

+ 57 - 0
applications/purchase/purchase-server/pom.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>purchase</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>purchase-server</artifactId>
+    <description>purchase server</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>purchase-dto</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>auth-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </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>
+        </dependency>
+        <!-- sleuth -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-zipkin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit</artifactId>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 19 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/PurchaseApplication.java

@@ -0,0 +1,19 @@
+package com.usoftchina.saas.purchase;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+@SpringBootApplication
+@EnableEurekaClient
+@EnableTransactionManagement
+public class PurchaseApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(PurchaseApplication.class, args);
+    }
+}

+ 20 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/controller/PurchaseController.java

@@ -0,0 +1,20 @@
+package com.usoftchina.saas.purchase.controller;
+
+import com.usoftchina.saas.purchase.service.PurchaseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+@RestController
+@RequestMapping("/api/purchase")
+public class PurchaseController {
+
+    @Autowired
+    private PurchaseService purchaseService;
+
+
+}

+ 20 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/mapper/PurchaseMapper.java

@@ -0,0 +1,20 @@
+package com.usoftchina.saas.purchase.mapper;
+
+import com.usoftchina.saas.base.mapper.CommonBaseMapper;
+import com.usoftchina.saas.purchase.po.Purchase;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+public interface PurchaseMapper extends CommonBaseMapper<Purchase> {
+
+    /**
+     * 按单号查询
+     *
+     * @param code
+     * @return
+     */
+    Purchase selectByCode(@Param("code") String code);
+}

+ 135 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/po/Purchase.java

@@ -0,0 +1,135 @@
+package com.usoftchina.saas.purchase.po;
+
+import com.usoftchina.saas.base.entity.CommonBaseEntity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 采购订单
+ *
+ * @author yingp
+ * @date 2018/10/9
+ */
+public class Purchase extends CommonBaseEntity implements Serializable{
+    /**
+     * 编号
+     */
+    private String code;
+    /**
+     * 状态
+     */
+    private String status;
+    /**
+     * 供应商
+     */
+    private long vendorId;
+    /**
+     * 交货日期
+     */
+    private Date deliveryDate;
+    /**
+     * 单据日期
+     */
+    private Date docDate;
+    /**
+     * 自定义字段1
+     */
+    private String userDefined1;
+    /**
+     * 自定义字段2
+     */
+    private String userDefined2;
+    /**
+     * 自定义字段3
+     */
+    private String userDefined3;
+    /**
+     * 自定义字段4
+     */
+    private String userDefined4;
+    /**
+     * 自定义字段5
+     */
+    private String userDefined5;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public long getVendorId() {
+        return vendorId;
+    }
+
+    public void setVendorId(long vendorId) {
+        this.vendorId = vendorId;
+    }
+
+    public Date getDeliveryDate() {
+        return deliveryDate;
+    }
+
+    public void setDeliveryDate(Date deliveryDate) {
+        this.deliveryDate = deliveryDate;
+    }
+
+    public Date getDocDate() {
+        return docDate;
+    }
+
+    public void setDocDate(Date docDate) {
+        this.docDate = docDate;
+    }
+
+    public String getUserDefined1() {
+        return userDefined1;
+    }
+
+    public void setUserDefined1(String userDefined1) {
+        this.userDefined1 = userDefined1;
+    }
+
+    public String getUserDefined2() {
+        return userDefined2;
+    }
+
+    public void setUserDefined2(String userDefined2) {
+        this.userDefined2 = userDefined2;
+    }
+
+    public String getUserDefined3() {
+        return userDefined3;
+    }
+
+    public void setUserDefined3(String userDefined3) {
+        this.userDefined3 = userDefined3;
+    }
+
+    public String getUserDefined4() {
+        return userDefined4;
+    }
+
+    public void setUserDefined4(String userDefined4) {
+        this.userDefined4 = userDefined4;
+    }
+
+    public String getUserDefined5() {
+        return userDefined5;
+    }
+
+    public void setUserDefined5(String userDefined5) {
+        this.userDefined5 = userDefined5;
+    }
+}

+ 177 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/po/PurchaseItem.java

@@ -0,0 +1,177 @@
+package com.usoftchina.saas.purchase.po;
+
+import com.usoftchina.saas.base.entity.CommonBaseEntity;
+
+import java.io.Serializable;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+public class PurchaseItem extends CommonBaseEntity implements Serializable{
+    private long mainId;
+    /**
+     * 商品
+     */
+    private long productId;
+    /**
+     * 仓库
+     */
+    private long warehouseId;
+    /**
+     * 数量
+     */
+    private double qty;
+    /**
+     * 单价
+     */
+    private double price;
+    /**
+     * 含税单价
+     */
+    private double taxPrice;
+    /**
+     * 税率
+     */
+    private float taxRate;
+    /**
+     * 税额
+     */
+    private double taxAmount;
+    /**
+     * 折扣率
+     */
+    private float disRate;
+    /**
+     * 折扣额
+     */
+    private double disAmount;
+    /**
+     * 金额
+     */
+    private double amount;
+    /**
+     * 价税合计
+     */
+    private double totalTaxAmount;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 关联订单
+     */
+    private Long srcOrderId;
+
+    public long getMainId() {
+        return mainId;
+    }
+
+    public void setMainId(long mainId) {
+        this.mainId = mainId;
+    }
+
+    public long getProductId() {
+        return productId;
+    }
+
+    public void setProductId(long productId) {
+        this.productId = productId;
+    }
+
+    public long getWarehouseId() {
+        return warehouseId;
+    }
+
+    public void setWarehouseId(long warehouseId) {
+        this.warehouseId = warehouseId;
+    }
+
+    public double getQty() {
+        return qty;
+    }
+
+    public void setQty(double qty) {
+        this.qty = qty;
+    }
+
+    public double getPrice() {
+        return price;
+    }
+
+    public void setPrice(double price) {
+        this.price = price;
+    }
+
+    public double getTaxPrice() {
+        return taxPrice;
+    }
+
+    public void setTaxPrice(double taxPrice) {
+        this.taxPrice = taxPrice;
+    }
+
+    public float getTaxRate() {
+        return taxRate;
+    }
+
+    public void setTaxRate(float taxRate) {
+        this.taxRate = taxRate;
+    }
+
+    public double getTaxAmount() {
+        return taxAmount;
+    }
+
+    public void setTaxAmount(double taxAmount) {
+        this.taxAmount = taxAmount;
+    }
+
+    public float getDisRate() {
+        return disRate;
+    }
+
+    public void setDisRate(float disRate) {
+        this.disRate = disRate;
+    }
+
+    public double getDisAmount() {
+        return disAmount;
+    }
+
+    public void setDisAmount(double disAmount) {
+        this.disAmount = disAmount;
+    }
+
+    public double getAmount() {
+        return amount;
+    }
+
+    public void setAmount(double amount) {
+        this.amount = amount;
+    }
+
+    public double getTotalTaxAmount() {
+        return totalTaxAmount;
+    }
+
+    public void setTotalTaxAmount(double totalTaxAmount) {
+        this.totalTaxAmount = totalTaxAmount;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public Long getSrcOrderId() {
+        return srcOrderId;
+    }
+
+    public void setSrcOrderId(Long srcOrderId) {
+        this.srcOrderId = srcOrderId;
+    }
+}

+ 19 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/service/PurchaseService.java

@@ -0,0 +1,19 @@
+package com.usoftchina.saas.purchase.service;
+
+import com.usoftchina.saas.base.service.CommonBaseService;
+import com.usoftchina.saas.purchase.mapper.PurchaseMapper;
+import com.usoftchina.saas.purchase.po.Purchase;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+public interface PurchaseService extends CommonBaseService<PurchaseMapper, Purchase>{
+    /**
+     * 按单号查询
+     *
+     * @param code
+     * @return
+     */
+    Purchase findByCode(String code);
+}

+ 20 - 0
applications/purchase/purchase-server/src/main/java/com/usoftchina/saas/purchase/service/impl/PurchaseServiceImpl.java

@@ -0,0 +1,20 @@
+package com.usoftchina.saas.purchase.service.impl;
+
+import com.usoftchina.saas.base.service.CommonBaseServiceImpl;
+import com.usoftchina.saas.purchase.mapper.PurchaseMapper;
+import com.usoftchina.saas.purchase.po.Purchase;
+import com.usoftchina.saas.purchase.service.PurchaseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author yingp
+ * @date 2018/10/9
+ */
+@Service
+public class PurchaseServiceImpl extends CommonBaseServiceImpl<PurchaseMapper, Purchase> implements PurchaseService{
+
+    @Override
+    public Purchase findByCode(String code) {
+        return getMapper().selectByCode(code);
+    }
+}

+ 40 - 0
applications/purchase/purchase-server/src/main/resources/application.yml

@@ -0,0 +1,40 @@
+spring:
+  application:
+    name: purchase-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  datasource:
+    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***
+  messages:
+    basename: i18n/messages
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    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}@127.0.0.1:8500/eureka/
+server:
+  port: 8580
+  tomcat:
+    uri-encoding: UTF-8
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+mybatis:
+  type-aliases-package: com.usoftchina.saas.purchase.po
+  mapper-locations: classpath:mapper/*.xml

+ 15 - 0
applications/purchase/purchase-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}

+ 64 - 0
applications/purchase/purchase-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/purchase-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="purchase-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>

+ 38 - 0
applications/purchase/purchase-server/src/main/resources/mapper/PurchaseMapper.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.usoftchina.saas.purchase.mapper.PurchaseMapper">
+    <resultMap id="BaseResultMap" type="com.usoftchina.saas.purchase.po.Purchase">
+        <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="company_id" jdbcType="BIGINT" property="companyId"/>
+        <result column="code" jdbcType="VARCHAR" property="code"/>
+        <result column="status" jdbcType="VARCHAR" property="status"/>
+        <result column="vendor_id" jdbcType="BIGINT" property="vendorId"/>
+        <result column="delivery_date" jdbcType="TIMESTAMP" property="deliveryDate"/>
+        <result column="doc_date" jdbcType="TIMESTAMP" property="docDate"/>
+        <result column="user_defined1" jdbcType="VARCHAR" property="userDefined1"/>
+        <result column="user_defined2" jdbcType="VARCHAR" property="userDefined2"/>
+        <result column="user_defined3" jdbcType="VARCHAR" property="userDefined3"/>
+        <result column="user_defined4" jdbcType="VARCHAR" property="userDefined4"/>
+        <result column="user_defined5" jdbcType="VARCHAR" property="userDefined5"/>
+        <result column="creator_id" jdbcType="BIGINT" property="creatorId"/>
+        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
+        <result column="updater_id" jdbcType="BIGINT" property="updaterId"/>
+        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
+    </resultMap>
+    <sql id="baseColumns">
+        id,company_id,code,status,vendor_id,delivery_date,doc_date,user_defined1,user_defined2,user_defined3,
+        user_defined4,user_defined5,creator_id,create_time,updater_id,update_time
+    </sql>
+    <insert id="insert" parameterType="com.usoftchina.saas.purchase.po.Purchase">
+        insert into purchase(company_id, code, status, vendor_id, delivery_date, doc_date, user_defined1, user_defined2,
+        user_defined3, user_defined4, user_defined5, creator_id, create_time, updater_id, update_time)
+        values (#{companyId,jdbcType=BIGINT}, #{code,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
+        #{vendorId,jdbcType=BIGINT}, #{deliveryDate,jdbcType=TIMESTAMP}, #{docDate,jdbcType=TIMESTAMP},
+        #{userDefined1,jdbcType=VARCHAR}, #{userDefined2,jdbcType=VARCHAR}, #{userDefined3,jdbcType=VARCHAR},
+        #{userDefined4,jdbcType=VARCHAR}, #{userDefined5,jdbcType=VARCHAR}, #{creatorId,jdbcType=BIGINT},
+        #{createTime,jdbcType=TIMESTAMP}, #{updaterId,jdbcType=BIGINT}, #{updateTime,jdbcType=TIMESTAMP})
+    </insert>
+    <select id="selectByCode" parameterType="java.lang.String" resultMap="BaseResultMap">
+        select <include refid="baseColumns"/> from purchase where code=#{code}
+    </select>
+</mapper>

+ 117 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/Component.js

@@ -0,0 +1,117 @@
+/**
+ * @class Ext.fx.target.Component
+ * 
+ * This class represents a animation target for a {@link Ext.Component}. In general this class will not be
+ * created directly, the {@link Ext.Component} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+Ext.define('Ext.fx.target.Component', {
+
+    /* Begin Definitions */
+   
+    extend: 'Ext.fx.target.Target',
+    
+    /* End Definitions */
+
+    type: 'component',
+
+    // Methods to call to retrieve unspecified "from" values from a target Component
+    getPropMethod: {
+        top: function() {
+            return this.getPosition(true)[1];
+        },
+        left: function() {
+            return this.getPosition(true)[0];
+        },
+        x: function() {
+            return this.getPosition()[0];
+        },
+        y: function() {
+            return this.getPosition()[1];
+        },
+        height: function() {
+            return this.getHeight();
+        },
+        width: function() {
+            return this.getWidth();
+        },
+        opacity: function() {
+            return this.el.getStyle('opacity');
+        }
+    },
+
+    setMethods: {
+        top:     'setPosition',
+        left:    'setPosition',
+        x:       'setPagePosition',
+        y:       'setPagePosition',
+        height:  'setSize',
+        width:   'setSize',
+        opacity: 'setOpacity'
+    },
+
+    // Read the named attribute from the target Component. Use the defined getter for the attribute
+    getAttr: function(attr, val) {
+        return [[this.target, val !== undefined ? val : this.getPropMethod[attr].call(this.target)]];
+    },
+
+    setAttr: function(targetData, isFirstFrame, isLastFrame) {
+        var me = this,
+            ln = targetData.length,
+            attrs, attr, o, i, j, targets, left, top, w, h,
+            methodsToCall = {},
+            methodProps;
+
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i].attrs;
+            for (attr in attrs) {
+                targets = attrs[attr].length;
+                for (j = 0; j < targets; j++) {
+                    o = attrs[attr][j];
+                    methodProps = methodsToCall[me.setMethods[attr]] || (methodsToCall[me.setMethods[attr]] = {});
+                    methodProps.target = o[0];
+                    methodProps[attr] = o[1];
+                    // debugging code: Ext.log('Setting ' + o[0].id + "'s " + attr + ' to ' + o[1]);
+                }
+            }
+            if (methodsToCall.setPosition) {
+                o = methodsToCall.setPosition;
+                left = (o.left === undefined) ? undefined : parseFloat(o.left);
+                top = (o.top === undefined) ? undefined : parseFloat(o.top);
+                o.target.setPosition(left, top);
+            }
+            if (methodsToCall.setPagePosition) {
+                o = methodsToCall.setPagePosition;
+                o.target.setPagePosition(o.x, o.y);
+            }
+            if (methodsToCall.setSize) {
+                o = methodsToCall.setSize;
+                // Dimensions not being animated MUST NOT be autosized. They must remain at current value.
+                w = (o.width === undefined) ? o.target.getWidth() : parseFloat(o.width);
+                h = (o.height === undefined) ? o.target.getHeight() : parseFloat(o.height);
+
+                // Only set the size of the Component on the last frame, or if the animation was
+                // configured with dynamic: true.
+                // In other cases, we just set the target element size.
+                // This will result in either clipping if animating a reduction in size, or the revealing of
+                // the inner elements of the Component if animating an increase in size.
+                // Component's animate function initially resizes to the larger size before resizing the
+                // outer element to clip the contents.
+                o.target.el.setSize(w, h);
+                if (isLastFrame || me.dynamic) {
+                    // Defer the final sizing & layout until we are outside of this frame.
+                    // In case anything in the resulting layout calls animation.
+                    // If it does, *this* frame will fire again... recursively
+                    Ext.GlobalEvents.on({
+                        idle: Ext.Function.bind(o.target.setSize, o.target, [w, h]),
+                        single: true
+                    });
+                }
+            }
+            if (methodsToCall.setOpacity) {
+                o = methodsToCall.setOpacity;
+                o.target.el.setStyle('opacity', o.opacity);
+            }
+        }
+    }
+});

+ 79 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/CompositeElement.js

@@ -0,0 +1,79 @@
+/**
+ * @class Ext.fx.target.CompositeElement
+ * 
+ * This class represents a animation target for a {@link Ext.CompositeElement}. It allows
+ * each {@link Ext.dom.Element} in the group to be animated as a whole. In general this class will not be
+ * created directly, the {@link Ext.CompositeElement} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+Ext.define('Ext.fx.target.CompositeElement', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Element',
+
+    /* End Definitions */
+
+    /**
+     * @property {Boolean} isComposite
+     * `true` in this class to identify an object as an instantiated CompositeElement, or subclass thereof.
+     */
+    isComposite: true,
+    
+    constructor: function(target) {
+        target.id = target.id || Ext.id(null, 'ext-composite-');
+        this.callParent([target]);
+    },
+
+    getAttr: function(attr, val) {
+        var out      = [],
+            target = this.target,
+            elements = target.elements,
+            length   = elements.length,
+            i,
+            el;
+
+        for (i = 0; i < length; i++) {
+            el = elements[i];
+
+            if (el) {
+                el = target.getElement(el);
+                out.push([el, this.getElVal(el, attr, val)]);
+            }
+        }
+
+        return out;
+    },
+    
+    setAttr: function(targetData){
+        var target = this.target,
+            ln = targetData.length,
+            elements = target.elements,
+            ln3 = elements.length,
+            value, k,
+            attrs, attr, el, i, j, ln2;
+            
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i].attrs;
+            for (attr in attrs) {
+                if (attrs.hasOwnProperty(attr)) {
+                    ln2 = attrs[attr].length;
+                    for (j = 0; j < ln2; j++) {
+                        value = attrs[attr][j][1];
+                        for (k = 0; k < ln3; ++k) {
+                            el = elements[k];
+                            if (el) {
+                                el = target.getElement(el);
+                                this.setElVal(el, attr, value);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    },
+    
+    remove: function() {
+        this.target.destroy();
+    }
+});

+ 22 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/CompositeElementCSS.js

@@ -0,0 +1,22 @@
+/**
+ * @class Ext.fx.target.CompositeElementCSS
+ * 
+ * This class represents a animation target for a {@link Ext.CompositeElement}, where the
+ * constituent elements support CSS based animation. It allows each {@link Ext.dom.Element} in 
+ * the group to be animated as a whole. In general this class will not be created directly, 
+ * the {@link Ext.CompositeElement} will be passed to the animation and the appropriate target 
+ * will be created.
+ */
+Ext.define('Ext.fx.target.CompositeElementCSS', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.CompositeElement',
+
+    requires: ['Ext.fx.target.ElementCSS'],
+
+    /* End Definitions */
+    setAttr: function() {
+        return Ext.fx.target.ElementCSS.prototype.setAttr.apply(this, arguments);
+    }
+});

+ 31 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/CompositeSprite.js

@@ -0,0 +1,31 @@
+/**
+ * @class Ext.fx.target.CompositeSprite
+ *
+ * This class represents a animation target for a {@link Ext.draw.sprite.Composite}. It allows
+ * each {@link Ext.draw.sprite.Sprite} in the group to be animated as a whole. In general this class will not be
+ * created directly, the {@link Ext.draw.sprite.Composite} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+
+Ext.define('Ext.fx.target.CompositeSprite', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Sprite',
+
+    /* End Definitions */
+
+    getAttr: function(attr, val) {
+        var out     = [],
+            sprites = [].concat(this.target.items),
+            length  = sprites.length,
+            i, sprite;
+
+        for (i = 0; i < length; i++) {
+            sprite = sprites[i];
+            out.push([sprite, val !== undefined ? val : this.getFromPrim(sprite, attr)]);
+        }
+
+        return out;
+    }
+});

+ 94 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/Element.js

@@ -0,0 +1,94 @@
+/**
+ * @class Ext.fx.target.Element
+ * 
+ * This class represents a animation target for an {@link Ext.dom.Element}. In general this class will not be
+ * created directly, the {@link Ext.dom.Element} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+Ext.define('Ext.fx.target.Element', {
+
+    /* Begin Definitions */
+    
+    extend: 'Ext.fx.target.Target',
+    
+    /* End Definitions */
+
+    type: 'element',
+    
+    constructor: function(target) {
+        this.callParent([target]);
+
+        // Allow simple local left/top style setting for top level absolute positioned elements.
+        this.isAbsoluteOnPage = this.target.dom.parentNode === document.body && this.target.isStyle('position', 'absolute');
+    },
+
+    getElVal: function(el, attr, val) {
+        if (val === undefined) {
+            if (attr === 'x') {
+                val = el.getX();
+            } else if (attr === 'y') {
+                val = el.getY();
+            } else if (attr === 'scrollTop') {
+                val = el.getScroll().top;
+            } else if (attr === 'scrollLeft') {
+                val = el.getScroll().left;
+            } else if (attr === 'height') {
+                val = el.getHeight();
+            } else if (attr === 'width') {
+                val = el.getWidth();
+            } else {
+                val = el.getStyle(attr);
+            }
+        }
+        return val;
+    },
+
+    getAttr: function(attr, val) {
+        var el = this.target;
+        return [[ el, this.getElVal(el, attr, val)]];
+    },
+
+    setAttr: function(targetData) {
+        var ln = targetData.length,
+            attrs, attr, o, i, j, ln2;
+            
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i].attrs;
+            for (attr in attrs) {
+                if (attrs.hasOwnProperty(attr)) {
+                    ln2 = attrs[attr].length;
+                    for (j = 0; j < ln2; j++) {
+                        o = attrs[attr][j];
+                        this.setElVal(o[0], attr, o[1]);
+                    }
+                }
+            }
+        }
+    },
+    
+    setElVal: function(element, attr, value){
+        if (attr === 'x') {
+            if (this.isAbsoluteOnPage) {
+                element.setLocalX(value);
+            } else {
+                element.setXY([value, null]);
+            }
+        } else if (attr === 'y') {
+            if (this.isAbsoluteOnPage) {
+                element.setLocalY(value);
+            } else {
+                element.setXY([null, value]);
+            }
+        } else if (attr === 'scrollTop') {
+            element.scrollTo('top', value);
+        } else if (attr === 'scrollLeft') {
+            element.scrollTo('left',value);
+        } else if (attr === 'width') {
+            element.setWidth(value);
+        } else if (attr === 'height') {
+            element.setHeight(value);
+        } else {
+            element.setStyle(attr, value);
+        }
+    }
+});

+ 74 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/ElementCSS.js

@@ -0,0 +1,74 @@
+/**
+ * @class Ext.fx.target.ElementCSS
+ * 
+ * This class represents a animation target for an {@link Ext.dom.Element} that supports CSS
+ * based animation. In general this class will not be created directly, the {@link Ext.dom.Element} 
+ * will be passed to the animation and the appropriate target will be created.
+ */
+Ext.define('Ext.fx.target.ElementCSS', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Element',
+
+    /* End Definitions */
+
+    setAttr: function(targetData, isFirstFrame) {
+        var cssArr = {
+                attrs: [],
+                duration: [],
+                easing: []
+            },
+            ln = targetData.length,
+            cleanerFn = function() {
+                this.setStyle(Ext.supports.CSS3Prefix + 'TransitionProperty', null);
+                this.setStyle(Ext.supports.CSS3Prefix + 'TransitionDuration', null);
+                this.setStyle(Ext.supports.CSS3Prefix + 'TransitionTimingFunction', null);
+            },
+            single = { single: true },
+            attributes, attrs, attr, easing, duration, o, i, j, ln2;
+
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i];
+            duration = attrs.duration;
+            easing = attrs.easing;
+            attrs = attrs.attrs;
+            for (attr in attrs) {
+                if (Ext.Array.indexOf(cssArr.attrs, attr) == -1) {
+                    cssArr.attrs.push(attr.replace(/[A-Z]/g, function(v) {
+                        return '-' + v.toLowerCase();
+                    }));
+                    cssArr.duration.push(duration + 'ms');
+                    cssArr.easing.push(easing);
+                }
+            }
+        }
+
+        attributes = cssArr.attrs.join(',');
+        duration = cssArr.duration.join(',');
+        easing = cssArr.easing.join(', ');
+
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i].attrs;
+            for (attr in attrs) {
+                ln2 = attrs[attr].length;
+                for (j = 0; j < ln2; j++) {
+                    o = attrs[attr][j];
+                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionProperty', isFirstFrame ? '' : attributes);
+                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionDuration', isFirstFrame ? '' : duration);
+                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionTimingFunction', isFirstFrame ? '' : easing);
+                    o[0].setStyle(attr, o[1]);
+
+                    // Must trigger reflow to make this get used as the start point for the transition that follows
+                    if (isFirstFrame) {
+                        o = o[0].dom.offsetWidth;
+                    }
+                    else {
+                        // Remove transition properties when completed.
+                        o[0].on(Ext.supports.CSS3TransitionEnd, cleanerFn, o[0], single);
+                    }
+                }
+            }
+        }
+    }
+});

+ 125 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/Sprite.js

@@ -0,0 +1,125 @@
+/**
+ * @class Ext.fx.target.Sprite
+ * This class represents an animation target for a {@link Ext.draw.sprite.Sprite}. In general this class will not be
+ * created directly, the {@link Ext.draw.sprite.Sprite} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+
+Ext.define('Ext.fx.target.Sprite', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Target',
+
+    /* End Definitions */
+
+    type: 'draw',
+
+    getFromPrim: function (sprite, attr) {
+        var obj;
+        switch (attr) {
+            case 'rotate':
+            case 'rotation':
+                obj = sprite.attr.rotation;
+                return {
+                    x: obj.x || 0,
+                    y: obj.y || 0,
+                    degrees: obj.degrees || 0
+                };
+            case 'scale':
+            case 'scaling':
+                obj = sprite.attr.scaling;
+                return {
+                    x: obj.x || 1,
+                    y: obj.y || 1,
+                    cx: obj.cx || 0,
+                    cy: obj.cy || 0
+                };
+            case 'translate':
+            case 'translation':
+                obj = sprite.attr.translation;
+                return {
+                    x: obj.x || 0,
+                    y: obj.y || 0
+                };
+            default:
+                return sprite.attr[attr];
+        }
+    },
+
+    getAttr: function (attr, val) {
+        return [
+            [this.target, val !== undefined ? val : this.getFromPrim(this.target, attr)]
+        ];
+    },
+
+    setAttr: function (targetData) {
+        var ln = targetData.length,
+            spriteArr = [],
+            attrsConf, attr, attrArr, attrs, sprite, idx, value, i, j, x, y, ln2;
+        for (i = 0; i < ln; i++) {
+            attrsConf = targetData[i].attrs;
+            for (attr in attrsConf) {
+                attrArr = attrsConf[attr];
+                ln2 = attrArr.length;
+                for (j = 0; j < ln2; j++) {
+                    sprite = attrArr[j][0];
+                    attrs = attrArr[j][1];
+                    if (attr === 'translate' || attr === 'translation') {
+                        value = {
+                            x: attrs.x,
+                            y: attrs.y
+                        };
+                    }
+                    else if (attr === 'rotate' || attr === 'rotation') {
+                        x = attrs.x;
+                        if (isNaN(x)) {
+                            x = null;
+                        }
+                        y = attrs.y;
+                        if (isNaN(y)) {
+                            y = null;
+                        }
+                        value = {
+                            degrees: attrs.degrees,
+                            x: x,
+                            y: y
+                        };
+                    } else if (attr === 'scale' || attr === 'scaling') {
+                        x = attrs.x;
+                        if (isNaN(x)) {
+                            x = null;
+                        }
+                        y = attrs.y;
+                        if (isNaN(y)) {
+                            y = null;
+                        }
+                        value = {
+                            x: x,
+                            y: y,
+                            cx: attrs.cx,
+                            cy: attrs.cy
+                        };
+                    }
+                    else if (attr === 'width' || attr === 'height' || attr === 'x' || attr === 'y') {
+                        value = parseFloat(attrs);
+                    }
+                    else {
+                        value = attrs;
+                    }
+                    idx = Ext.Array.indexOf(spriteArr, sprite);
+                    if (idx === -1) {
+                        spriteArr.push([sprite, {}]);
+                        idx = spriteArr.length - 1;
+                    }
+                    spriteArr[idx][1][attr] = value;
+                }
+            }
+        }
+        ln = spriteArr.length;
+        for (i = 0; i < ln; i++) {
+            spriteArr[i][0].setAttributes(spriteArr[i][1]);
+        }
+        this.target.redraw();
+    }
+});

+ 39 - 0
frontend/saas-web/ext/classic/classic/src/fx/target/Target.js

@@ -0,0 +1,39 @@
+/**
+ * @class Ext.fx.target.Target
+
+This class specifies a generic target for an animation. It provides a wrapper around a
+series of different types of objects to allow for a generic animation API.
+A target can be a single object or a Composite object containing other objects that are 
+to be animated. This class and it's subclasses are generally not created directly, the 
+underlying animation will create the appropriate Ext.fx.target.Target object by passing 
+the instance to be animated.
+
+The following types of objects can be animated:
+
+- {@link Ext.fx.target.Component Components}
+- {@link Ext.fx.target.Element Elements}
+- {@link Ext.fx.target.Sprite Sprites}
+
+ * @abstract
+ */
+Ext.define('Ext.fx.target.Target', {
+
+    isAnimTarget: true,
+
+    /**
+     * Creates new Target.
+     * @param {Ext.Component/Ext.dom.Element/Ext.draw.sprite.Sprite} target The object to be animated
+     */
+    constructor: function(target) {
+        this.target = target;
+        this.id = this.getId();
+    },
+    
+    getId: function() {
+        return this.target.id;
+    },
+    
+    remove: function() {
+        Ext.destroy(this.target);
+    }
+});

+ 10 - 0
pom.xml

@@ -227,6 +227,16 @@
                 <artifactId>auth-client</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.usoftchina.saas</groupId>
+                <artifactId>purchase-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.saas</groupId>
+                <artifactId>purchase-dto</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <!-- file upload -->
             <dependency>
                 <groupId>io.github.openfeign.form</groupId>