Browse Source

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

FANGLH 6 years ago
parent
commit
80d0ac733a
93 changed files with 2765 additions and 561 deletions
  1. 18 0
      applications/device/device-server/pom.xml
  2. 6 0
      applications/device/device-server/src/main/docker/Dockerfile
  3. 35 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/controller/DeviceController.java
  4. 41 4
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/listener/AccessControlListener.java
  5. 18 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/mapper/DeviceMapper.java
  6. 81 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/Device.java
  7. 63 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/ImageFile.java
  8. 16 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/DeviceService.java
  9. 79 0
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/DeviceServiceImpl.java
  10. 74 1
      applications/device/device-server/src/main/resources/application.yml
  11. 23 0
      applications/device/device-server/src/main/resources/config/application-docker-cloud.yml
  12. 15 0
      applications/device/device-server/src/main/resources/config/application-docker-prod.yml
  13. 110 0
      applications/device/device-server/src/main/resources/mapper/DeviceMapper.xml
  14. 14 0
      applications/school/school-api/pom.xml
  15. 14 0
      applications/school/school-api/src/main/java/com/usoftchina/smartschool/school/api/SchoolApi.java
  16. 110 0
      applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/dto/SysSchoolDTO.java
  17. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/controller/SchoolController.java
  18. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/SchoolService.java
  19. 5 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/CurriculumServiceImpl.java
  20. 3 4
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/GradeServiceImpl.java
  21. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolServiceImpl.java
  22. 18 7
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/TeacherServiceImpl.java
  23. 0 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/controller/ScoreController.java
  24. 10 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java
  25. 10 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java
  26. 3 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/common/service/impl/ExcelServiceImpl.java
  27. 5 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  28. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/CurriculumMapper.java
  29. 6 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/HomeWorkMapper.java
  30. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/NoticeMapper.java
  31. 1 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysClazzMapper.java
  32. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysSchoolMapper.java
  33. 1 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysTeacherMapper.java
  34. 10 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SysSchool.java
  35. 4 0
      applications/school/school-server/src/main/resources/mapper/CurriculumMapper.xml
  36. 12 0
      applications/school/school-server/src/main/resources/mapper/HomeWorkMapper.xml
  37. 5 0
      applications/school/school-server/src/main/resources/mapper/MessagelogMapper.xml
  38. 4 0
      applications/school/school-server/src/main/resources/mapper/NotifyMapper.xml
  39. 3 0
      applications/school/school-server/src/main/resources/mapper/SysClazzMapper.xml
  40. 5 0
      applications/school/school-server/src/main/resources/mapper/SysSchoolMapper.xml
  41. 1 1
      applications/school/school-server/src/main/resources/mapper/SysStudentMapper.xml
  42. 2 2
      applications/school/school-server/src/main/resources/mapper/SysTeacherMapper.xml
  43. 2 0
      applications/wechat/pom.xml
  44. 44 0
      applications/wechat/wechat-auth/pom.xml
  45. 18 0
      applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/EnableOpenApiAuthClient.java
  46. 12 0
      applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/annotation/IgnoreOpenApiAuth.java
  47. 49 0
      applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/configuration/OpenApiConfig.java
  48. 31 0
      applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/configuration/OpenApiConfiguration.java
  49. 110 0
      applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/interceptor/OpenApiAuthInterceptor.java
  50. 15 0
      applications/wechat/wechat-dto/pom.xml
  51. 30 0
      applications/wechat/wechat-dto/src/main/java/com/usoftchina/smartschool/wechat/constant/Status.java
  52. 162 0
      applications/wechat/wechat-dto/src/main/java/com/usoftchina/smartschool/wechat/dto/MessageInfoDTO.java
  53. 14 9
      applications/wechat/wechat-server/pom.xml
  54. 4 28
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/WechatApplication.java
  55. 26 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/config/ExpirationMessagePostProcessor.java
  56. 73 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/config/RabbitConfig.java
  57. 63 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/controller/TransfersController.java
  58. 2 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/controller/WxPushController.java
  59. 34 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/mapper/BrokerMessageLogMapper.java
  60. 26 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/BrokerMessagelog.java
  61. 58 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/MessageInfo.java
  62. 35 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/MessagePackage.java
  63. 95 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/ReceiveService.java
  64. 148 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/SendService.java
  65. 3 0
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/WxPushService.java
  66. 48 2
      applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/impl/WxPushServiceImpl.java
  67. 16 5
      applications/wechat/wechat-server/src/main/resources/application.yml
  68. 0 125
      applications/wechat/wechat-server/src/main/resources/logback-spring.xml
  69. 128 0
      applications/wechat/wechat-server/src/main/resources/mapper/BrokermessagelogMapper.xml
  70. 6 0
      base-servers/gateway-server/src/main/resources/application.yml
  71. 0 131
      base-servers/gateway-server/src/main/resources/logback-spring.xml
  72. 2 1
      framework/core/src/main/java/com/usoftchina/smartschool/exception/ExceptionCode.java
  73. 2 1
      frontend/pc-web/app/Application.js
  74. 47 0
      frontend/pc-web/app/store/GradeClass.js
  75. 7 0
      frontend/pc-web/app/view/Interaction/homework/Release.js
  76. 31 0
      frontend/pc-web/app/view/Interaction/score/Detail.js
  77. 23 0
      frontend/pc-web/app/view/Interaction/score/DetailController.js
  78. 4 4
      frontend/pc-web/app/view/Interaction/score/List.js
  79. 139 134
      frontend/pc-web/app/view/Interaction/timetable/Detail.js
  80. 1 1
      frontend/pc-web/app/view/Interaction/timetable/List.js
  81. 10 4
      frontend/pc-web/app/view/basic/class/ClassInfo.js
  82. 9 3
      frontend/pc-web/app/view/basic/class/ClassInfoController.js
  83. 1 2
      frontend/pc-web/app/view/basic/class/ListCard.js
  84. 0 9
      frontend/pc-web/app/view/basic/class/ListCardController.js
  85. 1 0
      frontend/pc-web/app/view/basic/subject/List.js
  86. 25 29
      frontend/pc-web/app/view/basic/subject/ListController.js
  87. 90 0
      frontend/pc-web/app/view/setting/device/List.js
  88. 246 0
      frontend/pc-web/app/view/setting/device/ListController.js
  89. 0 41
      frontend/pc-web/app/view/viewport/ViewportModel.js
  90. 1 1
      frontend/pc-web/overrides/form/field/Text.js
  91. 5 0
      frontend/pc-web/overrides/form/field/TextArea.js
  92. 2 2
      frontend/pc-web/resources/json/navigation.json
  93. 16 1
      pom.xml

+ 18 - 0
applications/device/device-server/pom.xml

@@ -28,6 +28,24 @@
             <groupId>com.usoftchina.smartschool</groupId>
             <artifactId>file-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <!-- db -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>school-dto</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper</artifactId>
+            <version>RELEASE</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 6 - 0
applications/device/device-server/src/main/docker/Dockerfile

@@ -0,0 +1,6 @@
+FROM frolvlad/alpine-oraclejdk8:slim
+VOLUME /tmp
+ADD device-server-1.0.0-SNAPSHOT.jar app.jar
+RUN sh -c 'touch /app.jar'
+ENV JAVA_OPTS=""
+ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

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

@@ -1,9 +1,44 @@
 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();
+    }
+
 }

+ 41 - 4
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/listener/AccessControlListener.java

@@ -1,15 +1,28 @@
 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.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.service.DeviceService;
 import com.usoftchina.smartschool.file.api.FileApi;
+import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+import com.usoftchina.smartschool.utils.StringUtils;
+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.util.ArrayList;
 import java.util.List;
 
 /**
@@ -19,12 +32,17 @@ import java.util.List;
 @Component
 public class AccessControlListener implements InitializingBean{
 
-    @Autowired
-    private FileApi fileApi;
+    /*@Autowired
+    private FileApi fileApi;*/
 
     @Autowired
     private DeviceApi deviceApi;
 
+    @Autowired
+    private DeviceMapper deviceMapper;
+
+    private Logger logger = LoggerFactory.getLogger(AccessControlListener.class);
+
     /**
      * 门禁事件
      *
@@ -35,14 +53,33 @@ public class AccessControlListener implements InitializingBean{
     public void onAccessControlEvent(AccessControlEvent event) {
         /**
          * 1、保存图片文件;
+         */
+        byte[] imageData = event.getAccessControlInfo().getImageData();
+        MultipartFile file = new ImageFile(imageData, "测试");
+        Result<FileInfoDTO> fileInfo = null;
+        try {
+           // fileInfo = fileApi.upload(0l, file);
+        }catch (Exception ex) {
+        }
+        /**
          * 2、保存门禁出入记录;
+         */
+        Long fileId = fileInfo.getData().getId();
+
+        logger.info(event.getAccessControlInfo().getCardNo());
+        /**
          * 3、推送消息到消息服务器(微信服务监听此消息发送微信消息)
          */
+
     }
 
     @Override
     public void afterPropertiesSet() throws Exception {
-        List<DeviceInfo> deviceInfos = null;
-        deviceInfos.forEach(deviceApi::add);
+        List<DeviceInfo> devices = deviceMapper.findAll();
+        devices.forEach(device -> {
+            if (!StringUtils.isEmpty(device.getUsername())) {
+                deviceApi.add(device);
+            }
+        });
     }
 }

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

@@ -1,8 +1,26 @@
 package com.usoftchina.smartschool.device.mapper;
 
+import com.usoftchina.smartschool.device.dto.DeviceInfo;
+import com.usoftchina.smartschool.device.po.Device;
+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);
 }

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

@@ -0,0 +1,81 @@
+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;
+    }
+}

+ 63 - 0
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/ImageFile.java

@@ -0,0 +1,63 @@
+package com.usoftchina.smartschool.device.po;
+
+import org.springframework.lang.Nullable;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+
+/**
+ * @author: guq
+ * @create: 2019-03-08 16:42
+ **/
+public class ImageFile implements MultipartFile{
+
+    private final byte[] imgContent;
+    private final String header;
+
+    public ImageFile(byte[] imgContent, String header) {
+        this.imgContent = imgContent;
+        this.header = header.split(";")[0];
+    }
+
+    @Override
+    public String getName() {
+        return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
+    }
+
+    @Nullable
+    @Override
+    public String getOriginalFilename() {
+        return System.currentTimeMillis() + (int)Math.random() * 10000 + "." + header.split("/")[1];
+    }
+
+    @Nullable
+    @Override
+    public String getContentType() {
+        return header.split(":")[1];
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return imgContent == null || imgContent.length == 0;
+    }
+
+    @Override
+    public long getSize() {
+        return imgContent.length;
+    }
+
+    @Override
+    public byte[] getBytes() throws IOException {
+        return imgContent;
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(imgContent);
+    }
+
+    @Override
+    public void transferTo(File dest) throws IOException, IllegalStateException {
+        new FileOutputStream(dest).write(imgContent);
+    }
+}

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

@@ -0,0 +1,16 @@
+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);
+}

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

@@ -0,0 +1,79 @@
+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);
+    }
+}

+ 74 - 1
applications/device/device-server/src/main/resources/application.yml

@@ -1,4 +1,77 @@
 device:
   dahua:
     wait-time: 5000
-    connect-time: 10000
+    connect-time: 10000
+spring:
+  application:
+    name: device-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://10.10.100.166: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
+  messages:
+    basename: i18n/messages
+    encoding: UTF-8
+  servlet:
+    multipart:
+      max-file-size: 100Mb
+      max-request-size: 100Mb
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: always
+server:
+  port: 9620
+  tomcat:
+    uri-encoding: UTF-8
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+ribbon:
+  ReadTimeout: 10000
+  ConnectTimeout: 10000
+feign:
+  hystrix:
+    enabled: true
+hystrix:
+    command:
+        default:
+            execution:
+              timeout:
+                enabled: true
+              isolation:
+                    thread:
+                        timeoutInMilliseconds: 4000
+mybatis:
+  type-aliases-package: com.usoftchina.smartschool.device.po
+  mapper-locations: classpath:mapper/*.xml

+ 23 - 0
applications/device/device-server/src/main/resources/config/application-docker-cloud.yml

@@ -0,0 +1,23 @@
+eureka:
+  instance:
+    hostname: smartschool-device-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      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

+ 15 - 0
applications/device/device-server/src/main/resources/config/application-docker-prod.yml

@@ -0,0 +1,15 @@
+eureka:
+  instance:
+    hostname: smartschool-device-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/
+spring:
+  datasource:
+    url: jdbc:mysql://10.10.100.166:3306/smart_campus?characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
+    username: root
+    password: select111***
+  redis:
+    host: 10.10.100.166
+    port: 6379

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

@@ -0,0 +1,110 @@
+<?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 ktest="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>
+
+</mapper>

+ 14 - 0
applications/school/school-api/pom.xml

@@ -12,4 +12,18 @@
     <artifactId>school-api</artifactId>
 
 
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>school-dto</artifactId>
+        </dependency>
+    </dependencies>
 </project>

+ 14 - 0
applications/school/school-api/src/main/java/com/usoftchina/smartschool/school/api/SchoolApi.java

@@ -0,0 +1,14 @@
+package com.usoftchina.smartschool.school.api;
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.school.dto.SysSchoolDTO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@FeignClient("school-server")
+public interface SchoolApi {
+
+    @GetMapping("/find")
+    public Result<SysSchoolDTO> find(@RequestParam("schoolName") String schoolName);
+}

+ 110 - 0
applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/dto/SysSchoolDTO.java

@@ -0,0 +1,110 @@
+package com.usoftchina.smartschool.school.dto;
+
+import java.io.Serializable;
+
+/**
+ * @author: guq
+ * @create: 2019-03-09 16:08
+ **/
+public class SysSchoolDTO implements Serializable{
+    private Long school_id;
+
+    private String school_name;
+
+    private Integer school_status;
+
+    private String school_remarks;
+
+    private String school_address;
+
+    private String school_phone;
+
+    private String school_appid;
+
+    private String school_secret;
+
+    private String school_accesssecret;
+
+
+    public String getSchool_accesssecret() {
+        return school_accesssecret;
+    }
+
+    public void setSchool_accesssecret(String school_accesssecret) {
+        this.school_accesssecret = school_accesssecret;
+    }
+
+    private Boolean leaf = false;
+
+    public Boolean getLeaf() {
+        return leaf;
+    }
+
+    public void setLeaf(Boolean leaf) {
+        this.leaf = leaf;
+    }
+
+    public Long getSchool_id() {
+        return school_id;
+    }
+
+    public void setSchool_id(Long school_id) {
+        this.school_id = school_id;
+    }
+
+    public String getSchool_name() {
+        return school_name;
+    }
+
+    public void setSchool_name(String school_name) {
+        this.school_name = school_name == null ? null : school_name.trim();
+    }
+
+    public Integer getSchool_status() {
+        return school_status;
+    }
+
+    public void setSchool_status(Integer school_status) {
+        this.school_status = school_status;
+    }
+
+    public String getSchool_remarks() {
+        return school_remarks;
+    }
+
+    public void setSchool_remarks(String school_remarks) {
+        this.school_remarks = school_remarks == null ? null : school_remarks.trim();
+    }
+
+    public String getSchool_address() {
+        return school_address;
+    }
+
+    public void setSchool_address(String school_address) {
+        this.school_address = school_address == null ? null : school_address.trim();
+    }
+
+    public String getSchool_phone() {
+        return school_phone;
+    }
+
+    public void setSchool_phone(String school_phone) {
+        this.school_phone = school_phone == null ? null : school_phone.trim();
+    }
+
+    public String getSchool_appid() {
+        return school_appid;
+    }
+
+    public void setSchool_appid(String school_appid) {
+        this.school_appid = school_appid == null ? null : school_appid.trim();
+    }
+
+    public String getSchool_secret() {
+        return school_secret;
+    }
+
+    public void setSchool_secret(String school_secret) {
+        this.school_secret = school_secret == null ? null : school_secret.trim();
+    }
+}

