Przeglądaj źródła

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

zhaoy 7 lat temu
rodzic
commit
e44dbf574a
82 zmienionych plików z 2030 dodań i 185 usunięć
  1. 12 2
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/listener/AccessControlListener.java
  2. 48 1
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/AccessControl.java
  3. 10 4
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/AccessControlRepository.java
  4. 4 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/AccessControlService.java
  5. 3 1
      applications/device/device-client/src/main/resources/schema.sql
  6. 9 0
      applications/device/device-client/src/main/resources/static/index.html
  7. 1 0
      applications/device/device-client/src/main/resources/static/js/index.js
  8. 12 3
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDataAnalyzeService.java
  9. 1 1
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDeviceService.java
  10. 8 0
      applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/dto/DeviceInfo.java
  11. 12 1
      applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/event/AccessControlEvent.java
  12. 71 23
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/ImageFile.java
  13. 8 3
      applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/service/impl/AccessControlServiceImpl.java
  14. 3 1
      applications/device/device-server/src/main/resources/application.yml
  15. 3 1
      applications/device/device-server/src/main/resources/config/application-docker-cloud.yml
  16. 3 1
      applications/device/device-server/src/main/resources/config/application-docker-prod.yml
  17. 25 2
      applications/device/device-server/src/test/java/com/usoftchina/smartschool/device/test/TestService.java
  18. 31 0
      applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/enums/NoticeTemplate.java
  19. 45 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/controller/SchoolTemplateController.java
  20. 15 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/SchoolTemplateService.java
  21. 73 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolTemplateServiceImpl.java
  22. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java
  23. 12 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java
  24. 36 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java
  25. 1 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  26. 25 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SchoolTemplateMapper.java
  27. 55 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SchoolTemplate.java
  28. 104 0
      applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml
  29. 18 1
      base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/FileApi.java
  30. 90 0
      base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/ByteArrayMultipartFile.java
  31. 35 0
      base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/FileUploadUtils.java
  32. 17 4
      base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/FileInfoDTO.java
  33. 37 0
      base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/ImageFile.java
  34. 41 0
      base-servers/file/file-server-fdfs/pom.xml
  35. 1 1
      base-servers/file/file-server-fdfs/src/main/docker/Dockerfile
  36. 5 8
      base-servers/file/file-server-fdfs/src/main/java/com/usoftchina/smartschool/file/fdfs/FdfsFileApplication.java
  37. 11 11
      base-servers/file/file-server-fdfs/src/main/resources/application.yml
  38. 1 4
      base-servers/file/file-server-fdfs/src/main/resources/config/application-docker-prod.yml
  39. 0 0
      base-servers/file/file-server-fdfs/src/main/resources/config/application-docker.yml
  40. 0 0
      base-servers/file/file-server-fdfs/src/main/resources/logback-spring.xml
  41. 41 0
      base-servers/file/file-server-qcloud/pom.xml
  42. 6 0
      base-servers/file/file-server-qcloud/src/main/docker/Dockerfile
  43. 26 0
      base-servers/file/file-server-qcloud/src/main/java/com/usoftchina/smartschool/file/qcloud/QCloudFileApplication.java
  44. 97 0
      base-servers/file/file-server-qcloud/src/main/resources/application.yml
  45. 29 0
      base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-cloud.yml
  46. 7 0
      base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-prod.yml
  47. 131 0
      base-servers/file/file-server-qcloud/src/main/resources/logback-spring.xml
  48. 2 19
      base-servers/file/file-server/pom.xml
  49. 7 16
      base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/controller/FileController.java
  50. 31 24
      base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/po/FileInfo.java
  51. 0 13
      base-servers/file/file-server/src/main/resources/config/application-dev.yml
  52. 0 12
      base-servers/file/file-server/src/main/resources/config/application-docker-dev.yml
  53. 0 12
      base-servers/file/file-server/src/main/resources/config/application-docker-test.yml
  54. 0 0
      base-servers/file/file-server/src/main/resources/i18n/messages_en_US.properties
  55. 0 0
      base-servers/file/file-server/src/main/resources/i18n/messages_zh_CN.properties
  56. 24 0
      base-servers/file/file-storage-fdfs/pom.xml
  57. 21 0
      base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsConfig.java
  58. 50 0
      base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsFileStorageClient.java
  59. 3 0
      base-servers/file/file-storage-fdfs/src/main/resources/META-INF/spring.factories
  60. 35 0
      base-servers/file/file-storage-qcloud/pom.xml
  61. 81 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClient.java
  62. 58 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/CosProperties.java
  63. 24 0
      base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/QCloudConfig.java
  64. 3 0
      base-servers/file/file-storage-qcloud/src/main/resources/META-INF/spring.factories
  65. 37 0
      base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClientTest.java
  66. 49 0
      base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/RandomTextFile.java
  67. 15 0
      base-servers/file/file-storage/pom.xml
  68. 44 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileMetadata.java
  69. 39 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileStorageClient.java
  70. 1 1
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileType.java
  71. 3 6
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileTypeUtils.java
  72. 97 0
      base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FilenameUtils.java
  73. 5 0
      base-servers/file/pom.xml
  74. 1 1
      frontend/pc-web/app/view/Interaction/homework/Release.js
  75. 1 1
      frontend/pc-web/app/view/Interaction/notice/SchoolNotice.js
  76. 1 1
      frontend/pc-web/app/view/core/form/field/ClassComboBox.js
  77. 23 0
      frontend/pc-web/app/view/setting/msgtemplate/Panel.js
  78. 116 0
      frontend/pc-web/app/view/setting/msgtemplate/PanelController.js
  79. 4 0
      frontend/pc-web/resources/json/navigation.json
  80. 3 2
      frontend/wechat-web/src/modules/hiPages/access-notice/ItemComp.js
  81. BIN
      frontend/wechat-web/src/style/imgs/no_data.png
  82. 20 0
      pom.xml

+ 12 - 2
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/listener/AccessControlListener.java

@@ -1,6 +1,8 @@
 package com.usoftchina.smartschool.device.client.listener;
 
+import com.usoftchina.smartschool.device.client.po.AccessControl;
 import com.usoftchina.smartschool.device.client.service.AccessControlService;
+import com.usoftchina.smartschool.device.dto.AccessControlInfo;
 import com.usoftchina.smartschool.device.event.AccessControlEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,9 +30,17 @@ public class AccessControlListener {
     @Async
     @EventListener(AccessControlEvent.class)
     public void onAccessControlEvent(AccessControlEvent event) {
+        AccessControlInfo info = event.getAccessControlInfo();
+        AccessControl accessControl = accessControlService.findById(event.getDeviceId());
+        // 通过门禁设备绑定的访问类型,来设置本次事件的访问类型
+        if (accessControl.isEntryType()) {
+            info.setEventType(AccessControlInfo.EventType.ENTRY);
+        } else {
+            info.setEventType(AccessControlInfo.EventType.EXIT);
+        }
         if(logger.isDebugEnabled()) {
-            logger.debug(event.getAccessControlInfo().toString());
+            logger.debug(info.toString());
         }
-        accessControlService.saveRecord(event.getAccessControlInfo());
+        accessControlService.saveRecord(info);
     }
 }

+ 48 - 1
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/AccessControl.java

@@ -1,12 +1,15 @@
 package com.usoftchina.smartschool.device.client.po;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.usoftchina.smartschool.device.dto.DeviceInfo;
 
+import java.util.Arrays;
+
 /**
  * @author yingp
  * @date 2019/3/11
  */
