Browse Source

Merge branch 'dev' of ssh://10.10.100.21/source/smartschool-platform into dev

FANGLH 7 years ago
parent
commit
038856b50a
98 changed files with 2112 additions and 859 deletions
  1. 18 1
      applications/device/device-client/pom.xml
  2. 4 6
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/DeviceClientApplication.java
  3. 91 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/RestTemplateConfig.java
  4. 1 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/WebMvcConfig.java
  5. 6 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/AccessControlController.java
  6. 44 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/IcCardController.java
  7. 41 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/SchoolController.java
  8. 24 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/School.java
  9. 5 3
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/SchoolRepository.java
  10. 18 11
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/AccessControlService.java
  11. 71 4
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/IcCardService.java
  12. 8 2
      applications/device/device-client/src/main/resources/application.yml
  13. 3 1
      applications/device/device-client/src/main/resources/schema.sql
  14. 10 6
      applications/device/device-client/src/main/resources/static/css/iconfont.css
  15. BIN
      applications/device/device-client/src/main/resources/static/css/iconfont.eot
  16. 3 0
      applications/device/device-client/src/main/resources/static/css/iconfont.svg
  17. BIN
      applications/device/device-client/src/main/resources/static/css/iconfont.ttf
  18. BIN
      applications/device/device-client/src/main/resources/static/css/iconfont.woff
  19. 47 0
      applications/device/device-client/src/main/resources/static/iccard.html
  20. 3 0
      applications/device/device-client/src/main/resources/static/index.html
  21. 47 0
      applications/device/device-client/src/main/resources/static/js/iccard.js
  22. 18 0
      applications/device/device-client/src/main/resources/static/js/index.js
  23. 44 0
      applications/device/device-client/src/main/resources/static/js/school.js
  24. 33 0
      applications/device/device-client/src/main/resources/static/school.html
  25. 40 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/Hex.java
  26. 96 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacEncoder.java
  27. 9 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacSHA256Encoder.java
  28. 13 0
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/config/DahuaProperties.java
  29. 40 2
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/lib/DahuaSdk.java
  30. 1 0
      applications/device/device-sdk-dahua/src/main/resources/linux-amd64/manifest.txt
  31. 1 0
      applications/device/device-sdk-dahua/src/main/resources/win32-x86-64/manifest.txt
  32. 132 0
      applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/dto/AccTransDetail.java
  33. 11 5
      applications/device/device-server/pom.xml
  34. 0 2
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/DeviceApplication.java
  35. 91 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/config/RestTemplateConfig.java
  36. 66 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/AccessControlController.java
  37. 0 44
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/DeviceController.java
  38. 35 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/IcCardController.java
  39. 0 139
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/listener/AccessControlListener.java
  40. 27 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/AccessControlRecordMapper.java
  41. 0 32
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/DeviceMapper.java
  42. 18 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/IcCardMapper.java
  43. 15 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/StudentInfoMapper.java
  44. 1 1
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/AccessControlRecord.java
  45. 0 81
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Device.java
  46. 1 1
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/StudentInfo.java
  47. 49 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Transaction.java
  48. 32 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/AccessControlService.java
  49. 0 16
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/DeviceService.java
  50. 11 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/IcCardService.java
  51. 128 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/AccessControlServiceImpl.java
  52. 0 79
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/DeviceServiceImpl.java
  53. 123 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/IcCardServiceImpl.java
  54. 3 4
      applications/device/device-server/src/main/resources/application.yml
  55. 109 0
      applications/device/device-server/src/main/resources/mapper/AccessControlRecordMapper.xml
  56. 0 237
      applications/device/device-server/src/main/resources/mapper/DeviceMapper.xml
  57. 20 0
      applications/device/device-server/src/main/resources/mapper/IcCardMapper.xml
  58. 25 0
      applications/device/device-server/src/main/resources/mapper/StudentInfoMapper.xml
  59. 49 0
      applications/device/device-server/src/test/java/com/usoftchina/smartschool/device/test/TestService.java
  60. 5 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/ClassServiceImpl.java
  61. 40 7
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/CurriculumServiceImpl.java
  62. 16 6
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/GradeServiceImpl.java
  63. 3 3
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  64. 1 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/CurriculumMapper.java
  65. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/HomeWorkMapper.java
  66. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysClazzMapper.java
  67. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysStudentMapper.java
  68. 0 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysTeacherMapper.java
  69. 5 0
      applications/school/school-server/src/main/resources/mapper/CurriculumMapper.xml
  70. 5 0
      applications/school/school-server/src/main/resources/mapper/HomeWorkMapper.xml
  71. 12 0
      applications/school/school-server/src/main/resources/mapper/SysClazzMapper.xml
  72. 4 9
      applications/school/school-server/src/main/resources/mapper/SysStudentMapper.xml
  73. 1 1
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/ReceiveService.java
  74. 1 1
      applications/wechat/wechat-server/src/main/resources/config/application-docker-cloud.yml
  75. 24 5
      applications/wechat/wechat-server/src/main/resources/config/application-docker-test.yml
  76. 30 0
      applications/wechat/wechat-server/src/test/java/com/usoftchina/smartschool/wechat/Test_service.java
  77. 2 2
      frontend/pc-web/app/util/BaseUtil.js
  78. 20 15
      frontend/pc-web/app/view/Interaction/homework/List.js
  79. 20 15
      frontend/pc-web/app/view/Interaction/notice/List.js
  80. 52 22
      frontend/pc-web/app/view/Interaction/score/List.js
  81. 35 10
      frontend/pc-web/app/view/Interaction/timetable/Detail.js
  82. 30 0
      frontend/pc-web/app/view/Interaction/timetable/DetailModel.js
  83. 54 18
      frontend/pc-web/app/view/Interaction/timetable/List.js
  84. 1 1
      frontend/pc-web/app/view/auth/Login.js
  85. 2 1
      frontend/pc-web/app/view/basic/class/ClassDetail.js
  86. 20 15
      frontend/pc-web/app/view/basic/staff/StaffList.js
  87. 20 15
      frontend/pc-web/app/view/basic/student/StudentList.js
  88. 0 16
      frontend/pc-web/app/view/core/form/FormPanel.js
  89. 6 6
      frontend/pc-web/app/view/core/form/FormPanelController.js
  90. 1 1
      frontend/pc-web/app/view/main/Main.js
  91. 8 8
      frontend/pc-web/app/view/main/Main.scss
  92. 2 2
      frontend/pc-web/app/view/main/MainController.js
  93. 1 1
      frontend/pc-web/index.html
  94. BIN
      frontend/pc-web/resources/images/auth-background.jpg
  95. BIN
      frontend/pc-web/resources/images/default/logo-default.png
  96. BIN
      frontend/pc-web/resources/images/favicon.png
  97. BIN
      frontend/pc-web/resources/images/login-text-img.png
  98. BIN
      frontend/pc-web/resources/images/zhihuixiaoyuan.png

+ 18 - 1
applications/device/device-client/pom.xml

@@ -37,6 +37,23 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-jdbc</artifactId>
         </dependency>
+        <!-- JSON -->
+        <dependency>
+          <groupId>com.alibaba</groupId>
+          <artifactId>fastjson</artifactId>
+        </dependency>
+        <!-- httpClient -->
+        <dependency>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient</artifactId>
+        </dependency>
     </dependencies>
-
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
 </project>

+ 4 - 6
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/DeviceClientApplication.java

@@ -4,9 +4,10 @@ import com.usoftchina.smartschool.device.client.config.DeviceServerProperties;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
 import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 import org.springframework.web.client.RestTemplate;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * @author yingp
@@ -14,14 +15,11 @@ import org.springframework.web.client.RestTemplate;
  */
 @SpringBootApplication
 @EnableAsync
+@EnableTransactionManagement
 @EnableConfigurationProperties(DeviceServerProperties.class)
+@EnableScheduling
 public class DeviceClientApplication {
     public static void main(String[] args) {
         SpringApplication.run(DeviceClientApplication.class, args);
     }
-
-    @Bean
-    public RestTemplate restTemplate() {
-        return new RestTemplate();
-    }
 }

+ 91 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/RestTemplateConfig.java

@@ -0,0 +1,91 @@
+package com.usoftchina.smartschool.device.client.config;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * @Author chenwei
+ * @Date 2019/03/07
+ */
+@Configuration
+public class RestTemplateConfig {
+
+    private static final Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);
+
+    @Bean
+    public RestTemplate restTemplate(){
+        RestTemplate restTemplate = new RestTemplate();
+        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
+        converterList.add(0, responseBodyConverter());
+        restTemplate.setRequestFactory(httpRequestFactory());
+        return restTemplate;
+    }
+
+    @Bean
+    public HttpMessageConverter<String> responseBodyConverter() {
+        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        return converter;
+    }
+
+    @Bean
+    public HttpComponentsClientHttpRequestFactory httpRequestFactory(){
+        try {
+            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
+            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                    return true;
+                }
+            }).build();
+            httpClientBuilder.setSSLContext(sslContext);
+            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
+            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
+            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                    .register("https", sslConnectionSocketFactory).build();// 注册http和https请求
+            // 开始设置连接池
+            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+            poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500
+            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100
+            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
+            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
+            HttpClient httpClient = httpClientBuilder.build();
+            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
+            clientHttpRequestFactory.setConnectTimeout(20000);              // 连接超时
+            clientHttpRequestFactory.setReadTimeout(30000);                 // 数据读取超时时间
+            clientHttpRequestFactory.setConnectionRequestTimeout(20000);    // 连接不够用的等待时间
+            return clientHttpRequestFactory;
+        }catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e){
+            logger.info("初始化HTTP连接池出错, message={}", e);
+        }
+        return null;
+    }
+
+}

+ 1 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/WebMvcConfig.java

@@ -17,5 +17,6 @@ public class WebMvcConfig implements WebMvcConfigurer {
         registry.addViewController("/").setViewName("index.html");
         registry.addViewController("/login").setViewName("/login.html");
         registry.addViewController("/iccard").setViewName("/iccard.html");
+        registry.addViewController("/school").setViewName("/school.html");
     }
 }

+ 6 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/AccessControlController.java

@@ -40,4 +40,10 @@ public class AccessControlController {
         accessControlService.save(accessControl);
         return Result.success();
     }
+
+    @DeleteMapping("/{id}")
+    public Result delete(@PathVariable("id") String id) {
+        accessControlService.delete(id);
+        return Result.success();
+    }
 }

+ 44 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/IcCardController.java

@@ -0,0 +1,44 @@
+package com.usoftchina.smartschool.device.client.controller;
+
+import com.usoftchina.smartschool.device.base.Result;
+import com.usoftchina.smartschool.device.client.po.IcCard;
+import com.usoftchina.smartschool.device.client.service.IcCardService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author yingp
+ * @date 2019/3/11
+ */
+@RestController
+@RequestMapping("/api/iccard")
+public class IcCardController {
+
+    @Autowired
+    private IcCardService icCardService;
+
+    /**
+     * 查询消费卡配置
+     *
+     * @return
+     */
+    @GetMapping
+    public Result<IcCard> find() {
+        return Result.success(icCardService.find());
+    }
+
+    /**
+     * 保存消费卡配置
+     *
+     * @param icCard
+     * @return
+     */
+    @PostMapping
+    public Result save(IcCard icCard) {
+        icCardService.save(icCard);
+        return Result.success();
+    }
+}

+ 41 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/controller/SchoolController.java

@@ -0,0 +1,41 @@
+package com.usoftchina.smartschool.device.client.controller;
+
+import com.usoftchina.smartschool.device.base.Result;
+import com.usoftchina.smartschool.device.client.po.School;
+import com.usoftchina.smartschool.device.client.service.SchoolService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author yingp
+ * @date 2019/3/11
+ */
+@RestController
+@RequestMapping("/api/school")
+public class SchoolController {
+
+    @Autowired
+    private SchoolService schoolService;
+
+    /**
+     * 查询学校信息
+     *
+     * @return
+     */
+    @GetMapping
+    public Result<School> find() {
+        return Result.success(schoolService.find());
+    }
+
+    /**
+     * 保存学校信息
+     *
+     * @param school
+     * @return
+     */
+    @PostMapping
+    public Result save(School school) {
+        schoolService.save(school);
+        return Result.success();
+    }
+}

+ 24 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/School.java