+ 9 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/controller/SchoolController.java

@@ -2,7 +2,9 @@ package com.usoftchina.smartschool.school.basic.controller;
 
 import com.usoftchina.smartschool.base.Result;
 import com.usoftchina.smartschool.school.basic.service.SchoolService;
+import com.usoftchina.smartschool.school.dto.SysSchoolDTO;
 import com.usoftchina.smartschool.school.po.SysSchool;
+import com.usoftchina.smartschool.utils.BeanMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -24,6 +26,13 @@ public class SchoolController {
         return Result.success(school);
     }
 
+    @GetMapping("/find")
+    public Result find(@RequestParam("schoolName") String schoolName) {
+        SysSchool school = schoolService.find(schoolName);
+        SysSchoolDTO schoolDTO = BeanMapper.map(school, SysSchoolDTO.class);
+        return Result.success(schoolDTO);
+    }
+
     @PostMapping("/save")
     public Result saveFormData(@RequestBody SysSchool school) {
         schoolService.saveFormData(school);

+ 2 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/SchoolService.java

@@ -10,4 +10,6 @@ public interface SchoolService {
     SysSchool getFormData(Long id);
 
     void saveFormData(SysSchool school);
+
+    SysSchool find(String schoolName);
 }

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

@@ -145,6 +145,7 @@ public class CurriculumServiceImpl implements CurriculumService {
             main.setCreateTime(new Date());
             main.setSchoolId(BaseContextHolder.getSchoolId());
             main.setCreatorName(BaseContextHolder.getUserName());
+            main.setStatus("0");
             //保存主表
             curriculumMapper.insertSelective(main);
             Long mId = main.getId();
@@ -156,6 +157,7 @@ public class CurriculumServiceImpl implements CurriculumService {
                     curriculumDetailDTO.setSchoolId(schoolId);
                     curriculumDetailDTO.setClazzId(Long.parseLong(main.getClazzId()));
                     curriculumDetailDTO.setStatus(Integer.parseInt(main.getStatus()));
+                    curriculumDetailDTO.setStatus(0);
                 });
                 curriculumMapper.insertDetailSelective(items);
                 messageLogService.save(new DocBaseDTO(mId, CODE, NAME));
@@ -190,6 +192,9 @@ public class CurriculumServiceImpl implements CurriculumService {
     @Override
     @Transactional
     public void delete(Long id) {
+        if(curriculumMapper.courseStatus(id)>0){
+            throw new BizException(BizExceptionCode.COURSE_RELEASE_STATUS);
+        }
         curriculumMapper.deleteDetailByMainId(id);
         curriculumMapper.delete(id);
         messageLogService.delete(new DocBaseDTO(id, CODE, NAME));

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

@@ -175,14 +175,13 @@ public class GradeServiceImpl implements GradeService{
         }
         sysClazz.setClazz_status(1);
         SysGrade gradeData = sysGradeMapper.selectByPrimaryKey(sysClazz.getGrade_id());
-        String clazz_grade = gradeData.getGrade_name();
-        if(sysClazzMapper.countClazz(sysClazz.getClazz_name(),clazz_grade ) >0 ){
+        if(sysClazzMapper.countClazz(sysClazz.getClazz_name(),gradeData.getGrade_name(),gradeData.getSchool_id() ) >0 ){
             throw new BizException(BizExceptionCode.REPEAT_CLASS_NAME);
         }
 
         sysClazz.setSchool_id(gradeData.getSchool_id());
-        sysClazz.setClazz_grade(clazz_grade);
-        sysClazz.setClazz_nickname(clazz_grade+sysClazz.getClazz_name());
+        sysClazz.setClazz_grade(gradeData.getGrade_name());
+        sysClazz.setClazz_nickname(gradeData.getGrade_name()+sysClazz.getClazz_name());
         sysClazzMapper.insertSelective(sysClazz);
         return new DocBaseDTO(sysClazz.getClazz_id());
     }

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

@@ -37,4 +37,13 @@ public class SchoolServiceImpl implements SchoolService {
         }
         sysSchoolMapper.updateByPrimaryKeySelective(school);
     }
+
+    @Override
+    public SysSchool find(String schoolName) {
+        if (StringUtils.isEmpty(schoolName)) {
+            throw new BizException(BizExceptionCode.USELESS_DATA);
+        }
+        SysSchool school = sysSchoolMapper.selectByName(schoolName);
+        return school;
+    }
 }

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

@@ -138,6 +138,12 @@ public class TeacherServiceImpl implements TeacherService{
                         }else if ("女".equals(json.get("teacher_sex"))) {
                             json.put("teacher_sex", 2);
                         };
+
+                        if ("已婚".equals(json.get("teacher_marriage"))) {
+                            json.put("teacher_marriage", 0);
+                        }else if ("否".equals(json.get("teacher_marriage"))) {
+                            json.put("teacher_marriage", 1);
+                        };
                     }
                     teacher = JSONObject.parseObject(json.toJSONString(), SysTeacher.class);
                     teacher.setSchool_id(schoolId);
@@ -164,26 +170,31 @@ public class TeacherServiceImpl implements TeacherService{
         if (null == id || "0".equals(id)) {
             return;
         }
-        List<String> check = null;
         //教师检测
-        check = sysTeacherMapper.checkTeacher(id);
-        if (check != null) {
-            String.join("|", check);
-            throw new BizException(BizExceptionCode.TEACHERS_EXISTS_CLASS.getCode(), String.format(BizExceptionCode.TEACHERS_EXISTS_CLASS.getMessage(), String.join("|", check)));
+        int count = sysTeacherMapper.checkTeacher(id);
+        if (count > 0) {
+            throw new BizException(BizExceptionCode.EXISTS_TEACHER_CLASS);
         }
         sysTeacherMapper.deleteByPrimaryKey(id);
         sysTeacherMapper.deleteRelation(id);
     }
 
     @Override
+    @Transactional
     public void batchDelete(BatchDealBaseDTO baseDTOs) {
         if (null == baseDTOs || null == baseDTOs.getBaseDTOs() ||
                 baseDTOs.getBaseDTOs().size() == 0) {
             return;
         }
-
+        StringBuilder sb = new StringBuilder();
         for (DocBaseDTO base : baseDTOs.getBaseDTOs()) {
-            delete(base.getId());
+            try {
+                delete(base.getId());
+            }catch (Exception e){
+                sb.append(sysTeacherMapper.selectByPrimaryKey(base.getId()).getTeacher_name() + "|");
+                throw new BizException(BizExceptionCode.TEACHERS_EXISTS_CLASS.getCode(), String.format(BizExceptionCode.TEACHERS_EXISTS_CLASS.getMessage(), sb.substring(0, sb.length() - 1)));
+            }
         }
+
     }
 }

+ 0 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/controller/ScoreController.java

@@ -7,9 +7,7 @@ import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.business.service.ScoreService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
-import com.usoftchina.smartschool.school.po.Notify;
 import com.usoftchina.smartschool.school.po.ScoreForm;
-import com.usoftchina.smartschool.school.po.ScoreImport;
 import com.usoftchina.smartschool.school.po.ScoreImportList;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;

+ 10 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java

@@ -22,8 +22,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 
+import java.util.Calendar;
 import java.util.List;
-import java.util.StringJoiner;
 
 /**
  * @author: guq
@@ -54,10 +54,16 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             //增加推送人(学生)信息
             String studentIds = getNotifer(formdata.getGrade_name(), formdata.getClassz_name(), school_id);
             formdata.setTask_notifier(studentIds);
+            //获取时间
+            Calendar calendar= Calendar.getInstance();
+            formdata.setCreate_date(calendar.getTime());
             homeWorkMapper.insertSelective(formdata);
         } else {
             //更新
             homeWorkMapper.updateByPrimaryKeySelective(formdata);
+            if(formdata.getTask_status()==1){
+                publish(formdata.getTask_id());
+            }
         }
         return new DocBaseDTO(formdata.getTask_id());
     }
@@ -81,6 +87,9 @@ public class HomeWorkServiceImpl implements HomeWorkService{
         if (StringUtils.isEmpty(id) || "0".equals(id)) {
             return;
         }
+        if(homeWorkMapper.taskStatus("1",id)>0){
+            throw new BizException(BizExceptionCode.TASK_RELEASE_STATUS);
+        }
         homeWorkMapper.deleteByPrimaryKey(id);
     }
 

+ 10 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java

@@ -16,6 +16,7 @@ import com.usoftchina.smartschool.utils.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Calendar;
 import java.util.List;
 
 /**
@@ -38,11 +39,17 @@ public class NoticeServiceImpl implements NoticeService{
         //新增
         if (StringUtils.isEmpty(formdata.getNotify_id()) || "0".equals(formdata.getNotify_id().toString())) {
             formdata.setNotify_status(2);
+            //获取时间
+            Calendar calendar= Calendar.getInstance();
+            formdata.setCreate_date(calendar.getTime());
             noticeMapper.insertSelective(formdata);
 
         } else {
             //更新
             noticeMapper.updateByPrimaryKeySelective(formdata);
+            if(formdata.getNotify_status()==1){
+                publish(formdata.getNotify_id());
+            }
         }
         return new DocBaseDTO(formdata.getNotify_id());
     }
@@ -75,6 +82,9 @@ public class NoticeServiceImpl implements NoticeService{
         if (StringUtils.isEmpty(id) || "0".equals(id)) {
             return;
         }
+        if(noticeMapper.noticeStatus(id)>0){
+            throw new BizException(BizExceptionCode.NOTICE_RELEASE_STATUS);
+        }
         noticeMapper.deleteByPrimaryKey(id);
     }
 

+ 3 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/common/service/impl/ExcelServiceImpl.java

@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -366,10 +367,10 @@ public class ExcelServiceImpl implements ExcelService {
                 case Cell.CELL_TYPE_NUMERIC:{
                     //POI在解析时,会将日期格式也解析为NUMERIC(数字类型);可查看API中CellType.java
                     if (!HSSFDateUtil.isCellDateFormatted(cell)) {
-                        cellValue = String.valueOf(cell.getNumericCellValue());
+                        cellValue = String.valueOf(new BigDecimal(cell.getNumericCellValue()));
                         cellValue = RegexpUtils.replaceSpecialCharacterNotcodefield(cellValue);
                         //判断是否为INT类型
-                        if (Double.valueOf(cellValue.toString()).intValue() - Double.valueOf(cellValue.toString()) == 0) {
+                        if (Double.valueOf(cellValue.toString()).intValue() - Double.valueOf(cellValue.toString()) == 0 && cellValue.toString().indexOf(".") > -1) {
                             return cellValue.toString().substring(0, cellValue.toString().indexOf("."));
                         }
                     }else {

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

@@ -27,7 +27,11 @@ public enum BizExceptionCode implements BaseExceptionCode {
     REPEAT_GRADE_NAME(600001, "年级名称重复"),
     REPEAT_CLASS_NAME(600002, "班级名称重复"),
     REPEAT_STUDENT_NUMBER(600003, "学生学号不可重复"),
-    EFFECTIVE_CLASS_DATA(600004, "无法删除有学生的班级");
+    EFFECTIVE_CLASS_DATA(600004, "无法删除有学生的班级"),
+    TASK_RELEASE_STATUS(600005, "作业已发布无法更改"),
+    COURSE_RELEASE_STATUS(600006, "课程表已生效,无法删除"),
+    NOTICE_RELEASE_STATUS(600007, "学校发布已生效,无法删除"),
+    NOT_EXISTS_SUBJECT(60005, "科目<u>%s</u>不存在");
 
 
     private int code;

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

@@ -82,4 +82,6 @@ public interface CurriculumMapper {
      * @param curriculumDetailDTOList
      */
     void updateDetailSelective(List<CurriculumDetailDTO> curriculumDetailDTOList);
+
+    int courseStatus(Long id);
 }

+ 6 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/HomeWorkMapper.java

@@ -3,7 +3,6 @@ package com.usoftchina.smartschool.school.mapper;
 import com.usoftchina.smartschool.school.po.HomeWork;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