-public class AccessControl implements DeviceInfo{
+public class AccessControl implements DeviceInfo {
     private String id;
     /**
      * 名称
@@ -21,6 +24,11 @@ public class AccessControl implements DeviceInfo{
 
     private String password;
 
+    /**
+     * 闸机头绑定访问类型 1 进入 / 2 出去
+     */
+    private int accessType;
+
     public String getName() {
         return name;
     }
@@ -29,6 +37,7 @@ public class AccessControl implements DeviceInfo{
         this.name = name;
     }
 
+    @Override
     public String getId() {
         return id;
     }
@@ -72,4 +81,42 @@ public class AccessControl implements DeviceInfo{
     public void setPassword(String password) {
         this.password = password;
     }
+
+    public int getAccessType() {
+        return accessType;
+    }
+
+    public void setAccessType(int accessType) {
+        this.accessType = accessType;
+    }
+
+    /**
+     * 是否进门类型
+     *
+     * @return
+     */
+    @JsonIgnore
+    public boolean isEntryType() {
+        return AccessType.of(accessType) == AccessType.ENTRY;
+    }
+
+    public enum AccessType {
+        ENTRY(1),
+        EXIT(2);
+
+        private final int code;
+
+        AccessType(int code) {
+            this.code = code;
+        }
+
+        public static AccessType of(int code) {
+            for (AccessType type : values()) {
+                if (type.code == code) {
+                    return type;
+                }
+            }
+            return ENTRY;
+        }
+    }
 }

+ 10 - 4
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/AccessControlRepository.java

@@ -2,6 +2,8 @@ package com.usoftchina.smartschool.device.client.repository;
 
 import com.usoftchina.smartschool.device.client.po.AccessControl;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -38,6 +40,7 @@ public class AccessControlRepository {
         }
     }
 
+    @Cacheable(value = "accessControl", key = "#id")
     public AccessControl findById(String id) {
         try {
             return jdbcTemplate.queryForObject("select * from access_control where id=?",
@@ -47,20 +50,23 @@ public class AccessControlRepository {
         }
     }
 
+    @CacheEvict(value = "accessControl", key = "#accessControl.id")
     public boolean save(AccessControl accessControl) {
-        int ret = jdbcTemplate.update("insert into access_control(id, name,ip,port,username,password) values " +
+        int ret = jdbcTemplate.update("insert into access_control(id, name,ip,port,username,password,accessType) values " +
                         "(?,?,?,?,?,?)", accessControl.getId(), accessControl.getName(), accessControl.getIp(), accessControl.getPort(),
-                accessControl.getUsername(), accessControl.getPassword());
+                accessControl.getUsername(), accessControl.getPassword(), accessControl.getAccessType());
         return ret > 0;
     }
 
+    @CacheEvict(value = "accessControl", key = "#accessControl.id")
     public boolean update(AccessControl accessControl) {
-        int ret = jdbcTemplate.update("update access_control set name=?,ip=?,port=?,username=?,password=? where " +
+        int ret = jdbcTemplate.update("update access_control set name=?,ip=?,port=?,username=?,password=?,accessType=? where " +
                         "id=?", accessControl.getName(), accessControl.getIp(), accessControl.getPort(),
-                accessControl.getUsername(), accessControl.getPassword(), accessControl.getId());
+                accessControl.getUsername(), accessControl.getPassword(), accessControl.getAccessType(), accessControl.getId());
         return ret > 0;
     }
 
+    @CacheEvict(value = "accessControl", key = "#id")
     public boolean delete(String id) {
         return jdbcTemplate.update("delete from access_control where id=?", id) > 0;
     }

+ 4 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/AccessControlService.java

@@ -94,6 +94,10 @@ public class AccessControlService {
         }
     }
 
+    public AccessControl findById(String id) {
+        return accessControlRepository.findById(id);
+    }
+
     /**
      * 远程保存门禁记录
      *

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

@@ -22,4 +22,6 @@ port int not null,
 username varchar(30) not null,
 password varchar(50) not null,
 databaseName varchar(30) not null
-);
+);
+
+alter table access_control add column if not exists accessType int default 1;

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

@@ -68,6 +68,13 @@
                         <input type="password" class="form-control" id="passwordInput" name="password"
                                required aria-describedby="passwordHelp" placeholder="登录密码">
                     </div>
+                    <div class="form-group">
+                        <label for="accessTypeInput">访问类型</label>
+                        <select class="form-control" id="accessTypeInput" name="accessType">
+                            <option value="1">进门</option>
+                            <option value="2">出门</option>
+                        </select>
+                    </div>
                 </form>
             </div>
             <div class="modal-footer">
@@ -83,6 +90,7 @@
         <th scope="col">名称</th>
         <th scope="col">IP</th>
         <th scope="col">端口</th>
+        <th scope="col">访问类型</th>
         <th scope="col">操作</th>
     </tr>
     </thead>
@@ -95,6 +103,7 @@
         <td><%=data[i].name%></td>
         <td><%=data[i].ip%></td>
         <td><%=data[i].port%></td>
+        <td><%=data[i].accessType == 1 ? '进门' : '出门'%></td>
         <td>
             <button type="button" class="btn btn-link btn-edit" data-index="<%=i%>" title="编辑"
                     data-toggle="modal" data-target="#formModal">

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

@@ -21,6 +21,7 @@ $(document).ready(function () {
                                 $('#portInput').val(accessControl.port);
                                 $('#usernameInput').val(accessControl.username);
                                 $('#passwordInput').val(accessControl.password);
+                                $('#accessTypeInput').val(accessControl.accessType);
                             });
                             $('.btn-delete').click(function(){
                                 var index = $(this).data('index'),

+ 12 - 3
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDataAnalyzeService.java

@@ -39,13 +39,15 @@ public class DahuaDataAnalyzeService {
     /**
      * 启动智能数据监听
      *
+     * @param deviceId 门禁设备ID
      * @param loginHandle 登录句柄
      */
-    public void startListen(NativeLong loginHandle) {
+    public void startListen(String deviceId, NativeLong loginHandle) {
         long key = loginHandle.longValue();
         if (key != 0 && !analyzerHandles.containsKey(key)) {
             NativeLong lAnalyzerHandle = sdk.getInstance().CLIENT_RealLoadPictureEx(loginHandle, 0,
-                    DahuaEvents.EVENT_IVS_ALL, true, new AnalyzerDataCallBack(), new NativeLong(), null);
+                    DahuaEvents.EVENT_IVS_ALL, true, new AnalyzerDataCallBack(deviceId),
+                    new NativeLong(), null);
             analyzerHandles.put(key, lAnalyzerHandle);
         }
     }
@@ -54,6 +56,13 @@ public class DahuaDataAnalyzeService {
      * 智能分析数据回调
      */
     class AnalyzerDataCallBack implements fAnalyzerDataCallBack {
+        private final String deviceId;
+
+        public AnalyzerDataCallBack(String deviceId) {
+            super();
+            this.deviceId = deviceId;
+        }
+
         @Override
         public void invoke(NativeLong lAnalyzerHandle, int dwAlarmType, Pointer pAlarmInfo, Pointer pBuffer,
                            int dwBufSize, NativeLong dwUser, int nSequence, Pointer reserved) {
@@ -75,7 +84,7 @@ public class DahuaDataAnalyzeService {
                     accessControlInfo.setOpenMethod(convertOpenMethod(info.emOpenMethod));
                     accessControlInfo.setEventTime(info.UTC.toDate());
                     SpringContextHolder.getContext().publishEvent(new AccessControlEvent(this,
-                            accessControlInfo));
+                            deviceId, accessControlInfo));
                     // 其他地方可通过监听 AccessControlEvent 来扩展
                     break;
                 /**

+ 1 - 1
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDeviceService.java

@@ -44,7 +44,7 @@ public class DahuaDeviceService implements DeviceApi {
             NativeLong loginHandle = login(info.getIp(), info.getPort(), info.getUsername(), info.getPassword());
             loginHandles.put(id, loginHandle);
             // 开启智能事件监听
-            dataAnalyzeService.startListen(loginHandle);
+            dataAnalyzeService.startListen(info.getId(), loginHandle);
         }
     }
 

+ 8 - 0
applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/dto/DeviceInfo.java

@@ -7,6 +7,14 @@ package com.usoftchina.smartschool.device.dto;
  * @date 2019/3/8
  */
 public interface DeviceInfo {
+
+    /**
+     * ID
+     *
+     * @return
+     */
+    String getId();
+
     /**
      * ip
      *

+ 12 - 1
applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/event/AccessControlEvent.java

@@ -11,13 +11,24 @@ import org.springframework.context.ApplicationEvent;
  */
 public class AccessControlEvent extends ApplicationEvent {
 
+    private final String deviceId;
     private final AccessControlInfo accessControlInfo;
 
-    public AccessControlEvent(Object source, AccessControlInfo accessControlInfo) {
+    public AccessControlEvent(Object source, String deviceId, AccessControlInfo accessControlInfo) {
         super(source);
+        this.deviceId = deviceId;
         this.accessControlInfo = accessControlInfo;
     }
 
+    /**
+     * 产生事件的门禁设备ID
+     *
+     * @return
+     */
+    public String getDeviceId() {
+        return deviceId;
+    }
+
     public AccessControlInfo getAccessControlInfo() {
         return accessControlInfo;
     }

+ 71 - 23
applications/device/device-server/src/main/java/com/usoftchina/smartschool/device/po/ImageFile.java

@@ -1,6 +1,8 @@
 package com.usoftchina.smartschool.device.po;
 
 import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.FileCopyUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.*;
@@ -9,55 +11,101 @@ import java.io.*;
  * @author: guq
  * @create: 2019-03-08 16:42
  **/
-public class ImageFile implements MultipartFile{
+public class ImageFile implements MultipartFile {
 
-    private final byte[] imgContent;
-    private final String header;
+    private final String name;
 
-    public ImageFile(byte[] imgContent, String header) {
-        this.imgContent = imgContent;
-        this.header = header.split(";")[0];
+    private String originalFilename;
+
+    @Nullable
+    private String contentType;
+
+    private final byte[] content;
+
+
+    /**
+     * Create a new MockMultipartFile with the given content.
+     * @param name the name of the file
+     * @param content the content of the file
+     */
+    public ImageFile(String name, @Nullable byte[] content) {
+        this(name, "", null, content);
+    }
+
+    /**
+     * Create a new MockMultipartFile with the given content.
+     * @param name the name of the file
+     * @param contentStream the content of the file as stream
+     * @throws IOException if reading from the stream failed
+     */
+    public ImageFile(String name, InputStream contentStream) throws IOException {
+        this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
+    }
+
+    /**
+     * Create a new MockMultipartFile with the given content.
+     * @param name the name of the file
+     * @param originalFilename the original filename (as on the client's machine)
+     * @param contentType the content type (if known)
+     * @param content the content of the file
+     */
+    public ImageFile(
+            String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
+
+        Assert.hasLength(name, "Name must not be null");
+        this.name = name;
+        this.originalFilename = (originalFilename != null ? originalFilename : "");
+        this.contentType = contentType;
+        this.content = (content != null ? content : new byte[0]);
+    }
+
+    /**
+     * Create a new MockMultipartFile with the given content.
+     * @param name the name of the file
+     * @param originalFilename the original filename (as on the client's machine)
+     * @param contentType the content type (if known)
+     * @param contentStream the content of the file as stream
+     * @throws IOException if reading from the stream failed
+     */
+    public ImageFile(
+            String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
+            throws IOException {
+
+        this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
     }
 
-    @Override
+
     public String getName() {
-        return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
+        return this.name;
     }
 
-    @Nullable
-    @Override
     public String getOriginalFilename() {
-        return System.currentTimeMillis() + (int)Math.random() * 10000 + "." + header.split("/")[1];
+        return this.originalFilename;
     }
 
     @Nullable
-    @Override
     public String getContentType() {
-        return header.split(":")[1];
+        return this.contentType;
     }
 
-    @Override
     public boolean isEmpty() {
-        return imgContent == null || imgContent.length == 0;
+        return (this.content.length == 0);
     }
 
-    @Override
     public long getSize() {
-        return imgContent.length;
+        return this.content.length;
     }
 
-    @Override
     public byte[] getBytes() throws IOException {
-        return imgContent;
+        return this.content;
     }
 
-    @Override
     public InputStream getInputStream() throws IOException {
-        return new ByteArrayInputStream(imgContent);
+        return new ByteArrayInputStream(this.content);
     }
 
-    @Override
     public void transferTo(File dest) throws IOException, IllegalStateException {
-        new FileOutputStream(dest).write(imgContent);
+        FileCopyUtils.copy(this.content, dest);
     }
+
 }

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

@@ -5,11 +5,11 @@ import com.usoftchina.smartschool.device.dto.AccessControlInfo;
 import com.usoftchina.smartschool.device.mapper.AccessControlRecordMapper;
 import com.usoftchina.smartschool.device.mapper.StudentInfoMapper;
 import com.usoftchina.smartschool.device.po.AccessControlRecord;
-import com.usoftchina.smartschool.device.po.ImageFile;
 import com.usoftchina.smartschool.device.po.StudentInfo;
 import com.usoftchina.smartschool.device.service.AccessControlService;
 import com.usoftchina.smartschool.file.api.FileApi;
 import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+import com.usoftchina.smartschool.file.dto.ImageFile;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
 import com.usoftchina.smartschool.wechat.api.WechatApi;
@@ -18,6 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -48,6 +49,9 @@ public class AccessControlServiceImpl implements AccessControlService{
     @Value("${wechat.template.accesscontrol}")
     private String accessControlTemplateId;
 
+    @Value("${smartschool.domain.wechat}")
+    private String wechatBaseUrl;
+
     @Override
     public void onAccessControlEvent(AccessControlInfo info) {
         String filePath = null;
@@ -68,10 +72,10 @@ public class AccessControlServiceImpl implements AccessControlService{
          */
         byte[] imageData = info.getImageData();
         if (null != imageData && imageData.length > 0) {
-            MultipartFile file = new ImageFile(imageData, information.get(0).getStuName());
+            ImageFile file = new ImageFile(information.get(0).getStuName(), imageData);
             Result<FileInfoDTO> fileInfo = null;
             try {
-                fileInfo = fileApi.upload(0L, file);
+                fileInfo = fileApi.imageUpload(file);
                 filePath = fileInfo.getData().getFullPath();
             }catch (Exception ex) {
                 logger.error(ex.getMessage());
@@ -101,6 +105,7 @@ public class AccessControlServiceImpl implements AccessControlService{
          * 3、推送消息到消息服务器(微信服务监听此消息发送微信消息)
          */
         MessageInfoDTO msg = new MessageInfoDTO();
+        msg.setUrl(wechatBaseUrl + "/accessnoticedetail/" + record.getRecord_id());
         msg.setAppId(studentInfo.getAppId());
         msg.setSecret(studentInfo.getSecret());
         msg.setTouser(studentInfo.getOpenId());

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

@@ -76,4 +76,6 @@ mybatis:
   mapper-locations: classpath:mapper/*.xml
 smartschool:
   wechat:
-    pushUrl: https://school-api.ubtob.com/api/wechat/send/Messages
+    pushUrl: https://school-api.ubtob.com/api/wechat/send/Messages
+  domain:
+    wechat: https://school-wechat.ubtob.com

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

@@ -23,4 +23,6 @@ spring:
         connection-timeout: 30000
 smartschool:
   wechat:
-    pushUrl: https://school-api.ydyhz.com/api/wechat/send/Messages
+    pushUrl: https://school-api.ydyhz.com/api/wechat/send/Messages
+  domain:
+    wechat: https://school-wechat.ydyhz.com

+ 3 - 1
applications/device/device-server/src/main/resources/config/application-docker-prod.yml

@@ -15,4 +15,6 @@ spring:
     port: 6379
 smartschool:
   wechat:
-    pushUrl: https://school-api.ubtob.com/api/wechat/send/Messages
+    pushUrl: https://school-api.ubtob.com/api/wechat/send/Messages
+  domain:
+    wechat: https://school-wechat.ubtob.com

+ 25 - 2
applications/device/device-server/src/test/java/com/usoftchina/smartschool/device/test/TestService.java

@@ -1,7 +1,12 @@
 package com.usoftchina.smartschool.device.test;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.device.DeviceApplication;
 import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.file.api.FileApi;
+import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+import com.usoftchina.smartschool.file.dto.ImageFile;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.wechat.api.WechatApi;
 import com.usoftchina.smartschool.wechat.dto.MessageInfoDTO;
@@ -11,18 +16,22 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.io.*;
+
 /**
  * @author: guq
  * @create: 2019-03-12 09:48
  **/
 @RunWith(SpringRunner.class)
-@SpringBootTest
+@SpringBootTest(classes = DeviceApplication.class)
 public class TestService {
 
   /*  @Autowired
     AccessService accessService;*/
     @Autowired
     WechatApi wechatApi;
+    @Autowired
+    private FileApi fileApi;
 
     @Test
     public void testa_accessservice() {
@@ -46,4 +55,18 @@ public class TestService {
         msg.setRemark("您好! 你的孩子: ");
         wechatApi.sendMsg(msg);
     }
+
+    @Test
+    public void testC() throws IOException {
+        InputStream in = new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\cw.jpg"));
+        int len = 0;
+        byte[] bytes = new byte[1024 * 1024];
+        while ((len = in.read(bytes)) != -1) {
+            in.read(bytes);
+        }
+        in.close();
+        Result<FileInfoDTO> result = fileApi.imageUpload(new ImageFile("测试", bytes));
+        System.out.println(JSON.toJSONString(result));
+    }
+
 }

+ 31 - 0
applications/school/school-dto/src/main/java/com/usoftchina/smartschool/school/enums/NoticeTemplate.java

@@ -0,0 +1,31 @@
+package com.usoftchina.smartschool.school.enums;
+
+public enum NoticeTemplate {
+
+    INOUT_NOTICE("inout", "出入校提醒"),
+    SCHOOL_NOTICE("school", "学校通知"),
+    HOMEWORK_NOTICE("homework", "作业通知"),
+    ASK4LEAVE_NOTICE("ask4leave", "学生请假申请"),
+    LEAVECONFIRM_NOTICE("leaveConfirm", "学生请假确认"),
+    SCORE_NOTICE("score", "成绩通知"),
+    UNAUDIT_NOTICE("unAudit", "待审批通知"),
+    MEETING_NOTICE("meeting", "会议提醒"),
+    MONEY_NOTICE("money", "资金异动提醒");
+
+    private String code;
+
+    private String title;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    NoticeTemplate(String code, String title) {
+        this.code = code;
+        this.title = title;
+    }
+}

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

@@ -0,0 +1,45 @@
+package com.usoftchina.smartschool.school.basic.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.page.PageDefault;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.basic.service.SchoolTemplateService;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 学校微信推送模板
+ * @author: guq
+ * @create: 2019-03-14 11:51
+ **/
+@RestController
+@RequestMapping("/template")
+public class SchoolTemplateController {
+
+
+    @Autowired
+    private SchoolTemplateService schoolTemplateService;
+
+    @GetMapping("/list")
+    public Result getList(@PageDefault PageRequest page, ListReqDTO listReqDTO) {
+        PageInfo<SchoolTemplate> data = schoolTemplateService.getListData(page, listReqDTO);
+        return Result.success(data);
+    }
+
+    @GetMapping("/read/{id}")
+    public Result getFormData(@PathVariable("id") Long id) {
+        SchoolTemplate data = schoolTemplateService.getFormData(id);
+        return Result.success(data);
+    }
+
+    @PostMapping("/save")
+    public Result saveFormData(@RequestBody SchoolTemplate data) {
+        DocBaseDTO baseDTO = schoolTemplateService.saveFormData(data);
+        return Result.success(baseDTO);
+    }
+
+}

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

@@ -0,0 +1,15 @@
+package com.usoftchina.smartschool.school.basic.service;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+
+public interface SchoolTemplateService {
+    PageInfo<SchoolTemplate> getListData(PageRequest page, ListReqDTO listReqDTO);
+
+    SchoolTemplate getFormData(Long id);
+
+    DocBaseDTO saveFormData(SchoolTemplate data);
+}

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

@@ -0,0 +1,73 @@
+package com.usoftchina.smartschool.school.basic.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.smartschool.context.BaseContextHolder;
+import com.usoftchina.smartschool.exception.BizException;
+import com.usoftchina.smartschool.page.PageRequest;
+import com.usoftchina.smartschool.school.basic.service.SchoolTemplateService;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
+import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.exception.BizExceptionCode;
+import com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import com.usoftchina.smartschool.school.po.SysSchool;
+import com.usoftchina.smartschool.school.po.SysStudent;
+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;
+
+/**
+ * @author: guq
+ * @create: 2019-03-14 13:56
+ **/
+@Service
+public class SchoolTemplateServiceImpl implements SchoolTemplateService {
+
+
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
+
+    @Override
+    public PageInfo<SchoolTemplate> getListData(PageRequest page, ListReqDTO listReqDTO) {
+        PageHelper.startPage(page.getNumber(), page.getSize());
+        Long schoolId = BaseContextHolder.getSchoolId();
+        //condition语句
+        String condition = listReqDTO.getFinalCondition();
+        if(condition == null){
+            condition = "1=1";
+        }
+        List<SchoolTemplate> data = schoolTemplateMapper.selectByConditon(condition, schoolId);
+        PageInfo<SchoolTemplate> list = new PageInfo<>(data);
+        return list;
+    }
+
+    @Override
+    public SchoolTemplate getFormData(Long id) {
+        if (null == id || "0".equals(id)) {
+            throw new BizException(BizExceptionCode.USELESS_DATA);
+        }
+        SchoolTemplate data = schoolTemplateMapper.selectByPrimaryKey(id);
+        return data;
+    }
+
+    @Override
+    public DocBaseDTO saveFormData(SchoolTemplate formdata) {
+        if (StringUtils.isEmpty(formdata)){
+            throw new BizException(BizExceptionCode.EMPTY_DATA);
+        }
+        Long school_id = BaseContextHolder.getSchoolId();
+        formdata.setSt_schoolid(school_id);
+        //新增
+        if (StringUtils.isEmpty(formdata.getSt_id()) || "0".equals(formdata.getSt_id().toString())) {
+            schoolTemplateMapper.insertSelective(formdata);
+        } else {
+            //更新
+            schoolTemplateMapper.updateByPrimaryKeySelective(formdata);
+        }
+        return new DocBaseDTO(formdata.getSt_id());
+    }
+}

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

@@ -9,6 +9,7 @@ import com.usoftchina.smartschool.school.business.service.HomeWorkService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
 import com.usoftchina.smartschool.school.po.*;
@@ -46,6 +47,8 @@ public class HomeWorkServiceImpl implements HomeWorkService{
     private SysSchoolMapper sysSchoolMapper;
     @Autowired
     private WechatApi wechatApi;
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
 
     @Override
     public DocBaseDTO save(HomeWork formdata) {
@@ -132,6 +135,11 @@ public class HomeWorkServiceImpl implements HomeWorkService{
         SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         //微信推送
         List<HomeworkNoticer> noticers = homeWorkMapper.selectHomeworkNoticer(id);
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
         //消息内容
         List<MessageInfoDTO> msgs = new ArrayList<>();
         noticers.forEach(noticer -> {
@@ -143,6 +151,7 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             msg.setTouser(noticer.getOpenid());
             msg.setAppId(school.getSchool_appid());
             msg.setSecret(school.getSchool_secret());
+            msg.setTemplateId(template.getSt_templateid());
             msgs.add(msg);
         });
         if (msgs.size() > 0) {

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

@@ -9,11 +9,14 @@ import com.usoftchina.smartschool.school.business.service.NoticeService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.NoticeMapper;
+import com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper;
 import com.usoftchina.smartschool.school.mapper.SysSchoolMapper;
 import com.usoftchina.smartschool.school.po.Notify;
 import com.usoftchina.smartschool.school.po.SchoolNoticer;
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
 import com.usoftchina.smartschool.school.po.SysSchool;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
@@ -43,7 +46,9 @@ public class NoticeServiceImpl implements NoticeService{
     @Autowired
     private WechatApi wechatApi;
 
-    final static String TEMPLATEID = "h0BkcnTo24b2jsficMeVO0B17GvE-VzlPvF0fVXea4w";
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
+
 
     @Override
     public DocBaseDTO save(Notify formdata) {
@@ -125,6 +130,11 @@ public class NoticeServiceImpl implements NoticeService{
         SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         List<MessageInfoDTO> msgs = new ArrayList<>();
         List<SchoolNoticer> noticers = noticeMapper.selectNoticer(BaseContextHolder.getSchoolId());
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (org.springframework.util.StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
         noticers.forEach(noticer -> {
             MessageInfoDTO msg = new MessageInfoDTO();
             msg.setTitle(data.getNotify_title());
@@ -133,7 +143,7 @@ public class NoticeServiceImpl implements NoticeService{
             msg.setKeyword3(DateUtils.format());
             msg.setKeyword4(data.getNotify_details());
             msg.setRemark(data.getNotify_remarks());
-            msg.setTemplateId(TEMPLATEID);
+            msg.setTemplateId(template.getSt_templateid());
             msg.setTouser(noticer.getOpenid());
             msg.setAppId(school.getSchool_appid());
             msg.setSecret(school.getSchool_secret());

+ 36 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java

@@ -10,6 +10,7 @@ import com.usoftchina.smartschool.school.business.service.ScoreService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
+import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
 import com.usoftchina.smartschool.school.po.*;
@@ -57,8 +58,8 @@ public class ScoreServiceImpl implements ScoreService{
     @Autowired
     private WechatApi wechatApi;
 
-
-    final static String TEMPLATEID = "GwR7hZ9ya7ghAiH3PR-ws1l24P_ETE3phYJBjKTcpKY";
+    @Autowired
+    private SchoolTemplateMapper schoolTemplateMapper;
 
     @Autowired
     private SubjectMapper subjectMapper;
@@ -218,6 +219,8 @@ public class ScoreServiceImpl implements ScoreService{
         List<StuScore> appScores = new ArrayList<StuScore>();
         StuScore appScore = null;
         Long school_id = BaseContextHolder.getSchoolId();
+        //学校信息
+        SysSchool school = sysSchoolMapper.selectByPrimaryKey(BaseContextHolder.getSchoolId());
         ScoreImport main = scoreMapper.selectByPrimaryKey(id);
         List<ScoreImportdetail> details = scoreMapper.selectDetail(id);
         for (ScoreImportdetail detail : details) {
@@ -237,6 +240,37 @@ public class ScoreServiceImpl implements ScoreService{
             appScores.add(appScore);
         }
         scoreMapper.batchInsert(appScores);
+
+        //微信推送
+        List<ScoreNoticer> noticers = scoreMapper.selectWechatMsg(id);
+        //消息内容
+        List<MessageInfoDTO> msgs = new ArrayList<>();
+        //模板信息
+        SchoolTemplate template = schoolTemplateMapper.selectByCode(NoticeTemplate.HOMEWORK_NOTICE.getCode(), school.getSchool_id());
+        if (StringUtils.isEmpty(template.getSt_templateid())) {
+            throw new BizException(BizExceptionCode.NULL_TEMPLATE);
+        }
+        noticers.forEach(noticer -> {
+            MessageInfoDTO msg = new MessageInfoDTO();
+            msg.setTitle("您好,请查收您小孩" + noticer.getStuName() + "的成绩单");
+            msg.setKeyword1(noticer.getStuName());
+            msg.setKeyword2(noticer.getStuNo());
+            msg.setKeyword3(main.getSi_examtitle());
+            msg.setKeyword4(DateUtils.format(main.getSi_examdate(),"yyyy-MM-dd"));
+            msg.setKeyword5(school.getSchool_name());
+            msg.setRemark("成绩为:" + noticer.getScore());
+            msg.setTemplateId(template.getSt_templateid());
+            msg.setTouser(noticer.getOpenid());
+            msg.setAppId(school.getSchool_appid());
+            msg.setSecret(school.getSchool_secret());
+            msgs.add(msg);
+        });
+        if (msgs.size() > 0) {
+            TransferDTO transferDTO = new TransferDTO();
+            transferDTO.setData(msgs);
+            //调用推送接口
+            wechatApi.largeMessages(transferDTO);
+        }
         //更新已转标志
         scoreMapper.updateTurnPublish(id);
     }

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

@@ -34,6 +34,7 @@ public enum BizExceptionCode implements BaseExceptionCode {
     NOTICE_RELEASE_STATUS(600007, "学校通知已生效,无法删除"),
     ILLEGAL_Gender(600007, "无效性别"),
     ILLEGAL_MARRIAGE(600008, "婚姻状态无效,应为:已婚或未婚"),
+    NULL_TEMPLATE(600010, "模板ID为空"),
     NOT_EXISTS_SUBJECT(60005, "科目<u>%s</u>不存在");
 
 

+ 25 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SchoolTemplateMapper.java

@@ -0,0 +1,25 @@
+package com.usoftchina.smartschool.school.mapper;
+
+import com.usoftchina.smartschool.school.po.SchoolTemplate;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+@Mapper
+public interface SchoolTemplateMapper {
+    int deleteByPrimaryKey(Long st_id);
+
+    int insert(SchoolTemplate record);
+
+    int insertSelective(SchoolTemplate record);
+
+    SchoolTemplate selectByPrimaryKey(Long st_id);
+
+    int updateByPrimaryKeySelective(SchoolTemplate record);
+
+    int updateByPrimaryKey(SchoolTemplate record);
+
+    List<SchoolTemplate> selectByConditon(@Param("con") String condition, @Param("school_id") Long schoolId);
+
+    SchoolTemplate selectByCode(@Param("code") String code, @Param("school_id") Long school_id);
+}

+ 55 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/SchoolTemplate.java

@@ -0,0 +1,55 @@
+package com.usoftchina.smartschool.school.po;
+
+import java.io.Serializable;
+
+public class SchoolTemplate implements Serializable{
+    private Long st_id;
+
+    private String st_code;
+
+    private String st_name;
+
+    private String st_templateid;
+
+    private Long st_schoolid;
+
+    public Long getSt_id() {
+        return st_id;
+    }
+
+    public void setSt_id(Long st_id) {
+        this.st_id = st_id;
+    }
+
+    public String getSt_code() {
+        return st_code;
+    }
+
+    public void setSt_code(String st_code) {
+        this.st_code = st_code == null ? null : st_code.trim();
+    }
+
+    public String getSt_name() {
+        return st_name;
+    }
+
+    public void setSt_name(String st_name) {
+        this.st_name = st_name == null ? null : st_name.trim();
+    }
+
+    public String getSt_templateid() {
+        return st_templateid;
+    }
+
+    public void setSt_templateid(String st_templateid) {
+        this.st_templateid = st_templateid == null ? null : st_templateid.trim();
+    }
+
+    public Long getSt_schoolid() {
+        return st_schoolid;
+    }
+
+    public void setSt_schoolid(Long st_schoolid) {
+        this.st_schoolid = st_schoolid;
+    }
+}

+ 104 - 0
applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml

@@ -0,0 +1,104 @@
+<?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.school.mapper.SchoolTemplateMapper" >
+  <resultMap id="BaseResultMap" type="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    <id column="st_id" property="st_id" jdbcType="BIGINT" />
+    <result column="st_code" property="st_code" jdbcType="VARCHAR" />
+    <result column="st_name" property="st_name" jdbcType="VARCHAR" />
+    <result column="st_templateid" property="st_templateid" jdbcType="VARCHAR" />
+    <result column="st_schoolid" property="st_schoolid" jdbcType="BIGINT" />
+  </resultMap>
+  <sql id="Base_Column_List" >
+    st_id, st_code, st_name, st_templateid, st_schoolid
+  </sql>
+  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
+    select 
+    <include refid="Base_Column_List" />
+    from school_template
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
+    delete from school_template
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    insert into school_template (st_id, st_code, st_name, 
+      st_templateid, st_schoolid)
+    values (#{st_id,jdbcType=BIGINT}, #{st_code,jdbcType=VARCHAR}, #{st_name,jdbcType=VARCHAR}, 
+      #{st_templateid,jdbcType=VARCHAR}, #{st_schoolid,jdbcType=BIGINT})
+  </insert>
+  <insert id="insertSelective" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    insert into school_template
+    <trim prefix="(" suffix=")" suffixOverrides="," >
+      <if test="st_code != null" >
+        st_code,
+      </if>
+      <if test="st_name != null" >
+        st_name,
+      </if>
+      <if test="st_templateid != null" >
+        st_templateid,
+      </if>
+      <if test="st_schoolid != null" >
+        st_schoolid,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides="," >
+      <if test="st_code != null" >
+        #{st_code,jdbcType=VARCHAR},
+      </if>
+      <if test="st_name != null" >
+        #{st_name,jdbcType=VARCHAR},
+      </if>
+      <if test="st_templateid != null" >
+        #{st_templateid,jdbcType=VARCHAR},
+      </if>
+      <if test="st_schoolid != null" >
+        #{st_schoolid,jdbcType=BIGINT},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    update school_template
+    <set >
+      <if test="st_code != null" >
+        st_code = #{st_code,jdbcType=VARCHAR},
+      </if>
+      <if test="st_name != null" >
+        st_name = #{st_name,jdbcType=VARCHAR},
+      </if>
+      <if test="st_templateid != null" >
+        st_templateid = #{st_templateid,jdbcType=VARCHAR},
+      </if>
+      <if test="st_schoolid != null" >
+        st_schoolid = #{st_schoolid,jdbcType=BIGINT},
+      </if>
+    </set>
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    update school_template
+    set st_code = #{st_code,jdbcType=VARCHAR},
+      st_name = #{st_name,jdbcType=VARCHAR},
+      st_templateid = #{st_templateid,jdbcType=VARCHAR},
+      st_schoolid = #{st_schoolid,jdbcType=BIGINT}
+    where st_id = #{st_id,jdbcType=BIGINT}
+  </update>
+
+  <select id="selectByConditon" resultMap="BaseResultMap">
+    select * from school_template <where>
+    <if test="con != null">
+      ${con}
+    </if>
+    <if test="school_id != null">
+      and  st_schoolid = #{school_id}
+    </if>
+  </where>
+    order by st_id DESC
+  </select>
+
+  <select id="selectByCode" resultMap="BaseResultMap">
+    select * from school_template where st_code=#{code} and st_schoolid=#{school_id}
+  </select>
+
+</mapper>

+ 18 - 1
base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/FileApi.java

@@ -4,9 +4,14 @@ import com.usoftchina.smartschool.base.Result;
 import com.usoftchina.smartschool.file.dto.FileInfoDTO;
 import com.usoftchina.smartschool.file.dto.FolderDTO;
 import com.usoftchina.smartschool.file.dto.FolderSaveDTO;
+import com.usoftchina.smartschool.file.dto.ImageFile;
 import feign.codec.Encoder;
 import feign.form.spring.SpringFormEncoder;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.MediaType;
@@ -26,9 +31,13 @@ public interface FileApi {
 
     @Configuration
     class MultipartSupportConfig {
+
+        @Autowired
+        private ObjectFactory<HttpMessageConverters> messageConverters;
+
         @Bean
         public Encoder feignFormEncoder() {
-            return new SpringFormEncoder();
+            return new SpringFormEncoder(new SpringEncoder(messageConverters));
         }
     }
 
@@ -79,6 +88,14 @@ public interface FileApi {
     @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     Result<FileInfoDTO> upload(@RequestParam("folderId") Long folderId, @RequestPart(value = "file") MultipartFile file) throws Exception;
 
+    /**
+     * 上传图片文件
+     * @param file
+     * @return
+     */
+    @PostMapping(value = "/imageUpload")
+    Result<FileInfoDTO> imageUpload(@RequestBody ImageFile file);
+
     /**
      * 文件下载
      *

+ 90 - 0
base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/ByteArrayMultipartFile.java

@@ -0,0 +1,90 @@
+package com.usoftchina.smartschool.file.api.util;
+
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author yingp
+ * @date 2019/1/15
+ */
+public class ByteArrayMultipartFile implements MultipartFile {
+    private final String name;
+
+    private String originalFilename;
+
+    @Nullable
+    private String contentType;
+
+    private final byte[] content;
+
+    public ByteArrayMultipartFile(String name, byte[] content) throws IOException {
+        this(name, "", null, content);
+    }
+
+    public ByteArrayMultipartFile(String name, String contentType, byte[] content) throws IOException {
+        this(name, "", contentType, content);
+    }
+
+    public ByteArrayMultipartFile(
+            String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
+        Assert.hasLength(name, "Name must not be null");
+        this.name = name;
+        this.originalFilename = (originalFilename != null ? originalFilename : "");
+        this.contentType = contentType;
+        this.content = (content != null ? content : new byte[0]);
+    }
+
+    public ByteArrayMultipartFile(
+            String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
+            throws IOException {
+        this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String getOriginalFilename() {
+        return this.originalFilename;
+    }
+
+    @Override
+    @Nullable
+    public String getContentType() {
+        return this.contentType;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return this.content.length == 0;
+    }
+
+    @Override
+    public long getSize() {
+        return this.content.length;
+    }
+
+    @Override
+    public byte[] getBytes() throws IOException {
+        return this.content;
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(this.content);
+    }
+
+    @Override
+    public void transferTo(File dest) throws IOException, IllegalStateException {
+        FileCopyUtils.copy(this.content, dest);
+    }
+}

+ 35 - 0
base-servers/file/file-api/src/main/java/com/usoftchina/smartschool/file/api/util/FileUploadUtils.java

@@ -0,0 +1,35 @@
+package com.usoftchina.smartschool.file.api.util;
+
+import com.usoftchina.smartschool.base.Result;
+import com.usoftchina.smartschool.context.SpringContextHolder;
+import com.usoftchina.smartschool.exception.BizException;
+import com.usoftchina.smartschool.file.api.FileApi;
+import com.usoftchina.smartschool.file.dto.FileInfoDTO;
+
+/**
+ * @author yingp
+ * @date 2019/1/15
+ */
+public class FileUploadUtils {
+
+    /**
+     * 文件上传
+     *
+     * @param fileName
+     * @param contentType
+     * @param content
+     * @return
+     * @throws Exception
+     */
+    public static FileInfoDTO upload(String fileName, String contentType, byte[] content) throws Exception{
+        FileApi api = SpringContextHolder.getBean(FileApi.class);
+        Result<FileInfoDTO> result = api.upload(null,
+                new ByteArrayMultipartFile(fileName, contentType, content));
+        if (result.isSuccess()) {
+            return result.getData();
+        } else {
+            throw new BizException(result.getCode(), result.getMessage());
+        }
+    }
+
+}

+ 17 - 4
base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/FileInfoDTO.java

@@ -15,11 +15,17 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
     private Long id;
 
     /**
-     * 链接
+     * 存储路径
      */
-    @ApiModelProperty(value = "文件path")
+    @ApiModelProperty(value = "文件存储path")
     private String fullPath;
 
+    /**
+     * 访问链接
+     */
+    @ApiModelProperty(value = "文件访问path")
+    private String accessPath;
+
     /**
      * 类型
      */
@@ -67,6 +73,14 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
         this.mime = mime;
     }
 
+    public String getAccessPath() {
+        return accessPath;
+    }
+
+    public void setAccessPath(String accessPath) {
+        this.accessPath = accessPath;
+    }
+
     public String getExt() {
         return ext;
     }
@@ -95,9 +109,8 @@ public class FileInfoDTO extends BaseFileInfo implements Serializable {
     public String toString() {
         return "FileInfoDTO{" +
                 "id=" + id +
-                ", folderId=" + folderId +
-                ", name=" + name +
                 ", fullPath='" + fullPath + '\'' +
+                ", accessPath='" + accessPath + '\'' +
                 ", mime='" + mime + '\'' +
                 ", ext='" + ext + '\'' +
                 ", size=" + size +

+ 37 - 0
base-servers/file/file-dto/src/main/java/com/usoftchina/smartschool/file/dto/ImageFile.java

@@ -0,0 +1,37 @@
+package com.usoftchina.smartschool.file.dto;
+
+/**
+ * @Author chenwei
+ * @Date 2019-03-14
+ */
+public class ImageFile {
+
+    private String name;
+
+    private byte[] content;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public byte[] getContent() {
+        return content;
+    }
+
+    public void setContent(byte[] content) {
+        this.content = content;
+    }
+
+    public ImageFile() {
+    }
+
+    public ImageFile(String name, byte[] content) {
+
+        this.name = name;
+        this.content = content;
+    }
+}

+ 41 - 0
base-servers/file/file-server-fdfs/pom.xml

@@ -0,0 +1,41 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-server-fdfs</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage-fdfs</artifactId>
+        </dependency>
+        <!-- test -->
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>test-starter</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 1 - 1
base-servers/file/file-server/src/main/docker/Dockerfile → base-servers/file/file-server-fdfs/src/main/docker/Dockerfile

@@ -1,6 +1,6 @@
 FROM frolvlad/alpine-oraclejdk8:slim
 VOLUME /tmp
-ADD file-server-1.0.0-SNAPSHOT.jar app.jar
+ADD file-server-fdfs-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" ]

+ 5 - 8
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/FileApplication.java → base-servers/file/file-server-fdfs/src/main/java/com/usoftchina/smartschool/file/fdfs/FdfsFileApplication.java

@@ -1,29 +1,26 @@
-package com.usoftchina.smartschool.file;
+package com.usoftchina.smartschool.file.fdfs;
 
-import com.github.tobato.fastdfs.FdfsClientConfig;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 import org.springframework.context.annotation.EnableMBeanExport;
-import org.springframework.context.annotation.Import;
 import org.springframework.jmx.support.RegistrationPolicy;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 /**
  * @author yingp
- * @date 2018/9/29
+ * @date 2019/3/14
  */
-@SpringBootApplication
+@SpringBootApplication(scanBasePackages = "com.usoftchina.smartschool.file")
 @EnableEurekaClient
 @EnableTransactionManagement
 @MapperScan("com.usoftchina.smartschool.file.mapper")
-@Import(FdfsClientConfig.class)
 @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
 @EnableSwagger2
-public class FileApplication {
+public class FdfsFileApplication {
     public static void main(String[] args) {
-        SpringApplication.run(FileApplication.class, args);
+        SpringApplication.run(FdfsFileApplication.class, args);
     }
 }

+ 11 - 11
base-servers/file/file-server/src/main/resources/application.yml → base-servers/file/file-server-fdfs/src/main/resources/application.yml

@@ -1,3 +1,13 @@
+fdfs:
+  so-timeout: 1500
+  connect-timeout: 600
+  thumb-image:
+    width: 150
+    height: 150
+  tracker-list:
+    - 10.10.100.200:22122
+file:
+  base-url: http://10.1.81.1:8888/
 spring:
   application:
     name: file-server
@@ -86,14 +96,4 @@ mybatis:
   type-aliases-package: com.usoftchina.smartschool.file.po
   mapper-locations: classpath:mapper/*.xml
 auth:
-  public-key: auth/pub.key
-fdfs:
-  so-timeout: 1500
-  connect-timeout: 600
-  thumb-image:
-    width: 150
-    height: 150
-  tracker-list:
-    - 10.1.81.1:22122
-file:
-  base-url: http://10.1.81.1:8888/
+  public-key: auth/pub.key

+ 1 - 4
base-servers/file/file-server/src/main/resources/config/application-docker-prod.yml → base-servers/file/file-server-fdfs/src/main/resources/config/application-docker-prod.yml

@@ -4,7 +4,4 @@ eureka:
     prefer-ip-address: false
   client:
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/
-fdfs:
-  tracker-list:
-    - 10.10.100.200:22122
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/

+ 0 - 0
base-servers/file/file-server/src/main/resources/config/application-docker.yml → base-servers/file/file-server-fdfs/src/main/resources/config/application-docker.yml


+ 0 - 0
base-servers/file/file-server/src/main/resources/logback-spring.xml → base-servers/file/file-server-fdfs/src/main/resources/logback-spring.xml


+ 41 - 0
base-servers/file/file-server-qcloud/pom.xml

@@ -0,0 +1,41 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-server-qcloud</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage-qcloud</artifactId>
+        </dependency>
+        <!-- test -->
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>test-starter</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 6 - 0
base-servers/file/file-server-qcloud/src/main/docker/Dockerfile

@@ -0,0 +1,6 @@
+FROM frolvlad/alpine-oraclejdk8:slim
+VOLUME /tmp
+ADD file-server-qcloud-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" ]

+ 26 - 0
base-servers/file/file-server-qcloud/src/main/java/com/usoftchina/smartschool/file/qcloud/QCloudFileApplication.java

@@ -0,0 +1,26 @@
+package com.usoftchina.smartschool.file.qcloud;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.context.annotation.EnableMBeanExport;
+import org.springframework.jmx.support.RegistrationPolicy;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@SpringBootApplication(scanBasePackages = "com.usoftchina.smartschool.file")
+@EnableEurekaClient
+@EnableTransactionManagement
+@MapperScan("com.usoftchina.smartschool.file.mapper")
+@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
+@EnableSwagger2
+public class QCloudFileApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(QCloudFileApplication.class, args);
+    }
+}

+ 97 - 0
base-servers/file/file-server-qcloud/src/main/resources/application.yml

@@ -0,0 +1,97 @@
+qcloud:
+  cos:
+    secretId: AKIDngQ1QbKfRHxOcl6QxG5jIxcQ3YelYKUR
+    secretKey: ykGDn9HYAZkOs30oPxNcqgoyWvSnqfGf
+    region: ap-chengdu
+    bucketName: ydy-1258516134
+file:
+  base-url: https://${qcloud.cos.bucketName}.cos.${qcloud.cos.region}.myqcloud.com/
+spring:
+  application:
+    name: file-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  rabbitmq:
+    host: 10.10.100.166
+    port: 5672
+    virtual-host: school
+    username: school
+    password: select123***
+  zipkin:
+    sender:
+      type: rabbit
+    locator:
+      discovery:
+        enabled: true
+  sleuth:
+    sampler:
+      probability: 1.0
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://10.10.100.166:3306/smart_campus?characterEncoding=utf-8&useSSL=false
+    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
+  redis:
+    host: 10.10.100.166
+    port: 6379
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  profiles:
+    active: dev
+  servlet:
+    multipart:
+      enabled: true
+      #20971520 ->  20M
+      max-file-size: 20971520
+      max-request-size: 20971520
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    prefer-ip-address: true
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/
+server:
+  port: 9540
+  tomcat:
+    uri-encoding: UTF-8
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: always
+    shutdown:
+      enabled: true
+    restart:
+      enabled: true
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+mybatis:
+  type-aliases-package: com.usoftchina.smartschool.file.po
+  mapper-locations: classpath:mapper/*.xml
+auth:
+  public-key: auth/pub.key

+ 29 - 0
base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-cloud.yml

@@ -0,0 +1,29 @@
+eureka:
+  instance:
+    hostname: smartschool-file-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
+    rabbitmq:
+          host: 132.232.174.14
+          port: 5672
+          virtual-host: school
+          username: saas
+          password: select123***

+ 7 - 0
base-servers/file/file-server-qcloud/src/main/resources/config/application-docker-prod.yml

@@ -0,0 +1,7 @@
+eureka:
+  instance:
+    hostname: smartschool-file-server
+    prefer-ip-address: false
+  client:
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@smartschool-eureka-server:9500/eureka/

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

@@ -0,0 +1,131 @@
+<?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/file-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="file-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-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.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>

+ 2 - 19
base-servers/file/file-server/pom.xml

@@ -48,8 +48,8 @@
         </dependency>
 
         <dependency>
-            <groupId>com.github.tobato</groupId>
-            <artifactId>fastdfs-client</artifactId>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
@@ -68,23 +68,6 @@
             <groupId>net.logstash.logback</groupId>
             <artifactId>logstash-logback-encoder</artifactId>
         </dependency>
-        <!-- test -->
-        <dependency>
-            <groupId>com.usoftchina.smartschool</groupId>
-            <artifactId>test-starter</artifactId>
-        </dependency>
     </dependencies>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>com.spotify</groupId>
-                <artifactId>docker-maven-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
 
 </project>

+ 7 - 16
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/controller/FileController.java

@@ -1,16 +1,13 @@
 package com.usoftchina.smartschool.file.controller;
 
-import com.github.tobato.fastdfs.domain.StorePath;
-import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.usoftchina.smartschool.base.Result;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.exception.ExceptionCode;
 import com.usoftchina.smartschool.file.constant.FileConstant;
-import com.usoftchina.smartschool.file.dto.FileInfoDTO;
-import com.usoftchina.smartschool.file.dto.FolderDTO;
-import com.usoftchina.smartschool.file.dto.FolderSaveDTO;
+import com.usoftchina.smartschool.file.dto.*;
 import com.usoftchina.smartschool.file.po.FileInfo;
 import com.usoftchina.smartschool.file.service.FileInfoService;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
 import com.usoftchina.smartschool.utils.BeanMapper;
 import com.usoftchina.smartschool.utils.BizAssert;
 import com.usoftchina.smartschool.utils.CollectionUtils;
@@ -20,7 +17,6 @@ import io.swagger.annotations.ApiOperation;
 import org.apache.commons.compress.archivers.ArchiveOutputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
@@ -48,7 +44,7 @@ public class FileController {
     private FileInfoService fileService;
 
     @Autowired
-    private FastFileStorageClient storageClient;
+    private FileStorageClient storageClient;
     /**
      * 文件访问服务baseUrl
      *
@@ -98,7 +94,7 @@ public class FileController {
         // 检查父文件夹
         FileInfo parent = checkFolder(folderId);
         FileInfo info = FileInfo.newFile(file).folder(parent.getId())
-                .storeBy(storageClient).build();
+                .storeBy(storageClient).baseUrl(fileBaseUrl).build();
         fileService.save(info);
         return Result.success(BeanMapper.map(info, FileInfoDTO.class));
     }
@@ -127,9 +123,7 @@ public class FileController {
             if (null != info.getFullPath()) {
                 response.setHeader("Content-disposition",
                         "attachment; filename=" + URLEncoder.encode(info.getName(), "UTF-8"));
-                StorePath path = StorePath.praseFromUrl(info.getFullPath());
-                storageClient.downloadFile(path.getGroup(), path.getPath(),
-                        in -> IOUtils.copy(in, response.getOutputStream()));
+                storageClient.downloadFile(info.getFullPath(), response.getOutputStream());
             }
         }
     }
@@ -159,9 +153,7 @@ public class FileController {
             if (!StringUtils.isEmpty(info.getMime())) {
                 response.setContentType(info.getMime());
             }
-            StorePath path = StorePath.praseFromUrl(info.getFullPath());
-            storageClient.downloadFile(path.getGroup(), path.getPath(),
-                    in -> IOUtils.copy(in, response.getOutputStream()));
+            storageClient.downloadFile(info.getFullPath(), response.getOutputStream());
         } else {
             // 无法直接查看的文件,下载到客户端
             download(info.getId(), response);
@@ -248,8 +240,7 @@ public class FileController {
             }
         } else {
             out.putArchiveEntry(new ZipArchiveEntry(directory + info.getName()));
-            StorePath path = StorePath.praseFromUrl(info.getFullPath());
-            storageClient.downloadFile(path.getGroup(), path.getPath(), in -> IOUtils.copy(in, out));
+            storageClient.downloadFile(info.getFullPath(), out);
             out.closeArchiveEntry();
         }
     }

+ 31 - 24
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/po/FileInfo.java

@@ -1,14 +1,14 @@
 package com.usoftchina.smartschool.file.po;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.github.tobato.fastdfs.domain.StorePath;
-import com.github.tobato.fastdfs.service.FastFileStorageClient;
 import com.usoftchina.smartschool.base.entity.CommonBaseEntity;
 import com.usoftchina.smartschool.context.BaseContextHolder;
-import com.usoftchina.smartschool.file.constant.FileType;
-import com.usoftchina.smartschool.file.util.FileTypeUtils;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import com.usoftchina.smartschool.file.storage.util.FileType;
+import com.usoftchina.smartschool.file.storage.util.FileTypeUtils;
+import com.usoftchina.smartschool.file.storage.util.FilenameUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
-import org.apache.commons.io.FilenameUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
@@ -19,7 +19,7 @@ import java.util.Date;
  * @author yingp
  * @date 2018/9/29
  */
-public class FileInfo extends CommonBaseEntity implements Serializable{
+public class FileInfo extends CommonBaseEntity implements Serializable {
     /**
      * 文件夹id
      */
@@ -33,6 +33,10 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
      * 存储路径
      */
     private String fullPath;
+    /**
+     * 访问路径
+     */
+    private String accessPath;
     /**
      * Content-Type
      */
@@ -47,7 +51,8 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
     private long size;
     /**
      * 类型
-     * @see com.usoftchina.smartschool.file.constant.FileType
+     *
+     * @see com.usoftchina.smartschool.file.storage.util.FileType
      */
     private String type;
 
@@ -76,10 +81,11 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         this.name = name;
     }
 
-    public FileInfo(Long folderId, String name, String fullPath, String mime, String ext, String type, long size) {
+    public FileInfo(Long folderId, String name, String fullPath, String accessPath, String mime, String ext, String type, long size) {
         this.folderId = folderId;
         this.name = name;
         this.fullPath = fullPath;
+        this.accessPath = accessPath;
         this.mime = mime;
         this.ext = ext;
         this.type = type;
@@ -142,6 +148,14 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         this.type = type;
     }
 
+    public String getAccessPath() {
+        return accessPath;
+    }
+
+    public void setAccessPath(String accessPath) {
+        this.accessPath = accessPath;
+    }
+
     public boolean isDeleted() {
         return deleted;
     }
@@ -211,7 +225,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         return info;
     }
 
-    public static Builder newFile(MultipartFile file){
+    public static Builder newFile(MultipartFile file) {
         return new Builder(file);
     }
 
@@ -227,7 +241,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
         private long size;
         private String type;
         private MultipartFile multipartFile;
-        private FastFileStorageClient storageClient;
+        private FileStorageClient storageClient;
         private String baseUrl;
 
         public Builder(MultipartFile file) {
@@ -274,7 +288,7 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
             return this;
         }
 
-        public Builder storeBy(FastFileStorageClient storageClient){
+        public Builder storeBy(FileStorageClient storageClient) {
             this.storageClient = storageClient;
             return this;
         }
@@ -284,21 +298,14 @@ public class FileInfo extends CommonBaseEntity implements Serializable{
             return this;
         }
 
-        public FileInfo build() throws IOException{
+        public FileInfo build() throws IOException {
             if (null != storageClient) {
-                StorePath storePath;
-                if (FileType.of(type) == FileType.IMAGE) {
-                    // 保存图片 + 生成缩略图
-                    storePath = storageClient.uploadImageAndCrtThumbImage(multipartFile.getInputStream(),
-                            size, ext, null);
-                } else {
-                    storePath = storageClient.uploadFile(multipartFile.getInputStream(),
-                            size, ext, null);
-                }
-                this.fullPath = StringUtils.nullIf(baseUrl) + storePath.getFullPath();
+                this.fullPath = storageClient.uploadFile(multipartFile.getInputStream(),
+                        new FileMetadata(mime, ext, size));
             }
 
-            return new FileInfo(folderId, name, fullPath, mime, ext, type, size);
+            String accessPath = StringUtils.nullIf(baseUrl) + fullPath;
+            return new FileInfo(folderId, name, fullPath, accessPath, mime, ext, type, size);
         }
     }
-}
+}

+ 0 - 13
base-servers/file/file-server/src/main/resources/config/application-dev.yml

@@ -1,13 +0,0 @@
-eureka:
-  instance:
-    leaseRenewalIntervalInSeconds: 10
-    health-check-url-path: /actuator/health
-    status-page-url-path: /actuator/info
-    prefer-ip-address: true
-    metadata-map:
-      user.name: ${spring.security.user.name}
-      user.password: ${spring.security.user.password}
-  client:
-    registryFetchIntervalSeconds: 5
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/

+ 0 - 12
base-servers/file/file-server/src/main/resources/config/application-docker-dev.yml

@@ -1,12 +0,0 @@
-eureka:
-  instance:
-    hostname: saas-file-server-dev
-    prefer-ip-address: false
-  client:
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-dev:8510/eureka/
-spring:
-  rabbitmq:
-    virtual-host: dev
-server:
-  port: 8650

+ 0 - 12
base-servers/file/file-server/src/main/resources/config/application-docker-test.yml

@@ -1,12 +0,0 @@
-eureka:
-  instance:
-    hostname: saas-file-server-test
-    prefer-ip-address: false
-  client:
-    serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@saas-eureka-server-test:8515/eureka/
-spring:
-  rabbitmq:
-    virtual-host: test
-server:
-  port: 8655

+ 0 - 0
base-servers/file/file-server/src/main/resources/i18n/messages_en_US.properties


+ 0 - 0
base-servers/file/file-server/src/main/resources/i18n/messages_zh_CN.properties


+ 24 - 0
base-servers/file/file-storage-fdfs/pom.xml

@@ -0,0 +1,24 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage-fdfs</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.tobato</groupId>
+            <artifactId>fastdfs-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 21 - 0
base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsConfig.java

@@ -0,0 +1,21 @@
+package com.usoftchina.smartschool.file.storage.fdfs;
+
+import com.github.tobato.fastdfs.FdfsClientConfig;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@Configuration
+@Import(FdfsClientConfig.class)
+public class FdfsConfig {
+
+    @Bean
+    public FileStorageClient fileStorageClient() {
+        return new FdfsFileStorageClient();
+    }
+}

+ 50 - 0
base-servers/file/file-storage-fdfs/src/main/java/com/usoftchina/smartschool/file/storage/fdfs/FdfsFileStorageClient.java

@@ -0,0 +1,50 @@
+package com.usoftchina.smartschool.file.storage.fdfs;
+
+import com.github.tobato.fastdfs.domain.StorePath;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import com.usoftchina.smartschool.file.storage.util.FileType;
+import com.usoftchina.smartschool.file.storage.util.FileTypeUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FdfsFileStorageClient implements FileStorageClient{
+
+    @Autowired
+    private FastFileStorageClient storageClient;
+
+    @Override
+    public String uploadFile(InputStream inputStream, FileMetadata metadata) {
+        FileType type = FileTypeUtils.getFileType(metadata.getMime(), metadata.getExt());
+        StorePath storePath;
+        if (FileType.IMAGE == type) {
+            // 保存图片 + 生成缩略图
+            storePath = storageClient.uploadImageAndCrtThumbImage(inputStream, metadata.getSize(),
+                    metadata.getExt(), null);
+        } else {
+            storePath = storageClient.uploadFile(inputStream, metadata.getSize(),
+                    metadata.getExt(), null);
+        }
+        return storePath.getFullPath();
+    }
+
+    @Override
+    public void deleteFile(String filePath) {
+        storageClient.deleteFile(filePath);
+    }
+
+    @Override
+    public void downloadFile(String filePath, OutputStream out) throws IOException{
+        StorePath path = StorePath.praseFromUrl(filePath);
+        storageClient.downloadFile(path.getGroup(), path.getPath(), in -> IOUtils.copy(in, out));
+    }
+}

+ 3 - 0
base-servers/file/file-storage-fdfs/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# Auto Configuration
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.usoftchina.smartschool.file.storage.fdfs.FdfsConfig

+ 35 - 0
base-servers/file/file-storage-qcloud/pom.xml

@@ -0,0 +1,35 @@
+<?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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage-qcloud</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>5.4.10</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.usoftchina.smartschool</groupId>
+            <artifactId>file-storage</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 81 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClient.java

@@ -0,0 +1,81 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.model.COSObject;
+import com.qcloud.cos.model.ObjectMetadata;
+import com.qcloud.cos.region.Region;
+import com.qcloud.cos.utils.IOUtils;
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.UUID;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class COSFileStorageClient implements FileStorageClient {
+
+    private final CosProperties cosProperties;
+    private final COSClient client;
+
+    public COSFileStorageClient(CosProperties cosProperties) {
+        this.cosProperties = cosProperties;
+        this.client = initCOSClient();
+    }
+
+    private COSClient initCOSClient() {
+        // 1 初始化用户身份信息
+        COSCredentials cred = new BasicCOSCredentials(cosProperties.getSecretId(),
+                cosProperties.getSecretKey());
+        // 2 设置bucket的区域
+        ClientConfig clientConfig = new ClientConfig(new Region(cosProperties.getRegion()));
+        // 3 生成 cos 客户端。
+        return new COSClient(cred, clientConfig);
+    }
+
+    @Override
+    public String uploadFile(InputStream inputStream, FileMetadata metadata) {
+        ObjectMetadata objectMetadata = new ObjectMetadata();
+        objectMetadata.setContentLength(metadata.getSize());
+        if (!StringUtils.isEmpty(metadata.getMime())) {
+            objectMetadata.setContentType(metadata.getMime());
+        }
+        String filePath = generateDefaultFilePath() +
+                (StringUtils.isEmpty(metadata.getExt()) ? "" : ("." + metadata.getExt()));
+        client.putObject(cosProperties.getBucketName(), filePath, inputStream, objectMetadata);
+        return filePath;
+    }
+
+    private String generateDefaultFilePath() {
+        // 当天 + 随机串
+        return LocalDateTime.now().format(DateTimeFormatter.ISO_DATE) + "/" +
+                UUID.randomUUID().toString();
+    }
+
+    @Override
+    public void deleteFile(String filePath) {
+        client.deleteObject(cosProperties.getBucketName(), filePath);
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        client.shutdown();
+    }
+
+    @Override
+    public void downloadFile(String filePath, OutputStream out) throws IOException {
+        COSObject object = client.getObject(cosProperties.getBucketName(), filePath);
+        IOUtils.copy(object.getObjectContent(), out);
+    }
+}

+ 58 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/CosProperties.java

@@ -0,0 +1,58 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@ConfigurationProperties(CosProperties.PREFIX)
+public class CosProperties {
+    public static final String PREFIX = "qcloud.cos";
+
+    /**
+     * 秘钥
+     */
+    private String secretId;
+    private String secretKey;
+    /**
+     * 所属地域
+     */
+    private String region;
+    /**
+     * 存储桶名称
+     */
+    private String bucketName;
+
+    public String getSecretId() {
+        return secretId;
+    }
+
+    public void setSecretId(String secretId) {
+        this.secretId = secretId;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getBucketName() {
+        return bucketName;
+    }
+
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+}

+ 24 - 0
base-servers/file/file-storage-qcloud/src/main/java/com/usoftchina/smartschool/file/storage/qcloud/QCloudConfig.java

@@ -0,0 +1,24 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.usoftchina.smartschool.file.storage.FileStorageClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+@Configuration
+@EnableConfigurationProperties(CosProperties.class)
+public class QCloudConfig {
+
+    @Autowired
+    private CosProperties cosProperties;
+
+    @Bean
+    public FileStorageClient fileStorageClient() {
+        return new COSFileStorageClient(cosProperties);
+    }
+}

+ 3 - 0
base-servers/file/file-storage-qcloud/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# Auto Configuration
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.usoftchina.smartschool.file.storage.qcloud.QCloudConfig

+ 37 - 0
base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/COSFileStorageClientTest.java

@@ -0,0 +1,37 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import com.usoftchina.smartschool.file.storage.FileMetadata;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class COSFileStorageClientTest {
+    private static COSFileStorageClient getClient() {
+        CosProperties properties = new CosProperties();
+        properties.setSecretId("AKIDngQ1QbKfRHxOcl6QxG5jIxcQ3YelYKUR");
+        properties.setSecretKey("ykGDn9HYAZkOs30oPxNcqgoyWvSnqfGf");
+        properties.setRegion("ap-chengdu");
+        properties.setBucketName("ydy-1258516134");
+        return new COSFileStorageClient(properties);
+    }
+
+    public static void main(String[] args) throws IOException{
+        RandomTextFile file = new RandomTextFile();
+        COSFileStorageClient client = getClient();
+        try {
+            String filePath = client.uploadFile(file.getInputStream(), new FileMetadata(null,
+                    file.getFileExtName(), file.getFileSize()));
+            System.out.println(filePath);
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            client.downloadFile(filePath, out);
+            assert file.getText().equals(out.toString());
+            client.deleteFile(filePath);
+        } finally {
+            client.shutdown();
+        }
+    }
+}

+ 49 - 0
base-servers/file/file-storage-qcloud/src/test/java/com/usoftchina/smartschool/file/storage/qcloud/RandomTextFile.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.file.storage.qcloud;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.UUID;
+
+/**
+ * @author yingp
+ * @date 2018/11/9
+ */
+public class RandomTextFile {
+    private String text;
+
+    private InputStream inputStream;
+
+    private long fileSize;
+
+    private String fileExtName = "text";
+
+    public RandomTextFile() {
+        this(UUID.randomUUID().toString());
+    }
+
+    public RandomTextFile(String text) {
+        this.text = text;
+        this.fileSize = text.getBytes().length;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public InputStream getInputStream() {
+        this.inputStream = new ByteArrayInputStream(text.getBytes());
+        return inputStream;
+    }
+
+    public long getFileSize() {
+        return fileSize;
+    }
+
+    public String getFileExtName() {
+        return fileExtName;
+    }
+
+    public byte[] toByte() {
+        return this.text.getBytes();
+    }
+}

+ 15 - 0
base-servers/file/file-storage/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>file</artifactId>
+        <groupId>com.usoftchina.smartschool</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>file-storage</artifactId>
+
+
+</project>

+ 44 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileMetadata.java

@@ -0,0 +1,44 @@
+package com.usoftchina.smartschool.file.storage;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FileMetadata {
+    private String mime;
+    private String ext;
+    private long size;
+
+    public FileMetadata() {
+    }
+
+    public FileMetadata(String mime, String ext, long size) {
+        this.mime = mime;
+        this.ext = ext;
+        this.size = size;
+    }
+
+    public String getMime() {
+        return mime;
+    }
+
+    public void setMime(String mime) {
+        this.mime = mime;
+    }
+
+    public String getExt() {
+        return ext;
+    }
+
+    public void setExt(String ext) {
+        this.ext = ext;
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public void setSize(long size) {
+        this.size = size;
+    }
+}

+ 39 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/FileStorageClient.java

@@ -0,0 +1,39 @@
+package com.usoftchina.smartschool.file.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * 文件存储标准接口
+ *
+ * @author yingp
+ * @date 2019/3/14
+ */
+public interface FileStorageClient {
+
+    /**
+     * 上传文件
+     *
+     * @param inputStream
+     * @param metadata
+     * @return
+     */
+    String uploadFile(InputStream inputStream, FileMetadata metadata);
+
+    /**
+     * 删除文件
+     *
+     * @param filePath 文件路径 / 文件唯一标志
+     */
+    void deleteFile(String filePath);
+
+    /**
+     * 下载文件
+     *
+     * @param filePath 文件路径 / 文件唯一标志
+     * @param out
+     * @throws IOException
+     */
+    void downloadFile(String filePath, OutputStream out) throws IOException;
+}

+ 1 - 1
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/constant/FileType.java → base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileType.java

@@ -1,4 +1,4 @@
-package com.usoftchina.smartschool.file.constant;
+package com.usoftchina.smartschool.file.storage.util;
 
 /**
  * @author yingp

+ 3 - 6
base-servers/file/file-server/src/main/java/com/usoftchina/smartschool/file/util/FileTypeUtils.java → base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FileTypeUtils.java

@@ -1,7 +1,4 @@
-package com.usoftchina.smartschool.file.util;
-
-import com.usoftchina.smartschool.file.constant.FileType;
-import com.usoftchina.smartschool.utils.StringUtils;
+package com.usoftchina.smartschool.file.storage.util;
 
 /**
  * @author yingp
@@ -25,7 +22,7 @@ public class FileTypeUtils {
     }
 
     public static FileType getFileTypeByMime(String mime) {
-        if (!StringUtils.isEmpty(mime)) {
+        if (null != mime && !mime.isEmpty()) {
             if (mime.startsWith("image/")) {
                 return FileType.IMAGE;
             }
@@ -56,7 +53,7 @@ public class FileTypeUtils {
     }
 
     public static FileType getFileTypeByExtension(String ext) {
-        if (!StringUtils.isEmpty(ext)) {
+        if (null != ext && !ext.isEmpty()) {
             switch (ext) {
                 case "gif":
                 case "jpeg":

+ 97 - 0
base-servers/file/file-storage/src/main/java/com/usoftchina/smartschool/file/storage/util/FilenameUtils.java

@@ -0,0 +1,97 @@
+package com.usoftchina.smartschool.file.storage.util;
+
+/**
+ * @author yingp
+ * @date 2019/3/14
+ */
+public class FilenameUtils {
+
+    /**
+     * The extension separator character.
+     * @since 1.4
+     */
+    public static final char EXTENSION_SEPARATOR = '.';
+
+    /**
+     * The Unix separator character.
+     */
+    private static final char UNIX_SEPARATOR = '/';
+
+    /**
+     * The Windows separator character.
+     */
+    private static final char WINDOWS_SEPARATOR = '\\';
+
+    /**
+     * Gets the extension of a filename.
+     * <p>
+     * This method returns the textual part of the filename after the last dot.
+     * There must be no directory separator after the dot.
+     * <pre>
+     * foo.txt      --> "txt"
+     * a/b/c.jpg    --> "jpg"
+     * a/b.txt/c    --> ""
+     * a/b/c        --> ""
+     * </pre>
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename the filename to retrieve the extension of.
+     * @return the extension of the file or an empty string if none exists or {@code null}
+     * if the filename is {@code null}.
+     */
+    public static String getExtension(String filename) {
+        if (filename == null) {
+            return null;
+        }
+        int index = indexOfExtension(filename);
+        if (index == -1) {
+            return "";
+        } else {
+            return filename.substring(index + 1);
+        }
+    }
+
+    /**
+     * Returns the index of the last extension separator character, which is a dot.
+     * <p>
+     * This method also checks that there is no directory separator after the last dot.
+     * To do this it uses {@link #indexOfLastSeparator(String)} which will
+     * handle a file in either Unix or Windows format.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename  the filename to find the last path separator in, null returns -1
+     * @return the index of the last separator character, or -1 if there
+     * is no such character
+     */
+    public static int indexOfExtension(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
+        int lastSeparator = indexOfLastSeparator(filename);
+        return lastSeparator > extensionPos ? -1 : extensionPos;
+    }
+
+    /**
+     * Returns the index of the last directory separator character.
+     * <p>
+     * This method will handle a file in either Unix or Windows format.
+     * The position of the last forward or backslash is returned.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is running on.
+     *
+     * @param filename  the filename to find the last path separator in, null returns -1
+     * @return the index of the last separator character, or -1 if there
+     * is no such character
+     */
+    public static int indexOfLastSeparator(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
+        int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
+        return Math.max(lastUnixPos, lastWindowsPos);
+    }
+}

+ 5 - 0
base-servers/file/pom.xml

@@ -15,6 +15,11 @@
         <module>file-api</module>
         <module>file-dto</module>
         <module>file-server</module>
+        <module>file-server-qcloud</module>
+        <module>file-storage-fdfs</module>
+        <module>file-storage-qcloud</module>
+        <module>file-storage</module>
+        <module>file-server-fdfs</module>
     </modules>
 
 

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

@@ -29,7 +29,7 @@ Ext.define('school.view.interaction.homework.Release', {
                 xtype: "textfield",
                 name: "task_creator",
                 fieldLabel: "发布人id",
-                defaultValue: school.util.BaseUtil.getCurrentUser().id,
+                defaultValue: school.util.BaseUtil.getCurrentUser().teacher_id,
                 hidden: true
             }, {
                 xtype: "textfield",

+ 1 - 1
frontend/pc-web/app/view/Interaction/notice/SchoolNotice.js

@@ -29,7 +29,7 @@ Ext.define('school.view.interaction.notice.SchoolNotice', {
                 name: "notify_creator",
                 fieldLabel: "发布人id",
                 columnWidth: 0.5,
-                defaultValue: school.util.BaseUtil.getCurrentUser().id,
+                defaultValue: school.util.BaseUtil.getCurrentUser().teacher_id,
                 hidden: true
             }, {
                 xtype: "textfield",

+ 1 - 1
frontend/pc-web/app/view/core/form/field/ClassComboBox.js

@@ -20,7 +20,7 @@ Ext.define('school.view.core.form.field.ClassComboBox', {
     // template for the content inside text field
     displayTpl: Ext.create('Ext.XTemplate',
         '<tpl for=".">',
-        '{clazz_name} | {clazz_grade}',
+        '{clazz_name}',
         '</tpl>'
     ),
 

+ 23 - 0
frontend/pc-web/app/view/setting/msgtemplate/Panel.js

@@ -0,0 +1,23 @@
+Ext.define('school.view.setting.msgtemplate.Panel', {
+    extend: 'Ext.form.Panel',
+    xtype: 'setting-msgtemplate-panel',
+
+    controller: 'setting-msgtemplate-panel',
+
+    layout: 'column',
+    autoScroll: true,
+    bodyPadding: '8 12 8 12',
+
+    fieldDefaults: {
+        margin: '0 0 10 0',
+        labelAlign: 'right',
+        labelWidth: 90,
+        columnWidth: 1,
+    },
+
+    items: [],
+
+    listeners: {
+        afterrender: 'afterrender'
+    }
+});

+ 116 - 0
frontend/pc-web/app/view/setting/msgtemplate/PanelController.js

@@ -0,0 +1,116 @@
+Ext.define('school.view.setting.msgtemplate.PanelController', {
+    extend: 'Ext.app.ViewController',
+    alias: 'controller.setting-msgtemplate-panel',
+    
+    afterrender: function() {
+        let me = this,
+        view = me.getView();
+
+        view.setLoading(true);
+        school.util.BaseUtil.request({
+            // url: 'http://10.1.80.47:9520/api/school/template/list'
+            url: '/api/school/template/list'
+        }).then(function(res) {
+            view.setLoading(false);
+            let data = res.data.list.map(function(l) {
+                return {
+                    id: l.st_id,
+                    title: l.st_name,
+                    templateId: l.st_templateid
+                }
+            })
+            if(data.length > 0) {
+                me.addTemplate(data);
+            }else {
+                me.addEmptyText();
+            }
+        }).catch(function(e) {
+            view.setLoading(false);
+            me.addEmptyText();
+            school.util.BaseUtil.showErrorToast(e.message);
+        });
+    },
+
+    update: function(btn) {
+        let container = btn.up('fieldcontainer'),
+        items = container.items.items,
+        valueField = items[0],
+        titleField = items[1],
+        templateIdField = items[2],
+        id = valueField.value,
+        title = titleField.value,
+        templateId = templateIdField.value;
+
+        if(!templateIdField.isDirty()) {
+            school.util.BaseUtil.showErrorToast('数据无修改');
+            return;
+        }
+
+        container.setLoading(true);
+        school.util.BaseUtil.request({
+            // url: 'http://10.1.80.47:9520/api/school/template/save',
+            url: '/api/school/template/save',
+            method: 'POST',
+            params: JSON.stringify({
+                st_id: id,
+                st_name: title,
+                st_templateid: templateId
+            })
+        }).then(function(res) {
+            container.setLoading(false);
+            templateIdField.originalValue = templateId;
+            school.util.BaseUtil.showSuccessToast('更新成功');
+        }).catch(function(e) {
+            container.setLoading(false);
+            school.util.BaseUtil.showErrorToast('更新失败: ' + e.message);
+        });
+    },
+
+    addTemplate: function(datas) {
+        let me = this,
+        view = me.getView();
+
+        if(datas.length > 0) {
+            Ext.Array.each(datas, function(data) {
+                view.add(me.applyTemplate(data));
+            });
+        }
+    },
+
+    addEmptyText: function() {
+        let me = this,
+        view = me.getView();
+
+        view.setHtml('暂无数据');
+    },
+
+    applyTemplate: function(data) {
+        let template = {
+            xtype: 'fieldcontainer',
+            layout: 'hbox',
+            items: [{
+                xtype: 'hidden',
+                fieldLabel: 'ID',
+                name: 'id',
+                value: data.id
+            }, {
+                xtype: 'displayfield',
+                fieldLabel: '模板标题',
+                name: 'title',
+                value: data.title
+            }, {
+                xtype: 'textfield',
+                fieldLabel: '模板ID',
+                name: 'templateId',
+                value: data.templateId
+            }, {
+                xtype: 'button',
+                text: '保存',
+                handler: 'update'
+            }] 
+        };
+
+        return template;
+    }
+
+});

+ 4 - 0
frontend/pc-web/resources/json/navigation.json

@@ -54,6 +54,10 @@
     "text": "系统设置",
     "iconCls": "x-ss ss-nav-setting",
     "items": [{
+        "id": "setting-msgtemplate-panel",
+        "text": "消息模板设置",
+        "view": "setting-msgtemplate-panel"
+    }, {
         "id": "setting-device-list",
         "text": "设备参数",
         "view": "setting-device-list"

+ 3 - 2
frontend/wechat-web/src/modules/hiPages/access-notice/ItemComp.js

@@ -15,7 +15,8 @@ export default class ItemComp extends Component{
    constructor(props){
         super(props);
         this.state = {
-            showTime1:(this.props.itemdata.inDate==''||this.props.itemdata.inDate==null) ? this.props.itemdata.outDate : this.props.itemdata.inDate,
+            // showTime1:(this.props.itemdata.inDate==''||this.props.itemdata.inDate==null) ? this.props.itemdata.outDate : this.props.itemdata.inDate,
+            showTime1:this.props.itemdata.recordDate
         }
     }
      render(){
@@ -28,7 +29,7 @@ export default class ItemComp extends Component{
                          style={{height: '100%', justifyContent: 'center', alignItems: 'center'}}>
                         {this.props.isFirst ? <div style={{flex: 1}}></div>
                             : <div style={{background: '#E9E9E9', flex: '1', width: '2px'}}></div>}
-                        {(this.props.itemdata.inDate==''||this.props.itemdata.inDate==null) ?
+                        { this.props.itemdata.recordType == 1  ?
                             <div className="item_in_out in">进</div> :
                             <div className="item_in_out out">出</div>
                         }

BIN
frontend/wechat-web/src/style/imgs/no_data.png


+ 20 - 0
pom.xml

@@ -283,6 +283,26 @@
                 <artifactId>device-sdk-dahua</artifactId>
                 <version>${project.release.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-server</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage-fdfs</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.usoftchina.smartschool</groupId>
+                <artifactId>file-storage-qcloud</artifactId>
+                <version>${project.release.version}</version>
+            </dependency>
             <!-- file upload -->
             <dependency>
                 <groupId>io.github.openfeign.form</groupId>