@@ -11,6 +11,14 @@ public class School implements Serializable {
      * 学校名称
      */
     private String name;
+    /**
+     * ID
+     */
+    private String id;
+    /**
+     * 私钥
+     */
+    private String secret;
 
     public String getName() {
         return name;
@@ -19,4 +27,20 @@ public class School implements Serializable {
     public void setName(String name) {
         this.name = name;
     }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
 }

+ 5 - 3
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/SchoolRepository.java

@@ -19,7 +19,7 @@ public class SchoolRepository{
 
     public School find() {
         try {
-            return jdbcTemplate.queryForObject("select * from iccard",
+            return jdbcTemplate.queryForObject("select * from school",
                     new BeanPropertyRowMapper<>(School.class));
         } catch (EmptyResultDataAccessException e) {
             return null;
@@ -27,10 +27,12 @@ public class SchoolRepository{
     }
 
     public void save(School school) {
-        jdbcTemplate.update("insert into school (name) values (?)", school.getName());
+        jdbcTemplate.update("insert into school (name,id,secret) values (?,?,?)", school.getName(),
+                school.getId(), school.getSecret());
     }
 
     public void update(School school) {
-        jdbcTemplate.update("update school set name=?", school.getName());
+        jdbcTemplate.update("update school set name=?,id=?,secret=?",
+                school.getName(), school.getId(), school.getSecret());
     }
 }

+ 18 - 11
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/AccessControlService.java

@@ -49,27 +49,34 @@ public class AccessControlService {
     public void save(AccessControl accessControl) {
         AccessControl oldOne = accessControlRepository.findByIpAndPort(accessControl.getIp(),
                 accessControl.getPort());
+        boolean isNew = StringUtils.isEmpty(accessControl.getId());
         if (null != oldOne) {
-            if (StringUtils.isEmpty(accessControl.getId())) {
+            if (isNew) {
                 accessControl.setId(oldOne.getId());
             } else if (!accessControl.getId().equals(oldOne.getId())) {
                 ExceptionCode.ERROR_IP_PORT_EXIST.occur();
             }
-            accessControlRepository.update(accessControl);
+        } else {
+            if (isNew) {
+                accessControl.setId(RandomUtils.randomString());
+            }
+        }
+
+        if (isNew) {
+            // 调用设备接口监听
+            deviceApi.add(accessControl);
+            accessControlRepository.save(accessControl);
+        } else {
+            oldOne = accessControlRepository.findById(accessControl.getId());
             if (!oldOne.getIp().equals(accessControl.getIp()) || oldOne.getPort() != accessControl.getPort() ||
                     !oldOne.getUsername().equals(accessControl.getUsername()) ||
-                            !oldOne.getPassword().equals(accessControl.getPassword())) {
-                // 先调用设备接口停止监听
-                deviceApi.remove(accessControl);
+                    !oldOne.getPassword().equals(accessControl.getPassword())) {
                 // 调用设备接口监听
                 deviceApi.add(accessControl);
+                // 调用设备接口停止监听
+                deviceApi.remove(oldOne);
             }
-
-        } else {
-            accessControl.setId(RandomUtils.randomString());
-            accessControlRepository.save(accessControl);
-            // 调用设备接口监听
-            deviceApi.add(accessControl);
+            accessControlRepository.update(accessControl);
         }
     }
 

+ 71 - 4
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/IcCardService.java

@@ -1,13 +1,27 @@
 package com.usoftchina.smartschool.device.client.service;
 
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.smartschool.device.base.Result;
 import com.usoftchina.smartschool.device.client.jdbc.DynamicDataSourceContextHolder;
 import com.usoftchina.smartschool.device.client.jdbc.DynamicDataSourceRegister;
-import com.usoftchina.smartschool.device.client.po.IcCard;
+import com.usoftchina.smartschool.device.client.po.*;
 import com.usoftchina.smartschool.device.client.repository.IcCardRepository;
+import com.usoftchina.smartschool.device.dto.AccTransDetail;
+import com.usoftchina.smartschool.device.exception.ExceptionCode;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
 
 /**
  * @author yingp
@@ -19,9 +33,32 @@ public class IcCardService {
     @Autowired
     private IcCardRepository icCardRepository;
 
+    @Autowired
+    private SchoolService schoolService;
+
     @Autowired
     private DynamicDataSourceRegister dynamicDataSourceRegister;
 
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Value("${device.icCard.icCardUrl}")
+    private String targetURL;
+
+    //SQL语句
+    private static final String insertSql = "INSERT INTO XF_AccTransDetail_push(GUID,AccNo,AccTransDay,AccTransType,IMoneyValue,OMoneyValue,CardUseNum,CardMoneyValue,DevID,DevOwner,OprtNo,Remark,XFDataSysID,XFPosMoneyByCredit,SendStatus,CreateTime) "
+            + " SELECT SOURCE.GUID,SOURCE.AccNo,SOURCE.AccTransDay,SOURCE.AccTransType,SOURCE.IMoneyValue,SOURCE.OMoneyValue,SOURCE.CardUseNum,SOURCE.CardMoneyValue,SOURCE.DevID,SOURCE.DevOwner,SOURCE.OprtNo,SOURCE.Remark,SOURCE.XFDataSysID,SOURCE.XFPosMoneyByCredit,'待上传',GETDATE() "
+            + " FROM XF_AccTransDetail SOURCE WHERE NOT EXISTS (SELECT 1 FROM XF_AccTransDetail_push TARGET WHERE SOURCE.GUID = TARGET.GUID)";
+
+    private static final String getDataSql = "select top 100 XF_AccTransDetail_push.GUID,RS_EMP.EmpSysID,RS_EMP.EmpNo,RS_EMP.EmpName,XF_AccHead.AccNo, XF_AccTransDetail_push.AccTransType,XF_AccTransDetail_push.AccTransDay,XF_AccTransDetail_push.IMoneyValue,XF_AccTransDetail_push.OMoneyValue,XF_AccTransDetail_push.CardMoneyValue "
+            + "from XF_AccTransDetail_push left join XF_AccHead on XF_AccTransDetail_push.AccNo=XF_AccHead.AccNo left join Tx_EmpCard on Tx_EmpCard.CardID=XF_AccHead.CardID "
+            + "left join RS_EMP ON RS_EMP.EmpSysID=XF_AccHead.EmpSysID where XF_AccTransDetail_push.SendStatus=? order by AccTransDay desc";
+
+    private static final String updateSql = "update XF_AccTransDetail_push set SendStatus = ? where GUID in (?)";
+
     public IcCard find() {
         return icCardRepository.find();
     }
@@ -38,16 +75,46 @@ public class IcCardService {
         dynamicDataSourceRegister.createDataSource(card);
     }
 
-    @Scheduled(cron = "", initialDelay = 5000)
+    @Scheduled(fixedRate = 1000 * 60, initialDelay = 5000)
     public void dataTask() {
         IcCard card = find();
-        if (null != card && dynamicDataSourceRegister.contains(card)) {
+        School school = schoolService.find();
+        if (null != card && dynamicDataSourceRegister.contains(card) && null != school) {
             DynamicDataSourceContextHolder.set(card);
             try {
-                // TODO
+                doTask();
             } finally {
                 DynamicDataSourceContextHolder.clear();
             }
         }
     }
+
+    private void doTask(){
+        //1.准备本次需要传输的数据->转移至中间表
+        jdbcTemplate.execute(insertSql);
+        //2.获取本次传输的数据
+        List<AccTransDetail> resultList = jdbcTemplate.query(getDataSql, new BeanPropertyRowMapper<>(AccTransDetail.class), "待上传");
+        //3.传输
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
+        requestEntity.add("data", JSON.toJSONString(resultList));
+        requestEntity.add("school", schoolService.find().getName());
+        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(requestEntity, headers);
+        ResponseEntity<Result> response = restTemplate.postForEntity(targetURL, resultList, Result.class);
+        if (response.getStatusCode() == HttpStatus.OK) {
+            Result<String> result = response.getBody();
+            if (!result.isSuccess()) {
+                ExceptionCode.ERROR_UNKNOWN.occur(result.getMessage());
+            }else {
+                //更新发送的数据
+                String ids = result.getData();
+                if (!StringUtils.isEmpty(ids)){
+                    jdbcTemplate.update(updateSql, "已上传", ids);
+                }
+            }
+        } else {
+            ExceptionCode.ERROR_UNKNOWN.occur("IC卡消费记录发送失败");
+        }
+    }
 }

+ 8 - 2
applications/device/device-client/src/main/resources/application.yml

@@ -4,7 +4,10 @@ device:
     connect-time: 10000
   server:
   # 门禁事件的服务端接口
-    accessControlEvent: https://school-api.ydyhz.com/device/accesscontrol/event
+    accessControlEvent: https://school-api.ydyhz.com/api/device/accesscontrol/event
+  # IC卡传输的服务端接口
+  icCard:
+    icCardUrl: https://school-api.ydyhz.com/api/device/iccard/consume/record
 server:
   tomcat:
     uri-encoding: UTF-8
@@ -25,4 +28,7 @@ spring:
       maximum-pool-size: 50
       idle-timeout: 30000
       max-lifetime: 1800000
-      connection-timeout: 30000
+      connection-timeout: 30000
+logging:
+  level:
+    com.usoftchina.smartschool.device.client: debug

+ 3 - 1
applications/device/device-client/src/main/resources/schema.sql

@@ -10,7 +10,9 @@ password varchar(50) not null
 
 create table if not exists school
 (
-name varchar(500) primary key not null
+name varchar(500) not null,
+id varchar(32) not null,
+secret varchar(100) not null
 );
 
 create table if not exists iccard

+ 10 - 6
applications/device/device-client/src/main/resources/static/css/iconfont.css

@@ -1,10 +1,10 @@
 @font-face {font-family: "iconfont";
-  src: url('iconfont.eot?t=1552350156920'); /* IE9 */
-  src: url('iconfont.eot?t=1552350156920#iefix') format('embedded-opentype'), /* IE6-IE8 */
-  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMIAAsAAAAAByQAAAK8AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAqCMIF+ATYCJAMICwYABCAFhG0HLhsiBhEVlA9kHwm5Kc2foji2NKFqzMQD31z5J5m9pgAMsqz2VAnIAQuLYMuy8t7e/1o7EYsT0jn6+m1H4+r8FZ8/aKdTKskqoR4hEgoeGgZcjv8r8XlAOa05aG0MMN4a0N4YRVYgCcTWhzjslXmfgDIaaCcMGzFumkxkLQsI61avXCzL+UVRSGWCopq9UdgvJ0t2JFvsCz8f/ugSMhK5lJU3acXwZQb9qGkvyOcLefPSYvn5rBAOkaIdImFarX2CNI63kyqjxaMm7Cs78KPmf8E3Cnv984QiVmY5UA/59yRwhbeamYCIw/OxetRPSqxXr3K1Ladfduvcf92geO5Nz7YKl6/XKpy40bx77VYolo31Zy469qSmfay4xujozmrW4dvVTjZVf8i3ii9+2Ozk8tW656fu1bRv7RrwV7/0tvMt7rdlL+G4eot6k57El/R1UAvotLrsKmnNx5f/029unfuv+fewktYl0fk3JvefjGuWH/p17Nctc0v+9LhtvdNxSsubKU/w4Lzfkw0ChXzMpsU/+ztar5/TSq3Y739WNoKPd+ptQ2E/J9ktOQK/tiaiUIhBFFmq5CL55EjMz3glIFd0KbDcVXwfq67+HukgU/1tnKXUT5HKNCMirR1yyuqGIhnSQJTRlnK4rKpIXoil0cYdIKjkEYkKXiBVyRsRae/IqeEbRSqFPMqYEaqeWVaL4NaGEuqMFhg34JpxJBwT16LsI7QvAp2yopB+hiTdECym82JKwQhpjg3y0l4yCxAUh7CBxzAIYkgo9tDkqcOcHM5mou5FUzMOMzVDEaRjyAIMN4DLFIsIvz2rld5/BNkuBHTU0lTjPIOI5I4OFqbmPQhFHvVqupdnpEu2JcYEIJBYCGzAigI7HgNJ/SwPMrEpZ0Q0cWhGrURf+XR9Zfh1O6AMS5MEuzgVl1suZzI=') format('woff2'),
-  url('iconfont.woff?t=1552350156920') format('woff'),
-  url('iconfont.ttf?t=1552350156920') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
-  url('iconfont.svg?t=1552350156920#iconfont') format('svg'); /* iOS 4.1- */
+  src: url('iconfont.eot?t=1552353178223'); /* IE9 */
+  src: url('iconfont.eot?t=1552353178223#iefix') format('embedded-opentype'), /* IE6-IE8 */
+  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOMAAsAAAAACEAAAAM/AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqEKIM+ATYCJAMMCwgABCAFhG0HNxsFBxHVm3PIfiTGtmjyzpmhr6KJ9maCB6rzfbMzSfcbqOSkpG/2iTr+JgBMmnPARkVNluQsevQP99BympHPczluPQ9sfstymmPZsrJF8QEFtDceRVYgAXnD2JUX8RwCsMafWERpeW0rdBTGOgGIQf37dkdPmVE1tQIdgbHkqEIswYCuzdVuAYv974svJAsdNAwS46XGPmW9KHx/94OHNFlMdJJmTOM5AXYKJBALKBBdSt3tkGE6Fom1olb1pUYUAm2smMWCL1a1xpX+8TQQRoxqWwAioVHjpCQ2HwI+eIighvM/BUZAB04ANyDDlaRC+QbZ2fn6OrkOtj/1wN9g3j9/L8q018Zh/n6Ratxwr6v1PPf8VdYu0zV3RcM+834bm4LVpx3H/Kg8u3avaU+/eftEv749NonU+A33Uh1H3bX5YYYD9jv2eKq1e8Ocdo88qo0qv7Lb6vMefVeb3d1XzXPtteKAa6uxbntNkeHtZ0Jb7djl03b9YY++++dbCkyt9UJ7J18ne9dtj70vSs3UW7f5/8527c219vPtkNn2XdGch8Fv8lzmR14Ifpi0NE1tr/bFXQ8SM8n/6Wc1e0v4ktn6MX+ab5Jv43l1TJ4vDAdE3UamjCzf8vnlv9b7JnT8FvattCmqKbh+b/M8z9pQWfKq5tX4jk1f0idEpSW0iBjf4jzc2elzc7oBYLkit8hCnDUpIc3/9Tf0WZW6satD7j/dRgHw7GDkOiht5wX9rj0C/mKTAiwWJbjMsEgli22x7pF0TgTRAAq5hn9XD+DMm/5at9bVINBxi6HRDD9IdEIpihELAzakwohOAayJoeK0DS6MQCKUFRDNTACBI4ehYc9lSBy5TVGM1zDgzjcYcRQS1rQRLlfaoO5F3B0ZSmBJ/ymarnWWTXZB7Q3+XStOynzWCzzGGOVJls1d0YLH2DF+fCHiyHHX0AW8hrruqOeuhJEkiPSHNHVlb0pM10x2HBlKYAn9J6LpWueOl13u8zf4d624pqMi+AKPcXIiJyFrQbmq21Yd10Jm/PgCEUc47hriApyozXRH9OWLShhJCD2S/YEU9XJt1cn82ub5EgBrjDul0IQUilUv1BAsYKNMJgA=') format('woff2'),
+  url('iconfont.woff?t=1552353178223') format('woff'),
+  url('iconfont.ttf?t=1552353178223') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+  url('iconfont.svg?t=1552353178223#iconfont') format('svg'); /* iOS 4.1- */
 }
 
 .iconfont {
@@ -15,6 +15,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-delete:before {
+  content: "\e6cf";
+}
+
 .icon-edit:before {
   content: "\e717";
 }

BIN
applications/device/device-client/src/main/resources/static/css/iconfont.eot


+ 3 - 0
applications/device/device-client/src/main/resources/static/css/iconfont.svg

@@ -20,6 +20,9 @@ Created by iconfont
   />
     <missing-glyph />
     
+    <glyph glyph-name="delete" unicode="&#59087;" d="M768-64H256c-52.8 0-96 43.2-96 96V608c0 17.6 14.4 32 32 32s32-14.4 32-32v-576c0-17.6 14.4-32 32-32h512c17.6 0 32 14.4 32 32V608c0 17.6 14.4 32 32 32s32-14.4 32-32v-576c0-52.8-43.2-96-96-96zM896 704H672c-8 0-16 3.2-22.4 9.6l-44.8 44.8c-6.4 6.4-14.4 9.6-24 9.6h-139.2c-8 0-16-3.2-22.4-9.6l-44.8-44.8c-6.4-6.4-14.4-9.6-22.4-9.6H128c-17.6 0-32 14.4-32 32s14.4 32 32 32h211.2l35.2 35.2C392 822.4 417.6 832 443.2 832h139.2c25.6 0 49.6-9.6 67.2-28.8L684.8 768H896c17.6 0 32-14.4 32-32s-14.4-32-32-32zM400 64c-17.6 0-32 14.4-32 32V608c0 17.6 14.4 32 32 32s32-14.4 32-32v-512c0-17.6-14.4-32-32-32zM624 64c-17.6 0-32 14.4-32 32V608c0 17.6 14.4 32 32 32s32-14.4 32-32v-512c0-17.6-14.4-32-32-32z"  horiz-adv-x="1024" />
+
+    
     <glyph glyph-name="edit" unicode="&#59159;" d="M1006.592-29.39392c0-54.311936-44.859392-98.60608-100.196352-98.60608H100.196352C45.207552-128 0-83.994624 0-29.710336V660.494336C0 714.807296 45.125632 758.784 100.79232 758.784h539.76576v-49.265664H100.79232c-27.92448 0-50.46272-21.972992-50.46272-49.024v-690.204672c0-26.954752 22.550528-49.024 49.866752-49.024h806.199296c27.416576 0 49.866752 22.116352 49.866752 49.340416v626.944H1006.592v-626.944z m0 0c0-54.311936-44.859392-98.60608-100.196352-98.60608H100.196352C45.207552-128 0-83.994624 0-29.710336V660.494336C0 714.807296 45.125632 758.784 100.79232 758.784h539.76576v-49.265664H100.79232c-27.92448 0-50.46272-21.972992-50.46272-49.024v-690.204672c0-26.954752 22.550528-49.024 49.866752-49.024h806.199296c27.416576 0 49.866752 22.116352 49.866752 49.340416v626.944H1006.592v-626.944zM516.465664 378.235904c19.206144 6.542336 50.36032 24.948736 64.864256 38.288384l378.635264 348.248064c19.523584 17.956864 19.503104 47.152128-0.088064 65.272832l-5.225472 4.83328c-20.186112 18.670592-52.790272 18.783232-72.92928 0.260096L503.044096 486.852608c-13.686784-12.589056-31.880192-40.728576-37.430272-57.837568l-24.835072-76.560384 75.685888 25.781248zM989.96224 868.345856l5.225472-4.83328c39.458816-36.49536 39.602176-95.865856-0.011264-132.3008L616.539136 382.96576c-19.570688-18.000896-56.854528-40.067072-82.895872-48.93696l-123.001856-41.897984c-26.315776-8.964096-40.638464 4.017152-32.60416 28.78464l39.502848 121.772032c7.969792 24.57088 30.553088 59.567104 50.295808 77.725696L846.512128 868.698112c39.836672 36.63872 103.842816 36.28032 143.449088-0.352256z"  horiz-adv-x="1024" />
 
     

BIN
applications/device/device-client/src/main/resources/static/css/iconfont.ttf


BIN
applications/device/device-client/src/main/resources/static/css/iconfont.woff


+ 47 - 0
applications/device/device-client/src/main/resources/static/iccard.html

@@ -24,4 +24,51 @@
         </ul>
     </div>
 </nav>
+<div class="container">
+    <div class="row justify-content-md-center">
+        <div class="col-lg-auto" style="width: 500px;padding: 20px">
+            <form id="form">
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="ipInput">IP</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="ipInput" name="ip" required
+                               placeholder="ip地址,例如192.168.1.100">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="portInput">端口</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="portInput" name="port" required
+                               placeholder="tcp端口,例如1433">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="usernameInput">账号</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="usernameInput" name="username"
+                               value="admin" required placeholder="数据库账号,例如sa">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="passwordInput">密码</label>
+                    <div class="col-sm-10">
+                        <input type="password" class="form-control" id="passwordInput" name="password"
+                               required placeholder="数据库密码">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="databaseNameInput">数据库</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="databaseNameInput" name="databaseName"
+                               required placeholder="数据库名称">
+                    </div>
+                </div>
+                <button type="button" class="btn btn-primary btn-save">保存</button>
+            </form>
+        </div>
+    </div>
+</div>
+<script src="/js/jquery.min.js"></script>
+<script src="/js/bootstrap.min.js"></script>
+<script src="/js/iccard.js"></script>
 </body>

+ 3 - 0
applications/device/device-client/src/main/resources/static/index.html

@@ -100,6 +100,9 @@
                     data-toggle="modal" data-target="#formModal">
                 <span class="iconfont icon-edit"></span>
             </button>
+            <button type="button" class="btn btn-link btn-delete" data-index="<%=i%>" title="删除">
+                <span class="iconfont icon-delete"></span>
+            </button>
         </td>
     </tr>
     <%}%>

+ 47 - 0
applications/device/device-client/src/main/resources/static/js/iccard.js

@@ -0,0 +1,47 @@
+$(document).ready(function () {
+    var app = {
+        methods: {
+            get: function () {
+                $.ajax({
+                    url: '/api/iccard',
+                    method: 'GET',
+                    success: function (content) {
+                        if (content.success) {
+                            var card = content.data;
+                            $('#ipInput').val(card.ip);
+                            $('#portInput').val(card.port);
+                            $('#usernameInput').val(card.username);
+                            $('#passwordInput').val(card.password);
+                            $('#databaseNameInput').val(card.databaseName);
+                        } else {
+                            alert(content.message);
+                        }
+                    }
+                });
+            },
+            save: function () {
+                $.ajax({
+                    url: '/api/iccard',
+                    method: 'POST',
+                    data: $('#form').serialize(),
+                    success: function (content) {
+                        if (content.success) {
+                            window.location.reload();
+                        } else {
+                            alert(content.message);
+                        }
+                    }
+                });
+            }
+        },
+        init: function () {
+            $('.btn-save').click(function(){
+                app.methods.save();
+            });
+
+            app.methods.get();
+        }
+    };
+
+    app.init();
+});

+ 18 - 0
applications/device/device-client/src/main/resources/static/js/index.js

@@ -22,6 +22,11 @@ $(document).ready(function () {
                                 $('#usernameInput').val(accessControl.username);
                                 $('#passwordInput').val(accessControl.password);
                             });
+                            $('.btn-delete').click(function(){
+                                var index = $(this).data('index'),
+                                    accessControl = app.data.accessControls[index];
+                                app.methods.remove(accessControl.id);
+                            });
                         } else {
                             alert(content.message);
                         }
@@ -41,6 +46,19 @@ $(document).ready(function () {
                         }
                     }
                 });
+            },
+            remove: function (id) {
+                $.ajax({
+                    url: '/api/accesscontrol/' + id,
+                    method: 'DELETE',
+                    success: function (content) {
+                        if (content.success) {
+                            window.location.reload();
+                        } else {
+                            alert(content.message);
+                        }
+                    }
+                });
             }
         },
         init: function () {

+ 44 - 0
applications/device/device-client/src/main/resources/static/js/school.js

@@ -0,0 +1,44 @@
+$(document).ready(function () {
+    var app = {
+        methods: {
+            get: function () {
+                $.ajax({
+                    url: '/api/school',
+                    method: 'GET',
+                    success: function (content) {
+                        if (content.success) {
+                            $('#nameInput').val(content.data.name);
+                            $('#idInput').val(content.data.id);
+                            $('#secretInput').val(content.data.secret);
+                        } else {
+                            alert(content.message);
+                        }
+                    }
+                });
+            },
+            save: function () {
+                $.ajax({
+                    url: '/api/school',
+                    method: 'POST',
+                    data: $('#form').serialize(),
+                    success: function (content) {
+                        if (content.success) {
+                            window.location.reload();
+                        } else {
+                            alert(content.message);
+                        }
+                    }
+                });
+            }
+        },
+        init: function () {
+            $('.btn-save').click(function(){
+                app.methods.save();
+            });
+
+            app.methods.get();
+        }
+    };
+
+    app.init();
+});

+ 33 - 0
applications/device/device-client/src/main/resources/static/school.html

@@ -24,4 +24,37 @@
         </ul>
     </div>
 </nav>
+<div class="container">
+    <div class="row justify-content-md-center">
+        <div class="col-lg-auto" style="width: 500px;padding: 20px">
+            <form id="form">
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="nameInput">名称</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="nameInput" name="name" required
+                               placeholder="学校名称">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="idInput">ID</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="idInput" name="id" required
+                               placeholder="学校唯一标志">
+                    </div>
+                </div>
+                <div class="form-group row">
+                    <label class="col-sm-2 col-form-label" for="secretInput">私钥</label>
+                    <div class="col-sm-10">
+                        <input type="text" class="form-control" id="secretInput" name="secret" required
+                               placeholder="学校数据传输私钥">
+                    </div>
+                </div>
+                <button type="button" class="btn btn-primary btn-save">保存</button>
+            </form>
+        </div>
+    </div>
+</div>
+<script src="/js/jquery.min.js"></script>
+<script src="/js/bootstrap.min.js"></script>
+<script src="/js/school.js"></script>
 </body>

+ 40 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/Hex.java

@@ -0,0 +1,40 @@
+package com.usoftchina.smartschool.device.crypto;
+
+public final class Hex {
+	private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+	public static char[] encode(byte[] bytes) {
+		int nBytes = bytes.length;
+		char[] result = new char[2 * nBytes];
+
+		int j = 0;
+		for (int i = 0; i < nBytes; ++i) {
+			result[(j++)] = HEX[((0xF0 & bytes[i]) >>> 4)];
+
+			result[(j++)] = HEX[(0xF & bytes[i])];
+		}
+
+		return result;
+	}
+
+	public static byte[] decode(CharSequence s) {
+		int nChars = s.length();
+
+		if (nChars % 2 != 0) {
+			throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");
+		}
+
+		byte[] result = new byte[nChars / 2];
+
+		for (int i = 0; i < nChars; i += 2) {
+			int msb = Character.digit(s.charAt(i), 16);
+			int lsb = Character.digit(s.charAt(i + 1), 16);
+
+			if ((msb < 0) || (lsb < 0)) {
+				throw new IllegalArgumentException("Non-hex character in input: " + s);
+			}
+			result[(i / 2)] = (byte) (msb << 4 | lsb);
+		}
+		return result;
+	}
+}

+ 96 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacEncoder.java

@@ -0,0 +1,96 @@
+package com.usoftchina.smartschool.device.crypto;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Hash-based message authentication code,利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出
+ * 
+ * @author yingp
+ *
+ */
+public class HmacEncoder {
+
+	private final String algorithm;
+
+	public HmacEncoder(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+	/**
+	 * 根据给定密钥生成算法创建密钥
+	 * @return 密钥
+	 * @throws RuntimeException
+	 *             当 {@link NoSuchAlgorithmException} 发生时
+	 */
+	public byte[] getKey() {
+		// 初始化KeyGenerator
+		KeyGenerator keyGenerator = null;
+		try {
+			keyGenerator = KeyGenerator.getInstance(algorithm);
+		} catch (NoSuchAlgorithmException e) {
+			throw new RuntimeException(e.getMessage());
+		}
+		// 产生密钥
+		SecretKey secretKey = keyGenerator.generateKey();
+		// 获得密钥
+		return secretKey.getEncoded();
+	}
+
+	/**
+	 * 转换密钥
+	 * 
+	 * @param key
+	 *            二进制密钥
+	 * @param algorithm
+	 *            密钥算法
+	 * @return 密钥
+	 */
+	private static Key toKey(byte[] key, String algorithm) {
+		// 生成密钥
+		return new SecretKeySpec(key, algorithm);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, Key key) {
+		Mac mac = null;
+		try {
+			mac = Mac.getInstance(algorithm);
+			mac.init(key);
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+			return new byte[0];
+		} catch (InvalidKeyException e) {
+			e.printStackTrace();
+			return new byte[0];
+		}
+		return mac.doFinal(data);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, byte[] key) {
+		return encode(data, toKey(key, algorithm));
+	}
+
+}

+ 9 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacSHA256Encoder.java

@@ -0,0 +1,9 @@
+package com.usoftchina.smartschool.device.crypto;
+
+public class HmacSHA256Encoder extends HmacEncoder {
+
+	public HmacSHA256Encoder() {
+		super("HmacSHA256");
+	}
+
+}

+ 13 - 0
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/config/DahuaProperties.java

@@ -20,6 +20,11 @@ public class DahuaProperties {
      */
     private int connectTime = 10000;
 
+    /**
+     * DLL资源路径
+     */
+    private String library;
+
     public int getWaitTime() {
         return waitTime;
     }
@@ -35,4 +40,12 @@ public class DahuaProperties {
     public void setConnectTime(int connectTime) {
         this.connectTime = connectTime;
     }
+
+    public String getLibrary() {
+        return library;
+    }
+
+    public void setLibrary(String library) {
+        this.library = library;
+    }
 }

+ 40 - 2
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/lib/DahuaSdk.java

@@ -11,9 +11,17 @@ import com.usoftchina.smartschool.device.event.DeviceDisconnectEvent;
 import com.usoftchina.smartschool.device.event.DeviceReconnectEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
+import org.springframework.util.StringUtils;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 
 /**
  * @author yingp
@@ -31,10 +39,40 @@ public class DahuaSdk {
      */
     private int tryTimes = 1;
 
+    /**
+     * 拷贝DLL资源到临时目录,解决fat jar无法加载DLL问题
+     *
+     * @return
+     */
+    private String createTempLibraries() {
+        try {
+            String tempDir = Files.createTempDirectory("dahua-lib-").toFile().getCanonicalPath();
+            String manifest = StreamUtils.copyToString(
+                    new ClassPathResource(Platform.RESOURCE_PREFIX + File.separator + "manifest.txt").getInputStream(),
+                    Charset.defaultCharset());
+            String[] names = manifest.split(",");
+            for (String name : names) {
+                if (StringUtils.hasText(name)) {
+                    Path tempLib = Paths.get(tempDir, name);
+                    Files.copy(new ClassPathResource(Platform.RESOURCE_PREFIX + File.separator + name).getInputStream(),
+                            tempLib);
+                }
+            }
+            return tempDir;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Platform.RESOURCE_PREFIX;
+    }
+
     public DahuaSdk(DahuaProperties properties) {
         this.properties = properties;
-        this.instance = Native.load(Platform.RESOURCE_PREFIX +
-                (Platform.isWindows() ? "/dhnetsdk" : "/libdhnetsdk"), DahuaLibrary.class);
+        String libDir = properties.getLibrary();
+        if (StringUtils.isEmpty(libDir)) {
+            libDir = createTempLibraries();
+        }
+        this.instance = Native.load(libDir + File.separator +
+                (Platform.isWindows() ? "dhnetsdk" : "libdhnetsdk"), DahuaLibrary.class);
     }
 
     public DahuaLibrary getInstance() {

+ 1 - 0
applications/device/device-sdk-dahua/src/main/resources/linux-amd64/manifest.txt

@@ -0,0 +1 @@
+libavnetsdk.so,libdhconfigsdk.so,libdhnetsdk.so,libInfra.so,libNetFramework.so,libStream.so,libStreamSvr.so

+ 1 - 0
applications/device/device-sdk-dahua/src/main/resources/win32-x86-64/manifest.txt

@@ -0,0 +1 @@
+aacdec.dll,adpcmdec.dll,amrdec.dll,armenc64.dll,avnetsdk.dll,dhconfigsdk.dll,dhconfigsdk.lib,dhnetsdk.dll,dhnetsdk.lib,dhplay.dll,fisheye.dll,g729dec.dll,g7221dec.dll,h26ldec.dll,h264dec.dll,hevcdec.dll,HWDec.dll,Infra.dll,IvsDrawer.dll,Json.dll,MCL_FPTZ.dll,mjpegdec.dll,mp2dec.dll,mp3dec.dll,mpeg4dec.dll,NetFramework.dll,postproc.dll,Stream.dll,StreamSvr.dll,svac_dec.dll,swscale.dll,VTHStack.dll

+ 132 - 0
applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/dto/AccTransDetail.java

@@ -0,0 +1,132 @@
+package com.usoftchina.smartschool.device.dto;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description 交易记录
+ * @Author chenwei
+ * @Date 2019/03/07
+ */
+public class AccTransDetail implements Serializable {
+    /**
+     * 交易ID
+     */
+    private String guid;
+    /**
+     * 用户ID
+     */
+    private String empSysID;
+    /**
+     * 学号
+     */
+    private String empNo;
+    /**
+     * 姓名
+     */
+    private String empName;
+    /**
+     * 账户
+     */
+    private String accNo;
+    /**
+     * 交易类型
+     */
+    private String accTransType;
+    /**
+     * 交易日期
+     */
+    private Date accTransDay;
+    /**
+     * 收入
+     */
+    private Double iMoneyValue;
+    /**
+     * 支出
+     */
+    private Double oMoneyValue;
+    /**
+     * 余额
+     */
+    private Double cardMoneyValue;
+
+    public String getGuid() {
+        return guid;
+    }
+
+    public void setGuid(String guid) {
+        this.guid = guid;
+    }
+
+    public String getEmpSysID() {
+        return empSysID;
+    }
+
+    public void setEmpSysID(String empSysID) {
+        this.empSysID = empSysID;
+    }
+
+    public String getEmpNo() {
+        return empNo;
+    }
+
+    public void setEmpNo(String empNo) {
+        this.empNo = empNo;
+    }
+
+    public String getEmpName() {
+        return empName;
+    }
+
+    public void setEmpName(String empName) {
+        this.empName = empName;
+    }
+
+    public String getAccNo() {
+        return accNo;
+    }
+
+    public void setAccNo(String accNo) {
+        this.accNo = accNo;
+    }
+
+    public String getAccTransType() {
+        return accTransType;
+    }
+
+    public void setAccTransType(String accTransType) {
+        this.accTransType = accTransType;
+    }
+
+    public Date getAccTransDay() {
+        return accTransDay;
+    }
+
+    public void setAccTransDay(Date accTransDay) {
+        this.accTransDay = accTransDay;
+    }
+
+    public Double getiMoneyValue() {
+        return iMoneyValue;
+    }
+
+    public void setiMoneyValue(Double iMoneyValue) {
+        this.iMoneyValue = iMoneyValue;
+    }
+
+    public Double getoMoneyValue() {
+        return oMoneyValue;
+    }
+
+    public void setoMoneyValue(Double oMoneyValue) {
+        this.oMoneyValue = oMoneyValue;
+    }
+
+    public Double getCardMoneyValue() {
+        return cardMoneyValue;
+    }
+
+    public void setCardMoneyValue(Double cardMoneyValue) {
+        this.cardMoneyValue = cardMoneyValue;
+    }
+}

+ 11 - 5
applications/device/device-server/pom.xml

@@ -12,13 +12,9 @@
     <artifactId>device-server</artifactId>
 
     <dependencies>
-        <dependency>
-            <groupId>net.java.dev.jna</groupId>
-            <artifactId>jna</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.usoftchina.smartschool</groupId>
-            <artifactId>device-sdk-dahua</artifactId>
+            <artifactId>device-sdk</artifactId>
         </dependency>
         <dependency>
             <groupId>com.usoftchina.smartschool</groupId>
@@ -54,6 +50,16 @@
             <groupId>com.usoftchina.smartschool</groupId>
             <artifactId>school-dto</artifactId>
         </dependency>
+        <!--test-->
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>test-starter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>device-core</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 0 - 2
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/DeviceApplication.java

@@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.scheduling.annotation.EnableAsync;
 
 /**
  * @author yingp
@@ -12,7 +11,6 @@ import org.springframework.scheduling.annotation.EnableAsync;
  */
 @SpringBootApplication
 @EnableEurekaClient
-@EnableAsync
 @EnableFeignClients({
         "com.usoftchina.smartschool.file.api","com.usoftchina.smartschool.wechat.api"
 })

+ 91 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/config/RestTemplateConfig.java

@@ -0,0 +1,91 @@
+package com.usoftchina.smartschool.device.config;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * @Author chenwei
+ * @Date 2019/03/07
+ */
+@Configuration
+public class RestTemplateConfig {
+
+    private static final Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);
+
+    @Bean
+    public RestTemplate restTemplate(){
+        RestTemplate restTemplate = new RestTemplate();
+        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
+        converterList.add(0, responseBodyConverter());
+        restTemplate.setRequestFactory(httpRequestFactory());
+        return restTemplate;
+    }
+
+    @Bean
+    public HttpMessageConverter<String> responseBodyConverter() {
+        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        return converter;
+    }
+
+    @Bean
+    public HttpComponentsClientHttpRequestFactory httpRequestFactory(){
+        try {
+            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
+            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                    return true;
+                }
+            }).build();
+            httpClientBuilder.setSSLContext(sslContext);
+            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
+            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
+            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                    .register("https", sslConnectionSocketFactory).build();// 注册http和https请求
+            // 开始设置连接池
+            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+            poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500
+            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100
+            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
+            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
+            HttpClient httpClient = httpClientBuilder.build();
+            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
+            clientHttpRequestFactory.setConnectTimeout(20000);              // 连接超时
+            clientHttpRequestFactory.setReadTimeout(30000);                 // 数据读取超时时间
+            clientHttpRequestFactory.setConnectionRequestTimeout(20000);    // 连接不够用的等待时间
+            return clientHttpRequestFactory;
+        }catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e){
+            logger.info("初始化HTTP连接池出错, message={}", e);
+        }
+        return null;
+    }
+
+}

+ 66 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/AccessControlController.java

@@ -0,0 +1,66 @@
+package com.usoftchina.smartschool.device.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.po.AccessControlRecord;
+import com.usoftchina.smartschool.device.service.AccessControlService;
+import com.usoftchina.smartschool.page.PageDefault;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/3/8
+ */
+@RestController
+@RequestMapping("/accesscontrol")
+public class AccessControlController {
+
+    @Autowired
+    private AccessControlService accessControlService;
+
+    /**
+     * 按人和时间期间查找门禁记录
+     *
+     * @param stuNumber
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    @GetMapping("/record")
+    public Result<List<AccessControlRecord>> getRecords(String stuNumber, Date beginDate, Date endDate) {
+        return Result.success(accessControlService.findByStuNumberAndDate(stuNumber, beginDate, endDate));
+    }
+
+    /**
+     * 门禁记录 - 列表查询
+     *
+     * @param page
+     * @param listReqDTO
+     * @return
+     */
+    @GetMapping("/record/list")
+    public Result<PageInfo<AccessControlRecord>> getRecordsPage(@PageDefault PageRequest page,
+                                                                ListReqDTO listReqDTO) {
+        return Result.success();
+    }
+
+    /**
+     * 接收门禁事件
+     *
+     * @param info
+     * @return
+     */
+    @PostMapping("/event")
+    public Result onAccessControlEvent(AccessControlInfo info) {
+        accessControlService.onAccessControlEvent(info);
+        return Result.success();
+    }
+
+}

+ 0 - 44
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/DeviceController.java

@@ -1,44 +0,0 @@
-package com.usoftchina.smartschool.device.controller;
-
-import com.github.pagehelper.PageInfo;
-import com.usoftchina.smartschool.base.Result;
-import com.usoftchina.smartschool.device.po.Device;
-import com.usoftchina.smartschool.device.service.DeviceService;
-import com.usoftchina.smartschool.page.PageDefault;
-import com.usoftchina.smartschool.page.PageRequest;
-import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
-import com.usoftchina.smartschool.school.dto.DocBaseDTO;
-import com.usoftchina.smartschool.school.dto.ListReqDTO;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-/**
- * @author yingp
- * @date 2019/3/8
- */
-@RestController
-@RequestMapping("/device")
-public class DeviceController {
-
-    @Autowired
-    private DeviceService deviceService;
-
-    @GetMapping("/list")
-    public Result getList(@PageDefault PageRequest page, ListReqDTO listReqDTO) {
-        PageInfo<Device> data = deviceService.getListData(page, listReqDTO);
-        return Result.success(data);
-    }
-
-    @PostMapping("/save")
-    public Result saveFormData(@RequestBody Device data) {
-        DocBaseDTO formData = deviceService.saveFormData(data);
-        return Result.success(formData);
-    }
-
-    @PostMapping("/batchDelete")
-    public Result batchDelete(@RequestBody BatchDealBaseDTO baseDTOs) {
-        deviceService.batchDelete(baseDTOs);
-        return Result.success();
-    }
-
-}

+ 35 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/IcCardController.java

@@ -0,0 +1,35 @@
+package com.usoftchina.smartschool.device.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.device.dto.AccTransDetail;
+import com.usoftchina.smartschool.device.service.IcCardService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 对接IC卡业务
+ *
+ * @author yingp
+ * @date 2019/3/12
+ */
+@RestController
+@RequestMapping("/iccard")
+public class IcCardController {
+
+    @Autowired
+    private IcCardService icCardService;
+
+    @PostMapping("/consume/record")
+    public Result consumePush(String data, String school){
+        List<AccTransDetail> accTransDetailList = JSON.parseArray(data, AccTransDetail.class);
+        String result = icCardService.consumePush(accTransDetailList, school);
+        return Result.success(result);
+    }
+
+
+}

+ 0 - 139
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/listener/AccessControlListener.java

@@ -1,139 +0,0 @@
-package com.usoftchina.smartschool.device.listener;
-
-import com.usoftchina.smartschool.base.Result;
-import com.usoftchina.smartschool.device.api.DeviceApi;
-import com.usoftchina.smartschool.device.dto.AccessControlInfo;
-import com.usoftchina.smartschool.device.dto.DeviceInfo;
-import com.usoftchina.smartschool.device.event.AccessControlEvent;
-import com.usoftchina.smartschool.device.mapper.DeviceMapper;
-import com.usoftchina.smartschool.device.po.Device;
-import com.usoftchina.smartschool.device.po.ImageFile;
-import com.usoftchina.smartschool.device.po.Information;
-import com.usoftchina.smartschool.device.po.OutInRecord;
-import com.usoftchina.smartschool.device.service.DeviceService;
-import com.usoftchina.smartschool.file.api.FileApi;
-import com.usoftchina.smartschool.file.dto.FileInfoDTO;
-import com.usoftchina.smartschool.school.dto.StudentDTO;
-import com.usoftchina.smartschool.utils.DateUtils;
-import com.usoftchina.smartschool.utils.StringUtils;
-import com.usoftchina.smartschool.wechat.api.WechatApi;
-import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
-import org.apache.catalina.realm.LockOutRealm;
-import org.aspectj.util.FileUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.event.EventListener;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.File;
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author yingp
- * @date 2019/3/8
- */
-@Component
-public class AccessControlListener implements InitializingBean{
-
-    @Autowired
-    private FileApi fileApi;
-
-    @Autowired
-    private DeviceApi deviceApi;
-
-    @Autowired
-    private WechatApi wechatApi;
-
-    @Autowired
-    private DeviceMapper deviceMapper;
-
-    final static String TEMPLATEID = "JcWRReMGC1odqcaAgXDfETv9sWwVbWLXc9KLEn_Nve0";
-
-    private Logger logger = LoggerFactory.getLogger(AccessControlListener.class);
-
-    /**
-     * 门禁事件
-     *
-     * @param event
-     */
-    @Async
-    @EventListener(AccessControlEvent.class)
-    public void onAccessControlEvent(AccessControlEvent event) {
-        Long fileId = null;
-        String cardNo = event.getAccessControlInfo().getCardNo();
-        if (StringUtils.isEmpty(cardNo)) {
-            return;
-        }
-        /**
-         * 查询人员信息
-         */
-        List<Information> information = deviceMapper.selectInfoByCardNo(cardNo);
-        if (null == information || information.size() == 0) {
-            logger.error("学生信息不存在");
-            return;
-        }
-        /**
-         * 1、保存图片文件;
-         */
-        byte[] imageData = event.getAccessControlInfo().getImageData();
-        if (null != imageData && imageData.length > 0) {
-            MultipartFile file = new ImageFile(imageData, information.get(0).getStuName());
-            Result<FileInfoDTO> fileInfo = null;
-            try {
-                fileInfo = fileApi.upload(0l, file);
-                fileId = fileInfo.getData().getId();
-            }catch (Exception ex) {
-                logger.error(ex.getMessage());
-            }
-        }
-        /**
-         * 2、保存门禁出入记录;
-         */
-        int type = event.getAccessControlInfo().getEventType();
-        Information info = information.get(0);
-        OutInRecord record = new OutInRecord();
-        record.setClazz_id(info.getClazz_id());
-        record.setSchool_id(info.getSchoolId());
-        record.setClazz_name(info.getStuClass());
-        record.setSchool_id(info.getSchoolId());
-        record.setGrade_clazz(info.getStuClassnickname());
-        record.setGrade_name(info.getStuGrade());
-        record.setRecord_date(new Date());
-        record.setStu_sex(info.getStuSex());
-        record.setRecord_type(type);
-        record.setStu_id(info.getStuId());
-        record.setStu_number(info.getStuNumber());
-        record.setRecord_name(info.getStuName() + (type == 1 ? "进人" : "出去"));
-        deviceMapper.insertRecordSelective(record);
-        /**
-         * 3、推送消息到消息服务器(微信服务监听此消息发送微信消息)
-         */
-        MessageInfoDTO msg = new MessageInfoDTO();
-        msg.setAppId(info.getAppId());
-        msg.setSecret(info.getSecret());
-        msg.setTouser(info.getOpenId());
-        msg.setTemplateId(TEMPLATEID);
-        msg.setTitle("出入校提醒");
-        msg.setKeyword1(info.getStuName());
-        msg.setKeyword2(DateUtils.format());
-        msg.setRemark("您好! 你的孩子: " + info.getStuName() + (type == 1 ? " 进人" : " 出去") + "学校");
-        wechatApi.sendMsg(msg);
-    }
-
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        List<DeviceInfo> devices = deviceMapper.findAll();
-        devices.forEach(device -> {
-            if (!StringUtils.isEmpty(device.getUsername())) {
-                deviceApi.add(device);
-            }
-        });
-    }
-}