-import org.springframework.web.bind.annotation.GetMapping;
 
 import java.util.List;
 
@@ -27,4 +26,10 @@ public interface HomeWorkMapper {
     List<HomeWork> selectByConditon(@Param("con") String condition, @Param("school_id") Long schoolId);
 
     int updateByPublish(Long task_id);
+
+    /**
+     * 查询作业发布状态
+     * @return
+     */
+    int taskStatus(@Param("task_status") String task_status,@Param("task_id") Long task_id);
 }

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

@@ -26,4 +26,6 @@ public interface NoticeMapper {
     List<Notify> selectByConditon(@Param("con") String con, @Param("school_id") Long schoolId);
 
     int updateByPublish(Long notify_id);
+
+    int noticeStatus(Long id);
 }

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

@@ -33,5 +33,5 @@ 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);
+    int countClazz(@Param("clazz_name") String clazz_name, @Param("clazz_grade") String clazz_grade, @Param("school_id") Long school_id);
 }

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

@@ -16,4 +16,6 @@ public interface SysSchoolMapper {
     int updateByPrimaryKeySelective(SysSchool record);
 
     int updateByPrimaryKey(SysSchool record);
+
+    SysSchool selectByName(String schoolName);
 }

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

@@ -39,5 +39,5 @@ public interface SysTeacherMapper {
 
     SysTeacher selectNumberByKey(String teacher_number);
 
-    List<String> checkTeacher(Long id);
+    int checkTeacher(Long id);
 }

+ 10 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SysSchool.java

@@ -25,10 +25,20 @@ public class SysSchool implements Serializable{
 
     private String school_secret;
 
+    private String school_accesssecret;
+
     private List<SysGrade> children;
 
     private Boolean leaf = false;
 
+    public String getSchool_accesssecret() {
+        return school_accesssecret;
+    }
+
+    public void setSchool_accesssecret(String school_accesssecret) {
+        this.school_accesssecret = school_accesssecret;
+    }
+
     public Boolean getLeaf() {
         return leaf;
     }

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

@@ -258,4 +258,8 @@
     </foreach>
   </update>
 
+  <select id="courseStatus" parameterType="long" resultType="int">
+    select count(1) from clazz_curriculum where mcur_status=1 and cur_id=#{id}
+  </select>
+
 </mapper>

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

@@ -246,4 +246,16 @@
       publish_date = now()
     where task_id = #{task_id,jdbcType=BIGINT}
   </update>
+
+    <select id="taskStatus" resultType="int">
+        select count(1) from task_notify
+        <where>
+            <if test="task_status != null">
+                task_status=#{task_status}
+            </if>
+            <if test="task_id != null">
+                and task_id=#{task_id}
+            </if>
+        </where>
+    </select>
 </mapper>

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

@@ -145,4 +145,9 @@
     </where>
     order by ml_id DESC
   </select>
+
+  <delete id="deleteDetail" parameterType="java.lang.Integer" >
+    delete from messagelog
+    where ml_id = #{id,jdbcType=INTEGER}
+  </delete>
 </mapper>

+ 4 - 0
applications/school/school-server/src/main/resources/mapper/NotifyMapper.xml

@@ -221,4 +221,8 @@
       publish_date = now()
     where notify_id = #{notify_id,jdbcType=BIGINT}
   </update>
+
+    <select id="noticeStatus" parameterType="long" resultType="int">
+    select count(1) from notify where notify_status=1 and notify_id=#{id}
+  </select>
 </mapper>

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

@@ -242,6 +242,9 @@
       <if test="clazz_grade != null">
         and clazz_grade=#{clazz_grade}
       </if>
+      <if test="school_id != null">
+        and school_id=#{school_id}
+      </if>
     </where>
   </select>
 

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

@@ -10,6 +10,7 @@
     <result column="school_phone" property="school_phone" jdbcType="VARCHAR" />
     <result column="school_appid" property="school_appid" jdbcType="VARCHAR" />
     <result column="school_secret" property="school_secret" jdbcType="VARCHAR" />
+    <result column="school_accesssecret" property="school_accesssecret" jdbcType="VARCHAR" />
   </resultMap>
   <sql id="Base_Column_List" >
     school_id, school_name, school_status, school_remarks, school_address, school_phone, 
@@ -126,4 +127,8 @@
       school_secret = #{school_secret,jdbcType=VARCHAR}
     where school_id = #{school_id,jdbcType=BIGINT}
   </update>
+
+  <select id="selectByName" parameterType="string" resultMap="BaseResultMap">
+    select * from sys_school where school_name = #{schoolName}
+  </select>
 </mapper>

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

@@ -486,6 +486,6 @@
   </select>
 
   <select id="selectIdByClazzId" resultType="string" parameterType="long">
-    SELECT stu_id FROM student WHERE clazz_id = #{clazzId}
+    SELECT stu_id FROM sys_student WHERE clazz_id = #{clazzId}
   </select>
 </mapper>

+ 2 - 2
applications/school/school-server/src/main/resources/mapper/SysTeacherMapper.xml

@@ -395,7 +395,7 @@ where sys_teacher_clazz.teacher_id=#{id}
     where teacher_number = #{teacher_number,jdbcType=VARCHAR}
   </select>
 
-  <select id="checkTeacher" parameterType="long" resultType="List">
-    select teacher_name from sys_teacher_clazz where  teacher_id= #{id}
+  <select id="checkTeacher" parameterType="long" resultType="int">
+    select count(*) from sys_teacher_clazz where  teacher_id= #{id}
   </select>
 </mapper>

+ 2 - 0
applications/wechat/pom.xml

@@ -14,6 +14,8 @@
     <modules>
         <module>wechat-api</module>
         <module>wechat-server</module>
+        <module>wechat-auth</module>
+        <module>wechat-dto</module>
     </modules>
 
 

+ 44 - 0
applications/wechat/wechat-auth/pom.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>wechat</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>wechat-auth</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-netflix-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>io.github.openfeign</groupId>
+            <artifactId>feign-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>school-api</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 18 - 0
applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/EnableOpenApiAuthClient.java

@@ -0,0 +1,18 @@
+package com.usoftchina.smartschool.wechat.auth;
+
+import com.usoftchina.smartschool.wechat.auth.configuration.OpenApiConfiguration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author: guq
+ * @create: 2019-03-08 09:10
+ **/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Import(OpenApiConfiguration.class)
+@Documented
+@Inherited
+public @interface EnableOpenApiAuthClient{
+}

+ 12 - 0
applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/annotation/IgnoreOpenApiAuth.java

@@ -0,0 +1,12 @@
+package com.usoftchina.smartschool.wechat.auth.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD,ElementType.TYPE})
+public @interface IgnoreOpenApiAuth {
+}

+ 49 - 0
applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/configuration/OpenApiConfig.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.wechat.auth.configuration;
+import org.springframework.beans.factory.annotation.Value;
+/**
+ * @author: guq
+ * @create: 2019-03-08 09:19
+ **/
+public class OpenApiConfig {
+
+    @Value("${openapi.signatureParam:_signature}")
+    private String signatureParam;
+    @Value("${openapi.timestampParam:_timestamp}")
+    private String timestampParam;
+    @Value("${openaip.school:school}")
+    private String school;
+    @Value("${openapi.timeout:60000}")
+    private int timeout;
+
+    public String getSchool() {
+        return school;
+    }
+
+    public void setSchool(String school) {
+        this.school = school;
+    }
+
+    public String getSignatureParam() {
+        return signatureParam;
+    }
+
+    public void setSignatureParam(String signatureParam) {
+        this.signatureParam = signatureParam;
+    }
+
+    public String getTimestampParam() {
+        return timestampParam;
+    }
+
+    public void setTimestampParam(String timestampParam) {
+        this.timestampParam = timestampParam;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+}

+ 31 - 0
applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/configuration/OpenApiConfiguration.java

@@ -0,0 +1,31 @@
+package com.usoftchina.smartschool.wechat.auth.configuration;
+
+import com.usoftchina.smartschool.wechat.auth.interceptor.OpenApiAuthInterceptor;
+import io.netty.resolver.AddressResolver;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author: guq
+ * @create: 2019-03-08 15:52
+ **/
+@Configuration
+public class OpenApiConfiguration implements WebMvcConfigurer {
+
+    @Bean
+    public OpenApiConfig openApiConfig() {
+        return new OpenApiConfig();
+    }
+
+    @Bean
+    public OpenApiAuthInterceptor openApiAuthInterceptor() {
+        return new OpenApiAuthInterceptor();
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(openApiAuthInterceptor());
+    }
+}

+ 110 - 0
applications/wechat/wechat-auth/src/main/java/com/usoftchina/smartschool/wechat/auth/interceptor/OpenApiAuthInterceptor.java

@@ -0,0 +1,110 @@
+package com.usoftchina.smartschool.wechat.auth.interceptor;
+
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.school.api.SchoolApi;
+import com.usoftchina.smartschool.school.dto.SysSchoolDTO;
+import com.usoftchina.smartschool.utils.http.HmacUtils;
+import com.usoftchina.smartschool.wechat.auth.annotation.IgnoreOpenApiAuth;
+import com.usoftchina.smartschool.wechat.auth.configuration.OpenApiConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.util.StringUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author: guq
+ * @create: 2019-01-10 16:05
+ **/
+public class OpenApiAuthInterceptor extends HandlerInterceptorAdapter{
+
+    @Autowired
+    private OpenApiConfig openApiConfig;
+
+    @Autowired
+    private SchoolApi schoolApi;
+
+    // 已使用签名
+    private Map<String, Long> signatureCache = new ConcurrentHashMap<>();
+
+    private static Logger logger = LoggerFactory.getLogger(OpenApiAuthInterceptor.class);
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (handler instanceof HandlerMethod) {
+            HandlerMethod handlerMethod = (HandlerMethod) handler;
+            // 配置该注解,说明不进行用户拦截
+            IgnoreOpenApiAuth annotation = handlerMethod.getBeanType().getAnnotation(IgnoreOpenApiAuth.class);
+            if (annotation == null) {
+                annotation = handlerMethod.getMethodAnnotation(IgnoreOpenApiAuth.class);
+            }
+            if (annotation != null) {
+                return super.preHandle(request, response, handler);
+            }
+
+            String sign = request.getParameter(openApiConfig.getSignatureParam());
+            String schoolName = request.getParameter(openApiConfig.getSchool());
+            if (!StringUtils.isEmpty(sign) && !StringUtils.isEmpty(schoolName)) {
+                String urlMessage = request.getRequestURI() + "?"
+                        + request.getQueryString().substring(0, request.getQueryString().indexOf(openApiConfig.getSignatureParam()) - 1);
+
+                logger.info("urlMessage:{}", urlMessage);
+                String servletPath = request.getServletPath();
+                logger.info("servletPath:{}", servletPath);
+
+                boolean check = false;
+                //获取密钥
+                Result<SysSchoolDTO> result = schoolApi.find(schoolName);
+                if (result.isSuccess()) {
+                    String localSign = null;
+                    //TransfersContextHodler.setB2bCompanyId(companyResult.getData().getId());
+                    localSign = result.getData().getSchool_accesssecret() == null ? HmacUtils.encode(urlMessage) :
+                                HmacUtils.encode(urlMessage, result.getData().getSchool_accesssecret());
+
+                    if (servletPath.indexOf("b2b") > -1) {
+                        logger.info("自己生产的sign:{}-----传入的sign:{}", localSign, sign);
+                        check = sign.equals(localSign);
+                    }
+
+                    if (check) {
+                        String timestamp = request.getParameter(openApiConfig.getTimestampParam());
+                        long now = System.currentTimeMillis();
+                        if (!StringUtils.isEmpty(timestamp) && Math.abs(now - Long.parseLong(timestamp)) <= openApiConfig.getTimeout()
+                                && !signatureCache.containsKey(sign)) {
+                            // 加入历史记录
+                            signatureCache.put(sign, now);
+                            return true;
+                        }
+                    }
+                }
+            }
+            response.setStatus(HttpStatus.FORBIDDEN.value());
+            return false;
+        } else {
+        }
+        return super.preHandle(request, response, handler);
+    }
+
+    /**
+     * 清除签名池历史记录
+     */
+    @Scheduled(cron = "0 0/3 * * * ?")
+    public void clearCache() {
+        long now = System.currentTimeMillis();
+        for (String key : signatureCache.keySet()) {
+            long time = signatureCache.get(key);
+            if (now - time > openApiConfig.getTimeout()) {
+                signatureCache.remove(key);
+            }
+        }
+    }
+}

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

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

+ 30 - 0
applications/wechat/wechat-dto/src/main/java/com/usoftchina/smartschool/wechat/constant/Status.java

@@ -0,0 +1,30 @@
+package com.usoftchina.smartschool.wechat.constant;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 11:41
+ **/
+public enum Status {
+
+    SEND("已发送"),
+
+    RETRY("重新发送"),
+
+    FAILURE("投递失败"),
+
+    SUCCESS("投递成功");
+
+    private String display;
+
+    public String getDisplay() {
+        return display;
+    }
+
+    public void setDisplay(String display) {
+        this.display = display;
+    }
+
+    Status(String display) {
+        this.display = display;
+    }
+}

+ 162 - 0
applications/wechat/wechat-dto/src/main/java/com/usoftchina/smartschool/wechat/dto/MessageInfoDTO.java

@@ -0,0 +1,162 @@
+package com.usoftchina.smartschool.wechat.dto;
+
+
+import java.io.Serializable;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 14:05
+ **/
+public class MessageInfoDTO implements Serializable{
+
+    private String msgId;
+    /**
+     * 公众号id
+     */
+    private String appId;
+
+    /**
+     * 公众号密钥
+     */
+    private String secret;
+
+    /*
+     * 推送人微信标识
+     */
+    private String touser;
+
+    /**
+     * 微信模板id
+     */
+    private String templateId;
+
+    private String title;
+
+    private String keyword1;
+
+    private String keyword2;
+
+    private String keyword3;
+
+    private String keyword4;
+
+    private String keyword5;
+
+    private String keyword6;
+
+    private String remark;
+
+    private String url;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public String getTouser() {
+        return touser;
+    }
+
+    public void setTouser(String touser) {
+        this.touser = touser;
+    }
+
+    public String getTemplateId() {
+        return templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getKeyword1() {
+        return keyword1;
+    }
+
+    public void setKeyword1(String keyword1) {
+        this.keyword1 = keyword1;
+    }
+
+    public String getKeyword2() {
+        return keyword2;
+    }
+
+    public void setKeyword2(String keyword2) {
+        this.keyword2 = keyword2;
+    }
+
+    public String getKeyword3() {
+        return keyword3;
+    }
+
+    public void setKeyword3(String keyword3) {
+        this.keyword3 = keyword3;
+    }
+
+    public String getKeyword4() {
+        return keyword4;
+    }
+
+    public void setKeyword4(String keyword4) {
+        this.keyword4 = keyword4;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getKeyword5() {
+        return keyword5;
+    }
+
+    public void setKeyword5(String keyword5) {
+        this.keyword5 = keyword5;
+    }
+
+    public String getMsgId() {
+        return msgId;
+    }
+
+    public void setMsgId(String msgId) {
+        this.msgId = msgId;
+    }
+
+    public String getKeyword6() {
+        return keyword6;
+    }
+
+    public void setKeyword6(String keyword6) {
+        this.keyword6 = keyword6;
+    }
+}

+ 14 - 9
applications/wechat/wechat-server/pom.xml

@@ -32,11 +32,6 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
-        <dependency>
-            <groupId>net.sf.json-lib</groupId>
-            <artifactId>json-lib</artifactId>
-            <classifier>jdk15</classifier>
-        </dependency>
         <dependency>
             <groupId>com.usoftchina.smartschool</groupId>
             <artifactId>server-starter</artifactId>
@@ -45,6 +40,12 @@
         <dependency>
             <groupId>com.usoftchina.smartschool</groupId>
             <artifactId>core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>HdrHistogram</artifactId>
+                    <groupId>org.hdrhistogram</groupId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <!--test-->
@@ -64,10 +65,6 @@
             <artifactId>mybatis-spring-boot-starter</artifactId>
         </dependency>
         <!-- sleuth -->
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-zipkin</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.springframework.amqp</groupId>
             <artifactId>spring-rabbit</artifactId>
@@ -90,6 +87,14 @@
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>wechat-dto</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>wechat-auth</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 4 - 28
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/WechatApplication.java

@@ -1,19 +1,12 @@
 package com.usoftchina.smartschool.wechat;
 
 
-import org.mybatis.spring.annotation.MapperScan;
+import com.usoftchina.smartschool.wechat.auth.EnableOpenApiAuthClient;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
 /**
  * @author: guq
@@ -21,28 +14,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
  **/
 @SpringBootApplication
 @EnableTransactionManagement
-@ServletComponentScan
-@MapperScan("com.usoftchina.smartschool.wechat.mapper")
 @EnableEurekaClient
-@EnableFeignClients("com.usoftchina.smartschool.wechat")
-@ComponentScan(basePackages = {"com.usoftchina.smartschool.wechat"})
-public class WechatApplication  extends WebMvcConfigurerAdapter {
+@EnableFeignClients({"com.usoftchina.smartschool.wechat","com.usoftchina.smartschool.school"})
+@EnableOpenApiAuthClient
+public class WechatApplication {
     public static void main(String[] args) {
         SpringApplication.run(WechatApplication.class, args);
     }
-
-    //解决跨域问题
-   /* @Override
-    public void addCorsMappings(CorsRegistry registry) {
-        registry.addMapping("/**")
-                .allowedHeaders("*")
-                .allowedOrigins("*")
-                .allowedMethods("*")
-                .allowCredentials(true).maxAge(3600000);
-    }
-
-    @Bean
-    public RestTemplate restTemplate(){
-        return new RestTemplate();
-    }*/
 }

+ 26 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/config/ExpirationMessagePostProcessor.java

@@ -0,0 +1,26 @@
+package com.usoftchina.smartschool.wechat.config;
+
+
+import org.springframework.amqp.AmqpException;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessagePostProcessor;
+
+/**
+ * @author: guq
+ * @create: 2019-01-07 18:27
+ **/
+public class ExpirationMessagePostProcessor implements MessagePostProcessor {
+
+    private final Long ttl; // 毫秒
+
+    public ExpirationMessagePostProcessor(Long ttl) {
+        this.ttl = ttl;
+    }
+
+    @Override
+    public Message postProcessMessage(Message message) throws AmqpException {
+        message.getMessageProperties() .setExpiration(ttl.toString());
+        // 设置message的失效时间
+        return message;
+    }
+}

+ 73 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/config/RabbitConfig.java

@@ -0,0 +1,73 @@
+package com.usoftchina.smartschool.wechat.config;
+
+
+import org.springframework.amqp.core.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 09:31
+ **/
+@Configuration
+public class RabbitConfig {
+
+
+    @Value("${school.rabbitmq.exchange}")
+    private String exchange;
+
+    /**
+     * 消费队列
+     */
+    @Value("${school.rabbitmq.activeQueue}")
+    private String activeQueue;
+    /**
+     * 延迟队列
+     */
+    @Value("${school.rabbitmq.delayQueue}")
+    private String delayQueue;
+
+    /**
+     * 转发规则
+     */
+    @Value("${school.rabbitmq.activeKey}")
+    private String activeKey;
+
+    /**
+     * 延迟规则
+     */
+    @Value("${school.rabbitmq.delayKey}")
+    private String delayKey;
+
+    final static String DEAD_EXCHANGE_PARAM = "x-dead-letter-exchange";
+
+    final static String DEAD_KEY_PARAM = "x-dead-letter-routing-key";
+
+
+    @Bean
+    TopicExchange createExchange() {
+        return new TopicExchange(exchange);
+    }
+
+    @Bean
+    Queue createActiveQueue() {
+        return QueueBuilder.durable(activeQueue).build();
+    }
+
+    @Bean
+    Queue createDelayQueue() {
+        return QueueBuilder.durable(delayQueue).withArgument(DEAD_EXCHANGE_PARAM, exchange)
+                .withArgument(DEAD_KEY_PARAM, activeKey).build();
+    }
+
+    @Bean
+    Binding activeBind(Queue createActiveQueue, TopicExchange createExchange) {
+        return BindingBuilder.bind(createActiveQueue).to(createExchange).with(activeKey);
+    }
+
+    @Bean
+    Binding delayBind(Queue createDelayQueue, TopicExchange createExchange) {
+        return BindingBuilder.bind(createDelayQueue).to(createExchange).with(delayKey);
+    }
+}

+ 63 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/controller/TransfersController.java

@@ -0,0 +1,63 @@
+package com.usoftchina.smartschool.wechat.controller;
+
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.utils.JsonUtils;
+import com.usoftchina.smartschool.wechat.auth.annotation.IgnoreOpenApiAuth;
+import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
+import com.usoftchina.smartschool.wechat.service.SendService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.List;
+
+/**
+ * @author: guq
+ * @create: 2019-01-06 22:15
+ **/
+@RestController
+@RequestMapping("/send")
+public class TransfersController {
+
+    @Autowired
+    private SendService sendService;
+
+    /**
+    * @Description 提供系统内部推送使用
+    * @Param: [info]
+    * @return: com.usoftchina.smartschool.base.Result
+    * @Author: guq
+    * @Date: 2019/3/7
+    */
+    @PostMapping("/Message")
+    @IgnoreOpenApiAuth
+    public Result sendMsg(@RequestBody MessageInfoDTO info) {
+        if (StringUtils.isEmpty(info)) {
+            return Result.error("信息为空");
+        }
+        sendService.sendMessage(info);
+        return Result.success();
+    }
+
+    /**
+    * @Description 对外提供大量数据使用
+    * @Param: [data]
+    * @return: com.usoftchina.smartschool.base.Result
+    * @Author: guq
+    * @Date: 2019/3/7
+    */
+    @PostMapping("/Messages")
+    public Result sendOutMessages(String data) throws UnsupportedEncodingException {
+        if (StringUtils.isEmpty(data)) {
+            return Result.error("信息为空");
+        }
+        data = URLDecoder.decode(data, "UTF-8");
+        List<MessageInfoDTO> messages = JsonUtils.fromJsonArray(data, MessageInfoDTO.class);
+        sendService.sendOutMessages(messages);
+        return Result.success();
+    }
+
+}

+ 2 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/controller/WxPushController.java

@@ -1,5 +1,6 @@
 package com.usoftchina.smartschool.wechat.controller;
 
+import com.usoftchina.smartschool.wechat.auth.annotation.IgnoreOpenApiAuth;
 import com.usoftchina.smartschool.wechat.service.WxPushService;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
  * @create: 2019-01-27 12:41
  **/
 @RestController
+@IgnoreOpenApiAuth
 public class WxPushController {
 
     @Autowired

+ 34 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/mapper/BrokerMessageLogMapper.java

@@ -0,0 +1,34 @@
+package com.usoftchina.smartschool.wechat.mapper;
+
+
+import com.usoftchina.smartschool.wechat.po.BrokerMessagelog;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author: guq
+ * @create: 2019-01-07 20:37
+ **/
+@Mapper
+public interface BrokerMessageLogMapper {
+    BrokerMessagelog getMessage(String msgId);
+
+    BrokerMessagelog getLiveMessage(String msgId);
+
+    BrokerMessagelog getDeadMessage(String msgId);
+
+    int deleteByPrimaryKey(Integer id);
+
+    int insert(BrokerMessagelog record);
+
+    int insertSelective(BrokerMessagelog record);
+
+    BrokerMessagelog selectByPrimaryKey(Integer id);
+
+    int updateByPrimaryKeySelective(BrokerMessagelog record);
+
+    int updateByPrimaryKey(BrokerMessagelog record);
+
+    int updateMessageLogandAddRetry(BrokerMessagelog record);
+
+    void updateSuccess(String msgId);
+}

+ 26 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/BrokerMessagelog.java

@@ -0,0 +1,26 @@
+package com.usoftchina.smartschool.wechat.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 11:36
+ **/
+@Data
+public class BrokerMessagelog implements Serializable{
+
+    private Long id;
+    private String msgId;
+    private String message;
+    private String status;
+
+    private Date createTime;
+    private int retry;
+    /**
+     * 失败原因
+     */
+    private String reason;
+}

+ 58 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/MessageInfo.java

@@ -0,0 +1,58 @@
+package com.usoftchina.smartschool.wechat.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 14:27
+ **/
+@Data
+public class MessageInfo implements Serializable {
+
+    /**
+     * 消息id
+     */
+    private String msgId;
+    /**
+     * 公众号id
+     */
+    private String appId;
+
+    /**
+     * 公众号密钥
+     */
+    private String secret;
+
+    /*
+     * 推送人微信标识
+     */
+    private String touser;
+
+    /**
+     * 微信模板id
+     */
+    private String templateId;
+
+    private String title;
+
+    private String keyword1;
+
+    private String keyword2;
+
+    private String keyword3;
+
+    private String keyword4;
+
+    private String keyword5;
+
+    private String remark;
+
+    private String url;
+
+    private Boolean send = false;
+
+    //发送失败原因
+    private String reason;
+}

+ 35 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/po/MessagePackage.java

@@ -0,0 +1,35 @@
+package com.usoftchina.smartschool.wechat.po;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author: guq
+ * @create: 2019-03-07 16:10
+ **/
+@Data
+public class MessagePackage implements Serializable{
+
+    private String packageId;
+
+    private List<MessageInfo> data;
+
+    private int retry;
+
+    public MessagePackage(List<MessageInfo> data) {
+        this.packageId = UUID.randomUUID().toString();
+        this.data = data;
+    }
+
+    public MessagePackage(List<MessageInfo> data, String msgId) {
+        this.packageId = msgId;
+        this.data = data;
+    }
+
+    public void addRetry() {
+        this.retry ++;
+    }
+}

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

@@ -0,0 +1,95 @@
+package com.usoftchina.smartschool.wechat.service;
+
+import com.rabbitmq.client.Channel;
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.wechat.mapper.BrokerMessageLogMapper;
+import com.usoftchina.smartschool.wechat.po.MessageInfo;
+import com.usoftchina.smartschool.wechat.po.MessagePackage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.annotation.*;
+import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.handler.annotation.Headers;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: guq
+ * @create: 2019-01-06 22:04
+ **/
+@Service
+public class ReceiveService {
+
+    @Autowired
+    private SendService sendService;
+
+    @Autowired
+    private WxPushService wxPushService;
+
+
+    @Autowired
+    private BrokerMessageLogMapper brokerMessageLogMapper;
+
+    private Logger logger = LoggerFactory.getLogger(ReceiveService.class);
+
+    private final static String DLEXCHANGE = "school-exchange";
+    private final static String QUEUE = "school-active-queue";
+    private final static String ROUTINGKEY = "school-active-key.*";
+
+
+    //配置监听的哪一个队列,同时在没有queue和exchange的情况下会去创建并建立绑定关系
+    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = QUEUE,durable = "true"),
+            exchange = @Exchange(name= DLEXCHANGE ,durable = "true",type = "topic"),
+            key = ROUTINGKEY))
+    @RabbitHandler
+    @Transactional
+    public void onMessage(@Payload MessagePackage msgPackage, @Headers Map<String,Object> headers, Channel channel)
+            throws IOException {
+        //消费者操作
+        logger.info("---------收到消息,消息id={},开始消费---------", msgPackage.getPackageId());
+        List<MessageInfo> data = msgPackage.getData();
+        Result result = null;
+        //记录发送失败次数
+        int count = 0;
+        for (MessageInfo msg : data) {
+            if (!msg.getSend()) {
+                result = wxPushService.wechatPush(msg);
+                if (result.isSuccess()) {
+                    msg.setSend(true);
+                } else {
+                    msg.setReason(result.getMessage());
+                    count ++;
+                }
+            }
+        }
+        //存在发送失败的消息
+        if (count > 0) {
+            msgPackage.addRetry();
+            sendService.sendDelayMessage(msgPackage);
+        }
+        /**
+         * Delivery Tag 用来标识信道中投递的消息。RabbitMQ 推送消息给 Consumer 时,会附带一个 Delivery Tag,
+         * 以便 Consumer 可以在消息确认时告诉 RabbitMQ 到底是哪条消息被确认了。
+         * RabbitMQ 保证在每个信道中,每条消息的 Delivery Tag 从 1 开始递增。
+         */
+        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
+        /**
+         *  multiple 取值为 false 时,表示通知 RabbitMQ 当前消息被确认
+         *  如果为 true,则额外将比第一个参数指定的 delivery tag 小的消息一并确认
+         */
+        boolean multiple = false;
+
+        //ACK,确认一条消息已经被消费
+        channel.basicAck(deliveryTag,multiple);
+        logger.info("消息成功消费,MessageInfo={}", msgPackage);
+        //重新返回队列 重新消费
+        //channel.basicNack(deliveryTag,false,true);
+    }
+}

+ 148 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/SendService.java

@@ -0,0 +1,148 @@
+package com.usoftchina.smartschool.wechat.service;
+
+import com.usoftchina.smartschool.exception.BizException;
+import com.usoftchina.smartschool.exception.ExceptionCode;
+import com.usoftchina.smartschool.utils.BeanMapper;
+import com.usoftchina.smartschool.utils.JsonUtils;
+import com.usoftchina.smartschool.wechat.config.ExpirationMessagePostProcessor;
+import com.usoftchina.smartschool.wechat.config.RabbitConfig;
+
+import com.usoftchina.smartschool.wechat.constant.Status;
+import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
+import com.usoftchina.smartschool.wechat.mapper.BrokerMessageLogMapper;
+import com.usoftchina.smartschool.wechat.po.BrokerMessagelog;
+import com.usoftchina.smartschool.wechat.po.MessageInfo;
+import com.usoftchina.smartschool.wechat.po.MessagePackage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.support.CorrelationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author: guq
+ * @create: 2019-01-06 22:04
+ **/
+@Service
+public class SendService {
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @Autowired
+    private BrokerMessageLogMapper brokerMessageLogMapper;
+
+    @Value("${school.rabbitmq.exchange}")
+    private String exchange;
+
+    /**
+     * 延迟时间
+     */
+    @Value("${school.rabbitmq.delayTime}")
+    private Long delayTime;
+
+    /**
+     * 转发规则
+     */
+    @Value("${school.rabbitmq.activeKey}")
+    private String activeKey;
+
+    /**
+     * 延迟规则
+     */
+    @Value("${school.rabbitmq.delayKey}")
+    private String delayKey;
+
+    @Value("${school.rabbitmq.retry}")
+    private int retry;
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+
+    //发送消息方法调用: 构建自定义对象消息
+    public void sendMessage(MessageInfoDTO messageInfo) {
+        MessageInfo info = BeanMapper.map(messageInfo, MessageInfo.class);
+        if (StringUtils.isEmpty(info.getMsgId())) {
+            info.setMsgId(UUID.randomUUID().toString());
+        }
+        String messageId = info.getMsgId();
+        //统一采用list处理
+        List list = new ArrayList<MessageInfo>();
+        list.add(info);
+        MessagePackage msgPackage = new MessagePackage(list, messageId);
+
+        // 通过实现 ConfirmCallback 接口,消息发送到 Broker 后触发回调,确认消息是否到达 Broker 服务器,也就是只确认是否正确到达 Exchange 中
+        rabbitTemplate.setConfirmCallback(confirmCallback);
+        //消息唯一ID
+        CorrelationData correlationData = new CorrelationData(messageId);
+        rabbitTemplate.convertAndSend(exchange, activeKey, msgPackage, correlationData);
+        logger.info("msgId={}, 消息发送", messageId);
+    }
+
+    //回调函数: confirm确认
+    final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
+        @Override
+        public void confirm(CorrelationData correlationData, boolean confirm, String cause) {
+            String messageId = correlationData.getId();
+            if (confirm) {
+                logger.info("msgId={},已发送服务器", messageId);
+            } else {
+                logger.error("msgId={},发送失败:{}", correlationData.getId(), cause);
+            }
+        }
+    };
+
+    //发送消息方法调用: 构建自定义对象消息
+    public void sendDelayMessage(MessagePackage info) {
+        if (StringUtils.isEmpty(info) || StringUtils.isEmpty(info.getPackageId())) {
+            throw new BizException(ExceptionCode.NULL_DATA);
+        }
+        String messageId = info.getPackageId();
+        int count = info.getRetry();
+        //循环次数大于设置值
+        if (count > retry) {
+            saveErrorMessage(info);
+        } else {
+        //未到设置值,继续投放发送至延迟队列
+        rabbitTemplate.setConfirmCallback(confirmCallback);
+        //消息唯一ID
+        CorrelationData correlationData = new CorrelationData(info.getPackageId());
+        rabbitTemplate.convertAndSend(exchange, delayKey, info,
+                new ExpirationMessagePostProcessor(delayTime), correlationData);
+        }
+    }
+
+    //发送大量数据
+    public void sendOutMessages(List<MessageInfoDTO> messages) {
+        List<MessageInfo> infos = BeanMapper.mapList(messages, MessageInfo.class);
+        MessagePackage msgPackage = new MessagePackage(infos);
+        String messageId = msgPackage.getPackageId();
+
+        //通过实现 ConfirmCallback 接口,消息发送到 Broker 后触发回调,确认消息是否到达 Broker 服务器,也就是只确认是否正确到达 Exchange 中
+        rabbitTemplate.setConfirmCallback(confirmCallback);
+        //消息唯一ID
+        CorrelationData correlationData = new CorrelationData(messageId);
+        rabbitTemplate.convertAndSend(exchange, activeKey, msgPackage, correlationData);
+        logger.info("msgId={}, 消息发送", messageId);
+    }
+
+    private void saveErrorMessage(MessagePackage msgPackage) {
+        String messageId = msgPackage.getPackageId();
+        //消息入库
+        BrokerMessagelog messagelog = new BrokerMessagelog();
+        messagelog.setCreateTime(new Date());
+        messagelog.setMessage(JsonUtils.toJsonString(msgPackage));
+        messagelog.setMsgId(messageId);
+        messagelog.setStatus(Status.FAILURE.getDisplay());
+        brokerMessageLogMapper.insertSelective(messagelog);
+    }
+}