+ 27 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/AccessControlRecordMapper.java

@@ -0,0 +1,27 @@
+package com.usoftchina.smartschool.device.mapper;
+
+import com.usoftchina.smartschool.device.po.AccessControlRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/3/8
+ */
+@Mapper
+public interface AccessControlRecordMapper {
+    void insertRecordSelective(AccessControlRecord record);
+
+    /**
+     * 按学号和时间期间查找
+     *
+     * @param stuNumber
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    List<AccessControlRecord> selectByStuNumberAndDate(String stuNumber, Date beginDate,
+                                                     Date endDate);
+}

+ 0 - 32
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/DeviceMapper.java

@@ -1,32 +0,0 @@
-package com.usoftchina.smartschool.device.mapper;
-
-import com.usoftchina.smartschool.device.dto.DeviceInfo;
-import com.usoftchina.smartschool.device.po.Device;
-import com.usoftchina.smartschool.device.po.Information;
-import com.usoftchina.smartschool.device.po.OutInRecord;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-
-import java.util.List;
-
-/**
- * @author yingp
- * @date 2019/3/8
- */
-@Mapper
-public interface DeviceMapper {
-    List<DeviceInfo> findAll();
-
-    List<Device> selectByConditon(@Param("con") String condition);
-
-    void insertSelective(Device formdata);
-
-    void updateByPrimaryKeySelective(Device formdata);
-
-    void deleteByPrimaryKey(Long id);
-
-    List<Information>selectInfoByCardNo(String cardNo);
-
-    void insertRecordSelective(OutInRecord record);
-}

+ 18 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/IcCardMapper.java

@@ -0,0 +1,18 @@
+package com.usoftchina.smartschool.device.mapper;
+
+import com.usoftchina.smartschool.school.dto.SysSchoolDTO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * @Author ChenWei
+ * @Date 2019/03/12
+ */
+@Mapper
+public interface IcCardMapper {
+
+    String SelectParentOpenId(@Param("code") String code, @Param("schoolId") Long schoolId);
+
+    SysSchoolDTO getSchoolIdByName(@Param("name") String name);
+
+}

+ 15 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/StudentInfoMapper.java

@@ -0,0 +1,15 @@
+package com.usoftchina.smartschool.device.mapper;
+
+import com.usoftchina.smartschool.device.po.StudentInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/3/8
+ */
+@Mapper
+public interface StudentInfoMapper {
+    List<StudentInfo> selectInfoByCardNo(String cardNo);
+}

+ 1 - 1
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/OutInRecord.java → applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/AccessControlRecord.java

@@ -10,7 +10,7 @@ import java.util.Date;
  * @create: 2019-03-11 11:33
  **/
 @Data
-public class OutInRecord implements Serializable{
+public class AccessControlRecord implements Serializable{
     private Long record_id;         //编号
 
     private String record_name;     //记录名

+ 0 - 81
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Device.java

@@ -1,81 +0,0 @@
-package com.usoftchina.smartschool.device.po;
-
-
-import java.io.Serializable;
-
-/**
- * @author: guq
- * @create: 2019-03-08 16:53
- **/
-public class Device implements Serializable{
-
-    private Long deviceId;
-
-    private String deviceName;
-
-    private String deviceIp;
-
-    private Integer devicePort;
-
-    private String deviceUser;
-
-    private String devicePassword;
-
-    private String deviceRemark;
-
-    public Integer getDevicePort() {
-        return devicePort;
-    }
-
-    public void setDevicePort(Integer devicePort) {
-        this.devicePort = devicePort;
-    }
-
-    public String getDeviceIp() {
-        return deviceIp;
-    }
-
-    public void setDeviceIp(String deviceIp) {
-        this.deviceIp = deviceIp;
-    }
-
-    public String getDeviceRemark() {
-        return deviceRemark;
-    }
-
-    public void setDeviceRemark(String deviceRemark) {
-        this.deviceRemark = deviceRemark;
-    }
-
-    public Long getDeviceId() {
-        return deviceId;
-    }
-
-    public void setDeviceId(Long deviceId) {
-        this.deviceId = deviceId;
-    }
-
-    public String getDeviceName() {
-        return deviceName;
-    }
-
-    public void setDeviceName(String deviceName) {
-        this.deviceName = deviceName;
-    }
-
-    public String getDeviceUser() {
-        return deviceUser;
-    }
-
-    public void setDeviceUser(String deviceUser) {
-        this.deviceUser = deviceUser;
-    }
-
-    public String getDevicePassword() {
-        return devicePassword;
-    }
-
-    public void setDevicePassword(String devicePassword) {
-        this.devicePassword = devicePassword;
-    }
-}

+ 1 - 1
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Information.java → applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/StudentInfo.java

@@ -9,7 +9,7 @@ import java.io.Serializable;
  * @create: 2019-03-11 10:57
  **/
 @Data
-public class Information implements Serializable{
+public class StudentInfo implements Serializable{
 
     private String appId;
 

+ 49 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Transaction.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.device.po;
+
+public enum Transaction {
+
+    AUTO_RECHARGE("自动充值", "10"),
+    HAND_RECHARGE("手动充值", "11"),
+    TRANSFER_RECHARGE("转账充值", "12"),
+    SUPPLEMENT__RECHARGE("补账充值", "13"),
+    TRAPS_RECHARGE("圈存充值", "14"),
+
+    CONSUMPTION_PAY("消费支出", "20"),
+    REFUND("退款", "21"),
+    CLOSE_ACCOUNT("销户", "22"),
+    TRANSFER_PAY("转账支出", "23"),
+    SUPPLEMENT_PAY("补账支出", "24");
+
+    private String name;
+    private String code;
+
+    Transaction(String name, String code) {
+        this.name = name;
+        this.code = code;
+    }
+
+    public static String getName(String code){
+        for (Transaction transaction : Transaction.values()) {
+            if (transaction.getCode().equals(code)) {
+                return transaction.name;
+            }
+        }
+        return null;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 32 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/AccessControlService.java

@@ -0,0 +1,32 @@
+package com.usoftchina.smartschool.device.service;
+
+import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.po.AccessControlRecord;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/3/12
+ */
+public interface AccessControlService {
+
+    /**
+     * 处理门禁事件
+     *
+     * @param info
+     */
+    void onAccessControlEvent(AccessControlInfo info);
+
+    /**
+     * 按学号和时间期间查找
+     *
+     * @param stuNumber
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    List<AccessControlRecord> findByStuNumberAndDate(String stuNumber, Date beginDate, Date endDate);
+
+}

+ 0 - 16
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/DeviceService.java

@@ -1,16 +0,0 @@
-package com.usoftchina.smartschool.device.service;
-
-import com.github.pagehelper.PageInfo;
-import com.usoftchina.smartschool.device.po.Device;
-import com.usoftchina.smartschool.page.PageRequest;
-import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
-import com.usoftchina.smartschool.school.dto.DocBaseDTO;
-import com.usoftchina.smartschool.school.dto.ListReqDTO;
-
-public interface DeviceService {
-    PageInfo<Device> getListData(PageRequest page, ListReqDTO listReqDTO);
-
-    DocBaseDTO saveFormData(Device data);
-
-    void batchDelete(BatchDealBaseDTO baseDTOs);
-}

+ 11 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/IcCardService.java

@@ -0,0 +1,11 @@
+package com.usoftchina.smartschool.device.service;
+
+import com.usoftchina.smartschool.device.dto.AccTransDetail;
+
+import java.util.List;
+
+public interface IcCardService {
+
+    String consumePush(List<AccTransDetail> accTransDetailList, String school);
+
+}

+ 128 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/AccessControlServiceImpl.java

@@ -0,0 +1,128 @@
+package com.usoftchina.smartschool.device.service.impl;
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.mapper.AccessControlRecordMapper;
+import com.usoftchina.smartschool.device.mapper.StudentInfoMapper;
+import com.usoftchina.smartschool.device.po.AccessControlRecord;
+import com.usoftchina.smartschool.device.po.ImageFile;
+import com.usoftchina.smartschool.device.po.StudentInfo;
+import com.usoftchina.smartschool.device.service.AccessControlService;
+import com.usoftchina.smartschool.file.api.FileApi;
+import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+import com.usoftchina.smartschool.utils.DateUtils;
+import com.usoftchina.smartschool.utils.StringUtils;
+import com.usoftchina.smartschool.wechat.api.WechatApi;
+import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/3/12
+ */
+@Service
+public class AccessControlServiceImpl implements AccessControlService{
+
+    @Autowired
+    private FileApi fileApi;
+
+    @Autowired
+    private WechatApi wechatApi;
+
+    @Autowired
+    private AccessControlRecordMapper accessControlRecordMapper;
+
+    @Autowired
+    private StudentInfoMapper studentInfoMapper;
+
+    private Logger logger = LoggerFactory.getLogger(AccessControlServiceImpl.class);
+
+    @Value("${wechat.template.accesscontrol}")
+    private String accessControlTemplateId;
+
+    @Override
+    public void onAccessControlEvent(AccessControlInfo info) {
+        Long fileId = null;
+        String cardNo = info.getCardNo();
+        if (StringUtils.isEmpty(cardNo)) {
+            return;
+        }
+        /**
+         * 查询人员信息
+         */
+        List<StudentInfo> information = studentInfoMapper.selectInfoByCardNo(cardNo);
+        if (null == information || information.size() == 0) {
+            logger.error("学生信息不存在");
+            return;
+        }
+        /**
+         * 1、保存图片文件;
+         */
+        byte[] imageData = info.getImageData();
+        if (null != imageData && imageData.length > 0) {
+            MultipartFile file = new ImageFile(imageData, information.get(0).getStuName());
+            Result<FileInfoDTO> fileInfo = null;
+            try {
+                fileInfo = fileApi.upload(0L, file);
+                fileId = fileInfo.getData().getId();
+            }catch (Exception ex) {
+                logger.error(ex.getMessage());
+            }
+        }
+        /**
+         * 2、保存门禁出入记录;
+         */
+        int type = info.getEventType();
+        StudentInfo studentInfo = information.get(0);
+        AccessControlRecord record = new AccessControlRecord();
+        record.setClazz_id(studentInfo.getClazz_id());
+        record.setSchool_id(studentInfo.getSchoolId());
+        record.setClazz_name(studentInfo.getStuClass());
+        record.setSchool_id(studentInfo.getSchoolId());
+        record.setGrade_clazz(studentInfo.getStuClassnickname());
+        record.setGrade_name(studentInfo.getStuGrade());
+        record.setRecord_date(new Date());
+        record.setStu_sex(studentInfo.getStuSex());
+        record.setRecord_type(type);
+        record.setStu_id(studentInfo.getStuId());
+        record.setStu_number(studentInfo.getStuNumber());
+        record.setRecord_name(studentInfo.getStuName() + (type == 1 ? "进人" : "出去"));
+        accessControlRecordMapper.insertRecordSelective(record);
+        /**
+         * 3、推送消息到消息服务器(微信服务监听此消息发送微信消息)
+         */
+        MessageInfoDTO msg = new MessageInfoDTO();
+        msg.setAppId(studentInfo.getAppId());
+        msg.setSecret(studentInfo.getSecret());
+        msg.setTouser(studentInfo.getOpenId());
+        msg.setTemplateId(accessControlTemplateId);
+        msg.setTitle("出入校提醒");
+        msg.setKeyword1(studentInfo.getStuName());
+        msg.setKeyword2(DateUtils.format());
+        msg.setRemark("您好! 你的孩子: " + studentInfo.getStuName() + (type == 1 ? " 进人" : " 出去") + "学校");
+        wechatApi.sendMsg(msg);
+    }
+
+    /**
+     * 按学号和时间期间查找
+     *
+     * @param stuNumber
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    @Override
+    public List<AccessControlRecord> findByStuNumberAndDate(String stuNumber, Date beginDate,
+                                                     Date endDate) {
+        return accessControlRecordMapper.selectByStuNumberAndDate(stuNumber, beginDate, endDate);
+    }
+
+}

+ 0 - 79
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/DeviceServiceImpl.java

@@ -1,79 +0,0 @@
-package com.usoftchina.smartschool.device.service.impl;
-
-import com.github.pagehelper.PageHelper;
-import com.github.pagehelper.PageInfo;
-import com.usoftchina.smartschool.context.BaseContextHolder;
-import com.usoftchina.smartschool.device.mapper.DeviceMapper;
-import com.usoftchina.smartschool.device.po.Device;
-import com.usoftchina.smartschool.device.service.DeviceService;
-import com.usoftchina.smartschool.exception.BizException;
-import com.usoftchina.smartschool.exception.ExceptionCode;
-import com.usoftchina.smartschool.page.PageRequest;
-import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
-import com.usoftchina.smartschool.school.dto.DocBaseDTO;
-import com.usoftchina.smartschool.school.dto.ListReqDTO;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import java.util.List;
-
-/**
- * @author: guq
- * @create: 2019-03-08 16:48
- **/
-@Service
-public class DeviceServiceImpl implements DeviceService{
-
-    @Autowired
-    private DeviceMapper deviceMapper;
-
-    @Override
-    public PageInfo<Device> getListData(PageRequest page, ListReqDTO listReqDTO) {
-        PageHelper.startPage(page.getNumber(), page.getSize());
-        //condition语句
-        String condition = listReqDTO.getFinalCondition();
-        if(condition == null){
-            condition = "1=1";
-        }
-        List<Device> data = deviceMapper.selectByConditon(condition);
-        PageInfo<Device> list = new PageInfo<>(data);
-        return list;
-    }
-
-    @Override
-    public DocBaseDTO saveFormData(Device formdata) {
-        if (StringUtils.isEmpty(formdata)){
-            throw new BizException(ExceptionCode.ILLEGAL_ARGUMENTS);
-        }
-        Long id = formdata.getDeviceId();
-        if (StringUtils.isEmpty(id) || "0".equals(id.toString())) {
-            deviceMapper.insertSelective(formdata);
-            id = formdata.getDeviceId();
-        } else {
-            //更新
-            deviceMapper.updateByPrimaryKeySelective(formdata);
-        }
-        return new DocBaseDTO(formdata.getDeviceId());
-    }
-
-
-    @Override
-    public void batchDelete(BatchDealBaseDTO baseDTOs) {
-        if (null == baseDTOs || null == baseDTOs.getBaseDTOs() ||
-                baseDTOs.getBaseDTOs().size() == 0) {
-            return;
-        }
-        for (DocBaseDTO base : baseDTOs.getBaseDTOs()) {
-            delete(base.getId());
-        }
-    }
-
-    private void delete(Long id) {
-        if (null == id || "0".equals(id)) {
-            return;
-        }
-        deviceMapper.deleteByPrimaryKey(id);
-    }
-}

+ 123 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/IcCardServiceImpl.java

@@ -0,0 +1,123 @@
+package com.usoftchina.smartschool.device.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.smartschool.device.base.Result;
+import com.usoftchina.smartschool.device.dto.AccTransDetail;
+import com.usoftchina.smartschool.device.mapper.IcCardMapper;
+import com.usoftchina.smartschool.device.po.Transaction;
+import com.usoftchina.smartschool.device.service.IcCardService;
+import com.usoftchina.smartschool.school.dto.SysSchoolDTO;
+import com.usoftchina.smartschool.utils.ObjectUtils;
+import com.usoftchina.smartschool.utils.http.HmacUtils;
+import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+import java.net.URI;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Author chenwei
+ * @Date 2019/03/12
+ */
+@Service
+public class IcCardServiceImpl implements IcCardService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private IcCardMapper icCardMapper;
+
+    private final String targetURL = "https://school-api.ydyhz.com/api/wechat/send/Messages";
+
+    public String consumePush(List<AccTransDetail> accTransDetailList, String school){
+        List<MessageInfoDTO> messageInfoList = new ArrayList<MessageInfoDTO>();
+        SysSchoolDTO sysSchoolDTO = icCardMapper.getSchoolIdByName(school);
+        if (!ObjectUtils.isEmpty(sysSchoolDTO)) {
+            String appId = sysSchoolDTO.getSchool_appid();
+            String secret = sysSchoolDTO.getSchool_secret();
+            Long schoolId = sysSchoolDTO.getSchool_id();
+            StringBuilder sb = new StringBuilder();
+            accTransDetailList.forEach(accTransDetail -> {
+                sb.append(accTransDetail.getGuid() + ",");
+                String oldType = accTransDetail.getAccTransType();
+                accTransDetail.setAccTransType(Transaction.getName(accTransDetail.getAccTransType()));
+                //构造messageInfo对象
+                MessageInfoDTO messageInfo = new MessageInfoDTO();
+                messageInfo.setMsgId(accTransDetail.getGuid());
+                String openId = icCardMapper.SelectParentOpenId(accTransDetail.getEmpNo(), schoolId);
+                messageInfo.setTouser(openId);
+                messageInfo.setAppId(appId);
+                messageInfo.setSecret(secret);
+                //messageInfo.setUserType(2);
+                messageInfo.setTemplateId("FhtdzLdpzLLp4eJGtgvH4SUfIpSIF0kWwIpsWsSBp6c");
+                String accNo = accTransDetail.getAccNo();
+                String cardNo = StringUtils.isEmpty(accNo) ? null : accNo.substring(accTransDetail.getAccNo().length() - 4);
+                String header = "您好,您的小孩" + accTransDetail.getEmpName() + "在校的校园卡(卡号:*** " + cardNo + ")发生如下交易";
+                messageInfo.setTitle(header);
+                Date accTransDay = accTransDetail.getAccTransDay();
+                if (null != accTransDay) {
+                    messageInfo.setKeyword1(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(accTransDetail.getAccTransDay()));
+                }
+                if (Integer.parseInt(oldType) > 15) {
+                    messageInfo.setKeyword2(String.format("%.2f", accTransDetail.getoMoneyValue()));
+                } else {
+                    messageInfo.setKeyword2(String.format("%.2f", accTransDetail.getiMoneyValue()));
+                }
+                messageInfo.setKeyword3(accTransDetail.getAccTransType());
+                messageInfo.setKeyword4(String.format("%.2f", accTransDetail.getCardMoneyValue()));
+                messageInfo.setRemark("感谢您使用");
+                messageInfoList.add(messageInfo);
+            });
+            //3.传输
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+            MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
+            requestEntity.add("data", JSON.toJSONString(messageInfoList));
+            HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(requestEntity, headers);
+            //禁止对该url进行encode操作
+            DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory();
+            defaultUriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
+            restTemplate.setUriTemplateHandler(defaultUriBuilderFactory);
+            ResponseEntity<String> responseEntity = restTemplate.postForEntity(getURI(targetURL, "/send", school), httpEntity, String.class);
+            //4.完成后,将传输的成功的数据状态更新为"已上传"
+            if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
+                Result result = JSON.parseObject(responseEntity.getBody(), Result.class);
+                if (result.isSuccess()) {
+                    String ids = "'" + sb.substring(0, sb.length() - 1).replaceAll(",", "','") + "'";
+                    return ids;
+                }
+            }
+        }
+        return null;
+    }
+
+    private String getURI(String url, String subIndexOf, String school, Object... vars){
+        StringBuilder accessUrl = new StringBuilder(url);
+        accessUrl.append(url.contains("?") ? "&" : "?");
+        // 身份ID
+        accessUrl.append("school=").append(school);
+        //时间戳
+        accessUrl.append("&_timestamp=").append(System.currentTimeMillis());
+        RestTemplate restTemplate = new RestTemplate();
+        URI uri = restTemplate.getUriTemplateHandler().expand(accessUrl.toString(), vars);
+        url = uri.toString();
+        /*if (StringUtils.isEmpty(accessSecretKey)) {
+            return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)));
+        }else {
+            return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)), accessSecretKey);
+        }*/
+        return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)));
+    }
+
+}

+ 3 - 4
applications/device/device-server/src/main/resources/application.yml

@@ -1,7 +1,6 @@
-device:
-  dahua:
-    wait-time: 5000
-    connect-time: 10000
+wechat:
+  template:
+    accesscontrol: JcWRReMGC1odqcaAgXDfETv9sWwVbWLXc9KLEn_Nve0
 spring:
   application:
     name: device-server

+ 109 - 0
applications/device/device-server/src/main/resources/mapper/AccessControlRecordMapper.xml

@@ -0,0 +1,109 @@
+<?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.smartschool.device.mapper.AccessControlRecordMapper" >
+    <insert id="insertRecordSelective" parameterType="com.usoftchina.smartschool.device.po.AccessControlRecord" >
+        insert into out_in_record
+        <trim prefix="(" suffix=")" suffixOverrides="," >
+            <if test="record_name != null" >
+                record_name,
+            </if>
+            <if test="out_date != null" >
+                out_date,
+            </if>
+            <if test="in_date != null" >
+                in_date,
+            </if>
+            <if test="record_details != null" >
+                record_details,
+            </if>
+            <if test="record_remarks != null" >
+                record_remarks,
+            </if>
+            <if test="device_id != null" >
+                device_id,
+            </if>
+            <if test="stu_id != null" >
+                stu_id,
+            </if>
+            <if test="school_id != null" >
+                school_id,
+            </if>
+            <if test="stu_number != null" >
+                stu_number,
+            </if>
+            <if test="clazz_id != null" >
+                clazz_id,
+            </if>
+            <if test="clazz_name != null" >
+                clazz_name,
+            </if>
+            <if test="grade_name != null" >
+                grade_name,
+            </if>
+            <if test="grade_clazz != null" >
+                grade_clazz,
+            </if>
+            <if test="stu_sex != null" >
+                stu_sex,
+            </if>
+            <if test="record_type != null" >
+                record_type,
+            </if>
+            <if test="record_date != null" >
+                record_date,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides="," >
+            <if test="record_name != null" >
+                #{record_name,jdbcType=VARCHAR},
+            </if>
+            <if test="out_date != null" >
+                #{out_date,jdbcType=TIMESTAMP},
+            </if>
+            <if test="in_date != null" >
+                #{in_date,jdbcType=TIMESTAMP},
+            </if>
+            <if test="record_details != null" >
+                #{record_details,jdbcType=VARCHAR},
+            </if>
+            <if test="record_remarks != null" >
+                #{record_remarks,jdbcType=VARCHAR},
+            </if>
+            <if test="device_id != null" >
+                #{device_id,jdbcType=BIGINT},
+            </if>
+            <if test="stu_id != null" >
+                #{stu_id,jdbcType=BIGINT},
+            </if>
+            <if test="school_id != null" >
+                #{school_id,jdbcType=BIGINT},
+            </if>
+
+            <if test="stu_number != null" >
+                #{stu_number,jdbcType=VARCHAR},
+            </if>
+            <if test="clazz_id != null" >
+                #{clazz_id,jdbcType=BIGINT},
+            </if>
+            <if test="clazz_name != null" >
+                #{clazz_name,jdbcType=VARCHAR},
+            </if>
+            <if test="grade_name != null" >
+                #{grade_name,jdbcType=VARCHAR},
+            </if>
+            <if test="grade_clazz != null" >
+                #{grade_clazz,jdbcType=VARCHAR},
+            </if>
+            <if test="stu_sex != null" >
+                #{stu_sex,jdbcType=INTEGER},
+            </if>
+            <if test="record_type != null" >
+                #{record_type,jdbcType=INTEGER},
+            </if>
+            <if test="record_date != null" >
+                #{record_date,jdbcType=TIMESTAMP},
+            </if>
+        </trim>
+    </insert>
+
+</mapper>

+ 0 - 237
applications/device/device-server/src/main/resources/mapper/DeviceMapper.xml

@@ -1,237 +0,0 @@
-<?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.smartschool.device.mapper.DeviceMapper" >
-   <resultMap id="CurriculumDetailDTOMap" type="com.usoftchina.smartschool.device.po.Device">
-        <id column="deviceId" property="deviceId" jdbcType="BIGINT" />
-        <result column="deviceName" property="deviceName" jdbcType="VARCHAR" />
-        <result column="deviceIp" property="deviceIp" jdbcType="VARCHAR" />
-        <result column="devicePort" property="devicePort" jdbcType="VARCHAR" />
-        <result column="deviceUser" property="deviceUser" jdbcType="VARCHAR" />
-        <result column="devicePassword" property="devicePassword" jdbcType="VARCHAR"/>
-    </resultMap>
-    <select id="findAll" resultMap="deviceInfoMap">
-        select * from device
-    </select>
-
-    <resultMap id="deviceInfoMap" type="com.usoftchina.smartschool.device.dto.DeviceInfo">
-        <result column="deviceIp" property="ip" jdbcType="VARCHAR" />
-        <result column="devicePort" property="port" jdbcType="INTEGER" />
-        <result column="deviceUser" property="username" jdbcType="VARCHAR" />
-        <result column="devicePassword" property="password" jdbcType="VARCHAR"/>
-    </resultMap>
-
-    <select id="selectByConditon" resultType="com.usoftchina.smartschool.device.po.Device">
-        select * from device
-        <where>
-            <if test="con != null">
-                ${con}
-            </if>
-        </where>
-        ORDER BY deviceId DESC
-    </select>
-
-
-    <insert id="insertSelective" parameterType="com.usoftchina.smartschool.device.po.Device" >
-        <selectKey  resultType="java.lang.Long" keyProperty="deviceId">
-            SELECT LAST_INSERT_ID() AS ID
-        </selectKey>
-        insert into device
-        <trim prefix="(" suffix=")" suffixOverrides="," >
-            <if test="deviceUser != null" >
-                deviceUser,
-            </if>
-            <if test="devicePassword != null" >
-                devicePassword,
-            </if>
-            <if test="deviceIp != null" >
-                deviceIp,
-            </if>
-            <if test="devicePort != null" >
-                devicePort,
-            </if>
-            <if test="deviceRemark != null" >
-                deviceRemark,
-            </if>
-            <if test="deviceName != null" >
-                deviceName,
-            </if>
-        </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides="," >
-            <if test="deviceUser != null" >
-                #{deviceUser,jdbcType=VARCHAR},
-            </if>
-            <if test="devicePassword != null" >
-                #{devicePassword,jdbcType=VARCHAR},
-            </if>
-            <if test="deviceIp != null" >
-                #{deviceIp,jdbcType=VARCHAR},
-            </if>
-            <if test="devicePort != null" >
-                #{devicePort,jdbcType=INTEGER},
-            </if>
-            <if test="deviceRemark != null" >
-                #{deviceRemark,jdbcType=VARCHAR},
-            </if>
-            <if test="deviceName != null" >
-                #{deviceName,jdbcType=VARCHAR},
-            </if>
-        </trim>
-    </insert>
-
-    <update id="updateByPrimaryKeySelective" parameterType="com.usoftchina.smartschool.device.po.Device" >
-        update device
-    <set >
-        <if test="deviceUser != null" >
-            deviceUser = #{deviceUser,jdbcType=VARCHAR},
-        </if>
-        <if test="devicePort != null" >
-            devicePort = #{devicePort,jdbcType=INTEGER},
-        </if>
-        <if test="devicePassword != null" >
-            devicePassword = #{devicePassword,jdbcType=VARCHAR},
-        </if>
-        <if test="deviceIp != null" >
-            deviceIp = #{deviceIp,jdbcType=VARCHAR},
-        </if>
-        <if test="deviceRemark != null" >k
-            deviceRemark = #{deviceRemark,jdbcType=VARCHAR},
-        </if>
-        <if test="deviceName != null" >
-            deviceName = #{deviceName,jdbcType=VARCHAR},
-        </if>
-    </set>
-        where deviceId = #{deviceId,jdbcType=BIGINT}
-    </update>
-
-    <delete id="deleteByPrimaryKey" parameterType="long">
-        delete from device where deviceId = #{id}
-    </delete>
-
-    <select id="selectInfoByCardNo" parameterType="string" resultMap="information">
-        select school_appid,school_secret,sys_parents.openid,sys_student.stu_name,sys_student.stu_id,sys_school.school_id,
-         stu_number,sys_student.clazz_id,stu_class,stu_grade,stu_classnickname,stu_sex from sys_student left join sys_school on sys_student.school_id=sys_school.school_id
-        left join sys_parents_stu on sys_student.stu_id=sys_parents_stu.stu_id left join sys_parents on sys_parents.parent_id =
-        sys_parents_stu.parent_id where stu_cardNo = #{cardNo}
-    </select>
-
-    <resultMap id="information" type="com.usoftchina.smartschool.device.po.Information" >
-        <result column="school_appid" property="appId" jdbcType="VARCHAR" />
-        <result column="school_secret" property="secret" jdbcType="VARCHAR" />
-        <result column="openid" property="openId" jdbcType="VARCHAR" />
-        <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
-        <result column="stu_id" property="stuId" jdbcType="BIGINT"/>
-        <result column="school_id" property="schoolId" jdbcType="BIGINT"/>
-        <result column="stu_number" property="stuNumber" jdbcType="VARCHAR" />
-        <result column="clazz_id" property="clazz_id" jdbcType="BIGINT" />
-        <result column="stu_class" property="stuClass" jdbcType="VARCHAR" />
-        <result column="stu_grade" property="stuGrade" jdbcType="VARCHAR" />
-        <result column="stu_classnickname" property="stuClassnickname" jdbcType="VARCHAR"/>
-        <result column="stu_sex" property="stuSex" jdbcType="INTEGER"/>
-    </resultMap>
-
-    <insert id="insertRecordSelective" parameterType="com.usoftchina.smartschool.device.po.OutInRecord" >
-        insert into out_in_record
-        <trim prefix="(" suffix=")" suffixOverrides="," >
-            <if test="record_name != null" >
-                record_name,
-            </if>
-            <if test="out_date != null" >
-                out_date,
-            </if>
-            <if test="in_date != null" >
-                in_date,
-            </if>
-            <if test="record_details != null" >
-                record_details,
-            </if>
-            <if test="record_remarks != null" >
-                record_remarks,
-            </if>
-            <if test="device_id != null" >
-                device_id,
-            </if>
-            <if test="stu_id != null" >
-                stu_id,
-            </if>
-            <if test="school_id != null" >
-                school_id,
-            </if>
-            <if test="stu_number != null" >
-                stu_number,
-            </if>
-            <if test="clazz_id != null" >
-                clazz_id,
-            </if>
-            <if test="clazz_name != null" >
-                clazz_name,
-            </if>
-            <if test="grade_name != null" >
-                grade_name,
-            </if>
-            <if test="grade_clazz != null" >
-                grade_clazz,
-            </if>
-            <if test="stu_sex != null" >
-                stu_sex,
-            </if>
-            <if test="record_type != null" >
-                record_type,
-            </if>
-            <if test="record_date != null" >
-                record_date,
-            </if>
-        </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides="," >
-            <if test="record_name != null" >
-                #{record_name,jdbcType=VARCHAR},
-            </if>
-            <if test="out_date != null" >
-                #{out_date,jdbcType=TIMESTAMP},
-            </if>
-            <if test="in_date != null" >
-                #{in_date,jdbcType=TIMESTAMP},
-            </if>
-            <if test="record_details != null" >
-                #{record_details,jdbcType=VARCHAR},
-            </if>
-            <if test="record_remarks != null" >
-                #{record_remarks,jdbcType=VARCHAR},
-            </if>
-            <if test="device_id != null" >
-                #{device_id,jdbcType=BIGINT},
-            </if>
-            <if test="stu_id != null" >
-                #{stu_id,jdbcType=BIGINT},
-            </if>
-            <if test="school_id != null" >
-                #{school_id,jdbcType=BIGINT},
-            </if>
-
-            <if test="stu_number != null" >
-                #{stu_number,jdbcType=VARCHAR},
-            </if>
-            <if test="clazz_id != null" >
-                #{clazz_id,jdbcType=BIGINT},
-            </if>
-            <if test="clazz_name != null" >
-                #{clazz_name,jdbcType=VARCHAR},
-            </if>
-            <if test="grade_name != null" >
-                #{grade_name,jdbcType=VARCHAR},
-            </if>
-            <if test="grade_clazz != null" >
-                #{grade_clazz,jdbcType=VARCHAR},
-            </if>
-            <if test="stu_sex != null" >
-                #{stu_sex,jdbcType=INTEGER},
-            </if>
-            <if test="record_type != null" >
-                #{record_type,jdbcType=INTEGER},
-            </if>
-            <if test="record_date != null" >
-                #{record_date,jdbcType=TIMESTAMP},
-            </if>
-        </trim>
-    </insert>
-
-</mapper>

+ 20 - 0
applications/device/device-server/src/main/resources/mapper/IcCardMapper.xml

@@ -0,0 +1,20 @@
+<?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.smartschool.device.mapper.IcCardMapper" >
+  <resultMap id="BaseResultMap" type="com.usoftchina.smartschool.school.dto.SysSchoolDTO">
+
+  </resultMap>
+
+  <select id="getSchoolIdByName" resultType="com.usoftchina.smartschool.school.dto.SysSchoolDTO">
+    SELECT * FROM SYS_SCHOOL WHERE SCHOOL_NAME = #{name}
+  </select>
+
+  <select id="SelectParentOpenId" resultType="string">
+    select openid from sys_parents where  parent_id in
+    (SELECT parent_id FROM sys_parents_stu WHERE stu_id =
+      (SELECT stu_id FROM sys_student WHERE stu_number = #{code} and school_id = #{schoolId})
+    )
+    and school_id=#{schoolId}
+    and   ifnull(openid,'')  != ''  limit 0,1
+  </select>
+</mapper>

+ 25 - 0
applications/device/device-server/src/main/resources/mapper/StudentInfoMapper.xml

@@ -0,0 +1,25 @@
+<?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.smartschool.device.mapper.AccessControlRecordMapper" >
+    <select id="selectInfoByCardNo" parameterType="string" resultMap="studentInfo">
+        select school_appid,school_secret,sys_parents.openid,sys_student.stu_name,sys_student.stu_id,sys_school.school_id,
+         stu_number,sys_student.clazz_id,stu_class,stu_grade,stu_classnickname,stu_sex from sys_student left join sys_school on sys_student.school_id=sys_school.school_id
+        left join sys_parents_stu on sys_student.stu_id=sys_parents_stu.stu_id left join sys_parents on sys_parents.parent_id =
+        sys_parents_stu.parent_id where stu_cardNo = #{cardNo}
+    </select>
+
+    <resultMap id="studentInfo" type="com.usoftchina.smartschool.device.po.StudentInfo" >
+        <result column="school_appid" property="appId" jdbcType="VARCHAR" />
+        <result column="school_secret" property="secret" jdbcType="VARCHAR" />
+        <result column="openid" property="openId" jdbcType="VARCHAR" />
+        <result column="stu_name" property="stuName" jdbcType="VARCHAR" />
+        <result column="stu_id" property="stuId" jdbcType="BIGINT"/>
+        <result column="school_id" property="schoolId" jdbcType="BIGINT"/>
+        <result column="stu_number" property="stuNumber" jdbcType="VARCHAR" />
+        <result column="clazz_id" property="clazz_id" jdbcType="BIGINT" />
+        <result column="stu_class" property="stuClass" jdbcType="VARCHAR" />
+        <result column="stu_grade" property="stuGrade" jdbcType="VARCHAR" />
+        <result column="stu_classnickname" property="stuClassnickname" jdbcType="VARCHAR"/>
+        <result column="stu_sex" property="stuSex" jdbcType="INTEGER"/>
+    </resultMap>
+</mapper>

+ 49 - 0
applications/device/device-server/src/test/java/com/usoftchina/smartschool/device/test/TestService.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.device.test;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.utils.DateUtils;
+import com.usoftchina.smartschool.wechat.api.WechatApi;
+import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
+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.SpringRunner;
+
+/**
+ * @author: guq
+ * @create: 2019-03-12 09:48
+ **/
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class TestService {
+
+  /*  @Autowired
+    AccessService accessService;*/
+    @Autowired
+    WechatApi wechatApi;
+
+    @Test
+    public void testa_accessservice() {
+        AccessControlInfo info = new AccessControlInfo();
+        info.setCardNo("school");
+        info.setEventType(1);
+        //accessService.accessEvent(info);
+    }
+
+    @Test
+    public void testb_wechatapi() {
+        MessageInfoDTO msg = new MessageInfoDTO();
+        msg.setUserType(0);
+        msg.setAppId("asdf");
+        msg.setSecret("asdf");
+        msg.setTouser("asdf");
+        msg.setTemplateId("JcWRReMGC1odqcaAgXDfETv9sWwVbWLXc9KLEn_Nve0");
+        msg.setTitle("出入校提醒");
+        msg.setKeyword1("asdf");
+        msg.setKeyword2(DateUtils.format());
+        msg.setRemark("您好! 你的孩子: ");
+        wechatApi.sendMsg(msg);
+    }
+}

+ 5 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/ClassServiceImpl.java

@@ -85,6 +85,11 @@ public class ClassServiceImpl implements ClassService{
         //更新明细
         for (SysTeacherClazz detail : teachers) {
             detail.setClazz_id(clazz.getClazz_id());
+            Integer count = 0;
+            count = sysClazzMapper.teacherClazz(detail.getSubject_name(),detail.getTeacher_id());
+            if(count > 0){
+                throw new BizException(BizExceptionCode.REPEAT_SUBJECTS);
+            }
             if (StringUtils.isEmpty(detail.getTeacher_clazz_id()) || "0".equals(detail.getTeacher_clazz_id().toString())) {
                 insertDetails.add(detail);
             } else {

+ 40 - 7
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/CurriculumServiceImpl.java

@@ -26,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.stream.Collectors;
 
 /**
  * @Description 课程表
@@ -112,18 +113,21 @@ public class CurriculumServiceImpl implements CurriculumService {
     private void convertToId(CurriculumDetailDTO curriculumDetailDTO, SubjectDO subjectDO) {
         if (curriculumDetailDTO.getMon().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setMon(subjectDO.getSubjectId().toString());
-        }else if (curriculumDetailDTO.getTues().equals(subjectDO.getSubjectName())){
+        }
+        if (curriculumDetailDTO.getTues().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setTues(subjectDO.getSubjectId().toString());
-        }else if (curriculumDetailDTO.getThur().equals(subjectDO.getSubjectName())){
+        }
+        if (curriculumDetailDTO.getThur().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setThur(subjectDO.getSubjectId().toString());
-        }else if (curriculumDetailDTO.getWed().equals(subjectDO.getSubjectName())){
+        }
+        if (curriculumDetailDTO.getWed().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setWed(subjectDO.getSubjectId().toString());
-        }else if (curriculumDetailDTO.getFri().equals(subjectDO.getSubjectName())){
+        }
+        if (curriculumDetailDTO.getFri().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setFri(subjectDO.getSubjectId().toString());
-        }else if (curriculumDetailDTO.getSat().equals(subjectDO.getSubjectName())){
+        }
+        if (curriculumDetailDTO.getSat().equals(subjectDO.getSubjectName())){
             curriculumDetailDTO.setSat(subjectDO.getSubjectId().toString());
-        }else {
-            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), subjectDO.getSubjectName()));
         }
     }
 
@@ -266,6 +270,8 @@ public class CurriculumServiceImpl implements CurriculumService {
                             curriculumDetailDTO.setSchoolId(schoolId);
                             curriculumDetailDTO.setClazzId(clazzId);
                             curriculumDetailDTO.setLessons(detno++);
+                            List<String> subNameList = subjectDOList.stream().map(SubjectDO::getSubjectName).collect(Collectors.toList());
+                            checkExists(curriculumDetailDTO, subNameList);
                             subjectDOList.forEach(subjectDO -> { convertToId(curriculumDetailDTO, subjectDO); });
                         }
                         //2. 插入
@@ -277,12 +283,39 @@ public class CurriculumServiceImpl implements CurriculumService {
         dataImportMapper.updateDataImport(id);
     }
 
+    /**
+     * 检查科目有效性
+     * @param curriculumDetailDTO
+     * @param subNameList
+     */
+    private void checkExists(CurriculumDetailDTO curriculumDetailDTO, List<String> subNameList) {
+        if (!subNameList.contains(curriculumDetailDTO.getMon())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getMon()));
+        }
+        if (!subNameList.contains(curriculumDetailDTO.getTues())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getTues()));
+        }
+        if (!subNameList.contains(curriculumDetailDTO.getWed())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getWed()));
+        }
+        if (!subNameList.contains(curriculumDetailDTO.getThur())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getThur()));
+        }
+        if (!subNameList.contains(curriculumDetailDTO.getFri())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getFri()));
+        }
+        if (!subNameList.contains(curriculumDetailDTO.getSat())) {
+            throw new BizException(BizExceptionCode.NOT_EXISTS_SUBJECT.getCode(), String.format(BizExceptionCode.NOT_EXISTS_SUBJECT.getMessage(), curriculumDetailDTO.getSat()));
+        }
+    }
+
     @Override
     public void publish(Long id) {
         if(org.springframework.util.StringUtils.isEmpty(id) || "0".equals(id)) {
             return;
         }
         curriculumMapper.updateByPublish(id);
+        curriculumMapper.updateByPublishFrom(id);
     }
 
     @Override