+ 3 - 0
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/WxPushService.java

@@ -1,5 +1,7 @@
 package com.usoftchina.smartschool.wechat.service;
 
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.wechat.po.MessageInfo;
 import org.apache.ibatis.annotations.Param;
 
 public interface WxPushService {
@@ -16,5 +18,6 @@ public interface WxPushService {
                          @Param("keyword3") String keyword3, @Param("keyword4") String keyword4,
                          @Param("remark") String remark, @Param("url") String url);
 
+    public Result wechatPush(MessageInfo info);
     /*public String getWxAccessToken(@Param("appId") String appId, @Param("secret") String secret);*/
 }

+ 48 - 2
applications/wechat/wechat-server/src/main/java/com/usoftchina/smartschool/wechat/service/impl/WxPushServiceImpl.java

@@ -2,8 +2,12 @@ package com.usoftchina.smartschool.wechat.service.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.github.kevinsawicki.http.HttpRequest;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.wechat.po.MessageInfo;
 import com.usoftchina.smartschool.wechat.service.WxPushService;
 import com.usoftchina.smartschool.wechat.wxUtils.ObjectUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
@@ -11,6 +15,10 @@ import java.util.HashMap;
 @Service
 public class WxPushServiceImpl implements WxPushService{
 
+
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    private static final String WECHATURL = "https://api.weixin.qq.com/cgi-bin";
     /**
      * 推送消息
      * @param
@@ -34,11 +42,11 @@ public class WxPushServiceImpl implements WxPushService{
                 params.put("appid", appId);
                 params.put("secret", secret);
                 params.put("grant_type", "client_credential");
-                HttpRequest httpRequest= HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token",params,false);
+                HttpRequest httpRequest= HttpRequest.get(WECHATURL + "/token",params,false);
                 String content=httpRequest.body();
                 System.err.println("getWxAccessTokenContent======"+content);
                 String token= JSON.parseObject(content).getString("access_token");
-                HttpRequest hRequest=  HttpRequest.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+token)
+                HttpRequest hRequest=  HttpRequest.post(WECHATURL + "/message/template/send?access_token="+token)
                         .header("Content-Type", "application/json")
                         .send(json.getBytes());
                 String result= hRequest.body();
@@ -60,4 +68,42 @@ public class WxPushServiceImpl implements WxPushService{
 
             return token;
         }*/
+
+    /**
+     * 推送消息
+     * @param
+     */
+    @Override
+    public Result wechatPush(MessageInfo info) {
+        if (ObjectUtils.isNotEmpty(info.getTouser())){
+            String json="{\"touser\":\"" + info.getTouser() + "\","
+                    + "\"template_id\":\"" + info.getTemplateId() + "\","
+                    + "\"url\":\"" + "" + info.getUrl() + "" + "\","
+                    + "\"data\":{"
+                    + "\"first\":{\"value\":\"" + info.getTitle() + "\","
+                    +"\"color\":\"#173177\"},"
+                    + "\"keyword1\":{\"value\":\"" + info.getKeyword1() + "\",\"color\":\"#173177\"},"
+                    + "\"keyword2\":{\"value\":\"" + info.getKeyword2() + "\",\"color\":\"#173177\"},"
+                    + "\"keyword3\":{\"value\":\"" + info.getKeyword3() + "\",\"color\":\"#173177\"},"
+                    + "\"keyword4\":{\"value\":\"" + info.getKeyword4() + "\",\"color\":\"#173177\"},"
+                    + "\"remark\":{\"value\":\"" + info.getRemark() + "\",\"color\":\"#173177\"}}}";
+
+            HashMap<String, Object> params=new HashMap<>();
+            params.put("appid", info.getAppId());
+            params.put("secret", info.getSecret());
+            params.put("grant_type", "client_credential");
+            HttpRequest httpRequest= HttpRequest.get(WECHATURL + "/token",params,false);
+            String content=httpRequest.body();
+            String token= JSON.parseObject(content).getString("access_token");
+            HttpRequest hRequest=  HttpRequest.post(WECHATURL + "/message/template/send?access_token="+token)
+                    .header("Content-Type", "application/json")
+                    .send(json.getBytes());
+            String result= hRequest.body();
+            logger.info("result={}", result);
+            if (result.equals("error")) {
+                Result.error(result);
+            }
+        }
+        return Result.success();
+    }
 }

+ 16 - 5
applications/wechat/wechat-server/src/main/resources/application.yml

@@ -22,11 +22,13 @@ spring:
     basename: i18n/messages
     encoding: UTF-8
   rabbitmq:
-    host: 10.10.100.166
-    port: 3306
+    host: 10.10.100.103
+    port: 5672
     virtual-host: school
-    username: school
-    password: select111***
+    username: saas
+    password: select123***
+    publisher-returns: true
+    publisher-confirms: true
   zipkin:
     sender:
       type: rabbit
@@ -89,4 +91,13 @@ hystrix:
                 enabled: true
               isolation:
                     thread:
-                        timeoutInMilliseconds: 4000
+                        timeoutInMilliseconds: 4000
+school:
+  rabbitmq:
+    exchange: school-exchange
+    activeQueue: school-active-queue
+    delayQueue: school-delay-queue
+    activeKey: school-active-key.*
+    delayKey: school-delay-key.*
+    delayTime: 20000
+    retry: 2

+ 0 - 125
applications/wechat/wechat-server/src/main/resources/logback-spring.xml

@@ -1,125 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-    <include resource="org/springframework/boot/logging/logback/base.xml" />
-    <jmxConfigurator/>
-
-    <!--
-    %m
-    输出代码中指定的消息
-    %p
-    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
-    %r
-    输出自应用启动到输出该log信息耗费的毫秒数
-    %c
-    输出所属的类目,通常就是所在类的全名
-    %t
-    输出产生该日志事件的线程名
-    %n
-    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
-    %d
-    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
-    输出类似:2002年10月18日 22:10:28,921
-    %l
-    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
-    -->
-
-    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/smartschool/wechat-server"/>
-    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="wechat-server"/>
-    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
-    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
-    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
-    <springProperty scope="context" name="log.destination" source="logging.destination" defaultValue="10.1.81.1:5000"/>
-
-    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
-
-    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
-        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
-            <level>${log.level.console}</level>
-        </filter>
-        <encoder>
-            <pattern>${common-pattern}</pattern>
-        </encoder>
-    </appender>
-
-    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <file>${log.path}/root.log</file>
-        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
-            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
-            <maxFileSize>128MB</maxFileSize>
-            <maxHistory>7</maxHistory>
-            <totalSizeCap>20GB</totalSizeCap>
-        </rollingPolicy>
-        <encoder>
-            <pattern>${common-pattern}</pattern>
-        </encoder>
-    </appender>
-
-    <!-- Appender to log in a JSON format -->
-    <appender name="JSON_APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
-        <destination>${log.destination}</destination>
-        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
-            <providers>
-                <pattern>
-                    <pattern>
-                        {
-                        "severity": "%level",
-                        "service": "${spring.application.name:-}",
-                        "trace": "%X{X-B3-TraceId:-}",
-                        "span": "%X{X-B3-SpanId:-}",
-                        "parent": "%X{X-B3-ParentSpanId:-}",
-                        "exportable": "%X{X-Span-Export:-}",
-                        "pid": "${PID:-}",
-                        "thread": "%thread",
-                        "class": "%logger{40}",
-                        "rest": "%message"
-                        }
-                    </pattern>
-                </pattern>
-            </providers>
-        </encoder>
-    </appender>
-
-    <logger name="org.springframework" level="INFO"/>
-    <logger name="com.usoftchina.smartschool" level="INFO"/>
-
-    <springProfile name="dev">
-        <root level="INFO">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="test">
-        <root level="INFO">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="ROOT_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.smartschool" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker-test">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.smartschool" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker-prod">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.smartschool" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-</configuration>