+ 16 - 6
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/GradeServiceImpl.java

@@ -212,15 +212,25 @@ public class GradeServiceImpl implements GradeService{
             throw new BizException(BizExceptionCode.USELESS_DATA);
         }
         Integer check = 0;
-        //检测学生
-        check = sysStudentMapper.countStudent(id);
-        if(check > 0){
-            throw new BizException(BizExceptionCode.EFFECTIVE_CLASS_DATA);
+        //学生检测
+        check = sysStudentMapper.checkStu(id);
+        if (check > 0) {
+            throw new BizException(BizExceptionCode.EXISTS_STU);
+        }
+        //教师检测
+        check = sysStudentMapper.checkTeacher(id);
+        if (check > 0) {
+            throw new BizException(BizExceptionCode.EXISTS_TEACHER);
+        }
+        //课表检测
+        check = sysStudentMapper.repeatCurriculum(id);
+        if (check > 0) {
+            throw new BizException(BizExceptionCode.EXISTS_CURRICULUM);
         }
         //检测科目
-        check = sysTeacherMapper.checkTeacherSubjects(id);
+        check = homeWorkMapper.homeWorkRelease(id);
         if(check > 0){
-            throw new BizException(BizExceptionCode.EXISTS_TEACHER_SUBJECTS);
+            throw new BizException(BizExceptionCode.HOMEWORK_RELEASE);
         }
         sysClazzMapper.deleteByPrimaryKey(id);
     }