+ 128 - 0
applications/wechat/wechat-server/src/main/resources/mapper/BrokermessagelogMapper.xml

@@ -0,0 +1,128 @@
+<?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.wechat.mapper.BrokerMessageLogMapper" >
+  <resultMap id="BaseResultMap" type="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    <id column="id" property="id" jdbcType="INTEGER" />
+    <result column="msgId" property="msgId" jdbcType="VARCHAR" />
+    <result column="message" property="message" jdbcType="LONGVARCHAR" />
+    <result column="status" property="status" jdbcType="VARCHAR" />
+    <result column="createTime" property="createTime" jdbcType="TIMESTAMP" />
+    <result column="reason" property="reason" jdbcType="VARCHAR" />
+    <result column="retry" property="retry" jdbcType="INTEGER" />
+  </resultMap>
+  <sql id="Base_Column_List" >
+    id, msgId, message, status, createTime, reason, retry
+  </sql>
+  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
+    select 
+    <include refid="Base_Column_List" />
+    from brokermessagelog
+    where id = #{id,jdbcType=INTEGER}
+  </select>
+
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
+    delete from brokermessagelog
+    where id = #{id,jdbcType=INTEGER}
+  </delete>
+  <insert id="insert" parameterType="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    insert into brokermessagelog (msgId, message,
+      status, createTime, reason
+      )
+    values ( #{msgId,jdbcType=VARCHAR}, #{message,jdbcType=VARCHAR},
+      #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{reason,jdbcType=VARCHAR}
+      )
+  </insert>
+  <insert id="insertSelective" parameterType="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    insert into brokermessagelog
+    <trim prefix="(" suffix=")" suffixOverrides="," >
+      <if test="msgId != null" >
+        msgId,
+      </if>
+      <if test="message != null" >
+        message,
+      </if>
+      <if test="status != null" >
+        status,
+      </if>
+      <if test="createTime != null" >
+        createTime,
+      </if>
+      <if test="reason != null" >
+        reason,
+      </if>
+      <if test="retry != null" >
+        retry,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides="," >
+      <if test="msgId != null" >
+        #{msgId,jdbcType=VARCHAR},
+      </if>
+      <if test="message != null" >
+        #{message,jdbcType=LONGVARCHAR},
+      </if>
+      <if test="status != null" >
+        #{status,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null" >
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="reason != null" >
+        #{reason,jdbcType=VARCHAR},
+      </if>
+      <if test="retry != null" >
+        #{retry},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    update brokermessagelog
+    <set >
+      <if test="message != null" >
+        message = #{message,jdbcType=VARCHAR},
+      </if>
+      <if test="status != null" >
+        status = #{status,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null" >
+        createTime = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="reason != null" >
+        reason = #{reason,jdbcType=VARCHAR},
+      </if>
+    </set>
+    where msgId = #{msgId,jdbcType=VARCHAR}
+  </update>
+
+  <update id="updateMessageLogandAddRetry" parameterType="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    update brokermessagelog
+    set  status = #{status}, reason = #{reason}, retry = retry + 1
+    where msgId = #{msgId,jdbcType=VARCHAR}
+  </update>
+
+  <update id="updateByPrimaryKey" parameterType="com.usoftchina.smartschool.wechat.po.BrokerMessagelog" >
+    update brokermessagelog
+    set msgId = #{msgId,jdbcType=VARCHAR},
+      message = #{message,jdbcType=VARCHAR},
+      status = #{status,jdbcType=VARCHAR},
+      createTime = #{createTime,jdbcType=TIMESTAMP},
+      reason = #{reason,jdbcType=VARCHAR}
+    where id = #{id,jdbcType=INTEGER}
+  </update>
+
+  <select id="getMessage" parameterType="string" resultMap="BaseResultMap">
+    select * from BrokerMessagelog where msgId = #{msgId}
+  </select>
+
+  <select id="getLiveMessage" parameterType="string" resultMap="BaseResultMap">
+    select * from BrokerMessagelog where msgId = #{msgId} and retry &lt; 3
+  </select>
+
+  <select id="getDeadMessage" parameterType="string" resultMap="BaseResultMap">
+    select * from BrokerMessagelog where msgId = #{msgId} and retry &gt; 3
+  </select>
+
+  <update id="updateSuccess" parameterType="string">
+    update BrokerMessagelog set status='投递成功',reason='' where msgid = #{msgId}
+  </update>
+</mapper>

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

@@ -62,6 +62,12 @@ spring:
         - Path=/api/auth/**
         filters:
         - RewritePath=/api/auth/(?<segment>.*), /$\{segment}
+      - id: DEVICE-SERVER
+        uri: lb://DEVICE-SERVER
+        predicates:
+        - Path=/api/device/**
+        filters:
+        - RewritePath=/api/device/(?<segment>.*), /$\{segment}
   redis:
     host: 10.10.100.166
     port: 6379

+ 0 - 131
base-servers/gateway-server/src/main/resources/logback-spring.xml

@@ -1,131 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-    <include resource="org/springframework/boot/logging/logback/base.xml" />
-    <jmxConfigurator/>
-
-    <!--
-    %m
-    输出代码中指定的消息
-    %p
-    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
-    %r
-    输出自应用启动到输出该log信息耗费的毫秒数
-    %c
-    输出所属的类目,通常就是所在类的全名
-    %t
-    输出产生该日志事件的线程名
-    %n
-    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
-    %d
-    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
-    输出类似:2002年10月18日 22:10:28,921
-    %l
-    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
-    -->
-
-    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/saas/gateway-server"/>
-    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="gateway-server"/>
-    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
-    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
-    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
-    <springProperty scope="context" name="log.destination" source="logging.destination" defaultValue="10.1.81.1:5000"/>
-
-    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
-
-    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
-        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
-            <level>${log.level.console}</level>
-        </filter>
-        <encoder>
-            <pattern>${common-pattern}</pattern>
-        </encoder>
-    </appender>
-
-    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <file>${log.path}/root.log</file>
-        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
-            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
-            <maxFileSize>128MB</maxFileSize>
-            <maxHistory>7</maxHistory>
-            <totalSizeCap>20GB</totalSizeCap>
-        </rollingPolicy>
-        <encoder>
-            <pattern>${common-pattern}</pattern>
-        </encoder>
-    </appender>
-
-    <!-- Appender to log in a JSON format -->
-    <appender name="JSON_APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
-        <destination>${log.destination}</destination>
-        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
-            <providers>
-                <pattern>
-                    <pattern>
-                        {
-                        "severity": "%level",
-                        "service": "${spring.application.name:-}",
-                        "trace": "%X{X-B3-TraceId:-}",
-                        "span": "%X{X-B3-SpanId:-}",
-                        "parent": "%X{X-B3-ParentSpanId:-}",
-                        "exportable": "%X{X-Span-Export:-}",
-                        "pid": "${PID:-}",
-                        "thread": "%thread",
-                        "class": "%logger{40}",
-                        "rest": "%message"
-                        }
-                    </pattern>
-                </pattern>
-            </providers>
-        </encoder>
-    </appender>
-
-    <logger name="org.springframework" level="INFO"/>
-    <logger name="com.usoftchina.saas" level="INFO"/>
-
-    <springProfile name="dev">
-        <root level="INFO">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="test">
-        <root level="INFO">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="ROOT_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.saas" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker-dev">
-        <root level="INFO">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker-test">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.saas" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-    <springProfile name="docker-prod">
-        <logger name="org.springframework" level="WARN"/>
-        <logger name="com.usoftchina.saas" level="WARN"/>
-        <root level="WARN">
-            <appender-ref ref="CONSOLE_APPENDER"/>
-            <appender-ref ref="JSON_APPENDER"/>
-        </root>
-    </springProfile>
-
-</configuration>

+ 2 - 1
framework/core/src/main/java/com/usoftchina/smartschool/exception/ExceptionCode.java

@@ -63,7 +63,8 @@ public enum ExceptionCode implements BaseExceptionCode {
     TURNIN_EXIST(60000,"已入库"),
     TURNINNUM_NOT_EXIST(60001,"该采购单已全部转验收,无法转采购验收单"),
 
-    CLOSED_EXIST(60002,"已关闭")
+    CLOSED_EXIST(60002,"已关闭"),
+    NULL_DATA(60003,"无效数据")
 
     ;
 

+ 2 - 1
frontend/pc-web/app/Application.js

@@ -15,7 +15,8 @@ Ext.define('school.Application', {
         // TODO: add global / shared stores here
         'school.store.Grade',
         'school.store.Class',
-        'school.store.Subject'
+        'school.store.Subject',
+        'school.store.GradeClass'
     ],
 
     defaultToken: 'main',

+ 47 - 0
frontend/pc-web/app/store/GradeClass.js

@@ -0,0 +1,47 @@
+/**
+ * 年级组织
+ */
+Ext.define('school.store.GradeClass', {
+    extend: 'Ext.data.TreeStore',
+    alias: 'store.store_gradeclass',
+
+    storeId: 'store_gradeclass',
+
+    fields: [{
+        name: 'text'
+    }],
+    root: {
+        text: '全年级',
+        type: 'SCHOOL',
+        expanded: false
+    },
+    autoLoad: false,
+    proxy: {
+        type: 'ajax',
+        // url: 'http://10.1.80.47:9560/grade/read',
+        url: '/api/school/grade/read',
+        reader: {
+            transform: {
+                fn: function(data) {
+                    let grades = [];
+                    if(!!data.data) {
+                        grades = data.data.children || [];
+                        grades.map(function(s) {
+                            s._id = s.id;
+                            s.id = 'grade-' + s.id;
+                            let classes = s.children;
+                            let d = classes.map(function(c) {
+                                c._id = c.id;
+                                c.id = 'class-' + c.id;
+                                return c;
+                            });
+                            return s;
+                        });
+                    }
+                    return grades;
+                },
+                scope: this
+            }
+        }
+    }
+});

+ 7 - 0
frontend/pc-web/app/view/Interaction/homework/Release.js

@@ -129,6 +129,13 @@ Ext.define('school.view.interaction.homework.Release', {
                     disabled: '{!base.valid}'
                 }
             }],
+            applyBtns: [{
+                apply: true,
+                text: '删除',
+                bind: {
+                    hidden: '{!showDeleteBtn || !task_id || task_status == 1}'
+                },
+            }],
             toolBtns: [{
                 xtype: 'button',
                 text: '发布',

+ 31 - 0
frontend/pc-web/app/view/Interaction/score/Detail.js

@@ -44,6 +44,21 @@ Ext.define('school.view.interaction.score.Detail', {
                 xtype: 'classcombo',
                 name: 'si_class',
                 fieldLabel: '班级'
+            }, {
+                xtype: 'combobox',
+                name: 'si_publish',
+                fieldLabel: '发布状态',
+                displayField: 'name',
+                valueField: 'value',
+                editable: false,
+                readOnly: true,
+                defaultValue: 0,
+                store: Ext.create('Ext.data.ArrayStore', {
+                    fields: ['name', 'value'],
+                    data: [['未发布', 0], ['已发布', 1]]
+                }),
+                minChars: 0,
+                queryMode: 'local'
             }, {
                 name: "score",
                 xtype: "detailGridField",
@@ -71,6 +86,22 @@ Ext.define('school.view.interaction.score.Detail', {
                     dataIndex: 'sd_remark'
                 }]
             }],
+            applyBtns: [{
+                apply: true,
+                text: '删除',
+                bind: {
+                    hidden: '{!showDeleteBtn || !si_id || si_publish == 1}'
+                },
+            }],
+            toolBtns: [{
+                xtype: 'button',
+                text: '发布',
+                hidden: true,
+                bind: {
+                    hidden: '{!si_id || si_publish == 1}'
+                },
+                handler: 'onPublish'
+            }]
         });
         this.callParent();
         this.setEditable(false);

+ 23 - 0
frontend/pc-web/app/view/Interaction/score/DetailController.js

@@ -14,4 +14,27 @@ Ext.define('school.view.interaction.score.DetailController', {
             school.util.BaseUtil.refreshTabTitle(newId, newTitle);
         });
     },
+
+    onPublish: function() {
+        let me = this,
+        view = me.getView(),
+        viewModel = me.getViewModel(),
+        id = viewModel.data.si_id;
+        view.setLoading(true);
+        school.util.BaseUtil.request({
+            // url: 'http://10.1.80.180:9520/api/school/score/publish/' + id,
+            url: '/api/school/score/publish/' + id,
+            method: 'POST'
+        })
+        .then(function() {
+            view.setLoading(false);
+            school.util.BaseUtil.showSuccessToast('发布成功');
+            viewModel.set('si_publish', 1);
+            me.refresh();
+        })
+        .catch(function(e) {
+            view.setLoading(false);
+            school.util.BaseUtil.showErrorToast('发布失败: ' + e.message);
+        });
+    }
 });

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