+ 3 - 3
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java

@@ -24,14 +24,14 @@ public enum BizExceptionCode implements BaseExceptionCode {
     EXISTS_SUBJECT_TEACHER(5000012, "该课程存在班级与任课教师,禁止删除"),
     EXISTS_SCORE_PUBLISH(5000013, "存在已发布成绩,禁止删除"),
     EXISTS_CLASS(500011, "存在班级,无法删除"),
-    EXISTS_TEACHER_SUBJECTS(500012, "存在科目信息,无法删除"),
+    HOMEWORK_RELEASE(500012, "存在发布作业,无法删除"),
+    REPEAT_SUBJECTS(600001, "同个老师不可班带相同的课"),
     REPEAT_GRADE_NAME(600001, "年级名称重复"),
     REPEAT_CLASS_NAME(600002, "班级名称重复"),
     REPEAT_STUDENT_NUMBER(600003, "学生学号不可重复"),
-    EFFECTIVE_CLASS_DATA(600004, "无法删除有学生的班级"),
     TASK_RELEASE_STATUS(600005, "作业已发布无法更改"),
     COURSE_RELEASE_STATUS(600006, "课程表已生效,无法删除"),
-    NOTICE_RELEASE_STATUS(600007, "学校发布已生效,无法删除"),
+    NOTICE_RELEASE_STATUS(600007, "学校通知已生效,无法删除"),
     ILLEGAL_Gender(600007, "无效性别"),
     ILLEGAL_MARRIAGE(600008, "婚姻状态无效"),
     NOT_EXISTS_SUBJECT(60005, "科目<u>%s</u>不存在");

+ 1 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/CurriculumMapper.java

@@ -91,6 +91,7 @@ public interface CurriculumMapper {
      * @return
      */
     int updateByPublish(Long id);
+    int updateByPublishFrom(Long id);
 
     /**
      * 取消发布

+ 2 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/HomeWorkMapper.java

@@ -32,4 +32,6 @@ public interface HomeWorkMapper {
      * @return
      */
     int taskStatus(@Param("task_status") String task_status,@Param("task_id") Long task_id);
+
+    Integer homeWorkRelease(Long id);
 }

+ 2 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysClazzMapper.java

@@ -34,4 +34,6 @@ public interface SysClazzMapper {
     List<SysClazz> selectByClazz(@Param("condition") String condition, @Param("school_id") Long schoolId);
 
     int countClazz(@Param("clazz_name") String clazz_name, @Param("clazz_grade") String clazz_grade, @Param("school_id") Long school_id);
+
+    Integer teacherClazz(@Param("subject_name") String subject_name,@Param("teacher_id") Long teacher_id );
 }

+ 2 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysStudentMapper.java

@@ -57,6 +57,8 @@ public interface SysStudentMapper {
 
     Integer checkCurriculum(Long id);
 
+    Integer repeatCurriculum(Long id);
+
     /**
      * 学生信息:学号重复
      * @return

+ 0 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysTeacherMapper.java

@@ -41,7 +41,5 @@ public interface SysTeacherMapper {
 
     int checkTeacher(@Param("teacher_id") Long teacher_id);
 
-    Integer checkTeacherSubjects(@Param("clazz_id") Long clazz_id);
-
     void deleteDetail(@Param("teacher_clazz_id") Long teacher_clazz_id);
 }

+ 5 - 0
applications/school/school-server/src/main/resources/mapper/CurriculumMapper.xml

@@ -269,6 +269,11 @@
       createTime = now()
     where id = #{id,jdbcType=BIGINT}
   </update>
+  <update id="updateByPublishFrom" parameterType="java.lang.Long">
+    update clazz_curriculum
+    set clazz_curriculum.cur_status = 1
+    where cur_mid = #{id,jdbcType=BIGINT}
+  </update>
 
   <update id="updateByRepublish" parameterType="java.lang.Long">
     update clazz_main_curriculum

+ 5 - 0
applications/school/school-server/src/main/resources/mapper/HomeWorkMapper.xml

@@ -258,4 +258,9 @@
             </if>
         </where>
     </select>
+
+    <select id="homeWorkRelease" parameterType="long" resultType="integer">
+      select count(1) from sys_clazz left join task_notify on sys_clazz.clazz_name=task_notify.classz_name
+      where sys_clazz.clazz_id = #{id} and task_notify.task_status=1
+  </select>
 </mapper>

+ 12 - 0
applications/school/school-server/src/main/resources/mapper/SysClazzMapper.xml

@@ -248,4 +248,16 @@
     </where>
   </select>
 
+  <select id="teacherClazz" resultType="int">
+    select count(*) from sys_teacher_clazz
+    <where>
+      <if test="subject_name != null">
+        subject_name=#{subject_name}
+      </if>
+        <if test="teacher_id != null">
+            and teacher_id=#{teacher_id}
+        </if>
+    </where>
+  </select>
+
 </mapper>

+ 4 - 9
applications/school/school-server/src/main/resources/mapper/SysStudentMapper.xml

@@ -458,6 +458,10 @@
     select count(1) from clazz_curriculum where clazz_id = #{id}
   </select>
 
+  <select id="repeatCurriculum" parameterType="long" resultType="integer">
+    select count(1) from clazz_curriculum where clazz_id = #{id} and clazz_curriculum.cur_status=1
+  </select>
+
   <select id="count" resultType="int">
     select count(*) from sys_student
     <where>
@@ -476,15 +480,6 @@
     where stu_number = #{stu_number,jdbcType=VARCHAR}
   </select>
 
-  <select id="countStudent" resultType="Integer">
-    select count(*) from sys_student
-    <where>
-      <if test="clazz_id != null">
-         clazz_id=#{clazz_id}
-      </if>
-    </where>
-  </select>
-
   <select id="selectIdByClazzId" resultType="string" parameterType="long">
     SELECT stu_id FROM sys_student WHERE clazz_id = #{clazzId}
   </select>

+ 1 - 1
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/ReceiveService.java

@@ -63,7 +63,7 @@ public class ReceiveService {
         for (MessageInfo msg : data) {
             if (!msg.getSend()) {
                 //处理openid,如果不存在openid,则直接忽略
-                getOpenId(msg);
+                //getOpenId(msg);
                 result = wxPushService.wechatPush(msg);
                 if (result.isSuccess()) {
                     msg.setSend(true);

+ 1 - 1
applications/wechat/wechat-server/src/main/resources/config/application-docker-cloud.yml

@@ -22,7 +22,7 @@ spring:
         max-lifetime: 1800000
         connection-timeout: 30000
   rabbitmq:
-      host: 127.0.0.1
+      host: 132.232.174.14
       port: 5672
       virtual-host: school
       username: saas

+ 24 - 5
applications/wechat/wechat-server/src/main/resources/config/application-docker-test.yml

@@ -1,12 +1,31 @@
 eureka:
   instance:
-    hostname: saas-sale-server-test
+    hostname: smartschool-wechat-server
     prefer-ip-address: false
   client:
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-test:8515/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/
 spring:
+  redis:
+    host: 172.27.0.13
+    port: 6379
+    password: select111***
+  datasource:
+      driver-class-name: com.mysql.jdbc.Driver
+      url: jdbc:mysql://172.27.0.15:3306/smart_campus?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
+      username: root
+      password: select111***
+      hikari:
+        minimum-idle: 5
+        maximum-pool-size: 50
+        idle-timeout: 30000
+        max-lifetime: 1800000
+        connection-timeout: 30000
   rabbitmq:
-    virtual-host: test
-server:
-  port: 8835
+      host: 127.0.0.1
+      port: 5672
+      virtual-host: school
+      username: saas
+      password: select123***
+      publisher-returns: true
+      publisher-confirms: true

+ 30 - 0
applications/wechat/wechat-server/src/test/java/com/usoftchina/smartschool/wechat/Test_service.java

@@ -42,6 +42,8 @@ public class Test_service {
         sendService.sendMessage(msg);
     }
 
+
+
     @Test
     public void testb_sendDelayMsg() {
         MessageInfo msg = new MessageInfo();
@@ -60,5 +62,33 @@ public class Test_service {
         sendService.sendDelayMessage(mp);
     }
 
+    @Test
+    public void testc_sendOUtMsg() {
+        MessageInfoDTO msg = new MessageInfoDTO();
+        msg.setAppId("wxbc1f8607137d3b8a");
+        msg.setSecret("cadf13c4e21c2c122cb2341b341e5c22");
+        msg.setTouser("o8lZ9uGFfByUEGOk-xMwmajgmjt4");
+        msg.setTemplateId(TEMPLATEID);
+        msg.setTitle("出入校提醒");
+        msg.setKeyword1("小黄");
+        msg.setKeyword2(DateUtils.format());
+        msg.setRemark("您好! 你的孩子: 小黄已经进入校园");
+       // List
+        //sendService.sendOutMessages(msg);
+    }
+
+    @Test
+    public void testd_wechatapi() {
+        MessageInfoDTO msg = new MessageInfoDTO();
+        msg.setAppId("wxbc1f8607137d3b8a");
+        msg.setSecret("cadf13c4e21c2c122cb2341b341e5c22");
+        msg.setTouser("o8lZ9uGFfByUEGOk-xMwmajgmjt4");
+        msg.setTemplateId(TEMPLATEID);
+        msg.setTitle("出入校提醒");
+        msg.setKeyword1("小黄");
+        msg.setKeyword2(DateUtils.format());
+        msg.setRemark("您好! 你的孩子: 小黄已经进入校园");
+        //sendService.sendOutMessages(msg);
+    }
 
 }

+ 2 - 2
frontend/pc-web/app/util/BaseUtil.js

@@ -52,8 +52,8 @@ Ext.define('school.util.BaseUtil', {
         refreshTabTitle: function (id, title) {
             var currentTab = this.getCurrentTab();
             currentTab.tabId = id;
-            currentTab.setTitle(title);
-            currentTab.setTooltip(title);
+            currentTab.tab.setText(title);
+            currentTab.tab.setTooltip(title);
         },
 
         /**

+ 20 - 15
frontend/pc-web/app/view/Interaction/homework/List.js

@@ -141,21 +141,26 @@ Ext.define('school.view.interaction.homework.List', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.47:9560/teacher/batchDelete',
-                            url: '/api/school/homework/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function (res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function (e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.47:9560/teacher/batchDelete',
+                                    url: '/api/school/homework/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function (res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function (e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],

+ 20 - 15
frontend/pc-web/app/view/Interaction/notice/List.js

@@ -109,21 +109,26 @@ Ext.define('school.view.interaction.notice.List', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.47:9560/teacher/batchDelete',
-                            url: '/api/school/notice/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function (res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function (e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.47:9560/teacher/batchDelete',
+                                    url: '/api/school/notice/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function (res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function (e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],

+ 52 - 22
frontend/pc-web/app/view/Interaction/score/List.js

@@ -51,15 +51,32 @@ Ext.define('school.view.interaction.score.List', {
             }, {
                 xtype: 'textfield',
                 name: 'keyword',
-                fieldLabel: '学',
+                fieldLabel: '学号/姓名',
                 getCondition: function (value) {
-                    return ' (sd_stu like\'%' + value + '%\') ';
+                    return ' (sd_stu like\'%' + value + '%\' or sd_stunumber like \'%' + value + '%\') ';
                 }
             }, {
                 xtype: 'condatefield',
                 name: 'si_examdate',
                 fieldLabel: '考试时间',
                 columnWidth: 0.5
+            }, {
+                xtype: 'combobox',
+                name: 'si_publish',
+                fieldLabel: '发布状态',
+                displayField: 'name',
+                valueField: 'value',
+                editable: false,
+                clearable: true,
+                store: Ext.create('Ext.data.ArrayStore', {
+                    fields: ['name', 'value'],
+                    data: [
+                        ['已发布', 1],
+                        ['未发布', 0]
+                    ]
+                }),
+                minChars: 0,
+                queryMode: 'local'
             }],
 
             gridConfig: {
@@ -113,21 +130,26 @@ Ext.define('school.view.interaction.score.List', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.47:9520/api/school/score/batchDelete',
-                            url: '/api/school/score/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function(res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function(e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.47:9520/api/school/score/batchDelete',
+                                    url: '/api/school/score/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function(res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function(e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],
@@ -148,15 +170,23 @@ Ext.define('school.view.interaction.score.List', {
                     dataIndex: 'si_examscope'
                 }, {
                     text: '年级',
-                    dataIndex: 'si_grade'
+                    dataIndex: 'si_grade',
+                    width: 120
                 }, {
                     text: '班级',
-                    dataIndex: 'si_class'
+                    dataIndex: 'si_class',
+                    width: 120
+                }, {
+                    text: '发布状态',
+                    dataIndex: 'si_publish',
+                    renderer: function(v) {
+                        return v == 1 ? '已发布' : '未发布'
+                    }
                 }],
                 supColumns: [{
-                //     text: '学生编号',
-                //     dataIndex: ''
-                // }, {
+                    text: '学生编号',
+                    dataIndex: 'sd_stunumber'
+                }, {
                     text: '学生姓名',
                     dataIndex: 'sd_stu'
                 }, {

+ 35 - 10
frontend/pc-web/app/view/Interaction/timetable/Detail.js

@@ -3,6 +3,7 @@ Ext.define('school.view.interaction.timetable.Detail', {
     xtype: 'interaction-timetable-detail',
 
     controller: 'interaction-timetable-detail',
+    viewModel: 'interaction-timetable-detail',
 
     _title: '课程表',
     _idField: 'id',
@@ -33,7 +34,11 @@ Ext.define('school.view.interaction.timetable.Detail', {
             }, {
                 xtype: 'textfield',
                 name: 'name',
-                fieldLabel: '课表名称'
+                fieldLabel: '课表名称',
+                emptyText: '请选择年级',
+                bind: {
+                    emptyText: '{name_emptyText}'
+                }
             }, {
                 xtype: 'numberfield',
                 name: 'gradeId',
@@ -46,9 +51,10 @@ Ext.define('school.view.interaction.timetable.Detail', {
                 allowBlank: false,
                 listeners: {
                     select: function (combo, record, eOpts) {
-                        combo.up('form').getForm().findField('gradeId').setValue(record.get('grade_id'));
-                        combo.up('form').getForm().findField('clazzId').setValue(null);
-                        combo.up('form').getForm().findField('clazzName').setValue(null);
+                        let viewModel = me.getViewModel();
+                        viewModel.set('gradeId', record.get('grade_id'));
+                        viewModel.set('clazzId', null);
+                        viewModel.set('clazzName', null);
                     }
                 }
             }, {
@@ -78,9 +84,10 @@ Ext.define('school.view.interaction.timetable.Detail', {
                         }
                     },
                     select: function (combo, record, eOpts) {
-                        combo.up('form').getForm().findField('clazzId').setValue(record.get('clazz_id'));
-                        combo.up('form').getForm().findField('gradeId').setValue(record.get('grade_id'));
-                        combo.up('form').getForm().findField('gradeName').setValue(record.get('clazz_grade'));
+                        let viewModel = me.getViewModel();
+                        viewModel.set('clazzId', record.get('clazz_id'));
+                        viewModel.set('gradeId', record.get('grade_id'));
+                        viewModel.set('gradeName', record.get('clazz_grade'));
                     }
                 }
             }, {
@@ -126,9 +133,17 @@ Ext.define('school.view.interaction.timetable.Detail', {
                     data: [['第一学期'], ['第二学期']]
                 }),
                 defaultValue: (function() {
-                    let now = new Date();
-                    let month = now.getMonth() + 1;
-                    return (month < 9) ? '第一学期' : '第二学期'
+                    let now = new Date(),
+                    month = now.getMonth() + 1,
+                    date = now.getDate(),
+                    term;
+
+                    if((month > 2 && month < 8) || (month == 2 && date > 15) || (month == 8 && date < 15)) {
+                        term = '第二学期';
+                    }else {
+                        term = '第一学期'
+                    }
+                    return term;
                 })()
             }, {
                 xtype: "textfield",
@@ -371,6 +386,16 @@ Ext.define('school.view.interaction.timetable.Detail', {
         this.callParent();
     },
 
+    listeners: {
+        beforeSave: function(form) {
+            let nameField = form.getForm().findField('name');
+            if(!nameField.value) {
+                nameField.setValue(nameField.emptyText);
+            }
+            return true;
+        }
+    },
+
     onSelectPeriod0: function(picker, menu, record) {
         let me = this;
         let cRecord = me.currentRecord;

+ 30 - 0
frontend/pc-web/app/view/Interaction/timetable/DetailModel.js

@@ -0,0 +1,30 @@
+Ext.define('school.view.interaction.timetable.DetailModel', {
+    extend: 'school.view.core.form.FormPanelModel',
+    alias: 'viewmodel.interaction-timetable-detail',
+
+    formulas: {
+        name_emptyText: function(get) {
+            let gradeName = get('gradeName'),
+            clazzName = get('clazzName'),
+            termPart = get('termPart'),
+            termName = get('termName'),
+            text;
+
+            if(!!gradeName && !!clazzName && !!termPart && !!termName) {
+                text =  gradeName + clazzName + termPart.split('-')[0] + '学年' + termName + '课表';
+                // this.set('name', text);
+            }else if(!gradeName) {
+                text = '请选择年级';
+            }else if(!clazzName) {
+                text = '请选择班级';
+            }else if(!termPart) {
+                text = '请选择学年';
+            }else if(!termName) {
+                text = '请选择学期';
+            }
+
+            return text;
+        }
+    }
+
+});

+ 54 - 18
frontend/pc-web/app/view/Interaction/timetable/List.js

@@ -96,10 +96,35 @@ Ext.define('school.view.interaction.timetable.List', {
                     data: [['第一学期'], ['第二学期']]
                 }),
                 value: (function() {
-                    let now = new Date();
-                    let month = now.getMonth() + 1;
-                    return (month < 9) ? '第一学期' : '第二学期'
+                    let now = new Date(),
+                    month = now.getMonth() + 1,
+                    date = now.getDate(),
+                    term;
+
+                    if((month > 2 && month < 8) || (month == 2 && date > 15) || (month == 8 && date < 15)) {
+                        term = '第二学期';
+                    }else {
+                        term = '第一学期'
+                    }
+                    return term;
                 })()
+            }, {
+                xtype: 'combobox',
+                name: 'status',
+                fieldLabel: '发布状态',
+                displayField: 'name',
+                valueField: 'value',
+                editable: false,
+                clearable: true,
+                store: Ext.create('Ext.data.ArrayStore', {
+                    fields: ['name', 'value'],
+                    data: [
+                        ['已生效', 1],
+                        ['未生效', 0]
+                    ]
+                }),
+                minChars: 0,
+                queryMode: 'local'
             }],
         
             gridConfig: {
@@ -154,21 +179,26 @@ Ext.define('school.view.interaction.timetable.List', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.36:9520/api/school/curriculum/batchDelete',
-                            url: '/api/school/curriculum/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function (res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function (e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.36:9520/api/school/curriculum/batchDelete',
+                                    url: '/api/school/curriculum/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function (res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function (e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],
@@ -202,6 +232,12 @@ Ext.define('school.view.interaction.timetable.List', {
                     text: '学期',
                     dataIndex: 'termName',
                     width: 120
+                }, {
+                    text: '状态',
+                    dataIndex: 'status',
+                    renderer: function(v) {
+                        return v == '1' ? '已生效' : '未生效'
+                    }
                 }]
             },
         });

+ 1 - 1
frontend/pc-web/app/view/auth/Login.js

@@ -43,7 +43,7 @@ Ext.define('school.view.auth.Login', {
                 {
                     xtype: 'component',
                     height: 50,
-                    html:'<div class="auth-title"><img class="x-logo-text" style="" src="resources/images/zhihuixiaoyuan.png" alt=""><div>',
+                    html:'<div class="auth-title"><img class="x-logo-text" style="" src="resources/images/login-text-img.png" alt=""><div>',
                 },
                 {
                     xtype: 'label',

+ 2 - 1
frontend/pc-web/app/view/basic/class/ClassDetail.js

@@ -116,6 +116,7 @@ Ext.define('school.view.basic.class.ClassDetail', {
                 idColumn: 'teacher_clazz_id',
                 detnoColumn: 'no',
                 storeModel: 'school.model.basic.Subject',
+                // deleteDetailUrl: 'http://10.1.80.180:9520/api/school/class/deleteDetail',
                 deleteDetailUrl: '/api/school/class/deleteDetail',
                 allowEmpty: true,
                 showCount: false,
@@ -132,7 +133,7 @@ Ext.define('school.view.basic.class.ClassDetail', {
                         xtype: 'textfield'
                     }
                     /**
-                     * TODO 未写入id
+                     * TODO 未写入学科id
                      */
                 }, {
                     text: '学科',

+ 20 - 15
frontend/pc-web/app/view/basic/staff/StaffList.js

@@ -77,21 +77,26 @@ Ext.define('school.view.basic.staff.StaffList', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.47:9560/teacher/batchDelete',
-                            url: '/api/school/teacher/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function (res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function (e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.47:9560/teacher/batchDelete',
+                                    url: '/api/school/teacher/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function (res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function (e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],

+ 20 - 15
frontend/pc-web/app/view/basic/student/StudentList.js

@@ -115,21 +115,26 @@ Ext.define('school.view.basic.student.StudentList', {
                             return;
                         }
 
-                        grid.setLoading(true);
-                        school.util.BaseUtil.request({
-                            // url: 'http://10.1.80.47:9560/student/batchDelete',
-                            url: '/api/school/student/batchDelete',
-                            method: 'POST',
-                            params: JSON.stringify({
-                                baseDTOs: data
-                            })
-                        }).then(function(res) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
-                            grid.store.loadPage(grid.store.currentPage);
-                        }).catch(function(e) {
-                            grid.setLoading(false);
-                            school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                        school.util.BaseUtil.showConfirm('确认删除', '确定要删除这' + data.length + '条记录吗?')
+                        .then(function(yes) {
+                            if(yes == 'yes') {
+                                grid.setLoading(true);
+                                school.util.BaseUtil.request({
+                                    // url: 'http://10.1.80.47:9560/student/batchDelete',
+                                    url: '/api/school/student/batchDelete',
+                                    method: 'POST',
+                                    params: JSON.stringify({
+                                        baseDTOs: data
+                                    })
+                                }).then(function(res) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showSuccessToast('成功删除' + data.length + '条记录');
+                                    grid.store.loadPage(grid.store.currentPage);
+                                }).catch(function(e) {
+                                    grid.setLoading(false);
+                                    school.util.BaseUtil.showErrorToast('删除失败: ' + e.message);
+                                });
+                            }
                         });
                     }
                 }],

+ 0 - 16
frontend/pc-web/app/view/core/form/FormPanel.js

@@ -489,22 +489,6 @@ Ext.define('school.view.core.form.FormPanel', {
         return dirtyData;
     },
 
-    beforeSave: function() {
-        return true;
-    },
-
-    beforeDelete: function() {
-        return true;
-    },
-
-    beforeAudit: function() {
-        return true;
-    },
-
-    beforeUnAudit: function() {
-        return true;
-    },
-
     promiseCloseTab: function() {
         let me = this,
         controller = me.getController();

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

@@ -116,7 +116,7 @@ Ext.define('school.view.core.form.FormPanelController', {
         var code = viewModel.get(form._codeField);
         if(id&&id.value!=0){
 
-            if(!form.beforeDelete()) {
+            if(form.fireEvent('beforeDelete', form) == false) {
                 return false;
             }
 
@@ -157,7 +157,7 @@ Ext.define('school.view.core.form.FormPanelController', {
             return false;
         }
 
-        if(!form.beforeSave()) {
+        if(form.fireEvent('beforeSave', form) == false) {
             return false;
         }
 
@@ -254,7 +254,7 @@ Ext.define('school.view.core.form.FormPanelController', {
             return false;
         }
 
-        if(!form.beforeAudit()) {
+        if(form.fireEvent('beforeAudit', form) == false) {
             return false;
         }
 
@@ -342,7 +342,7 @@ Ext.define('school.view.core.form.FormPanelController', {
         var code = viewModel.get(form._codeField);
         if(id&&id.value!=0){
 
-            if(!form.beforeUnAudit()) {
+            if(form.fireEvent('beforeUnAudit', form)) {
                 return false;
             }
 
@@ -447,7 +447,7 @@ Ext.define('school.view.core.form.FormPanelController', {
         id = viewModel.get(form._idField),
         code = viewModel.get(form._codeField);
 
-        me.beforePrint(caller).then(function(flag) {
+        me.checkPrintAccess(caller).then(function(flag) {
             if(!flag) {
                 return false;
             }
@@ -484,7 +484,7 @@ Ext.define('school.view.core.form.FormPanelController', {
     /**
      * 判断权限
      */
-    beforePrint: function(caller) {
+    checkPrintAccess: function(caller) {
         return school.util.BaseUtil.request({
             url: '/api/commons/' + caller + '/print',
             method: 'GET',

+ 1 - 1
frontend/pc-web/app/view/main/Main.js

@@ -30,7 +30,7 @@ Ext.define('school.view.main.Main', {
                     xtype: 'component',
                     reference: 'mainLogo',
                     cls: 'main-logo-wrap',
-                    html: '<div class="main-logo"><img src="resources/images/default/logo-default.png"/><div class="logo-text">智慧校园</div></div>',
+                    html: '<div class="main-logo"><img src="resources/images/default/logo-default.png"/><div class="logo-text">云平安校园</div></div>',
                     bind: {
                         width: '{navWidth}'
                     }

+ 8 - 8
frontend/pc-web/app/view/main/Main.scss

@@ -79,21 +79,21 @@ $treelist-nav-ui: (
         background: #34BAF6;
 
         img {
-            width: 32px;
-            height: 32px;
-            top: 8px;
-            left: 28px;
+            width: 45px;
+            height: 30px;
+            top: 10px;
+            left: 10px;
             position: relative;
         }
 
         .logo-text {
-            // font-family: 'pingFangSC-Regular';
             font-size: 18px;
-            color: #FFFFFF;
+            color: #fff;
             text-align: left;
-            top: 22px;
+            top: 16px;
             position: absolute;
-            left: 64px;
+            left: 60px;
+            white-space: nowrap;
         }
     }
 }

+ 2 - 2
frontend/pc-web/app/view/main/MainController.js

@@ -14,10 +14,10 @@ Ext.define('school.view.main.MainController', {
         navigationList = refs.navigationTreeList,
         navCollapsed = !navigationList.navCollapsed,
         new_width = navCollapsed ? viewModel.get('smallNavWidth') : viewModel.get('navWidth'),
-        newLogoImgStyle = navCollapsed ? { width: 36, height: 36, top: 6, left: 12 } : { width: 32, height: 32, top: 8, left: 28 },
+        newLogoImgStyle = navCollapsed ? { width: 51, height: 32, top: 8, left: 6 } : { width: 45, height: 30, top: 10, left: 10 },
         newLogoTextStyle = navCollapsed ? {
             0: { opacity: 0 },
-            100: { opacity: 0, display: 'none' }
+            70: { opacity: 0 }
         } : {
             10: { opacity: 0 },
             90: { opacity: 1 }

+ 1 - 1
frontend/pc-web/index.html

@@ -6,7 +6,7 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=10, user-scalable=yes">
 
-    <title>智慧校园</title>
+    <title>云平安校园</title>
     <link rel="icon" href="./resources/images/favicon.png" type="image/x-icon">
     <!-- The line below must be kept intact for Sencha Cmd to build your application -->
     <script id="microloader" data-app="a20e1670-7932-41f6-8e9c-55b77cba3f26" type="text/javascript" src="bootstrap.js"></script>

BIN
frontend/pc-web/resources/images/auth-background.jpg


BIN
frontend/pc-web/resources/images/default/logo-default.png


BIN
frontend/pc-web/resources/images/favicon.png


BIN
frontend/pc-web/resources/images/login-text-img.png


BIN
frontend/pc-web/resources/images/zhihuixiaoyuan.png