@@ -80,10 +80,10 @@ Ext.define('school.view.interaction.score.List', {
                 },
                 hiddenTools: false,
                 toolBtns: [{
-                    xtype: 'button',
-                    text: '新增',
-                    handler: 'onAddClick'
-                }, {
+                //     xtype: 'button',
+                //     text: '新增',
+                //     handler: 'onAddClick'
+                // }, {
                     xtype: 'importbutton',
                     text: '导入',
                     belong: me,

+ 139 - 134
frontend/pc-web/app/view/Interaction/timetable/Detail.js

@@ -111,7 +111,7 @@ Ext.define('school.view.interaction.timetable.Detail', {
                     let o1, o2;
                     o1 = [(year - 1) + '-' + year];
                     o2 = [year + '-' + (year + 1)];
-                    return (month < 9) ? o1 : o2
+                    return (month < 9) ? o1[0] : o2[0]
                 })()
             }, {
                 xtype: "combobox",
@@ -174,150 +174,150 @@ Ext.define('school.view.interaction.timetable.Detail', {
                     text: 'id',
                     dataIndex: 'id',
                     hidden: true
-                }, {
-                    text: '时间段',
-                    xtype: 'widgetcolumn',
-                    width: 200,
-                    padding: 0,
-                    tdCls: 'x-period-column',
-                    getBindField: function(c) {
-                        return ['startTime', 'endTime']
-                    },
-                    widget: {
-                        xtype: 'container',
-                        style: {
-                            textAlign: 'center'
-                        },
-                        items: [{
-                            xtype: 'button',
-                            bind: {
-                                text: '{record._timeText1}',
-                            },
-                            style: {
-                                margin: '5px',
-                                height: '22px',
-                                width: '74px',
-                                padding: 0
-                            },
-                            handler: function(btn) {
-                                let record = btn.ownerCt.$widgetRecord;
-                                let store = record.store;
-                                let idx = record.get('lessons') - 2;
-                                let preRecord, preDate;
+                // }, {
+                //     text: '时间段',
+                //     xtype: 'widgetcolumn',
+                //     width: 200,
+                //     padding: 0,
+                //     tdCls: 'x-period-column',
+                //     getBindField: function(c) {
+                //         return ['startTime', 'endTime']
+                //     },
+                //     widget: {
+                //         xtype: 'container',
+                //         style: {
+                //             textAlign: 'center'
+                //         },
+                //         items: [{
+                //             xtype: 'button',
+                //             bind: {
+                //                 text: '{record._timeText1}',
+                //             },
+                //             style: {
+                //                 margin: '5px',
+                //                 height: '22px',
+                //                 width: '74px',
+                //                 padding: 0
+                //             },
+                //             handler: function(btn) {
+                //                 let record = btn.ownerCt.$widgetRecord;
+                //                 let store = record.store;
+                //                 let idx = record.get('lessons') - 2;
+                //                 let preRecord, preDate;
 
-                                if(idx > -1) {
-                                    preRecord = store.getAt(idx);
-                                    preDate = preRecord.get('_time2');
+                //                 if(idx > -1) {
+                //                     preRecord = store.getAt(idx);
+                //                     preDate = preRecord.get('_time2');
 
-                                    if(!!preDate && Ext.Date.format(preDate, 'H:i') != '00:00' && Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME) <= Ext.Date.parse(Ext.Date.format(preDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
-                                        record.set('startTime', Ext.Date.format(Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME), 'H:i:s'));
-                                    }
-                                }
+                //                     if(!!preDate && Ext.Date.format(preDate, 'H:i') != '00:00' && Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME) <= Ext.Date.parse(Ext.Date.format(preDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
+                //                         record.set('startTime', Ext.Date.format(Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME), 'H:i:s'));
+                //                     }
+                //                 }
                                 
-                                me.currentRecord = record;
-                            },
-                            menu: {
-                                xtype: 'menu',
-                                plain: true,
-                                items: [{
-                                    xtype: 'timepicker',
-                                    maxHeight: 300,
-                                    increment: 5,
-                                    format: 'H:i',
-                                    minValue: me.START_TIME,
-                                    maxValue: me.END_TIME,
-                                    listeners: {
-                                        select: function(model, record, index, eOpts) {
-                                            me.onSelectPeriod0(this, this.up(), record);
-                                        },
-                                    }
-                                }],
-                                listeners: {
-                                    beforeshow: function(th, eOpts) {
-                                        let record = th.ownerCmp.ownerCt.$widgetRecord
-                                        let picker = th.down('timepicker');
-                                        let store = th.ownerCmp.ownerCt.$widgetRecord.store;
-                                        let idx = record.get('lessons') - 2;
-                                        let preRecord, preDate, minValue;
+                //                 me.currentRecord = record;
+                //             },
+                //             menu: {
+                //                 xtype: 'menu',
+                //                 plain: true,
+                //                 items: [{
+                //                     xtype: 'timepicker',
+                //                     maxHeight: 300,
+                //                     increment: 5,
+                //                     format: 'H:i',
+                //                     minValue: me.START_TIME,
+                //                     maxValue: me.END_TIME,
+                //                     listeners: {
+                //                         select: function(model, record, index, eOpts) {
+                //                             me.onSelectPeriod0(this, this.up(), record);
+                //                         },
+                //                     }
+                //                 }],
+                //                 listeners: {
+                //                     beforeshow: function(th, eOpts) {
+                //                         let record = th.ownerCmp.ownerCt.$widgetRecord
+                //                         let picker = th.down('timepicker');
+                //                         let store = th.ownerCmp.ownerCt.$widgetRecord.store;
+                //                         let idx = record.get('lessons') - 2;
+                //                         let preRecord, preDate, minValue;
                                         
-                                        me.currentRecord = record;
+                //                         me.currentRecord = record;
 
-                                        if(idx > -1) {
-                                            preRecord = store.getAt(idx);
-                                            preDate = preRecord.get('_time2');
-                                            if(Ext.Date.format(preDate, 'H:i') == '00:00') {
-                                                school.util.BaseUtil.showErrorToast('请先完成上一课时设置');
-                                                return false;
-                                            }
-                                            if(Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME) >= Ext.Date.parse(Ext.Date.format(preDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
-                                                school.util.BaseUtil.showErrorToast('可用课程时间不足(08:00~22:00)');
-                                            }
-                                            minValue = Ext.Date.add(preDate, Ext.Date.MINUTE, me.MIN_BREAK_TIME);
-                                        }else {
-                                            minValue = Ext.Date.parse('08:00', 'H:i');
-                                        }
+                //                         if(idx > -1) {
+                //                             preRecord = store.getAt(idx);
+                //                             preDate = preRecord.get('_time2');
+                //                             if(Ext.Date.format(preDate, 'H:i') == '00:00') {
+                //                                 school.util.BaseUtil.showErrorToast('请先完成上一课时设置');
+                //                                 return false;
+                //                             }
+                //                             if(Ext.Date.add(preDate, Ext.Date.MINUTE, me.BREAK_TIME) >= Ext.Date.parse(Ext.Date.format(preDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
+                //                                 school.util.BaseUtil.showErrorToast('可用课程时间不足(08:00~22:00)');
+                //                             }
+                //                             minValue = Ext.Date.add(preDate, Ext.Date.MINUTE, me.MIN_BREAK_TIME);
+                //                         }else {
+                //                             minValue = Ext.Date.parse('08:00', 'H:i');
+                //                         }
 
-                                        picker.setMinValue(minValue)
-                                    },
-                                }
-                            },
-                        }, {
-                            xtype: 'button',
-                            bind: {
-                                text: '{record._timeText2}',
-                            },
-                            style: {
-                                margin: '5px',
-                                height: '22px',
-                                width: '74px',
-                                padding: 0
-                            },
-                            handler: function(btn) {
-                                let record = btn.ownerCt.$widgetRecord;
-                                let startDate = record.get('_time1');
+                //                         picker.setMinValue(minValue)
+                //                     },
+                //                 }
+                //             },
+                //         }, {
+                //             xtype: 'button',
+                //             bind: {
+                //                 text: '{record._timeText2}',
+                //             },
+                //             style: {
+                //                 margin: '5px',
+                //                 height: '22px',
+                //                 width: '74px',
+                //                 padding: 0
+                //             },
+                //             handler: function(btn) {
+                //                 let record = btn.ownerCt.$widgetRecord;
+                //                 let startDate = record.get('_time1');
                                 
-                                if(Ext.Date.format(startDate, 'H:i') != '00:00' && Ext.Date.add(startDate, Ext.Date.MINUTE, me.CLASS_TIME) <= Ext.Date.parse(Ext.Date.format(startDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
-                                    record.set('endTime', Ext.Date.format(Ext.Date.add(startDate, Ext.Date.MINUTE, me.CLASS_TIME), 'H:i:s'));
-                                }
+                //                 if(Ext.Date.format(startDate, 'H:i') != '00:00' && Ext.Date.add(startDate, Ext.Date.MINUTE, me.CLASS_TIME) <= Ext.Date.parse(Ext.Date.format(startDate, 'Y-m-d') + ' 22:00:00', 'Y-m-d H:i:s')) {
+                //                     record.set('endTime', Ext.Date.format(Ext.Date.add(startDate, Ext.Date.MINUTE, me.CLASS_TIME), 'H:i:s'));
+                //                 }
 
-                                me.currentRecord = record;
-                            },
-                            menu: {
-                                xtype: 'menu',
-                                plain: true,
-                                items: [{
-                                    xtype: 'timepicker',
-                                    maxHeight: 300,
-                                    increment: 5,
-                                    format: 'H:i',
-                                    minValue: me.START_TIME,
-                                    maxValue: me.END_TIME,
-                                    listeners: {
-                                        select: function(model, record, index, eOpts) {
-                                            me.onSelectPeriod1(this, this.up(), record);
-                                        },
-                                    }
-                                }],
-                                listeners: {
-                                    beforeshow: function(th, eOpts) {
-                                        let record = th.ownerCmp.ownerCt.$widgetRecord;
-                                        let picker = th.down('timepicker');
+                //                 me.currentRecord = record;
+                //             },
+                //             menu: {
+                //                 xtype: 'menu',
+                //                 plain: true,
+                //                 items: [{
+                //                     xtype: 'timepicker',
+                //                     maxHeight: 300,
+                //                     increment: 5,
+                //                     format: 'H:i',
+                //                     minValue: me.START_TIME,
+                //                     maxValue: me.END_TIME,
+                //                     listeners: {
+                //                         select: function(model, record, index, eOpts) {
+                //                             me.onSelectPeriod1(this, this.up(), record);
+                //                         },
+                //                     }
+                //                 }],
+                //                 listeners: {
+                //                     beforeshow: function(th, eOpts) {
+                //                         let record = th.ownerCmp.ownerCt.$widgetRecord;
+                //                         let picker = th.down('timepicker');
 
-                                        if(Ext.Date.format(record.get('_time1'), 'H:i') == '00:00') {
-                                            school.util.BaseUtil.showErrorToast('请先设置开始时间');
-                                            return false;
-                                        }
+                //                         if(Ext.Date.format(record.get('_time1'), 'H:i') == '00:00') {
+                //                             school.util.BaseUtil.showErrorToast('请先设置开始时间');
+                //                             return false;
+                //                         }
 
-                                        let startDate = record.get('_time1') || Ext.Date.parse('08:00', 'H:i');
-                                        let minValue = Ext.Date.add(startDate, Ext.Date.MINUTE, me.MIN_MIN_WHILE);
-                                        me.currentRecord = record;
+                //                         let startDate = record.get('_time1') || Ext.Date.parse('08:00', 'H:i');
+                //                         let minValue = Ext.Date.add(startDate, Ext.Date.MINUTE, me.MIN_MIN_WHILE);
+                //                         me.currentRecord = record;
 
-                                        picker.setMinValue(minValue)
-                                    },
-                                }
-                            },
-                        }]
-                    }
+                //                         picker.setMinValue(minValue)
+                //                     },
+                //                 }
+                //             },
+                //         }]
+                //     }
                 }, {
                     text: '星期一',
                     dataIndex: 'mon',
@@ -350,6 +350,11 @@ Ext.define('school.view.interaction.timetable.Detail', {
                     hidden: true
                 }]
             }],
+            // toolBtns: [{
+            //     xtype: 'button',
+            //     text: '发布',
+            //     handler: 'onPublish'
+            // }]
         });
         this.callParent();
     },

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

@@ -80,7 +80,7 @@ Ext.define('school.view.interaction.timetable.List', {
                     let o1, o2;
                     o1 = [(year - 1) + '-' + year];
                     o2 = [year + '-' + (year + 1)];
-                    return (month < 9) ? o1 : o2
+                    return (month < 9) ? o1[0] : o2[0]
                 })()
             }, {
                 xtype: "combobox",

+ 10 - 4
frontend/pc-web/app/view/basic/class/ClassInfo.js

@@ -18,6 +18,7 @@ Ext.define('school.view.basic.class.ClassInfo', {
 
     initComponent: function() {
         let me = this;
+        let store = Ext.StoreMgr.get('store_gradeclass');
         Ext.apply(me, {
             items: [{
                 region: 'west',
@@ -28,8 +29,8 @@ Ext.define('school.view.basic.class.ClassInfo', {
                 width: 250,
                 xtype: 'treepanel',
                 reference: 'treelist',
+                store: store,
                 bind: {
-                    store: '{store_gradeclass}',
                     width: '{treeWidth}'
                 },
                 // viewConfig: {
@@ -81,9 +82,14 @@ Ext.define('school.view.basic.class.ClassInfo', {
                     caller: 'GradeAndCLass',
                     pathKey: 'grade',
                     onSuccess: function() {
-                        let viewModel = me.getViewModel();
-        
-                        viewModel.get('store_gradeclass').load();
+                        let treePanel = me.down('treepanel');
+                        let listCard = me.down('listcard');
+                        let treeStore = treePanel.store;
+                        treeStore.load(function() {
+                            let rootNode = treeStore.getRootNode();
+                            rootNode.expand();
+                            listCard.showNode(rootNode);
+                        });
                     }
                 }, '->'],
                 listeners: {

+ 9 - 3
frontend/pc-web/app/view/basic/class/ClassInfoController.js

@@ -4,13 +4,19 @@ Ext.define('school.view.basic.class.ClassInfoController', {
 
     onBeforeRender: function() {
         let me = this,
-        view = me.getView(),
-        viewModel = me.getViewModel();
+        refs = me.getReferences(),
+        treeList = refs.treelist,
+        listCard = refs.listcard,
+        treeStore = treeList.store;
 
         Ext.StoreMgr.get('store_grade').load();
         Ext.StoreMgr.get('store_class').load();
         Ext.StoreMgr.get('store_subject').load();
-        viewModel.get('store_gradeclass').load();
+        treeStore.load(function(records, operation, success) {
+            let rootNode = treeStore.getRootNode();
+            rootNode.expand();
+            listCard.showNode(rootNode);
+        });
     },
 
     onItemMouseEnter: function(tree, record, item, index, e, eOpts)  {

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

@@ -34,8 +34,7 @@ Ext.define('school.view.basic.class.ListCard', {
     singleSelect: true,
     itemSelector: '.item',
     listeners: {
-        itemclick: 'cardItemClick',
-        beforeRender: 'onBeforeRender'
+        itemclick: 'cardItemClick'
     },
 
     showNode: function(node) {

+ 0 - 9
frontend/pc-web/app/view/basic/class/ListCardController.js

@@ -2,15 +2,6 @@ Ext.define('school.view.basic.class.ListCardController', {
     extend: 'Ext.app.ViewController',
     alias: 'controller.listcard',
 
-    onBeforeRender: function() {
-        var me = this,
-        view = me.view,
-        viewModel = me.getViewModel(),
-        grade = viewModel.get('store_gradeclass');
-
-        view.showNode(grade.getRootNode());
-    },
-
     cardItemClick: function(view, record, navItem, index, e, eOpts) {
         var me = this;
         var view = me.getView();

+ 1 - 0
frontend/pc-web/app/view/basic/subject/List.js

@@ -37,6 +37,7 @@ Ext.define('school.view.basic.subject.List', {
                 selModel: {
                     type: 'cellmodel'
                 },
+                disableDetail: true,
                 hiddenTools: false,
                 toolBtns: [{
                     xtype: 'button',

+ 25 - 29
frontend/pc-web/app/view/basic/subject/ListController.js

@@ -73,7 +73,7 @@ Ext.define('school.view.basic.subject.ListController', {
         if(targetCls.contains('fa-pencil')) {
             me.modifyClick(record.data);
         }else if(targetCls.contains('fa-trash-o')) {
-            me.onDeleteClick(record.data.subject_id);
+            me.onDeleteClick(record);
         }
     },
 
@@ -144,41 +144,37 @@ Ext.define('school.view.basic.subject.ListController', {
         win.show();
     },
 
-    onDeleteClick: function(id) {
+    onDeleteClick: function(record) {
         let me = this,
         view = me.getView(),
         grid = view.down('grid'),
-        selectedRecords = grid.getSelection(),
+        id = record.data.subject_id,
         data;
 
-        data = id ? [{
+        data = [{
             id: id
-        }] : selectedRecords.map(function(r) {
-            return {
-                id: r.get('subject_id')
-            };
-        });
-
-        if(data.length == 0) {
-            school.util.BaseUtil.showErrorToast('请先勾选需要删除的记录');
-            return;
-        }
+        }];
 
-        grid.setLoading(true);
-        school.util.BaseUtil.request({
-            // url: 'http://10.1.80.47:9560/student/batchDelete',
-            url: '/api/school/subject/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('确认删除', '确定要删除学科' + record.get('subject_name') + '吗?')
+        .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/subject/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);
+                });
+            }
         });
     }
 

+ 90 - 0
frontend/pc-web/app/view/setting/device/List.js

@@ -0,0 +1,90 @@
+/**
+ * 设备参数列表
+ */
+Ext.define('school.view.setting.device.List', {
+    extend: 'school.view.core.base.BasePanel',
+    xtype: 'setting-device-list',
+
+    controller: 'setting-device-list',
+
+    // dataUrl: 'http://10.1.80.47:9520/api/device/device/list',
+    dataUrl: '/api/device/device/list',
+    _title: '设备参数',
+    caller: null,
+    pathKey: null,
+
+    initComponent: function() {
+        var me = this;
+        Ext.apply(this, {
+            searchField: [{
+                xtype: 'textfield',
+                name: 'deviceName',
+                fieldLabel: '名称'
+            }],
+            gridConfig: {
+                addTitle: '设备参数',
+                addXtype: null,
+                idField: 'id',
+                codeField: null,
+                detailField: null,
+                dataUrl: me.dataUrl,
+                caller: null,
+                rootProperty: 'data.list',
+                totalProperty: 'data.total',
+                actionColumn: [],
+                selModel: {
+                    type: 'cellmodel'
+                },
+                disableDetail: true,
+                hiddenTools: false,
+                toolBtns: [{
+                    xtype: 'button',
+                    text: '新增',
+                    handler: 'onAddClick'
+                }],
+                columns : [{
+                    text: '设备ID',
+                    dataIndex: 'deviceId'
+                }, {
+                    text: '设备IP',
+                    dataIndex: 'deviceIp',
+                    width: 120
+                }, {
+                    text: '设备名称',
+                    dataIndex: 'deviceName',
+                    width: 120
+                }, {
+                    text: '用户',
+                    dataIndex: 'deviceUser'
+                }, {
+                    text: '密码',
+                    dataIndex: 'devicePassword'
+                }, {
+                    text: '端口',
+                    dataIndex: 'devicePort'
+                }, {
+                    text: '备注',
+                    dataIndex: 'deviceRemark',
+                    width: 150
+                }, {
+                    xtype:'actioncolumn',
+                    width:70,
+                    dataIndex:'actioncolumn',
+                    text:'操作',
+                    align: 'center',
+                    items: [{
+                        tooltip: '编辑',
+                        iconCls: 'x-fa fa-pencil fa-fw'
+                    },{
+                        iconCls:'x-fa fa-trash-o fa-fw',
+                        tooltip: '删除'
+                    }],
+                    listeners: {
+                        click: 'onActionClick'
+                    }
+                }]
+            },
+        });
+        this.callParent(arguments);
+    }
+});

+ 246 - 0
frontend/pc-web/app/view/setting/device/ListController.js

@@ -0,0 +1,246 @@
+Ext.define('school.view.setting.device.ListController', {
+    extend: 'school.view.core.base.BasePanelController',
+    alias: 'controller.setting-device-list',
+
+    onAddClick: function () {
+        let me = this,
+        view = me.getView(),
+        win = Ext.getCmp('device-addwin');
+
+        if (!win) {
+            win = Ext.create('Ext.window.Window', {
+                title: '新增设备信息',
+                width: 450,
+                height: 380,
+                id: 'device-addwin',
+                constrain: true,
+                modal: true,
+                bodyPadding: 10,
+                layout: 'fit',
+                items: [{
+                    xtype: 'form',
+                    layout: 'column',
+                    defaults: {
+                        columnWidth: 1
+                    },
+                    items: [{
+                        xtype: 'textfield',
+                        name: 'deviceIp',
+                        emptyText: '设备IP',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceName',
+                        emptyText: '设备名称',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceUser',
+                        emptyText: '用户',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'devicePassword',
+                        emptyText: '密码',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'devicePort',
+                        emptyText: '端口',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceRemark',
+                        emptyText: '备注'
+                    }],
+                    buttonAlign: 'center',
+                    buttons: [{
+                        text: '确定',
+                        formBind: true,
+                        handler: function () {
+                            let form = this.up('form');
+                            let values = form.getValues();
+                            let url, params, headers;
+                            
+                            params = JSON.stringify(values);
+
+                            view.setLoading(true);
+                            school.util.BaseUtil.request({
+                                // url: 'http://10.1.80.47:9520/api/device/device/save',
+                                url: '/api/device/device/save',
+                                method: 'POST',
+                                params: params,
+                                headers: headers
+                            }).then(function (res) {
+                                view.setLoading(false);
+                                win.close();
+                                school.util.BaseUtil.showSuccessToast('添加成功');
+                                view.refresh();
+                            }).catch(function (e) {
+                                view.setLoading(false);
+                                school.util.BaseUtil.showErrorToast('添加失败: ' + e.message);
+                            });
+                        }
+                    }]
+                }]
+            });
+            view.add(win);
+        }
+        win.show();
+    },
+
+    onActionClick: function(tableView, td, row, col, e, record, tr) {
+        let me = this;
+        let targetCls = event.target.classList;
+        if(targetCls.contains('fa-pencil')) {
+            me.modifyClick(record.data);
+        }else if(targetCls.contains('fa-trash-o')) {
+            me.onDeleteClick(record);
+        }
+    },
+
+    modifyClick: function (data) {
+        let me = this,
+        view = me.getView(),
+        win = Ext.getCmp('device-modifywin');
+
+        if (!win) {
+            win = Ext.create('Ext.window.Window', {
+                title: '修改设备信息',
+                width: 450,
+                height: 380,
+                id: 'device-modifywin',
+                constrain: true,
+                modal: true,
+                bodyPadding: 10,
+                layout: 'fit',
+                items: [{
+                    xtype: 'form',
+                    layout: 'column',
+                    defaults: {
+                        columnWidth: 1
+                    },
+                    items: [{
+                        xtype: 'textfield',
+                        name: 'deviceId',
+                        emptyText: '设备ID',
+                        hidden: true,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceIp',
+                        emptyText: '设备IP',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceName',
+                        emptyText: '设备名称',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceUser',
+                        emptyText: '用户',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'devicePassword',
+                        emptyText: '密码',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'devicePort',
+                        emptyText: '端口',
+                        allowBlank: false,
+                        maxLength: 20
+                    }, {
+                        xtype: 'textfield',
+                        name: 'deviceRemark',
+                        emptyText: '备注'
+                    }],
+                    buttonAlign: 'center',
+                    buttons: [{
+                        text: '确定',
+                        formBind: true,
+                        handler: function () {
+                            let form = this.up('form');
+                            let values = form.getValues();
+                            let params, headers;
+                            
+                            params = JSON.stringify(values);
+
+                            view.setLoading(true);
+                            school.util.BaseUtil.request({
+                                // url: 'http://10.1.80.47:9520/api/device/device/save',
+                                url: '/api/device/device/save',
+                                method: 'POST',
+                                params: params,
+                                headers: headers
+                            }).then(function (res) {
+                                view.setLoading(false);
+                                win.close();
+                                school.util.BaseUtil.showSuccessToast('修改成功');
+                                view.refresh();
+                            }).catch(function (e) {
+                                view.setLoading(false);
+                                school.util.BaseUtil.showErrorToast('修改失败: ' + e.message);
+                            });
+                        }
+                    }]
+                }]
+            });
+            view.add(win);
+            win.down('form').getForm().findField('deviceId').setValue(data.deviceId);
+            win.down('form').getForm().findField('deviceIp').setValue(data.deviceIp);
+            win.down('form').getForm().findField('deviceName').setValue(data.deviceName);
+            win.down('form').getForm().findField('deviceUser').setValue(data.deviceUser);
+            win.down('form').getForm().findField('devicePassword').setValue(data.devicePassword);
+            win.down('form').getForm().findField('devicePort').setValue(data.devicePort);
+            win.down('form').getForm().findField('deviceRemark').setValue(data.deviceRemark);
+        }
+        win.show();
+    },
+
+    onDeleteClick: function(record) {
+        let me = this,
+        view = me.getView(),
+        grid = view.down('grid'),
+        id = record.data.deviceId,
+        data;
+
+        data = [{
+            id: id
+        }];
+
+        school.util.BaseUtil.showConfirm('确认删除', '确定要删除设备' + record.get('deviceName') + '吗?')
+        .then(function(yes) {
+            if(yes == 'yes') {
+                grid.setLoading(true);
+                school.util.BaseUtil.request({
+                    // url: 'http://10.1.80.47:9520/api/device/device/batchDelete',
+                    url: '/api/device/device/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 - 41
frontend/pc-web/app/view/viewport/ViewportModel.js

@@ -25,46 +25,5 @@ Ext.define('school.view.viewport.ViewportModel', {
                 }
             }
         },
-        store_gradeclass: {
-            type: 'tree',
-            autoLoad: false,
-            // model: 'school.model.Grade',
-            fields: [{
-                name: 'text'
-            }],
-            proxy: {
-                type: 'ajax',
-                // url: 'http://10.1.80.47:9560/grade/read',
-                url: '/api/school/grade/read',
-                reader: {
-                    transform: {
-                        fn: function(data) {
-                            let grades = [];
-                            if(!!data.data) {
-                                grades = data.data.children || [];
-                                grades.map(function(s) {
-                                    s._id = s.id;
-                                    s.id = 'grade-' + s.id;
-                                    let classes = s.children;
-                                    let d = classes.map(function(c) {
-                                        c._id = c.id;
-                                        c.id = 'class-' + c.id;
-                                        return c;
-                                    });
-                                    return s;
-                                });
-                            }
-                            return grades;
-                        },
-                        scope: this
-                    }
-                }
-            },
-            root: {
-                text: '全年级',
-                type: 'SCHOOL',
-                expanded: true
-            }
-        }
     }
 });

+ 1 - 1
frontend/pc-web/overrides/form/field/TextField.js → frontend/pc-web/overrides/form/field/Text.js

@@ -1,4 +1,4 @@
-Ext.define('school.override.form.field.TextField', {
+Ext.define('school.override.form.field.Text', {
     override: 'Ext.form.field.Text',
     maxLength: 50
 

+ 5 - 0
frontend/pc-web/overrides/form/field/TextArea.js

@@ -0,0 +1,5 @@
+Ext.define('school.override.form.field.TextArea', {
+    override: 'Ext.form.field.TextArea',
+    maxLength: 500
+
+});

+ 2 - 2
frontend/pc-web/resources/json/navigation.json

@@ -58,9 +58,9 @@
         "text": "角色授权",
         "view": "setting-access-roleaccess"
     }, {
-        "id": "device-param",
+        "id": "setting-device-list",
         "text": "设备参数",
-        "view": "device-param"
+        "view": "setting-device-list"
     }, {
         "id": "setting-operatelog-operatelog",
         "text": "操作日志",

+ 16 - 1
pom.xml

@@ -230,7 +230,12 @@
             </dependency>
             <dependency>
                 <groupId>com.usoftchina.smartschool</groupId>
-                <artifactId> school-dto</artifactId>
+                <artifactId>school-dto</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>school-api</artifactId>
                 <version>${project.release.version}</version>
             </dependency>
             <dependency>
@@ -238,6 +243,16 @@
                 <artifactId>wechat-api</artifactId>
                 <version>${project.release.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>wechat-dto</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>wechat-auth</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.usoftchina.smartschool</groupId>
                 <artifactId>wechat-server</artifactId>